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