From 9054f9a5267bee98cdf73bfd4ef368e3512f0491 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 11 Dec 2012 23:06:23 +0100 Subject: Snake --- kbd.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 kbd.c (limited to 'kbd.c') diff --git a/kbd.c b/kbd.c new file mode 100644 index 0000000..e3342e9 --- /dev/null +++ b/kbd.c @@ -0,0 +1,167 @@ +#include "kbd.h" + +#include +#include +#include + +#include +#include + + +static volatile int8_t kbd_state = 0; + +static volatile uint8_t kbd_input = 0; +static volatile uint8_t kbd_output = 0; +static volatile uint8_t kbd_flags = 0; + + +static volatile uint8_t ts = 10; + + +static inline bool kbd_data() { + return (PINC & (1 << 0)); +} + +static inline bool kbd_clock() { + return (PINC & (1 << 1)); +} + + +static inline void kbd_clock_down() { + DDRC |= 0x02; + PORTC &= ~0x02; +} + +static inline void kbd_clock_in() { + DDRC &= ~0x02; + PORTC |= 0x02; +} + +static inline void kbd_data_set(bool state) { + if (state) + PORTC |= 0x01; + else + PORTC &= ~0x01; +} + +static inline void kbd_data_out() { + DDRC |= 0x01; +} + +static inline void kbd_data_in() { + DDRC &= ~0x01; + PORTC |= 0x01; +} + + +static inline void kbd_wait() { + while (kbd_state) {} +} + + +ISR(PCINT1_vect) { + if (kbd_clock()) + return; + + if (kbd_state < 0) { + if (kbd_state >= -8) { + kbd_data_set(kbd_output & _BV(-1-kbd_state)); + } + else if (kbd_state == -9) { + kbd_data_set(!(__builtin_popcount(kbd_output) & 1)); + } + else if (kbd_state == -10) { + kbd_data_in(); + } + else { + kbd_state = 0; + return; + } + + kbd_state--; + return; + } + + bool data = kbd_data(); + + if (kbd_state == 0) { + if (!data) { /* start bit */ + kbd_input = 0; + kbd_state++; + } + + return; + } + + if (kbd_state <= 8) { + if (data) + kbd_input |= _BV(kbd_state-1); + kbd_state++; + return; + } + + if (kbd_state == 9) { + if ((__builtin_popcount(kbd_input) & 1) == data) + kbd_flags |= KBD_FLAG_ERROR; + + kbd_state++; + return; + } + + kbd_state = 0; + + if (kbd_flags & KBD_FLAG_ERROR) { + /* Retry */ + return; + } + + if (kbd_input == 0xe0) { + kbd_flags |= KBD_FLAG_EXT; + return; + } + + if (kbd_input == 0xf0) { + kbd_flags |= KBD_FLAG_BREAK; + return; + } + + uint16_t code = kbd_input; + if (kbd_flags & KBD_FLAG_EXT) + code |= 0xe000; + + kbd_handle(code, !(kbd_flags & KBD_FLAG_BREAK)); + + kbd_flags = 0; +} + + +void kbd_send(uint8_t command) { + kbd_wait(); + + kbd_clock_down(); + _delay_us(100); + + kbd_data_out(); + kbd_data_set(false); + _delay_us(10); + + kbd_clock_in(); + + kbd_output = command; + kbd_state = -1; + + kbd_wait(); + + /* wait for ack */ + while (!kbd_state) {} + + kbd_wait(); +} + +void kbd_init(void) { + DDRC &= ~0x03; + PORTC |= 0x03; + + PCMSK1 = (1 << PCINT9); + PCICR = (1 << PCIE1); +} -- cgit v1.2.3