Root/labsw/fw/labsw.c

Source at commit a400f9a0183af4ddf565a2acb2b08d9418749224 created 8 years 2 months ago.
By Werner Almesberger, labsw/fw/labsw.c: improved debouncing and cleaned up button logic
1/*
2 * labsw.c - Lab Switch initialization and main loop
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdint.h>
15
16#include "regs.h"
17#include "usb.h"
18
19#include "config.h"
20#include "io.h"
21#include "labsw/ep0.h"
22
23
24int local = 1;
25
26
27/*
28 * SDCC complains a lot about code that's unreachable due to constant
29 * conditional expressions.
30 */
31
32#pragma disable_warning 126 /* unreachable code */
33
34
35/* ----- Button debouncing ------------------------------------------------- */
36
37
38/* In the version of 2011-09-11, 10000 cycles are about 128 ms */
39
40#define PREBOUNCE_CYCLES 2000
41#define POSTBOUNCE_CYCLES 5000
42
43
44#define TURN(ch, on) \
45    do { \
46        CH##ch##_RELAY = on; \
47        CH##ch##_OPT = !on; \
48        if (on) \
49            LED(CH##ch, R); \
50        else \
51            LED(CH##ch, G); \
52    } while (0)
53
54
55#define DEBOUNCE(BUT, but) \
56    do { \
57        last_##but = but_##but; \
58        if (postbounce_##but) { \
59            postbounce_##but--; \
60            break; \
61        } \
62        if (but_##but == !BUT_##BUT) { \
63            prebounce_##but = 0; \
64            break; \
65        } \
66        if (prebounce_##but != PREBOUNCE_CYCLES) { \
67            prebounce_##but++; \
68            break; \
69        } \
70        prebounce_##but = 0; \
71        postbounce_##but = POSTBOUNCE_CYCLES; \
72        but_##but = !but_##but; \
73    } while (0)
74
75
76#define PRESSED(but) (but_##but && !last_##but)
77#define RELEASED(but) (!but_##but && last_##but)
78
79
80/* ----- LED and channel control ------------------------------------------- */
81
82
83#define IS_ON(ch) (CH##ch##_RELAY || !CH##ch##_OPT)
84
85#define LED_R_COLOR_R 1
86#define LED_R_COLOR_G 0
87#define LED_R_COLOR_OFF 0
88#define LED_G_COLOR_R 0
89#define LED_G_COLOR_G 1
90#define LED_G_COLOR_OFF 0
91
92
93#define LED(ch, color) \
94    do { \
95        LED_##ch##_R = LED_R_COLOR_##color; \
96        LED_##ch##_G = LED_G_COLOR_##color; \
97    } while (0)
98
99
100/* ----- I/O setup --------------------------------------------------------- */
101
102
103static void init_io(void)
104{
105    P0SKIP = 0xff;
106    P1SKIP = 0xff;
107    P2SKIP = 0xff;
108
109    /* @@@ we need this while using the boot loader of cntr */
110    P0MDOUT = 0;
111    P1MDOUT = 0;
112    P2MDOUT = 0;
113
114    LED_MAIN_R_MODE |= 1 << LED_MAIN_R_BIT;
115    LED_MAIN_G_MODE |= 1 << LED_MAIN_G_BIT;
116    LED_CH1_R_MODE |= 1 << LED_CH1_R_BIT;
117    LED_CH1_G_MODE |= 1 << LED_CH1_G_BIT;
118    LED_CH2_R_MODE |= 1 << LED_CH2_R_BIT;
119    LED_CH2_G_MODE |= 1 << LED_CH2_G_BIT;
120
121    CH1_RELAY = 0;
122    CH2_RELAY = 0;
123    CH1_RELAY_MODE |= 1 << CH1_RELAY_BIT;
124    CH2_RELAY_MODE |= 1 << CH2_RELAY_BIT;
125}
126
127
128/* ----- Main loop --------------------------------------------------------- */
129
130
131void main(void)
132{
133    int prebounce_main = 0, postbounce_main = 0;
134    int last_main = 0, but_main = 0;
135    int prebounce_ch1 = 0, postbounce_ch1 = 0, last_ch1 = 0, but_ch1 = 0;
136    int prebounce_ch2 = 0, postbounce_ch2 = 0, last_ch2 = 0, but_ch2 = 0;
137    init_io();
138
139    usb_init();
140    ep0_init();
141
142    LED(MAIN, G);
143    TURN(1, 0);
144    TURN(2, 0);
145
146    while (1) {
147        DEBOUNCE(MAIN, main);
148        DEBOUNCE(CH1, ch1);
149        DEBOUNCE(CH2, ch2);
150
151        /*
152         * Pressing MAIN forces local mode. Pressing it in local mode,
153         * it turns off both front channels.
154         */
155        if (PRESSED(main)) {
156            if (local) {
157                TURN(1, 0);
158                TURN(2, 0);
159            }
160            local = 1;
161        }
162
163        /*
164         * Update LEDs in local mode.
165         */
166        if (local) {
167            LED(MAIN, G);
168            if (IS_ON(1))
169                TURN(1, 1);
170            else
171                TURN(1, 0);
172            if (IS_ON(2))
173                TURN(2, 1);
174            else
175                TURN(2, 0);
176        }
177
178        /*
179         * In local mode, buttons CH1 and CH2 toggle the respective
180         * channel.
181         */
182        if (local) {
183            if (PRESSED(ch1))
184                TURN(1, !IS_ON(1));
185            if (PRESSED(ch2))
186                TURN(2, !IS_ON(2));
187        }
188        
189        usb_poll();
190    }
191}
192

Archive Download this file

Branches:
master



interactive