2 #include <avr/interrupt.h>
4 #include <util/delay.h>
5 #include <stdlib.h> // for NULL
9 #define WAKEUP_LIMIT 5 // times 100 ms
10 static uint16_t button_start[N_BUTTONS];
11 static unsigned char prev_pin;
13 static unsigned char user_params[MAX_USER_PARAMS] = { 0, 0, 0 };
14 static unsigned char user_params_max[MAX_USER_PARAMS] = { 3, 2, 2 };
16 static unsigned char user_params_state = 0;
18 * Here 0 means "no setup currently in progress",
19 * 1 .. MAX_USER_PARAMS means "now short presses increase or decrease
20 * the value of user_params[user_params_state-1]"
23 static uint16_t user_params_starttime;
25 static void inline set_status_led(unsigned char n, pattern_t *pattern)
27 led_set_pattern(n + N_PWMLEDS, pattern);
30 unsigned char buttons_setup_in_progress()
32 if (user_params_state // setup in progress ...
33 // or at least one button is pressed:
34 || !(prev_pin & _BV(PA3))
35 || !(prev_pin & _BV(PA4)))
40 pattern_t *buttons_setup_status0_pattern_select()
42 if (user_params_state) // Setup in progress
43 return number_pattern(user_params_state, 1);
48 pattern_t *buttons_setup_status1_pattern_select()
50 if (user_params_state) // Setup in progress
51 return number_pattern(
52 1 + user_params[user_params_state-1],
59 unsigned char get_user_param(unsigned char param)
61 if (param < MAX_USER_PARAMS)
62 return user_params[param];
63 return 0; // FIXME: internal error?
66 static inline void short_press(unsigned char button)
70 if (user_params_state == 0) {
78 param = user_params_state-1;
81 if (user_params[param])
84 user_params[param] = user_params_max[param]-1;
88 if (user_params[param] >= user_params_max[param])
89 user_params[param] = 0;
91 // FIXME: notify somebody about user_params change?
93 set_status_led(1, buttons_setup_status1_pattern_select());
95 user_params_starttime = jiffies;
98 static inline void long_press(unsigned char button)
105 // button 1 - cycle through states
108 if (user_params_state > MAX_USER_PARAMS)
109 user_params_state = 1;
111 set_status_led(0, buttons_setup_status0_pattern_select());
112 set_status_led(1, buttons_setup_status1_pattern_select());
113 user_params_starttime = jiffies;
118 DDRA &= ~(_BV(PA3) | _BV(PA4)); // set as input
119 PORTA |= _BV(PA3) | _BV(PA4); // enable internal pull-ups
121 GIMSK &= ~(_BV(PCIE0) | _BV(PCIE1)); // disable pin-change IRQs
122 PCMSK0 = 0; // disable pin-change IRQs on all pins of port A
123 PCMSK1 = 0; // disable pin-change IRQs on all pins of port B
127 prev_pin = _BV(PA3) | _BV(PA4);
128 user_params_state = 0;
133 DDRA &= ~(_BV(PA3) | _BV(PA4)); // set as input
134 PORTA |= _BV(PA3) | _BV(PA4); // enable internal pull-ups
136 GIMSK &= ~_BV(PCIE1); // disable pin-change IRQ on port B
139 PCMSK0 = _BV(PCINT3) | _BV(PCINT4);
140 // disable pin-change IRQs on all pins except PA3,PA4
141 PCMSK1 = 0; // disable pin-change IRQs on all pins of port B
144 static void handle_button(unsigned char button, unsigned char cur,
147 // BEWARE: pins are at _zero_ when pressed!
148 if (!cur && prev) { // --- just pressed ---
149 button_start[button] = jiffies;
150 set_status_led(button, NULL);
152 } else if (!cur && !prev) { // --- is still pressed ---
153 uint16_t duration = jiffies - button_start[button];
156 set_status_led(button, on1_pattern);
157 // acknowledge long press
159 } else if (cur && !prev) { // --- just released ---
160 uint16_t duration = jiffies - button_start[button];
162 if (duration > 6 && duration < 30) {
164 } else if (duration > 80) {
165 set_status_led(button, NULL);
168 // ignore other button-press durations
172 void timer_check_buttons()
174 unsigned char pin = PINA & (_BV(PA3) | _BV(PA4));
176 handle_button(0, pin & _BV(PA3), prev_pin & _BV(PA3));
177 handle_button(1, pin & _BV(PA4), prev_pin & _BV(PA4));
181 if (user_params_state && jiffies - user_params_starttime > 1000) {
182 user_params_state = 0;
183 set_status_led(0, buttons_setup_status0_pattern_select());
184 set_status_led(1, buttons_setup_status1_pattern_select());
188 unsigned char buttons_wait_for_release()
190 uint16_t wake_count = 0;
194 if (wake_count++ > WAKEUP_LIMIT)
195 gpio_set(0, 1); // inform the user
199 pin = PINA & (_BV(PA3) | _BV(PA4));
200 } while (!(pin & _BV(PA3)) || !(pin & _BV(PA4)));
204 return wake_count > WAKEUP_LIMIT;
210 // empty - let it wake us from sleep, but do nothing else