webradio/firmware/input.c

116 lines
2.4 KiB
C

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "input.h"
#include "systick.h"
static volatile uint8_t rotary_delta = 0;
static volatile uint8_t sw_event = 0;
void input_init()
{
PORT_ROTARY(DDR) &= ~(PIN_ROTARY_A | PIN_ROTARY_B); // Configure as input
PORT_ROTARY(PORT) |= (PIN_ROTARY_A | PIN_ROTARY_B); // Set pullups
PORT_KEYPAD(DDR) &= ~(PIN_KEYPAD_MASK); // Key inputs
PORT_KEYPAD(PORT) |= PIN_KEYPAD_MASK; // Key pullups
PORT_SBCMON(DDR) &= ~PIN_SBCMON;
PORT_SBCMON(PORT) |= PIN_SBCMON;
}
inline uint8_t get_rotary_delta()
{
return rotary_delta;
}
#define ROTARY_DEBOUNCE 150
static inline void input_proc_rotary()
{
static int8_t last_a;
int8_t a;
int8_t b;
int8_t p;
uint8_t silly_debounce = 0;
if (silly_debounce == 0) {
p = PORT_ROTARY(PIN);
a = (p & PIN_ROTARY_A);
b = (p & PIN_ROTARY_B);
a = !a;
b = !b;
if (a == 1 && last_a == 0) {
silly_debounce = ROTARY_DEBOUNCE;
if (rotary_delta < 31)
rotary_delta += !!(a ^ b);
}
if (a == 0 && last_a == 1) {
silly_debounce = ROTARY_DEBOUNCE;
if (rotary_delta > 0)
rotary_delta -= !(a ^ b);
}
last_a = a;
} else {
silly_debounce--;
}
}
// TODO: Pressing two keys at the same time can lead to unfortunate behavior.
void input_proc_switches()
{
uint8_t sw;
uint8_t ev;
uint8_t i;
static uint8_t sw_last = 0xFF;
sw = PORT_KEYPAD(PIN) & PIN_KEYPAD_MASK;
ev = sw ^ sw_last;
if (ev) {
if (timer_expired(TIMID_SW_DEBOUNCE)) { // If we read a value, wait for the debounce time before we process any other state
for (i=0; i < 8; ++i) {
if (ev & (1 << i)) {
if (sw & (1 << i)) { // Key release
if (timer_expired(TIMID_SW_LONGPRESS))
i |= (1 << 7) | (1 << 6);
else
i |= (1 << 7);
sw_event = i;
} else { // Key push
sw_event = 0; // To be honest, I don't have a f*cking clue why I need this...
timer_set(TIMID_SW_LONGPRESS, MS_TO_TICKS(1000));
}
timer_set(TIMID_SW_DEBOUNCE, MS_TO_TICKS(250));
break; // We can only process one event at a time anyway, so let's quit it here
}
}
}
sw_last = sw;
}
}
inline uint8_t get_switch_event()
{
return sw_event;
}
inline void input_clear_events()
{
rotary_delta = 16;
sw_event = 0;
}
inline uint8_t get_sbc_state()
{
return (PORT_SBCMON(PIN) & PIN_SBCMON);
}
// Need to call timer_proc() before calling this function!
void input_proc()
{
input_proc_rotary();
input_proc_switches();
}