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.

760 lines
25 KiB

  1. /* Copyright 2019 Jason Williams (Wilba)
  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. #ifndef RAW_ENABLE
  17. # error "RAW_ENABLE is not enabled"
  18. #endif
  19. #ifndef DYNAMIC_KEYMAP_ENABLE
  20. # error "DYNAMIC_KEYMAP_ENABLE is not enabled"
  21. #endif
  22. #include "quantum.h"
  23. #include "via.h"
  24. #include "raw_hid.h"
  25. #include "dynamic_keymap.h"
  26. #include "eeprom.h"
  27. #include "version.h" // for QMK_BUILDDATE used in EEPROM magic
  28. #if defined(RGB_MATRIX_ENABLE)
  29. # include <lib/lib8tion/lib8tion.h>
  30. #endif
  31. // Can be called in an overriding via_init_kb() to test if keyboard level code usage of
  32. // EEPROM is invalid and use/save defaults.
  33. bool via_eeprom_is_valid(void) {
  34. char * p = QMK_BUILDDATE; // e.g. "2019-11-05-11:29:54"
  35. uint8_t magic0 = ((p[2] & 0x0F) << 4) | (p[3] & 0x0F);
  36. uint8_t magic1 = ((p[5] & 0x0F) << 4) | (p[6] & 0x0F);
  37. uint8_t magic2 = ((p[8] & 0x0F) << 4) | (p[9] & 0x0F);
  38. return (eeprom_read_byte((void *)VIA_EEPROM_MAGIC_ADDR + 0) == magic0 && eeprom_read_byte((void *)VIA_EEPROM_MAGIC_ADDR + 1) == magic1 && eeprom_read_byte((void *)VIA_EEPROM_MAGIC_ADDR + 2) == magic2);
  39. }
  40. // Sets VIA/keyboard level usage of EEPROM to valid/invalid
  41. // Keyboard level code (eg. via_init_kb()) should not call this
  42. void via_eeprom_set_valid(bool valid) {
  43. char * p = QMK_BUILDDATE; // e.g. "2019-11-05-11:29:54"
  44. uint8_t magic0 = ((p[2] & 0x0F) << 4) | (p[3] & 0x0F);
  45. uint8_t magic1 = ((p[5] & 0x0F) << 4) | (p[6] & 0x0F);
  46. uint8_t magic2 = ((p[8] & 0x0F) << 4) | (p[9] & 0x0F);
  47. eeprom_update_byte((void *)VIA_EEPROM_MAGIC_ADDR + 0, valid ? magic0 : 0xFF);
  48. eeprom_update_byte((void *)VIA_EEPROM_MAGIC_ADDR + 1, valid ? magic1 : 0xFF);
  49. eeprom_update_byte((void *)VIA_EEPROM_MAGIC_ADDR + 2, valid ? magic2 : 0xFF);
  50. }
  51. // Override this at the keyboard code level to check
  52. // VIA's EEPROM valid state and reset to defaults as needed.
  53. // Used by keyboards that store their own state in EEPROM,
  54. // for backlight, rotary encoders, etc.
  55. // The override should not set via_eeprom_set_valid(true) as
  56. // the caller also needs to check the valid state.
  57. __attribute__((weak)) void via_init_kb(void) {}
  58. // Called by QMK core to initialize dynamic keymaps etc.
  59. void via_init(void) {
  60. // Let keyboard level test EEPROM valid state,
  61. // but not set it valid, it is done here.
  62. via_init_kb();
  63. via_set_layout_options_kb(via_get_layout_options());
  64. // If the EEPROM has the magic, the data is good.
  65. // OK to load from EEPROM.
  66. if (!via_eeprom_is_valid()) {
  67. eeconfig_init_via();
  68. }
  69. }
  70. void eeconfig_init_via(void) {
  71. // set the magic number to false, in case this gets interrupted
  72. via_eeprom_set_valid(false);
  73. // This resets the layout options
  74. via_set_layout_options(VIA_EEPROM_LAYOUT_OPTIONS_DEFAULT);
  75. // This resets the keymaps in EEPROM to what is in flash.
  76. dynamic_keymap_reset();
  77. // This resets the macros in EEPROM to nothing.
  78. dynamic_keymap_macro_reset();
  79. // Save the magic number last, in case saving was interrupted
  80. via_eeprom_set_valid(true);
  81. }
  82. // This is generalized so the layout options EEPROM usage can be
  83. // variable, between 1 and 4 bytes.
  84. uint32_t via_get_layout_options(void) {
  85. uint32_t value = 0;
  86. // Start at the most significant byte
  87. void *source = (void *)(VIA_EEPROM_LAYOUT_OPTIONS_ADDR);
  88. for (uint8_t i = 0; i < VIA_EEPROM_LAYOUT_OPTIONS_SIZE; i++) {
  89. value = value << 8;
  90. value |= eeprom_read_byte(source);
  91. source++;
  92. }
  93. return value;
  94. }
  95. __attribute__((weak)) void via_set_layout_options_kb(uint32_t value) {}
  96. void via_set_layout_options(uint32_t value) {
  97. via_set_layout_options_kb(value);
  98. // Start at the least significant byte
  99. void *target = (void *)(VIA_EEPROM_LAYOUT_OPTIONS_ADDR + VIA_EEPROM_LAYOUT_OPTIONS_SIZE - 1);
  100. for (uint8_t i = 0; i < VIA_EEPROM_LAYOUT_OPTIONS_SIZE; i++) {
  101. eeprom_update_byte(target, value & 0xFF);
  102. value = value >> 8;
  103. target--;
  104. }
  105. }
  106. #if defined(AUDIO_ENABLE)
  107. float via_device_indication_song[][2] = SONG(STARTUP_SOUND);
  108. #endif // AUDIO_ENABLE
  109. // Used by VIA to tell a device to flash LEDs (or do something else) when that
  110. // device becomes the active device being configured, on startup or switching
  111. // between devices. This function will be called six times, at 200ms interval,
  112. // with an incrementing value starting at zero. Since this function is called
  113. // an even number of times, it can call a toggle function and leave things in
  114. // the original state.
  115. __attribute__((weak)) void via_set_device_indication(uint8_t value) {
  116. #if defined(BACKLIGHT_ENABLE)
  117. backlight_toggle();
  118. #endif // BACKLIGHT_ENABLE
  119. #if defined(RGBLIGHT_ENABLE)
  120. rgblight_toggle_noeeprom();
  121. #endif // RGBLIGHT_ENABLE
  122. #if defined(RGB_MATRIX_ENABLE)
  123. rgb_matrix_toggle_noeeprom();
  124. #endif // RGB_MATRIX_ENABLE
  125. #if defined(AUDIO_ENABLE)
  126. if (value == 0) {
  127. wait_ms(10);
  128. PLAY_SONG(via_device_indication_song);
  129. }
  130. #endif // AUDIO_ENABLE
  131. }
  132. // Called by QMK core to process VIA-specific keycodes.
  133. bool process_record_via(uint16_t keycode, keyrecord_t *record) {
  134. // Handle macros
  135. if (record->event.pressed) {
  136. if (keycode >= QK_MACRO && keycode <= QK_MACRO_MAX) {
  137. uint8_t id = keycode - QK_MACRO;
  138. dynamic_keymap_macro_send(id);
  139. return false;
  140. }
  141. }
  142. return true;
  143. }
  144. //
  145. // via_custom_value_command() has the default handling of custom values for Core modules.
  146. // If a keyboard is using the default Core modules, it does not need to be overridden,
  147. // the VIA keyboard definition will have matching channel/IDs.
  148. //
  149. // If a keyboard has some extra custom values, then via_custom_value_command_kb() can be
  150. // overridden to handle the extra custom values, leaving via_custom_value_command() to
  151. // handle the custom values for Core modules.
  152. //
  153. // If a keyboard has custom values and code that are overlapping with Core modules,
  154. // then via_custom_value_command() can be overridden and call the same functions
  155. // as the default implementation, or do whatever else is required.
  156. //
  157. // DO NOT call raw_hid_send() in the override function.
  158. //
  159. // This is the default handler for "extra" custom values, i.e. keyboard-specific custom values
  160. // that are not handled by via_custom_value_command().
  161. __attribute__((weak)) void via_custom_value_command_kb(uint8_t *data, uint8_t length) {
  162. // data = [ command_id, channel_id, value_id, value_data ]
  163. uint8_t *command_id = &(data[0]);
  164. // Return the unhandled state
  165. *command_id = id_unhandled;
  166. }
  167. // This is the default handler for custom value commands.
  168. // It routes commands with channel IDs to command handlers as such:
  169. //
  170. // id_qmk_backlight_channel -> via_qmk_backlight_command()
  171. // id_qmk_rgblight_channel -> via_qmk_rgblight_command()
  172. // id_qmk_rgb_matrix_channel -> via_qmk_rgb_matrix_command()
  173. // id_qmk_audio_channel -> via_qmk_audio_command()
  174. //
  175. __attribute__((weak)) void via_custom_value_command(uint8_t *data, uint8_t length) {
  176. // data = [ command_id, channel_id, value_id, value_data ]
  177. uint8_t *channel_id = &(data[1]);
  178. #if defined(BACKLIGHT_ENABLE)
  179. if (*channel_id == id_qmk_backlight_channel) {
  180. via_qmk_backlight_command(data, length);
  181. return;
  182. }
  183. #endif // BACKLIGHT_ENABLE
  184. #if defined(RGBLIGHT_ENABLE)
  185. if (*channel_id == id_qmk_rgblight_channel) {
  186. via_qmk_rgblight_command(data, length);
  187. return;
  188. }
  189. #endif // RGBLIGHT_ENABLE
  190. #if defined(RGB_MATRIX_ENABLE)
  191. if (*channel_id == id_qmk_rgb_matrix_channel) {
  192. via_qmk_rgb_matrix_command(data, length);
  193. return;
  194. }
  195. #endif // RGBLIGHT_ENABLE
  196. #if defined(AUDIO_ENABLE)
  197. if (*channel_id == id_qmk_audio_channel) {
  198. via_qmk_audio_command(data, length);
  199. return;
  200. }
  201. #endif // AUDIO_ENABLE
  202. (void)channel_id; // force use of variable
  203. // If we haven't returned before here, then let the keyboard level code
  204. // handle this, if it is overridden, otherwise by default, this will
  205. // return the unhandled state.
  206. via_custom_value_command_kb(data, length);
  207. }
  208. // Keyboard level code can override this, but shouldn't need to.
  209. // Controlling custom features should be done by overriding
  210. // via_custom_value_command_kb() instead.
  211. __attribute__((weak)) bool via_command_kb(uint8_t *data, uint8_t length) {
  212. return false;
  213. }
  214. void raw_hid_receive(uint8_t *data, uint8_t length) {
  215. uint8_t *command_id = &(data[0]);
  216. uint8_t *command_data = &(data[1]);
  217. // If via_command_kb() returns true, the command was fully
  218. // handled, including calling raw_hid_send()
  219. if (via_command_kb(data, length)) {
  220. return;
  221. }
  222. switch (*command_id) {
  223. case id_get_protocol_version: {
  224. command_data[0] = VIA_PROTOCOL_VERSION >> 8;
  225. command_data[1] = VIA_PROTOCOL_VERSION & 0xFF;
  226. break;
  227. }
  228. case id_get_keyboard_value: {
  229. switch (command_data[0]) {
  230. case id_uptime: {
  231. uint32_t value = timer_read32();
  232. command_data[1] = (value >> 24) & 0xFF;
  233. command_data[2] = (value >> 16) & 0xFF;
  234. command_data[3] = (value >> 8) & 0xFF;
  235. command_data[4] = value & 0xFF;
  236. break;
  237. }
  238. case id_layout_options: {
  239. uint32_t value = via_get_layout_options();
  240. command_data[1] = (value >> 24) & 0xFF;
  241. command_data[2] = (value >> 16) & 0xFF;
  242. command_data[3] = (value >> 8) & 0xFF;
  243. command_data[4] = value & 0xFF;
  244. break;
  245. }
  246. case id_switch_matrix_state: {
  247. uint8_t offset = command_data[1];
  248. uint8_t rows = 28 / ((MATRIX_COLS + 7) / 8);
  249. uint8_t i = 2;
  250. for (uint8_t row = 0; row < rows && row + offset < MATRIX_ROWS; row++) {
  251. matrix_row_t value = matrix_get_row(row + offset);
  252. #if (MATRIX_COLS > 24)
  253. command_data[i++] = (value >> 24) & 0xFF;
  254. #endif
  255. #if (MATRIX_COLS > 16)
  256. command_data[i++] = (value >> 16) & 0xFF;
  257. #endif
  258. #if (MATRIX_COLS > 8)
  259. command_data[i++] = (value >> 8) & 0xFF;
  260. #endif
  261. command_data[i++] = value & 0xFF;
  262. }
  263. break;
  264. }
  265. case id_firmware_version: {
  266. uint32_t value = VIA_FIRMWARE_VERSION;
  267. command_data[1] = (value >> 24) & 0xFF;
  268. command_data[2] = (value >> 16) & 0xFF;
  269. command_data[3] = (value >> 8) & 0xFF;
  270. command_data[4] = value & 0xFF;
  271. break;
  272. }
  273. default: {
  274. // The value ID is not known
  275. // Return the unhandled state
  276. *command_id = id_unhandled;
  277. break;
  278. }
  279. }
  280. break;
  281. }
  282. case id_set_keyboard_value: {
  283. switch (command_data[0]) {
  284. case id_layout_options: {
  285. uint32_t value = ((uint32_t)command_data[1] << 24) | ((uint32_t)command_data[2] << 16) | ((uint32_t)command_data[3] << 8) | (uint32_t)command_data[4];
  286. via_set_layout_options(value);
  287. break;
  288. }
  289. case id_device_indication: {
  290. uint8_t value = command_data[1];
  291. via_set_device_indication(value);
  292. break;
  293. }
  294. default: {
  295. // The value ID is not known
  296. // Return the unhandled state
  297. *command_id = id_unhandled;
  298. break;
  299. }
  300. }
  301. break;
  302. }
  303. case id_dynamic_keymap_get_keycode: {
  304. uint16_t keycode = dynamic_keymap_get_keycode(command_data[0], command_data[1], command_data[2]);
  305. command_data[3] = keycode >> 8;
  306. command_data[4] = keycode & 0xFF;
  307. break;
  308. }
  309. case id_dynamic_keymap_set_keycode: {
  310. dynamic_keymap_set_keycode(command_data[0], command_data[1], command_data[2], (command_data[3] << 8) | command_data[4]);
  311. break;
  312. }
  313. case id_dynamic_keymap_reset: {
  314. dynamic_keymap_reset();
  315. break;
  316. }
  317. case id_custom_set_value:
  318. case id_custom_get_value:
  319. case id_custom_save: {
  320. via_custom_value_command(data, length);
  321. break;
  322. }
  323. #ifdef VIA_EEPROM_ALLOW_RESET
  324. case id_eeprom_reset: {
  325. via_eeprom_set_valid(false);
  326. eeconfig_init_via();
  327. break;
  328. }
  329. #endif
  330. case id_dynamic_keymap_macro_get_count: {
  331. command_data[0] = dynamic_keymap_macro_get_count();
  332. break;
  333. }
  334. case id_dynamic_keymap_macro_get_buffer_size: {
  335. uint16_t size = dynamic_keymap_macro_get_buffer_size();
  336. command_data[0] = size >> 8;
  337. command_data[1] = size & 0xFF;
  338. break;
  339. }
  340. case id_dynamic_keymap_macro_get_buffer: {
  341. uint16_t offset = (command_data[0] << 8) | command_data[1];
  342. uint16_t size = command_data[2]; // size <= 28
  343. dynamic_keymap_macro_get_buffer(offset, size, &command_data[3]);
  344. break;
  345. }
  346. case id_dynamic_keymap_macro_set_buffer: {
  347. uint16_t offset = (command_data[0] << 8) | command_data[1];
  348. uint16_t size = command_data[2]; // size <= 28
  349. dynamic_keymap_macro_set_buffer(offset, size, &command_data[3]);
  350. break;
  351. }
  352. case id_dynamic_keymap_macro_reset: {
  353. dynamic_keymap_macro_reset();
  354. break;
  355. }
  356. case id_dynamic_keymap_get_layer_count: {
  357. command_data[0] = dynamic_keymap_get_layer_count();
  358. break;
  359. }
  360. case id_dynamic_keymap_get_buffer: {
  361. uint16_t offset = (command_data[0] << 8) | command_data[1];
  362. uint16_t size = command_data[2]; // size <= 28
  363. dynamic_keymap_get_buffer(offset, size, &command_data[3]);
  364. break;
  365. }
  366. case id_dynamic_keymap_set_buffer: {
  367. uint16_t offset = (command_data[0] << 8) | command_data[1];
  368. uint16_t size = command_data[2]; // size <= 28
  369. dynamic_keymap_set_buffer(offset, size, &command_data[3]);
  370. break;
  371. }
  372. #ifdef ENCODER_MAP_ENABLE
  373. case id_dynamic_keymap_get_encoder: {
  374. uint16_t keycode = dynamic_keymap_get_encoder(command_data[0], command_data[1], command_data[2] != 0);
  375. command_data[3] = keycode >> 8;
  376. command_data[4] = keycode & 0xFF;
  377. break;
  378. }
  379. case id_dynamic_keymap_set_encoder: {
  380. dynamic_keymap_set_encoder(command_data[0], command_data[1], command_data[2] != 0, (command_data[3] << 8) | command_data[4]);
  381. break;
  382. }
  383. #endif
  384. default: {
  385. // The command ID is not known
  386. // Return the unhandled state
  387. *command_id = id_unhandled;
  388. break;
  389. }
  390. }
  391. // Return the same buffer, optionally with values changed
  392. // (i.e. returning state to the host, or the unhandled state).
  393. raw_hid_send(data, length);
  394. }
  395. #if defined(BACKLIGHT_ENABLE)
  396. void via_qmk_backlight_command(uint8_t *data, uint8_t length) {
  397. // data = [ command_id, channel_id, value_id, value_data ]
  398. uint8_t *command_id = &(data[0]);
  399. uint8_t *value_id_and_data = &(data[2]);
  400. switch (*command_id) {
  401. case id_custom_set_value: {
  402. via_qmk_backlight_set_value(value_id_and_data);
  403. break;
  404. }
  405. case id_custom_get_value: {
  406. via_qmk_backlight_get_value(value_id_and_data);
  407. break;
  408. }
  409. case id_custom_save: {
  410. via_qmk_backlight_save();
  411. break;
  412. }
  413. default: {
  414. *command_id = id_unhandled;
  415. break;
  416. }
  417. }
  418. }
  419. # if BACKLIGHT_LEVELS == 0
  420. # error BACKLIGHT_LEVELS == 0
  421. # endif
  422. void via_qmk_backlight_get_value(uint8_t *data) {
  423. // data = [ value_id, value_data ]
  424. uint8_t *value_id = &(data[0]);
  425. uint8_t *value_data = &(data[1]);
  426. switch (*value_id) {
  427. case id_qmk_backlight_brightness: {
  428. // level / BACKLIGHT_LEVELS * 255
  429. value_data[0] = ((uint16_t)get_backlight_level() * UINT8_MAX) / BACKLIGHT_LEVELS;
  430. break;
  431. }
  432. case id_qmk_backlight_effect: {
  433. # ifdef BACKLIGHT_BREATHING
  434. value_data[0] = is_backlight_breathing() ? 1 : 0;
  435. # else
  436. value_data[0] = 0;
  437. # endif
  438. break;
  439. }
  440. }
  441. }
  442. void via_qmk_backlight_set_value(uint8_t *data) {
  443. // data = [ value_id, value_data ]
  444. uint8_t *value_id = &(data[0]);
  445. uint8_t *value_data = &(data[1]);
  446. switch (*value_id) {
  447. case id_qmk_backlight_brightness: {
  448. // level / 255 * BACKLIGHT_LEVELS
  449. backlight_level_noeeprom(((uint16_t)value_data[0] * BACKLIGHT_LEVELS) / UINT8_MAX);
  450. break;
  451. }
  452. case id_qmk_backlight_effect: {
  453. # ifdef BACKLIGHT_BREATHING
  454. if (value_data[0] == 0) {
  455. backlight_disable_breathing();
  456. } else {
  457. backlight_enable_breathing();
  458. }
  459. # endif
  460. break;
  461. }
  462. }
  463. }
  464. void via_qmk_backlight_save(void) {
  465. eeconfig_update_backlight_current();
  466. }
  467. #endif // BACKLIGHT_ENABLE
  468. #if defined(RGBLIGHT_ENABLE)
  469. # ifndef RGBLIGHT_LIMIT_VAL
  470. # define RGBLIGHT_LIMIT_VAL 255
  471. # endif
  472. void via_qmk_rgblight_command(uint8_t *data, uint8_t length) {
  473. // data = [ command_id, channel_id, value_id, value_data ]
  474. uint8_t *command_id = &(data[0]);
  475. uint8_t *value_id_and_data = &(data[2]);
  476. switch (*command_id) {
  477. case id_custom_set_value: {
  478. via_qmk_rgblight_set_value(value_id_and_data);
  479. break;
  480. }
  481. case id_custom_get_value: {
  482. via_qmk_rgblight_get_value(value_id_and_data);
  483. break;
  484. }
  485. case id_custom_save: {
  486. via_qmk_rgblight_save();
  487. break;
  488. }
  489. default: {
  490. *command_id = id_unhandled;
  491. break;
  492. }
  493. }
  494. }
  495. void via_qmk_rgblight_get_value(uint8_t *data) {
  496. // data = [ value_id, value_data ]
  497. uint8_t *value_id = &(data[0]);
  498. uint8_t *value_data = &(data[1]);
  499. switch (*value_id) {
  500. case id_qmk_rgblight_brightness: {
  501. value_data[0] = ((uint16_t)rgblight_get_val() * UINT8_MAX) / RGBLIGHT_LIMIT_VAL;
  502. break;
  503. }
  504. case id_qmk_rgblight_effect: {
  505. value_data[0] = rgblight_is_enabled() ? rgblight_get_mode() : 0;
  506. break;
  507. }
  508. case id_qmk_rgblight_effect_speed: {
  509. value_data[0] = rgblight_get_speed();
  510. break;
  511. }
  512. case id_qmk_rgblight_color: {
  513. value_data[0] = rgblight_get_hue();
  514. value_data[1] = rgblight_get_sat();
  515. break;
  516. }
  517. }
  518. }
  519. void via_qmk_rgblight_set_value(uint8_t *data) {
  520. // data = [ value_id, value_data ]
  521. uint8_t *value_id = &(data[0]);
  522. uint8_t *value_data = &(data[1]);
  523. switch (*value_id) {
  524. case id_qmk_rgblight_brightness: {
  525. rgblight_sethsv_noeeprom(rgblight_get_hue(), rgblight_get_sat(), ((uint16_t)value_data[0] * RGBLIGHT_LIMIT_VAL) / UINT8_MAX);
  526. break;
  527. }
  528. case id_qmk_rgblight_effect: {
  529. if (value_data[0] == 0) {
  530. rgblight_disable_noeeprom();
  531. } else {
  532. rgblight_enable_noeeprom();
  533. rgblight_mode_noeeprom(value_data[0]);
  534. }
  535. break;
  536. }
  537. case id_qmk_rgblight_effect_speed: {
  538. rgblight_set_speed_noeeprom(value_data[0]);
  539. break;
  540. }
  541. case id_qmk_rgblight_color: {
  542. rgblight_sethsv_noeeprom(value_data[0], value_data[1], rgblight_get_val());
  543. break;
  544. }
  545. }
  546. }
  547. void via_qmk_rgblight_save(void) {
  548. eeconfig_update_rgblight_current();
  549. }
  550. #endif // QMK_RGBLIGHT_ENABLE
  551. #if defined(RGB_MATRIX_ENABLE)
  552. # if !defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) || RGB_MATRIX_MAXIMUM_BRIGHTNESS > UINT8_MAX
  553. # undef RGB_MATRIX_MAXIMUM_BRIGHTNESS
  554. # define RGB_MATRIX_MAXIMUM_BRIGHTNESS UINT8_MAX
  555. # endif
  556. void via_qmk_rgb_matrix_command(uint8_t *data, uint8_t length) {
  557. // data = [ command_id, channel_id, value_id, value_data ]
  558. uint8_t *command_id = &(data[0]);
  559. uint8_t *value_id_and_data = &(data[2]);
  560. switch (*command_id) {
  561. case id_custom_set_value: {
  562. via_qmk_rgb_matrix_set_value(value_id_and_data);
  563. break;
  564. }
  565. case id_custom_get_value: {
  566. via_qmk_rgb_matrix_get_value(value_id_and_data);
  567. break;
  568. }
  569. case id_custom_save: {
  570. via_qmk_rgb_matrix_save();
  571. break;
  572. }
  573. default: {
  574. *command_id = id_unhandled;
  575. break;
  576. }
  577. }
  578. }
  579. void via_qmk_rgb_matrix_get_value(uint8_t *data) {
  580. // data = [ value_id, value_data ]
  581. uint8_t *value_id = &(data[0]);
  582. uint8_t *value_data = &(data[1]);
  583. switch (*value_id) {
  584. case id_qmk_rgb_matrix_brightness: {
  585. value_data[0] = ((uint16_t)rgb_matrix_get_val() * UINT8_MAX) / RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  586. break;
  587. }
  588. case id_qmk_rgb_matrix_effect: {
  589. value_data[0] = rgb_matrix_is_enabled() ? rgb_matrix_get_mode() : 0;
  590. break;
  591. }
  592. case id_qmk_rgb_matrix_effect_speed: {
  593. value_data[0] = rgb_matrix_get_speed();
  594. break;
  595. }
  596. case id_qmk_rgb_matrix_color: {
  597. value_data[0] = rgb_matrix_get_hue();
  598. value_data[1] = rgb_matrix_get_sat();
  599. break;
  600. }
  601. }
  602. }
  603. void via_qmk_rgb_matrix_set_value(uint8_t *data) {
  604. // data = [ value_id, value_data ]
  605. uint8_t *value_id = &(data[0]);
  606. uint8_t *value_data = &(data[1]);
  607. switch (*value_id) {
  608. case id_qmk_rgb_matrix_brightness: {
  609. rgb_matrix_sethsv_noeeprom(rgb_matrix_get_hue(), rgb_matrix_get_sat(), scale8(value_data[0], RGB_MATRIX_MAXIMUM_BRIGHTNESS));
  610. break;
  611. }
  612. case id_qmk_rgb_matrix_effect: {
  613. if (value_data[0] == 0) {
  614. rgb_matrix_disable_noeeprom();
  615. } else {
  616. rgb_matrix_enable_noeeprom();
  617. rgb_matrix_mode_noeeprom(value_data[0]);
  618. }
  619. break;
  620. }
  621. case id_qmk_rgb_matrix_effect_speed: {
  622. rgb_matrix_set_speed_noeeprom(value_data[0]);
  623. break;
  624. }
  625. case id_qmk_rgb_matrix_color: {
  626. rgb_matrix_sethsv_noeeprom(value_data[0], value_data[1], rgb_matrix_get_val());
  627. break;
  628. }
  629. }
  630. }
  631. void via_qmk_rgb_matrix_save(void) {
  632. eeconfig_update_rgb_matrix();
  633. }
  634. #endif // RGB_MATRIX_ENABLE
  635. #if defined(AUDIO_ENABLE)
  636. extern audio_config_t audio_config;
  637. void via_qmk_audio_command(uint8_t *data, uint8_t length) {
  638. // data = [ command_id, channel_id, value_id, value_data ]
  639. uint8_t *command_id = &(data[0]);
  640. uint8_t *value_id_and_data = &(data[2]);
  641. switch (*command_id) {
  642. case id_custom_set_value: {
  643. via_qmk_audio_set_value(value_id_and_data);
  644. break;
  645. }
  646. case id_custom_get_value: {
  647. via_qmk_audio_get_value(value_id_and_data);
  648. break;
  649. }
  650. case id_custom_save: {
  651. via_qmk_audio_save();
  652. break;
  653. }
  654. default: {
  655. *command_id = id_unhandled;
  656. break;
  657. }
  658. }
  659. }
  660. void via_qmk_audio_get_value(uint8_t *data) {
  661. // data = [ value_id, value_data ]
  662. uint8_t *value_id = &(data[0]);
  663. uint8_t *value_data = &(data[1]);
  664. switch (*value_id) {
  665. case id_qmk_audio_enable: {
  666. value_data[0] = audio_config.enable ? 1 : 0;
  667. break;
  668. }
  669. case id_qmk_audio_clicky_enable: {
  670. value_data[0] = audio_config.clicky_enable ? 1 : 0;
  671. break;
  672. }
  673. }
  674. }
  675. void via_qmk_audio_set_value(uint8_t *data) {
  676. // data = [ value_id, value_data ]
  677. uint8_t *value_id = &(data[0]);
  678. uint8_t *value_data = &(data[1]);
  679. switch (*value_id) {
  680. case id_qmk_audio_enable: {
  681. audio_config.enable = value_data[0] ? 1 : 0;
  682. break;
  683. }
  684. case id_qmk_audio_clicky_enable: {
  685. audio_config.clicky_enable = value_data[0] ? 1 : 0;
  686. break;
  687. }
  688. }
  689. }
  690. void via_qmk_audio_save(void) {
  691. eeconfig_update_audio(audio_config.raw);
  692. }
  693. #endif // QMK_AUDIO_ENABLE