diff options
| author | tmk <nobody@nowhere> | 2014-10-27 21:39:02 +0900 |
|---|---|---|
| committer | Jun Wako <wakojun@gmail.com> | 2015-04-22 14:18:13 +0900 |
| commit | d42aa47809c97a77c49e9396201c2b5c3956bb54 (patch) | |
| tree | 07331fbb4b67630a5571f31af071021fbc9eb160 | |
| parent | 5ea50bfb30fa9917f6c1209a7ae7f31b7e7b4095 (diff) | |
| download | qmk_firmware-d42aa47809c97a77c49e9396201c2b5c3956bb54.tar.gz qmk_firmware-d42aa47809c97a77c49e9396201c2b5c3956bb54.zip | |
Fix ibm4704 protocol with using interrupt
| -rw-r--r-- | common/ring_buffer.h | 53 | ||||
| -rw-r--r-- | converter/ibm4704_usb/config.h | 2 | ||||
| -rw-r--r-- | converter/ibm4704_usb/matrix.c | 41 | ||||
| -rw-r--r-- | tmk_core/protocol/ibm4704.c | 135 |
4 files changed, 149 insertions, 82 deletions
diff --git a/common/ring_buffer.h b/common/ring_buffer.h new file mode 100644 index 000000000..7bdebbcf3 --- /dev/null +++ b/common/ring_buffer.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #ifndef RING_BUFFER_H | ||
| 2 | #define RING_BUFFER_H | ||
| 3 | /*-------------------------------------------------------------------- | ||
| 4 | * Ring buffer to store scan codes from keyboard | ||
| 5 | *------------------------------------------------------------------*/ | ||
| 6 | #define RBUF_SIZE 32 | ||
| 7 | static uint8_t rbuf[RBUF_SIZE]; | ||
| 8 | static uint8_t rbuf_head = 0; | ||
| 9 | static uint8_t rbuf_tail = 0; | ||
| 10 | static inline void rbuf_enqueue(uint8_t data) | ||
| 11 | { | ||
| 12 | uint8_t sreg = SREG; | ||
| 13 | cli(); | ||
| 14 | uint8_t next = (rbuf_head + 1) % RBUF_SIZE; | ||
| 15 | if (next != rbuf_tail) { | ||
| 16 | rbuf[rbuf_head] = data; | ||
| 17 | rbuf_head = next; | ||
| 18 | } else { | ||
| 19 | print("rbuf: full\n"); | ||
| 20 | } | ||
| 21 | SREG = sreg; | ||
| 22 | } | ||
| 23 | static inline uint8_t rbuf_dequeue(void) | ||
| 24 | { | ||
| 25 | uint8_t val = 0; | ||
| 26 | |||
| 27 | uint8_t sreg = SREG; | ||
| 28 | cli(); | ||
| 29 | if (rbuf_head != rbuf_tail) { | ||
| 30 | val = rbuf[rbuf_tail]; | ||
| 31 | rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE; | ||
| 32 | } | ||
| 33 | SREG = sreg; | ||
| 34 | |||
| 35 | return val; | ||
| 36 | } | ||
| 37 | static inline bool rbuf_has_data(void) | ||
| 38 | { | ||
| 39 | uint8_t sreg = SREG; | ||
| 40 | cli(); | ||
| 41 | bool has_data = (rbuf_head != rbuf_tail); | ||
| 42 | SREG = sreg; | ||
| 43 | return has_data; | ||
| 44 | } | ||
| 45 | static inline void rbuf_clear(void) | ||
| 46 | { | ||
| 47 | uint8_t sreg = SREG; | ||
| 48 | cli(); | ||
| 49 | rbuf_head = rbuf_tail = 0; | ||
| 50 | SREG = sreg; | ||
| 51 | } | ||
| 52 | |||
| 53 | #endif /* RING_BUFFER_H */ | ||
diff --git a/converter/ibm4704_usb/config.h b/converter/ibm4704_usb/config.h index 4f82f49ad..812d95c67 100644 --- a/converter/ibm4704_usb/config.h +++ b/converter/ibm4704_usb/config.h | |||
| @@ -56,7 +56,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 56 | /* | 56 | /* |
| 57 | * Pin interrupt | 57 | * Pin interrupt |
| 58 | */ | 58 | */ |
| 59 | #ifdef IBM4704_USE_INT | ||
| 60 | #define IBM4704_INT_INIT() do { \ | 59 | #define IBM4704_INT_INIT() do { \ |
| 61 | EICRA |= ((1<<ISC11) | \ | 60 | EICRA |= ((1<<ISC11) | \ |
| 62 | (0<<ISC10)); \ | 61 | (0<<ISC10)); \ |
| @@ -68,7 +67,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 68 | EIMSK &= ~(1<<INT1); \ | 67 | EIMSK &= ~(1<<INT1); \ |
| 69 | } while (0) | 68 | } while (0) |
| 70 | #define IBM4704_INT_VECT INT1_vect | 69 | #define IBM4704_INT_VECT INT1_vect |
| 71 | #endif | ||
| 72 | 70 | ||
| 73 | 71 | ||
| 74 | #endif | 72 | #endif |
diff --git a/converter/ibm4704_usb/matrix.c b/converter/ibm4704_usb/matrix.c index 0bfda2b15..857dea0f9 100644 --- a/converter/ibm4704_usb/matrix.c +++ b/converter/ibm4704_usb/matrix.c | |||
| @@ -69,41 +69,34 @@ static void enable_break(void) | |||
| 69 | { | 69 | { |
| 70 | uint8_t ret; | 70 | uint8_t ret; |
| 71 | print("Enable break: "); | 71 | print("Enable break: "); |
| 72 | // valid scancode: 00-77h | 72 | // valid scancode: 00-79h |
| 73 | for (uint8_t code = 0; code < 0x78; code++) { | 73 | for (uint8_t code = 0; code < 0x7A; code++) { |
| 74 | while (ibm4704_send(0x80|code) != 0) { | 74 | while (ibm4704_send(0x80|code)) _delay_ms(1); |
| 75 | print("z"); | 75 | // get none when ok, get FD when out of bound |
| 76 | _delay_us(500); | 76 | _delay_ms(5); |
| 77 | } | 77 | if ((ret = ibm4704_recv()) != 0xff) { |
| 78 | _delay_us(2000); | ||
| 79 | ret = ibm4704_recv(); | ||
| 80 | if (ret != 0xff) { | ||
| 81 | xprintf("c%02X:r%02X ", code, ret); | 78 | xprintf("c%02X:r%02X ", code, ret); |
| 82 | } | 79 | } |
| 83 | _delay_us(1000); | 80 | _delay_ms(1); |
| 84 | } | 81 | } |
| 85 | _delay_us(1000); | 82 | _delay_us(1000); |
| 86 | while (ibm4704_send(0xFF) != 0) { _delay_us(500); } // End | 83 | while (ibm4704_send(0xFF)) { _delay_ms(1); } // End |
| 87 | print("End\n"); | 84 | print("End\n"); |
| 88 | } | 85 | } |
| 89 | 86 | ||
| 90 | void matrix_init(void) | 87 | void matrix_init(void) |
| 91 | { | 88 | { |
| 92 | uint8_t ret; | 89 | debug_enable = false; |
| 93 | debug_enable = true; | ||
| 94 | 90 | ||
| 95 | ibm4704_init(); | 91 | ibm4704_init(); |
| 96 | matrix_clear(); | 92 | matrix_clear(); |
| 97 | 93 | ||
| 98 | // read keyboard id | 94 | _delay_ms(2000); // wait for starting up debug console |
| 99 | while ((ret = ibm4704_recv()) == 0xFF) { | ||
| 100 | ibm4704_send(0xFE); | ||
| 101 | _delay_us(100); | ||
| 102 | } | ||
| 103 | 95 | ||
| 104 | _delay_ms(2000); // wait for starting up debug console | ||
| 105 | print("IBM 4704 converter\n"); | 96 | print("IBM 4704 converter\n"); |
| 106 | xprintf("Keyboard ID: %02X\n", ret); | 97 | while (ibm4704_send(0xFE)) _delay_ms(1); // resend |
| 98 | _delay_ms(5); | ||
| 99 | xprintf("Keyboard ID: %02X\n", ibm4704_recv()); | ||
| 107 | enable_break(); | 100 | enable_break(); |
| 108 | } | 101 | } |
| 109 | 102 | ||
| @@ -116,14 +109,16 @@ uint8_t matrix_scan(void) | |||
| 116 | if (code==0xFF) { | 109 | if (code==0xFF) { |
| 117 | // Not receivd | 110 | // Not receivd |
| 118 | return 0; | 111 | return 0; |
| 119 | } else if ((code&0x78)==0x78) { | 112 | } else if ((code&0x7F) >= 0x7A) { |
| 120 | // 0xFF-F8 and 0x7F-78 is not scancode | 113 | // 0xFF-FA and 0x7F-7A is not scancode |
| 121 | xprintf("Error: %0X\n", code); | 114 | xprintf("Error: %02X\n", code); |
| 122 | matrix_clear(); | 115 | matrix_clear(); |
| 123 | return 0; | 116 | return 0; |
| 124 | } else if (code&0x80) { | 117 | } else if (code&0x80) { |
| 118 | dprintf("%02X\n", code); | ||
| 125 | matrix_make(code); | 119 | matrix_make(code); |
| 126 | } else { | 120 | } else { |
| 121 | dprintf("%02X\n", code); | ||
| 127 | matrix_break(code); | 122 | matrix_break(code); |
| 128 | } | 123 | } |
| 129 | return 1; | 124 | return 1; |
diff --git a/tmk_core/protocol/ibm4704.c b/tmk_core/protocol/ibm4704.c index 10e229fd1..152d7e61b 100644 --- a/tmk_core/protocol/ibm4704.c +++ b/tmk_core/protocol/ibm4704.c | |||
| @@ -4,6 +4,7 @@ Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com> | |||
| 4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
| 5 | #include <util/delay.h> | 5 | #include <util/delay.h> |
| 6 | #include "debug.h" | 6 | #include "debug.h" |
| 7 | #include "ring_buffer.h" | ||
| 7 | #include "ibm4704.h" | 8 | #include "ibm4704.h" |
| 8 | 9 | ||
| 9 | 10 | ||
| @@ -20,7 +21,9 @@ uint8_t ibm4704_error = 0; | |||
| 20 | 21 | ||
| 21 | void ibm4704_init(void) | 22 | void ibm4704_init(void) |
| 22 | { | 23 | { |
| 23 | inhibit(); | 24 | IBM4704_INT_INIT(); |
| 25 | IBM4704_INT_ON(); | ||
| 26 | idle(); | ||
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | /* | 29 | /* |
| @@ -47,6 +50,8 @@ uint8_t ibm4704_send(uint8_t data) | |||
| 47 | bool parity = true; // odd parity | 50 | bool parity = true; // odd parity |
| 48 | ibm4704_error = 0; | 51 | ibm4704_error = 0; |
| 49 | 52 | ||
| 53 | IBM4704_INT_OFF(); | ||
| 54 | |||
| 50 | /* Request to send */ | 55 | /* Request to send */ |
| 51 | idle(); | 56 | idle(); |
| 52 | clock_lo(); | 57 | clock_lo(); |
| @@ -57,7 +62,6 @@ uint8_t ibm4704_send(uint8_t data) | |||
| 57 | /* Data bit */ | 62 | /* Data bit */ |
| 58 | for (uint8_t i = 0; i < 8; i++) { | 63 | for (uint8_t i = 0; i < 8; i++) { |
| 59 | WAIT(clock_hi, 100, 0x40+i); | 64 | WAIT(clock_hi, 100, 0x40+i); |
| 60 | //_delay_us(5); | ||
| 61 | if (data&(1<<i)) { | 65 | if (data&(1<<i)) { |
| 62 | parity = !parity; | 66 | parity = !parity; |
| 63 | data_hi(); | 67 | data_hi(); |
| @@ -79,28 +83,25 @@ uint8_t ibm4704_send(uint8_t data) | |||
| 79 | /* End */ | 83 | /* End */ |
| 80 | WAIT(data_lo, 100, 0x36); | 84 | WAIT(data_lo, 100, 0x36); |
| 81 | 85 | ||
| 82 | inhibit(); | 86 | idle(); |
| 83 | _delay_us(200); // wait to recover clock to hi | 87 | IBM4704_INT_ON(); |
| 84 | return 0; | 88 | return 0; |
| 85 | ERROR: | 89 | ERROR: |
| 86 | inhibit(); | 90 | idle(); |
| 87 | if (ibm4704_error >= 0x30) { | 91 | if (ibm4704_error > 0x30) { |
| 88 | xprintf("x%02X ", ibm4704_error); | 92 | xprintf("S:%02X ", ibm4704_error); |
| 89 | } | 93 | } |
| 90 | _delay_us(200); // wait to recover clock to hi | 94 | IBM4704_INT_ON(); |
| 91 | return -1; | 95 | return -1; |
| 92 | } | 96 | } |
| 93 | 97 | ||
| 94 | /* receive data when host want else inhibit communication */ | 98 | /* wait forever to receive data */ |
| 95 | uint8_t ibm4704_recv_response(void) | 99 | uint8_t ibm4704_recv_response(void) |
| 96 | { | 100 | { |
| 97 | // 250 * 100us(wait start bit in ibm4704_recv) | 101 | while (!rbuf_has_data()) { |
| 98 | uint8_t data = 0; | 102 | _delay_ms(1); |
| 99 | uint8_t try = 250; | 103 | } |
| 100 | do { | 104 | return rbuf_dequeue(); |
| 101 | data = ibm4704_recv(); | ||
| 102 | } while (try-- && ibm4704_error); | ||
| 103 | return data; | ||
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | /* | 107 | /* |
| @@ -121,49 +122,69 @@ Stop bit: Keyboard pulls down Data line to lo after 9th clock. | |||
| 121 | */ | 122 | */ |
| 122 | uint8_t ibm4704_recv(void) | 123 | uint8_t ibm4704_recv(void) |
| 123 | { | 124 | { |
| 124 | uint8_t data = 0; | 125 | if (rbuf_has_data()) { |
| 125 | bool parity = true; // odd parity | 126 | return rbuf_dequeue(); |
| 126 | ibm4704_error = IBM4704_ERR_NONE; | 127 | } else { |
| 127 | 128 | return -1; | |
| 128 | idle(); | ||
| 129 | _delay_us(5); // wait for line settles | ||
| 130 | |||
| 131 | /* start bit */ | ||
| 132 | WAIT(clock_lo, 100, 0x11); // wait for keyboard to send | ||
| 133 | WAIT(data_hi, 100, 0x12); // can be delayed that long | ||
| 134 | |||
| 135 | WAIT(clock_hi, 100, 0x13); // first rising edge which can take longer | ||
| 136 | /* data */ | ||
| 137 | for (uint8_t i = 0; i < 8; i++) { | ||
| 138 | WAIT(clock_hi, 100, 0x20+i); | ||
| 139 | //_delay_us(5); | ||
| 140 | if (data_in()) { | ||
| 141 | parity = !parity; | ||
| 142 | data |= (1<<i); | ||
| 143 | } | ||
| 144 | WAIT(clock_lo, 150, 0x28+i); | ||
| 145 | } | 129 | } |
| 130 | } | ||
| 146 | 131 | ||
| 147 | /* parity */ | 132 | ISR(IBM4704_INT_VECT) |
| 148 | WAIT(clock_hi, 100, 0x17); | 133 | { |
| 149 | if (data_in() != parity) { | 134 | static enum { |
| 150 | ibm4704_error = IBM4704_ERR_PARITY; | 135 | INIT, START, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, |
| 151 | goto ERROR; | 136 | } state = INIT; |
| 152 | } | 137 | // LSB first |
| 153 | WAIT(clock_lo, 150, 0x18); | 138 | static uint8_t data = 0; |
| 154 | 139 | // Odd parity | |
| 155 | /* stop bit */ | 140 | static uint8_t parity = false; |
| 156 | WAIT(clock_hi, 100, 0x19); | ||
| 157 | WAIT(data_lo, 1, 0x19); | ||
| 158 | 141 | ||
| 159 | inhibit(); | 142 | ibm4704_error = 0; |
| 160 | _delay_us(200); // wait to recover clock to hi | 143 | // return unless falling edge |
| 161 | return data; | 144 | if (clock_in()) { goto RETURN; } // why this occurs? |
| 162 | ERROR: | 145 | |
| 163 | if (ibm4704_error > 0x12) { | 146 | state++; |
| 164 | xprintf("x%02X ", ibm4704_error); | 147 | switch (state) { |
| 148 | case START: | ||
| 149 | // Data:Low | ||
| 150 | WAIT(data_hi, 10, state); | ||
| 151 | break; | ||
| 152 | case BIT0: | ||
| 153 | case BIT1: | ||
| 154 | case BIT2: | ||
| 155 | case BIT3: | ||
| 156 | case BIT4: | ||
| 157 | case BIT5: | ||
| 158 | case BIT6: | ||
| 159 | case BIT7: | ||
| 160 | data >>= 1; | ||
| 161 | if (data_in()) { | ||
| 162 | data |= 0x80; | ||
| 163 | parity = !parity; | ||
| 164 | } | ||
| 165 | break; | ||
| 166 | case PARITY: | ||
| 167 | if (data_in()) { | ||
| 168 | parity = !parity; | ||
| 169 | } | ||
| 170 | if (!parity) | ||
| 171 | goto ERROR; | ||
| 172 | rbuf_enqueue(data); | ||
| 173 | ibm4704_error = IBM4704_ERR_NONE; | ||
| 174 | goto DONE; | ||
| 175 | break; | ||
| 176 | default: | ||
| 177 | goto ERROR; | ||
| 165 | } | 178 | } |
| 166 | inhibit(); | 179 | goto RETURN; |
| 167 | _delay_us(200); // wait to recover clock to hi | 180 | ERROR: |
| 168 | return -1; | 181 | ibm4704_error = state; |
| 182 | while (ibm4704_send(0xFE)) _delay_ms(1); // resend | ||
| 183 | xprintf("R:%02X\n", data); | ||
| 184 | DONE: | ||
| 185 | state = INIT; | ||
| 186 | data = 0; | ||
| 187 | parity = false; | ||
| 188 | RETURN: | ||
| 189 | return; | ||
| 169 | } | 190 | } |
