From 2af794eed3fe03b3c3ab904bb02b3953d234adc0 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 2 Feb 2021 14:50:02 -0500 Subject: [PATCH] feat(underglow): Convert HSB changes to absolute. * Public type for HSB led color. * New API for calculating "next" HSB based on current state. * Update behavior to convert the increment/decrement commands to absolute command as well. --- app/include/dt-bindings/zmk/rgb.h | 3 +- app/include/zmk/rgb_underglow.h | 11 +- app/src/behaviors/behavior_rgb_underglow.c | 54 +++++++- app/src/rgb_underglow.c | 151 ++++++++++----------- 4 files changed, 132 insertions(+), 87 deletions(-) diff --git a/app/include/dt-bindings/zmk/rgb.h b/app/include/dt-bindings/zmk/rgb.h index 403cba98..95aa5029 100644 --- a/app/include/dt-bindings/zmk/rgb.h +++ b/app/include/dt-bindings/zmk/rgb.h @@ -32,5 +32,6 @@ #define RGB_SPD RGB_SPD_CMD 0 #define RGB_EFF RGB_EFF_CMD 0 #define RGB_EFR RGB_EFR_CMD 0 -#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD(((h) << 16) + ((s) << 8) + (v)) +#define RGB_COLOR_HSB_VAL(h, s, v) (((h) << 16) + ((s) << 8) + (v)) +#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD##(RGB_COLOR_HSB_VAL(h, s, v)) #define RGB_COLOR_HSV RGB_COLOR_HSB \ No newline at end of file diff --git a/app/include/zmk/rgb_underglow.h b/app/include/zmk/rgb_underglow.h index 7c2ff13f..4d452a6f 100644 --- a/app/include/zmk/rgb_underglow.h +++ b/app/include/zmk/rgb_underglow.h @@ -6,13 +6,22 @@ #pragma once +struct zmk_led_hsb { + uint16_t h; + uint8_t s; + uint8_t b; +}; + int zmk_rgb_underglow_toggle(); int zmk_rgb_underglow_get_state(bool *state); int zmk_rgb_underglow_on(); int zmk_rgb_underglow_off(); int zmk_rgb_underglow_cycle_effect(int direction); +struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction); +struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction); +struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction); int zmk_rgb_underglow_change_hue(int direction); int zmk_rgb_underglow_change_sat(int direction); int zmk_rgb_underglow_change_brt(int direction); int zmk_rgb_underglow_change_spd(int direction); -int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness); \ No newline at end of file +int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color); \ No newline at end of file diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index fe33e04a..79592cac 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -33,12 +33,57 @@ on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_bin } binding->param1 = state ? RGB_OFF_CMD : RGB_ON_CMD; - LOG_DBG("RGB relative toggle convert to absolute %s", state ? "OFF" : "ON"); - return 0; + break; + } + case RGB_BRI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_BRD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_HUI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_HUD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_SAI_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; + } + case RGB_SAD_CMD: { + struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(-1); + + binding->param1 = RGB_COLOR_HSB_CMD; + binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b); + break; } default: return 0; } + + LOG_DBG("RGB relative convert to absolute (%d/%d)", binding->param1, binding->param2); + + return 0; }; static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, @@ -71,8 +116,9 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, case RGB_EFR_CMD: return zmk_rgb_underglow_cycle_effect(-1); case RGB_COLOR_HSB_CMD: - return zmk_rgb_underglow_set_hsb((binding->param2 >> 16) & 0xFFFF, - (binding->param2 >> 8) & 0xFF, binding->param2 & 0xFF); + return zmk_rgb_underglow_set_hsb((struct zmk_led_hsb){.h = (binding->param2 >> 16) & 0xFFFF, + .s = (binding->param2 >> 8) & 0xFF, + .b = binding->param2 & 0xFF}); } return -ENOTSUP; diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 1e07fa28..5f38aba7 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -17,11 +17,17 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow)) #define STRIP_NUM_PIXELS DT_PROP(DT_CHOSEN(zmk_underglow), chain_length) +#define HUE_MAX 360 +#define SAT_MAX 100 +#define BRT_MAX 100 + enum rgb_underglow_effect { UNDERGLOW_EFFECT_SOLID, UNDERGLOW_EFFECT_BREATHE, @@ -30,16 +36,8 @@ enum rgb_underglow_effect { UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects }; -struct led_hsb { - uint16_t h; - uint8_t s; - uint8_t b; -}; - struct rgb_underglow_state { - uint16_t hue; - uint8_t saturation; - uint8_t brightness; + struct zmk_led_hsb color; uint8_t animation_speed; uint8_t current_effect; uint16_t animation_step; @@ -56,13 +54,13 @@ static struct rgb_underglow_state state; static const struct device *ext_power; #endif -static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { +static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) { double r, g, b; uint8_t i = hsb.h / 60; - double v = hsb.b / 100.0; - double s = hsb.s / 100.0; - double f = hsb.h / 360.0 * 6 - i; + double v = hsb.b / ((float)BRT_MAX); + double s = hsb.s / ((float)SAT_MAX); + double f = hsb.h / ((float)HUE_MAX) * 6 - i; double p = v * (1 - s); double q = v * (1 - f * s); double t = v * (1 - (1 - f) * s); @@ -107,23 +105,14 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { static void zmk_rgb_underglow_effect_solid() { for (int i = 0; i < STRIP_NUM_PIXELS; i++) { - int hue = state.hue; - int sat = state.saturation; - int brt = state.brightness; - - struct led_hsb hsb = {hue, sat, brt}; - - pixels[i] = hsb_to_rgb(hsb); + pixels[i] = hsb_to_rgb(state.color); } } static void zmk_rgb_underglow_effect_breathe() { for (int i = 0; i < STRIP_NUM_PIXELS; i++) { - int hue = state.hue; - int sat = state.saturation; - int brt = abs(state.animation_step - 1200) / 12; - - struct led_hsb hsb = {hue, sat, brt}; + struct zmk_led_hsb hsb = state.color; + hsb.b = abs(state.animation_step - 1200) / 12; pixels[i] = hsb_to_rgb(hsb); } @@ -137,32 +126,26 @@ static void zmk_rgb_underglow_effect_breathe() { static void zmk_rgb_underglow_effect_spectrum() { for (int i = 0; i < STRIP_NUM_PIXELS; i++) { - int hue = state.animation_step; - int sat = state.saturation; - int brt = state.brightness; - - struct led_hsb hsb = {hue, sat, brt}; + struct zmk_led_hsb hsb = state.color; + hsb.h = state.animation_step; pixels[i] = hsb_to_rgb(hsb); } state.animation_step += state.animation_speed; - state.animation_step = state.animation_step % 360; + state.animation_step = state.animation_step % HUE_MAX; } static void zmk_rgb_underglow_effect_swirl() { for (int i = 0; i < STRIP_NUM_PIXELS; i++) { - int hue = (360 / STRIP_NUM_PIXELS * i + state.animation_step) % 360; - int sat = state.saturation; - int brt = state.brightness; - - struct led_hsb hsb = {hue, sat, brt}; + struct zmk_led_hsb hsb = state.color; + hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX; pixels[i] = hsb_to_rgb(hsb); } state.animation_step += state.animation_speed * 2; - state.animation_step = state.animation_step % 360; + state.animation_step = state.animation_step % HUE_MAX; } static void zmk_rgb_underglow_tick(struct k_work *work) { @@ -243,9 +226,11 @@ static int zmk_rgb_underglow_init(const struct device *_arg) { #endif state = (struct rgb_underglow_state){ - hue : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START, - saturation : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START, - brightness : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START, + color : { + h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START, + s : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START, + b : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START, + }, animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START, current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START, animation_step : 0, @@ -337,16 +322,8 @@ int zmk_rgb_underglow_cycle_effect(int direction) { if (!led_strip) return -ENODEV; - if (state.current_effect == 0 && direction < 0) { - state.current_effect = UNDERGLOW_EFFECT_NUMBER - 1; - return 0; - } - - state.current_effect += direction; - - if (state.current_effect >= UNDERGLOW_EFFECT_NUMBER) { - state.current_effect = 0; - } + state.current_effect += UNDERGLOW_EFFECT_NUMBER + direction; + state.current_effect %= UNDERGLOW_EFFECT_NUMBER; state.animation_step = 0; @@ -357,47 +334,67 @@ int zmk_rgb_underglow_toggle() { return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on(); } -int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness) { - if (hue > 360 || saturation > 100 || brightness > 100) { +int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color) { + if (color.h > HUE_MAX || color.s > SAT_MAX || color.b > BRT_MAX) { return -ENOTSUP; } - state.hue = hue; - state.saturation = saturation; - state.brightness = brightness; + state.color = color; return 0; } -int zmk_rgb_underglow_change_hue(int direction) { - if (!led_strip) - return -ENODEV; +struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction) { + struct zmk_led_hsb color = state.color; - if (state.hue == 0 && direction < 0) { - state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP; - return 0; + color.h += HUE_MAX + (direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP); + color.h %= HUE_MAX; + + return color; +} + +struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction) { + struct zmk_led_hsb color = state.color; + + int s = color.s + (direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP); + if (s < 0) { + s = 0; + } else if (s > SAT_MAX) { + s = SAT_MAX; } + color.s = s; - state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP; + return color; +} - state.hue = state.hue % 360; +struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction) { + struct zmk_led_hsb color = state.color; - return zmk_rgb_underglow_save_state(); + int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP); + if (b < 0) { + b = 0; + } else if (b > BRT_MAX) { + b = BRT_MAX; + } + color.b = b; + + return color; } -int zmk_rgb_underglow_change_sat(int direction) { +int zmk_rgb_underglow_change_hue(int direction) { if (!led_strip) return -ENODEV; - if (state.saturation == 0 && direction < 0) { - return 0; - } + state.color = zmk_rgb_underglow_calc_hue(direction); - state.saturation += direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP; + return zmk_rgb_underglow_save_state(); +} - if (state.saturation > 100) { - state.saturation = 100; - } +int zmk_rgb_underglow_change_sat(int direction) { + if (!led_strip) + return -ENODEV; + + state.color = zmk_rgb_underglow_calc_sat(direction); return zmk_rgb_underglow_save_state(); } @@ -406,15 +403,7 @@ int zmk_rgb_underglow_change_brt(int direction) { if (!led_strip) return -ENODEV; - if (state.brightness == 0 && direction < 0) { - return 0; - } - - state.brightness += direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP; - - if (state.brightness > 100) { - state.brightness = 100; - } + state.color = zmk_rgb_underglow_calc_brt(direction); return zmk_rgb_underglow_save_state(); }