comparison main.c @ 18:021e6e0006f4

debug printing, 5v adc, fixes
author Matt Johnston <matt@ucc.asn.au>
date Thu, 13 Jun 2013 23:44:59 +0800
parents 21717153e0f1
children 5f9a40d6991b bc48a1d17edf
comparison
equal deleted inserted replaced
17:21717153e0f1 18:021e6e0006f4
32 #define NKEYS 10 32 #define NKEYS 10
33 #define HMACLEN 20 33 #define HMACLEN 20
34 #define AESLEN 16 34 #define AESLEN 16
35 #define KEYLEN HMACLEN 35 #define KEYLEN HMACLEN
36 36
37 #define BAUD 38400 37 #define BAUD 19200
38 #define UBRR ((F_CPU)/8/(BAUD)-1) 38 #define UBRR ((F_CPU)/8/(BAUD)-1)
39 39
40 #define PORT_PI_BOOT PORTD 40 #define PORT_PI_BOOT PORTD
41 #define DDR_PI_BOOT DDRD 41 #define DDR_PI_BOOT DDRD
42 #define PIN_PI_BOOT PD5 42 #define PIN_PI_BOOT PD5
43 43
44 #define PORT_PI_RESET PORTD 44 #define PORT_PI_RESET PORTD
45 #define DDR_PI_RESET DDRD 45 #define DDR_PI_RESET DDRD
46 #define PIN_PI_RESET PD6 46 #define PIN_PI_RESET PD6
47 47
48 #define PORT_LED PORTD 48 #define PORT_PI_WARNING PORTD
49 #define DDR_LED DDRD 49 #define DDR_PI_WARNING DDRD
50 #define PIN_LED PD7 50 #define PIN_PI_WARNING PD7
51 51
52 // #define HAVE_UART_ECHO 52 // #define HAVE_UART_ECHO
53 53
54 // stores a value of clock_epoch combined with the remainder of TCNT1, 54 // stores a value of clock_epoch combined with the remainder of TCNT1,
55 // for 1/32 second accuracy 55 // for 1/32 second accuracy
67 #define WATCHDOG_SHORT_MIN (60L*15) // 15 mins 67 #define WATCHDOG_SHORT_MIN (60L*15) // 15 mins
68 68
69 #define NEWBOOT_DEFAULT (60*10) // 10 minutes 69 #define NEWBOOT_DEFAULT (60*10) // 10 minutes
70 #define NEWBOOT_MIN (60*2) // 2 minutes 70 #define NEWBOOT_MIN (60*2) // 2 minutes
71 #define NEWBOOT_MAX (60*30) // 30 mins 71 #define NEWBOOT_MAX (60*30) // 30 mins
72
73 #define WARNING_TIME 10
72 74
73 // eeprom-settable parameters, default values defined here. 75 // eeprom-settable parameters, default values defined here.
74 // all timeouts should be a multiple of TICK 76 // all timeouts should be a multiple of TICK
75 static uint32_t watchdog_long_limit = WATCHDOG_LONG_DEFAULT; 77 static uint32_t watchdog_long_limit = WATCHDOG_LONG_DEFAULT;
76 static uint32_t watchdog_short_limit = 0; 78 static uint32_t watchdog_short_limit = 0;
87 static uint32_t watchdog_short_count; 89 static uint32_t watchdog_short_count;
88 // newboot counts down 90 // newboot counts down
89 static uint32_t newboot_count; 91 static uint32_t newboot_count;
90 // oneshot counts down 92 // oneshot counts down
91 static uint32_t oneshot_count; 93 static uint32_t oneshot_count;
94 // countdown after the warning.
95 static uint8_t reboot_count;
92 96
93 // ---- End atomic guards required 97 // ---- End atomic guards required
94 98
95 // boolean flags 99 // boolean flags
96 static uint8_t watchdog_long_hit; 100 static uint8_t watchdog_long_hit;
97 static uint8_t watchdog_short_hit; 101 static uint8_t watchdog_short_hit;
98 static uint8_t newboot_hit; 102 static uint8_t newboot_hit;
99 static uint8_t oneshot_hit; 103 static uint8_t oneshot_hit;
104 static uint8_t reboot_hit;
100 105
101 // flips between 0 and 1 each watchdog_long_hit, so eventually a 106 // flips between 0 and 1 each watchdog_long_hit, so eventually a
102 // working firmware should boot. set back to 0 for each 'alive' 107 // working firmware should boot. set back to 0 for each 'alive'
103 // command 108 // command
104 static uint8_t long_reboot_mode = 0; 109 static uint8_t long_reboot_mode = 0;
109 114
110 int uart_putchar(char c, FILE *stream); 115 int uart_putchar(char c, FILE *stream);
111 static void long_delay(int ms); 116 static void long_delay(int ms);
112 static void blink(); 117 static void blink();
113 static uint16_t adc_vcc(); 118 static uint16_t adc_vcc();
119 static uint16_t adc_5v(uint16_t vcc);
114 static void set_pi_boot_normal(uint8_t normal); 120 static void set_pi_boot_normal(uint8_t normal);
115 121
116 122
117 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, 123 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
118 _FDEV_SETUP_WRITE); 124 _FDEV_SETUP_WRITE);
158 // XXX matt pihelp 164 // XXX matt pihelp
159 //PORTB = 0xff; // XXX change when using SPI 165 //PORTB = 0xff; // XXX change when using SPI
160 //PORTD = 0xff; 166 //PORTD = 0xff;
161 //PORTC = 0xff; 167 //PORTC = 0xff;
162 168
163 // 3.3v power for bluetooth and SD 169 DDR_PI_WARNING |= _BV(PIN_PI_WARNING);
164 //DDR_LED |= _BV(PIN_LED);
165 170
166 #if 0 171 #if 0
167 // set pullup 172 // set pullup
168 PORTD |= _BV(PD2); 173 PORTD |= _BV(PD2);
169 // INT0 setup 174 // INT0 setup
223 228
224 // All of this needs to be done each time after turning off the PRR 229 // All of this needs to be done each time after turning off the PRR
225 // baud rate 230 // baud rate
226 UBRR0H = (unsigned char)(UBRR >> 8); 231 UBRR0H = (unsigned char)(UBRR >> 8);
227 UBRR0L = (unsigned char)UBRR; 232 UBRR0L = (unsigned char)UBRR;
228 // set 2x clock, improves accuracy of UBRR
229 UCSR0A |= _BV(U2X0);
230 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0); 233 UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
231 //8N1 234 //8N1
232 UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); 235 UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
233 } 236 }
234 237
238 #ifdef SIM_DEBUG
239 static char sim_out[140];
240 static uint8_t sim_idx = 0;
241 static uint8_t last_sim_idx = 0;
242 #endif
243
235 int 244 int
236 uart_putchar(char c, FILE *stream) 245 uart_putchar(char c, FILE *stream)
237 { 246 {
238 // XXX could perhaps sleep in the loop for power. 247 // XXX could perhaps sleep in the loop for power.
239 if (c == '\n') 248 if (c == '\n')
241 loop_until_bit_is_set(UCSR0A, UDRE0); 250 loop_until_bit_is_set(UCSR0A, UDRE0);
242 UDR0 = '\r'; 251 UDR0 = '\r';
243 } 252 }
244 loop_until_bit_is_set(UCSR0A, UDRE0); 253 loop_until_bit_is_set(UCSR0A, UDRE0);
245 UDR0 = c; 254 UDR0 = c;
255 #ifdef SIM_DEBUG
256 sim_out[sim_idx] = c;
257 sim_idx++;
258 sim_idx %= sizeof(sim_out);
259 #endif
246 if (c == '\r') 260 if (c == '\r')
247 { 261 {
248 loop_until_bit_is_set(UCSR0A, UDRE0); 262 loop_until_bit_is_set(UCSR0A, UDRE0);
249 UDR0 = '\n'; 263 UDR0 = '\n';
250 } 264 }
316 int ret = sscanf_P(params, PSTR("%lu %lu %lu"), 330 int ret = sscanf_P(params, PSTR("%lu %lu %lu"),
317 &new_watchdog_long_limit, 331 &new_watchdog_long_limit,
318 &new_watchdog_short_limit, 332 &new_watchdog_short_limit,
319 &new_newboot_limit); 333 &new_newboot_limit);
320 334
321
322 if (ret != 3) 335 if (ret != 3)
323 { 336 {
324 printf_P(PSTR("Bad values\n")); 337 printf_P(PSTR("Bad values\n"));
325 } 338 }
326 else 339 else
336 printf_P(PSTR("set_params for next boot\n")); 349 printf_P(PSTR("set_params for next boot\n"));
337 printf_P(PSTR("watchdog_long %lu watchdog_short %lu newboot %lu\n"), 350 printf_P(PSTR("watchdog_long %lu watchdog_short %lu newboot %lu\n"),
338 new_watchdog_long_limit, 351 new_watchdog_long_limit,
339 new_watchdog_short_limit, 352 new_watchdog_short_limit,
340 new_newboot_limit); 353 new_newboot_limit);
341
342 } 354 }
343 } 355 }
344 356
345 uint8_t from_hex(char c) 357 uint8_t from_hex(char c)
346 { 358 {
379 void 391 void
380 printhex(uint8_t *id, uint8_t n, FILE *stream) 392 printhex(uint8_t *id, uint8_t n, FILE *stream)
381 { 393 {
382 for (uint8_t i = 0; i < n; i++) 394 for (uint8_t i = 0; i < n; i++)
383 { 395 {
384 if (i > 0)
385 {
386 fputc(' ', stream);
387 }
388 printhex_byte(id[i], stream); 396 printhex_byte(id[i], stream);
389 } 397 }
390 } 398 }
391 399
392 static int8_t 400 static int8_t
501 } 509 }
502 printf_P(PSTR("oneshot new delay %lu\n"), new_delay); 510 printf_P(PSTR("oneshot new delay %lu\n"), new_delay);
503 } 511 }
504 512
505 static void 513 static void
514 clamp_params()
515 {
516 if (watchdog_long_limit < WATCHDOG_LONG_MIN
517 || watchdog_long_limit > WATCHDOG_LONG_MAX)
518 {
519 watchdog_long_limit = WATCHDOG_LONG_DEFAULT;
520 }
521
522 if (watchdog_short_limit != 0
523 && watchdog_short_limit < WATCHDOG_SHORT_MIN)
524 {
525 watchdog_short_limit = 0;
526 }
527
528 if (newboot_limit < NEWBOOT_MIN || newboot_limit > NEWBOOT_MAX)
529 {
530 newboot_limit = NEWBOOT_DEFAULT;
531 }
532 }
533
534 static void
506 load_params() 535 load_params()
507 { 536 {
508 uint16_t magic; 537 uint16_t magic;
509 eeprom_read(magic, magic); 538 eeprom_read(magic, magic);
510 if (magic == EXPECT_MAGIC) 539 if (magic == EXPECT_MAGIC)
512 eeprom_read(watchdog_long_limit, watchdog_long_limit); 541 eeprom_read(watchdog_long_limit, watchdog_long_limit);
513 eeprom_read(watchdog_short_limit, watchdog_short_limit); 542 eeprom_read(watchdog_short_limit, watchdog_short_limit);
514 eeprom_read(newboot_limit, newboot_limit); 543 eeprom_read(newboot_limit, newboot_limit);
515 } 544 }
516 545
517 if (watchdog_long_limit < WATCHDOG_LONG_MIN 546 clamp_params();
518 || watchdog_long_limit > WATCHDOG_LONG_MAX)
519 {
520 watchdog_long_limit = WATCHDOG_LONG_DEFAULT;
521 }
522
523 if (watchdog_short_limit != 0
524 && watchdog_short_limit < WATCHDOG_SHORT_MIN)
525 {
526 watchdog_short_limit = 0;
527 }
528
529 if (newboot_limit < NEWBOOT_MIN || newboot_limit > NEWBOOT_MAX)
530 {
531 newboot_limit = NEWBOOT_DEFAULT;
532 }
533
534 547
535 eeprom_read(avr_keys, avr_keys); 548 eeprom_read(avr_keys, avr_keys);
536 } 549 }
537 550
538 static void 551 static void
549 562
550 static void 563 static void
551 cmd_vcc() 564 cmd_vcc()
552 { 565 {
553 uint16_t vcc = adc_vcc(); 566 uint16_t vcc = adc_vcc();
554 printf_P(PSTR("vcc: %u mV\n"), vcc); 567 uint16_t v5 = adc_5v(vcc);
568 printf_P(PSTR("vcc: %u mV\n5v: %u mV\n"), vcc, v5);
555 } 569 }
556 570
557 static void 571 static void
558 read_handler() 572 read_handler()
559 { 573 {
571 LOCAL_PSTR(reset); 585 LOCAL_PSTR(reset);
572 LOCAL_PSTR(newboot); 586 LOCAL_PSTR(newboot);
573 LOCAL_PSTR(oldboot); 587 LOCAL_PSTR(oldboot);
574 LOCAL_HELP(set_params, "<long_limit> <short_limit> <newboot_limit>"); 588 LOCAL_HELP(set_params, "<long_limit> <short_limit> <newboot_limit>");
575 LOCAL_HELP(set_key, "20_byte_hex>"); 589 LOCAL_HELP(set_key, "20_byte_hex>");
576 LOCAL_HELP(timeout, "<timeout>"); 590 LOCAL_HELP(oneshot, "<timeout>");
577 LOCAL_HELP(hmac, "<key_index> <20_byte_hex_data>"); 591 LOCAL_HELP(hmac, "<key_index> <20_byte_hex_data>");
578 LOCAL_HELP(decrypt, "<key_index> <20_byte_hmac|16_byte_aes_block>"); 592 LOCAL_HELP(decrypt, "<key_index> <20_byte_hmac|16_byte_aes_block>");
579 593
580 static const struct handler { 594 static const struct handler {
581 PGM_P name; 595 PGM_P name;
585 } handlers[11] PROGMEM = 599 } handlers[11] PROGMEM =
586 { 600 {
587 {get_params_str, cmd_get_params, NULL}, 601 {get_params_str, cmd_get_params, NULL},
588 {set_params_str, cmd_set_params, set_params_help}, 602 {set_params_str, cmd_set_params, set_params_help},
589 {set_key_str, cmd_set_avr_key, set_key_help}, 603 {set_key_str, cmd_set_avr_key, set_key_help},
590 {oneshot_str, cmd_oneshot_reboot, timeout_help}, 604 {oneshot_str, cmd_oneshot_reboot, oneshot_help},
591 {hmac_str, cmd_hmac, hmac_help}, 605 {hmac_str, cmd_hmac, hmac_help},
592 {decrypt_str, cmd_decrypt, decrypt_help}, 606 {decrypt_str, cmd_decrypt, decrypt_help},
593 {alive_str, cmd_alive, NULL}, 607 {alive_str, cmd_alive, NULL},
594 {vcc_str, cmd_vcc, NULL}, 608 {vcc_str, cmd_vcc, NULL},
595 {reset_str, cmd_reset, NULL}, 609 {reset_str, cmd_reset, NULL},
600 if (readbuf[0] == '\0') 614 if (readbuf[0] == '\0')
601 { 615 {
602 return; 616 return;
603 } 617 }
604 618
605 if (strcmp_P(readbuf, PSTR("help"))) 619 if (strcmp_P(readbuf, PSTR("help")) == 0)
606 { 620 {
607 printf_P(PSTR("Commands:---\n")); 621 printf_P(PSTR("Commands:---\n"));
608 for (int i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) 622 for (int i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++)
609 { 623 {
610 struct handler h; 624 struct handler h;
616 printf_P(h.arg_help); 630 printf_P(h.arg_help);
617 } 631 }
618 putchar('\n'); 632 putchar('\n');
619 }; 633 };
620 printf_P(PSTR("---\n")); 634 printf_P(PSTR("---\n"));
635 return;
621 } 636 }
622 637
623 for (int i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++) 638 for (int i = 0; i < sizeof(handlers) / sizeof(handlers[0]); i++)
624 { 639 {
625 struct handler h; 640 struct handler h;
630 { 645 {
631 if (h.arg_help) 646 if (h.arg_help)
632 { 647 {
633 if (readbuf[h_len] == ' ') 648 if (readbuf[h_len] == ' ')
634 { 649 {
635 void(*cmd)(const char*) = (void*)pgm_read_word(h.cmd); 650 h.cmd(&readbuf[h_len+1]);
636 cmd(&readbuf[h_len+1]);
637 return; 651 return;
638 } 652 }
639 } 653 }
640 else 654 else
641 { 655 {
642 if (readbuf[h_len] == '\0') 656 if (readbuf[h_len] == '\0')
643 { 657 {
644 void(*void_cmd)() = (void*)pgm_read_word(h.cmd); 658 void(*void_cmd)() = h.cmd;
645 void_cmd(); 659 void_cmd();
646 return; 660 return;
647 } 661 }
648 } 662 }
649 } 663 }
650 } 664 }
651
652 #if 0
653 // TODO: make this an array, print automatic help
654 if (strcmp_P(readbuf, PSTR("get_params")) == 0)
655 {
656 cmd_get_params();
657 }
658 else if (strncmp_P(readbuf, PSTR("set_params "), 11) == 0)
659 {
660 cmd_set_params(&readbuf[11]);
661 }
662 else if (strncmp_P(readbuf, PSTR("set_key "), 8) == 0)
663 {
664 cmd_set_avr_key(&readbuf[8]);
665 }
666 else if (strncmp_P(readbuf, PSTR("oneshot "), 8) == 0)
667 {
668 cmd_oneshot_reboot(&readbuf[8]);
669 }
670 else if (strncmp_P(readbuf, PSTR("hmac "), 5) == 0)
671 {
672 cmd_hmac(&readbuf[5]);
673 }
674 else if (strncmp_P(readbuf, PSTR("decrypt "), 8) == 0)
675 {
676 cmd_decrypt(&readbuf[8]);
677 }
678 else if (strcmp_P(readbuf, PSTR("alive")) == 0)
679 {
680 cmd_alive();
681 }
682 else if (strcmp_P(readbuf, PSTR("vcc")) == 0)
683 {
684 cmd_vcc();
685 }
686 else if (strcmp_P(readbuf, PSTR("reset")) == 0)
687 {
688 cmd_reset();
689 }
690 else if (strcmp_P(readbuf, PSTR("newboot")) == 0)
691 {
692 cmd_newboot();
693 }
694 else if (strcmp_P(readbuf, PSTR("oldboot")) == 0)
695 {
696 cmd_oldboot();
697 }
698 else
699
700 #endif
701 665
702 printf_P(PSTR("Bad command '%s'\n"), readbuf); 666 printf_P(PSTR("Bad command '%s'\n"), readbuf);
703 } 667 }
704 668
705 ISR(INT0_vect) 669 ISR(INT0_vect)
776 oneshot_count-=TICK; 740 oneshot_count-=TICK;
777 if (oneshot_count <= 0) 741 if (oneshot_count <= 0)
778 { 742 {
779 oneshot_hit = 1; 743 oneshot_hit = 1;
780 oneshot_count = 0; 744 oneshot_count = 0;
745 }
746 }
747
748 if (reboot_count > 0)
749 {
750 reboot_count -= TICK;
751 if (reboot_count <= 0)
752 {
753 reboot_hit = 1;
754 reboot_count = 0;
781 } 755 }
782 } 756 }
783 } 757 }
784 758
785 static void 759 static void
823 //float res_volts = 1.1 * 1024 * num / sum; 797 //float res_volts = 1.1 * 1024 * num / sum;
824 //return 1000 * res_volts; 798 //return 1000 * res_volts;
825 return ((uint32_t)1100*1024*num) / sum; 799 return ((uint32_t)1100*1024*num) / sum;
826 } 800 }
827 801
802 #define SCALER_5V 2
803
804 static uint16_t
805 adc_5v(uint16_t vcc)
806 {
807 PRR &= ~_BV(PRADC);
808
809 // /16 prescaler
810 ADCSRA = _BV(ADEN) | _BV(ADPS2);
811
812 // set to measure ADC4 against AVCC
813 ADMUX = _BV(REFS0) | _BV(MUX2);
814 // average a number of samples
815 uint16_t sum = 0;
816 uint8_t num = 0;
817 for (uint8_t n = 0; n < 20; n++)
818 {
819 ADCSRA |= _BV(ADSC);
820 loop_until_bit_is_clear(ADCSRA, ADSC);
821
822 uint8_t low_11 = ADCL;
823 uint8_t high_11 = ADCH;
824 uint16_t val = low_11 + (high_11 << 8);
825
826 if (n >= 4)
827 {
828 sum += val;
829 num++;
830 }
831 }
832 ADCSRA = 0;
833 PRR |= _BV(PRADC);
834
835 return ((uint32_t)vcc*sum*SCALER_5V/(num*1024));;
836 }
837
828 static void 838 static void
829 reboot_pi() 839 reboot_pi()
830 { 840 {
831 // pull it low for 30ms 841 printf_P(PSTR("Real reboot now\n"));
842 // pull it low for 200ms
832 PORT_PI_RESET &= ~_BV(PIN_PI_RESET); 843 PORT_PI_RESET &= ~_BV(PIN_PI_RESET);
833 DDR_PI_RESET |= _BV(PIN_PI_RESET); 844 DDR_PI_RESET |= _BV(PIN_PI_RESET);
834 _delay_ms(30); 845 _delay_ms(200);
835 DDR_PI_RESET &= ~_BV(PIN_PI_RESET); 846
847 PORT_PI_WARNING &= ~_BV(PIN_PI_WARNING);
848 DDR_PI_RESET &= ~_BV(PIN_PI_RESET);
849 }
850
851 static void
852 wait_reboot_pi()
853 {
854 PORT_PI_WARNING |= _BV(PIN_PI_WARNING);
855 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
856 {
857 reboot_count = WARNING_TIME;
858 }
859 printf_P(PSTR("Rebooting in %hhu seconds\n"), reboot_count);
836 } 860 }
837 861
838 static void 862 static void
839 set_pi_boot_normal(uint8_t normal) 863 set_pi_boot_normal(uint8_t normal)
840 { 864 {
869 || watchdog_short_hit 893 || watchdog_short_hit
870 || oneshot_hit) 894 || oneshot_hit)
871 { 895 {
872 printf_P(PSTR("Rebooting! long %d, short %d, oneshot %d\n"), 896 printf_P(PSTR("Rebooting! long %d, short %d, oneshot %d\n"),
873 watchdog_long_hit, watchdog_short_hit, oneshot_hit); 897 watchdog_long_hit, watchdog_short_hit, oneshot_hit);
874 long_delay(300); 898 wait_reboot_pi();
875 reboot_pi();
876 } 899 }
877 900
878 if (newboot_hit) { 901 if (newboot_hit) {
879 set_pi_boot_normal(0); 902 set_pi_boot_normal(0);
903 }
904
905 if (reboot_hit) {
906 reboot_pi();
880 } 907 }
881 908
882 watchdog_long_hit = 0; 909 watchdog_long_hit = 0;
883 watchdog_short_hit = 0; 910 watchdog_short_hit = 0;
884 newboot_hit = 0; 911 newboot_hit = 0;
885 oneshot_hit = 0; 912 oneshot_hit = 0;
913 reboot_hit = 0;
886 } 914 }
887 915
888 static void 916 static void
889 do_comms() 917 do_comms()
890 { 918 {
895 923
896 while (1) 924 while (1)
897 { 925 {
898 wdt_reset(); 926 wdt_reset();
899 927
928 #ifdef SIM_DEBUG
929 if (sim_idx != last_sim_idx)
930 {
931 last_sim_idx = sim_idx;
932 }
933 #endif
934
900 check_flags(); 935 check_flags();
901 936
902 if (have_cmd) 937 if (have_cmd)
903 { 938 {
904 have_cmd = 0; 939 have_cmd = 0;
912 } 947 }
913 948
914 static void 949 static void
915 blink() 950 blink()
916 { 951 {
917 PORT_LED &= ~_BV(PIN_LED); 952 #if 0
953 PORT_ &= ~_BV(PIN_LED);
918 _delay_ms(1); 954 _delay_ms(1);
919 PORT_LED |= _BV(PIN_LED); 955 PORT_LED |= _BV(PIN_LED);
956 #endif
920 } 957 }
921 958
922 static void 959 static void
923 long_delay(int ms) 960 long_delay(int ms)
924 { 961 {