00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00024 #include <avr/io.h>
00025 #include <avr/signal.h>
00026 #include <avr/interrupt.h>
00027 #include <avr/pgmspace.h>
00028 #include <avr/eeprom.h>
00029 #include <inttypes.h>
00030 #include "net/application.h"
00031 #include "main/dcf77.h"
00032 #include "utils.h"
00033
00034
00035
00036 # define __isleap(year) \
00037 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
00038
00039
00040 static prog_uchar __dom[2][12] = {
00041
00042 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00043
00044 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
00045 };
00046
00047
00048
00049
00050
00051
00052 #define TK_SET_TIME 0
00053 #define TK_GET_TIME 1
00054 #define TK_SET_UPDATE_INTERVAL 2
00055 #define TK_GET_UPDATE_INTERVAL 3
00056
00057
00058 #define TK_ON_UPDATE 0
00059
00060
00061 static param_desc_t tk_methods[] = {
00062 {sizeof(struct snt_time_stamp),0},
00063 {0,sizeof(struct snt_time_stamp)},
00064 {2,0},
00065 {0,2}};
00066 static param_desc_t tk_events[] = {{0,sizeof(struct snt_time_stamp)}};
00067
00068
00069 static void TimeKeeper_Callback(struct AppObject *self, uint8_t method, uint8_t *buf, uint8_t *result, uint8_t repeated);
00070
00071
00072 static struct AppObject timeKeeper = {
00073 tk_methods,
00074 tk_events,
00075 TimeKeeper_Callback
00076 };
00077 static uint8_t tk_id;
00078
00079
00080 static uint16_t ee_update_interval EEPROM;
00081 static uint16_t update_interval;
00082
00083
00084
00085
00086
00087
00088 static uint8_t analyze, valid;
00089 static uint8_t period;
00090 static uint8_t sec;
00091 static uint8_t buffer[8];
00092
00093
00094 static uint8_t gb_act, gb_index, gb_parity;
00095
00096
00097 static struct snt_time_stamp tel;
00098 static struct snt_time_stamp clock = {0, 0, 0, 1, 0, 1, 2000};
00099 static uint8_t sec10;
00100
00101
00102
00103 SIGNAL(SIG_OUTPUT_COMPARE1A)
00104 {
00105 uint8_t byte, bit;
00106
00107 period++;
00108 if (period == 13) {
00109
00110 valid = 0;
00111 sei();
00112
00113
00114
00115 if (sec < 64) {
00116 bit = 1 << (sec & 0x07);
00117 byte = sec >> 3;
00118 sec++;
00119
00120
00121 if (bit_is_set(PINE, PE7)) {
00122 buffer[byte] |= bit;
00123 } else {
00124 buffer[byte] &= ~bit;
00125 }
00126 }
00127 } else if (period == 150) {
00128
00129
00130
00131
00132 if (sec == 59) analyze = 1;
00133 sec = 0;
00134 }
00135 sei();
00136
00137
00138 sec10+=1;
00139 if (sec10 >= 100) {
00140 sec10 = 0;
00141 clock.second++;
00142
00143
00144 if (update_interval > 0) {
00145 update_interval--;
00146 if (update_interval == 0) {
00147 app_trigger_event(tk_id, TK_ON_UPDATE);
00148 update_interval = eeprom_read_word(&ee_update_interval);
00149 }
00150 }
00151
00152 if (clock.second >= 60) {
00153 clock.second = 0;
00154 clock.minute++;
00155 if (clock.minute >= 60) {
00156 clock.minute=0;
00157 clock.hour++;
00158 if (clock.hour >= 24) {
00159 clock.hour = 0;
00160 clock.day++;
00161 clock.dow = (clock.dow+1)%7;
00162 PGM_VOID_P dom = &__dom[__isleap(clock.year)?1:0][clock.month-1];
00163 if (clock.day > PRG_RDB(dom)) {
00164 clock.day = 1;
00165 clock.month++;
00166 if (clock.month > 12) {
00167 clock.month = 1;
00168 clock.year++;
00169 }
00170 }
00171 }
00172 }
00173 }
00174 }
00175 }
00176
00177
00178
00179 SIGNAL(SIG_INTERRUPT7)
00180 {
00181 if (period > 150) {
00182
00183 period = 0;
00184 sei();
00185
00186
00187 if (!valid) return;
00188
00189
00190 clock = tel;
00191 } else {
00192
00193 period = 0;
00194 }
00195 }
00196
00202 static uint8_t get_bit(void)
00203 {
00204 if ((gb_index & 0x07) == 0) {
00205 gb_act = buffer[gb_index >> 3];
00206 } else {
00207 gb_act >>= 1;
00208 }
00209 gb_index++;
00210
00211 gb_parity ^= (gb_act & 0x01);
00212 return gb_act & 0x01;
00213 }
00214
00224 static uint8_t read_bcd(uint8_t bits)
00225 {
00226 uint8_t value = 0;
00227 uint8_t i;
00228
00229 for (i=1; (i<=8)&&(bits>0); i<<=1, bits--) if (get_bit()) value += i;
00230 for (i=10; (i<=80)&&(bits>0); i<<=1, bits--) if (get_bit()) value += i;
00231 return value;
00232 }
00233
00242 void dcf_init(void)
00243 {
00244
00245 cli();
00246 OCR1A = 60000-1;
00247 sei();
00248 TCCR1A = 0x00;
00249 TCCR1B = _BV(CTC1) | _BV(CS10);
00250 TIMSK |= _BV(OCIE1A);
00251
00252
00253 EICR |= _BV(ISC71) | _BV(ISC70);
00254 EIMSK |= _BV(INT7);
00255
00256
00257 update_interval = eeprom_read_word(&ee_update_interval);
00258
00259
00260 tk_id = app_register_obj(&timeKeeper, 1);
00261 }
00262
00269 void dcf_process(void)
00270 {
00271 uint8_t i;
00272
00273
00274 if (!analyze) return;
00275 analyze = 0;
00276
00277
00278 gb_index = 0;
00279 valid = 0;
00280
00281 if (get_bit()) return;
00282 for (i=0; i<19; i++) get_bit();
00283 if (!get_bit()) return;
00284
00285
00286 gb_parity = 0;
00287 tel.minute = read_bcd(7);
00288 if (tel.minute > 59) return;
00289 get_bit();
00290 if (gb_parity) return;
00291
00292
00293 gb_parity = 0;
00294 tel.hour = read_bcd(6);
00295 if (tel.hour > 23) return;
00296 get_bit();
00297 if (gb_parity) return;
00298
00299
00300 gb_parity = 0;
00301 tel.day = read_bcd(6);
00302 if ((tel.day == 0) || (tel.day > 31)) return;
00303 tel.dow = read_bcd(3);
00304 if ((tel.dow == 0) || (tel.dow > 7)) return;
00305 tel.month = read_bcd(5);
00306 if ((tel.month == 0) || (tel.month > 12)) return;
00307 tel.year = read_bcd(8)+2000;
00308 get_bit();
00309 if (gb_parity) return;
00310
00311
00312 tel.dow--;
00313 valid = 1;
00314 }
00315
00321 void dcf_get_time(struct snt_time_stamp *time)
00322 {
00323 *time = clock;
00324 }
00325
00326 static void TimeKeeper_Callback(struct AppObject *self, uint8_t method, uint8_t *buf, uint8_t *result, uint8_t repeated)
00327 {
00328 switch (method) {
00329 case TK_SET_TIME:
00330 clock = *(struct snt_time_stamp*)buf;
00331 break;
00332 case TK_GET_TIME:
00333 case TK_ON_UPDATE|0x80:
00334 *(struct snt_time_stamp*)result = clock;
00335 break;
00336 case TK_SET_UPDATE_INTERVAL:
00337 update_interval = *(uint16_t*)buf;
00338 eeprom_write_word(&ee_update_interval, update_interval);
00339 break;
00340 case TK_GET_UPDATE_INTERVAL:
00341 *(uint16_t*)result = update_interval;
00342 break;
00343 }
00344 }