]> git.donarmstrong.com Git - qmk_firmware.git/blob - protocol/ibm4704.c
New macro: ACTION_BACKLIGHT_LEVEL(level)
[qmk_firmware.git] / protocol / ibm4704.c
1 /*
2 Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3 */
4 #include <stdbool.h>
5 #include <util/delay.h>
6 #include "debug.h"
7 #include "ibm4704.h"
8
9
10 #define WAIT(stat, us, err) do { \
11     if (!wait_##stat(us)) { \
12         ibm4704_error = err; \
13         goto ERROR; \
14     } \
15 } while (0)
16
17
18 uint8_t ibm4704_error = 0;
19
20
21 void ibm4704_init(void)
22 {
23     inhibit();
24 }
25
26 /*
27 Host to Keyboard
28 ----------------
29 Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
30
31         ____        __   __   __   __   __   __   __   __   __   ________
32 Clock       \______/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
33             ^   ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
34 Data    ____|__/    X____X____X____X____X____X____X____X____X____X   \___
35             |  Start   0    1    2    3    4    5    6    7    P   Stop
36             Request by host
37
38 Start bit:  can be long as 300-350us.
39 Request:    Host pulls Clock line down to request to send a command.
40 Timing:     After Request keyboard pull up Data and down Clock line to low for start bit.
41             After request host release Clock line once Data line becomes hi.
42             Host writes a bit while Clock is hi and Keyboard reads while low.
43 Stop bit:   Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
44 */
45 uint8_t ibm4704_send(uint8_t data)
46 {
47     bool parity = true; // odd parity
48     ibm4704_error = 0;
49
50     /* Request to send */
51     idle();
52     clock_lo();
53
54     /* wait for Start bit(Clock:lo/Data:hi) */
55     WAIT(data_hi, 300, 0x30);
56
57     /* Data bit */
58     for (uint8_t i = 0; i < 8; i++) {
59         WAIT(clock_hi, 100, 0x40+i);
60         //_delay_us(5);
61         if (data&(1<<i)) {
62             parity = !parity;
63             data_hi();
64         } else {
65             data_lo();
66         }
67         WAIT(clock_lo, 100, 0x48+i);
68     }
69
70     /* Parity bit */
71     WAIT(clock_hi, 100, 0x34);
72     if (parity) { data_hi(); } else { data_lo(); }
73     WAIT(clock_lo, 100, 0x35);
74
75     /* Stop bit */
76     WAIT(clock_hi, 100, 0x34);
77     data_hi();
78
79     /* End */
80     WAIT(data_lo, 100, 0x36);
81
82     inhibit();
83     _delay_us(200); // wait to recover clock to hi
84     return 0;
85 ERROR:
86     inhibit();
87     if (ibm4704_error >= 0x30) {
88         xprintf("x%02X ", ibm4704_error);
89     }
90     _delay_us(200); // wait to recover clock to hi
91     return -1;
92 }
93
94 /* receive data when host want else inhibit communication */
95 uint8_t ibm4704_recv_response(void)
96 {
97     // 250 * 100us(wait start bit in ibm4704_recv)
98     uint8_t data = 0;
99     uint8_t try = 250;
100     do {
101         data = ibm4704_recv();
102     } while (try-- && ibm4704_error);
103     return data;
104 }
105
106 /*
107 Keyboard to Host
108 ----------------
109 Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
110
111         ____      __   __   __   __   __   __   __   __   __   ________
112 Clock       \____/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/  \_/
113              ____ ____ ____ ____ ____ ____ ____ ____ ____ ____    
114 Data    ____/    X____X____X____X____X____X____X____X____X____X________
115             Start   0    1    2    3    4    5    6    7    P  Stop
116
117 Start bit:  can be long as 300-350us.
118 Inhibit:    Pull Data line down to inhibit keyboard to send.
119 Timing:     Host reads bit while Clock is hi.
120 Stop bit:   Keyboard pulls down Data line to lo after 9th clock.
121 */
122 uint8_t ibm4704_recv(void)
123 {
124     uint8_t data = 0;
125     bool parity = true;    // odd parity
126     ibm4704_error = IBM4704_ERR_NONE;
127
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     }
146
147     /* parity */
148     WAIT(clock_hi, 100, 0x17);
149     if (data_in() != parity) {
150         ibm4704_error = IBM4704_ERR_PARITY;
151         goto ERROR;
152     }
153     WAIT(clock_lo, 150, 0x18);
154
155     /* stop bit */
156     WAIT(clock_hi, 100, 0x19);
157     WAIT(data_lo, 1, 0x19);
158
159     inhibit();
160     _delay_us(200); // wait to recover clock to hi
161     return data;
162 ERROR:
163     if (ibm4704_error > 0x12) {
164         xprintf("x%02X ", ibm4704_error);
165     }
166     inhibit();
167     _delay_us(200); // wait to recover clock to hi
168     return -1;
169 }