aboutsummaryrefslogtreecommitdiff
path: root/keyboards/chidori/board.c
diff options
context:
space:
mode:
authorAkshay <[email protected]>2022-04-10 12:13:40 +0100
committerAkshay <[email protected]>2022-04-10 12:13:40 +0100
commitdc90387ce7d8ba7b607d9c48540bf6d8b560f14d (patch)
tree4ccb8fa5886b66fa9d480edef74236c27f035e16 /keyboards/chidori/board.c
Diffstat (limited to 'keyboards/chidori/board.c')
-rw-r--r--keyboards/chidori/board.c364
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
26static board_info_t boards[NUM_BOARDS] = BOARD_INFOS;
27static board_info_t* master_board = NULL;
28
29static bool board_is_master(board_info_t* board);
30static bool board_is_initialized(board_info_t* board);
31static board_info_t* get_board_by_index(uint8_t board_index);
32static uint8_t board_merge_led_config(board_info_t* board, uint8_t iodir);
33static uint8_t board_merge_led_status(board_info_t* board, uint8_t data);
34static void board_master_init(void);
35static void board_slave_init(void);
36
37//
38// board interface
39//
40static void board_select_master_row(board_info_t* board, uint8_t row);
41static void board_unselect_master_row(board_info_t* board, uint8_t row);
42static void board_unselect_master_rows(board_info_t* board);
43static bool board_read_cols_on_master_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row);
44static void board_set_master_led(board_info_t* board, uint8_t led_index, bool status);
45static void board_select_slave_row(board_info_t* board, uint8_t row);
46static void board_unselect_slave_row(board_info_t* board, uint8_t row);
47static void board_unselect_slave_rows(board_info_t* board);
48static bool board_read_cols_on_slave_row(board_info_t* board, matrix_row_t current_matrix[], uint8_t row);
49static void board_set_slave_led(board_info_t* board, uint8_t led_index, bool status);
50
51static 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};
52static 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
54static 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
61static 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
68static 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
76static 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
83static 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
118static 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
137inline bool board_is_master(board_info_t* board) {
138 if (board) {
139 return board->master;
140 }
141 return false;
142}
143
144inline uint8_t matrix2board(uint8_t row) { return row % NUM_ROWS; }
145
146inline uint8_t board_index(uint8_t row) { return row / NUM_ROWS; }
147
148static 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
160inline bool board_is_initialized(board_info_t* board) { return board == NULL ? false : board->initialized; }
161
162static 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
172static 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
183static 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//
201static 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
210static 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
221static 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
231static 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 */
236static 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//
258static 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
263static void board_unselect_master_row(board_info_t* board, uint8_t board_row) { setPinInputHigh(board->row_pins[board_row]); }
264
265static 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 */
277static 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
294static 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
305static 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...
317void 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
324bool 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
334void 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
343void 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
352void 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
359void board_init(void) {
360 board_setup();
361 board_master_init();
362 board_slave_init();
363 board_unselect_rows();
364}