--- /dev/null
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <util/delay.h>
+#include <stdlib.h> // for NULL
+
+#include "lights.h"
+
+#define WAKEUP_LIMIT 5 // times 100 ms
+#define SHORT_PRESS_MIN 10 // in jiffies (100 Hz ticks)
+#define SHORT_PRESS_MAX 50
+#define LONG_PRESS_MIN 100
+static uint16_t button_start;
+static unsigned char prev_state;
+
+void status_led_on_off(unsigned char mode)
+{
+ if (mode)
+ PORTB |= _BV(PORTB0);
+ else
+ PORTB &= ~_BV(PORTB0);
+}
+
+void init_buttons()
+{
+ DDRB &= ~_BV(DDB1);
+ DDRB |= _BV(DDB0);
+ PORTB |= _BV(PORTB1); // enable internal pull-up
+ PORTB &= ~_BV(PORTB0); // status led off
+ GIMSK &= ~_BV(PCIE); // disable pin-change IRQs
+ PCMSK = 0; // disable pin-change IRQs on all pins of port B
+
+ button_start = 0;
+ prev_state = 0;
+}
+
+void susp_buttons()
+{
+ DDRB &= ~(_BV(DDB1)); // set as input
+ PORTB |= _BV(PORTB1); // enable internal pull-up
+ PORTB &= ~_BV(PORTB0); // set to zero
+
+ GIMSK |= _BV(PCIE);
+
+ PCMSK = _BV(PCINT1);
+ // disable pin-change IRQs on all pins except PB1
+}
+
+void timer_check_buttons()
+{
+ unsigned char cur = !(PINB & _BV(PINB1));
+ unsigned char prev = prev_state;
+
+ prev_state = cur;
+
+ if (cur && !prev) { // --- just pressed ---
+ button_start = jiffies;
+ // set_status_led(button, NULL);
+
+ } else if (cur && prev) { // --- is still pressed ---
+ uint16_t duration = jiffies - button_start;
+
+ if (duration > LONG_PRESS_MIN) {
+ long_press_start();
+ // acknowledge long press
+ }
+ } else if (!cur && prev) { // --- just released ---
+ uint16_t duration = jiffies - button_start;
+
+ if (duration > SHORT_PRESS_MIN && duration < SHORT_PRESS_MAX) {
+ short_press();
+ } else if (duration > LONG_PRESS_MIN) {
+ // set_status_led(button, NULL);
+ long_press();
+ }
+ // ignore other button-press durations
+ }
+}
+
+#if 0
+static void handle_brake(unsigned char cur, unsigned char prev)
+{
+ if (cur && !prev) { // --- just pressed ---
+ button_start[2] = jiffies;
+ } else if (!cur && prev) { // --- just released ---
+ button_start[2] = jiffies;
+ } else { // --- no change ---
+ uint16_t duration = jiffies - button_start[2];
+
+ if (duration > 6) {
+ if (cur) {
+ if (button_state.brake_working
+ && !button_state.brake_reported) {
+ button_state.brake_reported = 1;
+ brake_on();
+ }
+ } else {
+ button_state.brake_working = 1;
+ if (button_state.brake_reported) {
+ button_state.brake_reported = 0;
+ brake_off();
+ }
+ }
+ button_start[2] = jiffies - 7; // avoid overflow
+ }
+ }
+}
+#endif
+
+unsigned char buttons_wait_for_release()
+{
+ uint16_t wake_count = 0;
+ unsigned char pin;
+
+ do {
+ if (wake_count++ > WAKEUP_LIMIT)
+ status_led_on_off(1); // inform the user
+
+ _delay_ms(100);
+
+ pin = PINB & _BV(PINB1);
+ } while (!(pin & _BV(PINB1)));
+
+ status_led_on_off(0);
+
+ return wake_count > WAKEUP_LIMIT;
+}
+
+ISR(PCINT0_vect)
+{
+ // empty - let it wake us from sleep, but do nothing else
+}
+