via_ec.c 14 KB

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