- /* Copyright 2020 zvecr<git@zvecr.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "led.h"
- #include "host.h"
- #include "timer.h"
- #include "debug.h"
- #include "gpio.h"
-
- #ifdef BACKLIGHT_CAPS_LOCK
- # ifdef BACKLIGHT_ENABLE
- # include "backlight.h"
- extern backlight_config_t backlight_config;
- # else
- # pragma message "Cannot use BACKLIGHT_CAPS_LOCK without backlight being enabled"
- # undef BACKLIGHT_CAPS_LOCK
- # endif
- #endif
-
- #ifndef LED_PIN_ON_STATE
- # define LED_PIN_ON_STATE 1
- #endif
-
- #ifdef BACKLIGHT_CAPS_LOCK
- /** \brief Caps Lock indicator using backlight (for keyboards without dedicated LED)
- */
- static void handle_backlight_caps_lock(led_t led_state) {
- // Use backlight as Caps Lock indicator
- uint8_t bl_toggle_lvl = 0;
-
- if (led_state.caps_lock && !backlight_config.enable) {
- // Turning Caps Lock ON and backlight is disabled in config
- // Toggling backlight to the brightest level
- bl_toggle_lvl = BACKLIGHT_LEVELS;
- } else if (!led_state.caps_lock && backlight_config.enable) {
- // Turning Caps Lock OFF and backlight is enabled in config
- // Toggling backlight and restoring config level
- bl_toggle_lvl = backlight_config.level;
- }
-
- // Set level without modify backlight_config to keep ability to restore state
- backlight_set(bl_toggle_lvl);
- }
- #endif
-
- static uint32_t last_led_modification_time = 0;
- uint32_t last_led_activity_time(void) {
- return last_led_modification_time;
- }
- uint32_t last_led_activity_elapsed(void) {
- return timer_elapsed32(last_led_modification_time);
- }
-
- /** \brief Lock LED set callback - keymap/user level
- *
- * \deprecated Use led_update_user() instead.
- */
- __attribute__((weak)) void led_set_user(uint8_t usb_led) {}
-
- /** \brief Lock LED update callback - keymap/user level
- *
- * \return True if led_update_kb() should run its own code, false otherwise.
- */
- __attribute__((weak)) bool led_update_user(led_t led_state) {
- return true;
- }
-
- /** \brief Lock LED update callback - keyboard level
- *
- * \return Ignored for now.
- */
- __attribute__((weak)) bool led_update_kb(led_t led_state) {
- bool res = led_update_user(led_state);
- if (res) {
- led_update_ports(led_state);
- }
- return res;
- }
-
- /** \brief Write LED state to hardware
- */
- __attribute__((weak)) void led_update_ports(led_t led_state) {
- #if LED_PIN_ON_STATE == 0
- // invert the whole thing to avoid having to conditionally !led_state.x later
- led_state.raw = ~led_state.raw;
- #endif
-
- #ifdef LED_NUM_LOCK_PIN
- writePin(LED_NUM_LOCK_PIN, led_state.num_lock);
- #endif
- #ifdef LED_CAPS_LOCK_PIN
- writePin(LED_CAPS_LOCK_PIN, led_state.caps_lock);
- #endif
- #ifdef LED_SCROLL_LOCK_PIN
- writePin(LED_SCROLL_LOCK_PIN, led_state.scroll_lock);
- #endif
- #ifdef LED_COMPOSE_PIN
- writePin(LED_COMPOSE_PIN, led_state.compose);
- #endif
- #ifdef LED_KANA_PIN
- writePin(LED_KANA_PIN, led_state.kana);
- #endif
- }
-
- /** \brief Initialise any LED related hardware and/or state
- */
- __attribute__((weak)) void led_init_ports(void) {
- #ifdef LED_NUM_LOCK_PIN
- setPinOutput(LED_NUM_LOCK_PIN);
- writePin(LED_NUM_LOCK_PIN, !LED_PIN_ON_STATE);
- #endif
- #ifdef LED_CAPS_LOCK_PIN
- setPinOutput(LED_CAPS_LOCK_PIN);
- writePin(LED_CAPS_LOCK_PIN, !LED_PIN_ON_STATE);
- #endif
- #ifdef LED_SCROLL_LOCK_PIN
- setPinOutput(LED_SCROLL_LOCK_PIN);
- writePin(LED_SCROLL_LOCK_PIN, !LED_PIN_ON_STATE);
- #endif
- #ifdef LED_COMPOSE_PIN
- setPinOutput(LED_COMPOSE_PIN);
- writePin(LED_COMPOSE_PIN, !LED_PIN_ON_STATE);
- #endif
- #ifdef LED_KANA_PIN
- setPinOutput(LED_KANA_PIN);
- writePin(LED_KANA_PIN, !LED_PIN_ON_STATE);
- #endif
- }
-
- /** \brief Entrypoint for protocol to LED binding
- */
- __attribute__((weak)) void led_set(uint8_t usb_led) {
- #ifdef BACKLIGHT_CAPS_LOCK
- handle_backlight_caps_lock((led_t)usb_led);
- #endif
-
- led_set_user(usb_led);
- led_update_kb((led_t)usb_led);
- }
-
- /** \brief Trigger behaviour on transition to suspend
- */
- void led_suspend(void) {
- uint8_t leds_off = 0;
- #ifdef BACKLIGHT_CAPS_LOCK
- if (is_backlight_enabled()) {
- // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
- leds_off |= (1 << USB_LED_CAPS_LOCK);
- }
- #endif
- led_set(leds_off);
- }
-
- /** \brief Trigger behaviour on transition from suspend
- */
- void led_wakeup(void) {
- led_set(host_keyboard_leds());
- }
-
- /** \brief set host led state
- *
- * Only sets state if change detected
- */
- void led_task(void) {
- static uint8_t last_led_status = 0;
-
- // update LED
- uint8_t led_status = host_keyboard_leds();
- if (last_led_status != led_status) {
- last_led_status = led_status;
- last_led_modification_time = timer_read32();
-
- if (debug_keyboard) {
- debug("led_task: ");
- debug_hex8(led_status);
- debug("\n");
- }
- led_set(led_status);
- }
- }
|