matrix.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /* Copyright 2023 ebastler and elpekenin
  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 "pca9555.h"
  17. #include "quantum.h"
  18. // PCA9555 i2c address, 0x20: A0 = 0, A1 = 0, A2 = 0
  19. #define IC1 0x20
  20. // Define how long to wait to reach the IO expander after connection loss again
  21. // Since this board is modular, it should not spam unnecessary i2c requests if used without a module
  22. #define RETRY_TIMESPAN 2000
  23. typedef enum {
  24. PLUGGED,
  25. DOUBTFUL,
  26. UNPLUGGED
  27. } expander_status_t;
  28. void pca9555_setup(void) {
  29. // Initialize the expander, no need to set ports to inputs as that is the default behavior
  30. pca9555_init(IC1);
  31. }
  32. void matrix_init_custom(void) {
  33. // Encoder pushbutton on the MCU is connected to PD2
  34. setPinInputHigh(D2);
  35. pca9555_setup();
  36. }
  37. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  38. static expander_status_t status = DOUBTFUL;
  39. static uint32_t retry_timer = 0;
  40. // initialize one byte filled with 1
  41. uint8_t pin_states = 0xFF;
  42. if (status != UNPLUGGED || timer_elapsed32(retry_timer) > RETRY_TIMESPAN) {
  43. // If the chip was unplugged before, it needs to be re-initialized
  44. if(status==UNPLUGGED) {
  45. pca9555_setup();
  46. }
  47. // Read the entire port into this byte, 1 = not pressed, 0 = pressed
  48. bool ret = pca9555_readPins(IC1, PCA9555_PORT0, &pin_states);
  49. // Update state
  50. if (ret) {
  51. status = PLUGGED;
  52. } else {
  53. switch (status) {
  54. case PLUGGED:
  55. status = DOUBTFUL;
  56. break;
  57. case DOUBTFUL:
  58. status = UNPLUGGED;
  59. break;
  60. // If we've diagnosed as unplugged, update timer to not read I2C
  61. case UNPLUGGED:
  62. retry_timer = timer_read32();
  63. }
  64. }
  65. }
  66. // Shift pin states by 1 to make room for the switch connected to the MCU, then OR them together and invert (as QMK uses inverted logic compared to the electrical levels)
  67. matrix_row_t data = ~(pin_states << 1 | readPin(D2));
  68. bool changed = current_matrix[0] != data;
  69. current_matrix[0] = data;
  70. return changed;
  71. }