X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=tmk_core%2Fprotocol%2Fibmpc.c;h=5f2ca79b2fba9f1bd8067b46ed1d2ca8ca6044a1;hb=12e5a3a13eb86852ad58c131e28ba29c5f09bb2d;hp=0e3998aae6a846e5e512e078f70ecb609436cdd2;hpb=0cf9dfc888755e18a88f71f40863e3dc035ab91a;p=max%2Ftmk_keyboard.git diff --git a/tmk_core/protocol/ibmpc.c b/tmk_core/protocol/ibmpc.c index 0e3998aa..5f2ca79b 100644 --- a/tmk_core/protocol/ibmpc.c +++ b/tmk_core/protocol/ibmpc.c @@ -60,12 +60,13 @@ volatile uint16_t ibmpc_isr_debug = 0; volatile uint8_t ibmpc_protocol = IBMPC_PROTOCOL_NO; volatile uint8_t ibmpc_error = IBMPC_ERR_NONE; -/* 2-byte buffer for data received from keyhboard +/* 2-byte buffer for data received from keyboard * buffer states: * FFFF: empty * FFss: one data - * sstt: two data(full) - * 0xFF can not be stored as data in buffer because it means empty or no data. + * sstt: two data + * eeFF: error + * where ss, tt and ee are 0x00-0xFE. 0xFF means empty or no data in buffer. */ static volatile uint16_t recv_data = 0xFFFF; /* internal state of receiving data */ @@ -104,12 +105,13 @@ int16_t ibmpc_host_send(uint8_t data) /* terminate a transmission if we have */ inhibit(); - wait_us(100); // 100us [4]p.13, [5]p.50 + wait_us(100); // [5]p.54 /* 'Request to Send' and Start bit */ data_lo(); - clock_hi(); - WAIT(clock_lo, 10000, 1); // 10ms [5]p.50 + wait_us(100); + clock_hi(); // [5]p.54 [clock low]>100us [5]p.50 + WAIT(clock_lo, 10000, 1); // [5]p.53, -10ms [5]p.50 /* Data bit[2-9] */ for (uint8_t i = 0; i < 8; i++) { @@ -133,14 +135,15 @@ int16_t ibmpc_host_send(uint8_t data) /* Stop bit */ wait_us(15); data_hi(); + WAIT(clock_hi, 50, 6); + WAIT(clock_lo, 50, 7); /* Ack */ - WAIT(data_lo, 50, 6); - WAIT(clock_lo, 50, 7); + WAIT(data_lo, 50, 8); /* wait for idle state */ - WAIT(clock_hi, 50, 8); - WAIT(data_hi, 50, 9); + WAIT(clock_hi, 50, 9); + WAIT(data_hi, 50, 10); // clear buffer to get response correctly recv_data = 0xFFFF; @@ -166,19 +169,50 @@ int16_t ibmpc_host_recv(void) ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { data = recv_data; - if ((data&0xFF00) != 0xFF00) { // recv_data:sstt -> recv_data:FFtt, ret:ss - ret = (data>>8)&0x00FF; - recv_data = data | 0xFF00; - } else if (data != 0xFFFF) { // recv_data:FFss -> recv_data:FFFF, ret:ss - ret = data&0x00FF; - recv_data = data | 0x00FF; - } + + // remove data from buffer: + // FFFF(empty) -> FFFF + // FFss(one data) -> FFFF + // sstt(two data) -> FFtt + // eeFF(errror) -> FFFF + recv_data = data | (((data&0xFF00) == 0xFF00) ? 0x00FF : 0xFF00); } - if ((data | 0x00FF) != 0xFFFF) dprintf("b%04X ", data); - if (ret != 0xFF) dprintf("r%02X ", ret); - return ((ret != 0xFF) ? ret : -1); + if ((data&0x00FF) == 0x00FF) { + // error: eeFF + switch (data>>8) { + case IBMPC_ERR_FF: + // 0xFF(Overrun/Error) from keyboard + dprintf("!FF! "); + ret = 0xFF; + break; + case IBMPC_ERR_FULL: + // buffer full + dprintf("!FULL! "); + ret = 0xFF; + break; + case 0xFF: + // empty: FFFF + return -1; + default: + // other errors + dprintf("e%02X ", data>>8); + return -1; + } + } else { + if ((data | 0x00FF) != 0xFFFF) { + // two data: sstt + dprintf("b:%04X ", data); + ret = (data>>8); + } else { + // one data: FFss + ret = (data&0x00FF); + } + } + //dprintf("i%04X ", ibmpc_isr_debug); ibmpc_isr_debug = 0; + dprintf("r%02X ", ret); + return ret; } int16_t ibmpc_host_recv_response(void) @@ -194,10 +228,15 @@ int16_t ibmpc_host_recv_response(void) void ibmpc_host_isr_clear(void) { + ibmpc_isr_debug = 0; + ibmpc_protocol = 0; + ibmpc_error = 0; isr_state = 0x8000; recv_data = 0xFFFF; } +#define LO8(w) (*((uint8_t *)&(w))) +#define HI8(w) (*(((uint8_t *)&(w))+1)) // NOTE: With this ISR data line can be read within 2us after clock falling edge. // To read data line early as possible: // write naked ISR with asembly code to read the line and call C func to do other job? @@ -214,13 +253,16 @@ ISR(IBMPC_INT_VECT) if (isr_state == 0x8000) { timer_start = t; } else { - // should not take more than 1ms - if (timer_start != t && (uint8_t)(timer_start + 1) != t) { + // This gives 2.0ms at least before timeout + if ((uint8_t)(t - timer_start) >= 3) { + ibmpc_isr_debug = isr_state; ibmpc_error = IBMPC_ERR_TIMEOUT; - //goto ERROR; - // timeout error recovery by clearing isr_state? - timer_start = t; - isr_state = 0x8000; + goto ERROR; + + // timeout error recovery - start receiving new data + // it seems to work somehow but may not under unstable situation + //timer_start = t; + //isr_state = 0x8000; } } @@ -279,6 +321,7 @@ ISR(IBMPC_INT_VECT) goto NEXT; } else { // XT_Clone-done + ibmpc_isr_debug = isr_state; isr_state = isr_state>>8; ibmpc_protocol = IBMPC_PROTOCOL_XT_CLONE; goto DONE; @@ -304,6 +347,7 @@ ISR(IBMPC_INT_VECT) goto NEXT; } else { // no stop bit: XT_IBM-done + ibmpc_isr_debug = isr_state; isr_state = isr_state>>8; ibmpc_protocol = IBMPC_PROTOCOL_XT_IBM; goto DONE; @@ -315,11 +359,17 @@ ISR(IBMPC_INT_VECT) case 0b01010000: case 0b11010000: // AT-done - // DO NOT check stop bit. Zenith Z-150(AT) asserts stop bit as low for no reason. - // https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige // TODO: parity check? + ibmpc_isr_debug = isr_state; + // stop bit check + if (isr_state & 0x8000) { + ibmpc_protocol = IBMPC_PROTOCOL_AT; + } else { + // Zenith Z-150 AT(beige/white lable) asserts stop bit as low + // https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige + ibmpc_protocol = IBMPC_PROTOCOL_AT_Z150; + } isr_state = isr_state>>6; - ibmpc_protocol = IBMPC_PROTOCOL_AT; goto DONE; break; case 0b01100000: @@ -336,22 +386,26 @@ ISR(IBMPC_INT_VECT) } ERROR: - ibmpc_isr_debug = isr_state; - isr_state = 0x8000; - recv_data = 0xFF00; // clear data and scancode of error 0x00 - return; + // error: eeFF + recv_data = (ibmpc_error<<8) | 0x00FF; + goto CLEAR; DONE: if ((isr_state & 0x00FF) == 0x00FF) { // receive error code 0xFF ibmpc_error = IBMPC_ERR_FF; + goto ERROR; } - if ((recv_data & 0xFF00) != 0xFF00) { - // buffer full and overwritten + if (HI8(recv_data) != 0xFF && LO8(recv_data) != 0xFF) { + // buffer full ibmpc_error = IBMPC_ERR_FULL; + goto ERROR; } + // store data recv_data = recv_data<<8; recv_data |= isr_state & 0xFF; - isr_state = 0x8000; // clear to next data +CLEAR: + // clear for next data + isr_state = 0x8000; NEXT: return; }