dcf routines for microbit

Fork of microbit-dcf by Kurt Schuster

Committer:
qrti
Date:
Fri Feb 24 07:52:08 2017 +0000
Revision:
3:baecb5137d1a
Parent:
1:f5f3ea306641
Child:
4:eda8c18d0564
automatic sec correction

Who changed what in which revision?

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