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.

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