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 @@
+#define F_CPU 8*1000000UL
#include <stdint.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
+#include <util/delay.h>
#ifndef PIN
#error need to define a PIN
#endif
-#define B_RED (1 << 0)
-#define B_YLW (1 << 1)
+/* port B RJ45
+ * 0
+ * 1 BEEP (OC1A)
+ * 2 SS up:8
+ * 3 MOSI up:2
+ * 4 MISO up:4
+ * 5 SCK up:7
+ * port C
+ * 0-3
+ * 4 (SDA)
+ * 5 (SCL)
+ * port D
+ * 0 PS2_DATA (RXD) kb:3
+ * 1 PS2_DATA_O (TXD)
+ * 2
+ * 3 PS2_CLK_O (INT1)
+ * 4 PS2_CLK (XCK) kb:2
+ * 5 PS2_PWREN
+ * 6-7
+ */
+
+#define D_DATA (1 << 0)
+#define D_CLK (1 << 4)
+#define D_PWR (1 << 5)
+
+#define B_BEEP (1 << 1)
+#define B_OPEN 0
+#define B_CLOSE 0
+#define B_MISO (1 << 4)
+
+enum state {
+ STATE_NONE = 0,
+ STATE_FAILURE,
+ STATE_POWERUP,
+ STATE_INITRESET,
+ STATE_CONFIG,
+ STATE_IDLE,
+ STATE_IDLEBLINK,
+};
+static volatile enum state state, nextstate;
+
+static void power_up()
+{
+ DDRD = D_PWR;
+ PORTD = D_DATA | D_CLK;
+}
+
+static void power_down()
+{
+ DDRD = D_PWR;
+ PORTD = D_PWR;
+}
static void usart_rx()
{
+ UCSR0A = 0;
UCSR0B = (1 << RXCIE0) /* recv int en */
| (1 << RXEN0); /* do RX */
}
static void usart_rxpoll()
{
+ UCSR0A = 0;
UCSR0B = (1 << RXEN0); /* do RX*/
}
static void usart_dis()
{
UCSR0B = 0;
+ (void)UDR0;
}
-#define CLK (1 << 3)
-#define DATA (1 << 1)
+static uint8_t dbgtx[64];
+static uint8_t dbgpos;
-static uint8_t send_byte(uint8_t byte)
+static void dbg_wr(uint8_t what)
{
- uint8_t cntr, bit, parity = 1, rv;
+ cli();
+ if (dbgpos < sizeof(dbgtx))
+ dbgtx[dbgpos++] = what;
+ SPCR = (1 << SPIE) | (1 << SPE);
+ sei();
+}
- usart_dis();
- rv = UDR0;
+ISR(SIG_SPI)
+{
+ if (dbgpos) {
+ SPDR = dbgtx[0];
+ for (uint8_t c = 0; c < sizeof(dbgtx); c++)
+ dbgtx[c] = dbgtx[c + 1];
+ dbgpos--;
+ } else {
+ SPDR = 0xff;
+ SPCR = (1 << SPE);
+ }
+}
+
+static void dbg_init(void)
+{
+ DDRB |= B_MISO;
+ /* MSB first, cpol = rise,fall, cpha = sample(r),setup(f) */
+ SPCR = (1 << SPIE) | (1 << SPE);
+}
- /* 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;
+static volatile uint8_t statecntr = 0;
+
+#define mayabort if (TIFR0 & (1 << TOV0)) return 0;
+#define wait_CLKlo while (PIND & D_CLK) { __asm__ volatile ("nop\n"); mayabort; }
+#define wait_CLKhi while (!(PIND & D_CLK)) { __asm__ volatile ("nop\n"); mayabort; }
+#define wait_CLK wait_CLKhi; wait_CLKlo; _delay_us(5)
+
+static void timer_return(void)
+{
+ TCNT0 = 0;
+ TIFR0 |= (1 << TOV0);
+ __asm__ volatile("nop\n");
+ TIMSK0 = (1 << TOIE0);
+}
+
+static uint8_t do_send_byte(uint8_t byte)
+{
+ uint8_t bit = 0, parity = 1, rv, usarts;
+
+ usart_dis();
+
+ /* make clock low, request clock from keyboard */
+ PORTD &= ~D_CLK;
+ DDRD |= D_CLK;
- delay(10);
+ _delay_us(250);
- DDRD = DATA;
- PORTD = CLK;
+ PORTD &= ~D_DATA;
+ DDRD |= D_DATA;
-#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)
+ _delay_us(25);
+ DDRD &= ~D_CLK;
+ PORTD |= D_CLK;
+
+ /* data bits */
for (bit = 0; bit < 8; bit++) {
wait_CLK;
if (byte & 1) {
- PORTD = CLK | DATA;
- parity++;
+ PORTD |= D_DATA;
+ parity ^= 1;
} else {
- PORTD = CLK;
+ PORTD &= ~D_DATA;
}
byte >>= 1;
}
+ /* parity */
wait_CLK;
- PORTD = (parity & 1) ? (CLK | DATA) : CLK;
+ if (parity)
+ PORTD |= D_DATA;
+ else
+ PORTD &= ~D_DATA;
+
+ /* stop bit */
wait_CLK;
+ PORTD |= D_DATA;
- PORTD = CLK | DATA;
+ /* ACK from keyboard */
wait_CLKhi;
-
- DDRD = 0;
+ DDRD &= ~D_DATA;
wait_CLKlo;
wait_CLKhi;
+ while (!(PIND & D_DATA)) { __asm__ volatile ("nop\n"); mayabort; }
+
+ /* response from keyboard */
usart_rxpoll();
- while (!(UCSR0A & (1 << RXC0)))
- __asm__ volatile("nop\n");
+ usarts = 0;
+ while (!(usarts & ((1 << RXC0) | (1 << UPE0) | (1 << FE0)))) {
+ __asm__ volatile("nop\nnop\n");
+ usarts = UCSR0A;
+ mayabort;
+ }
rv = UDR0;
- usart_rx();
+ return rv;
+}
+
+static uint8_t send_byte(uint8_t byte)
+{
+ uint8_t rv, attempts;
+
+ /* stop timer, use for ourselves to enforce 8 ms timeout */
+ TIMSK0 = 0;
+
+ for (attempts = 5; attempts; attempts--) {
+ TCNT0 = 0;
+ TIFR0 |= (1 << TOV0);
+
+ if ((rv = do_send_byte(byte)) == 0xfa) {
+ dbg_wr(0x14);
+ dbg_wr(0x80 | (byte & 0x0f));
+ dbg_wr(0x80 | (byte >> 4));
+ dbg_wr(0x80 | attempts);
+ goto out;
+ }
+ /* clear state, wait, retry */
+ DDRD &= ~(D_DATA | D_CLK);
+ PORTD |= D_DATA | D_CLK;
+ _delay_us(50);
+ }
+
+ dbg_wr(0x01);
+ dbg_wr(0x80 | (byte & 0x0f));
+ dbg_wr(0x80 | (byte >> 4));
+
+out:
+ /* hand back timer to state machine */
+ timer_return();
+ usart_rx();
return rv;
}
-uint8_t ext, brk, pressed, state;
-const char passwd[4] = PIN;
-char code[sizeof(passwd)];
+static uint8_t wait_byte(void)
+{
+ uint8_t data, usarts;
-const char kbc_60[32] = {
- '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */
- '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */
- '0', '.', '2', '5', '6', '8', '_', '_', /* 70 - 77 */
- '_', '+', '3', '-', '*', '9', '_', '_' /* 78 - 7f */
-};
+ usart_rxpoll();
+ /* stop timer, use for ourselves to enforce 8 ms timeout */
+ TIMSK0 = 0;
+ TCNT0 = 0;
+ TIFR0 |= (1 << TOV0);
+
+ usarts = 0;
+ while (!(usarts & ((1 << RXC0) | (1 << UPE0) | (1 << FE0)))) {
+ if (TIFR0 & (1 << TOV0)) {
+ (void)UDR0;
+ timer_return();
+ usart_rx();
+
+ dbg_wr(0x02);
+ return 0;
+ }
+
+ __asm__ volatile("nop\nnop\n");
+ usarts = UCSR0A;
+ }
+
+ data = UDR0;
+ timer_return();
+ usart_rx();
+
+ dbg_wr(0x19);
+ dbg_wr(0x80 | (state));
+ dbg_wr(0x80 | (usarts & 0x0f));
+ dbg_wr(0x80 | (usarts >> 4));
+ dbg_wr(0x80 | (data & 0x0f));
+ dbg_wr(0x80 | (data >> 4));
+
+ return data;
+}
#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 122
+
+#define ENTER_FAIL 1
+#define WAIT_FAIL 5
+#define WAIT_POWERUP 3
+#define WAIT_INIT 3
+#define WAIT_IDLE 3
-#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 */
+#define WAIT_IDLEBLINK 1 /* no full cycle */
+#define CNTR_BLINK 6
+
+#define WAIT_ENTRY 15
static uint8_t cntr = 0;
-ISR(SIG_OVERFLOW0)
+static const char passwd[sizeof(PIN)] = PIN;
+static char code[sizeof(PIN)];
+
+static void state_enter(void)
{
- 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;
+ dbg_wr(0x11);
+ dbg_wr(state);
+
+ switch (state) {
+ case STATE_NONE:
+ case STATE_FAILURE:
+ statecntr = WAIT_FAIL;
+ usart_dis();
+ power_down();
break;
- case CNTROK_BEEPON2:
- if (state > 1)
- DDRD |= DDRD_BEEP;
+ case STATE_POWERUP:
+ statecntr = WAIT_POWERUP;
+ power_up();
+ usart_rx();
break;
- case CNTRKEYBEEPOFF:
- DDRD = 0;
+ case STATE_INITRESET:
+ statecntr = WAIT_INIT;
+ send_byte(0xff);
break;
- case 0x00:
- if (state <= 1) {
- send_byte(0xed);
- send_byte(state ? KBLED_STATE : 0);
- }
+ case STATE_CONFIG:
+ /* statecntr not used */
+ nextstate = STATE_FAILURE;
+ if (send_byte(0xed) != 0xfa)
+ break;
+ if (send_byte(0x00) != 0xfa)
+ break;
+ /* identify */
+ if (send_byte(0xf2) != 0xfa)
+ break;
+ if (wait_byte() != 0xab)
+ break;
+ if (wait_byte() != 0x83)
+ break;
+ /* scan code set 3 */
+ if (send_byte(0xf0) != 0xfa)
+ break;
+ if (send_byte(0x03) != 0xfa)
+ break;
+ /* make codes only */
+ if (send_byte(0xf9) != 0xfa)
+ break;
+ nextstate = STATE_IDLE;
+ break;
+ case STATE_IDLE:
+ statecntr = WAIT_IDLE;
+ nextstate = STATE_FAILURE;
+ if (send_byte(0xed) != 0xfa)
+ break;
+ if (send_byte(0x00) != 0xfa)
+ break;
+ nextstate = STATE_NONE;
+ break;
+ case STATE_IDLEBLINK:
+ statecntr = WAIT_IDLEBLINK;
+ nextstate = STATE_FAILURE;
+ if (send_byte(0xed) != 0xfa)
+ break;
+ if (send_byte(0x01) != 0xfa)
+ break;
+ nextstate = STATE_NONE;
+ cntr = CNTR_BLINK;
break;
}
- cntr++;
}
-ISR(SIG_USART_RECV)
+static void state_timeout(void)
{
- uint8_t data = UDR0, now;
-
- if (data == 0xe0) {
- ext = 0x80;
- return;
+ switch (state) {
+ case STATE_NONE:
+ case STATE_FAILURE:
+ state = STATE_POWERUP;
+ break;
+ case STATE_POWERUP:
+ state = STATE_INITRESET;
+ break;
+ case STATE_INITRESET:
+ case STATE_CONFIG:
+ state = STATE_FAILURE;
+ break;
+ case STATE_IDLE:
+ state = STATE_IDLEBLINK;
+ break;
+ case STATE_IDLEBLINK:
+ state = STATE_IDLE;
+ break;
}
- if (data == 0xf0) {
- brk = 1;
- return;
+ state_enter();
+}
+
+ISR(SIG_OVERFLOW0)
+{
+ if (!--cntr) {
+ cntr = CNTRTOP;
+ if (statecntr)
+ statecntr--;
}
- if (data < 0x80) {
- if (brk) {
- pressed = 0;
- brk = 0;
- ext = 0;
- return;
+}
+
+static const char kbc_60[48] = {
+ '_', '_', '_', '_', '_', '_', '_', '_', /* 60 - 67 */
+ '_', '1', '_', '4', '7', '_', '_', '_', /* 68 - 6f */
+ '0', '.', '2', '5', '6', '8', '_', '/', /* 70 - 77 */
+ '_', '_', '3', '_', '+', '9', '*', '_' /* 78 - 7f */
+};
+#define KC_ESC 0x08
+#define KC_ENTER 0x5a
+#define KC_NUM 0x76
+#define KC_NP_ENTER 0x79
+
+static void handle_keypress(uint8_t data)
+{
+ uint8_t unlock, lock;
+ uint8_t ascii = '_';
+ uint8_t c;
+
+ lock = data == KC_ESC || data == KC_NUM;
+ unlock = data == KC_ENTER || data == KC_NP_ENTER;
+
+ if (lock || unlock) {
+ /* passwd: a b c d \0
+ * code: \0 a b c d
+ */
+ if (code[0] || memcmp(passwd, code + 1, sizeof(passwd) - 1)) {
+
+ dbg_wr(0x20);
+ /* state = BLOCK; */
} 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);
- }
+ dbg_wr(lock ? 0x21 : 0x22);
+ /* state = OPENING; */
}
+ memset(&code, 0, sizeof(code));
return;
}
+
+ if (data >= 0x60 && data < 0x80)
+ ascii = kbc_60[data - 0x60];
+
+ for (c = 0; c < sizeof(code) - 1; c++)
+ code[c] = code[c + 1];
+ code[c] = ascii;
+
+ /* statecntr = WAIT_ENTRY; */
+
+#if 0
+ TCNT0 = 0;
+ state = 1;
+ send_byte(0xed);
+ send_byte(0x00);
+ DDRD = DDRD_BEEP;
+ cntr = 0;
+ TIFR0 = (1 << TOV0);
+#endif
}
-int main()
+ISR(SIG_USART_RECV)
{
- DDRB = (1 << 4) | B_RED | B_YLW;
- PORTB = (1 << 4) | B_RED | B_YLW;
+ uint8_t data = UDR0;
+
+ dbg_wr(0x80 | (data & 0x3f));
+ dbg_wr(0x84 | (data >> 6));
+
+ switch (state) {
+ case STATE_POWERUP:
+ case STATE_INITRESET:
+ if (data == 0xaa)
+ nextstate = STATE_CONFIG;
+ break;
+ case STATE_IDLE:
+ case STATE_IDLEBLINK:
+ if (data < 0x90)
+ handle_keypress(data);
+ default:
+ break;
+ }
+}
- DDRD = 0;
- PORTD = 0x3f;
+int main()
+{
+ dbg_init();
+ /* /256 = 31'250 Hz = 32 µs per 1 unit
+ * /256 = 122 Hz = 8'192 µs per for overflow
+ * /122 = 1,0006 Hz = 1 s per CNTRTOP */
TCCR0A = 0;
TIMSK0 = (1 << TOIE0);
- TCCR0B = (1 << CS02);
+ 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();
+ state = STATE_FAILURE;
+ nextstate = STATE_NONE;
+ state_enter();
sei();
- while (1)
- ;
+ while (1) {
+ if (nextstate != STATE_NONE) {
+ state = nextstate;
+ nextstate = STATE_NONE;
+ state_enter();
+
+ dbg_wr(0x0e);
+ } else if (!statecntr) {
+ state_timeout();
+
+ dbg_wr(0x0e);
+ }
+ }
}