#include #include #include #include #include #ifndef PIN #error need to define a PIN #endif #define B_RED (1 << 0) #define B_YLW (1 << 1) static void usart_rx() { UCSR0B = (1 << RXCIE0) /* recv int en */ | (1 << RXEN0); /* do RX */ } static void usart_rxpoll() { UCSR0B = (1 << RXEN0); /* do RX*/ } static void usart_dis() { UCSR0B = 0; } #define CLK (1 << 3) #define DATA (1 << 1) static uint8_t send_byte(uint8_t byte) { uint8_t cntr, bit, parity = 1, rv; usart_dis(); rv = UDR0; /* make clock low, request clock from keyboard */ PORTD = 0; DDRD = CLK; #define delay(x) for (cntr = 0; cntr < x; cntr++) __asm__ volatile ("nop\n") delay(200); DDRD = CLK | DATA; delay(10); DDRD = DATA; PORTD = CLK; #define wait_CLKlo while (PIND & CLK) __asm__ volatile ("nop\n") #define wait_CLKhi while (!(PIND & CLK)) __asm__ volatile ("nop\n") #define wait_CLK wait_CLKhi; wait_CLKlo; delay(3) for (bit = 0; bit < 8; bit++) { wait_CLK; if (byte & 1) { PORTD = CLK | DATA; parity++; } else { PORTD = CLK; } byte >>= 1; } wait_CLK; PORTD = (parity & 1) ? (CLK | DATA) : CLK; wait_CLK; PORTD = CLK | DATA; wait_CLKhi; DDRD = 0; wait_CLKlo; wait_CLKhi; usart_rxpoll(); while (!(UCSR0A & (1 << RXC0))) __asm__ volatile("nop\n"); rv = UDR0; usart_rx(); return rv; } uint8_t ext, brk, pressed, state; const char passwd[4] = PIN; char code[sizeof(passwd)]; const char kbc_60[32] = { '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */ '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */ '0', '.', '2', '5', '6', '8', '_', '_', /* 70 - 77 */ '_', '+', '3', '-', '*', '9', '_', '_' /* 78 - 7f */ }; #define KBLED_STATE 0x02 #define KBLED_ERROR 0x04 #define KBLED_OK 0x01 #define DDRD_BEEP 0x20 #define DDRD_OPEN 0x40 #define DDRD_CLOSE 0x80 #define CNTRTOP 96 #define CNTRERR 90 #define CNTRKEYBEEPOFF 4 #define CNTROK 88 /* regulates length of keymatic button press */ #define CNTROK_BEEPOFF 90 #define CNTROK_BEEPON2 94 #define OK_WAIT 3 /* mult CNTRTOP */ static uint8_t cntr = 0; ISR(SIG_OVERFLOW0) { switch (cntr) { case CNTRTOP: DDRD = 0; if (state > 1) { state--; } else if (state == 1) { memset(&code, 0, sizeof(code)); state = 0; } else { send_byte(0xed); send_byte(KBLED_STATE); } cntr = 0; return; case CNTROK_BEEPOFF: if (state > 1) DDRD &= ~DDRD_BEEP; break; case CNTROK_BEEPON2: if (state > 1) DDRD |= DDRD_BEEP; break; case CNTRKEYBEEPOFF: DDRD = 0; break; case 0x00: if (state <= 1) { send_byte(0xed); send_byte(state ? KBLED_STATE : 0); } break; } cntr++; } ISR(SIG_USART_RECV) { uint8_t data = UDR0, now; if (data == 0xe0) { ext = 0x80; return; } if (data == 0xf0) { brk = 1; return; } if (data < 0x80) { if (brk) { pressed = 0; brk = 0; ext = 0; return; } else { now = (data | ext); ext = 0; if (pressed == now) return; pressed = now; if (pressed > 0x60 && pressed < 0x80 && pressed != 0x76 && pressed != 0x77) { uint8_t c; for (c = 1; c < sizeof(code); c++) code[c - 1] = code[c]; code[sizeof(code) - 1] = kbc_60[pressed - 0x60]; TCNT0 = 0; state = 1; send_byte(0xed); send_byte(0x00); DDRD = DDRD_BEEP; cntr = 0; TIFR0 = (1 << TOV0); }; if (pressed == 0xda || pressed == 0x76 || pressed == 0x77) { if (memcmp(passwd, code, sizeof(passwd))) { TCNT0 = 0; memset(&code, 0, sizeof(code)); state = 0; send_byte(0xed); send_byte(KBLED_ERROR); DDRD = DDRD_BEEP; cntr = CNTRERR; TIFR0 = (1 << TOV0); return; } TCNT0 = 0; send_byte(0xed); send_byte(KBLED_OK); state = OK_WAIT; cntr = CNTROK; TIFR0 = (1 << TOV0); DDRD = DDRD_BEEP | ((pressed == 0xda) ? DDRD_OPEN : DDRD_CLOSE); } } return; } } int main() { DDRB = (1 << 4) | B_RED | B_YLW; PORTB = (1 << 4) | B_RED | B_YLW; DDRD = 0; PORTD = 0x3f; TCCR0A = 0; TIMSK0 = (1 << TOIE0); TCCR0B = (1 << CS02); UCSR0C = (1 << UMSEL00) /* synch mode */ | (1 << UPM01) | (1 << UPM00) /* odd parity */ | (1 << UCSZ01) | (1 << UCSZ00) /* 8-bit chars */ | (0 << UCPOL0); /* polarity: sample on falling */ usart_rx(); sei(); while (1) ; }