leddie/firmware/lib/button.c

88 lines
2.0 KiB
C

#include <avr/interrupt.h>
#include "button.h"
#include "timers.h"
#include "hal.h"
#include <util/delay.h>
#include "pm.h" // TODO: FOR DEBUGGING ONLY
volatile enum BUTTON_EVENTS button_event_status = NONE;
// User button interrupt
ISR(INT1_vect)
{
_delay_ms(50);
if (HAL_ASSERTED_N(BUTTON_N)) { // Button down event
switch (button_event_status) {
case NONE: // Start processing button from NONE,
case EV_BOOT: // or drop boot event if not polled for,
case EV_PRESS: // or drop current keypress to prevent unhandled keypresses from blocking other would-be-handled keypresses
case EV_DOUBLEPRESS:
case EV_LONGPRESS:
case EV_DOUBLELONGPRESS:
button_event_status = WAIT_FOR_RELEASE_1;
timer_set(TIMER_BUTTON, timer_ms(500));
break;
case WAIT_FOR_SECOND:
button_event_status = WAIT_FOR_RELEASE_2;
timer_set(TIMER_BUTTON, timer_ms(500));
break;
default:
break;
}
} else { // Button up event
switch (button_event_status) {
case WAIT_FOR_RELEASE_1:
button_event_status = WAIT_FOR_SECOND;
break;
case WAIT_FOR_RELEASE_2:
button_event_status = EV_DOUBLEPRESS;
break;
default:
break;
}
}
return;
}
void button_init()
{
HAL_INIT(BUTTON_N, INPUT, ON); // Pull-up for user button
button_event_status = EV_BOOT;
MCUCR = (1 << ISC10); // Any-edge interrupt
GICR = (1 << INT1); // Turn on button interrupt
}
void button_systick_cb()
{
if (button_event_status != 0) { // TODO: we should not enter on pending EV?
if (timer_expired(TIMER_BUTTON)) {
switch (button_event_status) {
case WAIT_FOR_RELEASE_1:
button_event_status = EV_LONGPRESS;
break;
case WAIT_FOR_RELEASE_2:
button_event_status = EV_DOUBLELONGPRESS;
pm_reset(); // TODO: For debugging purposes only
break;
case WAIT_FOR_SECOND:
button_event_status = EV_PRESS;
break;
default:
break;
}
}
}
}
int button_event(enum BUTTON_EVENTS ev)
{
if (button_event_status == ev) {
button_event_status = NONE; // Mark as handled
return 1;
}
return 0;
}