#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)); } ISR(PCINT1_vect) { if (kbd_clock()) return; if (kbd_state < 0) { if (kbd_state >= -8) { if (kbd_output & (1 << (-1-kbd_state))) PORTC |= 0x01; else PORTC &= ~0x01; kbd_state--; return; } if (kbd_state == -9) { if ((__builtin_popcount(kbd_output) & 1) == 0) PORTC |= 0x01; else PORTC &= ~0x01; kbd_state--; return; } if (kbd_state == -10) { kbd_state--; DDRC &= ~0x01; PORTC |= 0x01; return; } kbd_state = 0; return; } bool data = kbd_data(); if (kbd_state == 0) { if (!data) { /* start bit */ kbd_input = 0; kbd_state++; } return; } if (kbd_state <= 8) { kbd_input |= (data << (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) { while (kbd_state) {} /* wait for idle */ DDRC |= 0x02; PORTC &= ~0x02; _delay_us(100); DDRC |= 0x01; PORTC &= ~0x01; _delay_us(10); DDRC &= ~0x02; PORTC |= 0x02; kbd_output = command; kbd_state = -1; /* wait for idle */ while (kbd_state) {} while (!kbd_state) {} while (kbd_state) {} } 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; }