lamparray.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2024 QMK
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <string.h> // for memcpy
  4. #include "lamparray.h"
  5. #include "lamparray_surface.h"
  6. #include "keycodes.h"
  7. #include "keymap_introspection.h"
  8. #include "action_layer.h"
  9. // Defaults are generated from info.json layout content
  10. #ifndef LAMPARRAY_WIDTH
  11. # define LAMPARRAY_WIDTH ESTIMATED_KEYBOARD_WIDTH
  12. #endif
  13. #ifndef LAMPARRAY_HEIGHT
  14. # define LAMPARRAY_HEIGHT ESTIMATED_KEYBOARD_HEIGHT
  15. #endif
  16. #ifndef LAMPARRAY_DEPTH
  17. # define LAMPARRAY_DEPTH 30000
  18. #endif
  19. #ifndef LAMPARRAY_KIND
  20. # define LAMPARRAY_KIND LAMPARRAY_KIND_KEYBOARD
  21. #endif
  22. #ifdef RGB_MATRIX_ENABLE
  23. # include "rgb_matrix.h"
  24. # define LAMPARRAY_RED_LEVELS 255
  25. # define LAMPARRAY_GREEN_LEVELS 255
  26. # define LAMPARRAY_BLUE_LEVELS 255
  27. # define LAMPARRAY_INTENSITY_LEVELS 1
  28. # define LAMPARRAY_LAMP_COUNT RGB_MATRIX_LED_COUNT
  29. # define LAMPARRAY_UPDATE_INTERVAL (RGB_MATRIX_LED_FLUSH_LIMIT * 1000)
  30. #endif
  31. //****************************************************************************
  32. // utils
  33. /**
  34. * \brief Query a HID usage for a given location
  35. *
  36. * This can be requested while the user is changing layers. This is mitigated somewhat by assuming the default layer changes infrequently.
  37. * This is currently accepted as a limitation as there is no method to invalidate the hosts view of the data.
  38. */
  39. uint8_t lamparray_binding_at_keymap_location(uint8_t row, uint8_t col) {
  40. uint16_t keycode = keycode_at_keymap_location(get_highest_layer(default_layer_state), row, col);
  41. (void)keycode;
  42. #if LAMPARRAY_KIND == LAMPARRAY_KIND_KEYBOARD
  43. // Basic QMK keycodes currently map directly to Keyboard UsagePage so safe to return without added indirection
  44. // Mousekeys are ignored due to values overlap Keyboard UsagePage
  45. if (IS_BASIC_KEYCODE(keycode) || IS_MODIFIER_KEYCODE(keycode)) {
  46. return keycode;
  47. }
  48. #elif LAMPARRAY_KIND == LAMPARRAY_KIND_MOUSE
  49. // Usages from the Button UsagePage (0x09) in the range of Button1 (0x01) to Button5 (0x05) inclusive
  50. if ((code) >= KC_MS_BTN1 && (code) <= KC_MS_BTN5) {
  51. return keycode - KC_MS_BTN1 + 1;
  52. }
  53. #endif
  54. return 0;
  55. }
  56. //****************************************************************************
  57. // cache
  58. static uint8_t input_binding_cache[LAMPARRAY_LAMP_COUNT];
  59. void lamparray_update_cache(void) {
  60. for (uint8_t lamp_id = 0; lamp_id < LAMPARRAY_LAMP_COUNT; lamp_id++) {
  61. input_binding_cache[lamp_id] = lamparray_get_lamp_binding_impl(lamp_id);
  62. }
  63. }
  64. uint8_t lamparray_get_lamp_binding(uint16_t lamp_id) {
  65. return input_binding_cache[lamp_id];
  66. }
  67. //****************************************************************************
  68. // queue
  69. #ifndef LAMPARRAY_REQUEST_QUEUE_SIZE
  70. # define LAMPARRAY_REQUEST_QUEUE_SIZE 5
  71. #endif
  72. universal_lamparray_response_t request_queue[LAMPARRAY_REQUEST_QUEUE_SIZE] = {0};
  73. uint8_t queue_size = 0;
  74. void lamparray_queue_request(universal_lamparray_response_t* report) {
  75. // get next slot
  76. universal_lamparray_response_t* target = &request_queue[queue_size++];
  77. // copy data
  78. memcpy(target, report, sizeof(universal_lamparray_response_t));
  79. }
  80. void lamparray_handle_queue(void) {
  81. for (uint8_t id = 0; id < queue_size; id++) {
  82. universal_lamparray_response_t* report = &request_queue[id];
  83. switch (report->report_id) {
  84. case LAMPARRAY_REPORT_ID_RANGE_UPDATE:
  85. lamparray_set_range(&report->range_update);
  86. break;
  87. case LAMPARRAY_REPORT_ID_MULTI_UPDATE:
  88. lamparray_set_items(&report->multi_update);
  89. break;
  90. case LAMPARRAY_REPORT_ID_CONTROL:
  91. lamparray_set_control_response(report->autonomous);
  92. break;
  93. }
  94. }
  95. queue_size = 0;
  96. }
  97. //****************************************************************************
  98. // impl
  99. static uint16_t cur_lamp_id = 0;
  100. static bool is_autonomous = true;
  101. void lamparray_get_attributes(lamparray_attributes_t* data) {
  102. data->lamp_count = LAMPARRAY_LAMP_COUNT;
  103. data->update_interval = LAMPARRAY_UPDATE_INTERVAL;
  104. data->kind = LAMPARRAY_KIND;
  105. data->bounds.width = LAMPARRAY_WIDTH;
  106. data->bounds.height = LAMPARRAY_HEIGHT;
  107. data->bounds.depth = LAMPARRAY_DEPTH;
  108. }
  109. void lamparray_get_attributes_response(lamparray_attributes_response_t* data) {
  110. data->lamp_id = cur_lamp_id;
  111. data->update_latency = 1000;
  112. data->is_programmable = 1;
  113. data->input_binding = lamparray_get_lamp_binding(cur_lamp_id);
  114. data->levels.red = LAMPARRAY_RED_LEVELS;
  115. data->levels.green = LAMPARRAY_GREEN_LEVELS;
  116. data->levels.blue = LAMPARRAY_BLUE_LEVELS;
  117. data->levels.intensity = LAMPARRAY_INTENSITY_LEVELS;
  118. lamparray_get_lamp_impl(cur_lamp_id, data);
  119. // Automatic address pointer incrementing - 26.8.1 LampAttributesRequestReport
  120. cur_lamp_id++;
  121. if (cur_lamp_id >= LAMPARRAY_LAMP_COUNT) cur_lamp_id = 0;
  122. }
  123. void lamparray_set_attributes_response(uint16_t lamp_id) {
  124. cur_lamp_id = lamp_id;
  125. }
  126. void lamparray_set_control_response(uint8_t autonomous) {
  127. is_autonomous = !!autonomous;
  128. lamparray_surface_enable(!autonomous);
  129. }
  130. void lamparray_set_range(lamparray_range_update_t* data) {
  131. // Any Lamp*UpdateReports can be ignored - 26.10.1 AutonomousMode
  132. if (is_autonomous) {
  133. return;
  134. }
  135. // Ensure IDs are within bounds
  136. if ((data->start >= LAMPARRAY_LAMP_COUNT) || (data->end >= LAMPARRAY_LAMP_COUNT)) {
  137. return;
  138. }
  139. for (uint16_t index = data->start; index <= data->end; index++) {
  140. lamparray_surface_set_item(index, data->color);
  141. }
  142. // Batch update complete - 26.11 Updating Lamp State
  143. if (data->flags & LAMP_UPDATE_FLAG_COMPLETE) {
  144. lamparray_surface_update_finished();
  145. }
  146. }
  147. void lamparray_set_items(lamparray_multi_update_t* data) {
  148. // Any Lamp*UpdateReports can be ignored - 26.10.1 AutonomousMode
  149. if (is_autonomous) {
  150. return;
  151. }
  152. // Ensure data is within bounds
  153. if (data->count > LAMP_MULTI_UPDATE_LAMP_COUNT) {
  154. return;
  155. }
  156. for (uint8_t i = 0; i < data->count; i++) {
  157. // Ensure IDs are within bounds
  158. if (data->ids[i] >= LAMPARRAY_LAMP_COUNT) {
  159. continue;
  160. }
  161. lamparray_surface_set_item(data->ids[i], data->colors[i]);
  162. }
  163. // Batch update complete - 26.11 Updating Lamp State
  164. if (data->flags & LAMP_UPDATE_FLAG_COMPLETE) {
  165. lamparray_surface_update_finished();
  166. }
  167. }
  168. //****************************************************************************
  169. // feature hooks
  170. void lamparray_init(void) {
  171. lamparray_update_cache();
  172. }
  173. void lamparray_task(void) {
  174. lamparray_handle_queue();
  175. // TODO: regen cache if dynamic keymap updated?
  176. uint16_t temp = 0;
  177. if (!++temp) lamparray_update_cache();
  178. }
  179. // TODO: SRC += ...
  180. #ifdef RGB_MATRIX_ENABLE
  181. # include "lamparray_rgb_matrix.c"
  182. #endif