Merge branch 'ibm4704_fix_protocol'

example_keyboards
tmk 10 years ago
commit 81137b7a61

@ -8,6 +8,7 @@ Keyboard initialization process takes a few seconds at start up. During that you
Update Update
------ ------
2015/05/05 Added keymaps for 107-key, 77-key and 50-key. Thanks, orihalcon @ geekhack! 2015/05/05 Added keymaps for 107-key, 77-key and 50-key. Thanks, orihalcon @ geekhack!
2015/05/19 Fixed a protocol handling bug.

@ -51,9 +51,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define IBM4704_DATA_DDR DDRD #define IBM4704_DATA_DDR DDRD
#define IBM4704_DATA_BIT 0 #define IBM4704_DATA_BIT 0
/* Pin interrupt on rising edge */ /* Pin interrupt on rising edge of clock */
#define IBM4704_INT_INIT() do { EICRA |= ((1<<ISC11)|(0<<ISC10)); } while (0) #define IBM4704_INT_INIT() do { EICRA |= ((1<<ISC11)|(1<<ISC10)); } while (0)
#define IBM4704_INT_ON() do { EIMSK |= (1<<INT1); } while (0) #define IBM4704_INT_ON() do { EIFR |= (1<<INTF1); EIMSK |= (1<<INT1); } while (0)
#define IBM4704_INT_OFF() do { EIMSK &= ~(1<<INT1); } while (0) #define IBM4704_INT_OFF() do { EIMSK &= ~(1<<INT1); } while (0)
#define IBM4704_INT_VECT INT1_vect #define IBM4704_INT_VECT INT1_vect

@ -57,15 +57,15 @@ Keyboard to Host
---------------- ----------------
Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part. Data bits are LSB first and Pairty is odd. Clock has around 60us high and 30us low part.
____ __ __ __ __ __ __ __ __ __ ________ ____ __ __ __ __ __ __ __ __ __ _______
Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
Data ____/ X____X____X____X____X____X____X____X____X____X________ Data ____/ X____X____X____X____X____X____X____X____X____X________
Start 0 1 2 3 4 5 6 7 P Stop Start 0 1 2 3 4 5 6 7 P Stop
Start bit: can be long as 300-350us. Start bit: can be long as 300-350us.
Inhibit: Pull Data line down to inhibit keyboard to send. Inhibit: Pull Data line down to inhibit keyboard to send.
Timing: Host reads bit while Clock is hi. Timing: Host reads bit while Clock is hi.(rising edge)
Stop bit: Keyboard pulls down Data line to lo after 9th clock. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
@ -166,13 +166,14 @@ Data sent from host:
| `-----`--- scan code | `-----`--- scan code
`------------- enable bit(0: enable repeat, 1: enable break) `------------- enable bit(0: enable repeat, 1: enable break)
00-77 Enable repeat(78-7F: invalid scancode) 00-79 Enable repeat
80-F7 Enable break(F8-FF: invalid scancode) 80-F9 Enable break(FA-FF are used as other commands, see above.)
FE Resend(011ah) no need to use FE Resend(011ah) no need to use
FF End(0114h) exits FC command mode. FF End(0114h) exits FC command mode.
Response from keyboard: Response from keyboard:
FD Out of bound - Invalid scancode FD Out of bound - Invalid scancode
-- OK - No response means that command is accepted.
Examples: Examples:
To enable break code of all keys. To enable break code of all keys.

@ -67,35 +67,31 @@ uint8_t matrix_cols(void)
static void enable_break(void) static void enable_break(void)
{ {
uint8_t ret;
print("Enable break: "); print("Enable break: ");
// valid scancode: 00-79h // valid scancode: 00-79h
for (uint8_t code = 0; code < 0x7A; code++) { for (uint8_t code = 0; code < 0x7A; code++) {
while (ibm4704_send(0x80|code)) _delay_ms(1); while (ibm4704_send(0x80|code)) _delay_ms(10);
// get none when ok, get FD when out of bound _delay_ms(5); // wait for response
_delay_ms(5); // No response(FF) when ok, FD when out of bound
if ((ret = ibm4704_recv()) != 0xff) { xprintf("s%02X:r%02X ", code, ibm4704_recv());
xprintf("c%02X:r%02X ", code, ret);
} }
_delay_ms(1); while (ibm4704_send(0xFF)) { _delay_ms(10); } // End
}
_delay_us(1000);
while (ibm4704_send(0xFF)) { _delay_ms(1); } // End
print("End\n"); print("End\n");
} }
void matrix_init(void)
{
debug_enable = true;
void matrix_setup(void)
{
ibm4704_init(); ibm4704_init();
matrix_clear(); }
_delay_ms(2000); // wait for starting up debug console void matrix_init(void)
{
debug_enable = true;
print("IBM 4704 converter\n"); print("IBM 4704 converter\n");
while (ibm4704_send(0xFE)) _delay_ms(1); // resend matrix_clear();
_delay_ms(5); _delay_ms(2000); // wait for keyboard starting up
xprintf("Keyboard ID: %02X\n", ibm4704_recv()); xprintf("Keyboard ID: %02X\n", ibm4704_recv());
enable_break(); enable_break();
} }

@ -85,6 +85,8 @@ void suspend_power_down(void)
power_down(WDTO_15MS); power_down(WDTO_15MS);
} }
__attribute__ ((weak)) void matrix_power_up(void) {}
__attribute__ ((weak)) void matrix_power_down(void) {}
bool suspend_wakeup_condition(void) bool suspend_wakeup_condition(void)
{ {
matrix_power_up(); matrix_power_up();

@ -62,6 +62,12 @@ static bool has_ghost_in_row(uint8_t row)
#endif #endif
__attribute__ ((weak)) void matrix_setup(void) {}
void keyboard_setup(void)
{
matrix_setup();
}
void keyboard_init(void) void keyboard_init(void)
{ {
timer_init(); timer_init();

@ -58,13 +58,15 @@ static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) &&
} }
/* it runs once at early stage of startup before keyboard_init. */
void keyboard_setup(void);
/* it runs once after initializing host side protocol, debug and MCU peripherals. */
void keyboard_init(void); void keyboard_init(void);
/* it runs repeatedly in main loop */
void keyboard_task(void); void keyboard_task(void);
/* it runs when host LED status is updated */
void keyboard_set_leds(uint8_t leds); void keyboard_set_leds(uint8_t leds);
__attribute__ ((weak)) void matrix_power_up(void) {}
__attribute__ ((weak)) void matrix_power_down(void) {}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -43,7 +43,9 @@ extern "C" {
uint8_t matrix_rows(void); uint8_t matrix_rows(void);
/* number of matrix columns */ /* number of matrix columns */
uint8_t matrix_cols(void); uint8_t matrix_cols(void);
/* intialize matrix for scaning. should be called once. */ /* should be called at early stage of startup before matrix_init.(optional) */
void matrix_setup(void);
/* intialize matrix for scaning. */
void matrix_init(void); void matrix_init(void);
/* scan all key states on matrix */ /* scan all key states on matrix */
uint8_t matrix_scan(void); uint8_t matrix_scan(void);

@ -21,9 +21,10 @@ uint8_t ibm4704_error = 0;
void ibm4704_init(void) void ibm4704_init(void)
{ {
inhibit(); // keep keyboard from sending
IBM4704_INT_INIT(); IBM4704_INT_INIT();
IBM4704_INT_ON(); IBM4704_INT_ON();
idle(); idle(); // allow keyboard sending
} }
/* /*
@ -104,51 +105,44 @@ uint8_t ibm4704_recv_response(void)
return rbuf_dequeue(); return rbuf_dequeue();
} }
uint8_t ibm4704_recv(void)
{
if (rbuf_has_data()) {
return rbuf_dequeue();
} else {
return -1;
}
}
/* /*
Keyboard to Host Keyboard to Host
---------------- ----------------
Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part. Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
____ __ __ __ __ __ __ __ __ __ ________ ____ __ __ __ __ __ __ __ __ __ _______
Clock \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
Data ____/ X____X____X____X____X____X____X____X____X____X________ Data ____/ X____X____X____X____X____X____X____X____X____X________
Start 0 1 2 3 4 5 6 7 P Stop Start 0 1 2 3 4 5 6 7 P Stop
Start bit: can be long as 300-350us. Start bit: can be long as 300-350us.
Inhibit: Pull Data line down to inhibit keyboard to send. Inhibit: Pull Data line down to inhibit keyboard to send.
Timing: Host reads bit while Clock is hi. Timing: Host reads bit while Clock is hi.(rising edge)
Stop bit: Keyboard pulls down Data line to lo after 9th clock. Stop bit: Keyboard pulls down Data line to lo after 9th clock.
*/ */
uint8_t ibm4704_recv(void)
{
if (rbuf_has_data()) {
return rbuf_dequeue();
} else {
return -1;
}
}
ISR(IBM4704_INT_VECT) ISR(IBM4704_INT_VECT)
{ {
static enum { static enum {
INIT, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, STOP
} state = INIT; } state = BIT0;
// LSB first // LSB first
static uint8_t data = 0; static uint8_t data = 0;
// Odd parity // Odd parity
static uint8_t parity = false; static uint8_t parity = false;
ibm4704_error = 0; ibm4704_error = 0;
// return unless falling edge
if (clock_in()) { goto RETURN; } // why this occurs?
state++;
switch (state) { switch (state) {
case START:
// Data:Low
WAIT(data_hi, 10, state);
break;
case BIT0: case BIT0:
case BIT1: case BIT1:
case BIT2: case BIT2:
@ -169,6 +163,10 @@ ISR(IBM4704_INT_VECT)
} }
if (!parity) if (!parity)
goto ERROR; goto ERROR;
break;
case STOP:
// Data:Low
WAIT(data_lo, 100, state);
rbuf_enqueue(data); rbuf_enqueue(data);
ibm4704_error = IBM4704_ERR_NONE; ibm4704_error = IBM4704_ERR_NONE;
goto DONE; goto DONE;
@ -176,13 +174,14 @@ ISR(IBM4704_INT_VECT)
default: default:
goto ERROR; goto ERROR;
} }
state++;
goto RETURN; goto RETURN;
ERROR: ERROR:
ibm4704_error = state; ibm4704_error = state;
while (ibm4704_send(0xFE)) _delay_ms(1); // resend while (ibm4704_send(0xFE)) _delay_ms(1); // resend
xprintf("R:%02X%02X\n", state, data); xprintf("R:%02X%02X\n", state, data);
DONE: DONE:
state = INIT; state = BIT0;
data = 0; data = 0;
parity = false; parity = false;
RETURN: RETURN:

@ -544,7 +544,7 @@ int8_t sendchar(uint8_t c)
/******************************************************************************* /*******************************************************************************
* main * main
******************************************************************************/ ******************************************************************************/
static void SetupHardware(void) static void setup_mcu(void)
{ {
/* Disable watchdog if enabled by bootloader/fuses */ /* Disable watchdog if enabled by bootloader/fuses */
MCUSR &= ~(1 << WDRF); MCUSR &= ~(1 << WDRF);
@ -552,7 +552,10 @@ static void SetupHardware(void)
/* Disable clock division */ /* Disable clock division */
clock_prescale_set(clock_div_1); clock_prescale_set(clock_div_1);
}
static void setup_usb(void)
{
// Leonardo needs. Without this USB device is not recognized. // Leonardo needs. Without this USB device is not recognized.
USB_Disable(); USB_Disable();
@ -566,7 +569,9 @@ static void SetupHardware(void)
int main(void) __attribute__ ((weak)); int main(void) __attribute__ ((weak));
int main(void) int main(void)
{ {
SetupHardware(); setup_mcu();
keyboard_setup();
setup_usb();
sei(); sei();
/* wait for USB startup & debug output */ /* wait for USB startup & debug output */

@ -46,6 +46,8 @@ int main(void)
// set for 16 MHz clock // set for 16 MHz clock
CPU_PRESCALE(0); CPU_PRESCALE(0);
keyboard_setup();
// Initialize the USB, and then wait for the host to set configuration. // Initialize the USB, and then wait for the host to set configuration.
// If the Teensy is powered without a PC connected to the USB port, // If the Teensy is powered without a PC connected to the USB port,
// this will wait forever. // this will wait forever.

Loading…
Cancel
Save