You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

502 lines
20 KiB

  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 "keyboards/cipulot/common/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_num_indicator_enabled = 1,
  31. id_num_indicator_brightness = 2,
  32. id_num_indicator_color = 3,
  33. id_caps_indicator_enabled = 4,
  34. id_caps_indicator_brightness = 5,
  35. id_caps_indicator_color = 6,
  36. id_scroll_indicator_enabled = 7,
  37. id_scroll_indicator_brightness = 8,
  38. id_scroll_indicator_color = 9,
  39. id_actuation_mode = 10,
  40. id_mode_0_actuation_threshold = 11,
  41. id_mode_0_release_threshold = 12,
  42. id_save_threshold_data = 13,
  43. id_mode_1_initial_deadzone_offset = 14,
  44. id_mode_1_actuation_offset = 15,
  45. id_mode_1_release_offset = 16,
  46. id_bottoming_calibration = 17,
  47. id_noise_floor_calibration = 18,
  48. id_show_calibration_data = 19,
  49. id_clear_bottoming_calibration_data = 20
  50. // clang-format on
  51. };
  52. // Handle the data received by the keyboard from the VIA menus
  53. void via_config_set_value(uint8_t *data) {
  54. // data = [ value_id, value_data ]
  55. uint8_t *value_id = &(data[0]);
  56. uint8_t *value_data = &(data[1]);
  57. switch (*value_id) {
  58. case id_num_indicator_enabled: {
  59. if (value_data[0] == 1) {
  60. eeprom_ec_config.num.enabled = true;
  61. uprintf("#########################\n");
  62. uprintf("# Num indicator enabled #\n");
  63. uprintf("#########################\n");
  64. } else {
  65. eeprom_ec_config.num.enabled = false;
  66. uprintf("##########################\n");
  67. uprintf("# Num indicator disabled #\n");
  68. uprintf("##########################\n");
  69. }
  70. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, num.enabled);
  71. break;
  72. }
  73. case id_num_indicator_brightness: {
  74. eeprom_ec_config.num.v = value_data[0];
  75. uprintf("Num indicator brightness: %d\n", eeprom_ec_config.num.v);
  76. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, num.v);
  77. break;
  78. }
  79. case id_num_indicator_color: {
  80. eeprom_ec_config.num.h = value_data[0];
  81. eeprom_ec_config.num.s = value_data[1];
  82. uprintf("Num indicator color: %d, %d\n", eeprom_ec_config.num.h, eeprom_ec_config.num.s);
  83. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, num.h);
  84. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, num.s);
  85. break;
  86. }
  87. case id_caps_indicator_enabled: {
  88. if (value_data[0] == 1) {
  89. eeprom_ec_config.caps.enabled = true;
  90. uprintf("##########################\n");
  91. uprintf("# Caps indicator enabled #\n");
  92. uprintf("##########################\n");
  93. } else {
  94. eeprom_ec_config.caps.enabled = false;
  95. uprintf("###########################\n");
  96. uprintf("# Caps indicator disabled #\n");
  97. uprintf("###########################\n");
  98. }
  99. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, caps.enabled);
  100. break;
  101. }
  102. case id_caps_indicator_brightness: {
  103. eeprom_ec_config.caps.v = value_data[0];
  104. uprintf("Caps indicator brightness: %d\n", eeprom_ec_config.caps.v);
  105. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, caps.v);
  106. break;
  107. }
  108. case id_caps_indicator_color: {
  109. eeprom_ec_config.caps.h = value_data[0];
  110. eeprom_ec_config.caps.s = value_data[1];
  111. uprintf("Caps indicator color: %d, %d\n", eeprom_ec_config.caps.h, eeprom_ec_config.caps.s);
  112. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, caps.h);
  113. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, caps.s);
  114. break;
  115. }
  116. case id_scroll_indicator_enabled: {
  117. if (value_data[0] == 1) {
  118. eeprom_ec_config.scroll.enabled = true;
  119. uprintf("############################\n");
  120. uprintf("# Scroll indicator enabled #\n");
  121. uprintf("############################\n");
  122. } else {
  123. eeprom_ec_config.scroll.enabled = false;
  124. uprintf("#############################\n");
  125. uprintf("# Scroll indicator disabled #\n");
  126. uprintf("#############################\n");
  127. }
  128. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, scroll.enabled);
  129. break;
  130. }
  131. case id_scroll_indicator_brightness: {
  132. eeprom_ec_config.scroll.v = value_data[0];
  133. uprintf("Scroll indicator brightness: %d\n", eeprom_ec_config.scroll.v);
  134. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, scroll.v);
  135. break;
  136. }
  137. case id_scroll_indicator_color: {
  138. eeprom_ec_config.scroll.h = value_data[0];
  139. eeprom_ec_config.scroll.s = value_data[1];
  140. uprintf("Scroll indicator color: %d, %d\n", eeprom_ec_config.scroll.h, eeprom_ec_config.scroll.s);
  141. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, scroll.h);
  142. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, scroll.s);
  143. break;
  144. }
  145. case id_actuation_mode: {
  146. eeprom_ec_config.actuation_mode = value_data[0];
  147. ec_config.actuation_mode = eeprom_ec_config.actuation_mode;
  148. if (ec_config.actuation_mode == 0) {
  149. uprintf("#########################\n");
  150. uprintf("# Actuation Mode: APC #\n");
  151. uprintf("#########################\n");
  152. } else if (ec_config.actuation_mode == 1) {
  153. uprintf("#################################\n");
  154. uprintf("# Actuation Mode: Rapid Trigger #\n");
  155. uprintf("#################################\n");
  156. }
  157. EEPROM_KB_PARTIAL_UPDATE(eeprom_ec_config, actuation_mode);
  158. break;
  159. }
  160. case id_mode_0_actuation_threshold: {
  161. ec_config.mode_0_actuation_threshold = value_data[1] | (value_data[0] << 8);
  162. uprintf("APC Mode Actuation Threshold: %d\n", ec_config.mode_0_actuation_threshold);
  163. break;
  164. }
  165. case id_mode_0_release_threshold: {
  166. eeprom_ec_config.mode_0_release_threshold = value_data[1] | (value_data[0] << 8);
  167. ec_config.mode_0_release_threshold = eeprom_ec_config.mode_0_release_threshold;
  168. uprintf("APC Mode Release Threshold: %d\n", ec_config.mode_0_release_threshold);
  169. break;
  170. }
  171. case id_mode_1_initial_deadzone_offset: {
  172. ec_config.mode_1_initial_deadzone_offset = value_data[1] | (value_data[0] << 8);
  173. uprintf("Rapid Trigger Mode Initial Deadzone Offset: %d\n", ec_config.mode_1_initial_deadzone_offset);
  174. break;
  175. }
  176. case id_mode_1_actuation_offset: {
  177. ec_config.mode_1_actuation_offset = value_data[0];
  178. uprintf("Rapid Trigger Mode Actuation Sensitivity: %d\n", ec_config.mode_1_actuation_offset);
  179. break;
  180. }
  181. case id_mode_1_release_offset: {
  182. ec_config.mode_1_release_offset = value_data[0];
  183. uprintf("Rapid Trigger Mode Release Sensitivity: %d\n", ec_config.mode_1_release_offset);
  184. break;
  185. }
  186. case id_bottoming_calibration: {
  187. if (value_data[0] == 1) {
  188. ec_config.bottoming_calibration = true;
  189. uprintf("##############################\n");
  190. uprintf("# Bottoming calibration mode #\n");
  191. uprintf("##############################\n");
  192. } else {
  193. ec_config.bottoming_calibration = false;
  194. ec_save_bottoming_reading();
  195. uprintf("## Bottoming calibration done ##\n");
  196. ec_show_calibration_data();
  197. }
  198. break;
  199. }
  200. case id_save_threshold_data: {
  201. ec_save_threshold_data(value_data[0]);
  202. break;
  203. }
  204. case id_noise_floor_calibration: {
  205. if (value_data[0] == 0) {
  206. ec_noise_floor();
  207. ec_rescale_values(0);
  208. ec_rescale_values(1);
  209. ec_rescale_values(2);
  210. uprintf("#############################\n");
  211. uprintf("# Noise floor data acquired #\n");
  212. uprintf("#############################\n");
  213. break;
  214. }
  215. }
  216. case id_show_calibration_data: {
  217. // Show calibration data once if the user toggle the switch
  218. if (value_data[0] == 0) {
  219. ec_show_calibration_data();
  220. break;
  221. }
  222. }
  223. case id_clear_bottoming_calibration_data: {
  224. if (value_data[0] == 0) {
  225. ec_clear_bottoming_calibration_data();
  226. }
  227. }
  228. default: {
  229. // Unhandled value.
  230. break;
  231. }
  232. }
  233. // Call the indicator callback to set the indicator color
  234. indicators_callback();
  235. }
  236. // Handle the data sent by the keyboard to the VIA menus
  237. void via_config_get_value(uint8_t *data) {
  238. // data = [ value_id, value_data ]
  239. uint8_t *value_id = &(data[0]);
  240. uint8_t *value_data = &(data[1]);
  241. switch (*value_id) {
  242. case id_num_indicator_enabled: {
  243. value_data[0] = eeprom_ec_config.num.enabled;
  244. break;
  245. }
  246. case id_num_indicator_brightness: {
  247. value_data[0] = eeprom_ec_config.num.v;
  248. break;
  249. }
  250. case id_num_indicator_color: {
  251. value_data[0] = eeprom_ec_config.num.h;
  252. value_data[1] = eeprom_ec_config.num.s;
  253. break;
  254. }
  255. case id_caps_indicator_enabled: {
  256. value_data[0] = eeprom_ec_config.caps.enabled;
  257. break;
  258. }
  259. case id_caps_indicator_brightness: {
  260. value_data[0] = eeprom_ec_config.caps.v;
  261. break;
  262. }
  263. case id_caps_indicator_color: {
  264. value_data[0] = eeprom_ec_config.caps.h;
  265. value_data[1] = eeprom_ec_config.caps.s;
  266. break;
  267. }
  268. case id_scroll_indicator_enabled: {
  269. value_data[0] = eeprom_ec_config.scroll.enabled;
  270. break;
  271. }
  272. case id_scroll_indicator_brightness: {
  273. value_data[0] = eeprom_ec_config.scroll.v;
  274. break;
  275. }
  276. case id_scroll_indicator_color: {
  277. value_data[0] = eeprom_ec_config.scroll.h;
  278. value_data[1] = eeprom_ec_config.scroll.s;
  279. break;
  280. }
  281. case id_actuation_mode: {
  282. value_data[0] = eeprom_ec_config.actuation_mode;
  283. break;
  284. }
  285. case id_mode_0_actuation_threshold: {
  286. value_data[0] = eeprom_ec_config.mode_0_actuation_threshold >> 8;
  287. value_data[1] = eeprom_ec_config.mode_0_actuation_threshold & 0xFF;
  288. break;
  289. }
  290. case id_mode_0_release_threshold: {
  291. value_data[0] = eeprom_ec_config.mode_0_release_threshold >> 8;
  292. value_data[1] = eeprom_ec_config.mode_0_release_threshold & 0xFF;
  293. break;
  294. }
  295. case id_mode_1_initial_deadzone_offset: {
  296. value_data[0] = eeprom_ec_config.mode_1_initial_deadzone_offset >> 8;
  297. value_data[1] = eeprom_ec_config.mode_1_initial_deadzone_offset & 0xFF;
  298. break;
  299. }
  300. case id_mode_1_actuation_offset: {
  301. value_data[0] = eeprom_ec_config.mode_1_actuation_offset;
  302. break;
  303. }
  304. case id_mode_1_release_offset: {
  305. value_data[0] = eeprom_ec_config.mode_1_release_offset;
  306. break;
  307. }
  308. default: {
  309. // Unhandled value.
  310. break;
  311. }
  312. }
  313. }
  314. // Handle the commands sent and received by the keyboard with VIA
  315. void via_custom_value_command_kb(uint8_t *data, uint8_t length) {
  316. // data = [ command_id, channel_id, value_id, value_data ]
  317. uint8_t *command_id = &(data[0]);
  318. uint8_t *channel_id = &(data[1]);
  319. uint8_t *value_id_and_data = &(data[2]);
  320. if (*channel_id == id_custom_channel) {
  321. switch (*command_id) {
  322. case id_custom_set_value: {
  323. via_config_set_value(value_id_and_data);
  324. break;
  325. }
  326. case id_custom_get_value: {
  327. via_config_get_value(value_id_and_data);
  328. break;
  329. }
  330. case id_custom_save: {
  331. // Bypass the save function in favor of pinpointed saves
  332. break;
  333. }
  334. default: {
  335. // Unhandled message.
  336. *command_id = id_unhandled;
  337. break;
  338. }
  339. }
  340. return;
  341. }
  342. *command_id = id_unhandled;
  343. }
  344. // Rescale the values received by VIA to fit the new range
  345. void ec_rescale_values(uint8_t item) {
  346. switch (item) {
  347. // Rescale the APC mode actuation thresholds
  348. case 0:
  349. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  350. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  351. 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]);
  352. }
  353. }
  354. break;
  355. // Rescale the APC mode release thresholds
  356. case 1:
  357. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  358. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  359. 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]);
  360. }
  361. }
  362. break;
  363. // Rescale the Rapid Trigger mode initial deadzone offsets
  364. case 2:
  365. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  366. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  367. 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]);
  368. }
  369. }
  370. break;
  371. default:
  372. // Unhandled item.
  373. break;
  374. }
  375. }
  376. void ec_save_threshold_data(uint8_t option) {
  377. // Save APC mode thresholds and rescale them for runtime usage
  378. if (option == 0) {
  379. eeprom_ec_config.mode_0_actuation_threshold = ec_config.mode_0_actuation_threshold;
  380. eeprom_ec_config.mode_0_release_threshold = ec_config.mode_0_release_threshold;
  381. ec_rescale_values(0);
  382. ec_rescale_values(1);
  383. }
  384. // Save Rapid Trigger mode thresholds and rescale them for runtime usage
  385. else if (option == 1) {
  386. eeprom_ec_config.mode_1_initial_deadzone_offset = ec_config.mode_1_initial_deadzone_offset;
  387. ec_rescale_values(2);
  388. }
  389. eeconfig_update_kb_datablock(&eeprom_ec_config);
  390. uprintf("####################################\n");
  391. uprintf("# New thresholds applied and saved #\n");
  392. uprintf("####################################\n");
  393. }
  394. // Save the bottoming reading
  395. void ec_save_bottoming_reading(void) {
  396. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  397. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  398. // If the bottom reading doesn't go over the noise floor by 100, it is likely that:
  399. // 1. The key is not actually in the matrix
  400. // 2. The key is on an alternative layout, therefore not being pressed
  401. // 3. The key in in the current layout but not being pressed
  402. if (ec_config.bottoming_reading[row][col] < (ec_config.noise_floor[row][col] + 100)) {
  403. eeprom_ec_config.bottoming_reading[row][col] = 1023;
  404. } else {
  405. eeprom_ec_config.bottoming_reading[row][col] = ec_config.bottoming_reading[row][col];
  406. }
  407. }
  408. }
  409. // Rescale the values to fit the new range for runtime usage
  410. ec_rescale_values(0);
  411. ec_rescale_values(1);
  412. ec_rescale_values(2);
  413. eeconfig_update_kb_datablock(&eeprom_ec_config);
  414. }
  415. // Show the calibration data
  416. void ec_show_calibration_data(void) {
  417. uprintf("\n###############\n");
  418. uprintf("# Noise Floor #\n");
  419. uprintf("###############\n");
  420. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  421. for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
  422. uprintf("%4d,", ec_config.noise_floor[row][col]);
  423. }
  424. uprintf("%4d\n", ec_config.noise_floor[row][MATRIX_COLS - 1]);
  425. }
  426. uprintf("\n######################\n");
  427. uprintf("# Bottoming Readings #\n");
  428. uprintf("######################\n");
  429. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  430. for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
  431. uprintf("%4d,", eeprom_ec_config.bottoming_reading[row][col]);
  432. }
  433. uprintf("%4d\n", eeprom_ec_config.bottoming_reading[row][MATRIX_COLS - 1]);
  434. }
  435. uprintf("\n######################################\n");
  436. uprintf("# Rescaled APC Mode Actuation Points #\n");
  437. uprintf("######################################\n");
  438. uprintf("Original APC Mode Actuation Point: %4d\n", ec_config.mode_0_actuation_threshold);
  439. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  440. for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
  441. uprintf("%4d,", ec_config.rescaled_mode_0_actuation_threshold[row][col]);
  442. }
  443. uprintf("%4d\n", ec_config.rescaled_mode_0_actuation_threshold[row][MATRIX_COLS - 1]);
  444. }
  445. uprintf("\n######################################\n");
  446. uprintf("# Rescaled APC Mode Release Points #\n");
  447. uprintf("######################################\n");
  448. uprintf("Original APC Mode Release Point: %4d\n", ec_config.mode_0_release_threshold);
  449. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  450. for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
  451. uprintf("%4d,", ec_config.rescaled_mode_0_release_threshold[row][col]);
  452. }
  453. uprintf("%4d\n", ec_config.rescaled_mode_0_release_threshold[row][MATRIX_COLS - 1]);
  454. }
  455. uprintf("\n#######################################################\n");
  456. uprintf("# Rescaled Rapid Trigger Mode Initial Deadzone Offset #\n");
  457. uprintf("#######################################################\n");
  458. uprintf("Original Rapid Trigger Mode Initial Deadzone Offset: %4d\n", ec_config.mode_1_initial_deadzone_offset);
  459. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  460. for (uint8_t col = 0; col < MATRIX_COLS - 1; col++) {
  461. uprintf("%4d,", ec_config.rescaled_mode_1_initial_deadzone_offset[row][col]);
  462. }
  463. uprintf("%4d\n", ec_config.rescaled_mode_1_initial_deadzone_offset[row][MATRIX_COLS - 1]);
  464. }
  465. print("\n");
  466. }
  467. // Clear the calibration data
  468. void ec_clear_bottoming_calibration_data(void) {
  469. // Clear the EEPROM data
  470. eeconfig_init_kb();
  471. // Reset the runtime values to the EEPROM values
  472. keyboard_post_init_kb();
  473. uprintf("######################################\n");
  474. uprintf("# Bottoming calibration data cleared #\n");
  475. uprintf("######################################\n");
  476. }
  477. #endif // VIA_ENABLE