underglow-layer: add fade-delay property
This commit is contained in:
parent
62dc6d8ec5
commit
01f8f363f8
4 changed files with 105 additions and 67 deletions
|
|
@ -18,3 +18,7 @@ child-binding:
|
||||||
layer-id:
|
layer-id:
|
||||||
type: int
|
type: int
|
||||||
required: true
|
required: true
|
||||||
|
fade-delay:
|
||||||
|
type: int
|
||||||
|
required: false
|
||||||
|
default: -1
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
const int rgb_pixel_lookup(int idx);
|
const int rgb_pixel_lookup(int idx);
|
||||||
const int zmk_rgbmap_id(uint8_t layer);
|
const int zmk_rgbmap_id(uint8_t layer);
|
||||||
|
const int zmk_rgbmap_fade_delay(uint8_t layer);
|
||||||
|
|
||||||
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer);
|
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer);
|
||||||
|
|
||||||
uint8_t rgb_underglow_top_layer_with_state(uint32_t state_to_test);
|
uint8_t rgb_underglow_top_layer_with_state(uint32_t state_to_test);
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(zmk_underglow_layer) && IS_ENABLED(CONFIG_EXPERIMENTAL_RGB_LAYER)
|
#if DT_HAS_COMPAT_STATUS_OKAY(zmk_underglow_layer) && IS_ENABLED(CONFIG_EXPERIMENTAL_RGB_LAYER)
|
||||||
#define UNDERGLOW_LAYER_ENABLED 1
|
#define UNDERGLOW_LAYER_ENABLED 1
|
||||||
|
static void zmk_rgb_underglow_set_layer(uint8_t layer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HUE_MAX 360
|
#define HUE_MAX 360
|
||||||
|
|
@ -210,6 +211,23 @@ static void zmk_rgb_underglow_effect_swirl(void) {
|
||||||
state.animation_step = state.animation_step % HUE_MAX;
|
state.animation_step = state.animation_step % HUE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void zmk_rgb_underglow_effect_layer(void) {
|
||||||
|
bool active = false;
|
||||||
|
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||||
|
pixels[i].r -= state.animation_speed < pixels[i].r ? state.animation_speed : pixels[i].r;
|
||||||
|
pixels[i].g -= state.animation_speed < pixels[i].g ? state.animation_speed : pixels[i].g;
|
||||||
|
pixels[i].b -= state.animation_speed < pixels[i].b ? state.animation_speed : pixels[i].b;
|
||||||
|
if (pixels[i].r || pixels[i].g || pixels[i].b) {
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.animation_step += state.animation_speed;
|
||||||
|
|
||||||
|
if (state.animation_step > 255 || !active) {
|
||||||
|
zmk_rgb_underglow_transient_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int zmk_led_generate_status(void);
|
static int zmk_led_generate_status(void);
|
||||||
|
|
||||||
static void zmk_led_write_pixels(void) {
|
static void zmk_led_write_pixels(void) {
|
||||||
|
|
@ -448,70 +466,6 @@ static inline struct led_rgb hue_sat(int hue, int sat) {
|
||||||
return hsb_to_rgb(hsb_scale_min_max(hsb));
|
return hsb_to_rgb(hsb_scale_min_max(hsb));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(UNDERGLOW_LAYER_ENABLED)
|
|
||||||
|
|
||||||
static struct led_rgb hex_to_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
|
||||||
struct zmk_led_hsb hsb = state.color;
|
|
||||||
return (struct led_rgb){
|
|
||||||
r : (hsb.b * (r)) / 0xff,
|
|
||||||
g : (hsb.b * (g)) / 0xff,
|
|
||||||
b : (hsb.b * (b)) / 0xff
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zmk_rgb_underglow_apply_rgbmap(struct zmk_behavior_binding *bindings,
|
|
||||||
size_t rgbmap_len) {
|
|
||||||
int rc = 0;
|
|
||||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
|
||||||
uint8_t midx = rgb_pixel_lookup(i);
|
|
||||||
if (midx >= ZMK_KEYMAP_LEN) {
|
|
||||||
LOG_DBG("out of range");
|
|
||||||
} else {
|
|
||||||
const struct device *dev = zmk_behavior_get_binding(bindings[midx].behavior_dev);
|
|
||||||
|
|
||||||
if (dev == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
|
||||||
|
|
||||||
if (api->binding_pressed == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
struct zmk_behavior_binding_event event = {.position = midx,
|
|
||||||
.timestamp = k_uptime_get()};
|
|
||||||
|
|
||||||
int color =
|
|
||||||
api->binding_pressed((const struct zmk_behavior_binding *)&bindings[midx], event);
|
|
||||||
|
|
||||||
if (color > 0) {
|
|
||||||
pixels[i] =
|
|
||||||
hex_to_rgb((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF);
|
|
||||||
rc = 1;
|
|
||||||
} else {
|
|
||||||
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void zmk_rgb_underglow_set_layer(uint8_t layer) {
|
|
||||||
if (!state.layer_enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const struct zmk_behavior_binding *rgbmap = rgb_underglow_get_bindings(layer);
|
|
||||||
if (rgbmap != NULL && zmk_rgb_underglow_apply_rgbmap(rgbmap, ZMK_KEYMAP_LEN)) {
|
|
||||||
if (!state.on)
|
|
||||||
zmk_rgb_underglow_transient_on();
|
|
||||||
zmk_led_write_pixels();
|
|
||||||
} else {
|
|
||||||
if (state.on)
|
|
||||||
zmk_rgb_underglow_transient_off();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* IS_ENABLED(UNDERGLOW_LAYER_ENABLED) */
|
|
||||||
|
|
||||||
static void zmk_rgb_underglow_tick(struct k_work *work) {
|
static void zmk_rgb_underglow_tick(struct k_work *work) {
|
||||||
switch (state.current_effect) {
|
switch (state.current_effect) {
|
||||||
case UNDERGLOW_EFFECT_SOLID:
|
case UNDERGLOW_EFFECT_SOLID:
|
||||||
|
|
@ -526,6 +480,11 @@ static void zmk_rgb_underglow_tick(struct k_work *work) {
|
||||||
case UNDERGLOW_EFFECT_SWIRL:
|
case UNDERGLOW_EFFECT_SWIRL:
|
||||||
zmk_rgb_underglow_effect_swirl();
|
zmk_rgb_underglow_effect_swirl();
|
||||||
break;
|
break;
|
||||||
|
#if IS_ENABLED(UNDERGLOW_LAYER_ENABLED)
|
||||||
|
case UNDERGLOW_EFFECT_LAYER_INDICATORS:
|
||||||
|
zmk_rgb_underglow_effect_layer();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
zmk_led_write_pixels();
|
zmk_led_write_pixels();
|
||||||
|
|
@ -534,7 +493,7 @@ static void zmk_rgb_underglow_tick(struct k_work *work) {
|
||||||
K_WORK_DEFINE(underglow_tick_work, zmk_rgb_underglow_tick);
|
K_WORK_DEFINE(underglow_tick_work, zmk_rgb_underglow_tick);
|
||||||
|
|
||||||
static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
|
static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
|
||||||
if (!state.on || state.layer_enabled) {
|
if (!state.on) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -547,7 +506,6 @@ K_TIMER_DEFINE(underglow_tick, zmk_rgb_underglow_tick_handler, NULL);
|
||||||
static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||||
const char *next;
|
const char *next;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (settings_name_steq(name, "state", &next) && !next) {
|
if (settings_name_steq(name, "state", &next) && !next) {
|
||||||
if (len != sizeof(state)) {
|
if (len != sizeof(state)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -583,7 +541,6 @@ static struct k_work_delayable underglow_save_work;
|
||||||
|
|
||||||
static int zmk_rgb_underglow_init(void) {
|
static int zmk_rgb_underglow_init(void) {
|
||||||
led_strip = DEVICE_DT_GET(STRIP_CHOSEN);
|
led_strip = DEVICE_DT_GET(STRIP_CHOSEN);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
||||||
if (!device_is_ready(ext_power)) {
|
if (!device_is_ready(ext_power)) {
|
||||||
LOG_ERR("External power device \"%s\" is not ready", ext_power->name);
|
LOG_ERR("External power device \"%s\" is not ready", ext_power->name);
|
||||||
|
|
@ -752,6 +709,77 @@ int zmk_rgb_underglow_toggle(void) {
|
||||||
return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on();
|
return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(UNDERGLOW_LAYER_ENABLED)
|
||||||
|
|
||||||
|
static struct led_rgb hex_to_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
struct zmk_led_hsb hsb = state.color;
|
||||||
|
return (struct led_rgb){
|
||||||
|
r : (hsb.b * (r)) / 0xff,
|
||||||
|
g : (hsb.b * (g)) / 0xff,
|
||||||
|
b : (hsb.b * (b)) / 0xff
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zmk_rgb_underglow_apply_rgbmap(const struct zmk_behavior_binding *bindings,
|
||||||
|
size_t rgbmap_len) {
|
||||||
|
int rc = 0;
|
||||||
|
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||||
|
uint8_t midx = rgb_pixel_lookup(i);
|
||||||
|
if (midx >= ZMK_KEYMAP_LEN) {
|
||||||
|
LOG_DBG("out of range");
|
||||||
|
} else {
|
||||||
|
const struct device *dev = zmk_behavior_get_binding(bindings[midx].behavior_dev);
|
||||||
|
|
||||||
|
if (dev == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
||||||
|
|
||||||
|
if (api->binding_pressed == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
struct zmk_behavior_binding_event event = {.position = midx,
|
||||||
|
.timestamp = k_uptime_get()};
|
||||||
|
|
||||||
|
int color = api->binding_pressed((struct zmk_behavior_binding *)&bindings[midx], event);
|
||||||
|
|
||||||
|
if (color > 0) {
|
||||||
|
pixels[i] =
|
||||||
|
hex_to_rgb((color & 0xFF0000) >> 16, (color & 0xFF00) >> 8, color & 0xFF);
|
||||||
|
rc = 1;
|
||||||
|
} else {
|
||||||
|
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zmk_rgb_underglow_set_layer(uint8_t layer) {
|
||||||
|
LOG_DBG("state.layer: %d state.on: %d", state.layer_enabled, state.on);
|
||||||
|
if (!state.layer_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const struct zmk_behavior_binding *rgbmap = rgb_underglow_get_bindings(layer);
|
||||||
|
if (rgbmap != NULL && zmk_rgb_underglow_apply_rgbmap(rgbmap, ZMK_KEYMAP_LEN)) {
|
||||||
|
if (!state.on)
|
||||||
|
zmk_rgb_underglow_transient_on();
|
||||||
|
k_timer_stop(&underglow_tick);
|
||||||
|
state.animation_step = 0;
|
||||||
|
int fade_delay = zmk_rgbmap_fade_delay(layer);
|
||||||
|
if (fade_delay >= 0) {
|
||||||
|
k_timer_start(&underglow_tick, K_SECONDS(fade_delay), K_MSEC(50));
|
||||||
|
}
|
||||||
|
LOG_DBG("write pixels");
|
||||||
|
zmk_led_write_pixels();
|
||||||
|
} else {
|
||||||
|
if (state.on)
|
||||||
|
zmk_rgb_underglow_transient_off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* IS_ENABLED(UNDERGLOW_LAYER_ENABLED) */
|
||||||
|
|
||||||
static void zmk_led_write_pixels_work(struct k_work *work);
|
static void zmk_led_write_pixels_work(struct k_work *work);
|
||||||
static void zmk_rgb_underglow_status_update(struct k_timer *timer);
|
static void zmk_rgb_underglow_status_update(struct k_timer *timer);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#define UNDERGLOW_LAYER_ENABLED
|
#define UNDERGLOW_LAYER_ENABLED
|
||||||
#define LAYER_ID(node) DT_PROP(node, layer_id)
|
#define LAYER_ID(node) DT_PROP(node, layer_id)
|
||||||
|
#define FADE_DELAY(node) DT_PROP(node, fade_delay)
|
||||||
|
|
||||||
#define TRANSFORMED_RGB_LAYER(node) \
|
#define TRANSFORMED_RGB_LAYER(node) \
|
||||||
{COND_CODE_1(DT_NODE_HAS_PROP(node, bindings), \
|
{COND_CODE_1(DT_NODE_HAS_PROP(node, bindings), \
|
||||||
|
|
@ -39,6 +40,7 @@ RGBMAP_VAR(zmk_rgbmap, COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE
|
||||||
const int pixel_lookup_table[] = DT_INST_PROP(0, pixel_lookup);
|
const int pixel_lookup_table[] = DT_INST_PROP(0, pixel_lookup);
|
||||||
|
|
||||||
static int zmk_rgbmap_ids[ZMK_RGBMAP_LAYERS_LEN] = {DT_INST_FOREACH_CHILD_SEP(0, LAYER_ID, (, ))};
|
static int zmk_rgbmap_ids[ZMK_RGBMAP_LAYERS_LEN] = {DT_INST_FOREACH_CHILD_SEP(0, LAYER_ID, (, ))};
|
||||||
|
static int zmk_rgbmap_fds[ZMK_RGBMAP_LAYERS_LEN] = {DT_INST_FOREACH_CHILD_SEP(0, FADE_DELAY, (, ))};
|
||||||
|
|
||||||
const int rgb_pixel_lookup(int idx) { return pixel_lookup_table[idx]; };
|
const int rgb_pixel_lookup(int idx) { return pixel_lookup_table[idx]; };
|
||||||
|
|
||||||
|
|
@ -51,6 +53,8 @@ const int zmk_rgbmap_id(uint8_t layer) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int zmk_rgbmap_fade_delay(uint8_t layer) { return zmk_rgbmap_fds[zmk_rgbmap_id(layer)]; }
|
||||||
|
|
||||||
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer) {
|
const struct zmk_behavior_binding *rgb_underglow_get_bindings(uint8_t layer) {
|
||||||
int rgblayer = zmk_rgbmap_id(layer);
|
int rgblayer = zmk_rgbmap_id(layer);
|
||||||
if (rgblayer == -1) {
|
if (rgblayer == -1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue