xwhatsit keyboards: implement row and dac tester
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / util_comm.c
1 /* Copyright 2020 Purdea Andrei
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
17 #include "quantum.h"
18 #include "raw_hid.h"
19 #include "util_comm.h"
20 #include "matrix_manipulate.h"
21 #include <string.h>
22 #include <tmk_core/common/eeprom.h>
23
24 #if defined(KEYBOARD_SHARED_EP) && defined(RAW_ENABLE)
25 #error "Enabling the KEYBOARD_SHARED_EP will make the util be unable to communicate with the firmware, because due to hidapi limiations, the util can't figure out which interface to talk to, so it hardcodes interface zero."
26 #endif
27
28 #ifndef RAW_EPSIZE
29 #define RAW_EPSIZE 32
30 #endif
31
32 extern const char *KEYBOARD_FILENAME; // This must be defined in keyboard_name.c to equal the filename. This is sent back to the PC-side software for it to determine which keyboard we are using.
33
34 static const uint8_t magic[] = UTIL_COMM_MAGIC;
35
36 void raw_hid_receive(uint8_t *data, uint8_t length) {
37 if (0 != memcmp(data, magic, sizeof(magic))) {
38 return;
39 }
40 uint8_t response[RAW_EPSIZE];
41 memcpy(response, magic, sizeof(magic));
42 response[2] = UTIL_COMM_RESPONSE_ERROR;
43 switch (data[2])
44 {
45 case UTIL_COMM_GET_VERSION:
46 response[2] = UTIL_COMM_RESPONSE_OK;
47 response[3] = UTIL_COMM_VERSION_MAJOR;
48 response[4] = UTIL_COMM_VERSION_MID;
49 response[5] = (UTIL_COMM_VERSION_MINOR >> 8) & 0xff;
50 response[6] = (UTIL_COMM_VERSION_MINOR >> 0) & 0xff;
51 break;
52 case UTIL_COMM_DISABLE_KEYBOARD:
53 response[2] = UTIL_COMM_RESPONSE_OK;
54 response[3] = (uint8_t) keyboard_scan_enabled;
55 keyboard_scan_enabled = 0;
56 break;
57 case UTIL_COMM_ENABLE_KEYBOARD:
58 response[2] = UTIL_COMM_RESPONSE_OK;
59 response[3] = (uint8_t) keyboard_scan_enabled;
60 keyboard_scan_enabled = 1;
61 break;
62 case UTIL_COMM_ENTER_BOOTLOADER:
63 keyboard_scan_enabled = 0;
64 wait_ms(10);
65 bootloader_jump();
66 // we should not be reaching the following:
67 wait_ms(10);
68 response[2] = UTIL_COMM_RESPONSE_OK;
69 break;
70 case UTIL_COMM_GET_KEYSTATE:
71 response[2] = UTIL_COMM_RESPONSE_OK;
72 #if 1
73 matrix_scan_raw((matrix_row_t *)&response[3]); // AVR doesn't require not-byte values to be aligned, so this is correct, and it's an optimization.
74 #else
75 {
76 matrix_row_t current_matrix[MATRIX_ROWS];
77 matrix_scan_raw(current_matrix);
78 memcpy(&response[3], current_matrix, sizeof(current_matrix));
79 }
80 #endif
81 break;
82 case UTIL_COMM_GET_THRESHOLDS:
83 response[2] = UTIL_COMM_RESPONSE_OK;
84 #if CAPSENSE_CAL_ENABLED
85 response[3] = CAPSENSE_CAL_BINS;
86 {
87 const uint8_t cal_bin = data[3];
88 response[4] = cal_thresholds[cal_bin] & 0xff;
89 response[5] = (cal_thresholds[cal_bin] >> 8) & 0xff;
90 memcpy(&response[6], assigned_to_threshold[cal_bin], sizeof(assigned_to_threshold[cal_bin]));
91 }
92 #else
93 response[3] = 0;
94 response[4] = (CAPSENSE_HARDCODED_THRESHOLD) & 0xff;
95 response[5] = ((CAPSENSE_HARDCODED_THRESHOLD) >> 8) & 0xff;
96 #endif
97 break;
98 case UTIL_COMM_GET_KEYBOARD_FILENAME:
99 {
100 response[2] = UTIL_COMM_RESPONSE_OK;
101 if (data[3] >= strlen(KEYBOARD_FILENAME) + 1)
102 {
103 response[3] = 0;
104 } else {
105 const char *substring = KEYBOARD_FILENAME + data[3];
106 size_t substring_length = strlen(substring) + 1;
107 if (substring_length > RAW_EPSIZE - 3) substring_length = RAW_EPSIZE - 3;
108 memcpy(&response[3], substring, substring_length);
109 }
110 break;
111 }
112 case UTIL_COMM_ERASE_EEPROM:
113 {
114 response[2] = UTIL_COMM_RESPONSE_OK;
115 uint16_t addr;
116 for (addr=0; addr<E2END; addr += 1)
117 {
118 eeprom_update_byte((uint8_t*)addr, 0xff);
119 }
120 break;
121 }
122 case UTIL_COMM_GET_SIGNAL_VALUE:
123 {
124 response[2] = UTIL_COMM_RESPONSE_OK;
125 uint8_t col = data[3];
126 uint8_t row = data[4];
127 uint8_t count = data[5];
128 int i;
129 for (i=0;i<count;i++)
130 {
131 uint16_t value = measure_middle_keymap_coords(col, row, CAPSENSE_HARDCODED_SAMPLE_TIME, 8);
132 response[3+i*2] = value & 0xff;
133 response[3+i*2+1] = (value >> 8) & 0xff;
134 col += 1;
135 if (col >= MATRIX_COLS) {
136 col -= MATRIX_COLS;
137 row += 1;
138 }
139 if (row >= MATRIX_ROWS)
140 {
141 break;
142 }
143 }
144 break;
145 }
146 case UTIL_COMM_GET_KEYBOARD_DETAILS:
147 {
148 response[2] = UTIL_COMM_RESPONSE_OK;
149 response[3] = MATRIX_COLS;
150 response[4] = MATRIX_ROWS;
151 #if defined(CONTROLLER_IS_XWHATSIT_BEAMSPRING_REV_4)
152 response[5] = 1;
153 #elif defined(CONTROLLER_IS_XWHATSIT_MODEL_F_OR_WCASS_MODEL_F)
154 response[5] = 2;
155 #elif defined(CONTROLLER_IS_THROUGH_HOLE_BEAMSPRING)
156 response[5] = 3;
157 #elif defined(CONTROLLER_IS_THROUGH_HOLE_MODEL_F)
158 response[5] = 4;
159 #else
160 response[5] = 0;
161 #endif
162 response[6] = CAPSENSE_KEYBOARD_SETTLE_TIME_US;
163 response[7] = CAPSENSE_DAC_SETTLE_TIME_US;
164 response[8] = CAPSENSE_HARDCODED_SAMPLE_TIME;
165 response[9] = CAPSENSE_CAL_ENABLED;
166 response[10] = CAPSENSE_DAC_MAX & 0xFF;
167 response[11] = (CAPSENSE_DAC_MAX >> 8) & 0xFF;
168 break;
169 }
170 case UTIL_COMM_SHIFT_DATA:
171 {
172 response[2] = UTIL_COMM_RESPONSE_OK;
173 uint32_t shdata = (((uint32_t)(data[3])) << 0) |
174 (((uint32_t)(data[4])) << 8) |
175 (((uint32_t)(data[5])) << 16) |
176 (((uint32_t)(data[6])) << 24);
177 shift_data(shdata);
178 break;
179 }
180 case UTIL_COMM_SET_DAC_VALUE:
181 {
182 response[2] = UTIL_COMM_RESPONSE_OK;
183 uint16_t value = data[3] | (((uint16_t)data[4]) << 8);
184 dac_write_threshold(value);
185 break;
186 }
187 case UTIL_COMM_GET_ROW_STATE:
188 {
189 response[2] = UTIL_COMM_RESPONSE_OK;
190 response[3] = test_single(255, 0, NULL);
191 break;
192 }
193 default:
194 break;
195 }
196 raw_hid_send(response, sizeof(response));
197 }