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.

190 lines
5.4 KiB

  1. /* Copyright 2020 zvecr<git@zvecr.com>
  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. #include "led.h"
  17. #include "host.h"
  18. #include "timer.h"
  19. #include "debug.h"
  20. #include "gpio.h"
  21. #ifdef BACKLIGHT_CAPS_LOCK
  22. # ifdef BACKLIGHT_ENABLE
  23. # include "backlight.h"
  24. extern backlight_config_t backlight_config;
  25. # else
  26. # pragma message "Cannot use BACKLIGHT_CAPS_LOCK without backlight being enabled"
  27. # undef BACKLIGHT_CAPS_LOCK
  28. # endif
  29. #endif
  30. #ifndef LED_PIN_ON_STATE
  31. # define LED_PIN_ON_STATE 1
  32. #endif
  33. #ifdef BACKLIGHT_CAPS_LOCK
  34. /** \brief Caps Lock indicator using backlight (for keyboards without dedicated LED)
  35. */
  36. static void handle_backlight_caps_lock(led_t led_state) {
  37. // Use backlight as Caps Lock indicator
  38. uint8_t bl_toggle_lvl = 0;
  39. if (led_state.caps_lock && !backlight_config.enable) {
  40. // Turning Caps Lock ON and backlight is disabled in config
  41. // Toggling backlight to the brightest level
  42. bl_toggle_lvl = BACKLIGHT_LEVELS;
  43. } else if (!led_state.caps_lock && backlight_config.enable) {
  44. // Turning Caps Lock OFF and backlight is enabled in config
  45. // Toggling backlight and restoring config level
  46. bl_toggle_lvl = backlight_config.level;
  47. }
  48. // Set level without modify backlight_config to keep ability to restore state
  49. backlight_set(bl_toggle_lvl);
  50. }
  51. #endif
  52. static uint32_t last_led_modification_time = 0;
  53. uint32_t last_led_activity_time(void) {
  54. return last_led_modification_time;
  55. }
  56. uint32_t last_led_activity_elapsed(void) {
  57. return timer_elapsed32(last_led_modification_time);
  58. }
  59. /** \brief Lock LED set callback - keymap/user level
  60. *
  61. * \deprecated Use led_update_user() instead.
  62. */
  63. __attribute__((weak)) void led_set_user(uint8_t usb_led) {}
  64. /** \brief Lock LED update callback - keymap/user level
  65. *
  66. * \return True if led_update_kb() should run its own code, false otherwise.
  67. */
  68. __attribute__((weak)) bool led_update_user(led_t led_state) {
  69. return true;
  70. }
  71. /** \brief Lock LED update callback - keyboard level
  72. *
  73. * \return Ignored for now.
  74. */
  75. __attribute__((weak)) bool led_update_kb(led_t led_state) {
  76. bool res = led_update_user(led_state);
  77. if (res) {
  78. led_update_ports(led_state);
  79. }
  80. return res;
  81. }
  82. /** \brief Write LED state to hardware
  83. */
  84. __attribute__((weak)) void led_update_ports(led_t led_state) {
  85. #if LED_PIN_ON_STATE == 0
  86. // invert the whole thing to avoid having to conditionally !led_state.x later
  87. led_state.raw = ~led_state.raw;
  88. #endif
  89. #ifdef LED_NUM_LOCK_PIN
  90. gpio_write_pin(LED_NUM_LOCK_PIN, led_state.num_lock);
  91. #endif
  92. #ifdef LED_CAPS_LOCK_PIN
  93. gpio_write_pin(LED_CAPS_LOCK_PIN, led_state.caps_lock);
  94. #endif
  95. #ifdef LED_SCROLL_LOCK_PIN
  96. gpio_write_pin(LED_SCROLL_LOCK_PIN, led_state.scroll_lock);
  97. #endif
  98. #ifdef LED_COMPOSE_PIN
  99. gpio_write_pin(LED_COMPOSE_PIN, led_state.compose);
  100. #endif
  101. #ifdef LED_KANA_PIN
  102. gpio_write_pin(LED_KANA_PIN, led_state.kana);
  103. #endif
  104. }
  105. /** \brief Initialise any LED related hardware and/or state
  106. */
  107. __attribute__((weak)) void led_init_ports(void) {
  108. #ifdef LED_NUM_LOCK_PIN
  109. gpio_set_pin_output(LED_NUM_LOCK_PIN);
  110. gpio_write_pin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE);
  111. #endif
  112. #ifdef LED_CAPS_LOCK_PIN
  113. gpio_set_pin_output(LED_CAPS_LOCK_PIN);
  114. gpio_write_pin(LED_CAPS_LOCK_PIN, !LED_PIN_ON_STATE);
  115. #endif
  116. #ifdef LED_SCROLL_LOCK_PIN
  117. gpio_set_pin_output(LED_SCROLL_LOCK_PIN);
  118. gpio_write_pin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE);
  119. #endif
  120. #ifdef LED_COMPOSE_PIN
  121. gpio_set_pin_output(LED_COMPOSE_PIN);
  122. gpio_write_pin(LED_COMPOSE_PIN, !LED_PIN_ON_STATE);
  123. #endif
  124. #ifdef LED_KANA_PIN
  125. gpio_set_pin_output(LED_KANA_PIN);
  126. gpio_write_pin(LED_KANA_PIN, !LED_PIN_ON_STATE);
  127. #endif
  128. }
  129. /** \brief Entrypoint for protocol to LED binding
  130. */
  131. __attribute__((weak)) void led_set(uint8_t usb_led) {
  132. #ifdef BACKLIGHT_CAPS_LOCK
  133. handle_backlight_caps_lock((led_t)usb_led);
  134. #endif
  135. led_set_user(usb_led);
  136. led_update_kb((led_t)usb_led);
  137. }
  138. /** \brief Trigger behaviour on transition to suspend
  139. */
  140. void led_suspend(void) {
  141. led_t leds_off = {0};
  142. #ifdef BACKLIGHT_CAPS_LOCK
  143. if (is_backlight_enabled()) {
  144. // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
  145. leds_off.caps_lock = true;
  146. }
  147. #endif
  148. led_set(leds_off.raw);
  149. }
  150. /** \brief Trigger behaviour on transition from suspend
  151. */
  152. void led_wakeup(void) {
  153. led_set(host_keyboard_leds());
  154. }
  155. /** \brief set host led state
  156. *
  157. * Only sets state if change detected
  158. */
  159. void led_task(void) {
  160. static uint8_t last_led_status = 0;
  161. // update LED
  162. uint8_t led_status = host_keyboard_leds();
  163. if (last_led_status != led_status) {
  164. last_led_status = led_status;
  165. last_led_modification_time = timer_read32();
  166. if (debug_keyboard) {
  167. dprintf("led_task: %02X\n", led_status);
  168. }
  169. led_set(led_status);
  170. }
  171. }