logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

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