#include #include #include #include #define MODULE led_strip_module #include #include #include #include #include #include #include #include "led_strip_en_event.h" LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF); #define LED_STRIP_NODE DT_CHOSEN(zephyr_led_strip) #define LED_STRIP_NUM_PIXELS DT_PROP(LED_STRIP_NODE, chain_length) #define LED_STRIP_EFFECT_INTERVAL K_MSEC(400) BUILD_ASSERT(DT_NODE_HAS_STATUS(LED_STRIP_NODE, okay), "Missing zephyr,led-strip chosen node"); BUILD_ASSERT(DT_NODE_HAS_PROP(LED_STRIP_NODE, supply_gpios), "Missing supply-gpios on zephyr,led-strip node"); static const struct device *const strip = DEVICE_DT_GET(LED_STRIP_NODE); static const struct gpio_dt_spec strip_en = GPIO_DT_SPEC_GET(LED_STRIP_NODE, supply_gpios); static struct led_rgb pixels[LED_STRIP_NUM_PIXELS]; static struct k_work_delayable effect_work; static bool initialized; static bool running; static bool enabled = true; static uint8_t effect_step; static void clear_pixels(void) { memset(pixels, 0, sizeof(pixels)); } static void fill_pixels(uint8_t r, uint8_t g, uint8_t b) { for (size_t i = 0; i < ARRAY_SIZE(pixels); i++) { pixels[i].r = r; pixels[i].g = g; pixels[i].b = b; } } static int submit_frame(void) { int err; err = led_strip_update_rgb(strip, pixels, ARRAY_SIZE(pixels)); if (err) { LOG_WRN("led_strip_update_rgb failed (%d)", err); } return err; } static int set_strip_power(bool on) { int err; err = gpio_pin_set_dt(&strip_en, on ? 1 : 0); if (err) { LOG_WRN("LED strip EN set failed (%d)", err); } return err; } static void render_effect_step(void) { switch (effect_step) { case 0U: fill_pixels(0x40, 0x00, 0x00); break; case 1U: fill_pixels(0x00, 0x40, 0x00); break; default: fill_pixels(0x00, 0x00, 0x40); break; } } static void effect_work_handler(struct k_work *work) { ARG_UNUSED(work); if (!running || !enabled) { return; } render_effect_step(); (void)submit_frame(); effect_step = (uint8_t)((effect_step + 1U) % 3U); k_work_reschedule(&effect_work, LED_STRIP_EFFECT_INTERVAL); } static int enable_effect_output(void) { int err; err = set_strip_power(true); if (err) { return err; } render_effect_step(); err = submit_frame(); if (err) { return err; } k_work_reschedule(&effect_work, LED_STRIP_EFFECT_INTERVAL); return 0; } static void disable_effect_output(void) { k_work_cancel_delayable(&effect_work); clear_pixels(); (void)submit_frame(); (void)set_strip_power(false); } static int module_init(void) { int err; if (!device_is_ready(strip)) { LOG_ERR("LED strip device %s not ready", strip->name); return -ENODEV; } if (!gpio_is_ready_dt(&strip_en)) { LOG_ERR("LED strip EN GPIO not ready"); return -ENODEV; } err = gpio_pin_configure_dt(&strip_en, GPIO_OUTPUT_INACTIVE); if (err) { LOG_ERR("Failed to configure LED strip EN (%d)", err); return err; } k_work_init_delayable(&effect_work, effect_work_handler); clear_pixels(); effect_step = 0U; LOG_INF("LED strip ready len:%u", (uint32_t)led_strip_length(strip)); return 0; } static int module_start(void) { int err; if (running) { return 0; } running = true; if (!enabled) { return 0; } err = enable_effect_output(); if (err) { running = false; } return err; } static void module_pause(void) { if (!running) { return; } disable_effect_output(); running = false; } static bool handle_led_strip_en_event(const struct led_strip_en_event *event) { enabled = event->enabled; if (!running) { return false; } if (enabled) { int err = enable_effect_output(); if (err) { module_set_state(MODULE_STATE_ERROR); } } else { disable_effect_output(); } return false; } static bool app_event_handler(const struct app_event_header *aeh) { if (is_led_strip_en_event(aeh)) { return handle_led_strip_en_event(cast_led_strip_en_event(aeh)); } if (is_module_state_event(aeh)) { const struct module_state_event *event = cast_module_state_event(aeh); if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) { int err; if (!initialized) { err = module_init(); if (err) { module_set_state(MODULE_STATE_ERROR); return false; } initialized = true; } err = module_start(); if (err) { module_set_state(MODULE_STATE_ERROR); } else { module_set_state(MODULE_STATE_READY); } } return false; } if (is_power_down_event(aeh)) { if (initialized) { module_pause(); module_set_state(MODULE_STATE_STANDBY); } return false; } if (is_wake_up_event(aeh)) { if (initialized) { int err = module_start(); if (err) { module_set_state(MODULE_STATE_ERROR); } else { module_set_state(MODULE_STATE_READY); } } return false; } return false; } APP_EVENT_LISTENER(MODULE, app_event_handler); APP_EVENT_SUBSCRIBE(MODULE, led_strip_en_event); APP_EVENT_SUBSCRIBE(MODULE, module_state_event); APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event); APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);