#include #include #include #include #include // for NULL #include "lights.h" #define WAKEUP_LIMIT 5 // times 100 ms #define SHORT_PRESS_MIN 2 // in jiffies (16 Hz ticks) #define SHORT_PRESS_MAX 5 #define LONG_PRESS_MIN 10 static uint16_t button_start; static unsigned char prev_state; void status_led_on_off(unsigned char mode) { if (mode) PORTB |= _BV(PORTB1); else PORTB &= ~_BV(PORTB1); } void init_buttons() { DDRB &= ~_BV(DDB0); DDRB |= _BV(DDB1); PORTB |= _BV(PORTB0); // enable internal pull-up PORTB &= ~_BV(PORTB1); // 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(DDB0)); // set as input PORTB |= _BV(PORTB0); // enable internal pull-up PORTB &= ~_BV(PORTB1); // set to zero GIMSK |= _BV(PCIE); PCMSK = _BV(PCINT0); // disable pin-change IRQs on all pins except PB1 } void timer_check_buttons() { unsigned char cur = !(PINB & _BV(PINB0)); 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(PINB0); } while (!(pin & _BV(PINB0))); status_led_on_off(0); return wake_count > WAKEUP_LIMIT; } ISR(PCINT0_vect) { // empty - let it wake us from sleep, but do nothing else }