Some more vibing
This commit is contained in:
+12
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
#define NVS_ID_CONFIG 1
|
||||
#define CONFIG_ID 0xDEADBEEF
|
||||
#define CONFIG_VERSION 2
|
||||
#define CONFIG_VERSION 7
|
||||
|
||||
static struct nvs_fs nvs;
|
||||
static app_config_t ram_config;
|
||||
@@ -18,6 +18,17 @@ static const app_config_t default_config = {
|
||||
.phase_a_ms = (20 * 60 * 1000),
|
||||
.phase_b_ms = (20 * 1000),
|
||||
},
|
||||
.light_config = {
|
||||
.min = 5,
|
||||
.max = 600,
|
||||
.gain = 0b00000100,
|
||||
},
|
||||
.color = {
|
||||
.r = 1,
|
||||
.g = 0.2,
|
||||
.b = 0,
|
||||
},
|
||||
.color_duration = 2000,
|
||||
};
|
||||
|
||||
int config_init(void)
|
||||
|
||||
+11
-1
@@ -4,11 +4,21 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "mode.h"
|
||||
#include "led.h"
|
||||
|
||||
struct light_config_t {
|
||||
uint16_t min;
|
||||
uint16_t max;
|
||||
uint8_t gain;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
uint16_t version;
|
||||
struct mode_config mode_config;
|
||||
struct mode_config_t mode_config;
|
||||
struct light_config_t light_config;
|
||||
struct color_t color;
|
||||
uint16_t color_duration;
|
||||
} app_config_t;
|
||||
|
||||
int config_init(void);
|
||||
|
||||
@@ -88,11 +88,24 @@ static int cmd_dbg_leds_fade_to(const struct shell *sh, size_t argc, char **argv
|
||||
atoi(argv[4]) < 0 ? -1.0f : atoi(argv[4]) / 255.0f);
|
||||
}
|
||||
|
||||
static int cmd_dbg_led_color(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
struct color_t color;
|
||||
if (led_color_from_str(argv[1], &color) != 0) {
|
||||
shell_error(sh, "Unknown color: %s", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
leds_set_all(color.r, color.g, color.b);
|
||||
leds_update();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(debug_leds_cmds,
|
||||
SHELL_CMD(all, NULL, "Set all LEDs <r> <g> <b>.", cmd_dbg_leds_all),
|
||||
SHELL_CMD(clear, NULL, "Clear all LEDs.", cmd_dbg_leds_clear),
|
||||
SHELL_CMD(fade, NULL, "Fade in/out <ms> <r> <g> <b>.", cmd_dbg_leds_fade),
|
||||
SHELL_CMD(fade_to, NULL, "Fade to color <ms> <r> <g> <b>.", cmd_dbg_leds_fade_to),
|
||||
SHELL_CMD(color, NULL, "Set to color <color>. eg. yellow", cmd_dbg_led_color),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HELPERS_H
|
||||
#define HELPERS_H
|
||||
|
||||
float map(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
|
||||
#endif // HELPERS_H
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "led.h"
|
||||
#include "light.h"
|
||||
#include "config.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
@@ -15,11 +18,15 @@ 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 strip color for fade_to interpolation */
|
||||
/* Saved strip color for fade_to interpolation (logical, pre-brightness) */
|
||||
static float saved_r = 0.0f;
|
||||
static float saved_g = 0.0f;
|
||||
static float saved_b = 0.0f;
|
||||
|
||||
/* Light sensor config loaded during init */
|
||||
static uint16_t light_min = 0;
|
||||
static uint16_t light_max = 1023;
|
||||
|
||||
#define NR_LEDS 8
|
||||
#define PWM_RESOLUTION 255
|
||||
|
||||
@@ -36,6 +43,88 @@ static const struct pwm_dt_spec *leds[NR_LEDS] = {
|
||||
&led1, &led2, &led3, &led4, &led5, &led6, &led7, &led8
|
||||
};
|
||||
|
||||
static const led_color_entry_t color_table[] = {
|
||||
{ "red", { LED_COLOR_RED } },
|
||||
{ "green", { LED_COLOR_GREEN } },
|
||||
{ "blue", { LED_COLOR_BLUE } },
|
||||
{ "yellow", { LED_COLOR_YELLOW } },
|
||||
{ "cyan", { LED_COLOR_CYAN } },
|
||||
{ "magenta", { LED_COLOR_MAGENTA } },
|
||||
{ "white", { LED_COLOR_WHITE } },
|
||||
{ "warm_white", { LED_COLOR_WARM_WHITE } },
|
||||
{ "cold_white", { LED_COLOR_COLD_WHITE } },
|
||||
{ "black", { LED_COLOR_BLACK } },
|
||||
{ "orange", { LED_COLOR_ORANGE } },
|
||||
{ "deep_orange", { LED_COLOR_DEEP_ORANGE } },
|
||||
{ "amber", { LED_COLOR_AMBER } },
|
||||
{ "coral", { LED_COLOR_CORAL } },
|
||||
{ "tomato", { LED_COLOR_TOMATO } },
|
||||
{ "crimson", { LED_COLOR_CRIMSON } },
|
||||
{ "scarlet", { LED_COLOR_SCARLET } },
|
||||
{ "pink", { LED_COLOR_PINK } },
|
||||
{ "hot_pink", { LED_COLOR_HOT_PINK } },
|
||||
{ "deep_pink", { LED_COLOR_DEEP_PINK } },
|
||||
{ "purple", { LED_COLOR_PURPLE } },
|
||||
{ "deep_purple", { LED_COLOR_DEEP_PURPLE } },
|
||||
{ "violet", { LED_COLOR_VIOLET } },
|
||||
{ "indigo", { LED_COLOR_INDIGO } },
|
||||
{ "lavender", { LED_COLOR_LAVENDER } },
|
||||
{ "lime", { LED_COLOR_LIME } },
|
||||
{ "chartreuse", { LED_COLOR_CHARTREUSE } },
|
||||
{ "mint", { LED_COLOR_MINT } },
|
||||
{ "teal", { LED_COLOR_TEAL } },
|
||||
{ "forest_green", { LED_COLOR_FOREST_GREEN } },
|
||||
{ "olive", { LED_COLOR_OLIVE } },
|
||||
{ "sky_blue", { LED_COLOR_SKY_BLUE } },
|
||||
{ "deep_sky_blue", { LED_COLOR_DEEP_SKY_BLUE } },
|
||||
{ "dodger_blue", { LED_COLOR_DODGER_BLUE } },
|
||||
{ "royal_blue", { LED_COLOR_ROYAL_BLUE } },
|
||||
{ "navy", { LED_COLOR_NAVY } },
|
||||
{ "steel_blue", { LED_COLOR_STEEL_BLUE } },
|
||||
{ "ice_blue", { LED_COLOR_ICE_BLUE } },
|
||||
{ "gold", { LED_COLOR_GOLD } },
|
||||
{ "silver", { LED_COLOR_SILVER } },
|
||||
};
|
||||
const int color_table_size = ARRAY_SIZE(color_table);
|
||||
|
||||
int led_color_from_str(const char *name, struct color_t *out)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(color_table); i++) {
|
||||
if (strcasecmp(color_table[i].name, name) == 0) {
|
||||
*out = color_table[i].color;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const char *led_color_to_str(const struct color_t *color)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(color_table); i++) {
|
||||
if (color_table[i].color.r == color->r &&
|
||||
color_table[i].color.g == color->g &&
|
||||
color_table[i].color.b == color->b) {
|
||||
return color_table[i].name;
|
||||
}
|
||||
}
|
||||
return "custom";
|
||||
}
|
||||
|
||||
int led_color_count(void)
|
||||
{
|
||||
return ARRAY_SIZE(color_table);
|
||||
}
|
||||
|
||||
const led_color_entry_t *led_color_get(int index)
|
||||
{
|
||||
if (index < 0 || index >= ARRAY_SIZE(color_table)) {
|
||||
return NULL;
|
||||
}
|
||||
return &color_table[index];
|
||||
}
|
||||
|
||||
/* ---------- PWM helpers ---------- */
|
||||
|
||||
static int set_pwm(const struct pwm_dt_spec *dev, uint32_t value, uint32_t max_brightness)
|
||||
{
|
||||
if (value <= max_brightness && max_brightness > 0) {
|
||||
@@ -45,36 +134,96 @@ static int set_pwm(const struct pwm_dt_spec *dev, uint32_t value, uint32_t max_b
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* ---------- brightness helpers ---------- */
|
||||
|
||||
/**
|
||||
* Read the light sensor and return a brightness multiplier in [0.0, 1.0].
|
||||
* The raw value is mapped from [light_min, light_max] → [0.0, 1.0] and
|
||||
* clamped so out-of-range readings never over- or under-drive the LEDs.
|
||||
*/
|
||||
static float get_brightness(void)
|
||||
{
|
||||
struct light_data_t data;
|
||||
light_read(&data);
|
||||
float b = map((float)data.value,
|
||||
(float)light_min, (float)light_max,
|
||||
0.0f, 1.0f);
|
||||
if (b < 0.0f) b = 0.0f;
|
||||
if (b > 1.0f) b = 1.0f;
|
||||
return b;
|
||||
}
|
||||
|
||||
static float get_brightness_pwm(void)
|
||||
{
|
||||
for (int j = 0; j < NR_LEDS; j++) {
|
||||
set_pwm(leds[j], 0, PWM_RESOLUTION);
|
||||
}
|
||||
return get_brightness();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like set_pwm() but scales `value` by the current ambient brightness before
|
||||
* writing. All PWM-facing call sites go through here.
|
||||
*/
|
||||
static int set_pwm_bright(const struct pwm_dt_spec *dev, uint32_t value,
|
||||
uint32_t max_brightness, float brightness)
|
||||
{
|
||||
uint32_t scaled = (uint32_t)((float)value * brightness);
|
||||
return set_pwm(dev, scaled, max_brightness);
|
||||
}
|
||||
|
||||
/* ---------- init ---------- */
|
||||
|
||||
int led_init(void)
|
||||
{
|
||||
for (int i = 0; i < NR_LEDS; i++) {
|
||||
if (!device_is_ready(leds[i]->dev)) {
|
||||
LOG_ERR("PWM LED %d not ready", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
LOG_INF("PWM LEDs initialized");
|
||||
/* Load light config so brightness mapping is ready before first use */
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
light_min = cfg.light_config.min;
|
||||
light_max = cfg.light_config.max;
|
||||
|
||||
if (!device_is_ready(strip)) {
|
||||
LOG_ERR("LED strip device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
LOG_INF("LED strip initialized with %d pixels", STRIP_NUM_PIXELS);
|
||||
/* Sanity-check: inverted or zero range would make map() degenerate */
|
||||
if (light_min >= light_max) {
|
||||
LOG_WRN("Invalid light_config range [%u, %u], using defaults",
|
||||
light_min, light_max);
|
||||
light_min = 0;
|
||||
light_max = 1023;
|
||||
}
|
||||
LOG_INF("Light config: min=%u max=%u", light_min, light_max);
|
||||
|
||||
for (int i = 0; i < NR_LEDS; i++) {
|
||||
if (!device_is_ready(leds[i]->dev)) {
|
||||
LOG_ERR("PWM LED %d not ready", i);
|
||||
return -ENODEV;
|
||||
}
|
||||
set_pwm(leds[i], 0, PWM_RESOLUTION);
|
||||
}
|
||||
LOG_INF("PWM LEDs initialized");
|
||||
|
||||
if (!device_is_ready(strip)) {
|
||||
LOG_ERR("LED strip device not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
LOG_INF("LED strip initialized with %d pixels", STRIP_NUM_PIXELS);
|
||||
leds_clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fade all PWM LEDs in then out over duration ms */
|
||||
/* ---------- PWM LED effects ---------- */
|
||||
|
||||
int led_fade(uint32_t duration)
|
||||
{
|
||||
uint32_t step = (duration * 1000) / (PWM_RESOLUTION * 2);
|
||||
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm(leds[j], i, PWM_RESOLUTION); }
|
||||
float b = get_brightness();
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm_bright(leds[j], i, PWM_RESOLUTION, b); }
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm(leds[j], PWM_RESOLUTION - i - 1, PWM_RESOLUTION); }
|
||||
float b = get_brightness();
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm_bright(leds[j], PWM_RESOLUTION - i - 1, PWM_RESOLUTION, b); }
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
return 0;
|
||||
@@ -84,7 +233,8 @@ int led_fade_in(uint32_t duration)
|
||||
{
|
||||
uint32_t step = (duration * 1000) / PWM_RESOLUTION;
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm(leds[j], i, PWM_RESOLUTION); }
|
||||
float b = get_brightness();
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm_bright(leds[j], i, PWM_RESOLUTION, b); }
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
return 0;
|
||||
@@ -94,68 +244,79 @@ int led_fade_out(uint32_t duration)
|
||||
{
|
||||
uint32_t step = (duration * 1000) / PWM_RESOLUTION;
|
||||
for (int i = 0; i < PWM_RESOLUTION; i++) {
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm(leds[j], PWM_RESOLUTION - i - 1, PWM_RESOLUTION); }
|
||||
float b = get_brightness();
|
||||
for (int j = 0; j < NR_LEDS; j++) { set_pwm_bright(leds[j], PWM_RESOLUTION - i - 1, PWM_RESOLUTION, b); }
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Light N+fraction LEDs to represent progress [0.0, 1.0] */
|
||||
int led_set_progress(float progress)
|
||||
{
|
||||
float b = get_brightness(); /* LEDs blanked; write real values below */
|
||||
uint32_t total = (uint32_t)(progress * NR_LEDS * PWM_RESOLUTION);
|
||||
|
||||
for (int i = 0; i < NR_LEDS; i++) {
|
||||
uint32_t val;
|
||||
if (total > PWM_RESOLUTION) {
|
||||
set_pwm(leds[i], PWM_RESOLUTION, PWM_RESOLUTION);
|
||||
val = PWM_RESOLUTION;
|
||||
total -= PWM_RESOLUTION;
|
||||
} else {
|
||||
set_pwm(leds[i], total, PWM_RESOLUTION);
|
||||
val = total;
|
||||
total = 0;
|
||||
}
|
||||
set_pwm_bright(leds[i], val, PWM_RESOLUTION, b);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- Addressable LED strip --- */
|
||||
/* ---------- addressable strip ---------- */
|
||||
|
||||
/**
|
||||
* Write r/g/b to a pixel after applying the ambient brightness multiplier.
|
||||
* `r`, `g`, `b` are logical values in [0.0, 1.0]; `brightness` scales them.
|
||||
*/
|
||||
static void set_pixel_bright(int idx, float r, float g, float b, float brightness)
|
||||
{
|
||||
pixels[idx].r = (uint8_t)(r * brightness * STRIP_MAX_BRIGHTNESS);
|
||||
pixels[idx].g = (uint8_t)(g * brightness * STRIP_MAX_BRIGHTNESS);
|
||||
pixels[idx].b = (uint8_t)(b * brightness * STRIP_MAX_BRIGHTNESS);
|
||||
}
|
||||
|
||||
int leds_set_color(uint8_t led_index, float r, float g, float b)
|
||||
{
|
||||
if (led_index >= STRIP_NUM_PIXELS) {
|
||||
LOG_ERR("LED index %d out of range (max %d)", led_index, STRIP_NUM_PIXELS - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
pixels[led_index].r = r * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[led_index].g = g * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[led_index].b = b * STRIP_MAX_BRIGHTNESS;
|
||||
return 0;
|
||||
if (led_index >= STRIP_NUM_PIXELS) {
|
||||
LOG_ERR("LED index %d out of range (max %d)", led_index, STRIP_NUM_PIXELS - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
set_pixel_bright(led_index, r, g, b, get_brightness());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_set_all(float r, float g, float b)
|
||||
{
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
pixels[i].r = r * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[i].g = g * STRIP_MAX_BRIGHTNESS;
|
||||
pixels[i].b = b * STRIP_MAX_BRIGHTNESS;
|
||||
}
|
||||
saved_r = r;
|
||||
saved_g = g;
|
||||
saved_b = b;
|
||||
return 0;
|
||||
float brightness = get_brightness();
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
set_pixel_bright(i, r, g, b, brightness);
|
||||
}
|
||||
saved_r = r;
|
||||
saved_g = g;
|
||||
saved_b = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_update(void)
|
||||
{
|
||||
int ret = led_strip_update_rgb(strip, pixels, STRIP_NUM_PIXELS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to update LED strip: %d", ret);
|
||||
}
|
||||
return ret;
|
||||
int ret = led_strip_update_rgb(strip, pixels, STRIP_NUM_PIXELS);
|
||||
if (ret) {
|
||||
LOG_ERR("Failed to update LED strip: %d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int leds_clear(void)
|
||||
{
|
||||
return leds_set_all(0, 0, 0) || leds_update();
|
||||
return leds_set_all(0, 0, 0) || leds_update();
|
||||
}
|
||||
|
||||
int leds_fade(uint32_t duration, float r, float g, float b)
|
||||
@@ -174,10 +335,10 @@ int leds_fade(uint32_t duration, float r, float g, float b)
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
saved_r = 0.0f;
|
||||
saved_g = 0.0f;
|
||||
saved_b = 0.0f;
|
||||
return 0;
|
||||
saved_r = 0.0f;
|
||||
saved_g = 0.0f;
|
||||
saved_b = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_fade_in(uint32_t duration, float r, float g, float b)
|
||||
@@ -189,8 +350,8 @@ int leds_fade_in(uint32_t duration, float r, float g, float b)
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
saved_r = r; saved_g = g; saved_b = b;
|
||||
return 0;
|
||||
saved_r = r; saved_g = g; saved_b = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int leds_fade_out(uint32_t duration, float r, float g, float b)
|
||||
@@ -202,11 +363,10 @@ int leds_fade_out(uint32_t duration, float r, float g, float b)
|
||||
leds_update();
|
||||
k_sleep(K_USEC(step));
|
||||
}
|
||||
saved_r = 0.0f; saved_g = 0.0f; saved_b = 0.0f;
|
||||
return 0;
|
||||
saved_r = 0.0f; saved_g = 0.0f; saved_b = 0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fade from current saved color to target; pass -1.0 to keep a channel unchanged */
|
||||
int leds_fade_to(uint32_t duration, float r, float g, float b)
|
||||
{
|
||||
float target_r = (r < 0.0f) ? saved_r : r;
|
||||
@@ -228,4 +388,4 @@ int leds_fade_to(uint32_t duration, float r, float g, float b)
|
||||
saved_g = target_g;
|
||||
saved_b = target_b;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,92 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* ---------- predefined colors (r, g, b) in [0.0, 1.0] ---------- */
|
||||
|
||||
/* Primaries */
|
||||
#define LED_COLOR_RED 1.0f, 0.0f, 0.0f
|
||||
#define LED_COLOR_GREEN 0.0f, 1.0f, 0.0f
|
||||
#define LED_COLOR_BLUE 0.0f, 0.0f, 1.0f
|
||||
|
||||
/* Secondaries */
|
||||
#define LED_COLOR_YELLOW 1.0f, 1.0f, 0.0f
|
||||
#define LED_COLOR_CYAN 0.0f, 1.0f, 1.0f
|
||||
#define LED_COLOR_MAGENTA 1.0f, 0.0f, 1.0f
|
||||
|
||||
/* Whites */
|
||||
#define LED_COLOR_WHITE 1.0f, 1.0f, 1.0f
|
||||
#define LED_COLOR_WARM_WHITE 1.0f, 0.89f, 0.70f
|
||||
#define LED_COLOR_COLD_WHITE 0.90f, 0.95f, 1.0f
|
||||
#define LED_COLOR_BLACK 0.0f, 0.0f, 0.0f
|
||||
|
||||
/* Oranges & reds */
|
||||
#define LED_COLOR_ORANGE 1.0f, 0.50f, 0.0f
|
||||
#define LED_COLOR_DEEP_ORANGE 1.0f, 0.25f, 0.0f
|
||||
#define LED_COLOR_AMBER 1.0f, 0.75f, 0.0f
|
||||
#define LED_COLOR_CORAL 1.0f, 0.31f, 0.19f
|
||||
#define LED_COLOR_TOMATO 1.0f, 0.27f, 0.23f
|
||||
#define LED_COLOR_CRIMSON 0.86f, 0.08f, 0.24f
|
||||
#define LED_COLOR_SCARLET 1.0f, 0.14f, 0.0f
|
||||
|
||||
/* Pinks & purples */
|
||||
#define LED_COLOR_PINK 1.0f, 0.40f, 0.70f
|
||||
#define LED_COLOR_HOT_PINK 1.0f, 0.07f, 0.58f
|
||||
#define LED_COLOR_DEEP_PINK 1.0f, 0.08f, 0.58f
|
||||
#define LED_COLOR_PURPLE 0.50f, 0.0f, 1.0f
|
||||
#define LED_COLOR_DEEP_PURPLE 0.40f, 0.0f, 0.80f
|
||||
#define LED_COLOR_VIOLET 0.56f, 0.0f, 1.0f
|
||||
#define LED_COLOR_INDIGO 0.29f, 0.0f, 0.51f
|
||||
#define LED_COLOR_LAVENDER 0.71f, 0.49f, 0.86f
|
||||
|
||||
/* Greens */
|
||||
#define LED_COLOR_LIME 0.75f, 1.0f, 0.0f
|
||||
#define LED_COLOR_CHARTREUSE 0.50f, 1.0f, 0.0f
|
||||
#define LED_COLOR_MINT 0.24f, 1.0f, 0.49f
|
||||
#define LED_COLOR_TEAL 0.0f, 0.50f, 0.50f
|
||||
#define LED_COLOR_FOREST_GREEN 0.13f, 0.55f, 0.13f
|
||||
#define LED_COLOR_OLIVE 0.50f, 0.50f, 0.0f
|
||||
|
||||
/* Blues */
|
||||
#define LED_COLOR_SKY_BLUE 0.53f, 0.81f, 0.98f
|
||||
#define LED_COLOR_DEEP_SKY_BLUE 0.0f, 0.75f, 1.0f
|
||||
#define LED_COLOR_DODGER_BLUE 0.12f, 0.56f, 1.0f
|
||||
#define LED_COLOR_ROYAL_BLUE 0.25f, 0.41f, 0.88f
|
||||
#define LED_COLOR_NAVY 0.0f, 0.0f, 0.50f
|
||||
#define LED_COLOR_STEEL_BLUE 0.27f, 0.51f, 0.71f
|
||||
#define LED_COLOR_ICE_BLUE 0.60f, 0.85f, 1.0f
|
||||
|
||||
/* Neutrals */
|
||||
#define LED_COLOR_GOLD 1.0f, 0.84f, 0.0f
|
||||
#define LED_COLOR_SILVER 0.75f, 0.75f, 0.75f
|
||||
|
||||
/* ---------- color lookup by name ---------- */
|
||||
|
||||
struct color_t {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
struct color_t color;
|
||||
} led_color_entry_t;
|
||||
|
||||
int led_color_from_str(const char *name, struct color_t *out);
|
||||
const char *led_color_to_str(const struct color_t *color);
|
||||
int led_color_count(void);
|
||||
const led_color_entry_t *led_color_get(int index);
|
||||
|
||||
/* ---------- PWM LED functions ---------- */
|
||||
|
||||
int led_init(void);
|
||||
int led_fade(uint32_t duration);
|
||||
int led_fade_in(uint32_t duration);
|
||||
int led_fade_out(uint32_t duration);
|
||||
int led_set_progress(float progress);
|
||||
|
||||
/* ---------- addressable LED strip functions ---------- */
|
||||
|
||||
int leds_set_color(uint8_t led_index, float r, float g, float b);
|
||||
int leds_set_all(float r, float g, float b);
|
||||
int leds_update(void);
|
||||
@@ -18,4 +98,4 @@ 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
|
||||
#endif // LED_H
|
||||
+10
@@ -1,5 +1,7 @@
|
||||
#include "light.h"
|
||||
#include "zbus_channels.h"
|
||||
#include "led.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
@@ -15,6 +17,8 @@ static const uint8_t i2c_address = 0x38;
|
||||
|
||||
static const struct device *const i2c_dev = DEVICE_DT_GET(DT_ALIAS(i2c_1));
|
||||
|
||||
static struct light_config_t cfg;
|
||||
|
||||
int light_init(void)
|
||||
{
|
||||
if (!device_is_ready(i2c_dev)) {
|
||||
@@ -22,10 +26,16 @@ int light_init(void)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
app_config_t app_cfg;
|
||||
config_get(&app_cfg);
|
||||
cfg = app_cfg.light_config;
|
||||
|
||||
const uint8_t RESET[2] = {0x00, 0b00000001}; // reset
|
||||
const uint8_t ALS_GAIN[2] = {0x04, cfg.gain}; // configure ALS gain
|
||||
const uint8_t ENABLE_ALS[2] = {0x00, 0b00000001}; // enable ALS
|
||||
|
||||
i2c_write(i2c_dev, RESET, sizeof(RESET), i2c_address); k_sleep(K_MSEC(100));
|
||||
i2c_write(i2c_dev, ALS_GAIN, sizeof(ALS_GAIN), i2c_address); k_sleep(K_MSEC(10));
|
||||
i2c_write(i2c_dev, ENABLE_ALS, sizeof(ENABLE_ALS), i2c_address); k_sleep(K_MSEC(100));
|
||||
|
||||
return 0;
|
||||
|
||||
+7
-5
@@ -13,7 +13,9 @@ 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 struct mode_config_t cfg;
|
||||
static struct color_t color;
|
||||
static uint16_t color_duration = 2000;
|
||||
|
||||
static void mode_thread_fn(void *p1, void *p2, void *p3)
|
||||
{
|
||||
@@ -30,10 +32,8 @@ static void mode_thread_fn(void *p1, void *p2, void *p3)
|
||||
/* Phase B: color animation over phase_b_ms */
|
||||
start = k_uptime_get();
|
||||
while (atomic_get(&running) && k_uptime_get() - start < cfg.phase_b_ms) {
|
||||
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);
|
||||
leds_fade_to(color_duration/2, color.r, color.g, color.b);
|
||||
leds_fade_to(color_duration/2, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ void mode_init(void)
|
||||
app_config_t app_cfg;
|
||||
config_get(&app_cfg);
|
||||
cfg = app_cfg.mode_config;
|
||||
color = app_cfg.color;
|
||||
color_duration = app_cfg.color_duration;
|
||||
LOG_INF("Mode init: phase_a=%d ms, phase_b=%d ms", cfg.phase_a_ms, cfg.phase_b_ms);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct mode_config {
|
||||
struct mode_config_t {
|
||||
int32_t phase_a_ms;
|
||||
int32_t phase_b_ms;
|
||||
};
|
||||
|
||||
+73
-3
@@ -1,13 +1,27 @@
|
||||
// User-facing shell commands.
|
||||
// mode set <phase_a_ms> <phase_b_ms> — save config and restart
|
||||
// mode color <name> — save color by name and restart
|
||||
// mode duration <ms> — save color duration and restart
|
||||
// mode status — show current config
|
||||
//
|
||||
#include "mode.h"
|
||||
#include "config.h"
|
||||
#include "led.h"
|
||||
|
||||
#include <zephyr/shell/shell.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Print a color as 0-255 integers — %f is unavailable without
|
||||
CONFIG_CBPRINTF_FP_SUPPORT, and integer RGB is more readable anyway. */
|
||||
static void print_color(const struct shell *sh, const struct color_t *color)
|
||||
{
|
||||
shell_print(sh, " color=%s rgb=(%d, %d, %d)",
|
||||
led_color_to_str(color),
|
||||
(int)(color->r * 255),
|
||||
(int)(color->g * 255),
|
||||
(int)(color->b * 255));
|
||||
}
|
||||
|
||||
static int cmd_mode_set(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
app_config_t cfg;
|
||||
@@ -21,20 +35,76 @@ static int cmd_mode_set(const struct shell *sh, size_t argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_mode_color(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
struct color_t color;
|
||||
if (led_color_from_str(argv[1], &color) != 0) {
|
||||
shell_error(sh, "Unknown color: %s", argv[1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
cfg.color = color;
|
||||
config_save(&cfg);
|
||||
mode_init();
|
||||
mode_restart();
|
||||
shell_print(sh, "Color saved and restarting.");
|
||||
print_color(sh, &color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_mode_duration(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
int val = atoi(argv[1]);
|
||||
if (val <= 0) {
|
||||
shell_error(sh, "Duration must be a positive integer (ms)");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
cfg.color_duration = (uint16_t)val;
|
||||
config_save(&cfg);
|
||||
mode_init();
|
||||
mode_restart();
|
||||
shell_print(sh, "Color duration saved: %d ms. Restarting.", cfg.color_duration);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_mode_status(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
app_config_t cfg;
|
||||
config_get(&cfg);
|
||||
|
||||
shell_print(sh, "phase_a=%d ms, phase_b=%d ms",
|
||||
cfg.mode_config.phase_a_ms,
|
||||
cfg.mode_config.phase_b_ms);
|
||||
print_color(sh, &cfg.color);
|
||||
shell_print(sh, " duration=%d ms", cfg.color_duration);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_mode_colors(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
for (int i = 0; i < led_color_count(); i++) {
|
||||
const led_color_entry_t *entry = led_color_get(i);
|
||||
shell_print(sh, " %-16s rgb=(%d, %d, %d)",
|
||||
entry->name,
|
||||
(int)(entry->color.r * 255),
|
||||
(int)(entry->color.g * 255),
|
||||
(int)(entry->color.b * 255));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(mode_cmds,
|
||||
SHELL_CMD_ARG(set, NULL, "Set <phase_a_ms> <phase_b_ms>, save and restart.", cmd_mode_set, 3, 0),
|
||||
SHELL_CMD( status, NULL, "Show current config.", cmd_mode_status),
|
||||
SHELL_CMD_ARG(set, NULL, "Set <phase_a_ms> <phase_b_ms>, save and restart.", cmd_mode_set, 3, 0),
|
||||
SHELL_CMD_ARG(color, NULL, "Set color by name (e.g. deep_orange), save and restart.", cmd_mode_color, 2, 0),
|
||||
SHELL_CMD_ARG(duration, NULL, "Set color duration <ms>, save and restart.", cmd_mode_duration, 2, 0),
|
||||
SHELL_CMD( status, NULL, "Show current config.", cmd_mode_status),
|
||||
SHELL_CMD( colors, NULL, "List all available colors.", cmd_mode_colors),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_CMD_REGISTER(mode, &mode_cmds, "Mode control.", NULL);
|
||||
SHELL_CMD_REGISTER(mode, &mode_cmds, "Mode control.", NULL);
|
||||
Reference in New Issue
Block a user