dcf routines for microbit

Fork of microbit-dcf by Kurt Schuster

Committer:
qrti
Date:
Sat Feb 25 16:57:37 2017 +0000
Revision:
4:eda8c18d0564
Parent:
3:baecb5137d1a
ticker and timer use

Who changed what in which revision?

UserRevisionLine numberNew contents of line
qrti 4:eda8c18d0564 1 // dcf V0.6 170225 qrt@qland.de
qrti 3:baecb5137d1a 2 //
qrti 3:baecb5137d1a 3 // V0.1 initial version
qrti 3:baecb5137d1a 4 // V0.3 automatic sec correction
qrti 4:eda8c18d0564 5 // V0.4 refined sec correction
qrti 4:eda8c18d0564 6 // V0.5 returned to simple sec correction, added lost signal sync
qrti 4:eda8c18d0564 7 // V0.6 ticker and timer use
qrti 1:f5f3ea306641 8
qrti 1:f5f3ea306641 9 #include "dcf.h"
qrti 1:f5f3ea306641 10
qrti 1:f5f3ea306641 11 MicroBit *Dcf::uBit;
qrti 1:f5f3ea306641 12
qrti 1:f5f3ea306641 13 uint8_t Dcf::sec;
qrti 1:f5f3ea306641 14 uint8_t Dcf::min;
qrti 1:f5f3ea306641 15 uint8_t Dcf::hou;
qrti 1:f5f3ea306641 16 uint8_t Dcf::day;
qrti 1:f5f3ea306641 17 uint8_t Dcf::wday;
qrti 1:f5f3ea306641 18 uint8_t Dcf::month;
qrti 1:f5f3ea306641 19 uint8_t Dcf::year;
qrti 1:f5f3ea306641 20
qrti 1:f5f3ea306641 21 uint8_t Dcf::hsec;
qrti 1:f5f3ea306641 22 uint8_t Dcf::hmin;
qrti 1:f5f3ea306641 23 uint8_t Dcf::hhou;
qrti 1:f5f3ea306641 24 uint8_t Dcf::hday;
qrti 1:f5f3ea306641 25 uint8_t Dcf::hwday;
qrti 1:f5f3ea306641 26 uint8_t Dcf::hmonth;
qrti 1:f5f3ea306641 27 uint8_t Dcf::hyear;
qrti 1:f5f3ea306641 28
qrti 1:f5f3ea306641 29 uint8_t Dcf::status;
qrti 1:f5f3ea306641 30 uint8_t Dcf::bit;
qrti 1:f5f3ea306641 31 uint8_t Dcf::parity;
qrti 4:eda8c18d0564 32
qrti 4:eda8c18d0564 33 uint32_t Dcf::dt;
qrti 1:f5f3ea306641 34
qrti 4:eda8c18d0564 35 Ticker ticker;
qrti 4:eda8c18d0564 36 Timer timer;
qrti 1:f5f3ea306641 37
qrti 1:f5f3ea306641 38 void Dcf::init(MicroBit *_uBit)
qrti 1:f5f3ea306641 39 {
qrti 1:f5f3ea306641 40 uBit = _uBit;
qrti 1:f5f3ea306641 41 }
qrti 1:f5f3ea306641 42
qrti 1:f5f3ea306641 43 void Dcf::receive()
qrti 1:f5f3ea306641 44 {
qrti 1:f5f3ea306641 45 uBit->io.PIN.setPull(PULL);
qrti 1:f5f3ea306641 46
qrti 1:f5f3ea306641 47 #if DCF_LOGIC==NEGATIVE
qrti 1:f5f3ea306641 48 uBit->messageBus.listen(DCF_INPUT_PIN, MICROBIT_PIN_EVT_FALL, secPulse, MESSAGE_BUS_LISTENER_IMMEDIATE);
qrti 1:f5f3ea306641 49 uBit->messageBus.listen(DCF_INPUT_PIN, MICROBIT_PIN_EVT_RISE, bitPulse, MESSAGE_BUS_LISTENER_IMMEDIATE);
qrti 1:f5f3ea306641 50 #else
qrti 1:f5f3ea306641 51 uBit->messageBus.listen(DCF_INPUT_PIN, MICROBIT_PIN_EVT_RISE, secPulse, MESSAGE_BUS_LISTENER_IMMEDIATE);
qrti 1:f5f3ea306641 52 uBit->messageBus.listen(DCF_INPUT_PIN, MICROBIT_PIN_EVT_FALL, bitPulse, MESSAGE_BUS_LISTENER_IMMEDIATE);
qrti 1:f5f3ea306641 53 #endif
qrti 1:f5f3ea306641 54
qrti 1:f5f3ea306641 55 uBit->io.P16.eventOn(MICROBIT_PIN_EVENT_ON_EDGE);
qrti 1:f5f3ea306641 56
qrti 4:eda8c18d0564 57 ticker.attach(&service, 1); // attach sec ticker
qrti 4:eda8c18d0564 58 timer.start(); // start sec timer
qrti 4:eda8c18d0564 59
qrti 4:eda8c18d0564 60 while(true)
qrti 4:eda8c18d0564 61 fiber_sleep(1000); // sleep
qrti 4:eda8c18d0564 62 }
qrti 3:baecb5137d1a 63
qrti 4:eda8c18d0564 64 void Dcf::service()
qrti 4:eda8c18d0564 65 {
qrti 4:eda8c18d0564 66 incTime();
qrti 1:f5f3ea306641 67
qrti 4:eda8c18d0564 68 if(status&SYNCDAV && min==58 && sec==50) // no new sync while data not verified
qrti 4:eda8c18d0564 69 status &= SYNCRES; // hourly sync, lost signal sync after LOSIGT ms
qrti 1:f5f3ea306641 70 }
qrti 1:f5f3ea306641 71
qrti 1:f5f3ea306641 72 void Dcf::secPulse(MicroBitEvent e)
qrti 1:f5f3ea306641 73 {
qrti 4:eda8c18d0564 74 dt = timer.read_ms(); // get last timer
qrti 4:eda8c18d0564 75 timer.reset(); // restart
qrti 1:f5f3ea306641 76
qrti 3:baecb5137d1a 77 if(!(status & SYNCINI)){ // ignore first pulses after poweron
qrti 4:eda8c18d0564 78 if(++parity == IGNOPU) // parity used as init counter
qrti 3:baecb5137d1a 79 status |= SYNCINI;
qrti 3:baecb5137d1a 80 }
qrti 3:baecb5137d1a 81 else if(!(status & SYNCSEC)){ // sec sync
qrti 4:eda8c18d0564 82 ticker.detach(); // detach ticker
qrti 4:eda8c18d0564 83 ticker.attach(&service, 1); // attach
qrti 3:baecb5137d1a 84 status |= SYNCSEC;
qrti 3:baecb5137d1a 85 }
qrti 3:baecb5137d1a 86 else if(!(status & SYNC59)){ // sec 59 sync
qrti 4:eda8c18d0564 87 if(dt>1950 && dt<2050){ // 2000 ms +- 50 ms
qrti 3:baecb5137d1a 88 hsec = 0; // start data capture
qrti 1:f5f3ea306641 89 parity = 0;
qrti 1:f5f3ea306641 90 status |= SYNC59;
qrti 1:f5f3ea306641 91 }
qrti 1:f5f3ea306641 92 }
qrti 1:f5f3ea306641 93 else if((status & (SYNCDAR | SYNCDAT)) == SYNCDAR){ // data ready, but not taken
qrti 4:eda8c18d0564 94 ticker.detach(); // detach ticker
qrti 1:f5f3ea306641 95 takeData(); // take data
qrti 4:eda8c18d0564 96 ticker.attach(&service, 1); // attach ticker
qrti 1:f5f3ea306641 97 status |= SYNCDAT; // data taken
qrti 1:f5f3ea306641 98
qrti 1:f5f3ea306641 99 hsec = 0; // start data verify
qrti 1:f5f3ea306641 100 parity = 0;
qrti 4:eda8c18d0564 101 status &= ~SYNCDAR;
qrti 1:f5f3ea306641 102 }
qrti 1:f5f3ea306641 103 else if((status & (SYNCDAR | SYNCDAV)) == SYNCDAR){ // data ready, but not verified
qrti 1:f5f3ea306641 104 if(verifyData()) // verify data
qrti 1:f5f3ea306641 105 status &= SYNCRES; // restart sync if error
qrti 1:f5f3ea306641 106 else
qrti 1:f5f3ea306641 107 status |= SYNCDAV; // data verified
qrti 1:f5f3ea306641 108 }
qrti 1:f5f3ea306641 109 }
qrti 1:f5f3ea306641 110
qrti 1:f5f3ea306641 111 void Dcf::bitPulse(MicroBitEvent e)
qrti 1:f5f3ea306641 112 {
qrti 3:baecb5137d1a 113 if((status & (SYNC59 | SYNCDAR)) == SYNC59){ // SYNC59 done, data not ready
qrti 3:baecb5137d1a 114 if(getData()) // get data
qrti 3:baecb5137d1a 115 status &= SYNCRES; // restart sync if error
qrti 1:f5f3ea306641 116 }
qrti 1:f5f3ea306641 117 }
qrti 1:f5f3ea306641 118
qrti 1:f5f3ea306641 119 void Dcf::incTime()
qrti 1:f5f3ea306641 120 {
qrti 1:f5f3ea306641 121 if(++sec < 60)
qrti 1:f5f3ea306641 122 return;
qrti 1:f5f3ea306641 123
qrti 1:f5f3ea306641 124 sec = 0;
qrti 1:f5f3ea306641 125
qrti 1:f5f3ea306641 126 if(++min < 60)
qrti 1:f5f3ea306641 127 return;
qrti 1:f5f3ea306641 128
qrti 1:f5f3ea306641 129 min = 0;
qrti 1:f5f3ea306641 130
qrti 1:f5f3ea306641 131 if(++hou < 24)
qrti 1:f5f3ea306641 132 return;
qrti 1:f5f3ea306641 133
qrti 1:f5f3ea306641 134 hou = 0;
qrti 1:f5f3ea306641 135
qrti 1:f5f3ea306641 136 if(++day<29 ||
qrti 1:f5f3ea306641 137 (day==29 && month==2 && year%4==0 && year%400!=0) ||
qrti 1:f5f3ea306641 138 (day<31 && (month==4 || month==6 || month==9 || month==11)) ||
qrti 1:f5f3ea306641 139 (day<32 && (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12)))
qrti 1:f5f3ea306641 140 return;
qrti 1:f5f3ea306641 141
qrti 1:f5f3ea306641 142 day = 1;
qrti 1:f5f3ea306641 143
qrti 1:f5f3ea306641 144 if(++month < 13)
qrti 1:f5f3ea306641 145 return;
qrti 1:f5f3ea306641 146
qrti 1:f5f3ea306641 147 month = 0;
qrti 1:f5f3ea306641 148 year++;
qrti 1:f5f3ea306641 149 }
qrti 1:f5f3ea306641 150
qrti 1:f5f3ea306641 151 // 5 4 3 2 1 P parity, Y year, M month, W weekday, D day
qrti 1:f5f3ea306641 152 // 876543210 9876543210 9876543210 9876543210 9876543210 9676543210 h hour, m minute, L leap second, S time start
qrti 1:f5f3ea306641 153 // PYYYYYYYY MMMMMWWWDD DDDDPhhhhh hPmmmmmmmS LZZEARRRRR RRRRRRRRR0 Z zone, A approching zone change, R reserved
qrti 1:f5f3ea306641 154 // -------- ---------- ---|------ |-------|1 0
qrti 1:f5f3ea306641 155 //
qrti 1:f5f3ea306641 156 uint8_t Dcf::getData()
qrti 1:f5f3ea306641 157 {
qrti 4:eda8c18d0564 158 dt = timer.read_ms(); // bit length
qrti 1:f5f3ea306641 159
qrti 1:f5f3ea306641 160 if(dt>80 && dt<140) // zero
qrti 1:f5f3ea306641 161 bit = 0;
qrti 1:f5f3ea306641 162 else if(dt>180 && dt<240) // one
qrti 1:f5f3ea306641 163 bit = 0x80;
qrti 1:f5f3ea306641 164 else // not valid
qrti 1:f5f3ea306641 165 return 1;
qrti 1:f5f3ea306641 166
qrti 1:f5f3ea306641 167 if(hsec == 0){ // bit 0
qrti 1:f5f3ea306641 168 if(bit == 0x80) // always 0
qrti 1:f5f3ea306641 169 return 2;
qrti 1:f5f3ea306641 170 }
qrti 1:f5f3ea306641 171 else if(hsec == 20){ // bit 20
qrti 1:f5f3ea306641 172 if(bit == 0) // always 1
qrti 1:f5f3ea306641 173 return 3;
qrti 1:f5f3ea306641 174 }
qrti 1:f5f3ea306641 175 else if(hsec>20 && hsec<29){ // bits 21-28
qrti 1:f5f3ea306641 176 if(hsec < 28){ // minute
qrti 1:f5f3ea306641 177 hmin = hmin >> 1 | bit;
qrti 1:f5f3ea306641 178
qrti 1:f5f3ea306641 179 if(hsec==27 && (hmin=decBin(hmin>>1))>59)
qrti 1:f5f3ea306641 180 return 4;
qrti 1:f5f3ea306641 181 }
qrti 1:f5f3ea306641 182
qrti 1:f5f3ea306641 183 if((parity^=bit) && hsec==28) // parity
qrti 1:f5f3ea306641 184 return 5;
qrti 1:f5f3ea306641 185 }
qrti 1:f5f3ea306641 186 else if(hsec>28 && hsec<36){ // bits 29-35
qrti 1:f5f3ea306641 187 if(hsec < 35){ // hour
qrti 1:f5f3ea306641 188 hhou = hhou >> 1 | bit;
qrti 1:f5f3ea306641 189
qrti 1:f5f3ea306641 190 if(hsec==34 && (hhou=decBin(hhou>>2))>24)
qrti 1:f5f3ea306641 191 return 6;
qrti 1:f5f3ea306641 192 }
qrti 1:f5f3ea306641 193
qrti 1:f5f3ea306641 194 if((parity^=bit) && hsec==35) // parity
qrti 1:f5f3ea306641 195 return 7;
qrti 1:f5f3ea306641 196 }
qrti 1:f5f3ea306641 197 else if(hsec>35 && hsec<59){ // bits 36-58
qrti 1:f5f3ea306641 198 if(hsec < 42){ // day
qrti 1:f5f3ea306641 199 hday = hday >> 1 | bit;
qrti 1:f5f3ea306641 200
qrti 1:f5f3ea306641 201 if(hsec==41 && (hday==0 || (hday=decBin(hday>>2))>31))
qrti 1:f5f3ea306641 202 return 8;
qrti 1:f5f3ea306641 203 }
qrti 1:f5f3ea306641 204 else if(hsec < 45){ // weekday
qrti 1:f5f3ea306641 205 hwday = hwday >> 1 | bit;
qrti 1:f5f3ea306641 206
qrti 1:f5f3ea306641 207 if(hsec==44 && (hwday==0 || (hwday>>=5)>7))
qrti 1:f5f3ea306641 208 return 9;
qrti 1:f5f3ea306641 209 }
qrti 1:f5f3ea306641 210 else if(hsec < 50){ // month
qrti 1:f5f3ea306641 211 hmonth = hmonth >> 1 | bit;
qrti 1:f5f3ea306641 212
qrti 1:f5f3ea306641 213 if(hsec==49 && (hmonth==0 || (hmonth=decBin(hmonth>>3))>12))
qrti 1:f5f3ea306641 214 return 10;
qrti 1:f5f3ea306641 215 }
qrti 1:f5f3ea306641 216 else if(hsec < 58){ // year
qrti 1:f5f3ea306641 217 hyear = hyear >> 1 | bit;
qrti 1:f5f3ea306641 218
qrti 1:f5f3ea306641 219 if(hsec==57 && (hyear=decBin(hyear))>99)
qrti 1:f5f3ea306641 220 return 11;
qrti 1:f5f3ea306641 221 }
qrti 1:f5f3ea306641 222
qrti 1:f5f3ea306641 223 if((parity^=bit) && hsec==58) // parity
qrti 1:f5f3ea306641 224 return 12;
qrti 1:f5f3ea306641 225
qrti 1:f5f3ea306641 226 if(hsec == 58)
qrti 1:f5f3ea306641 227 status |= SYNCDAR; // data ready
qrti 1:f5f3ea306641 228 }
qrti 1:f5f3ea306641 229
qrti 1:f5f3ea306641 230 hsec++;
qrti 1:f5f3ea306641 231
qrti 1:f5f3ea306641 232 return 0;
qrti 1:f5f3ea306641 233 }
qrti 1:f5f3ea306641 234
qrti 1:f5f3ea306641 235 void Dcf::takeData()
qrti 1:f5f3ea306641 236 {
qrti 1:f5f3ea306641 237 sec = 0;
qrti 1:f5f3ea306641 238 min = hmin;
qrti 1:f5f3ea306641 239 hou = hhou;
qrti 1:f5f3ea306641 240 day = hday;
qrti 1:f5f3ea306641 241 wday = hwday;
qrti 1:f5f3ea306641 242 month = hmonth;
qrti 1:f5f3ea306641 243 year = hyear;
qrti 1:f5f3ea306641 244 }
qrti 1:f5f3ea306641 245
qrti 1:f5f3ea306641 246 uint8_t Dcf::verifyData()
qrti 1:f5f3ea306641 247 {
qrti 1:f5f3ea306641 248 return (hou!=hhou || day!=hday || wday!=hwday || month!=hmonth || year!=hyear);
qrti 1:f5f3ea306641 249 }
qrti 1:f5f3ea306641 250
qrti 1:f5f3ea306641 251 uint8_t Dcf::decBin(uint8_t b)
qrti 1:f5f3ea306641 252 {
qrti 1:f5f3ea306641 253 return (b >> 4) * 10 + (b & 0x0f);
qrti 1:f5f3ea306641 254 }
qrti 1:f5f3ea306641 255
qrti 1:f5f3ea306641 256 // uint8_t Dcf::parity(uint8_t b)
qrti 1:f5f3ea306641 257 // {
qrti 1:f5f3ea306641 258 // b ^= b >> 4;
qrti 1:f5f3ea306641 259 // b ^= b >> 2;
qrti 1:f5f3ea306641 260 // b ^= b >> 1;
qrti 1:f5f3ea306641 261
qrti 1:f5f3ea306641 262 // return b & 1;
qrti 1:f5f3ea306641 263 // }
qrti 3:baecb5137d1a 264
qrti 3:baecb5137d1a 265 // uint8_t x = 0;
qrti 3:baecb5137d1a 266 // uBit->io.P0.setDigitalValue(x++ & 1);