]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/deltasplit75/matrix.c
Changed case of deltasplit75 to be lowercase.
[qmk_firmware.git] / keyboards / deltasplit75 / matrix.c
1 /*\r
2 Copyright 2012 Jun Wako <wakojun@gmail.com>\r
3 \r
4 This program is free software: you can redistribute it and/or modify\r
5 it under the terms of the GNU General Public License as published by\r
6 the Free Software Foundation, either version 2 of the License, or\r
7 (at your option) any later version.\r
8 \r
9 This program is distributed in the hope that it will be useful,\r
10 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12 GNU General Public License for more details.\r
13 \r
14 You should have received a copy of the GNU General Public License\r
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
16 */\r
17 \r
18 /*\r
19  * scan matrix\r
20  */\r
21 #include <stdint.h>\r
22 #include <stdbool.h>\r
23 #include <avr/io.h>\r
24 #include <avr/wdt.h>\r
25 #include <avr/interrupt.h>\r
26 #include <util/delay.h>\r
27 #include "print.h"\r
28 #include "debug.h"\r
29 #include "util.h"\r
30 #include "matrix.h"\r
31 #include "split_util.h"\r
32 #include "pro_micro.h"\r
33 #include "config.h"\r
34 \r
35 #ifdef USE_I2C\r
36 #  include "i2c.h"\r
37 #else // USE_SERIAL\r
38 #  include "serial.h"\r
39 #endif\r
40 \r
41 #ifndef DEBOUNCE\r
42 #  define DEBOUNCE      5\r
43 #endif\r
44 \r
45 #define ERROR_DISCONNECT_COUNT 5\r
46 \r
47 static uint8_t debouncing = DEBOUNCE;\r
48 static const int ROWS_PER_HAND = MATRIX_ROWS/2;\r
49 static uint8_t error_count = 0;\r
50 \r
51 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;\r
52 static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;\r
53 \r
54 /* matrix state(1:on, 0:off) */\r
55 static matrix_row_t matrix[MATRIX_ROWS];\r
56 static matrix_row_t matrix_debouncing[MATRIX_ROWS];\r
57 \r
58 static matrix_row_t read_cols(void);\r
59 static void init_cols(void);\r
60 static void unselect_rows(void);\r
61 static void select_row(uint8_t row);\r
62 \r
63 __attribute__ ((weak))\r
64 void matrix_init_quantum(void) {\r
65     matrix_init_kb();\r
66 }\r
67 \r
68 __attribute__ ((weak))\r
69 void matrix_scan_quantum(void) {\r
70     matrix_scan_kb();\r
71 }\r
72 \r
73 __attribute__ ((weak))\r
74 void matrix_init_kb(void) {\r
75     matrix_init_user();\r
76 }\r
77 \r
78 __attribute__ ((weak))\r
79 void matrix_scan_kb(void) {\r
80     matrix_scan_user();\r
81 }\r
82 \r
83 __attribute__ ((weak))\r
84 void matrix_init_user(void) {\r
85 }\r
86 \r
87 __attribute__ ((weak))\r
88 void matrix_scan_user(void) {\r
89 }\r
90 \r
91 inline\r
92 uint8_t matrix_rows(void)\r
93 {\r
94     return MATRIX_ROWS;\r
95 }\r
96 \r
97 inline\r
98 uint8_t matrix_cols(void)\r
99 {\r
100     return MATRIX_COLS;\r
101 }\r
102 \r
103 void matrix_init(void)\r
104 {\r
105     debug_enable = true;\r
106     debug_matrix = true;\r
107     debug_mouse = true;\r
108     // initialize row and col\r
109     unselect_rows();\r
110     init_cols();\r
111 \r
112     TX_RX_LED_INIT;\r
113 \r
114     // initialize matrix state: all keys off\r
115     for (uint8_t i=0; i < MATRIX_ROWS; i++) {\r
116         matrix[i] = 0;\r
117         matrix_debouncing[i] = 0;\r
118     }\r
119 \r
120     matrix_init_quantum();\r
121 }\r
122 \r
123 uint8_t _matrix_scan(void)\r
124 {\r
125     // Right hand is stored after the left in the matirx so, we need to offset it\r
126     int offset = isLeftHand ? 0 : (ROWS_PER_HAND);\r
127 \r
128     for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {\r
129         select_row(i);\r
130         _delay_us(30);  // without this wait read unstable value.\r
131         matrix_row_t cols = read_cols();\r
132         if (matrix_debouncing[i+offset] != cols) {\r
133             matrix_debouncing[i+offset] = cols;\r
134             debouncing = DEBOUNCE;\r
135         }\r
136         unselect_rows();\r
137     }\r
138 \r
139     if (debouncing) {\r
140         if (--debouncing) {\r
141             _delay_ms(1);\r
142         } else {\r
143             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {\r
144                 matrix[i+offset] = matrix_debouncing[i+offset];\r
145             }\r
146         }\r
147     }\r
148 \r
149     return 1;\r
150 }\r
151 \r
152 #ifdef USE_I2C\r
153 \r
154 // Get rows from other half over i2c\r
155 int i2c_transaction(void) {\r
156     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;\r
157 \r
158     int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);\r
159     if (err) goto i2c_error;\r
160 \r
161     // start of matrix stored at 0x00\r
162     err = i2c_master_write(0x00);\r
163     if (err) goto i2c_error;\r
164 \r
165     // Start read\r
166     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);\r
167     if (err) goto i2c_error;\r
168 \r
169     if (!err) {\r
170         int i;\r
171         for (i = 0; i < ROWS_PER_HAND-1; ++i) {\r
172             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);\r
173         }\r
174         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);\r
175         i2c_master_stop();\r
176     } else {\r
177 i2c_error: // the cable is disconnceted, or something else went wrong\r
178         i2c_reset_state();\r
179         return err;\r
180     }\r
181 \r
182     return 0;\r
183 }\r
184 \r
185 #else // USE_SERIAL\r
186 \r
187 int serial_transaction(void) {\r
188     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;\r
189 \r
190     if (serial_update_buffers()) {\r
191         return 1;\r
192     }\r
193 \r
194     for (int i = 0; i < ROWS_PER_HAND; ++i) {\r
195         matrix[slaveOffset+i] = serial_slave_buffer[i];\r
196     }\r
197     return 0;\r
198 }\r
199 #endif\r
200 \r
201 uint8_t matrix_scan(void)\r
202 {\r
203     int ret = _matrix_scan();\r
204 \r
205 \r
206 \r
207 #ifdef USE_I2C\r
208     if( i2c_transaction() ) {\r
209 #else // USE_SERIAL\r
210     if( serial_transaction() ) {\r
211 #endif\r
212         // turn on the indicator led when halves are disconnected\r
213         TXLED1;\r
214 \r
215         error_count++;\r
216 \r
217         if (error_count > ERROR_DISCONNECT_COUNT) {\r
218             // reset other half if disconnected\r
219             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;\r
220             for (int i = 0; i < ROWS_PER_HAND; ++i) {\r
221                 matrix[slaveOffset+i] = 0;\r
222             }\r
223         }\r
224     } else {\r
225         // turn off the indicator led on no error\r
226         TXLED0;\r
227         error_count = 0;\r
228     }\r
229 \r
230     matrix_scan_quantum();\r
231 \r
232     return ret;\r
233 }\r
234 \r
235 void matrix_slave_scan(void) {\r
236     _matrix_scan();\r
237 \r
238     int offset = (isLeftHand) ? 0 : (MATRIX_ROWS / 2);\r
239 \r
240 #ifdef USE_I2C\r
241     for (int i = 0; i < ROWS_PER_HAND; ++i) {\r
242         /* i2c_slave_buffer[i] = matrix[offset+i]; */\r
243         i2c_slave_buffer[i] = matrix[offset+i];\r
244     }\r
245 #else // USE_SERIAL\r
246     for (int i = 0; i < ROWS_PER_HAND; ++i) {\r
247         serial_slave_buffer[i] = matrix[offset+i];\r
248     }\r
249 #endif\r
250 }\r
251 \r
252 bool matrix_is_modified(void)\r
253 {\r
254     if (debouncing) return false;\r
255     return true;\r
256 }\r
257 \r
258 inline\r
259 bool matrix_is_on(uint8_t row, uint8_t col)\r
260 {\r
261     return (matrix[row] & ((matrix_row_t)1<<col));\r
262 }\r
263 \r
264 inline\r
265 matrix_row_t matrix_get_row(uint8_t row)\r
266 {\r
267     return matrix[row];\r
268 }\r
269 \r
270 void matrix_print(void)\r
271 {\r
272     print("\nr/c 0123456789ABCDEF\n");\r
273     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {\r
274         phex(row); print(": ");\r
275         pbin_reverse16(matrix_get_row(row));\r
276         print("\n");\r
277     }\r
278 }\r
279 \r
280 uint8_t matrix_key_count(void)\r
281 {\r
282     uint8_t count = 0;\r
283     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {\r
284         count += bitpop16(matrix[i]);\r
285     }\r
286     return count;\r
287 }\r
288 \r
289 static void  init_cols(void)\r
290 {\r
291     for(int x = 0; x < MATRIX_COLS; x++) {\r
292         _SFR_IO8((col_pins[x] >> 4) + 1) &=  ~_BV(col_pins[x] & 0xF);\r
293         _SFR_IO8((col_pins[x] >> 4) + 2) |= _BV(col_pins[x] & 0xF);\r
294     }\r
295 }\r
296 \r
297 static matrix_row_t read_cols(void)\r
298 {\r
299     matrix_row_t result = 0;\r
300     for(int x = 0; x < MATRIX_COLS; x++) {\r
301         result |= (_SFR_IO8(col_pins[x] >> 4) & _BV(col_pins[x] & 0xF)) ? 0 : (1 << x);\r
302     }\r
303     return result;\r
304 }\r
305 \r
306 static void unselect_rows(void)\r
307 {\r
308     for(int x = 0; x < ROWS_PER_HAND; x++) {\r
309         _SFR_IO8((row_pins[x] >> 4) + 1) &=  ~_BV(row_pins[x] & 0xF);\r
310         _SFR_IO8((row_pins[x] >> 4) + 2) |= _BV(row_pins[x] & 0xF);\r
311     }\r
312 }\r
313 \r
314 static void select_row(uint8_t row)\r
315 {\r
316     _SFR_IO8((row_pins[row] >> 4) + 1) |=  _BV(row_pins[row] & 0xF);\r
317     _SFR_IO8((row_pins[row] >> 4) + 2) &= ~_BV(row_pins[row] & 0xF);\r
318 }\r