summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile38
-rw-r--r--kbc.c246
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 @@
1*.o
2*.flash
3*.eeprom
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..642202a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
1MCU=atmega48
2AVRDUDE=avrdude
3ACC=avr-gcc
4AOBJCOPY=avr-objcopy
5ALD=avr-ld
6CFLAGS=-Wall -Wextra -Wno-unused-parameter -pedantic -std=c99
7ifdef PIN
8DPIN=-DPIN=\"$(PIN)\"
9endif
10ACFLAGS=-g -mmcu=$(MCU) $(CFLAGS) $(DPIN) -Os -mcall-prologues
11# ALDFLAGS=-L/usr/avr/lib/avr4 -L/usr/lib/binutils/avr/2.18
12LD=gcc
13CC=gcc
14CXX=g++ -g
15LDXX=g++ -g
16
17love: kbc.flash
18
19%.flash: %.ld.o
20 $(AOBJCOPY) -O binary $< $@
21
22%.eeprom: %.ld.o
23 $(AOBJCOPY) -j .eeprom -O binary $^ $@
24
25%.ld.o: %.o
26 $(ACC) $(ACFLAGS) $(ALDFLAGS) -o $@ $<
27
28%.o: %.c
29 $(ACC) $(ACFLAGS) -c -o $@ $<
30
31flash: kbc.flash
32 $(AVRDUDE) -y -p m48 -E noreset -U $^
33
34clean:
35 rm -f *.flash *.eeprom *.o
36
37.PHONY: love flash clean
38
diff --git a/kbc.c b/kbc.c
new file mode 100644
index 0000000..6a161c3
--- /dev/null
+++ b/kbc.c
@@ -0,0 +1,246 @@
1#include <stdint.h>
2#include <string.h>
3#include <avr/io.h>
4#include <avr/interrupt.h>
5#include <avr/sleep.h>
6
7#ifndef PIN
8#error need to define a PIN
9#endif
10
11#define B_RED (1 << 0)
12#define B_YLW (1 << 1)
13
14static void usart_rx()
15{
16 UCSR0B = (1 << RXCIE0) /* recv int en */
17 | (1 << RXEN0); /* do RX */
18}
19
20static void usart_rxpoll()
21{
22 UCSR0B = (1 << RXEN0); /* do RX*/
23}
24
25static void usart_dis()
26{
27 UCSR0B = 0;
28}
29
30#define CLK (1 << 3)
31#define DATA (1 << 1)
32
33static uint8_t send_byte(uint8_t byte)
34{
35 uint8_t cntr, bit, parity = 1, rv;
36
37 usart_dis();
38 rv = UDR0;
39
40 /* make clock low, request clock from keyboard */
41 PORTD = 0;
42 DDRD = CLK;
43
44#define delay(x) for (cntr = 0; cntr < x; cntr++) __asm__ volatile ("nop\n")
45
46 delay(200);
47
48 DDRD = CLK | DATA;
49
50 delay(10);
51
52 DDRD = DATA;
53 PORTD = CLK;
54
55#define wait_CLKlo while (PIND & CLK) __asm__ volatile ("nop\n")
56#define wait_CLKhi while (!(PIND & CLK)) __asm__ volatile ("nop\n")
57#define wait_CLK wait_CLKhi; wait_CLKlo; delay(3)
58
59 for (bit = 0; bit < 8; bit++) {
60 wait_CLK;
61 if (byte & 1) {
62 PORTD = CLK | DATA;
63 parity++;
64 } else {
65 PORTD = CLK;
66 }
67 byte >>= 1;
68 }
69 wait_CLK;
70 PORTD = (parity & 1) ? (CLK | DATA) : CLK;
71 wait_CLK;
72
73 PORTD = CLK | DATA;
74 wait_CLKhi;
75
76 DDRD = 0;
77
78 wait_CLKlo;
79 wait_CLKhi;
80
81 usart_rxpoll();
82
83 while (!(UCSR0A & (1 << RXC0)))
84 __asm__ volatile("nop\n");
85
86 rv = UDR0;
87 usart_rx();
88
89 return rv;
90}
91
92uint8_t ext, brk, pressed, state;
93const char passwd[4] = PIN;
94char code[sizeof(passwd)];
95
96const char kbc_60[32] = {
97 '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */
98 '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */
99 '0', '.', '2', '5', '6', '8', '_', '_', /* 70 - 77 */
100 '_', '+', '3', '-', '*', '9', '_', '_' /* 78 - 7f */
101};
102
103#define KBLED_STATE 0x02
104#define KBLED_ERROR 0x04
105#define KBLED_OK 0x01
106
107#define DDRD_BEEP 0x20
108#define DDRD_OPEN 0x40
109#define DDRD_CLOSE 0x80
110
111#define CNTRTOP 96
112#define CNTRERR 90
113#define CNTRKEYBEEPOFF 4
114#define CNTROK 88 /* regulates length of keymatic button press */
115#define CNTROK_BEEPOFF 90
116#define CNTROK_BEEPON2 94
117#define OK_WAIT 3 /* mult CNTRTOP */
118
119static uint8_t cntr = 0;
120
121ISR(SIG_OVERFLOW0)
122{
123 switch (cntr) {
124 case CNTRTOP:
125 DDRD = 0;
126 if (state > 1) {
127 state--;
128 } else if (state == 1) {
129 memset(&code, 0, sizeof(code));
130 state = 0;
131 } else {
132 send_byte(0xed);
133 send_byte(KBLED_STATE);
134 }
135 cntr = 0;
136 return;
137 case CNTROK_BEEPOFF:
138 if (state > 1)
139 DDRD &= ~DDRD_BEEP;
140 break;
141 case CNTROK_BEEPON2:
142 if (state > 1)
143 DDRD |= DDRD_BEEP;
144 break;
145 case CNTRKEYBEEPOFF:
146 DDRD = 0;
147 break;
148 case 0x00:
149 if (state <= 1) {
150 send_byte(0xed);
151 send_byte(state ? KBLED_STATE : 0);
152 }
153 break;
154 }
155 cntr++;
156}
157
158ISR(SIG_USART_RECV)
159{
160 uint8_t data = UDR0, now;
161
162 if (data == 0xe0) {
163 ext = 0x80;
164 return;
165 }
166 if (data == 0xf0) {
167 brk = 1;
168 return;
169 }
170 if (data < 0x80) {
171 if (brk) {
172 pressed = 0;
173 brk = 0;
174 ext = 0;
175 return;
176 } else {
177 now = (data | ext);
178 ext = 0;
179 if (pressed == now)
180 return;
181 pressed = now;
182
183 if (pressed > 0x60 && pressed < 0x80 && pressed != 0x76 && pressed != 0x77) {
184 uint8_t c;
185 for (c = 1; c < sizeof(code); c++)
186 code[c - 1] = code[c];
187 code[sizeof(code) - 1] = kbc_60[pressed - 0x60];
188
189 TCNT0 = 0;
190 state = 1;
191 send_byte(0xed);
192 send_byte(0x00);
193 DDRD = DDRD_BEEP;
194 cntr = 0;
195 TIFR0 = (1 << TOV0);
196 };
197 if (pressed == 0xda || pressed == 0x76 || pressed == 0x77) {
198 if (memcmp(passwd, code, sizeof(passwd))) {
199 TCNT0 = 0;
200 memset(&code, 0, sizeof(code));
201 state = 0;
202 send_byte(0xed);
203 send_byte(KBLED_ERROR);
204 DDRD = DDRD_BEEP;
205 cntr = CNTRERR;
206 TIFR0 = (1 << TOV0);
207 return;
208 }
209 TCNT0 = 0;
210 send_byte(0xed);
211 send_byte(KBLED_OK);
212 state = OK_WAIT;
213 cntr = CNTROK;
214 TIFR0 = (1 << TOV0);
215
216 DDRD = DDRD_BEEP | ((pressed == 0xda) ? DDRD_OPEN : DDRD_CLOSE);
217 }
218 }
219 return;
220 }
221}
222
223int main()
224{
225 DDRB = (1 << 4) | B_RED | B_YLW;
226 PORTB = (1 << 4) | B_RED | B_YLW;
227
228 DDRD = 0;
229 PORTD = 0x3f;
230
231 TCCR0A = 0;
232 TIMSK0 = (1 << TOIE0);
233 TCCR0B = (1 << CS02);
234
235 UCSR0C = (1 << UMSEL00) /* synch mode */
236 | (1 << UPM01) | (1 << UPM00) /* odd parity */
237 | (1 << UCSZ01) | (1 << UCSZ00) /* 8-bit chars */
238 | (0 << UCPOL0); /* polarity: sample on falling */
239
240 usart_rx();
241
242 sei();
243 while (1)
244 ;
245}
246