00001 00010 #include "boole.h" 00011 #include "dcftime.h" 00012 00013 // TODO: define and use meaningful states for certain situations (valid time, no values received, etc.) 00014 // TODO: find correct start of the seconds. ATM the clock is running late by one second 00015 // TODO: check if it is possible to give DCF_RATE as parameter for init() 00016 00017 typedef unsigned int dcf_sample; 00018 typedef unsigned int dcf_sizetype; 00020 const dcf_sample dcf_second_samples = (DCF_RATE); 00022 const dcf_sample dcf_logic_false_min = (DCF_RATE)*3/100; 00024 const dcf_sample dcf_logic_false_max = (DCF_RATE)*13/100; 00026 const dcf_sample dcf_logic_true_min = (DCF_RATE)*14/100; 00028 const dcf_sample dcf_logic_true_max = (DCF_RATE)*23/100; 00030 const dcf_sample dcf_second_tolerance_min = (DCF_RATE) - (DCF_RATE)*3/100; 00032 const dcf_sample dcf_second_tolerance_max = (DCF_RATE) + (DCF_RATE)*3/100; 00033 00035 enum dcf_logic_signal_enum { 00036 dcf_signal_no, 00037 dcf_signal_false, 00038 dcf_signal_true, 00039 dcf_signal_invalid 00040 }; 00042 typedef enum dcf_logic_signal_enum dcf_logic_signal; 00043 00045 struct dcf_receiving_data_struct { 00046 dcf_date date; 00047 dcf_time time; 00048 boolean parity; 00049 boolean is_valid; 00050 dcf_logic_signal current_signal; 00051 dcf_sample low_samples; 00052 dcf_sample high_samples; 00053 }; 00055 typedef struct dcf_receiving_data_struct dcf_receiving_data; 00056 00062 struct dcf_data_struct { 00063 dcf_datetime current_datetime[2]; 00064 boolean use_first_current_datetime; 00065 dcf_sample current_datetime_sample; 00066 dcf_receiving_data receiving_data; 00067 }; 00068 00069 /* 00070 global data 00071 */ 00072 00073 static struct dcf_data_struct dcf_data; 00075 /* 00076 dcf_time 00077 */ 00078 00083 static void dcf_time_init(dcf_time * pTime) { 00084 pTime->second = 0; 00085 pTime->minute = 0; 00086 pTime->hour = 0; 00087 pTime->is_dst = False; 00088 } 00089 00095 static boolean dcf_time_inc(dcf_time * pTime) { 00096 ++(pTime->second); 00097 if (pTime->second == 60) { 00098 pTime->second = 0; 00099 ++(pTime->minute); 00100 if (pTime->minute == 60) { 00101 pTime->minute = 0; 00102 ++(pTime->hour); 00103 if (pTime->hour == 24) { 00104 pTime->hour = 0; 00105 return True; /* overflow => increment date */ 00106 } 00107 } 00108 } 00109 return False; 00110 } 00111 00117 static boolean dcf_time_is_valid(dcf_time * pTime) { 00118 return (pTime->second <= 60) 00119 && (pTime->minute <= 60) 00120 && (pTime->hour <= 24); 00121 } 00122 00123 /* 00124 dcf_date 00125 */ 00126 00131 static void dcf_date_init(dcf_date * pDate) { 00132 pDate->dayofweek = dcf_sunday; 00133 pDate->dayofmonth = 1; 00134 pDate->month = dcf_january; 00135 pDate->year = 0; 00136 } 00137 00143 static dcf_sizetype dcf_date_days_in_month(dcf_date * pDate) { 00144 switch (pDate->month) { 00145 case dcf_february: 00146 if (pDate->year % 4 != 0) 00147 return 28; /* year not divisible by 4 */ 00148 else if (pDate->year != 0) 00149 return 29; /* year divisible by 4 and not divisible by 100 */ 00150 else if (((pDate->dayofmonth % 7) + 1) != pDate->dayofweek) 00151 return 28; /* year divisible by 100 and not divisible by 400 */ 00152 else 00153 return 29; /* year divisible by 400 */ 00154 /* 00155 if year is divisble by 400 (eg year 2000) the 1st february is a tuesday (== 2 (== 1+1)) 00156 if year divided by 400 remains 100 1st February is a monday 00157 if year divided by 400 remains 200 1st February is a saturday 00158 if year divided by 400 remains 300 1st February is a thursday 00159 this repeats every 400 years, because 400 year are 3652425/25 day 00160 which is 7*521775/25, therefore divisible by 7 00161 which means every 400 years the day of week are the same 00162 ! dayofmonth and dayofweek must be synchronized to get the right value 00163 */ 00164 case dcf_april: 00165 case dcf_june: 00166 case dcf_september: 00167 case dcf_november: 00168 return 30; 00169 default: 00170 return 31; 00171 } 00172 } 00173 00178 static void dcf_date_inc(dcf_date * pDate) { 00179 ++(pDate->dayofweek); 00180 if (pDate->dayofweek == 8) { 00181 pDate->dayofweek = 1; 00182 } 00183 00184 ++(pDate->dayofmonth); 00185 if (pDate->dayofmonth == (dcf_date_days_in_month(pDate) + 1)) { 00186 pDate->dayofmonth = 1; 00187 ++(pDate->month); 00188 if (pDate->month == 13) { 00189 pDate->month = 1; 00190 ++(pDate->year); 00191 if (pDate->year == 100) { 00192 pDate->year = 0; 00193 } 00194 } 00195 } 00196 } 00197 00203 static boolean dcf_date_is_valid(dcf_date * pDate) { 00204 return (1 <= pDate->dayofweek) 00205 && (pDate->dayofweek <= 7) 00206 && (1 <= pDate->dayofmonth) 00207 && (pDate->dayofmonth <= dcf_date_days_in_month(pDate)) 00208 && (1 <= pDate->month) 00209 && (pDate->month <= 12) 00210 && (pDate->year <= 99); 00211 } 00212 00213 /* 00214 dcf_datetime 00215 */ 00220 static void dcf_datetime_init(dcf_datetime * pDatetime) { 00221 pDatetime->is_valid = False; 00222 pDatetime->has_signal = False; 00223 dcf_time_init(&(pDatetime->time)); 00224 dcf_date_init(&(pDatetime->date)); 00225 } 00226 00231 static void dcf_datetime_inc(dcf_datetime * pDatetime) { 00232 if (dcf_time_inc(&(pDatetime->time))) { 00233 dcf_date_inc(&(pDatetime->date)); 00234 } 00235 } 00236 00237 /* 00238 dcf_receiving_data 00239 */ 00240 00245 static void dcf_receiving_data_init(dcf_receiving_data * pReceive) { 00246 pReceive->current_signal = dcf_signal_no; 00247 pReceive->parity = False; 00248 pReceive->is_valid = True; 00249 pReceive->low_samples = 0; 00250 pReceive->high_samples = 0; 00251 dcf_time_init(&(pReceive->time)); 00252 dcf_date_init(&(pReceive->date)); 00253 } 00254 00259 static void dcf_logic(boolean signal) { 00260 dcf_data.receiving_data.parity ^= signal; 00261 switch (dcf_data.receiving_data.time.second) { 00262 case 16: dcf_data.receiving_data.parity = True; break; 00263 case 17: dcf_data.receiving_data.time.is_dst = signal; break; 00264 case 18: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break; 00265 case 19: dcf_data.receiving_data.parity = True; break; 00266 case 20: if(!signal) dcf_data.receiving_data.is_valid = False; break; 00267 case 21: dcf_data.receiving_data.time.minute = signal ? 1 : 0; break; 00268 case 22: dcf_data.receiving_data.time.minute += signal ? 2 : 0; break; 00269 case 23: dcf_data.receiving_data.time.minute += signal ? 4 : 0; break; 00270 case 24: dcf_data.receiving_data.time.minute += signal ? 8 : 0; break; 00271 case 25: dcf_data.receiving_data.time.minute += signal ? 10 : 0; break; 00272 case 26: dcf_data.receiving_data.time.minute += signal ? 20 : 0; break; 00273 case 27: dcf_data.receiving_data.time.minute += signal ? 40 : 0; break; 00274 case 28: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break; 00275 case 29: dcf_data.receiving_data.time.hour = signal ? 1 : 0; break; 00276 case 30: dcf_data.receiving_data.time.hour += signal ? 2 : 0; break; 00277 case 31: dcf_data.receiving_data.time.hour += signal ? 4 : 0; break; 00278 case 32: dcf_data.receiving_data.time.hour += signal ? 8 : 0; break; 00279 case 33: dcf_data.receiving_data.time.hour += signal ? 10 : 0; break; 00280 case 34: dcf_data.receiving_data.time.hour += signal ? 20 : 0; break; 00281 case 35: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break; 00282 case 36: dcf_data.receiving_data.date.dayofmonth = signal ? 1 : 0; break; 00283 case 37: dcf_data.receiving_data.date.dayofmonth += signal ? 2 : 0; break; 00284 case 38: dcf_data.receiving_data.date.dayofmonth += signal ? 4 : 0; break; 00285 case 39: dcf_data.receiving_data.date.dayofmonth += signal ? 8 : 0; break; 00286 case 40: dcf_data.receiving_data.date.dayofmonth += signal ? 10 : 0; break; 00287 case 41: dcf_data.receiving_data.date.dayofmonth += signal ? 20 : 0; break; 00288 case 42: dcf_data.receiving_data.date.dayofweek = signal ? 1 : 0; break; 00289 case 43: dcf_data.receiving_data.date.dayofweek += signal ? 2 : 0; break; 00290 case 44: dcf_data.receiving_data.date.dayofweek += signal ? 4 : 0; break; 00291 case 45: dcf_data.receiving_data.date.month = signal ? 1 : 0; break; 00292 case 46: dcf_data.receiving_data.date.month += signal ? 2 : 0; break; 00293 case 47: dcf_data.receiving_data.date.month += signal ? 4 : 0; break; 00294 case 48: dcf_data.receiving_data.date.month += signal ? 8 : 0; break; 00295 case 49: dcf_data.receiving_data.date.month += signal ? 10 : 0; break; 00296 case 50: dcf_data.receiving_data.date.year = signal ? 1 : 0; break; 00297 case 51: dcf_data.receiving_data.date.year += signal ? 2 : 0; break; 00298 case 52: dcf_data.receiving_data.date.year += signal ? 4 : 0; break; 00299 case 53: dcf_data.receiving_data.date.year += signal ? 8 : 0; break; 00300 case 54: dcf_data.receiving_data.date.year += signal ? 10 : 0; break; 00301 case 55: dcf_data.receiving_data.date.year += signal ? 20 : 0; break; 00302 case 56: dcf_data.receiving_data.date.year += signal ? 40 : 0; break; 00303 case 57: dcf_data.receiving_data.date.year += signal ? 80 : 0; break; 00304 case 58: if(dcf_data.receiving_data.parity) dcf_data.receiving_data.is_valid = False; break; 00305 } 00306 ++(dcf_data.receiving_data.time.second); 00307 } 00308 00312 static void dcf_store(void) { 00313 if ((dcf_data.receiving_data.is_valid) 00314 && dcf_time_is_valid(&(dcf_data.receiving_data.time)) 00315 && dcf_date_is_valid(&(dcf_data.receiving_data.date))) { 00316 dcf_data.current_datetime_sample = 0; 00317 if (dcf_data.use_first_current_datetime) { 00318 dcf_data.current_datetime[1].time = dcf_data.receiving_data.time; 00319 dcf_data.current_datetime[1].date = dcf_data.receiving_data.date; 00320 dcf_data.current_datetime[1].is_valid = True; 00321 dcf_data.use_first_current_datetime = False; 00322 } else { 00323 dcf_data.current_datetime[0].time = dcf_data.receiving_data.time; 00324 dcf_data.current_datetime[0].date = dcf_data.receiving_data.date; 00325 dcf_data.current_datetime[0].is_valid = True; 00326 dcf_data.use_first_current_datetime = True; 00327 } 00328 } 00329 } 00330 00334 static void dcf_inc(void) { 00335 if (dcf_data.use_first_current_datetime) { 00336 dcf_data.current_datetime[1] = dcf_data.current_datetime[0]; 00337 dcf_datetime_inc(&(dcf_data.current_datetime[1])); 00338 dcf_data.use_first_current_datetime = False; 00339 } else { 00340 dcf_data.current_datetime[0] = dcf_data.current_datetime[1]; 00341 dcf_datetime_inc(&(dcf_data.current_datetime[0])); 00342 dcf_data.use_first_current_datetime = True; 00343 } 00344 } 00345 00346 /* 00347 exported functions, documented in header file 00348 */ 00349 00350 void dcf_init(void) { 00351 dcf_data.use_first_current_datetime = True; 00352 dcf_data.current_datetime_sample = 0; 00353 dcf_datetime_init(&(dcf_data.current_datetime[0])); 00354 dcf_datetime_init(&(dcf_data.current_datetime[1])); 00355 dcf_receiving_data_init(&(dcf_data.receiving_data)); 00356 } 00357 00358 void dcf_signal(boolean signal) { 00359 if (dcf_data.receiving_data.low_samples > dcf_second_samples) { 00360 if (dcf_data.receiving_data.time.second == 59) { 00361 dcf_data.receiving_data.time.second = 0; 00362 dcf_store(); 00363 } else { 00364 dcf_data.receiving_data.time.second = 0; 00365 } 00366 dcf_data.receiving_data.low_samples = 0; 00367 dcf_data.receiving_data.is_valid = True; 00368 } 00369 /* calculate receiving date time */ 00370 if (signal) { 00371 dcf_data.receiving_data.low_samples = 0; 00372 ++(dcf_data.receiving_data.high_samples); 00373 } else { 00374 ++(dcf_data.receiving_data.low_samples); 00375 if (dcf_data.receiving_data.high_samples == 0) { 00376 } else if (dcf_data.receiving_data.high_samples < dcf_logic_false_min) { 00377 /* too short signal */ 00378 dcf_data.receiving_data.is_valid = False; 00379 dcf_data.receiving_data.current_signal = dcf_signal_invalid; 00380 } else if (dcf_data.receiving_data.high_samples < dcf_logic_false_max) { 00381 /* short signal, logic 0 */ 00382 dcf_logic(False); 00383 dcf_data.receiving_data.current_signal = dcf_signal_false; 00384 } else if (dcf_data.receiving_data.high_samples < dcf_logic_true_min) { 00385 /* signal cannot be assigned to true or false */ 00386 dcf_data.receiving_data.is_valid = False; 00387 dcf_data.receiving_data.current_signal = dcf_signal_invalid; 00388 } else if (dcf_data.receiving_data.high_samples < dcf_logic_true_max) { 00389 /* long signal, logic 1 */ 00390 dcf_logic(True); 00391 dcf_data.receiving_data.current_signal = dcf_signal_true; 00392 } else { 00393 /* too long signal */ 00394 dcf_data.receiving_data.is_valid = False; 00395 dcf_data.receiving_data.current_signal = dcf_signal_invalid; 00396 } 00397 dcf_data.receiving_data.high_samples = 0; 00398 } 00399 /* calculate current date time */ 00400 ++(dcf_data.current_datetime_sample); 00401 if (dcf_data.current_datetime_sample == dcf_second_samples) { 00402 dcf_data.current_datetime_sample = 0; 00403 dcf_inc(); 00404 } 00405 } 00406 00407 dcf_datetime dcf_current_datetime(void) { 00408 if (dcf_data.use_first_current_datetime) { 00409 dcf_data.current_datetime[0].has_signal = dcf_data.receiving_data.is_valid; 00410 return dcf_data.current_datetime[0]; 00411 } else { 00412 dcf_data.current_datetime[1].has_signal = dcf_data.receiving_data.is_valid; 00413 return dcf_data.current_datetime[1]; 00414 } 00415 } 00416 00417 const char *dcf_dayofweek_name(dcf_dayofweek dow) { 00418 switch (dow) { 00419 case 1: 00420 return "Mo"; 00421 case 2: 00422 return "Tu"; 00423 case 3: 00424 return "We"; 00425 case 4: 00426 return "Th"; 00427 case 5: 00428 return "Fr"; 00429 case 6: 00430 return "Sa"; 00431 case 7: 00432 return "Su"; 00433 default: 00434 return "??"; 00435 } 00436 } 00437 00438 const char *dcf_is_dst_name(dcf_is_dst dst) { 00439 if (dst) { 00440 return "ST"; 00441 } else { 00442 return "WT"; 00443 } 00444 }