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.

105 lines
4.0 KiB

  1. /* Copyright 2018-2021 James Laird-Wah, Islam Sharabash
  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 "matrix.h"
  17. #include "i2c_master.h"
  18. #include "wait.h"
  19. #include <string.h>
  20. #include "wire-protocol-constants.h"
  21. // shifting << 1 is because drivers/chibios/i2c_master.h expects the address
  22. // shifted.
  23. // 0x58 and 0x59 are the addresses defined in dygma/raise/Hand.h
  24. #define I2C_ADDR_LEFT (0x58 << 1)
  25. #define I2C_ADDR_RIGHT (0x59 << 1)
  26. #define I2C_ADDR(hand) ((hand) ? I2C_ADDR_RIGHT : I2C_ADDR_LEFT)
  27. #define LEFT 0
  28. #define RIGHT 1
  29. /* If no key events have occurred, the scanners will time out on reads.
  30. * So we don't want to be too permissive here. */
  31. // TODO(ibash) not convinced this is needed...
  32. #define MY_I2C_TIMEOUT 10
  33. #define ROWS_PER_HAND (MATRIX_ROWS / 2)
  34. typedef enum { CHANGED, OFFLINE, UNCHANGED } read_hand_t;
  35. static read_hand_t last_state[2] = {OFFLINE, OFFLINE};
  36. static read_hand_t i2c_read_hand(int hand, matrix_row_t current_matrix[]) {
  37. // dygma raise firmware says online is true iff we get the number of
  38. // expected bytes (e.g. 6 bytes or ROWS_PER_HAND + 1).
  39. // In the case where no keys are pressed the keyscanner will send the same 0
  40. // byte over and over. -- so this case is set.
  41. //
  42. // On the stm32 side if we don't get as many bytes as expecetd the
  43. // i2c_receive times out -- so online can be defined as getting
  44. // "I2C_STATUS_SUCCESS".
  45. uint8_t buf[ROWS_PER_HAND + 1];
  46. i2c_status_t ret = i2c_receive(I2C_ADDR(hand), buf, sizeof(buf), MY_I2C_TIMEOUT);
  47. if (ret != I2C_STATUS_SUCCESS) {
  48. return OFFLINE;
  49. }
  50. if (buf[0] != TWI_REPLY_KEYDATA) {
  51. return UNCHANGED;
  52. }
  53. int start_row = hand ? ROWS_PER_HAND : 0;
  54. matrix_row_t *out = &current_matrix[start_row];
  55. memcpy(out, &buf[1], ROWS_PER_HAND);
  56. return CHANGED;
  57. }
  58. static int i2c_set_keyscan_interval(int hand, int delay) {
  59. uint8_t buf[] = {TWI_CMD_KEYSCAN_INTERVAL, delay};
  60. i2c_status_t ret = i2c_transmit(I2C_ADDR(hand), buf, sizeof(buf), MY_I2C_TIMEOUT);
  61. return ret;
  62. }
  63. void matrix_init_custom(void) {
  64. i2c_init();
  65. // ref: https://github.com/Dygmalab/Kaleidoscope/blob/7bac53de106c42ffda889e6854abc06cf43a3c6f/src/kaleidoscope/device/dygma/Raise.cpp#L83
  66. // ref: https://github.com/Dygmalab/Kaleidoscope/blob/7bac53de106c42ffda889e6854abc06cf43a3c6f/src/kaleidoscope/device/dygma/raise/Hand.cpp#L73
  67. i2c_set_keyscan_interval(LEFT, 50);
  68. i2c_set_keyscan_interval(RIGHT, 50);
  69. }
  70. bool matrix_scan_custom(matrix_row_t current_matrix[]) {
  71. // HACK(ibash) without the delay between the two calls to i2c_read_hand, the
  72. // second call to i2c_read_hand breaks. I observed that the i2s start isn't
  73. // sent, or maybe it is, but the address matcher in the attiny can't recognize
  74. // it. In any case, a short delay fixes it.
  75. read_hand_t left_state = i2c_read_hand(LEFT, current_matrix);
  76. wait_us(10);
  77. read_hand_t right_state = i2c_read_hand(RIGHT, current_matrix);
  78. if ((last_state[LEFT] == OFFLINE && left_state != OFFLINE) || (last_state[RIGHT] == OFFLINE && right_state != OFFLINE)) {
  79. // reinitialize both sides
  80. i2c_set_keyscan_interval(LEFT, 50);
  81. i2c_set_keyscan_interval(RIGHT, 50);
  82. }
  83. last_state[LEFT] = left_state;
  84. last_state[RIGHT] = right_state;
  85. bool matrix_has_changed = left_state == CHANGED || right_state == CHANGED;
  86. return matrix_has_changed;
  87. }