Mercurial > pihelp
annotate main.c @ 15:915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 13 Jun 2013 00:14:20 +0800 |
parents | aec45c673a60 |
children | 8b1aeff120e9 |
rev | line source |
---|---|
0 | 1 #include <stdio.h> |
2 #include <string.h> | |
3 #include <stddef.h> | |
4 #include <stdbool.h> | |
5 #include <stdlib.h> | |
6 #include <avr/io.h> | |
7 #include <avr/interrupt.h> | |
8 #include <avr/sleep.h> | |
9 #include <util/delay.h> | |
10 #include <avr/pgmspace.h> | |
11 #include <avr/eeprom.h> | |
12 #include <avr/wdt.h> | |
13 #include <util/atomic.h> | |
14 #include <util/crc16.h> | |
15 | |
2 | 16 #include "hmac-sha1.h" |
5 | 17 #include "aes.h" |
2 | 18 |
1 | 19 //#include "simple_ds18b20.h" |
20 //#include "onewire.h" | |
0 | 21 |
5 | 22 LOCKBITS = (LB_MODE_3 & BLB0_MODE_4 & BLB1_MODE_4); |
23 | |
0 | 24 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) |
25 #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) | |
26 | |
27 // TICK should be 8 or less (8 untested). all timers need | |
28 // to be a multiple. | |
29 | |
1 | 30 #define TICK 1 |
2 | 31 #define SLEEP_COMPARE (2000000/64) // == 31250 exactly |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
32 #define COUNTER_DIV (F_CPU / 2000000) |
5 | 33 #define NKEYS 10 |
34 #define HMACLEN 20 | |
35 #define AESLEN 16 | |
36 #define KEYLEN HMACLEN | |
1 | 37 |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
38 #define BAUD 38400 |
0 | 39 #define UBRR ((F_CPU)/8/(BAUD)-1) |
40 | |
2 | 41 #define PORT_PI_BOOT PORTD |
42 #define DDR_PI_BOOT DDRD | |
4 | 43 #define PIN_PI_BOOT PD5 |
2 | 44 |
45 #define PORT_PI_RESET PORTD | |
46 #define DDR_PI_RESET DDRD | |
47 #define PIN_PI_RESET PD6 | |
48 | |
4 | 49 #define PORT_LED PORTD |
50 #define DDR_LED DDRD | |
51 #define PIN_LED PD7 | |
0 | 52 |
53 // #define HAVE_UART_ECHO | |
54 | |
7 | 55 // stores a value of clock_epoch combined with the remainder of TCNT1, |
0 | 56 // for 1/32 second accuracy |
57 struct epoch_ticks | |
58 { | |
59 uint32_t ticks; | |
60 // remainder | |
61 uint8_t rem; | |
62 }; | |
63 | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
64 // OCR1A ticks COUNTER_DIV(=4) times a second, we divide it down. |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
65 static uint8_t counter_div = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
66 |
1 | 67 // eeprom-settable parameters, default values defined here. |
68 // all timeouts should be a multiple of TICK | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
69 static uint32_t watchdog_long_limit = (60L*60*24); // 6 hours |
1 | 70 static uint32_t watchdog_short_limit = 0; |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
71 static uint32_t newboot_limit = 60*10; // 10 minutes |
0 | 72 |
1 | 73 // avr proves itself |
2 | 74 static uint8_t avr_keys[NKEYS][KEYLEN] = {{0}}; |
0 | 75 |
76 // ---- Atomic guards required accessing these variables | |
77 // clock_epoch in seconds | |
78 static uint32_t clock_epoch; | |
1 | 79 // watchdog counts up |
80 static uint32_t watchdog_long_count; | |
81 static uint32_t watchdog_short_count; | |
2 | 82 // newboot counts down |
1 | 83 static uint32_t newboot_count; |
2 | 84 // oneshot counts down |
85 static uint32_t oneshot_count; | |
86 | |
0 | 87 // ---- End atomic guards required |
88 | |
89 // boolean flags | |
1 | 90 static uint8_t watchdog_long_hit; |
91 static uint8_t watchdog_short_hit; | |
92 static uint8_t newboot_hit; | |
2 | 93 static uint8_t oneshot_hit; |
0 | 94 |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
95 // flips between 0 and 1 each watchdog_long_hit, so eventually a |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
96 // working firmware should boot. set back to 0 for each 'alive' |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
97 // command |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
98 static uint8_t long_reboot_mode = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
99 |
0 | 100 static uint8_t readpos; |
1 | 101 static char readbuf[50]; |
0 | 102 static uint8_t have_cmd; |
103 | |
104 int uart_putchar(char c, FILE *stream); | |
105 static void long_delay(int ms); | |
106 static void blink(); | |
107 static uint16_t adc_vcc(); | |
2 | 108 static void set_pi_boot_normal(uint8_t normal); |
0 | 109 |
110 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, | |
111 _FDEV_SETUP_WRITE); | |
112 | |
113 // thanks to http://projectgus.com/2010/07/eeprom-access-with-arduino/ | |
114 #define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block((dst_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (dst_size)) | |
115 #define eeprom_read(dst, eeprom_field) eeprom_read_to((&dst), eeprom_field, sizeof(dst)) | |
116 #define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block((src_p), (void *)offsetof(struct __eeprom_data, eeprom_field), (src_size)) | |
117 #define eeprom_write(src, eeprom_field) { eeprom_write_from(&src, eeprom_field, sizeof(src)); } | |
118 | |
1 | 119 #define EXPECT_MAGIC 0xdf83 |
0 | 120 |
121 struct __attribute__ ((__packed__)) __eeprom_data { | |
1 | 122 uint32_t watchdog_long_limit; |
123 uint32_t watchdog_short_limit; | |
124 uint32_t newboot_limit; | |
0 | 125 |
2 | 126 uint8_t avr_keys[NKEYS][KEYLEN]; |
0 | 127 |
128 uint16_t magic; | |
129 }; | |
130 | |
131 // Very first setup | |
132 static void | |
133 setup_chip() | |
134 { | |
135 cli(); | |
136 | |
137 // stop watchdog timer (might have been used to cause a reset) | |
138 wdt_reset(); | |
139 MCUSR &= ~_BV(WDRF); | |
140 WDTCSR |= _BV(WDCE) | _BV(WDE); | |
141 WDTCSR = 0; | |
142 | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
143 // set to 8 seconds, in case sha1 is slow etc. |
1 | 144 wdt_enable(WDTO_8S); |
145 | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
146 // Set scaler to /1, -> clock to 8mhz |
0 | 147 CLKPR = _BV(CLKPCE); |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
148 CLKPR = 0; |
0 | 149 |
150 // enable pullups | |
1 | 151 // XXX matt pihelp |
5 | 152 //PORTB = 0xff; // XXX change when using SPI |
153 //PORTD = 0xff; | |
154 //PORTC = 0xff; | |
0 | 155 |
156 // 3.3v power for bluetooth and SD | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
157 //DDR_LED |= _BV(PIN_LED); |
0 | 158 |
5 | 159 #if 0 |
0 | 160 // set pullup |
161 PORTD |= _BV(PD2); | |
162 // INT0 setup | |
163 EICRA = (1<<ISC01); // falling edge - data sheet says it won't work? | |
164 EIMSK = _BV(INT0); | |
5 | 165 #endif |
0 | 166 |
167 // comparator disable | |
168 ACSR = _BV(ACD); | |
169 | |
170 // disable adc pin input buffers | |
171 DIDR0 = 0x3F; // acd0-adc5 | |
172 DIDR1 = (1<<AIN1D)|(1<<AIN0D); // ain0/ain1 | |
173 | |
174 sei(); | |
175 } | |
176 | |
177 static void | |
178 get_epoch_ticks(struct epoch_ticks *t) | |
179 { | |
180 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | |
181 { | |
182 t->ticks = clock_epoch; | |
7 | 183 t->rem = TCNT1; |
0 | 184 } |
185 } | |
186 | |
187 static void | |
188 setup_tick_counter() | |
189 { | |
2 | 190 // set up counter1 |
191 | |
0 | 192 // set up counter2. |
193 // COM21 COM20 Set OC2 on Compare Match (p116) | |
194 // WGM21 Clear counter on compare | |
195 //TCCR2A = _BV(COM2A1) | _BV(COM2A0) | _BV(WGM21); | |
196 // toggle on match | |
2 | 197 TCCR1A = _BV(COM1A0); |
8 | 198 #ifdef SIM_DEBUG |
199 // systemclock/8 | |
200 TCCR1B = _BV(CS11); | |
201 #else | |
7 | 202 // systemclock/64 |
203 TCCR1B = _BV(CS11) | _BV(CS10); | |
8 | 204 #endif |
2 | 205 TCNT1 = 0; |
206 OCR1A = SLEEP_COMPARE; | |
0 | 207 // interrupt |
2 | 208 TIMSK1 = _BV(OCIE1A); |
0 | 209 } |
210 | |
211 static void | |
212 uart_on() | |
213 { | |
214 // Power reduction register | |
215 PRR &= ~_BV(PRUSART0); | |
216 | |
217 // All of this needs to be done each time after turning off the PRR | |
218 // baud rate | |
219 UBRR0H = (unsigned char)(UBRR >> 8); | |
220 UBRR0L = (unsigned char)UBRR; | |
221 // set 2x clock, improves accuracy of UBRR | |
222 UCSR0A |= _BV(U2X0); | |
223 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); | |
224 //8N1 | |
225 UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); | |
226 } | |
227 | |
228 static void | |
229 uart_off() | |
230 { | |
231 // Turn off interrupts and disable tx/rx | |
232 UCSR0B = 0; | |
233 | |
234 // Power reduction register | |
235 PRR |= _BV(PRUSART0); | |
236 } | |
237 | |
238 int | |
239 uart_putchar(char c, FILE *stream) | |
240 { | |
241 // XXX could perhaps sleep in the loop for power. | |
242 if (c == '\n') | |
243 { | |
244 loop_until_bit_is_set(UCSR0A, UDRE0); | |
245 UDR0 = '\r'; | |
246 } | |
247 loop_until_bit_is_set(UCSR0A, UDRE0); | |
248 UDR0 = c; | |
249 if (c == '\r') | |
250 { | |
251 loop_until_bit_is_set(UCSR0A, UDRE0); | |
252 UDR0 = '\n'; | |
253 } | |
254 return (unsigned char)c; | |
255 } | |
256 | |
257 static void | |
258 cmd_reset() | |
259 { | |
260 printf_P(PSTR("reset\n")); | |
261 _delay_ms(100); | |
262 cli(); // disable interrupts | |
263 wdt_enable(WDTO_15MS); // enable watchdog | |
264 while(1); // wait for watchdog to reset processor | |
265 } | |
266 | |
2 | 267 static void |
268 cmd_newboot() | |
269 { | |
270 set_pi_boot_normal(1); | |
271 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | |
272 { | |
273 newboot_count = newboot_limit; | |
274 } | |
275 printf_P(PSTR("newboot for %d secs"), newboot_limit); | |
276 } | |
277 | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
278 static void |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
279 cmd_oldboot() |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
280 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
281 set_pi_boot_normal(0); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
282 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
283 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
284 newboot_count = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
285 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
286 printf_P(PSTR("back to old boot\n")); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
287 } |
1 | 288 |
0 | 289 |
290 static void | |
1 | 291 cmd_get_params() |
0 | 292 { |
2 | 293 uint32_t cur_watchdog_long, cur_watchdog_short, cur_newboot, cur_oneshot; |
1 | 294 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |
295 { | |
2 | 296 cur_watchdog_long = watchdog_long_count; |
297 cur_watchdog_short = watchdog_short_count; | |
298 cur_newboot = newboot_count; | |
299 cur_oneshot = oneshot_count; | |
1 | 300 } |
301 | |
2 | 302 printf_P(PSTR("limit (count) : watchdog_long %lu (%lu) watchdog_short %lu (%lu) newboot %lu (%lu) oneshot (%lu)\n"), |
1 | 303 watchdog_long_limit, |
2 | 304 cur_watchdog_long, |
1 | 305 watchdog_short_limit, |
2 | 306 cur_watchdog_short, |
1 | 307 newboot_limit, |
2 | 308 cur_newboot, |
309 cur_oneshot); | |
0 | 310 } |
311 | |
312 static void | |
1 | 313 cmd_set_params(const char *params) |
0 | 314 { |
1 | 315 uint32_t new_watchdog_long_limit; |
316 uint32_t new_watchdog_short_limit; | |
317 uint32_t new_newboot_limit; | |
318 | |
319 int ret = sscanf_P(params, PSTR("%lu %lu %lu"), | |
320 &new_watchdog_long_limit, | |
321 &new_watchdog_short_limit, | |
322 &new_newboot_limit); | |
323 | |
324 | |
325 if (ret != 3) | |
0 | 326 { |
1 | 327 printf_P(PSTR("Bad values\n")); |
328 } | |
329 else | |
330 { | |
331 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | |
332 { | |
333 eeprom_write(new_watchdog_long_limit, watchdog_long_limit); | |
334 eeprom_write(new_watchdog_short_limit, watchdog_short_limit); | |
335 eeprom_write(new_newboot_limit, newboot_limit); | |
336 uint16_t magic = EXPECT_MAGIC; | |
337 eeprom_write(magic, magic); | |
0 | 338 } |
1 | 339 printf_P(PSTR("set_params for next boot\n")); |
340 printf_P(PSTR("watchdog_long %lu watchdog_short %lu newboot %lu\n"), | |
341 new_watchdog_long_limit, | |
342 new_watchdog_short_limit, | |
343 new_newboot_limit); | |
344 | |
345 } | |
346 } | |
0 | 347 |
1 | 348 uint8_t from_hex(char c) |
349 { | |
350 if (c >= '0' && c <= '9') { | |
351 return c-'0'; | |
352 } | |
353 if (c >= 'a' && c <= 'f') { | |
354 return c-'a' + 0xa; | |
355 } | |
356 if (c >= 'A' && c <= 'F') { | |
357 return c-'A' + 0xa; | |
358 } | |
359 return 0; | |
360 } | |
361 | |
2 | 362 static void |
363 printhex_nibble(const unsigned char b, FILE *stream) | |
364 { | |
365 unsigned char c = b & 0x0f; | |
366 if ( c > 9 ) { | |
367 c += 'A'-10; | |
368 } | |
369 else { | |
370 c += '0'; | |
371 } | |
372 fputc(c, stream); | |
373 } | |
374 | |
375 void | |
376 printhex_byte(const unsigned char b, FILE *stream) | |
377 { | |
378 printhex_nibble( b >> 4, stream); | |
379 printhex_nibble( b, stream); | |
380 } | |
381 | |
382 void | |
383 printhex(uint8_t *id, uint8_t n, FILE *stream) | |
384 { | |
385 for (uint8_t i = 0; i < n; i++) | |
386 { | |
387 if (i > 0) | |
388 { | |
389 fputc(' ', stream); | |
390 } | |
391 printhex_byte(id[i], stream); | |
392 } | |
393 } | |
394 | |
395 static int8_t | |
5 | 396 parse_key(const char *params, uint8_t *key_index, uint8_t *bytes, |
397 uint8_t bytes_len) | |
2 | 398 { |
399 // "N HEXKEY" | |
5 | 400 if (strlen(params) != bytes_len*2 + 2) { |
2 | 401 printf_P(PSTR("Wrong length key\n")); |
402 return -1; | |
403 } | |
404 | |
405 if (params[1] != ' ') | |
406 { | |
407 printf_P(PSTR("Missing space\n")); | |
408 return -1; | |
409 } | |
410 | |
411 *key_index = from_hex(params[0]); | |
412 if (*key_index >= NKEYS) | |
413 { | |
414 printf_P(PSTR("Bad key index %d, max %d\n"), *key_index, NKEYS); | |
415 return -1; | |
416 } | |
417 | |
5 | 418 for (int i = 0, p = 0; i < bytes_len; i++, p += 2) |
2 | 419 { |
420 bytes[i] = (from_hex(params[p+2]) << 4) | from_hex(params[p+3]); | |
421 } | |
422 return 0; | |
423 } | |
424 | |
1 | 425 static void |
426 cmd_set_avr_key(const char *params) | |
427 { | |
2 | 428 uint8_t new_key[KEYLEN]; |
429 uint8_t key_index; | |
5 | 430 if (parse_key(params, &key_index, new_key, sizeof(new_key)) != 0) |
2 | 431 { |
1 | 432 return; |
0 | 433 } |
2 | 434 memcpy(avr_keys[key_index], new_key, sizeof(new_key)); |
8 | 435 #ifndef SIM_DEBUG |
2 | 436 eeprom_write(avr_keys, avr_keys); |
8 | 437 #endif |
2 | 438 } |
439 | |
440 static void | |
441 cmd_hmac(const char *params) | |
442 { | |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
443 uint8_t indata[2+HMACLEN] = {'H', ':'}; |
7 | 444 uint8_t outdata[HMACLEN]; |
2 | 445 uint8_t key_index; |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
446 if (parse_key(params, &key_index, &indata[2], HMACLEN) != 0) |
2 | 447 { |
448 printf_P(PSTR("FAIL: Bad input\n")); | |
5 | 449 return; |
2 | 450 } |
0 | 451 |
8 | 452 #ifndef SIM_DEBUG |
5 | 453 long_delay(200); |
8 | 454 #endif |
5 | 455 |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
456 hmac_sha1(outdata, avr_keys[key_index], KEYLEN*8, indata, sizeof(indata)*8); |
2 | 457 printf_P(PSTR("HMAC: ")); |
7 | 458 printhex(outdata, HMACLEN, stdout); |
5 | 459 fputc('\n', stdout); |
460 } | |
461 | |
462 static void | |
463 cmd_decrypt(const char *params) | |
464 { | |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
465 uint8_t indata[HMACLEN+AESLEN]; // XXX |
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
466 // a temporary buffer |
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
467 uint8_t output[HMACLEN] = {'D', ':'}; |
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
468 _Static_assert(AESLEN+2 <= sizeof(output), "sufficient output buffer"); |
5 | 469 uint8_t key_index; |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
470 if (parse_key(params, &key_index, indata, sizeof(indata)) != 0) |
5 | 471 { |
472 printf_P(PSTR("FAIL: Bad input\n")); | |
473 return; | |
474 } | |
475 | |
8 | 476 #ifndef SIM_DEBUG |
5 | 477 long_delay(200); |
8 | 478 #endif |
7 | 479 |
5 | 480 // check the signature |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
481 memcpy(&output[2], &indata[HMACLEN], AESLEN); |
12 | 482 hmac_sha1(output, avr_keys[key_index], KEYLEN*8, output, (2+AESLEN)*8); |
5 | 483 |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
484 if (memcmp(output, indata, HMACLEN) != 0) { |
5 | 485 printf_P(PSTR("FAIL: hmac mismatch\n")); |
486 } | |
487 | |
11
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
488 uint8_t tmpbuf[256]; |
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
489 aesInit(avr_keys[key_index], tmpbuf); |
e83b35e864d7
hmac and decrypt keys differ now
Matt Johnston <matt@ucc.asn.au>
parents:
8
diff
changeset
|
490 aesDecrypt(&indata[HMACLEN], NULL); |
5 | 491 |
492 printf_P(PSTR("DECRYPTED: ")); | |
493 printhex(output, AESLEN, stdout); | |
2 | 494 fputc('\n', stdout); |
495 } | |
496 | |
497 static void | |
498 cmd_oneshot_reboot(const char *params) | |
499 { | |
500 uint32_t new_delay = strtoul(params, NULL, 10); | |
501 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | |
1 | 502 { |
2 | 503 oneshot_count = new_delay; |
1 | 504 } |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
505 printf_P(PSTR("oneshot new delay %lu\n"), new_delay); |
0 | 506 } |
507 | |
508 static void | |
509 load_params() | |
510 { | |
511 uint16_t magic; | |
512 eeprom_read(magic, magic); | |
513 if (magic == EXPECT_MAGIC) | |
514 { | |
1 | 515 eeprom_read(watchdog_long_limit, watchdog_long_limit); |
516 eeprom_read(watchdog_short_limit, watchdog_short_limit); | |
2 | 517 eeprom_read(newboot_limit, newboot_limit); |
1 | 518 } |
2 | 519 |
520 eeprom_read(avr_keys, avr_keys); | |
0 | 521 } |
522 | |
2 | 523 static void |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
524 cmd_alive() |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
525 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
526 printf_P(PSTR("Ah, good.\n")); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
527 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
528 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
529 watchdog_long_count = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
530 watchdog_short_count = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
531 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
532 long_reboot_mode = 0; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
533 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
534 |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
535 static void |
2 | 536 cmd_vcc() |
0 | 537 { |
2 | 538 uint16_t vcc = adc_vcc(); |
12 | 539 printf_P(PSTR("vcc: %u mV\n"), vcc); |
0 | 540 } |
541 | |
542 static void | |
543 read_handler() | |
544 { | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
545 // TODO: make this an array, print automatic help |
2 | 546 if (strcmp_P(readbuf, PSTR("get_params")) == 0) |
0 | 547 { |
548 cmd_get_params(); | |
549 } | |
550 else if (strncmp_P(readbuf, PSTR("set_params "), 11) == 0) | |
551 { | |
552 cmd_set_params(&readbuf[11]); | |
553 } | |
2 | 554 else if (strncmp_P(readbuf, PSTR("set_key "), 8) == 0) |
0 | 555 { |
2 | 556 cmd_set_avr_key(&readbuf[8]); |
0 | 557 } |
2 | 558 else if (strncmp_P(readbuf, PSTR("oneshot "), 8) == 0) |
0 | 559 { |
2 | 560 cmd_oneshot_reboot(&readbuf[8]); |
0 | 561 } |
2 | 562 else if (strncmp_P(readbuf, PSTR("hmac "), 5) == 0) |
0 | 563 { |
2 | 564 cmd_hmac(&readbuf[5]); |
0 | 565 } |
5 | 566 else if (strncmp_P(readbuf, PSTR("decrypt "), 8) == 0) |
567 { | |
12 | 568 cmd_decrypt(&readbuf[8]); |
5 | 569 } |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
570 else if (strcmp_P(readbuf, PSTR("alive")) == 0) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
571 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
572 cmd_alive(); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
573 } |
2 | 574 else if (strcmp_P(readbuf, PSTR("vcc")) == 0) |
0 | 575 { |
2 | 576 cmd_vcc(); |
0 | 577 } |
578 else if (strcmp_P(readbuf, PSTR("reset")) == 0) | |
579 { | |
580 cmd_reset(); | |
581 } | |
4 | 582 else if (strcmp_P(readbuf, PSTR("newboot")) == 0) |
583 { | |
584 cmd_newboot(); | |
585 } | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
586 else if (strcmp_P(readbuf, PSTR("oldboot")) == 0) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
587 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
588 cmd_oldboot(); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
589 } |
0 | 590 else |
591 { | |
592 printf_P(PSTR("Bad command '%s'\n"), readbuf); | |
593 } | |
594 } | |
595 | |
596 ISR(INT0_vect) | |
597 { | |
598 blink(); | |
599 _delay_ms(100); | |
600 blink(); | |
601 } | |
602 | |
603 ISR(USART_RX_vect) | |
604 { | |
605 char c = UDR0; | |
606 #ifdef HAVE_UART_ECHO | |
607 uart_putchar(c, NULL); | |
608 #endif | |
609 if (c == '\r' || c == '\n') | |
610 { | |
611 if (readpos > 0) | |
612 { | |
613 readbuf[readpos] = '\0'; | |
614 have_cmd = 1; | |
615 readpos = 0; | |
616 } | |
617 } | |
618 else | |
619 { | |
620 readbuf[readpos] = c; | |
621 readpos++; | |
622 if (readpos >= sizeof(readbuf)) | |
623 { | |
624 readpos = 0; | |
625 } | |
626 } | |
627 } | |
628 | |
2 | 629 ISR(TIMER1_COMPA_vect) |
0 | 630 { |
2 | 631 TCNT1 = 0; |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
632 counter_div++; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
633 if (counter_div < COUNTER_DIV) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
634 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
635 return; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
636 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
637 counter_div = 0; |
0 | 638 |
639 clock_epoch += TICK; | |
640 | |
1 | 641 // watchdogs count up, continuous |
642 if (watchdog_long_limit > 0) { | |
2 | 643 watchdog_long_count += TICK; |
1 | 644 if (watchdog_long_count >= watchdog_long_limit) |
645 { | |
646 watchdog_long_count = 0; | |
647 watchdog_long_hit = 1; | |
648 } | |
0 | 649 } |
650 | |
1 | 651 if (watchdog_short_limit > 0) { |
2 | 652 watchdog_short_count += TICK; |
1 | 653 if (watchdog_short_count >= watchdog_short_limit) |
654 { | |
655 watchdog_short_count = 0; | |
656 watchdog_short_hit = 1; | |
657 } | |
0 | 658 } |
659 | |
2 | 660 // newboot counts down |
1 | 661 if (newboot_count > 0) |
0 | 662 { |
2 | 663 newboot_count-=TICK; |
664 if (newboot_count <= 0) | |
1 | 665 { |
666 newboot_hit = 1; | |
2 | 667 newboot_count = 0; |
1 | 668 } |
0 | 669 } |
1 | 670 |
2 | 671 if (oneshot_count > 0) |
672 { | |
673 oneshot_count-=TICK; | |
674 if (oneshot_count <= 0) | |
675 { | |
676 oneshot_hit = 1; | |
677 oneshot_count = 0; | |
678 } | |
679 } | |
0 | 680 } |
681 | |
682 static void | |
683 idle_sleep() | |
684 { | |
685 set_sleep_mode(SLEEP_MODE_IDLE); | |
686 sleep_mode(); | |
687 } | |
688 | |
689 static uint16_t | |
690 adc_vcc() | |
691 { | |
692 PRR &= ~_BV(PRADC); | |
693 | |
694 // /16 prescaler | |
695 ADCSRA = _BV(ADEN) | _BV(ADPS2); | |
696 | |
697 // set to measure 1.1 reference | |
698 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
699 // average a number of samples | |
700 uint16_t sum = 0; | |
701 uint8_t num = 0; | |
702 for (uint8_t n = 0; n < 20; n++) | |
703 { | |
704 ADCSRA |= _BV(ADSC); | |
705 loop_until_bit_is_clear(ADCSRA, ADSC); | |
706 | |
707 uint8_t low_11 = ADCL; | |
708 uint8_t high_11 = ADCH; | |
709 uint16_t val = low_11 + (high_11 << 8); | |
710 | |
711 if (n >= 4) | |
712 { | |
713 sum += val; | |
714 num++; | |
715 } | |
716 } | |
717 ADCSRA = 0; | |
718 PRR |= _BV(PRADC); | |
719 | |
720 //float res_volts = 1.1 * 1024 * num / sum; | |
721 //return 1000 * res_volts; | |
722 return ((uint32_t)1100*1024*num) / sum; | |
723 } | |
724 | |
725 static void | |
2 | 726 reboot_pi() |
727 { | |
728 // pull it low for 30ms | |
729 PORT_PI_RESET &= ~_BV(PIN_PI_RESET); | |
730 DDR_PI_RESET |= _BV(PIN_PI_RESET); | |
731 _delay_ms(30); | |
732 DDR_PI_RESET &= ~_BV(PIN_PI_RESET); | |
733 } | |
734 | |
735 static void | |
736 set_pi_boot_normal(uint8_t normal) | |
737 { | |
738 PORT_PI_BOOT &= ~_BV(PIN_PI_BOOT); | |
739 if (normal) | |
740 { | |
741 // tristate | |
742 DDR_PI_BOOT &= ~_BV(PIN_PI_BOOT); | |
743 } | |
744 else | |
745 { | |
746 // pull it low | |
747 DDR_PI_RESET |= _BV(PIN_PI_BOOT); | |
748 | |
749 } | |
750 } | |
751 | |
752 static void | |
753 check_flags() | |
754 { | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
755 if (watchdog_long_hit) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
756 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
757 // alternate between booting normal and emergency |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
758 if (long_reboot_mode) |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
759 { |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
760 cmd_newboot(); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
761 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
762 long_reboot_mode ^= 1; |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
763 } |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
764 |
2 | 765 if (watchdog_long_hit |
766 || watchdog_short_hit | |
767 || oneshot_hit) | |
768 { | |
12 | 769 printf_P(PSTR("Rebooting! long %d, short %d, oneshot %d\n"), |
770 watchdog_long_hit, watchdog_short_hit, oneshot_hit); | |
771 long_delay(300); | |
2 | 772 reboot_pi(); |
773 } | |
774 | |
775 if (newboot_hit) { | |
776 set_pi_boot_normal(0); | |
777 } | |
778 | |
779 watchdog_long_hit = 0; | |
780 watchdog_short_hit = 0; | |
781 newboot_hit = 0; | |
782 oneshot_hit = 0; | |
783 } | |
784 | |
785 static void | |
0 | 786 do_comms() |
787 { | |
788 // avoid receiving rubbish, perhaps | |
789 uart_on(); | |
790 | |
791 // write sd card here? same 3.3v regulator... | |
792 | |
1 | 793 while (1) |
0 | 794 { |
1 | 795 wdt_reset(); |
2 | 796 |
797 check_flags(); | |
798 | |
0 | 799 if (have_cmd) |
800 { | |
801 have_cmd = 0; | |
802 read_handler(); | |
803 continue; | |
804 } | |
805 | |
806 // wait for commands from the master | |
807 idle_sleep(); | |
808 } | |
809 } | |
810 | |
811 static void | |
812 blink() | |
813 { | |
814 PORT_LED &= ~_BV(PIN_LED); | |
815 _delay_ms(1); | |
816 PORT_LED |= _BV(PIN_LED); | |
817 } | |
818 | |
819 static void | |
820 long_delay(int ms) | |
821 { | |
822 int iter = ms / 100; | |
823 | |
824 for (int i = 0; i < iter; i++) | |
825 { | |
826 _delay_ms(100); | |
827 } | |
828 } | |
829 | |
830 ISR(BADISR_vect) | |
831 { | |
832 //uart_on(); | |
833 printf_P(PSTR("Bad interrupt\n")); | |
834 } | |
835 | |
836 int main(void) | |
837 { | |
15
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
838 _Static_assert(F_CPU % 2000000 == 0, "F_CPU is a multiple of 2mhz for counter division"); |
915be6f0ff13
fix for 8mhz, add flip/flop long watchdog
Matt Johnston <matt@ucc.asn.au>
parents:
12
diff
changeset
|
839 |
0 | 840 setup_chip(); |
841 blink(); | |
842 | |
843 stdout = &mystdout; | |
844 uart_on(); | |
845 | |
12 | 846 printf_P(PSTR("Pi Watchdog\nMatt Johnston [email protected]")); |
0 | 847 |
2 | 848 set_pi_boot_normal(0); |
849 | |
0 | 850 load_params(); |
851 | |
852 setup_tick_counter(); | |
853 | |
854 sei(); | |
855 | |
8 | 856 #if 0 |
857 // encryption test | |
858 cmd_set_avr_key("1 6161626263636464656566666767686800000000"); | |
859 cmd_set_avr_key("2 7979757569696f6f646465656666717164646969"); | |
12 | 860 //cmd_decrypt("1 ecd858ee07a8e16575723513d2d072a7565865e40ba302059bfc650d4491268448102119"); |
861 cmd_decrypt("1 5a587b50fd48688bbda1b510cf9a3fab6fd4737b" "0ba302059bfc650d4491268448102119"); | |
862 cmd_hmac("2 7979757569696f6f646465656666717164646969"); | |
8 | 863 #endif |
864 | |
1 | 865 // doesn't return |
866 do_comms(); | |
0 | 867 |
868 return 0; /* never reached */ | |
869 } |