rgb-led-string: Christmas tree mod after real-world testing
[tinyboard.git] / projects / step-up / buttons.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <avr/sleep.h>
4 #include <util/delay.h>
5 #include <stdlib.h> // for NULL
6
7 #include "lights.h"
8
9 #define WAKEUP_LIMIT    5       // times 100 ms
10 #define SHORT_PRESS_MIN 2       // in jiffies (16 Hz ticks)
11 #define SHORT_PRESS_MAX 5
12 #define LONG_PRESS_MIN  10
13 static uint16_t button_start;
14 static unsigned char prev_state;
15
16 void status_led_on_off(unsigned char mode)
17 {
18         if (mode)
19                 PORTB |= _BV(PORTB1);
20         else
21                 PORTB &= ~_BV(PORTB1);
22 }
23
24 void init_buttons()
25 {
26         DDRB &= ~_BV(DDB0);
27         DDRB |= _BV(DDB1);
28         PORTB |= _BV(PORTB0); // enable internal pull-up
29         PORTB &= ~_BV(PORTB1); // status led off
30         GIMSK &= ~_BV(PCIE); // disable pin-change IRQs
31         PCMSK = 0; // disable pin-change IRQs on all pins of port B
32
33         button_start = 0;
34         prev_state   = 0;
35 }
36
37 void susp_buttons()
38 {
39         DDRB &= ~(_BV(DDB0)); // set as input
40         PORTB |= _BV(PORTB0);  // enable internal pull-up
41         PORTB &= ~_BV(PORTB1); // set to zero
42
43         GIMSK |= _BV(PCIE);
44
45         PCMSK = _BV(PCINT0);
46                 // disable pin-change IRQs on all pins except PB1
47 }
48
49 void timer_check_buttons()
50 {
51         unsigned char cur = !(PINB & _BV(PINB0));
52         unsigned char prev = prev_state;
53
54         prev_state = cur;
55
56         if (cur && !prev) {                   // --- just pressed ---
57                 button_start = jiffies;
58                 // set_status_led(button, NULL);
59
60         } else if (cur && prev) {           // --- is still pressed ---
61                 uint16_t duration = jiffies - button_start;
62
63                 if (duration > LONG_PRESS_MIN) {
64                         long_press_start();
65                                 // acknowledge long press
66                 }
67         } else if (!cur && prev) {            // --- just released ---
68                 uint16_t duration = jiffies - button_start;
69
70                 if (duration >= SHORT_PRESS_MIN && duration < SHORT_PRESS_MAX) {
71                         short_press();
72                 } else if (duration > LONG_PRESS_MIN) {
73                         // set_status_led(button, NULL);
74                         long_press();
75                 }
76                 // ignore other button-press durations
77         }
78 }
79
80 #if 0
81 static void handle_brake(unsigned char cur, unsigned char prev)
82 {
83         if (cur && !prev) {                   // --- just pressed ---
84                 button_start[2] = jiffies;
85         } else if (!cur && prev) {            // --- just released ---
86                 button_start[2] = jiffies;
87         } else {                              // --- no change ---
88                 uint16_t duration = jiffies - button_start[2];
89
90                 if (duration > 6) {
91                         if (cur) {
92                                 if (button_state.brake_working
93                                         && !button_state.brake_reported) {
94                                         button_state.brake_reported = 1;
95                                         brake_on();
96                                 }
97                         } else {
98                                 button_state.brake_working = 1;
99                                 if (button_state.brake_reported) {
100                                         button_state.brake_reported = 0;
101                                         brake_off();
102                                 }
103                         }
104                         button_start[2] = jiffies - 7; // avoid overflow
105                 }
106         }
107 }
108 #endif
109
110 unsigned char buttons_wait_for_release()
111 {
112         uint16_t wake_count = 0;
113         unsigned char pin;
114
115         do {
116                 if (wake_count++ > WAKEUP_LIMIT)
117                         status_led_on_off(1); // inform the user
118
119                 _delay_ms(100);
120
121                 pin = PINB & _BV(PINB0);
122         } while (!(pin & _BV(PINB0)));
123
124         status_led_on_off(0);
125
126         return wake_count > WAKEUP_LIMIT;
127 }
128
129 ISR(PCINT0_vect)
130 {
131         // empty - let it wake us from sleep, but do nothing else
132 }
133