summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kbc.c550
1 files changed, 407 insertions, 143 deletions
diff --git a/kbc.c b/kbc.c
index 6a161c3..b7bce72 100644
--- a/kbc.c
+++ b/kbc.c
@@ -1,246 +1,510 @@
1#define F_CPU 8*1000000UL
1#include <stdint.h> 2#include <stdint.h>
2#include <string.h> 3#include <string.h>
3#include <avr/io.h> 4#include <avr/io.h>
4#include <avr/interrupt.h> 5#include <avr/interrupt.h>
5#include <avr/sleep.h> 6#include <avr/sleep.h>
7#include <util/delay.h>
6 8
7#ifndef PIN 9#ifndef PIN
8#error need to define a PIN 10#error need to define a PIN
9#endif 11#endif
10 12
11#define B_RED (1 << 0) 13/* port B RJ45
12#define B_YLW (1 << 1) 14 * 0
15 * 1 BEEP (OC1A)
16 * 2 SS up:8
17 * 3 MOSI up:2
18 * 4 MISO up:4
19 * 5 SCK up:7
20 * port C
21 * 0-3
22 * 4 (SDA)
23 * 5 (SCL)
24 * port D
25 * 0 PS2_DATA (RXD) kb:3
26 * 1 PS2_DATA_O (TXD)
27 * 2
28 * 3 PS2_CLK_O (INT1)
29 * 4 PS2_CLK (XCK) kb:2
30 * 5 PS2_PWREN
31 * 6-7
32 */
33
34#define D_DATA (1 << 0)
35#define D_CLK (1 << 4)
36#define D_PWR (1 << 5)
37
38#define B_BEEP (1 << 1)
39#define B_OPEN 0
40#define B_CLOSE 0
41#define B_MISO (1 << 4)
42
43enum state {
44 STATE_NONE = 0,
45 STATE_FAILURE,
46 STATE_POWERUP,
47 STATE_INITRESET,
48 STATE_CONFIG,
49 STATE_IDLE,
50 STATE_IDLEBLINK,
51};
52static volatile enum state state, nextstate;
53
54static void power_up()
55{
56 DDRD = D_PWR;
57 PORTD = D_DATA | D_CLK;
58}
59
60static void power_down()
61{
62 DDRD = D_PWR;
63 PORTD = D_PWR;
64}
13 65
14static void usart_rx() 66static void usart_rx()
15{ 67{
68 UCSR0A = 0;
16 UCSR0B = (1 << RXCIE0) /* recv int en */ 69 UCSR0B = (1 << RXCIE0) /* recv int en */
17 | (1 << RXEN0); /* do RX */ 70 | (1 << RXEN0); /* do RX */
18} 71}
19 72
20static void usart_rxpoll() 73static void usart_rxpoll()
21{ 74{
75 UCSR0A = 0;
22 UCSR0B = (1 << RXEN0); /* do RX*/ 76 UCSR0B = (1 << RXEN0); /* do RX*/
23} 77}
24 78
25static void usart_dis() 79static void usart_dis()
26{ 80{
27 UCSR0B = 0; 81 UCSR0B = 0;
82 (void)UDR0;
28} 83}
29 84
30#define CLK (1 << 3) 85static uint8_t dbgtx[64];
31#define DATA (1 << 1) 86static uint8_t dbgpos;
32 87
33static uint8_t send_byte(uint8_t byte) 88static void dbg_wr(uint8_t what)
34{ 89{
35 uint8_t cntr, bit, parity = 1, rv; 90 cli();
91 if (dbgpos < sizeof(dbgtx))
92 dbgtx[dbgpos++] = what;
93 SPCR = (1 << SPIE) | (1 << SPE);
94 sei();
95}
36 96
37 usart_dis(); 97ISR(SIG_SPI)
38 rv = UDR0; 98{
99 if (dbgpos) {
100 SPDR = dbgtx[0];
101 for (uint8_t c = 0; c < sizeof(dbgtx); c++)
102 dbgtx[c] = dbgtx[c + 1];
103 dbgpos--;
104 } else {
105 SPDR = 0xff;
106 SPCR = (1 << SPE);
107 }
108}
109
110static void dbg_init(void)
111{
112 DDRB |= B_MISO;
113 /* MSB first, cpol = rise,fall, cpha = sample(r),setup(f) */
114 SPCR = (1 << SPIE) | (1 << SPE);
115}
39 116
40 /* make clock low, request clock from keyboard */
41 PORTD = 0;
42 DDRD = CLK;
43 117
44#define delay(x) for (cntr = 0; cntr < x; cntr++) __asm__ volatile ("nop\n")
45 118
46 delay(200);
47 119
48 DDRD = CLK | DATA; 120static volatile uint8_t statecntr = 0;
121
122#define mayabort if (TIFR0 & (1 << TOV0)) return 0;
123#define wait_CLKlo while (PIND & D_CLK) { __asm__ volatile ("nop\n"); mayabort; }
124#define wait_CLKhi while (!(PIND & D_CLK)) { __asm__ volatile ("nop\n"); mayabort; }
125#define wait_CLK wait_CLKhi; wait_CLKlo; _delay_us(5)
126
127static void timer_return(void)
128{
129 TCNT0 = 0;
130 TIFR0 |= (1 << TOV0);
131 __asm__ volatile("nop\n");
132 TIMSK0 = (1 << TOIE0);
133}
134
135static uint8_t do_send_byte(uint8_t byte)
136{
137 uint8_t bit = 0, parity = 1, rv, usarts;
138
139 usart_dis();
140
141 /* make clock low, request clock from keyboard */
142 PORTD &= ~D_CLK;
143 DDRD |= D_CLK;
49 144
50 delay(10); 145 _delay_us(250);
51 146
52 DDRD = DATA; 147 PORTD &= ~D_DATA;
53 PORTD = CLK; 148 DDRD |= D_DATA;
54 149
55#define wait_CLKlo while (PIND & CLK) __asm__ volatile ("nop\n") 150 _delay_us(25);
56#define wait_CLKhi while (!(PIND & CLK)) __asm__ volatile ("nop\n")
57#define wait_CLK wait_CLKhi; wait_CLKlo; delay(3)
58 151
152 DDRD &= ~D_CLK;
153 PORTD |= D_CLK;
154
155 /* data bits */
59 for (bit = 0; bit < 8; bit++) { 156 for (bit = 0; bit < 8; bit++) {
60 wait_CLK; 157 wait_CLK;
61 if (byte & 1) { 158 if (byte & 1) {
62 PORTD = CLK | DATA; 159 PORTD |= D_DATA;
63 parity++; 160 parity ^= 1;
64 } else { 161 } else {
65 PORTD = CLK; 162 PORTD &= ~D_DATA;
66 } 163 }
67 byte >>= 1; 164 byte >>= 1;
68 } 165 }
166 /* parity */
69 wait_CLK; 167 wait_CLK;
70 PORTD = (parity & 1) ? (CLK | DATA) : CLK; 168 if (parity)
169 PORTD |= D_DATA;
170 else
171 PORTD &= ~D_DATA;
172
173 /* stop bit */
71 wait_CLK; 174 wait_CLK;
175 PORTD |= D_DATA;
72 176
73 PORTD = CLK | DATA; 177 /* ACK from keyboard */
74 wait_CLKhi; 178 wait_CLKhi;
75 179 DDRD &= ~D_DATA;
76 DDRD = 0;
77 180
78 wait_CLKlo; 181 wait_CLKlo;
79 wait_CLKhi; 182 wait_CLKhi;
183 while (!(PIND & D_DATA)) { __asm__ volatile ("nop\n"); mayabort; }
184
185 /* response from keyboard */
80 186
81 usart_rxpoll(); 187 usart_rxpoll();
82 188
83 while (!(UCSR0A & (1 << RXC0))) 189 usarts = 0;
84 __asm__ volatile("nop\n"); 190 while (!(usarts & ((1 << RXC0) | (1 << UPE0) | (1 << FE0)))) {
191 __asm__ volatile("nop\nnop\n");
192 usarts = UCSR0A;
193 mayabort;
194 }
85 195
86 rv = UDR0; 196 rv = UDR0;
87 usart_rx(); 197 return rv;
198}
199
200static uint8_t send_byte(uint8_t byte)
201{
202 uint8_t rv, attempts;
203
204 /* stop timer, use for ourselves to enforce 8 ms timeout */
205 TIMSK0 = 0;
206
207 for (attempts = 5; attempts; attempts--) {
208 TCNT0 = 0;
209 TIFR0 |= (1 << TOV0);
210
211 if ((rv = do_send_byte(byte)) == 0xfa) {
212 dbg_wr(0x14);
213 dbg_wr(0x80 | (byte & 0x0f));
214 dbg_wr(0x80 | (byte >> 4));
215 dbg_wr(0x80 | attempts);
216 goto out;
217 }
88 218
219 /* clear state, wait, retry */
220 DDRD &= ~(D_DATA | D_CLK);
221 PORTD |= D_DATA | D_CLK;
222 _delay_us(50);
223 }
224
225 dbg_wr(0x01);
226 dbg_wr(0x80 | (byte & 0x0f));
227 dbg_wr(0x80 | (byte >> 4));
228
229out:
230 /* hand back timer to state machine */
231 timer_return();
232 usart_rx();
89 return rv; 233 return rv;
90} 234}
91 235
92uint8_t ext, brk, pressed, state; 236static uint8_t wait_byte(void)
93const char passwd[4] = PIN; 237{
94char code[sizeof(passwd)]; 238 uint8_t data, usarts;
95 239
96const char kbc_60[32] = { 240 usart_rxpoll();
97 '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */ 241 /* stop timer, use for ourselves to enforce 8 ms timeout */
98 '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */ 242 TIMSK0 = 0;
99 '0', '.', '2', '5', '6', '8', '_', '_', /* 70 - 77 */ 243 TCNT0 = 0;
100 '_', '+', '3', '-', '*', '9', '_', '_' /* 78 - 7f */ 244 TIFR0 |= (1 << TOV0);
101}; 245
246 usarts = 0;
247 while (!(usarts & ((1 << RXC0) | (1 << UPE0) | (1 << FE0)))) {
248 if (TIFR0 & (1 << TOV0)) {
249 (void)UDR0;
250 timer_return();
251 usart_rx();
252
253 dbg_wr(0x02);
254 return 0;
255 }
256
257 __asm__ volatile("nop\nnop\n");
258 usarts = UCSR0A;
259 }
260
261 data = UDR0;
262 timer_return();
263 usart_rx();
264
265 dbg_wr(0x19);
266 dbg_wr(0x80 | (state));
267 dbg_wr(0x80 | (usarts & 0x0f));
268 dbg_wr(0x80 | (usarts >> 4));
269 dbg_wr(0x80 | (data & 0x0f));
270 dbg_wr(0x80 | (data >> 4));
271
272 return data;
273}
102 274
103#define KBLED_STATE 0x02 275#define KBLED_STATE 0x02
104#define KBLED_ERROR 0x04 276#define KBLED_ERROR 0x04
105#define KBLED_OK 0x01 277#define KBLED_OK 0x01
106 278
107#define DDRD_BEEP 0x20 279#define CNTRTOP 122
108#define DDRD_OPEN 0x40 280
109#define DDRD_CLOSE 0x80 281#define ENTER_FAIL 1
282#define WAIT_FAIL 5
283#define WAIT_POWERUP 3
284#define WAIT_INIT 3
285#define WAIT_IDLE 3
110 286
111#define CNTRTOP 96 287#define WAIT_IDLEBLINK 1 /* no full cycle */
112#define CNTRERR 90 288#define CNTR_BLINK 6
113#define CNTRKEYBEEPOFF 4 289
114#define CNTROK 88 /* regulates length of keymatic button press */ 290#define WAIT_ENTRY 15
115#define CNTROK_BEEPOFF 90
116#define CNTROK_BEEPON2 94
117#define OK_WAIT 3 /* mult CNTRTOP */
118 291
119static uint8_t cntr = 0; 292static uint8_t cntr = 0;
120 293
121ISR(SIG_OVERFLOW0) 294static const char passwd[sizeof(PIN)] = PIN;
295static char code[sizeof(PIN)];
296
297static void state_enter(void)
122{ 298{
123 switch (cntr) { 299 dbg_wr(0x11);
124 case CNTRTOP: 300 dbg_wr(state);
125 DDRD = 0; 301
126 if (state > 1) { 302 switch (state) {
127 state--; 303 case STATE_NONE:
128 } else if (state == 1) { 304 case STATE_FAILURE:
129 memset(&code, 0, sizeof(code)); 305 statecntr = WAIT_FAIL;
130 state = 0; 306 usart_dis();
131 } else { 307 power_down();
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; 308 break;
141 case CNTROK_BEEPON2: 309 case STATE_POWERUP:
142 if (state > 1) 310 statecntr = WAIT_POWERUP;
143 DDRD |= DDRD_BEEP; 311 power_up();
312 usart_rx();
144 break; 313 break;
145 case CNTRKEYBEEPOFF: 314 case STATE_INITRESET:
146 DDRD = 0; 315 statecntr = WAIT_INIT;
316 send_byte(0xff);
147 break; 317 break;
148 case 0x00: 318 case STATE_CONFIG:
149 if (state <= 1) { 319 /* statecntr not used */
150 send_byte(0xed); 320 nextstate = STATE_FAILURE;
151 send_byte(state ? KBLED_STATE : 0); 321 if (send_byte(0xed) != 0xfa)
152 } 322 break;
323 if (send_byte(0x00) != 0xfa)
324 break;
325 /* identify */
326 if (send_byte(0xf2) != 0xfa)
327 break;
328 if (wait_byte() != 0xab)
329 break;
330 if (wait_byte() != 0x83)
331 break;
332 /* scan code set 3 */
333 if (send_byte(0xf0) != 0xfa)
334 break;
335 if (send_byte(0x03) != 0xfa)
336 break;
337 /* make codes only */
338 if (send_byte(0xf9) != 0xfa)
339 break;
340 nextstate = STATE_IDLE;
341 break;
342 case STATE_IDLE:
343 statecntr = WAIT_IDLE;
344 nextstate = STATE_FAILURE;
345 if (send_byte(0xed) != 0xfa)
346 break;
347 if (send_byte(0x00) != 0xfa)
348 break;
349 nextstate = STATE_NONE;
350 break;
351 case STATE_IDLEBLINK:
352 statecntr = WAIT_IDLEBLINK;
353 nextstate = STATE_FAILURE;
354 if (send_byte(0xed) != 0xfa)
355 break;
356 if (send_byte(0x01) != 0xfa)
357 break;
358 nextstate = STATE_NONE;
359 cntr = CNTR_BLINK;
153 break; 360 break;
154 } 361 }
155 cntr++;
156} 362}
157 363
158ISR(SIG_USART_RECV) 364static void state_timeout(void)
159{ 365{
160 uint8_t data = UDR0, now; 366 switch (state) {
161 367 case STATE_NONE:
162 if (data == 0xe0) { 368 case STATE_FAILURE:
163 ext = 0x80; 369 state = STATE_POWERUP;
164 return; 370 break;
371 case STATE_POWERUP:
372 state = STATE_INITRESET;
373 break;
374 case STATE_INITRESET:
375 case STATE_CONFIG:
376 state = STATE_FAILURE;
377 break;
378 case STATE_IDLE:
379 state = STATE_IDLEBLINK;
380 break;
381 case STATE_IDLEBLINK:
382 state = STATE_IDLE;
383 break;
165 } 384 }
166 if (data == 0xf0) { 385 state_enter();
167 brk = 1; 386}
168 return; 387
388ISR(SIG_OVERFLOW0)
389{
390 if (!--cntr) {
391 cntr = CNTRTOP;
392 if (statecntr)
393 statecntr--;
169 } 394 }
170 if (data < 0x80) { 395}
171 if (brk) { 396
172 pressed = 0; 397static const char kbc_60[48] = {
173 brk = 0; 398 '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */
174 ext = 0; 399 '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */
175 return; 400 '0', '.', '2', '5', '6', '8', '_', '/', /* 70 - 77 */
401 '_', '_', '3', '_', '+', '9', '*', '_' /* 78 - 7f */
402};
403#define KC_ESC 0x08
404#define KC_ENTER 0x5a
405#define KC_NUM 0x76
406#define KC_NP_ENTER 0x79
407
408static void handle_keypress(uint8_t data)
409{
410 uint8_t unlock, lock;
411 uint8_t ascii = '_';
412 uint8_t c;
413
414 lock = data == KC_ESC || data == KC_NUM;
415 unlock = data == KC_ENTER || data == KC_NP_ENTER;
416
417 if (lock || unlock) {
418 /* passwd: a b c d \0
419 * code: \0 a b c d
420 */
421 if (code[0] || memcmp(passwd, code + 1, sizeof(passwd) - 1)) {
422
423 dbg_wr(0x20);
424 /* state = BLOCK; */
176 } else { 425 } else {
177 now = (data | ext); 426 dbg_wr(lock ? 0x21 : 0x22);
178 ext = 0; 427 /* state = OPENING; */
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 } 428 }
429 memset(&code, 0, sizeof(code));
219 return; 430 return;
220 } 431 }
432
433 if (data >= 0x60 && data < 0x80)
434 ascii = kbc_60[data - 0x60];
435
436 for (c = 0; c < sizeof(code) - 1; c++)
437 code[c] = code[c + 1];
438 code[c] = ascii;
439
440 /* statecntr = WAIT_ENTRY; */
441
442#if 0
443 TCNT0 = 0;
444 state = 1;
445 send_byte(0xed);
446 send_byte(0x00);
447 DDRD = DDRD_BEEP;
448 cntr = 0;
449 TIFR0 = (1 << TOV0);
450#endif
221} 451}
222 452
223int main() 453ISR(SIG_USART_RECV)
224{ 454{
225 DDRB = (1 << 4) | B_RED | B_YLW; 455 uint8_t data = UDR0;
226 PORTB = (1 << 4) | B_RED | B_YLW; 456
457 dbg_wr(0x80 | (data & 0x3f));
458 dbg_wr(0x84 | (data >> 6));
459
460 switch (state) {
461 case STATE_POWERUP:
462 case STATE_INITRESET:
463 if (data == 0xaa)
464 nextstate = STATE_CONFIG;
465 break;
466 case STATE_IDLE:
467 case STATE_IDLEBLINK:
468 if (data < 0x90)
469 handle_keypress(data);
470 default:
471 break;
472 }
473}
227 474
228 DDRD = 0; 475int main()
229 PORTD = 0x3f; 476{
477 dbg_init();
230 478
479 /* /256 = 31'250 Hz = 32 µs per 1 unit
480 * /256 = 122 Hz = 8'192 µs per for overflow
481 * /122 = 1,0006 Hz = 1 s per CNTRTOP */
231 TCCR0A = 0; 482 TCCR0A = 0;
232 TIMSK0 = (1 << TOIE0); 483 TIMSK0 = (1 << TOIE0);
233 TCCR0B = (1 << CS02); 484 TCCR0B = (1 << CS02);
234 485
235 UCSR0C = (1 << UMSEL00) /* synch mode */ 486 UCSR0C = (1 << UMSEL00) /* synch mode */
236 | (1 << UPM01) | (1 << UPM00) /* odd parity */ 487 | (1 << UPM01) | (1 << UPM00) /* odd parity */
237 | (1 << UCSZ01) | (1 << UCSZ00) /* 8-bit chars */ 488 | (1 << UCSZ01) | (1 << UCSZ00) /* 8-bit chars */
238 | (0 << UCPOL0); /* polarity: sample on falling */ 489 | (0 << UCPOL0); /* polarity: sample on falling */
239 490
240 usart_rx(); 491 state = STATE_FAILURE;
492 nextstate = STATE_NONE;
493 state_enter();
241 494
242 sei(); 495 sei();
243 while (1) 496 while (1) {
244 ; 497 if (nextstate != STATE_NONE) {
498 state = nextstate;
499 nextstate = STATE_NONE;
500 state_enter();
501
502 dbg_wr(0x0e);
503 } else if (!statecntr) {
504 state_timeout();
505
506 dbg_wr(0x0e);
507 }
508 }
245} 509}
246 510