Skip to content

Commit

Permalink
Experimental: Add layer indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
caksoylar committed Dec 25, 2023
1 parent 841ee9c commit d0c59c1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
7 changes: 7 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ config RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL
int "Critical battery level percentage"
default 5

config RGBLED_WIDGET_SHOW_LAYER_CHANGE
bool "Indicate highest active layer on each layer change with a sequence of blinks"

config RGBLED_WIDGET_LAYER_BLINK_MS
int "Blink and wait duration for layer indicator"
default 100

endif
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,16 @@ For other keyboards, see the "Adding support" section below.
See [this video](https://cdn.discordapp.com/attachments/1134635625455292426/1134639930501496832/rgbled_widget.mp4) for a short demo, running through power on, profile switching and power offs.

Currently the widget does the following:

- Blink 🟢/🟡/🔴 on boot depending on battery level (for both central/peripherals), thresholds set by `CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_HIGH` and `CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_LOW`
- Blink 🔴 on every battery level change if below critical battery level (`CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL`)
- Blink 🔵 for connected, 🟡 for open (advertising), 🔴 for disconnected profiles on every BT profile switch (on central side for splits)
- Blink 🔵 for connected, 🔴 for disconnected on peripheral side of splits

_Experimental_: Enable `CONFIG_RGBLED_WIDGET_SHOW_LAYER_CHANGE` to show the highest active layer on every layer change
using a sequence of N cyan color blinks, where N is the zero-based index of the layer.
Note that this can be noisy and distracting, especially if you use conditional layers.

## Configuration

Blink durations can also be adjusted, see the [Kconfig file](Kconfig) for available config properties.
Expand All @@ -64,7 +69,7 @@ CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL=10

## Adding support in custom boards/shields

To be able to use this widget, you need three LEDs controlled by GPIOs (*not* smart LEDs), ideally red, green and blue colors.
To be able to use this widget, you need three LEDs controlled by GPIOs (_not_ smart LEDs), ideally red, green and blue colors.
Once you have these LED definitions in your board/shield, simply set the appropriate `aliases` to the RGB LED node labels.

As an example, here is a definition for three LEDs connected to GND and separate GPIOs for a nRF52840 controller:
Expand Down
38 changes: 37 additions & 1 deletion leds.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

#include <zmk/ble.h>
#include <zmk/endpoints.h>
#include <zmk/keymap.h>
#include <zmk/events/ble_active_profile_changed.h>
#include <zmk/split/bluetooth/peripheral.h>
#include <zmk/events/split_peripheral_status_changed.h>
#include <zmk/events/battery_state_changed.h>
#include <zmk/events/layer_state_changed.h>

#include <zephyr/logging/log.h>

Expand Down Expand Up @@ -45,6 +47,7 @@ struct blink_item {
enum color_t color;
uint16_t duration_ms;
bool first_item;
uint16_t sleep_ms;
};

// define message queue of blink work items, that will be processed by a separate thread
Expand Down Expand Up @@ -112,6 +115,35 @@ ZMK_LISTENER(led_battery_listener, led_battery_listener_cb);
ZMK_SUBSCRIPTION(led_battery_listener, zmk_battery_state_changed);
#endif // IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING)

#if IS_ENABLED(CONFIG_RGBLED_WIDGET_SHOW_LAYER_CHANGE)
#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
static int led_layer_listener_cb(const zmk_event_t *eh) {
// ignore layer off events
if (!((struct zmk_layer_state_changed *)eh)->state) {
return 0;
}

uint8_t index = zmk_keymap_highest_layer_active();
static const struct blink_item blink = {.duration_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS,
.color = LED_CYAN,
.sleep_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS};
static const struct blink_item last_blink = {.duration_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS,
.color = LED_CYAN};
for (int i = 0; i < index; i++) {
if (i < index - 1) {
k_msgq_put(&led_msgq, &blink, K_NO_WAIT);
} else {
k_msgq_put(&led_msgq, &last_blink, K_NO_WAIT);
}
}
return 0;
}

ZMK_LISTENER(led_layer_listener, led_layer_listener_cb);
ZMK_SUBSCRIPTION(led_layer_listener, zmk_layer_state_changed);
#endif
#endif // IS_ENABLED(CONFIG_RGBLED_WIDGET_SHOW_LAYER_CHANGE)

extern void led_thread(void *d0, void *d1, void *d2) {
ARG_UNUSED(d0);
ARG_UNUSED(d1);
Expand Down Expand Up @@ -176,7 +208,11 @@ extern void led_thread(void *d0, void *d1, void *d2) {
}

// wait interval before processing another blink
k_sleep(K_MSEC(CONFIG_RGBLED_WIDGET_INTERVAL_MS));
if (blink.sleep_ms > 0) {
k_sleep(K_MSEC(blink.sleep_ms));
} else {
k_sleep(K_MSEC(CONFIG_RGBLED_WIDGET_INTERVAL_MS));
}
}
}

Expand Down

0 comments on commit d0c59c1

Please sign in to comment.