diff options
Diffstat (limited to 'keyboards/chidori/board.c')
-rw-r--r-- | keyboards/chidori/board.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/keyboards/chidori/board.c b/keyboards/chidori/board.c new file mode 100644 index 000000000..e00156eb9 --- /dev/null +++ b/keyboards/chidori/board.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* Copyright 2019 ENDO Katsuhiro <[email protected]> | ||
2 | * | ||
3 | * This program is free software: you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License as published by | ||
5 | * the Free Software Foundation, either version 2 of the License, or | ||
6 | * (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | #include <stdint.h> | ||
17 | #include <stdbool.h> | ||
18 | #include "wait.h" | ||
19 | #include "print.h" | ||
20 | #include "debug.h" | ||
21 | #include "matrix.h" | ||
22 | #include "quantum.h" | ||
23 | #include "board.h" | ||
24 | #include "i2c_master.h" | ||
25 | |||
26 | static board_info_t boards[NUM_BOARDS] = BOARD_INFOS; | ||
27 | static board_info_t* master_board = NULL; | ||
28 | |||
29 | static bool board_is_master(board_info_t* board); | ||
30 | static bool board_is_initialized(board_info_t* board); | ||
31 | static board_info_t* get_board_by_index(uint8_t board_index); | ||
32 | static uint8_t board_merge_led_config(board_info_t* board, uint8_t iodir); | ||
33 | static uint8_t board_merge_led_status(board_info_t* board, uint8_t data); | ||
34 | static void board_master_init(void); | ||
35 | static void board_slave_init(void); | ||
36 | |||
37 | // | ||
38 | // board interface | ||
39 | // | ||
40 | static void board_select_master_row(board_info_t* board, uint8_t row); | ||
41 | static void board_unselect_master_row(board_info_t* board, uint8_t row); | ||
42 | static void board_unselect_master_rows(board_info_t* board); | ||
43 | static bool board_read_cols_on_master_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row); | ||
44 | static void board_set_master_led(board_info_t* board, uint8_t led_index, bool status); | ||
45 | static void board_select_slave_row(board_info_t* board, uint8_t row); | ||
46 | static void board_unselect_slave_row(board_info_t* board, uint8_t row); | ||
47 | static void board_unselect_slave_rows(board_info_t* board); | ||
48 | static bool board_read_cols_on_slave_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row); | ||
49 | static void board_set_slave_led(board_info_t* board, uint8_t led_index, bool status); | ||
50 | |||
51 | static board_interface_t master_interface = {board_select_master_row, board_unselect_master_row, board_unselect_master_rows, board_read_cols_on_master_row, board_set_master_led}; | ||
52 | static board_interface_t slave_interface = {board_select_slave_row, board_unselect_slave_row, board_unselect_slave_rows, board_read_cols_on_slave_row, board_set_slave_led}; | ||
53 | |||
54 | static board_interface_t* get_interface(board_info_t* board) { | ||
55 | if (board_is_master(board)) { | ||
56 | return &master_interface; | ||
57 | } | ||
58 | return &slave_interface; | ||
59 | } | ||
60 | |||
61 | static void board_set_master_led(board_info_t* board, uint8_t led_index, bool status) { | ||
62 | pin_t pin = board->led_pins[led_index]; | ||
63 | board->led_status[led_index] = status; | ||
64 | setPinOutput(pin); | ||
65 | status ? writePinHigh(pin) : writePinLow(pin); | ||
66 | } | ||
67 | |||
68 | static void board_set_slave_led(board_info_t* board, uint8_t led_index, bool status) { | ||
69 | board->led_status[led_index] = status; | ||
70 | uint8_t iodir = board_merge_led_config(board, 0xff); | ||
71 | uint8_t data = board_merge_led_status(board, 0x00); | ||
72 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IODIRB, (const uint8_t*)&iodir, sizeof(iodir), BOARD_I2C_TIMEOUT); | ||
73 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_OLATB, (const uint8_t*)&data, sizeof(data), BOARD_I2C_TIMEOUT); | ||
74 | } | ||
75 | |||
76 | static uint8_t board_merge_led_config(board_info_t* board, uint8_t iodir) { | ||
77 | for (uint8_t i = 0; i < NUM_LEDS; i++) { | ||
78 | iodir &= PIN2MASK(board->led_pins[i]); | ||
79 | } | ||
80 | return iodir; | ||
81 | } | ||
82 | |||
83 | static bool board_slave_config(board_info_t* board) { | ||
84 | uint8_t set = 0xff; | ||
85 | uint8_t clear = 0x00; | ||
86 | i2c_status_t res = 0; | ||
87 | |||
88 | // Set to input | ||
89 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IODIRA, (const uint8_t*)&set, sizeof(set), BOARD_I2C_TIMEOUT); | ||
90 | if (res < 0) return false; | ||
91 | // RESTRICTION: LEDs only on PORT B. | ||
92 | set = board_merge_led_config(board, set); | ||
93 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IODIRB, (const uint8_t*)&set, sizeof(set), BOARD_I2C_TIMEOUT); | ||
94 | if (res < 0) return false; | ||
95 | set = 0xff; | ||
96 | |||
97 | // Pull up for input - enable | ||
98 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_GPPUA, (const uint8_t*)&set, sizeof(set), BOARD_I2C_TIMEOUT); | ||
99 | if (res < 0) return false; | ||
100 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_GPPUB, (const uint8_t*)&set, sizeof(set), BOARD_I2C_TIMEOUT); | ||
101 | if (res < 0) return false; | ||
102 | |||
103 | // Disable interrupt | ||
104 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_GPINTENA, (const uint8_t*)&clear, sizeof(clear), BOARD_I2C_TIMEOUT); | ||
105 | if (res < 0) return false; | ||
106 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_GPINTENB, (const uint8_t*)&clear, sizeof(clear), BOARD_I2C_TIMEOUT); | ||
107 | if (res < 0) return false; | ||
108 | |||
109 | // Polarity - same logic | ||
110 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IPOLA, (const uint8_t*)&clear, sizeof(clear), BOARD_I2C_TIMEOUT); | ||
111 | if (res < 0) return false; | ||
112 | res = i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IPOLB, (const uint8_t*)&clear, sizeof(clear), BOARD_I2C_TIMEOUT); | ||
113 | if (res < 0) return false; | ||
114 | |||
115 | return true; | ||
116 | } | ||
117 | |||
118 | static void board_slave_init(void) { | ||
119 | i2c_init(); | ||
120 | _delay_ms(500); | ||
121 | |||
122 | for (uint8_t i = 0; i < NUM_BOARDS; i++) { | ||
123 | board_info_t* board = &boards[i]; | ||
124 | if (board_is_master(board)) { | ||
125 | continue; | ||
126 | } | ||
127 | if (i2c_start(EXPANDER_ADDR(board->i2c_address), BOARD_I2C_TIMEOUT) != I2C_STATUS_SUCCESS) { | ||
128 | continue; | ||
129 | } | ||
130 | i2c_stop(); | ||
131 | if (board_slave_config(board)) { | ||
132 | board->initialized = true; | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | inline bool board_is_master(board_info_t* board) { | ||
138 | if (board) { | ||
139 | return board->master; | ||
140 | } | ||
141 | return false; | ||
142 | } | ||
143 | |||
144 | inline uint8_t matrix2board(uint8_t row) { return row % NUM_ROWS; } | ||
145 | |||
146 | inline uint8_t board_index(uint8_t row) { return row / NUM_ROWS; } | ||
147 | |||
148 | static board_info_t* get_master_board(void) { | ||
149 | if (master_board == NULL) { | ||
150 | for (uint8_t i = 0; i < NUM_BOARDS; i++) { | ||
151 | if (boards[i].master) { | ||
152 | master_board = &boards[i]; | ||
153 | return master_board; | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | inline bool board_is_initialized(board_info_t* board) { return board == NULL ? false : board->initialized; } | ||
161 | |||
162 | static board_info_t* get_board_by_index(uint8_t board_index) { | ||
163 | if (board_index >= 0 && board_index < NUM_BOARDS) { | ||
164 | if (!board_is_initialized(&boards[board_index])) { | ||
165 | return NULL; | ||
166 | } | ||
167 | return &boards[board_index]; | ||
168 | } | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | static board_info_t* get_board(uint8_t row) { | ||
173 | uint8_t idx = board_index(row); | ||
174 | if (idx >= 0 && idx < NUM_BOARDS) { | ||
175 | if (!board_is_initialized(&boards[idx])) { | ||
176 | return NULL; | ||
177 | } | ||
178 | return &boards[idx]; | ||
179 | } | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | static uint8_t board_merge_led_status(board_info_t* board, uint8_t data) { | ||
184 | if (!board_is_initialized(board)) { | ||
185 | return data; | ||
186 | } | ||
187 | for (uint8_t i = 0; i < NUM_LEDS; i++) { | ||
188 | bool status = board->led_status[i]; | ||
189 | if (status) { | ||
190 | data |= (uint8_t)1 << PIN2INDEX(board->led_pins[i]); | ||
191 | } else { | ||
192 | data &= PIN2MASK(board->led_pins[i]); | ||
193 | } | ||
194 | } | ||
195 | return data; | ||
196 | } | ||
197 | |||
198 | // | ||
199 | // Functions for slave | ||
200 | // | ||
201 | static uint8_t board_read_slave_cols(board_info_t* board) { | ||
202 | if (!board_is_initialized(board)) { | ||
203 | return 0xff; | ||
204 | } | ||
205 | uint8_t data = 0xff; | ||
206 | i2c_status_t res = i2c_readReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_GPIOA, &data, sizeof(data), BOARD_I2C_TIMEOUT); | ||
207 | return (res < 0) ? 0xff : data; | ||
208 | } | ||
209 | |||
210 | static void board_select_slave_row(board_info_t* board, uint8_t board_row) { | ||
211 | if (!board_is_initialized(board)) { | ||
212 | return; | ||
213 | } | ||
214 | uint8_t pin = board->row_pins[board_row]; | ||
215 | uint8_t iodir = board_merge_led_config(board, PIN2MASK(pin)); | ||
216 | uint8_t status = board_merge_led_status(board, PIN2MASK(pin)); | ||
217 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IODIRB, (const uint8_t*)&iodir, sizeof(iodir), BOARD_I2C_TIMEOUT); | ||
218 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_OLATB, (const uint8_t*)&status, sizeof(status), BOARD_I2C_TIMEOUT); | ||
219 | } | ||
220 | |||
221 | static void board_unselect_slave_rows(board_info_t* board) { | ||
222 | if (!board_is_initialized(board)) { | ||
223 | return; | ||
224 | } | ||
225 | uint8_t iodir = board_merge_led_config(board, 0xff); | ||
226 | uint8_t data = board_merge_led_status(board, 0x00); | ||
227 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_IODIRB, (const uint8_t*)&iodir, sizeof(iodir), BOARD_I2C_TIMEOUT); | ||
228 | i2c_writeReg(EXPANDER_ADDR(board->i2c_address), EXPANDER_OLATB, (const uint8_t*)&data, sizeof(data), BOARD_I2C_TIMEOUT); | ||
229 | } | ||
230 | |||
231 | static void board_unselect_slave_row(board_info_t* board, uint8_t board_row) { board_unselect_slave_rows(board); } | ||
232 | |||
233 | /* | ||
234 | * row : matrix row (not board row) | ||
235 | */ | ||
236 | static bool board_read_cols_on_slave_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row) { | ||
237 | matrix_row_t last_row_value = current_matrix[row]; | ||
238 | current_matrix[row] = 0; | ||
239 | |||
240 | uint8_t board_row = matrix2board(row); | ||
241 | board_select_slave_row(board, board_row); | ||
242 | wait_us(30); | ||
243 | |||
244 | uint8_t cols = board_read_slave_cols(board); | ||
245 | for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { | ||
246 | uint8_t pin = board->col_pins[col_index]; | ||
247 | uint8_t pin_state = cols & PIN2BIT(pin); | ||
248 | current_matrix[row] |= pin_state ? 0 : (1 << col_index); | ||
249 | } | ||
250 | board_unselect_slave_row(board, board_row); | ||
251 | |||
252 | return (last_row_value != current_matrix[row]); | ||
253 | } | ||
254 | |||
255 | // | ||
256 | // Functions for master board | ||
257 | // | ||
258 | static void board_select_master_row(board_info_t* board, uint8_t board_row) { | ||
259 | setPinOutput(board->row_pins[board_row]); | ||
260 | writePinLow(board->row_pins[board_row]); | ||
261 | } | ||
262 | |||
263 | static void board_unselect_master_row(board_info_t* board, uint8_t board_row) { setPinInputHigh(board->row_pins[board_row]); } | ||
264 | |||
265 | static void board_unselect_master_rows(board_info_t* board) { | ||
266 | if (!board) { | ||
267 | return; | ||
268 | } | ||
269 | for (uint8_t x = 0; x < NUM_ROWS; x++) { | ||
270 | setPinInput(board->row_pins[x]); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * row : matrix row (not board row) | ||
276 | */ | ||
277 | static bool board_read_cols_on_master_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row) { | ||
278 | matrix_row_t last_row_value = current_matrix[row]; | ||
279 | current_matrix[row] = 0; | ||
280 | |||
281 | uint8_t board_row = matrix2board(row); | ||
282 | board_select_master_row(board, board_row); | ||
283 | wait_us(30); | ||
284 | |||
285 | for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { | ||
286 | uint8_t pin_state = readPin(board->col_pins[col_index]); | ||
287 | current_matrix[row] |= pin_state ? 0 : (1 << col_index); | ||
288 | } | ||
289 | board_unselect_master_row(board, board_row); | ||
290 | |||
291 | return (last_row_value != current_matrix[row]); | ||
292 | } | ||
293 | |||
294 | static void board_master_init(void) { | ||
295 | board_info_t* board = get_master_board(); | ||
296 | if (!board) { | ||
297 | return; | ||
298 | } | ||
299 | for (uint8_t x = 0; x < NUM_COLS; x++) { | ||
300 | setPinInputHigh(board->col_pins[x]); | ||
301 | } | ||
302 | board->initialized = true; | ||
303 | } | ||
304 | |||
305 | static void board_setup(void) { | ||
306 | for (uint8_t i = 0; i < NUM_BOARDS; i++) { | ||
307 | board_info_t* board = &boards[i]; | ||
308 | board->interface = get_interface(board); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // | ||
313 | // Public functions | ||
314 | // | ||
315 | |||
316 | // NOTE: Do not call this while matrix scanning... | ||
317 | void board_set_led_by_index(uint8_t board_index, uint8_t led_index, bool status) { | ||
318 | board_info_t* board = get_board_by_index(board_index); | ||
319 | if (!board) return; | ||
320 | if (led_index < 0 || led_index > NUM_LEDS) return; | ||
321 | (*board->interface->set_led)(board, led_index, status); | ||
322 | } | ||
323 | |||
324 | bool board_read_cols_on_row(matrix_row_t current_matrix[], uint8_t row) { | ||
325 | bool result = false; | ||
326 | board_info_t* board = get_board(row); | ||
327 | if (!board) { | ||
328 | return false; | ||
329 | } | ||
330 | result = (*board->interface->read_cols_on_row)(board, current_matrix, row); | ||
331 | return result; | ||
332 | } | ||
333 | |||
334 | void board_select_row(uint8_t row) { | ||
335 | board_info_t* board = get_board(row); | ||
336 | if (!board) { | ||
337 | return; | ||
338 | } | ||
339 | uint8_t board_row = matrix2board(row); | ||
340 | (*board->interface->select_row)(board, board_row); | ||
341 | } | ||
342 | |||
343 | void board_unselect_row(uint8_t row) { | ||
344 | board_info_t* board = get_board(row); | ||
345 | if (!board) { | ||
346 | return; | ||
347 | } | ||
348 | uint8_t board_row = matrix2board(row); | ||
349 | (*board->interface->unselect_row)(board, board_row); | ||
350 | } | ||
351 | |||
352 | void board_unselect_rows(void) { | ||
353 | for (uint8_t i = 0; i < NUM_BOARDS; i++) { | ||
354 | board_info_t* board = &boards[i]; | ||
355 | (*board->interface->unselect_rows)(board); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | void board_init(void) { | ||
360 | board_setup(); | ||
361 | board_master_init(); | ||
362 | board_slave_init(); | ||
363 | board_unselect_rows(); | ||
364 | } | ||