dcf routines for microbit

Fork of microbit-dcf by Kurt Schuster

Committer:
qrti
Date:
Wed Feb 22 10:14:43 2017 +0000
Revision:
1:f5f3ea306641
Child:
3:baecb5137d1a
initial version

Who changed what in which revision?

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