Skip to content

Commit 24f8fd3

Browse files
committed
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.
1 parent 43e0939 commit 24f8fd3

File tree

4 files changed

+132
-87
lines changed

4 files changed

+132
-87
lines changed

app/include/dt-bindings/zmk/rgb.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@
3232
#define RGB_SPD RGB_SPD_CMD 0
3333
#define RGB_EFF RGB_EFF_CMD 0
3434
#define RGB_EFR RGB_EFR_CMD 0
35-
#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD(((h) << 16) + ((s) << 8) + (v))
35+
#define RGB_COLOR_HSB_VAL(h, s, v) (((h) << 16) + ((s) << 8) + (v))
36+
#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD##(RGB_COLOR_HSB_VAL(h, s, v))
3637
#define RGB_COLOR_HSV RGB_COLOR_HSB

app/include/zmk/rgb_underglow.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@
66

77
#pragma once
88

9+
struct zmk_led_hsb {
10+
uint16_t h;
11+
uint8_t s;
12+
uint8_t b;
13+
};
14+
915
int zmk_rgb_underglow_toggle();
1016
int zmk_rgb_underglow_get_state(bool *state);
1117
int zmk_rgb_underglow_on();
1218
int zmk_rgb_underglow_off();
1319
int zmk_rgb_underglow_cycle_effect(int direction);
20+
struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction);
21+
struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction);
22+
struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction);
1423
int zmk_rgb_underglow_change_hue(int direction);
1524
int zmk_rgb_underglow_change_sat(int direction);
1625
int zmk_rgb_underglow_change_brt(int direction);
1726
int zmk_rgb_underglow_change_spd(int direction);
18-
int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness);
27+
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color);

app/src/behaviors/behavior_rgb_underglow.c

+50-4
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,57 @@ on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_bin
3333
}
3434

3535
binding->param1 = state ? RGB_OFF_CMD : RGB_ON_CMD;
36-
LOG_DBG("RGB relative toggle convert to absolute %s", state ? "OFF" : "ON");
37-
return 0;
36+
break;
37+
}
38+
case RGB_BRI_CMD: {
39+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(1);
40+
41+
binding->param1 = RGB_COLOR_HSB_CMD;
42+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
43+
break;
44+
}
45+
case RGB_BRD_CMD: {
46+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(-1);
47+
48+
binding->param1 = RGB_COLOR_HSB_CMD;
49+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
50+
break;
51+
}
52+
case RGB_HUI_CMD: {
53+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(1);
54+
55+
binding->param1 = RGB_COLOR_HSB_CMD;
56+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
57+
break;
58+
}
59+
case RGB_HUD_CMD: {
60+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(-1);
61+
62+
binding->param1 = RGB_COLOR_HSB_CMD;
63+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
64+
break;
65+
}
66+
case RGB_SAI_CMD: {
67+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(1);
68+
69+
binding->param1 = RGB_COLOR_HSB_CMD;
70+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
71+
break;
72+
}
73+
case RGB_SAD_CMD: {
74+
struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(-1);
75+
76+
binding->param1 = RGB_COLOR_HSB_CMD;
77+
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
78+
break;
3879
}
3980
default:
4081
return 0;
4182
}
83+
84+
LOG_DBG("RGB relative convert to absolute (%d/%d)", binding->param1, binding->param2);
85+
86+
return 0;
4287
};
4388

4489
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,
71116
case RGB_EFR_CMD:
72117
return zmk_rgb_underglow_cycle_effect(-1);
73118
case RGB_COLOR_HSB_CMD:
74-
return zmk_rgb_underglow_set_hsb((binding->param2 >> 16) & 0xFFFF,
75-
(binding->param2 >> 8) & 0xFF, binding->param2 & 0xFF);
119+
return zmk_rgb_underglow_set_hsb((struct zmk_led_hsb){.h = (binding->param2 >> 16) & 0xFFFF,
120+
.s = (binding->param2 >> 8) & 0xFF,
121+
.b = binding->param2 & 0xFF});
76122
}
77123

78124
return -ENOTSUP;

app/src/rgb_underglow.c

+70-81
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@
1717
#include <drivers/led_strip.h>
1818
#include <drivers/ext_power.h>
1919

20+
#include <zmk/rgb_underglow.h>
21+
2022
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
2123

2224
#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow))
2325
#define STRIP_NUM_PIXELS DT_PROP(DT_CHOSEN(zmk_underglow), chain_length)
2426

27+
#define HUE_MAX 360
28+
#define SAT_MAX 100
29+
#define BRT_MAX 100
30+
2531
enum rgb_underglow_effect {
2632
UNDERGLOW_EFFECT_SOLID,
2733
UNDERGLOW_EFFECT_BREATHE,
@@ -30,16 +36,8 @@ enum rgb_underglow_effect {
3036
UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects
3137
};
3238

33-
struct led_hsb {
34-
uint16_t h;
35-
uint8_t s;
36-
uint8_t b;
37-
};
38-
3939
struct rgb_underglow_state {
40-
uint16_t hue;
41-
uint8_t saturation;
42-
uint8_t brightness;
40+
struct zmk_led_hsb color;
4341
uint8_t animation_speed;
4442
uint8_t current_effect;
4543
uint16_t animation_step;
@@ -56,13 +54,13 @@ static struct rgb_underglow_state state;
5654
static const struct device *ext_power;
5755
#endif
5856

59-
static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
57+
static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
6058
double r, g, b;
6159

6260
uint8_t i = hsb.h / 60;
63-
double v = hsb.b / 100.0;
64-
double s = hsb.s / 100.0;
65-
double f = hsb.h / 360.0 * 6 - i;
61+
double v = hsb.b / ((float)BRT_MAX);
62+
double s = hsb.s / ((float)SAT_MAX);
63+
double f = hsb.h / ((float)HUE_MAX) * 6 - i;
6664
double p = v * (1 - s);
6765
double q = v * (1 - f * s);
6866
double t = v * (1 - (1 - f) * s);
@@ -107,23 +105,14 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
107105

108106
static void zmk_rgb_underglow_effect_solid() {
109107
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
110-
int hue = state.hue;
111-
int sat = state.saturation;
112-
int brt = state.brightness;
113-
114-
struct led_hsb hsb = {hue, sat, brt};
115-
116-
pixels[i] = hsb_to_rgb(hsb);
108+
pixels[i] = hsb_to_rgb(state.color);
117109
}
118110
}
119111

120112
static void zmk_rgb_underglow_effect_breathe() {
121113
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
122-
int hue = state.hue;
123-
int sat = state.saturation;
124-
int brt = abs(state.animation_step - 1200) / 12;
125-
126-
struct led_hsb hsb = {hue, sat, brt};
114+
struct zmk_led_hsb hsb = state.color;
115+
hsb.b = abs(state.animation_step - 1200) / 12;
127116

128117
pixels[i] = hsb_to_rgb(hsb);
129118
}
@@ -137,32 +126,26 @@ static void zmk_rgb_underglow_effect_breathe() {
137126

138127
static void zmk_rgb_underglow_effect_spectrum() {
139128
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
140-
int hue = state.animation_step;
141-
int sat = state.saturation;
142-
int brt = state.brightness;
143-
144-
struct led_hsb hsb = {hue, sat, brt};
129+
struct zmk_led_hsb hsb = state.color;
130+
hsb.h = state.animation_speed;
145131

146132
pixels[i] = hsb_to_rgb(hsb);
147133
}
148134

149135
state.animation_step += state.animation_speed;
150-
state.animation_step = state.animation_step % 360;
136+
state.animation_step = state.animation_step % HUE_MAX;
151137
}
152138

153139
static void zmk_rgb_underglow_effect_swirl() {
154140
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
155-
int hue = (360 / STRIP_NUM_PIXELS * i + state.animation_step) % 360;
156-
int sat = state.saturation;
157-
int brt = state.brightness;
158-
159-
struct led_hsb hsb = {hue, sat, brt};
141+
struct zmk_led_hsb hsb = state.color;
142+
hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX;
160143

161144
pixels[i] = hsb_to_rgb(hsb);
162145
}
163146

164147
state.animation_step += state.animation_speed * 2;
165-
state.animation_step = state.animation_step % 360;
148+
state.animation_step = state.animation_step % HUE_MAX;
166149
}
167150

168151
static void zmk_rgb_underglow_tick(struct k_work *work) {
@@ -243,9 +226,11 @@ static int zmk_rgb_underglow_init(const struct device *_arg) {
243226
#endif
244227

245228
state = (struct rgb_underglow_state){
246-
hue : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
247-
saturation : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
248-
brightness : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
229+
color : {
230+
h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
231+
s : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
232+
b : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
233+
},
249234
animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START,
250235
current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START,
251236
animation_step : 0,
@@ -337,16 +322,8 @@ int zmk_rgb_underglow_cycle_effect(int direction) {
337322
if (!led_strip)
338323
return -ENODEV;
339324

340-
if (state.current_effect == 0 && direction < 0) {
341-
state.current_effect = UNDERGLOW_EFFECT_NUMBER - 1;
342-
return 0;
343-
}
344-
345-
state.current_effect += direction;
346-
347-
if (state.current_effect >= UNDERGLOW_EFFECT_NUMBER) {
348-
state.current_effect = 0;
349-
}
325+
state.current_effect += UNDERGLOW_EFFECT_NUMBER + direction;
326+
state.current_effect %= UNDERGLOW_EFFECT_NUMBER;
350327

351328
state.animation_step = 0;
352329

@@ -357,47 +334,67 @@ int zmk_rgb_underglow_toggle() {
357334
return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on();
358335
}
359336

360-
int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness) {
361-
if (hue > 360 || saturation > 100 || brightness > 100) {
337+
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color) {
338+
if (color.h > HUE_MAX || color.s > SAT_MAX || color.b > BRT_MAX) {
362339
return -ENOTSUP;
363340
}
364341

365-
state.hue = hue;
366-
state.saturation = saturation;
367-
state.brightness = brightness;
342+
state.color = color;
368343

369344
return 0;
370345
}
371346

372-
int zmk_rgb_underglow_change_hue(int direction) {
373-
if (!led_strip)
374-
return -ENODEV;
347+
struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction) {
348+
struct zmk_led_hsb color = state.color;
375349

376-
if (state.hue == 0 && direction < 0) {
377-
state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
378-
return 0;
350+
color.h += HUE_MAX + (direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP);
351+
color.h %= HUE_MAX;
352+
353+
return color;
354+
}
355+
356+
struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction) {
357+
struct zmk_led_hsb color = state.color;
358+
359+
int s = color.s + (direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP);
360+
if (s < 0) {
361+
s = 0;
362+
} else if (s > SAT_MAX) {
363+
s = SAT_MAX;
379364
}
365+
color.s = s;
380366

381-
state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
367+
return color;
368+
}
382369

383-
state.hue = state.hue % 360;
370+
struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction) {
371+
struct zmk_led_hsb color = state.color;
384372

385-
return zmk_rgb_underglow_save_state();
373+
int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP);
374+
if (b < 0) {
375+
b = 0;
376+
} else if (b > BRT_MAX) {
377+
b = BRT_MAX;
378+
}
379+
color.b = b;
380+
381+
return color;
386382
}
387383

388-
int zmk_rgb_underglow_change_sat(int direction) {
384+
int zmk_rgb_underglow_change_hue(int direction) {
389385
if (!led_strip)
390386
return -ENODEV;
391387

392-
if (state.saturation == 0 && direction < 0) {
393-
return 0;
394-
}
388+
state.color = zmk_rgb_underglow_calc_hue(direction);
395389

396-
state.saturation += direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP;
390+
return zmk_rgb_underglow_save_state();
391+
}
397392

398-
if (state.saturation > 100) {
399-
state.saturation = 100;
400-
}
393+
int zmk_rgb_underglow_change_sat(int direction) {
394+
if (!led_strip)
395+
return -ENODEV;
396+
397+
state.color = zmk_rgb_underglow_calc_sat(direction);
401398

402399
return zmk_rgb_underglow_save_state();
403400
}
@@ -406,15 +403,7 @@ int zmk_rgb_underglow_change_brt(int direction) {
406403
if (!led_strip)
407404
return -ENODEV;
408405

409-
if (state.brightness == 0 && direction < 0) {
410-
return 0;
411-
}
412-
413-
state.brightness += direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP;
414-
415-
if (state.brightness > 100) {
416-
state.brightness = 100;
417-
}
406+
state.color = zmk_rgb_underglow_calc_brt(direction);
418407

419408
return zmk_rgb_underglow_save_state();
420409
}

0 commit comments

Comments
 (0)