#include #include #include #include #include #include "led_effect/led_effect.h" #define KEY_FADE_LEVEL_MAX 255U #define KEY_FADE_STEP_PER_TICK 12U struct led_effect_key_fade_state { const struct led_key_map *key_map; size_t key_map_len; size_t pixel_count; uint8_t default_brightness; uint8_t level[17]; struct theme_rgb theme; }; static struct led_effect_key_fade_state key_fade_state; static const struct led_key_map *find_key(const struct led_effect *effect, uint16_t key_id) { const struct led_effect_key_fade_state *state = effect->state; for (size_t i = 0; i < state->key_map_len; i++) { if (state->key_map[i].key_id == key_id) { return &state->key_map[i]; } } return NULL; } static int led_effect_key_fade_init(struct led_effect *effect, const struct led_effect_config *cfg) { struct led_effect_key_fade_state *state = effect->state; if ((effect == NULL) || (cfg == NULL) || (cfg->key_map == NULL) || (cfg->pixel_count > ARRAY_SIZE(state->level))) { return -EINVAL; } memset(state, 0, sizeof(*state)); state->key_map = cfg->key_map; state->key_map_len = cfg->key_map_len; state->pixel_count = cfg->pixel_count; state->default_brightness = cfg->default_brightness; state->theme.r = BLINKY_THEME_DEFAULT_R; state->theme.g = BLINKY_THEME_DEFAULT_G; state->theme.b = BLINKY_THEME_DEFAULT_B; return 0; } static void led_effect_key_fade_reset(struct led_effect *effect) { struct led_effect_key_fade_state *state = effect->state; memset(state->level, 0, sizeof(state->level)); } static void led_effect_key_fade_set_theme(struct led_effect *effect, const struct theme_rgb *theme) { struct led_effect_key_fade_state *state = effect->state; if (theme == NULL) { return; } state->theme = *theme; } static void led_effect_key_fade_on_key_press(struct led_effect *effect, uint16_t key_id) { struct led_effect_key_fade_state *state = effect->state; const struct led_key_map *map = find_key(effect, key_id); if ((map == NULL) || (map->led_idx >= state->pixel_count)) { return; } state->level[map->led_idx] = (state->default_brightness == 0U) ? KEY_FADE_LEVEL_MAX : state->default_brightness; } static bool led_effect_key_fade_tick(struct led_effect *effect, uint32_t dt_ms, struct led_rgb *pixels, size_t pixel_count) { struct led_effect_key_fade_state *state = effect->state; bool active = false; bool visible = false; uint8_t decay; ARG_UNUSED(dt_ms); if ((pixels == NULL) || (pixel_count < state->pixel_count)) { return false; } memset(pixels, 0, sizeof(*pixels) * pixel_count); decay = KEY_FADE_STEP_PER_TICK; for (size_t i = 0; i < state->pixel_count; i++) { uint8_t level = state->level[i]; if (level == 0U) { continue; } visible = true; pixels[i].r = (uint8_t)(((uint16_t)state->theme.r * level) / 255U); pixels[i].g = (uint8_t)(((uint16_t)state->theme.g * level) / 255U); pixels[i].b = (uint8_t)(((uint16_t)state->theme.b * level) / 255U); state->level[i] = (level > decay) ? (uint8_t)(level - decay) : 0U; active = active || (state->level[i] > 0U); } return visible || active; } static bool led_effect_key_fade_is_active(const struct led_effect *effect) { const struct led_effect_key_fade_state *state = effect->state; for (size_t i = 0; i < state->pixel_count; i++) { if (state->level[i] > 0U) { return true; } } return false; } static const struct led_effect_ops key_fade_ops = { .init = led_effect_key_fade_init, .reset = led_effect_key_fade_reset, .set_theme = led_effect_key_fade_set_theme, .on_key_press = led_effect_key_fade_on_key_press, .tick = led_effect_key_fade_tick, .is_active = led_effect_key_fade_is_active, }; struct led_effect led_effect_key_fade = { .ops = &key_fade_ops, .state = &key_fade_state, };