|
|
@ -4,6 +4,7 @@ Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> |
|
|
|
#include <stdbool.h> |
|
|
|
#include <util/delay.h> |
|
|
|
#include "debug.h" |
|
|
|
#include "ring_buffer.h" |
|
|
|
#include "ibm4704.h" |
|
|
|
|
|
|
|
|
|
|
@ -20,7 +21,9 @@ uint8_t ibm4704_error = 0; |
|
|
|
|
|
|
|
void ibm4704_init(void) |
|
|
|
{ |
|
|
|
inhibit(); |
|
|
|
IBM4704_INT_INIT(); |
|
|
|
IBM4704_INT_ON(); |
|
|
|
idle(); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
@ -47,6 +50,8 @@ uint8_t ibm4704_send(uint8_t data) |
|
|
|
bool parity = true; // odd parity |
|
|
|
ibm4704_error = 0; |
|
|
|
|
|
|
|
IBM4704_INT_OFF(); |
|
|
|
|
|
|
|
/* Request to send */ |
|
|
|
idle(); |
|
|
|
clock_lo(); |
|
|
@ -57,7 +62,6 @@ uint8_t ibm4704_send(uint8_t data) |
|
|
|
/* Data bit */ |
|
|
|
for (uint8_t i = 0; i < 8; i++) { |
|
|
|
WAIT(clock_hi, 100, 0x40+i); |
|
|
|
//_delay_us(5); |
|
|
|
if (data&(1<<i)) { |
|
|
|
parity = !parity; |
|
|
|
data_hi(); |
|
|
@ -79,28 +83,25 @@ uint8_t ibm4704_send(uint8_t data) |
|
|
|
/* End */ |
|
|
|
WAIT(data_lo, 100, 0x36); |
|
|
|
|
|
|
|
inhibit(); |
|
|
|
_delay_us(200); // wait to recover clock to hi |
|
|
|
idle(); |
|
|
|
IBM4704_INT_ON(); |
|
|
|
return 0; |
|
|
|
ERROR: |
|
|
|
inhibit(); |
|
|
|
if (ibm4704_error >= 0x30) { |
|
|
|
xprintf("x%02X ", ibm4704_error); |
|
|
|
idle(); |
|
|
|
if (ibm4704_error > 0x30) { |
|
|
|
xprintf("S:%02X ", ibm4704_error); |
|
|
|
} |
|
|
|
_delay_us(200); // wait to recover clock to hi |
|
|
|
IBM4704_INT_ON(); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
/* receive data when host want else inhibit communication */ |
|
|
|
/* wait forever to receive data */ |
|
|
|
uint8_t ibm4704_recv_response(void) |
|
|
|
{ |
|
|
|
// 250 * 100us(wait start bit in ibm4704_recv) |
|
|
|
uint8_t data = 0; |
|
|
|
uint8_t try = 250; |
|
|
|
do { |
|
|
|
data = ibm4704_recv(); |
|
|
|
} while (try-- && ibm4704_error); |
|
|
|
return data; |
|
|
|
while (!rbuf_has_data()) { |
|
|
|
_delay_ms(1); |
|
|
|
} |
|
|
|
return rbuf_dequeue(); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
@ -121,49 +122,69 @@ Stop bit: Keyboard pulls down Data line to lo after 9th clock. |
|
|
|
*/ |
|
|
|
uint8_t ibm4704_recv(void) |
|
|
|
{ |
|
|
|
uint8_t data = 0; |
|
|
|
bool parity = true; // odd parity |
|
|
|
ibm4704_error = IBM4704_ERR_NONE; |
|
|
|
|
|
|
|
idle(); |
|
|
|
_delay_us(5); // wait for line settles |
|
|
|
|
|
|
|
/* start bit */ |
|
|
|
WAIT(clock_lo, 100, 0x11); // wait for keyboard to send |
|
|
|
WAIT(data_hi, 100, 0x12); // can be delayed that long |
|
|
|
|
|
|
|
WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer |
|
|
|
/* data */ |
|
|
|
for (uint8_t i = 0; i < 8; i++) { |
|
|
|
WAIT(clock_hi, 100, 0x20+i); |
|
|
|
//_delay_us(5); |
|
|
|
if (data_in()) { |
|
|
|
parity = !parity; |
|
|
|
data |= (1<<i); |
|
|
|
} |
|
|
|
WAIT(clock_lo, 150, 0x28+i); |
|
|
|
if (rbuf_has_data()) { |
|
|
|
return rbuf_dequeue(); |
|
|
|
} else { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* parity */ |
|
|
|
WAIT(clock_hi, 100, 0x17); |
|
|
|
if (data_in() != parity) { |
|
|
|
ibm4704_error = IBM4704_ERR_PARITY; |
|
|
|
goto ERROR; |
|
|
|
} |
|
|
|
WAIT(clock_lo, 150, 0x18); |
|
|
|
|
|
|
|
/* stop bit */ |
|
|
|
WAIT(clock_hi, 100, 0x19); |
|
|
|
WAIT(data_lo, 1, 0x19); |
|
|
|
ISR(IBM4704_INT_VECT) |
|
|
|
{ |
|
|
|
static enum { |
|
|
|
INIT, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, |
|
|
|
} state = INIT; |
|
|
|
// LSB first |
|
|
|
static uint8_t data = 0; |
|
|
|
// Odd parity |
|
|
|
static uint8_t parity = false; |
|
|
|
|
|
|
|
inhibit(); |
|
|
|
_delay_us(200); // wait to recover clock to hi |
|
|
|
return data; |
|
|
|
ERROR: |
|
|
|
if (ibm4704_error > 0x12) { |
|
|
|
xprintf("x%02X ", ibm4704_error); |
|
|
|
ibm4704_error = 0; |
|
|
|
// return unless falling edge |
|
|
|
if (clock_in()) { goto RETURN; } // why this occurs? |
|
|
|
|
|
|
|
state++; |
|
|
|
switch (state) { |
|
|
|
case START: |
|
|
|
// Data:Low |
|
|
|
WAIT(data_hi, 10, state); |
|
|
|
break; |
|
|
|
case BIT0: |
|
|
|
case BIT1: |
|
|
|
case BIT2: |
|
|
|
case BIT3: |
|
|
|
case BIT4: |
|
|
|
case BIT5: |
|
|
|
case BIT6: |
|
|
|
case BIT7: |
|
|
|
data >>= 1; |
|
|
|
if (data_in()) { |
|
|
|
data |= 0x80; |
|
|
|
parity = !parity; |
|
|
|
} |
|
|
|
break; |
|
|
|
case PARITY: |
|
|
|
if (data_in()) { |
|
|
|
parity = !parity; |
|
|
|
} |
|
|
|
if (!parity) |
|
|
|
goto ERROR; |
|
|
|
rbuf_enqueue(data); |
|
|
|
ibm4704_error = IBM4704_ERR_NONE; |
|
|
|
goto DONE; |
|
|
|
break; |
|
|
|
default: |
|
|
|
goto ERROR; |
|
|
|
} |
|
|
|
inhibit(); |
|
|
|
_delay_us(200); // wait to recover clock to hi |
|
|
|
return -1; |
|
|
|
goto RETURN; |
|
|
|
ERROR: |
|
|
|
ibm4704_error = state; |
|
|
|
while (ibm4704_send(0xFE)) _delay_ms(1); // resend |
|
|
|
xprintf("R:%02X\n", data); |
|
|
|
DONE: |
|
|
|
state = INIT; |
|
|
|
data = 0; |
|
|
|
parity = false; |
|
|
|
RETURN: |
|
|
|
return; |
|
|
|
} |