diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 38 | ||||
-rw-r--r-- | kbc.c | 246 |
3 files changed, 287 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b31adb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.flash +*.eeprom diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..642202a --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +MCU=atmega48 +AVRDUDE=avrdude +ACC=avr-gcc +AOBJCOPY=avr-objcopy +ALD=avr-ld +CFLAGS=-Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 +ifdef PIN +DPIN=-DPIN=\"$(PIN)\" +endif +ACFLAGS=-g -mmcu=$(MCU) $(CFLAGS) $(DPIN) -Os -mcall-prologues +# ALDFLAGS=-L/usr/avr/lib/avr4 -L/usr/lib/binutils/avr/2.18 +LD=gcc +CC=gcc +CXX=g++ -g +LDXX=g++ -g + +love: kbc.flash + +%.flash: %.ld.o + $(AOBJCOPY) -O binary $< $@ + +%.eeprom: %.ld.o + $(AOBJCOPY) -j .eeprom -O binary $^ $@ + +%.ld.o: %.o + $(ACC) $(ACFLAGS) $(ALDFLAGS) -o $@ $< + +%.o: %.c + $(ACC) $(ACFLAGS) -c -o $@ $< + +flash: kbc.flash + $(AVRDUDE) -y -p m48 -E noreset -U $^ + +clean: + rm -f *.flash *.eeprom *.o + +.PHONY: love flash clean + @@ -0,0 +1,246 @@ +#include <stdint.h> +#include <string.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/sleep.h> + +#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) + ; +} + |