webradio/firmware/input.c

116 lines
2.4 KiB
C
Raw Permalink Normal View History

2020-07-27 21:39:29 +02:00
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "input.h"
#include "systick.h"
2020-08-09 12:14:21 +02:00
static volatile uint8_t rotary_delta = 0;
2020-07-27 21:39:29 +02:00
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
2020-07-27 21:39:29 +02:00
PORT_KEYPAD(DDR) &= ~(PIN_KEYPAD_MASK); // Key inputs
PORT_KEYPAD(PORT) |= PIN_KEYPAD_MASK; // Key pullups
2020-07-31 19:07:11 +02:00
PORT_SBCMON(DDR) &= ~PIN_SBCMON;
PORT_SBCMON(PORT) |= PIN_SBCMON;
2020-07-27 21:39:29 +02:00
}
2020-08-09 12:14:21 +02:00
inline uint8_t get_rotary_delta()
2020-07-27 21:39:29 +02:00
{
return rotary_delta;
2020-07-27 21:39:29 +02:00
}
2020-07-30 21:41:22 +02:00
#define ROTARY_DEBOUNCE 150
2020-07-27 21:39:29 +02:00
static inline void input_proc_rotary()
{
static int8_t last_a;
int8_t a;
int8_t b;
int8_t p;
2020-07-30 21:41:22 +02:00
uint8_t silly_debounce = 0;
2020-07-27 21:39:29 +02:00
2020-07-30 21:41:22 +02:00
if (silly_debounce == 0) {
p = PORT_ROTARY(PIN);
a = (p & PIN_ROTARY_A);
b = (p & PIN_ROTARY_B);
a = !a;
b = !b;
2020-07-27 21:39:29 +02:00
2020-07-30 21:41:22 +02:00
if (a == 1 && last_a == 0) {
silly_debounce = ROTARY_DEBOUNCE;
2020-08-09 12:14:21 +02:00
if (rotary_delta < 31)
rotary_delta += !!(a ^ b);
2020-07-30 21:41:22 +02:00
}
if (a == 0 && last_a == 1) {
silly_debounce = ROTARY_DEBOUNCE;
2020-08-09 12:14:21 +02:00
if (rotary_delta > 0)
rotary_delta -= !(a ^ b);
2020-07-30 21:41:22 +02:00
}
2020-07-27 21:39:29 +02:00
2020-07-30 21:41:22 +02:00
last_a = a;
} else {
silly_debounce--;
}
2020-07-27 21:39:29 +02:00
}
// 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()
2020-07-27 21:39:29 +02:00
{
return sw_event;
}
inline void input_clear_events()
{
2020-08-09 12:14:21 +02:00
rotary_delta = 16;
2020-07-27 21:39:29 +02:00
sw_event = 0;
}
2020-07-31 19:07:11 +02:00
inline uint8_t get_sbc_state()
{
2020-07-31 19:18:26 +02:00
return (PORT_SBCMON(PIN) & PIN_SBCMON);
2020-07-31 19:07:11 +02:00
}
2020-07-27 21:39:29 +02:00
// Need to call timer_proc() before calling this function!
void input_proc()
{
input_proc_rotary();
input_proc_switches();
}