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.

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