/* * labsw.c - Lab Switch initialization and main loop * * Written 2011 by Werner Almesberger * Copyright 2011 Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include "regs.h" #include "usb.h" #include "config.h" #include "io.h" #include "labsw/ep0.h" int local = 1; /* * 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) #define LED_R_COLOR_R 1 #define LED_R_COLOR_G 0 #define LED_R_COLOR_OFF 0 #define LED_G_COLOR_R 0 #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) /* ----- I/O setup --------------------------------------------------------- */ static void init_io(void) { P0SKIP = 0xff; P1SKIP = 0xff; P2SKIP = 0xff; /* @@@ we need this while using the boot loader of cntr */ P0MDOUT = 0; P1MDOUT = 0; P2MDOUT = 0; LED_MAIN_R_MODE |= 1 << LED_MAIN_R_BIT; LED_MAIN_G_MODE |= 1 << LED_MAIN_G_BIT; LED_CH1_R_MODE |= 1 << LED_CH1_R_BIT; LED_CH1_G_MODE |= 1 << LED_CH1_G_BIT; LED_CH2_R_MODE |= 1 << LED_CH2_R_BIT; LED_CH2_G_MODE |= 1 << LED_CH2_G_BIT; CH1_RELAY = 0; CH2_RELAY = 0; CH1_RELAY_MODE |= 1 << CH1_RELAY_BIT; CH2_RELAY_MODE |= 1 << CH2_RELAY_BIT; } /* ----- Main loop --------------------------------------------------------- */ void main(void) { 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(); ep0_init(); LED(MAIN, G); TURN(1, 0); TURN(2, 0); while (1) { DEBOUNCE(MAIN, main); DEBOUNCE(CH1, ch1); DEBOUNCE(CH2, ch2); /* * 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); } local = 1; } /* * Update LEDs in local mode. */ if (local) { LED(MAIN, G); if (IS_ON(1)) TURN(1, 1); else TURN(1, 0); if (IS_ON(2)) TURN(2, 1); else TURN(2, 0); } /* * In local mode, buttons CH1 and CH2 toggle the respective * channel. */ if (local) { if (PRESSED(ch1)) TURN(1, !IS_ON(1)); if (PRESSED(ch2)) TURN(2, !IS_ON(2)); } usb_poll(); } }