logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

matrix.c (6574B)


  1. // Copyright 2023 ZSA Technology Labs, Inc <@zsa>
  2. // Copyright 2023 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include <stdint.h>
  5. #include "voyager.h"
  6. #include "mcp23018.h"
  7. #pragma GCC push_options
  8. #pragma GCC optimize("-O3")
  9. extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  10. extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
  11. static matrix_row_t raw_matrix_right[MATRIX_COLS];
  12. #define MCP_ROWS_PER_HAND (MATRIX_ROWS / 2)
  13. #ifndef VOYAGER_I2C_TIMEOUT
  14. # define VOYAGER_I2C_TIMEOUT 100
  15. #endif
  16. // Delay between each i2c io expander ops (in MCU cycles)
  17. #ifndef IO_EXPANDER_OP_DELAY
  18. # define IO_EXPANDER_OP_DELAY 500
  19. #endif
  20. extern bool mcp23018_leds[2];
  21. extern bool is_launching;
  22. static uint16_t mcp23018_reset_loop;
  23. uint8_t mcp23018_errors;
  24. bool io_expander_ready(void) {
  25. uint8_t tx;
  26. return mcp23018_readPins(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTA, &tx);
  27. }
  28. void matrix_init_custom(void) {
  29. // outputs
  30. gpio_set_pin_output(B10);
  31. gpio_set_pin_output(B11);
  32. gpio_set_pin_output(B12);
  33. gpio_set_pin_output(B13);
  34. gpio_set_pin_output(B14);
  35. gpio_set_pin_output(B15);
  36. // inputs
  37. gpio_set_pin_input_low(A0);
  38. gpio_set_pin_input_low(A1);
  39. gpio_set_pin_input_low(A2);
  40. gpio_set_pin_input_low(A3);
  41. gpio_set_pin_input_low(A6);
  42. gpio_set_pin_input_low(A7);
  43. gpio_set_pin_input_low(B0);
  44. mcp23018_init(MCP23018_DEFAULT_ADDRESS);
  45. mcp23018_errors += !mcp23018_set_config(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTA, 0b00000000);
  46. mcp23018_errors += !mcp23018_set_config(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTB, 0b00111111);
  47. if (!mcp23018_errors) {
  48. is_launching = true;
  49. }
  50. }
  51. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  52. bool changed = false;
  53. // Attempt to reset the mcp23018 if it's not initialized
  54. if (mcp23018_errors) {
  55. if (++mcp23018_reset_loop > 0x1FFF) {
  56. if (io_expander_ready()) {
  57. // If we managed to initialize the mcp23018 - we need to reinitialize the matrix / layer state. During an electric discharge the i2c peripherals might be in a weird state. Giving a delay and resetting the MCU allows to recover from this.
  58. wait_ms(200);
  59. mcu_reset();
  60. }
  61. }
  62. }
  63. // Scanning left and right side of the keyboard for key presses.
  64. // Left side is scanned by reading the gpio pins directly, right side is scanned by reading the mcp23018 registers.
  65. matrix_row_t data = 0;
  66. for (uint8_t row = 0; row <= MCP_ROWS_PER_HAND; row++) {
  67. // strobe row
  68. switch (row) {
  69. case 0:
  70. gpio_write_pin_high(B10);
  71. break;
  72. case 1:
  73. gpio_write_pin_high(B11);
  74. break;
  75. case 2:
  76. gpio_write_pin_high(B12);
  77. break;
  78. case 3:
  79. gpio_write_pin_high(B13);
  80. break;
  81. case 4:
  82. gpio_write_pin_high(B14);
  83. break;
  84. case 5:
  85. gpio_write_pin_high(B15);
  86. break;
  87. case 6:
  88. break; // Left hand has 6 rows
  89. }
  90. // Selecting the row on the right side of the keyboard.
  91. if (!mcp23018_errors) {
  92. // select row
  93. mcp23018_errors += !mcp23018_set_output(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTA, 0b01111111 & ~(1 << (row)));
  94. mcp23018_errors += !mcp23018_set_output(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTB, ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7));
  95. }
  96. // Reading the left side of the keyboard.
  97. if (row < MCP_ROWS_PER_HAND) {
  98. // i2c comm incur enough wait time
  99. if (mcp23018_errors) {
  100. // need wait to settle pin state
  101. matrix_io_delay();
  102. }
  103. // read col data
  104. data = ((gpio_read_pin(A0) << 0) | (gpio_read_pin(A1) << 1) | (gpio_read_pin(A2) << 2) | (gpio_read_pin(A3) << 3) | (gpio_read_pin(A6) << 4) | (gpio_read_pin(A7) << 5) | (gpio_read_pin(B0) << 6));
  105. // unstrobe row
  106. switch (row) {
  107. case 0:
  108. gpio_write_pin_low(B10);
  109. break;
  110. case 1:
  111. gpio_write_pin_low(B11);
  112. break;
  113. case 2:
  114. gpio_write_pin_low(B12);
  115. break;
  116. case 3:
  117. gpio_write_pin_low(B13);
  118. break;
  119. case 4:
  120. gpio_write_pin_low(B14);
  121. break;
  122. case 5:
  123. gpio_write_pin_low(B15);
  124. break;
  125. case 6:
  126. break;
  127. }
  128. if (current_matrix[row] != data) {
  129. current_matrix[row] = data;
  130. changed = true;
  131. }
  132. }
  133. // Reading the right side of the keyboard.
  134. if (!mcp23018_errors) {
  135. for (uint16_t i = 0; i < IO_EXPANDER_OP_DELAY; i++) {
  136. __asm__("nop");
  137. }
  138. uint8_t rx;
  139. mcp23018_errors += !mcp23018_readPins(MCP23018_DEFAULT_ADDRESS, mcp23018_PORTB, &rx);
  140. data = ~(rx & 0b00111111);
  141. for (uint16_t i = 0; i < IO_EXPANDER_OP_DELAY; i++) {
  142. __asm__("nop");
  143. }
  144. } else {
  145. data = 0;
  146. }
  147. if (raw_matrix_right[row] != data) {
  148. raw_matrix_right[row] = data;
  149. changed = true;
  150. }
  151. }
  152. for (uint8_t row = 0; row < MCP_ROWS_PER_HAND; row++) {
  153. current_matrix[11 - row] = 0;
  154. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  155. current_matrix[11 - row] |= ((raw_matrix_right[6 - col] & (1 << row) ? 1 : 0) << col);
  156. }
  157. }
  158. return changed;
  159. }
  160. // DO NOT REMOVE
  161. // Needed for proper wake/sleep
  162. void matrix_power_up(void) {
  163. bool temp_launching = is_launching;
  164. matrix_init_custom();
  165. is_launching = temp_launching;
  166. if (!temp_launching) {
  167. STATUS_LED_1(false);
  168. STATUS_LED_2(false);
  169. STATUS_LED_3(false);
  170. STATUS_LED_4(false);
  171. }
  172. // initialize matrix state: all keys off
  173. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  174. matrix[i] = 0;
  175. }
  176. }
  177. bool is_transport_connected(void) {
  178. return (bool)(mcp23018_errors == 0);
  179. }
  180. #pragma GCC pop_options