via_ec.c (16676B)
1 /* Copyright 2023 Cipulot 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 3 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 "ec_switch_matrix.h" 17 #include "action.h" 18 #include "print.h" 19 #include "via.h" 20 21 #ifdef SPLIT_KEYBOARD 22 # include "transactions.h" 23 #endif 24 25 #ifdef VIA_ENABLE 26 27 void ec_rescale_values(uint8_t item); 28 void ec_save_threshold_data(uint8_t option); 29 void ec_save_bottoming_reading(void); 30 void ec_show_calibration_data(void); 31 void ec_clear_bottoming_calibration_data(void); 32 33 // Declaring enums for VIA config menu 34 enum via_enums { 35 // clang-format off 36 id_actuation_mode = 1, 37 id_mode_0_actuation_threshold = 2, 38 id_mode_0_release_threshold = 3, 39 id_save_threshold_data = 4, 40 id_mode_1_initial_deadzone_offset = 5, 41 id_mode_1_actuation_offset = 6, 42 id_mode_1_release_offset = 7, 43 id_bottoming_calibration = 8, 44 id_noise_floor_calibration = 9, 45 id_show_calibration_data = 10, 46 id_clear_bottoming_calibration_data = 11 47 // clang-format on 48 }; 49 50 // Handle the data received by the keyboard from the VIA menus 51 void via_config_set_value(uint8_t *data) { 52 // data = [ value_id, value_data ] 53 uint8_t *value_id = &(data[0]); 54 uint8_t *value_data = &(data[1]); 55 56 # ifdef SPLIT_KEYBOARD 57 if (is_keyboard_master()) { 58 transaction_rpc_send(RPC_ID_VIA_CMD, 30, data); 59 } 60 # endif 61 62 switch (*value_id) { 63 case id_actuation_mode: { 64 eeprom_ec_config.actuation_mode = value_data[0]; 65 ec_config.actuation_mode = eeprom_ec_config.actuation_mode; 66 if (ec_config.actuation_mode == 0) { 67 uprintf("#########################\n"); 68 uprintf("# Actuation Mode: APC #\n"); 69 uprintf("#########################\n"); 70 } else if (ec_config.actuation_mode == 1) { 71 uprintf("#################################\n"); 72 uprintf("# Actuation Mode: Rapid Trigger #\n"); 73 uprintf("#################################\n"); 74 } 75 eeconfig_update_kb_datablock_field(eeprom_ec_config, actuation_mode); 76 break; 77 } 78 case id_mode_0_actuation_threshold: { 79 ec_config.mode_0_actuation_threshold = value_data[1] | (value_data[0] << 8); 80 uprintf("APC Mode Actuation Threshold: %d\n", ec_config.mode_0_actuation_threshold); 81 break; 82 } 83 case id_mode_0_release_threshold: { 84 ec_config.mode_0_release_threshold = value_data[1] | (value_data[0] << 8); 85 uprintf("APC Mode Release Threshold: %d\n", ec_config.mode_0_release_threshold); 86 break; 87 } 88 case id_mode_1_initial_deadzone_offset: { 89 ec_config.mode_1_initial_deadzone_offset = value_data[1] | (value_data[0] << 8); 90 uprintf("Rapid Trigger Mode Initial Deadzone Offset: %d\n", ec_config.mode_1_initial_deadzone_offset); 91 break; 92 } 93 case id_mode_1_actuation_offset: { 94 ec_config.mode_1_actuation_offset = value_data[0]; 95 uprintf("Rapid Trigger Mode Actuation Offset: %d\n", ec_config.mode_1_actuation_offset); 96 break; 97 } 98 case id_mode_1_release_offset: { 99 ec_config.mode_1_release_offset = value_data[0]; 100 uprintf("Rapid Trigger Mode Release Offset: %d\n", ec_config.mode_1_release_offset); 101 break; 102 } 103 case id_bottoming_calibration: { 104 if (value_data[0] == 1) { 105 ec_config.bottoming_calibration = true; 106 uprintf("##############################\n"); 107 uprintf("# Bottoming calibration mode #\n"); 108 uprintf("##############################\n"); 109 } else { 110 ec_config.bottoming_calibration = false; 111 ec_save_bottoming_reading(); 112 uprintf("## Bottoming calibration done ##\n"); 113 ec_show_calibration_data(); 114 } 115 break; 116 } 117 case id_save_threshold_data: { 118 ec_save_threshold_data(value_data[0]); 119 break; 120 } 121 case id_noise_floor_calibration: { 122 if (value_data[0] == 0) { 123 ec_noise_floor(); 124 ec_rescale_values(0); 125 ec_rescale_values(1); 126 ec_rescale_values(2); 127 ec_rescale_values(3); 128 ec_rescale_values(4); 129 uprintf("#############################\n"); 130 uprintf("# Noise floor data acquired #\n"); 131 uprintf("#############################\n"); 132 break; 133 } 134 } 135 case id_show_calibration_data: { 136 if (value_data[0] == 0) { 137 ec_show_calibration_data(); 138 } 139 break; 140 } 141 case id_clear_bottoming_calibration_data: { 142 if (value_data[0] == 0) { 143 ec_clear_bottoming_calibration_data(); 144 } 145 break; 146 } 147 default: { 148 // Unhandled value. 149 break; 150 } 151 } 152 } 153 154 // Handle the data sent by the keyboard to the VIA menus 155 void via_config_get_value(uint8_t *data) { 156 // data = [ value_id, value_data ] 157 uint8_t *value_id = &(data[0]); 158 uint8_t *value_data = &(data[1]); 159 160 switch (*value_id) { 161 case id_actuation_mode: { 162 value_data[0] = eeprom_ec_config.actuation_mode; 163 break; 164 } 165 case id_mode_0_actuation_threshold: { 166 value_data[0] = eeprom_ec_config.mode_0_actuation_threshold >> 8; 167 value_data[1] = eeprom_ec_config.mode_0_actuation_threshold & 0xFF; 168 break; 169 } 170 case id_mode_0_release_threshold: { 171 value_data[0] = eeprom_ec_config.mode_0_release_threshold >> 8; 172 value_data[1] = eeprom_ec_config.mode_0_release_threshold & 0xFF; 173 break; 174 } 175 case id_mode_1_initial_deadzone_offset: { 176 value_data[0] = eeprom_ec_config.mode_1_initial_deadzone_offset >> 8; 177 value_data[1] = eeprom_ec_config.mode_1_initial_deadzone_offset & 0xFF; 178 break; 179 } 180 case id_mode_1_actuation_offset: { 181 value_data[0] = eeprom_ec_config.mode_1_actuation_offset; 182 break; 183 } 184 case id_mode_1_release_offset: { 185 value_data[0] = eeprom_ec_config.mode_1_release_offset; 186 break; 187 } 188 default: { 189 // Unhandled value. 190 break; 191 } 192 } 193 } 194 195 // Handle the commands sent and received by the keyboard with VIA 196 void via_custom_value_command_kb(uint8_t *data, uint8_t length) { 197 // data = [ command_id, channel_id, value_id, value_data ] 198 uint8_t *command_id = &(data[0]); 199 uint8_t *channel_id = &(data[1]); 200 uint8_t *value_id_and_data = &(data[2]); 201 202 if (*channel_id == id_custom_channel) { 203 switch (*command_id) { 204 case id_custom_set_value: { 205 via_config_set_value(value_id_and_data); 206 break; 207 } 208 case id_custom_get_value: { 209 via_config_get_value(value_id_and_data); 210 break; 211 } 212 case id_custom_save: { 213 // Bypass the save function in favor of pinpointed saves 214 break; 215 } 216 default: { 217 // Unhandled message. 218 *command_id = id_unhandled; 219 break; 220 } 221 } 222 return; 223 } 224 225 *command_id = id_unhandled; 226 } 227 228 // Rescale the values received by VIA to fit the new range 229 void ec_rescale_values(uint8_t item) { 230 switch (item) { 231 // Rescale the APC mode actuation thresholds 232 case 0: 233 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 234 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 235 ec_config.rescaled_mode_0_actuation_threshold[row][col] = rescale(ec_config.mode_0_actuation_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]); 236 } 237 } 238 break; 239 // Rescale the APC mode release thresholds 240 case 1: 241 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 242 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 243 ec_config.rescaled_mode_0_release_threshold[row][col] = rescale(ec_config.mode_0_release_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]); 244 } 245 } 246 break; 247 // Rescale the Rapid Trigger mode initial deadzone offsets 248 case 2: 249 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 250 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 251 ec_config.rescaled_mode_1_initial_deadzone_offset[row][col] = rescale(ec_config.mode_1_initial_deadzone_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]); 252 } 253 } 254 break; 255 // Rescale the Rapid Trigger mode actuation offsets 256 case 3: 257 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 258 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 259 ec_config.rescaled_mode_1_actuation_offset[row][col] = rescale(ec_config.mode_1_actuation_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]); 260 } 261 } 262 break; 263 // Rescale the Rapid Trigger mode release offsets 264 case 4: 265 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 266 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 267 ec_config.rescaled_mode_1_release_offset[row][col] = rescale(ec_config.mode_1_release_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]); 268 } 269 } 270 break; 271 272 default: 273 // Unhandled item. 274 break; 275 } 276 } 277 278 void ec_save_threshold_data(uint8_t option) { 279 // Save APC mode thresholds and rescale them for runtime usage 280 if (option == 0) { 281 eeprom_ec_config.mode_0_actuation_threshold = ec_config.mode_0_actuation_threshold; 282 eeprom_ec_config.mode_0_release_threshold = ec_config.mode_0_release_threshold; 283 ec_rescale_values(0); 284 ec_rescale_values(1); 285 } 286 // Save Rapid Trigger mode thresholds and rescale them for runtime usage 287 else if (option == 1) { 288 eeprom_ec_config.mode_1_initial_deadzone_offset = ec_config.mode_1_initial_deadzone_offset; 289 eeprom_ec_config.mode_1_actuation_offset = ec_config.mode_1_actuation_offset; 290 eeprom_ec_config.mode_1_release_offset = ec_config.mode_1_release_offset; 291 ec_rescale_values(2); 292 ec_rescale_values(3); 293 ec_rescale_values(4); 294 } 295 eeconfig_update_kb_datablock(&eeprom_ec_config, 0, EECONFIG_KB_DATA_SIZE); 296 uprintf("####################################\n"); 297 uprintf("# New thresholds applied and saved #\n"); 298 uprintf("####################################\n"); 299 } 300 301 // Save the bottoming reading 302 void ec_save_bottoming_reading(void) { 303 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 304 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 305 // If the calibration starter flag is still set on the key, it indicates that the key was skipped during the scan because it is not physically present. 306 // If the flag is not set, it means a bottoming reading was taken. If this reading doesn't exceed the noise floor by the BOTTOMING_CALIBRATION_THRESHOLD, it likely indicates one of the following: 307 // 1. The key is part of an alternative layout and is not being pressed. 308 // 2. The key is in the current layout but is not being pressed. 309 // In both conditions we should set the bottoming reading to the maximum value to avoid false positives. 310 if (ec_config.bottoming_calibration_starter[row][col] || ec_config.bottoming_reading[row][col] < (ec_config.noise_floor[row][col] + BOTTOMING_CALIBRATION_THRESHOLD)) { 311 eeprom_ec_config.bottoming_reading[row][col] = 1023; 312 } else { 313 eeprom_ec_config.bottoming_reading[row][col] = ec_config.bottoming_reading[row][col]; 314 } 315 } 316 } 317 // Rescale the values to fit the new range for runtime usage 318 ec_rescale_values(0); 319 ec_rescale_values(1); 320 ec_rescale_values(2); 321 ec_rescale_values(3); 322 ec_rescale_values(4); 323 eeconfig_update_kb_datablock(&eeprom_ec_config, 0, EECONFIG_KB_DATA_SIZE); 324 } 325 326 // Show the calibration data 327 void ec_show_calibration_data(void) { 328 uprintf("\n###############\n"); 329 uprintf("# Noise Floor #\n"); 330 uprintf("###############\n"); 331 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 332 for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) { 333 uprintf("%4d,", ec_config.noise_floor[row][col]); 334 } 335 uprintf("%4d\n", ec_config.noise_floor[row][MATRIX_COLS - 1]); 336 } 337 338 uprintf("\n######################\n"); 339 uprintf("# Bottoming Readings #\n"); 340 uprintf("######################\n"); 341 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 342 for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) { 343 uprintf("%4d,", eeprom_ec_config.bottoming_reading[row][col]); 344 } 345 uprintf("%4d\n", eeprom_ec_config.bottoming_reading[row][MATRIX_COLS - 1]); 346 } 347 348 uprintf("\n######################################\n"); 349 uprintf("# Rescaled APC Mode Actuation Points #\n"); 350 uprintf("######################################\n"); 351 uprintf("Original APC Mode Actuation Point: %4d\n", ec_config.mode_0_actuation_threshold); 352 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 353 for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) { 354 uprintf("%4d,", ec_config.rescaled_mode_0_actuation_threshold[row][col]); 355 } 356 uprintf("%4d\n", ec_config.rescaled_mode_0_actuation_threshold[row][MATRIX_COLS - 1]); 357 } 358 359 uprintf("\n######################################\n"); 360 uprintf("# Rescaled APC Mode Release Points #\n"); 361 uprintf("######################################\n"); 362 uprintf("Original APC Mode Release Point: %4d\n", ec_config.mode_0_release_threshold); 363 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 364 for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) { 365 uprintf("%4d,", ec_config.rescaled_mode_0_release_threshold[row][col]); 366 } 367 uprintf("%4d\n", ec_config.rescaled_mode_0_release_threshold[row][MATRIX_COLS - 1]); 368 } 369 370 uprintf("\n#######################################################\n"); 371 uprintf("# Rescaled Rapid Trigger Mode Initial Deadzone Offset #\n"); 372 uprintf("#######################################################\n"); 373 uprintf("Original Rapid Trigger Mode Initial Deadzone Offset: %4d\n", ec_config.mode_1_initial_deadzone_offset); 374 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 375 for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) { 376 uprintf("%4d,", ec_config.rescaled_mode_1_initial_deadzone_offset[row][col]); 377 } 378 uprintf("%4d\n", ec_config.rescaled_mode_1_initial_deadzone_offset[row][MATRIX_COLS - 1]); 379 } 380 print("\n"); 381 } 382 383 // Clear the calibration data 384 void ec_clear_bottoming_calibration_data(void) { 385 // Clear the EEPROM data 386 eeconfig_init_kb(); 387 388 // Reset the runtime values to the EEPROM values 389 keyboard_post_init_kb(); 390 391 uprintf("######################################\n"); 392 uprintf("# Bottoming calibration data cleared #\n"); 393 uprintf("######################################\n"); 394 } 395 396 # ifdef SPLIT_KEYBOARD 397 void via_cmd_slave_handler(uint8_t m2s_size, const void *m2s_buffer, uint8_t s2m_size, void *s2m_buffer) { 398 if (m2s_size == (RAW_EPSIZE-2)) { 399 via_config_set_value((uint8_t *)m2s_buffer); 400 } else { 401 uprintf("Unexpected response in slave handler\n"); 402 } 403 } 404 # endif 405 406 #endif // VIA_ENABLE