From 3a5e91c4bf63ba680c2a31ad1168d2eebeb519e3 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 21 May 2026 10:24:42 +0300 Subject: [PATCH] Third --- src/button.cpp | 49 ------------------------ src/button.hpp | 25 ------------ src/buttons.c | 44 ++++++++++++++++++++++ src/buttons.h | 20 ++++++++++ src/config.c | 13 ++++--- src/config.h | 8 ++-- src/config_shell.c | 92 ++++++++++++++++++++------------------------- src/imu.h | 2 +- src/led.c | 56 +++++++++++++++++++++++++-- src/led.h | 3 +- src/led_shell.c | 19 ++++++++-- src/main.c | 3 ++ src/mode.c | 89 +++++++++++++++++++++++++++++++++++++++++++ src/mode.h | 21 +++++++++++ src/mode_shell.c | 50 ++++++++++++++++++++++++ src/zbus_channels.c | 2 +- src/zbus_channels.h | 2 +- 17 files changed, 350 insertions(+), 148 deletions(-) delete mode 100644 src/button.cpp delete mode 100644 src/button.hpp create mode 100644 src/buttons.c create mode 100644 src/buttons.h create mode 100644 src/mode.c create mode 100644 src/mode.h create mode 100644 src/mode_shell.c diff --git a/src/button.cpp b/src/button.cpp deleted file mode 100644 index ff2719a..0000000 --- a/src/button.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "buttons.hpp" -#include -#include -#include - -LOG_MODULE_REGISTER(buttons, CONFIG_LOG_MAX_LEVEL); -K_WORK_DELAYABLE_DEFINE(debounce_work_btn, Buttons::debounce_cb); -#define DEBOUNCE_TIME_MS 100 - -static const struct gpio_dt_spec Buttons::buttons[Buttons::NR_BUTTONS] = { - GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_1), gpios, {0}), - GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_2), gpios, {0}) -}; -static struct gpio_callback Buttons::buttons_cb_data[Buttons::NR_BUTTONS]; - -Buttons::Buttons() { - buttons_init(); -} - -int Buttons::buttons_init() { - // BUTTON 1 - gpio_pin_configure_dt(&buttons[BUTTON1], GPIO_INPUT); - gpio_pin_interrupt_configure_dt(&(buttons[BUTTON1]), GPIO_INT_EDGE_TO_ACTIVE); - gpio_init_callback(&buttons_cb_data[0], buttons_cb, BIT(buttons[BUTTON1].pin)); - gpio_add_callback(buttons[BUTTON1].port, &buttons_cb_data[0]); - - // BUTTON 2 - gpio_pin_configure_dt(&buttons[BUTTON2], GPIO_INPUT); - gpio_pin_interrupt_configure_dt(&buttons[BUTTON2], GPIO_INT_EDGE_TO_ACTIVE); - gpio_init_callback(&buttons_cb_data[1], buttons_cb, BIT(buttons[BUTTON2].pin)); - gpio_add_callback(buttons[BUTTON2].port, &buttons_cb_data[1]); - - return 0; -} - -static void Buttons::debounce_cb(struct k_work *work) { - if ( gpio_pin_get_dt(&buttons[BUTTON1]) == GPIO_ACTIVE_HIGH || - gpio_pin_get_dt(&buttons[BUTTON2]) == GPIO_ACTIVE_HIGH) { - LOG_DBG("Callback"); - } -} - -static void Buttons::buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { - LOG_DBG("Button:"); - if (k_work_delayable_is_pending(&debounce_work_btn)) { - } else { - k_work_schedule(&debounce_work_btn, K_MSEC(DEBOUNCE_TIME_MS)); - } -} \ No newline at end of file diff --git a/src/button.hpp b/src/button.hpp deleted file mode 100644 index cbef963..0000000 --- a/src/button.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - - -#include - - -class Buttons { -public: - - enum Buttons_e { - BUTTON1, - BUTTON2, - NR_BUTTONS, - }; - - Buttons(); - ~Buttons(); - int buttons_init(); - static void buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins); - static void debounce_cb(struct k_work *work); - -private: - static const struct gpio_dt_spec buttons[NR_BUTTONS]; - static struct gpio_callback buttons_cb_data[NR_BUTTONS]; -}; \ No newline at end of file diff --git a/src/buttons.c b/src/buttons.c new file mode 100644 index 0000000..ea431a8 --- /dev/null +++ b/src/buttons.c @@ -0,0 +1,44 @@ +#include "buttons.h" +#include +#include +#include + +LOG_MODULE_REGISTER(buttons, CONFIG_LOG_MAX_LEVEL); +K_WORK_DELAYABLE_DEFINE(debounce_work_btn, debounce_cb); +#define DEBOUNCE_TIME_MS 100 + +static const struct gpio_dt_spec buttons[NR_BUTTONS] = { + GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_1), gpios, {0}), + GPIO_DT_SPEC_GET_OR(DT_ALIAS(int_btn_2), gpios, {0}), +}; +static struct gpio_callback buttons_cb_data[NR_BUTTONS]; + +int buttons_init(void) { + // BUTTON 1 + gpio_pin_configure_dt(&buttons[BUTTON1], GPIO_INPUT); + gpio_pin_interrupt_configure_dt(&buttons[BUTTON1], GPIO_INT_EDGE_TO_ACTIVE); + gpio_init_callback(&buttons_cb_data[0], buttons_cb, BIT(buttons[BUTTON1].pin)); + gpio_add_callback(buttons[BUTTON1].port, &buttons_cb_data[0]); + + // BUTTON 2 + gpio_pin_configure_dt(&buttons[BUTTON2], GPIO_INPUT); + gpio_pin_interrupt_configure_dt(&buttons[BUTTON2], GPIO_INT_EDGE_TO_ACTIVE); + gpio_init_callback(&buttons_cb_data[1], buttons_cb, BIT(buttons[BUTTON2].pin)); + gpio_add_callback(buttons[BUTTON2].port, &buttons_cb_data[1]); + + return 0; +} + +void debounce_cb(struct k_work *work) { + if (gpio_pin_get_dt(&buttons[BUTTON1]) == GPIO_ACTIVE_HIGH || + gpio_pin_get_dt(&buttons[BUTTON2]) == GPIO_ACTIVE_HIGH) { + LOG_DBG("Callback"); + } +} + +void buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { + LOG_DBG("Button:"); + if (!k_work_delayable_is_pending(&debounce_work_btn)) { + k_work_schedule(&debounce_work_btn, K_MSEC(DEBOUNCE_TIME_MS)); + } +} diff --git a/src/buttons.h b/src/buttons.h new file mode 100644 index 0000000..102fcbf --- /dev/null +++ b/src/buttons.h @@ -0,0 +1,20 @@ +#ifndef BUTTON_H +#define BUTTON_H + + + +#include + +typedef enum { + BUTTON1, + BUTTON2, + NR_BUTTONS, +} buttons_e; + +int buttons_init(void); +void buttons_cb(const struct device *dev, struct gpio_callback *cb, uint32_t pins); +void debounce_cb(struct k_work *work); + + + +#endif // BUTTON_H diff --git a/src/config.c b/src/config.c index c057678..cd9baa2 100644 --- a/src/config.c +++ b/src/config.c @@ -10,15 +10,16 @@ static struct nvs_fs nvs; static app_config_t ram_config; #define CONFIG_ID 0xDEADBEEF -#define CONFIG_VERSION 1 +#define CONFIG_VERSION 2 + static const app_config_t default_config = { .id = CONFIG_ID, .version = CONFIG_VERSION, - .device_name = "my-device", - .baud_rate = 115200, - .log_level = 3, - .feature_enabled = false, + .mode_config = { + .phase_a_ms = (20 * 60 * 1000), + .phase_a_ms = (20 * 1000), + }, }; int config_init(void) @@ -61,4 +62,4 @@ void config_update(void) void config_get(app_config_t *cfg) { *cfg = ram_config; -} \ No newline at end of file +} diff --git a/src/config.h b/src/config.h index 82e8fb3..fc2d642 100644 --- a/src/config.h +++ b/src/config.h @@ -3,14 +3,12 @@ #include #include +#include "mode.h" typedef struct { uint32_t id; uint16_t version; - char device_name[32]; - uint32_t baud_rate; - uint8_t log_level; - bool feature_enabled; + struct mode_config mode_config; } app_config_t; int config_init(void); @@ -18,4 +16,4 @@ int config_save(const app_config_t *cfg); void config_update(void); void config_get(app_config_t *cfg); -#endif /* CONFIG_H */ \ No newline at end of file +#endif /* CONFIG_H */ diff --git a/src/config_shell.c b/src/config_shell.c index 26df794..ee107e5 100644 --- a/src/config_shell.c +++ b/src/config_shell.c @@ -1,62 +1,50 @@ -#include +#include "mode.h" #include "config.h" +#include +#include -static int cmd_config_read(const struct shell *sh, size_t argc, char **argv) +static int cmd_start(const struct shell *sh, size_t argc, char **argv) { - ARG_UNUSED(argc); - ARG_UNUSED(argv); - - app_config_t cfg; - config_get(&cfg); - - shell_print(sh, "device_name: %s", cfg.device_name); - shell_print(sh, "baud_rate: %u", cfg.baud_rate); - shell_print(sh, "log_level: %u", cfg.log_level); - shell_print(sh, "feature_enabled: %s", cfg.feature_enabled ? "true" : "false"); - - return 0; + mode_start(); + return 0; } - -static int cmd_config_update(const struct shell *sh, size_t argc, char **argv) + +static int cmd_stop(const struct shell *sh, size_t argc, char **argv) { - ARG_UNUSED(argc); - ARG_UNUSED(argv); - - config_update(); - shell_print(sh, "Config refreshed from NVS"); - - return 0; + mode_stop(); + return 0; } - -static int cmd_config_baud(const struct shell *sh, size_t argc, char **argv) + +static int cmd_restart(const struct shell *sh, size_t argc, char **argv) { - if (argc != 2) { - shell_error(sh, "Usage: config baud "); - return -EINVAL; - } - - uint32_t baud = (uint32_t)strtoul(argv[1], NULL, 10); - if (baud == 0) { - shell_error(sh, "Invalid baud rate"); - return -EINVAL; - } - - app_config_t cfg; - config_get(&cfg); - cfg.baud_rate = baud; - config_save(&cfg); - - shell_print(sh, "Baud rate updated to %u", baud); - - return 0; + mode_restart(); + return 0; } - -SHELL_STATIC_SUBCMD_SET_CREATE(config_cmds, - SHELL_CMD(read, NULL, "Print config from RAM", cmd_config_read), - SHELL_CMD(update, NULL, "Refresh RAM config from NVS", cmd_config_update), - SHELL_CMD(baud, NULL, "Set baud rate: config baud ", cmd_config_baud), - SHELL_SUBCMD_SET_END + +/* mode init */ +static int cmd_init(const struct shell *sh, size_t argc, char **argv) +{ + app_config_t app_cfg; + + config_get(&app_cfg); + app_cfg.mode_config.phase_a_ms = atoi(argv[1]); + app_cfg.mode_config.phase_b_ms = atoi(argv[2]); + config_save(&app_cfg); + + mode_init(); + mode_restart(); + + shell_print(sh, "Config saved. phase_a=%s ms, phase_b=%s ms. Restarting.", argv[1], argv[2]); + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(mode_cmds, + SHELL_CMD(start, NULL, "Start the mode thread.", cmd_start), + SHELL_CMD(stop, NULL, "Stop the mode thread.", cmd_stop), + SHELL_CMD(restart, NULL, "Restart the mode thread.", cmd_restart), + SHELL_CMD_ARG(init, NULL, "Set , save and restart.", cmd_init, 3, 0), + SHELL_SUBCMD_SET_END ); - -SHELL_CMD_REGISTER(config, &config_cmds, "Config commands", NULL); \ No newline at end of file + +SHELL_CMD_REGISTER(mode, &mode_cmds, "Mode control.", NULL); diff --git a/src/imu.h b/src/imu.h index f4efb3a..4a986cd 100644 --- a/src/imu.h +++ b/src/imu.h @@ -18,4 +18,4 @@ static void debounce_cb(struct k_work *work); -#endif // IMU_H \ No newline at end of file +#endif // IMU_H diff --git a/src/led.c b/src/led.c index 68522dd..43f6653 100644 --- a/src/led.c +++ b/src/led.c @@ -17,6 +17,11 @@ LOG_MODULE_REGISTER(leds, LOG_LEVEL_INF); static const struct device *const strip = DEVICE_DT_GET(STRIP_NODE); static struct led_rgb pixels[STRIP_NUM_PIXELS]; +// Saved RGB state for the LED strip +static float saved_r = 0.0f; +static float saved_g = 0.0f; +static float saved_b = 0.0f; + #define NR_LEDS 8 #define PWM_RESOLUTION 255 @@ -145,6 +150,10 @@ int leds_set_all(float r, float g, float b) { pixels[i].b = b * STRIP_MAX_BRIGHTNESS; } + saved_r = r; + saved_g = g; + saved_b = b; + return 0; } @@ -163,9 +172,6 @@ int leds_clear(void) { } - - - int leds_fade(uint32_t duration, float r, float g, float b) { uint32_t step_duration = (duration * 1000) / (STRIP_MAX_BRIGHTNESS * 2); @@ -182,6 +188,10 @@ int leds_fade(uint32_t duration, float r, float g, float b) { k_sleep(K_USEC(step_duration)); } + saved_r = 0.0f; + saved_g = 0.0f; + saved_b = 0.0f; + return 0; } @@ -194,6 +204,11 @@ int leds_fade_in(uint32_t duration, float r, float g, float b) { leds_update(); k_sleep(K_USEC(step_duration)); } + + saved_r = r; + saved_g = g; + saved_b = b; + return 0; } @@ -207,5 +222,40 @@ int leds_fade_out(uint32_t duration, float r, float g, float b) { k_sleep(K_USEC(step_duration)); } + saved_r = 0.0f; + saved_g = 0.0f; + saved_b = 0.0f; + return 0; } + +int leds_fade_to(uint32_t duration, float r, float g, float b) { + // Resolve target channels — -1 means keep the saved value + float target_r = (r < 0.0f) ? saved_r : r; + float target_g = (g < 0.0f) ? saved_g : g; + float target_b = (b < 0.0f) ? saved_b : b; + + float from_r = saved_r; + float from_g = saved_g; + float from_b = saved_b; + + uint32_t step_duration = (duration * 1000) / STRIP_MAX_BRIGHTNESS; + + for (int i = 0; i <= STRIP_MAX_BRIGHTNESS; i++) { + float t = (float)i / STRIP_MAX_BRIGHTNESS; + leds_set_all( + from_r + t * (target_r - from_r), + from_g + t * (target_g - from_g), + from_b + t * (target_b - from_b) + ); + leds_update(); + k_sleep(K_USEC(step_duration)); + } + + // leds_set_all already saved the final color, but set explicitly for clarity + saved_r = target_r; + saved_g = target_g; + saved_b = target_b; + + return 0; +} diff --git a/src/led.h b/src/led.h index 34567bf..e91364f 100644 --- a/src/led.h +++ b/src/led.h @@ -17,6 +17,7 @@ int leds_clear(void); int leds_fade(uint32_t duration, float r, float g, float b); int leds_fade_in(uint32_t duration, float r, float g, float b); int leds_fade_out(uint32_t duration, float r, float g, float b); +int leds_fade_to(uint32_t duration, float r, float g, float b); -#endif // LED_H \ No newline at end of file +#endif // LED_H diff --git a/src/led_shell.c b/src/led_shell.c index e50df94..0509764 100644 --- a/src/led_shell.c +++ b/src/led_shell.c @@ -45,10 +45,21 @@ static int cmd_leds_clear(const struct shell *sh, size_t argc, char **argv) return leds_clear(); } +static int cmd_leds_fade_to(const struct shell *sh, size_t argc, char **argv) +{ + if (argc != 5) { shell_error(sh, "Usage: leds fade_to (0-255, -1 to keep)"); return -EINVAL; } + return leds_fade_to(atoi(argv[1]), + atoi(argv[2]) < 0 ? -1.0f : atoi(argv[2]) / 255.0f, + atoi(argv[3]) < 0 ? -1.0f : atoi(argv[3]) / 255.0f, + atoi(argv[4]) < 0 ? -1.0f : atoi(argv[4]) / 255.0f); +} + SHELL_STATIC_SUBCMD_SET_CREATE(leds_cmds, - SHELL_CMD(all, NULL, "Set all ", cmd_leds_all), - SHELL_CMD(clear, NULL, "Clear all", cmd_leds_clear), - SHELL_CMD(fade, NULL, "Fade to ", cmd_leds_fade), + SHELL_CMD(all, NULL, "Set all ", cmd_leds_all), + SHELL_CMD(clear, NULL, "Clear all", cmd_leds_clear), + SHELL_CMD(fade, NULL, "Fade in/out ", cmd_leds_fade), + SHELL_CMD(fade_to, NULL, "Fade to color ", cmd_leds_fade_to), SHELL_SUBCMD_SET_END ); -SHELL_CMD_REGISTER(leds, &leds_cmds, "Addressable LED commands", NULL); \ No newline at end of file + +SHELL_CMD_REGISTER(leds, &leds_cmds, "Addressable LED commands", NULL); diff --git a/src/main.c b/src/main.c index 4d78863..67267ec 100644 --- a/src/main.c +++ b/src/main.c @@ -32,6 +32,9 @@ int main(void) ret = led_init(); ret = imu_init(); + mode_init(); + mode_start(); + while (1) { // for (int i = 0; i < 10000; i++) { // led_set_progress((float)i / 10000.0); diff --git a/src/mode.c b/src/mode.c new file mode 100644 index 0000000..364575e --- /dev/null +++ b/src/mode.c @@ -0,0 +1,89 @@ +#include "mode.h" +#include "config.h" +#include "led.h" + +#include +#include + +LOG_MODULE_REGISTER(mode, LOG_LEVEL_INF); + +#define POLL_MS 100 + +K_THREAD_STACK_DEFINE(mode_stack, 1024); +static struct k_thread mode_thread; +static atomic_t running = ATOMIC_INIT(0); + +static struct mode_config cfg; + +static void mode_thread_fn(void *p1, void *p2, void *p3) +{ + while (atomic_get(&running)) { + /* --- Phase A --- */ + int64_t start = k_uptime_get(); + while (atomic_get(&running) && k_uptime_get() - start < cfg.phase_a_ms) { + float progress = (float)(k_uptime_get() - start) / cfg.phase_a_ms; + LOG_DBG("Phase A: %.2f", (double)progress); + led_set_progress(progress); + /* do phase A work here */ + k_msleep(POLL_MS); + } + led_set_progress(0); + + /* --- Phase B --- */ + start = k_uptime_get(); + while (atomic_get(&running) && k_uptime_get() - start < cfg.phase_b_ms) { + float progress = (float)(k_uptime_get() - start) / cfg.phase_b_ms; + LOG_DBG("Phase B: %.2f", (double)progress); + leds_fade_to(500, 1, -1, -1); + leds_fade_to(500, -1, 1, -1); + leds_fade_to(500, -1, 0, -1); + leds_fade_to(500, 0, -1, -1); + /* do phase B work here */ + // k_msleep(POLL_MS); + } + } + + LOG_INF("Mode thread stopped."); +} + +void mode_init(void) +{ + app_config_t app_cfg; + + config_init(); + config_get(&app_cfg); + + cfg = app_cfg.mode_config; + + LOG_INF("Mode init: phase_a=%d ms, phase_b=%d ms", cfg.phase_a_ms, cfg.phase_b_ms); +} + +void mode_start(void) +{ + if (atomic_cas(&running, 0, 1)) { + k_thread_create(&mode_thread, mode_stack, + K_THREAD_STACK_SIZEOF(mode_stack), + mode_thread_fn, NULL, NULL, NULL, + 5, 0, K_NO_WAIT); + k_thread_name_set(&mode_thread, "mode"); + LOG_INF("Mode started."); + } else { + LOG_WRN("Mode already running."); + } +} + +void mode_stop(void) +{ + if (atomic_cas(&running, 1, 0)) { + k_thread_join(&mode_thread, K_FOREVER); + LOG_INF("Mode stopped."); + } else { + LOG_WRN("Mode not running."); + } +} + +void mode_restart(void) +{ + mode_stop(); + mode_start(); +} diff --git a/src/mode.h b/src/mode.h new file mode 100644 index 0000000..abd85d3 --- /dev/null +++ b/src/mode.h @@ -0,0 +1,21 @@ +#ifndef MODE_H +#define MODE_H + + + +#include + + +struct mode_config { + int32_t phase_a_ms; + int32_t phase_b_ms; +}; + +void mode_init(void); +void mode_start(void); +void mode_stop(void); +void mode_restart(void); + + + +#endif /* MODE_H */ diff --git a/src/mode_shell.c b/src/mode_shell.c new file mode 100644 index 0000000..ee107e5 --- /dev/null +++ b/src/mode_shell.c @@ -0,0 +1,50 @@ +#include "mode.h" +#include "config.h" + +#include +#include + +static int cmd_start(const struct shell *sh, size_t argc, char **argv) +{ + mode_start(); + return 0; +} + +static int cmd_stop(const struct shell *sh, size_t argc, char **argv) +{ + mode_stop(); + return 0; +} + +static int cmd_restart(const struct shell *sh, size_t argc, char **argv) +{ + mode_restart(); + return 0; +} + +/* mode init */ +static int cmd_init(const struct shell *sh, size_t argc, char **argv) +{ + app_config_t app_cfg; + + config_get(&app_cfg); + app_cfg.mode_config.phase_a_ms = atoi(argv[1]); + app_cfg.mode_config.phase_b_ms = atoi(argv[2]); + config_save(&app_cfg); + + mode_init(); + mode_restart(); + + shell_print(sh, "Config saved. phase_a=%s ms, phase_b=%s ms. Restarting.", argv[1], argv[2]); + return 0; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(mode_cmds, + SHELL_CMD(start, NULL, "Start the mode thread.", cmd_start), + SHELL_CMD(stop, NULL, "Stop the mode thread.", cmd_stop), + SHELL_CMD(restart, NULL, "Restart the mode thread.", cmd_restart), + SHELL_CMD_ARG(init, NULL, "Set , save and restart.", cmd_init, 3, 0), + SHELL_SUBCMD_SET_END +); + +SHELL_CMD_REGISTER(mode, &mode_cmds, "Mode control.", NULL); diff --git a/src/zbus_channels.c b/src/zbus_channels.c index 37a5e49..6f25840 100644 --- a/src/zbus_channels.c +++ b/src/zbus_channels.c @@ -17,4 +17,4 @@ ZBUS_CHAN_DEFINE(geiger_data_chan, /* Name */ NULL, /* User data */ ZBUS_OBSERVERS(), /* observers */ ZBUS_MSG_INIT(.cps = 0) /* Initial value */ -); \ No newline at end of file +); diff --git a/src/zbus_channels.h b/src/zbus_channels.h index eed86ea..5aecffa 100644 --- a/src/zbus_channels.h +++ b/src/zbus_channels.h @@ -36,4 +36,4 @@ ZBUS_CHAN_DECLARE(geiger_data_chan); -#endif // ZBUS_CHANNEL \ No newline at end of file +#endif // ZBUS_CHANNEL