From a400f9a0183af4ddf565a2acb2b08d9418749224 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 11 Sep 2011 13:03:20 -0300 Subject: [PATCH] labsw/fw/labsw.c: improved debouncing and cleaned up button logic --- labsw/fw/labsw.c | 123 +++++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 42 deletions(-) diff --git a/labsw/fw/labsw.c b/labsw/fw/labsw.c index d92fa1f..e7634e2 100644 --- a/labsw/fw/labsw.c +++ b/labsw/fw/labsw.c @@ -24,7 +24,60 @@ int local = 1; -#define DEBOUNCE_CYCLES 10 +/* + * SDCC complains a lot about code that's unreachable due to constant + * conditional expressions. + */ + +#pragma disable_warning 126 /* unreachable code */ + + +/* ----- Button debouncing ------------------------------------------------- */ + + +/* In the version of 2011-09-11, 10000 cycles are about 128 ms */ + +#define PREBOUNCE_CYCLES 2000 +#define POSTBOUNCE_CYCLES 5000 + + +#define TURN(ch, on) \ + do { \ + CH##ch##_RELAY = on; \ + CH##ch##_OPT = !on; \ + if (on) \ + LED(CH##ch, R); \ + else \ + LED(CH##ch, G); \ + } while (0) + + +#define DEBOUNCE(BUT, but) \ + do { \ + last_##but = but_##but; \ + if (postbounce_##but) { \ + postbounce_##but--; \ + break; \ + } \ + if (but_##but == !BUT_##BUT) { \ + prebounce_##but = 0; \ + break; \ + } \ + if (prebounce_##but != PREBOUNCE_CYCLES) { \ + prebounce_##but++; \ + break; \ + } \ + prebounce_##but = 0; \ + postbounce_##but = POSTBOUNCE_CYCLES; \ + but_##but = !but_##but; \ + } while (0) + + +#define PRESSED(but) (but_##but && !last_##but) +#define RELEASED(but) (!but_##but && last_##but) + + +/* ----- LED and channel control ------------------------------------------- */ #define IS_ON(ch) (CH##ch##_RELAY || !CH##ch##_OPT) @@ -36,21 +89,15 @@ int local = 1; #define LED_G_COLOR_G 1 #define LED_G_COLOR_OFF 0 + #define LED(ch, color) \ do { \ LED_##ch##_R = LED_R_COLOR_##color; \ LED_##ch##_G = LED_G_COLOR_##color; \ } while (0) -#define TURN(ch, on) \ - do { \ - CH##ch##_RELAY = on; \ - CH##ch##_OPT = !on; \ - if (on) \ - LED(CH##ch, R); \ - else \ - LED(CH##ch, G); \ - } while (0) + +/* ----- I/O setup --------------------------------------------------------- */ static void init_io(void) @@ -78,11 +125,15 @@ static void init_io(void) } +/* ----- Main loop --------------------------------------------------------- */ + + void main(void) { - int debounce_main = 0, last_main = 0, but_main = 0; - int debounce_ch1 = 0, last_ch1 = 0, but_ch1 = 0; - int debounce_ch2 = 0, last_ch2 = 0, but_ch2 = 0; + int prebounce_main = 0, postbounce_main = 0; + int last_main = 0, but_main = 0; + int prebounce_ch1 = 0, postbounce_ch1 = 0, last_ch1 = 0, but_ch1 = 0; + int prebounce_ch2 = 0, postbounce_ch2 = 0, last_ch2 = 0, but_ch2 = 0; init_io(); usb_init(); @@ -93,34 +144,15 @@ void main(void) TURN(2, 0); while (1) { - if (debounce_main) - debounce_main--; - else { - last_main = but_main; - but_main = !BUT_MAIN; - if (last_main != but_main) - debounce_main = DEBOUNCE_CYCLES; - } + DEBOUNCE(MAIN, main); + DEBOUNCE(CH1, ch1); + DEBOUNCE(CH2, ch2); - if (debounce_ch1) - debounce_ch1--; - else { - last_ch1 = but_ch1; - but_ch1 = !BUT_CH1; - if (last_ch1 != but_ch1) - debounce_ch1 = DEBOUNCE_CYCLES; - } - - if (debounce_ch2) - debounce_ch2--; - else { - last_ch2 = but_ch2; - but_ch2 = !BUT_CH2; - if (last_ch2 != but_ch2) - debounce_ch2 = DEBOUNCE_CYCLES; - } - - if (but_main && !last_main) { + /* + * Pressing MAIN forces local mode. Pressing it in local mode, + * it turns off both front channels. + */ + if (PRESSED(main)) { if (local) { TURN(1, 0); TURN(2, 0); @@ -128,6 +160,9 @@ void main(void) local = 1; } + /* + * Update LEDs in local mode. + */ if (local) { LED(MAIN, G); if (IS_ON(1)) @@ -140,10 +175,14 @@ void main(void) TURN(2, 0); } + /* + * In local mode, buttons CH1 and CH2 toggle the respective + * channel. + */ if (local) { - if (but_ch1 && !last_ch1) + if (PRESSED(ch1)) TURN(1, !IS_ON(1)); - if (but_ch2 && !last_ch2) + if (PRESSED(ch2)) TURN(2, !IS_ON(2)); }