116 lines
2.4 KiB
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();
|
|
}
|