diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index a647e883..bfa57962 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -62,6 +62,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/events/endpoint_selection_changed.c) target_sources(app PRIVATE src/hid_listener.c) target_sources(app PRIVATE src/keymap.c) + target_sources(app PRIVATE src/caps_word.c) target_sources(app PRIVATE src/events/layer_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c) diff --git a/app/Kconfig b/app/Kconfig index ccc5f42d..487686c1 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -249,7 +249,7 @@ config ZMK_RGB_UNDERGLOW_SPD_START config ZMK_RGB_UNDERGLOW_EFF_START int "RGB underglow start effect int value related to the effect enum list" - range 0 3 + range 0 4 default 0 config ZMK_RGB_UNDERGLOW_ON_START @@ -263,6 +263,105 @@ config ZMK_RGB_UNDERGLOW_AUTO_OFF_USB bool "Turn off RGB underglow when USB is disconnected" depends on USB_DEVICE_STACK +config ZMK_RGB_UNDERGLOW_NUM_LEDS + int "Numer of leds on the pcb" + range 0 100 + default 100 + +config ZMK_RGB_UNDERGLOW_STATUS_BATTERY + bool "Shows battery status on a LED" + default y + +config ZMK_RGB_UNDERGLOW_STATUS_BATTERY_N + int "LED number to show the battery status" + range 0 ZMK_RGB_UNDERGLOW_NUM_LEDS + default 0 + depends on ZMK_RGB_UNDERGLOW_STATUS_BATTERY + +config ZMK_RGB_UNDERGLOW_STATUS_BATTERY_COLOR_MIN + int "Color when battery is at 0%" + range 0 360 + default 0 + +config ZMK_RGB_UNDERGLOW_STATUS_BATTERY_COLOR_MAX + int "Color when battery is at 100%" + range 0 360 + default 100 + +config ZMK_RGB_UNDERGLOW_STATUS_LAYER + bool "Shows layer status on a LED" + default y + +config ZMK_RGB_UNDERGLOW_STATUS_LAYER_N + int "LED number to show the layer status" + range 0 ZMK_RGB_UNDERGLOW_NUM_LEDS + default 1 + depends on ZMK_RGB_UNDERGLOW_STATUS_LAYER + +config ZMK_RGB_UNDERGLOW_STATUS_LAYER_COLOR_MIN + int "Color when lower layer is selected." + range 0 360 + default 320 + +config ZMK_RGB_UNDERGLOW_STATUS_LAYER_COLOR_MAX + int "Color when highest layer is selected." + range 0 360 + default 0 + +config ZMK_RGB_UNDERGLOW_STATUS_OUTPUT + bool "Shows output status on a LED" + default y + +config ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_N + int "LED number to show the output status" + range 0 ZMK_RGB_UNDERGLOW_NUM_LEDS + default 2 + depends on ZMK_RGB_UNDERGLOW_STATUS_OUTPUT + +config ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_COLOR_MIN + int "Color when usb is selected." + range 0 360 + default 50 + +config ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_COLOR_MAX + int "Color when ble is selected." + range 0 360 + default 300 + +config ZMK_RGB_UNDERGLOW_STATUS_BLE + bool "Shows on a LED the status of the selected ble device." + default y + +config ZMK_RGB_UNDERGLOW_STATUS_BLE_N + int "LED number to show the selected ble" + range 0 ZMK_RGB_UNDERGLOW_NUM_LEDS + default 3 + depends on ZMK_RGB_UNDERGLOW_STATUS_BLE + +config ZMK_RGB_UNDERGLOW_STATUS_BLE_COLOR_MIN + int "Color when ble selected is the first one." + range 0 360 + default 10 + +config ZMK_RGB_UNDERGLOW_STATUS_BLE_COLOR_MAX + int "Color when ble selected is the last one." + range 0 360 + default 320 + +config ZMK_RGB_UNDERGLOW_STATUS_CAPS + bool "Shows on a LED the status of caps word." + default y + +config ZMK_RGB_UNDERGLOW_STATUS_CAPS_N + int "LED number to show the status of caps word" + range 0 ZMK_RGB_UNDERGLOW_NUM_LEDS + default 4 + +config ZMK_RGB_UNDERGLOW_STATUS_CAPS_COLOR + int "Color when caps word is on." + range 0 360 + default 360 + #ZMK_RGB_UNDERGLOW endif diff --git a/app/include/zmk/caps_word.h b/app/include/zmk/caps_word.h new file mode 100644 index 00000000..46ee77d2 --- /dev/null +++ b/app/include/zmk/caps_word.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +extern bool last_state_of_caps_word; +bool zmk_caps_word_state(); \ No newline at end of file diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index a47cd505..12bb69c1 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -14,6 +14,7 @@ uint8_t zmk_keymap_layer_default(); zmk_keymap_layers_state_t zmk_keymap_layer_state(); bool zmk_keymap_layer_active(uint8_t layer); uint8_t zmk_keymap_highest_layer_active(); +uint8_t zmk_keymap_number_of_layers(); int zmk_keymap_layer_activate(uint8_t layer); int zmk_keymap_layer_deactivate(uint8_t layer); int zmk_keymap_layer_toggle(uint8_t layer); diff --git a/app/src/behaviors/behavior_caps_word.c b/app/src/behaviors/behavior_caps_word.c index 4c9fd711..4d0815c3 100644 --- a/app/src/behaviors/behavior_caps_word.c +++ b/app/src/behaviors/behavior_caps_word.c @@ -20,6 +20,10 @@ #include #include +#include + +bool last_state_of_caps_word = false; + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) @@ -44,12 +48,14 @@ struct behavior_caps_word_data { static void activate_caps_word(const struct device *dev) { struct behavior_caps_word_data *data = dev->data; + last_state_of_caps_word = true; data->active = true; } static void deactivate_caps_word(const struct device *dev) { struct behavior_caps_word_data *data = dev->data; + last_state_of_caps_word = false; data->active = false; } diff --git a/app/src/caps_word.c b/app/src/caps_word.c new file mode 100644 index 00000000..7a7d49c1 --- /dev/null +++ b/app/src/caps_word.c @@ -0,0 +1,6 @@ +#include + +#include +#include + +bool zmk_caps_word_state() { return last_state_of_caps_word; } \ No newline at end of file diff --git a/app/src/keymap.c b/app/src/keymap.c index 909fd20d..0e312c42 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -126,6 +126,10 @@ uint8_t zmk_keymap_highest_layer_active() { return zmk_keymap_layer_default(); } +uint8_t zmk_keymap_number_of_layers() { + return ZMK_KEYMAP_LAYERS_LEN; +} + int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); }; int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); }; diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 048b58b4..b8ec0de6 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -25,6 +25,12 @@ #include #include +#include +#include +#include +#include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if !DT_HAS_CHOSEN(zmk_underglow) @@ -48,6 +54,7 @@ enum rgb_underglow_effect { UNDERGLOW_EFFECT_BREATHE, UNDERGLOW_EFFECT_SPECTRUM, UNDERGLOW_EFFECT_SWIRL, + UNDERGLOW_EFFECT_STATUS, UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects }; @@ -80,6 +87,19 @@ static struct zmk_led_hsb hsb_scale_zero_max(struct zmk_led_hsb hsb) { return hsb; } +static uint16_t hue_scale_to_range(uint16_t hue, uint16_t from_max, uint16_t to_min, uint16_t to_max) { + if (to_max > HUE_MAX) to_max = HUE_MAX; + if (to_min > HUE_MAX) to_min = HUE_MAX; + + if (to_min < 0) to_min = 0; + if (to_max < 0) to_max = 0; + + int hue_d = abs(to_max - to_min); + int direc = hue_d - abs(to_max - to_min - 1); + hue = (hue * hue_d / from_max) + (to_min * direc); + return hue; +} + static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) { float r, g, b; @@ -174,6 +194,79 @@ static void zmk_rgb_underglow_effect_swirl() { state.animation_step = state.animation_step % HUE_MAX; } +static void zmk_rgb_underglow_effect_status() { + struct zmk_led_hsb hsb = state.color; + hsb.b = 0; + + // Turn off all LEDs + for (int i = 0; i < STRIP_NUM_PIXELS; i++) { + pixels[i] = hsb_to_rgb(hsb_scale_zero_max(hsb)); + } + + // and turn on specific ones. + + #if CONFIG_ZMK_SPLIT_ROLE_CENTRAL + struct zmk_led_hsb status_hsb = state.color; + + // ------- Turn on the layer status leds ------- + #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_STATUS_LAYER) + status_hsb.h = hue_scale_to_range( + zmk_keymap_highest_layer_active(), + zmk_keymap_number_of_layers(), + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_LAYER_COLOR_MIN, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_LAYER_COLOR_MAX + ); + pixels[CONFIG_ZMK_RGB_UNDERGLOW_STATUS_LAYER_N] = hsb_to_rgb(hsb_scale_min_max(status_hsb)); + #endif + + // ------- Turn on the output status led ------- + #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_STATUS_OUTPUT) + //status_hsb.h = zmk_endpoints_selected() * 90; + status_hsb.h = hue_scale_to_range( + zmk_endpoints_selected(), + ZMK_ENDPOINT_BLE, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_COLOR_MIN, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_COLOR_MAX + ); + pixels[CONFIG_ZMK_RGB_UNDERGLOW_STATUS_OUTPUT_N] = hsb_to_rgb(hsb_scale_min_max(status_hsb)); + #endif + + // ------- Turn on the status led for selected ble ------- + #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BLE) + status_hsb.h = hue_scale_to_range( + zmk_ble_active_profile_index(), + ZMK_BLE_PROFILE_COUNT, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BLE_COLOR_MIN, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BLE_COLOR_MAX + ); + pixels[CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BLE_N] = hsb_to_rgb(hsb_scale_min_max(status_hsb)); + #endif + + // ------- Turn on the caps word for status led ------- + #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_STATUS_CAPS) + struct zmk_led_hsb caps_word_hsb = state.color; + caps_word_hsb.h = zmk_caps_word_state() * CONFIG_ZMK_RGB_UNDERGLOW_STATUS_CAPS_COLOR; + caps_word_hsb.b = zmk_caps_word_state() * caps_word_hsb.b; + + pixels[CONFIG_ZMK_RGB_UNDERGLOW_STATUS_CAPS_N] = hsb_to_rgb(hsb_scale_zero_max(caps_word_hsb)); + #endif + #endif + + // ------- Turn on the battery status led ------- + #if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BATTERY) + struct zmk_led_hsb battery_hsb = state.color; + battery_hsb.h = hue_scale_to_range( + zmk_battery_state_of_charge(), + 100, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BATTERY_COLOR_MIN, + CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BATTERY_COLOR_MAX + ); + battery_hsb.b = zmk_battery_state_of_charge(); + + pixels[CONFIG_ZMK_RGB_UNDERGLOW_STATUS_BATTERY_N] = hsb_to_rgb(hsb_scale_zero_max(battery_hsb)); + #endif +} + static void zmk_rgb_underglow_tick(struct k_work *work) { switch (state.current_effect) { case UNDERGLOW_EFFECT_SOLID: @@ -188,6 +281,9 @@ static void zmk_rgb_underglow_tick(struct k_work *work) { case UNDERGLOW_EFFECT_SWIRL: zmk_rgb_underglow_effect_swirl(); break; + case UNDERGLOW_EFFECT_STATUS: + zmk_rgb_underglow_effect_status(); + break; } led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);