From 2bd7cc35f223bf439353b3ff7a0623baf637bc21 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 10 Dec 2012 16:46:49 +0100 Subject: Remove ard prefix from file names --- kbd.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 kbd.c (limited to 'kbd.c') diff --git a/kbd.c b/kbd.c new file mode 100644 index 0000000..02c23a5 --- /dev/null +++ b/kbd.c @@ -0,0 +1,216 @@ +#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; + + +#define KBD_FLAG_ERROR (_BV(0)) +#define KBD_FLAG_BREAK (_BV(1)) +#define KBD_FLAG_EXT (_BV(2)) + +#define KBD_CODE_UP 0xe075 +#define KBD_CODE_LEFT 0xe06b +#define KBD_CODE_DOWN 0xe072 +#define KBD_CODE_RIGHT 0xe074 + + + +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; + + if (!(kbd_flags & KBD_FLAG_BREAK)) { + switch (code) { + case KBD_CODE_UP: + if (ts > 0) + ts--; + break; + + case KBD_CODE_DOWN: + if (ts < 31) + ts++; + 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(); +} + + +int main(void) { + DDRB = 0xff; + PORTB = 0; + + DDRC = 0x00; + PORTC = 0x03; + + PCMSK1 = (1 << PCINT9); + PCICR = (1 << PCIE1); + + sei(); + + kbd_send(0xff); + + uint8_t l = 0; + + while(true) { + uint8_t state = PORTB ^ 0x20; + PORTB = state; + + if (state & 0x20) { + l = (l+1)%3; + + kbd_send(0xed); + kbd_send(1 << l); + } + + uint32_t i; + for (i = 0; i < (1 << ts); i++) + _delay_ms(1); + } + + return 0; +} -- cgit v1.2.3