]> www.fi.muni.cz Git - bike-lights.git/blob - firmware/buttons.c
90f57012bced79ac90605687bccafab15d9bfcdc
[bike-lights.git] / firmware / buttons.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <avr/sleep.h>
4 #include <util/delay.h>
5
6 #include "lights.h"
7
8 static uint16_t button_start[N_BUTTONS];
9 static unsigned char prev_pin;
10
11 static unsigned char user_params[MAX_USER_PARAMS] = { 0, 0, 0 };
12 static unsigned char user_params_max[MAX_USER_PARAMS] = { 3, 2, 2 };
13
14 static unsigned char user_params_state = 0;
15         /*
16          * Here 0 means "no setup currently in progress",
17          * 1 .. MAX_USER_PARAMS means "now short presses increase or decrease
18          *           the value of user_params[user_params_state-1]"
19          */
20
21 static uint16_t user_params_starttime;
22
23 static void inline set_status_led(unsigned char n, pattern_t *pattern)
24 {
25         led_set_pattern(n + N_PWMLEDS, pattern);
26 }
27
28 pattern_t *status_pattern_select(unsigned char n)
29 {
30         if (user_params_state) // Setup in progress
31                 return number_pattern(n == 0
32                         ? user_params_state
33                         : 1 + user_params[user_params_state-1]
34                 );
35         else if (!(prev_pin & _BV(PA3)) || !(prev_pin & _BV(PA4)))
36                 // at least one button is pressed
37                 return off_pattern;
38         // otherwise, an ordinary state
39         if (n == 0) {
40                 // error led
41                 return number_pattern(1 + ambient_zone);
42         } else {
43                 return off_pattern; // for now
44         }
45 }
46
47 static void toggle_bright_mode()
48 {
49         // TODO
50 }
51
52 static void set_panic_mode()
53 {
54         // TODO
55 }
56
57 unsigned char get_user_param(unsigned char param)
58 {
59         if (param < MAX_USER_PARAMS)
60                 return user_params[param];
61         return 0; // FIXME: internal error?
62 }
63
64 static inline void short_press(unsigned char button)
65 {
66         unsigned char param;
67
68         if (user_params_state == 0) {
69                 if (button == 0)
70                         toggle_bright_mode();
71                 else
72                         set_panic_mode();
73                 return;
74         }
75
76         param = user_params_state-1;
77
78         if (button == 0) {
79                 if (user_params[param])
80                         user_params[param]--;
81                 else
82                         user_params[param] = user_params_max[param];
83         } else {
84                 user_params[param]++;
85
86                 if (user_params[param] >= user_params_max[param])
87                         user_params[param] = 0;
88         }
89         // FIXME: notify somebody about user_params change?
90
91         set_status_led(1, status_pattern_select(1));
92
93         user_params_starttime = jiffies;
94 }
95
96 static inline void long_press(unsigned char button)
97 {
98         if (button == 0) {
99                 power_down();
100                 return;
101         }
102
103         // button 1 - cycle through states
104         user_params_state++;
105
106         if (user_params_state >= MAX_USER_PARAMS)
107                 user_params_state = 1;
108
109         set_status_led(0, status_pattern_select(0));
110         set_status_led(1, status_pattern_select(1));
111         user_params_starttime = jiffies;
112 }
113
114 void init_buttons()
115 {
116         DDRA &= ~(_BV(PA3) | _BV(PA4));
117         PORTA |=  _BV(PA3) | _BV(PA4);
118
119         button_start[0] = 0;
120         button_start[1] = 0;
121         prev_pin = _BV(PA3) | _BV(PA4);
122         user_params_state = 0;
123 }
124
125 static void handle_button(unsigned char button, unsigned char cur,
126         unsigned char prev)
127 {
128         // BEWARE: pins are at _zero_ when pressed!
129         if (!cur && prev) {                   // --- just pressed ---
130                 button_start[button] = jiffies;
131                 set_status_led(button, off_pattern);
132
133         } else if (!cur && !prev) {           // --- is still pressed ---
134                 uint16_t duration = jiffies - button_start[button];
135
136                 if (duration > 80) {
137                         set_status_led(button, on_pattern);
138                                 // acknowledge long press
139                 }
140         } else if (cur && !prev) {            // --- just released ---
141                 uint16_t duration = jiffies - button_start[button];
142
143                 if (duration > 6 && duration < 30) {
144                         short_press(button);
145                 } else if (duration > 80) {
146                         set_status_led(button, off_pattern);
147                         long_press(button);
148                 }
149                 // ignore other button-press durations
150         }
151 }
152
153 void timer_check_buttons()
154 {
155         unsigned char pin = PINA & (_BV(PA3) | _BV(PA4));
156
157         handle_button(0, pin & _BV(PA3), prev_pin & _BV(PA3));
158         handle_button(1, pin & _BV(PA4), prev_pin & _BV(PA4));
159
160         prev_pin = pin;
161
162         if (user_params_state && jiffies - user_params_starttime > 500) {
163                 user_params_state = 0;
164                 set_status_led(0, status_pattern_select(0));
165                 set_status_led(1, status_pattern_select(1));
166         }
167 }
168