Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LEDs to show status of different states #1475

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,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)
Expand Down
101 changes: 100 additions & 1 deletion app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,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
Expand All @@ -262,6 +262,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

Expand Down
12 changes: 12 additions & 0 deletions app/include/zmk/caps_word.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

#include <stdbool.h>

extern bool last_state_of_caps_word;
bool zmk_caps_word_state();
1 change: 1 addition & 0 deletions app/include/zmk/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions app/src/behaviors/behavior_caps_word.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include <zmk/hid.h>
#include <zmk/keymap.h>

#include <zmk/caps_word.h>

bool last_state_of_caps_word = false;

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
Expand All @@ -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;
}

Expand Down
6 changes: 6 additions & 0 deletions app/src/caps_word.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <zmk/caps_word.h>

#include <stdbool.h>
#include <kernel.h>

bool zmk_caps_word_state() { return last_state_of_caps_word; }
4 changes: 4 additions & 0 deletions app/src/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,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); };
Expand Down
96 changes: 96 additions & 0 deletions app/src/rgb_underglow.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
#include <zmk/events/activity_state_changed.h>
#include <zmk/events/usb_conn_state_changed.h>

#include <zmk/keymap.h>
#include <zmk/battery.h>
#include <zmk/endpoints.h>
#include <zmk/ble.h>
#include <zmk/caps_word.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow))
Expand All @@ -42,6 +48,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
};

Expand Down Expand Up @@ -74,6 +81,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) {
double r, g, b;

Expand Down Expand Up @@ -168,6 +188,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:
Expand All @@ -182,6 +275,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);
Expand Down