You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
7.3 KiB

  1. /* Copyright 2020 ZSA Technology Labs, Inc <@zsa>
  2. * Copyright 2020 Jack Humbert <jack.humb@gmail.com>
  3. * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "moonlander.h"
  19. #include "i2c_master.h"
  20. /*
  21. #define MATRIX_ROW_PINS { B10, B11, B12, B13, B14, B15 } outputs
  22. #define MATRIX_COL_PINS { A0, A1, A2, A3, A6, A7, B0 } inputs
  23. */
  24. /* matrix state(1:on, 0:off) */
  25. extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
  26. extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
  27. static matrix_row_t raw_matrix_right[MATRIX_COLS];
  28. #define ROWS_PER_HAND (MATRIX_ROWS / 2)
  29. #ifndef MOONLANDER_I2C_TIMEOUT
  30. # define MOONLANDER_I2C_TIMEOUT 100
  31. #endif
  32. extern bool mcp23018_leds[3];
  33. extern bool is_launching;
  34. bool mcp23018_initd = false;
  35. static uint8_t mcp23018_reset_loop;
  36. uint8_t mcp23018_tx[3];
  37. uint8_t mcp23018_rx[1];
  38. void mcp23018_init(void) {
  39. i2c_init();
  40. // #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs
  41. // #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs
  42. mcp23018_tx[0] = 0x00; // IODIRA
  43. mcp23018_tx[1] = 0b00000000; // A is output
  44. mcp23018_tx[2] = 0b00111111; // B is inputs
  45. if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, MOONLANDER_I2C_TIMEOUT)) {
  46. dprintf("error hori\n");
  47. } else {
  48. mcp23018_tx[0] = 0x0C; // GPPUA
  49. mcp23018_tx[1] = 0b10000000; // A is not pulled-up
  50. mcp23018_tx[2] = 0b11111111; // B is pulled-up
  51. if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, MOONLANDER_I2C_TIMEOUT)) {
  52. dprintf("error hori\n");
  53. } else {
  54. mcp23018_initd = is_launching = true;
  55. }
  56. }
  57. }
  58. void matrix_init_custom(void) {
  59. dprintf("matrix init\n");
  60. // debug_matrix = true;
  61. // outputs
  62. setPinOutput(B10);
  63. setPinOutput(B11);
  64. setPinOutput(B12);
  65. setPinOutput(B13);
  66. setPinOutput(B14);
  67. setPinOutput(B15);
  68. // inputs
  69. setPinInputLow(A0);
  70. setPinInputLow(A1);
  71. setPinInputLow(A2);
  72. setPinInputLow(A3);
  73. setPinInputLow(A6);
  74. setPinInputLow(A7);
  75. setPinInputLow(B0);
  76. mcp23018_init();
  77. }
  78. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  79. bool changed = false;
  80. // Try to re-init right side
  81. if (!mcp23018_initd) {
  82. if (++mcp23018_reset_loop == 0) {
  83. // if (++mcp23018_reset_loop >= 1300) {
  84. // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
  85. // this will be approx bit more frequent than once per second
  86. print("trying to reset mcp23018\n");
  87. mcp23018_init();
  88. if (!mcp23018_initd) {
  89. print("right side not responding\n");
  90. } else {
  91. print("right side attached\n");
  92. #ifdef RGB_MATRIX_ENABLE
  93. rgb_matrix_init();
  94. #endif
  95. }
  96. }
  97. }
  98. matrix_row_t data = 0;
  99. // actual matrix
  100. for (uint8_t row = 0; row <= ROWS_PER_HAND; row++) {
  101. // strobe row
  102. switch (row) {
  103. case 0: writePinHigh(B10); break;
  104. case 1: writePinHigh(B11); break;
  105. case 2: writePinHigh(B12); break;
  106. case 3: writePinHigh(B13); break;
  107. case 4: writePinHigh(B14); break;
  108. case 5: writePinHigh(B15); break;
  109. case 6: break; // Left hand has 6 rows
  110. }
  111. // right side
  112. if (mcp23018_initd) {
  113. // #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs
  114. // #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs
  115. // select row
  116. mcp23018_tx[0] = 0x12; // GPIOA
  117. mcp23018_tx[1] = (0b01111111 & ~(1 << (row))) | ((uint8_t)!mcp23018_leds[2] << 7); // activate row
  118. mcp23018_tx[2] = ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7); // activate row
  119. if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, MOONLANDER_I2C_TIMEOUT)) {
  120. dprintf("error hori\n");
  121. mcp23018_initd = false;
  122. }
  123. // read col
  124. mcp23018_tx[0] = 0x13; // GPIOB
  125. if (MSG_OK != i2c_read_register(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx[0], &mcp23018_rx[0], 1, MOONLANDER_I2C_TIMEOUT)) {
  126. dprintf("error vert\n");
  127. mcp23018_initd = false;
  128. }
  129. data = ~(mcp23018_rx[0] & 0b00111111);
  130. // data = 0x01;
  131. } else {
  132. data = 0;
  133. }
  134. if (raw_matrix_right[row] != data) {
  135. raw_matrix_right[row] = data;
  136. changed = true;
  137. }
  138. // left side
  139. if (row < ROWS_PER_HAND) {
  140. // i2c comm incur enough wait time
  141. if (!mcp23018_initd) {
  142. // need wait to settle pin state
  143. matrix_io_delay();
  144. }
  145. // read col data
  146. data = (
  147. (readPin(A0) << 0 ) |
  148. (readPin(A1) << 1 ) |
  149. (readPin(A2) << 2 ) |
  150. (readPin(A3) << 3 ) |
  151. (readPin(A6) << 4 ) |
  152. (readPin(A7) << 5 ) |
  153. (readPin(B0) << 6 )
  154. );
  155. // unstrobe row
  156. switch (row) {
  157. case 0: writePinLow(B10); break;
  158. case 1: writePinLow(B11); break;
  159. case 2: writePinLow(B12); break;
  160. case 3: writePinLow(B13); break;
  161. case 4: writePinLow(B14); break;
  162. case 5: writePinLow(B15); break;
  163. case 6: break;
  164. }
  165. if (current_matrix[row] != data) {
  166. current_matrix[row] = data;
  167. changed = true;
  168. }
  169. }
  170. }
  171. for (uint8_t row = 0; row < ROWS_PER_HAND; row++) {
  172. current_matrix[11 - row] = 0;
  173. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  174. current_matrix[11 - row] |= ((raw_matrix_right[6 - col] & (1 << row) ? 1 : 0) << col);
  175. }
  176. }
  177. return changed;
  178. }
  179. // DO NOT REMOVE
  180. // Needed for proper wake/sleep
  181. void matrix_power_up(void) {
  182. bool temp_launching = is_launching;
  183. matrix_init_custom();
  184. is_launching = temp_launching;
  185. if (!is_launching) {
  186. ML_LED_1(false);
  187. ML_LED_2(false);
  188. ML_LED_3(false);
  189. ML_LED_4(false);
  190. ML_LED_5(false);
  191. ML_LED_6(false);
  192. }
  193. // initialize matrix state: all keys off
  194. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  195. matrix[i] = 0;
  196. }
  197. }
  198. bool is_transport_connected(void) {
  199. return mcp23018_initd;
  200. }