firmware/dcftime.c

Go to the documentation of this file.
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 }

Generated on Wed Jan 3 22:22:35 2007 for Binary DCF-77 Clock by  doxygen 1.5.1