diff --git a/include/caf/led_effect.h b/include/caf/led_effect.h index c2b5a65b3027..332778cd8c6d 100644 --- a/include/caf/led_effect.h +++ b/include/caf/led_effect.h @@ -20,13 +20,16 @@ extern "C" { #endif -#define _CAF_LED_COLOR_CHANNEL_COUNT 3 +#define _CAF_LED_COLOR_CHANNEL_COUNT 4 /** @brief Color of LED. */ struct led_color { /** Values for color channels. */ uint8_t c[_CAF_LED_COLOR_CHANNEL_COUNT]; + + /** Number of channels in color */ + size_t channel_count; }; /** @brief Single step of a LED effect. @@ -82,7 +85,7 @@ struct led_effect { */ #define LED_COLOR_ARG_PASS(...) __VA_ARGS__ -/** Create LED color initializer for LED turned on. +/** Create LED color initializer for LED with RGB channels turned on. * * @note As arguments, pass the brightness levels for every color channel. * @@ -97,14 +100,57 @@ struct led_effect { .c = { \ COLOR_BRIGHTNESS_TO_PCT(_r), \ COLOR_BRIGHTNESS_TO_PCT(_g), \ - COLOR_BRIGHTNESS_TO_PCT(_b) \ - } \ + COLOR_BRIGHTNESS_TO_PCT(_b), \ + 0 \ + }, \ + .channel_count = 3 \ +} + +/** Create LED color initializer for LED with RGBW channels turned on. + * + * @note As arguments, pass the brightness levels for every color channel. + * + * @note The macro returns the structure initializer that once expanded + * contains commas not placed in brackets. + * This means that when passed as an argument, this argument + * cannot be passed simply to another macro. + * Use @ref LED_COLOR_ARG_PASS macro for the preprocessor + * to treat it as a single argument again. + */ +#define LED_COLOR_RGBW(_r, _g, _b, _w) { \ + .c = { \ + COLOR_BRIGHTNESS_TO_PCT(_r), \ + COLOR_BRIGHTNESS_TO_PCT(_g), \ + COLOR_BRIGHTNESS_TO_PCT(_b), \ + COLOR_BRIGHTNESS_TO_PCT(_w), \ + }, \ + .channel_count = 4 \ +} + +/** Create LED color initializer for single LED color turned on. + * + * @note As arguments, pass the brightness level for the LED. + * + * @note The macro returns the structure initializer that once expanded + * contains commas not placed in brackets. + * This means that when passed as an argument, this argument + * cannot be passed simply to another macro. + * Use @ref LED_COLOR_ARG_PASS macro for the preprocessor + * to treat it as a single argument again. + */ +#define LED_COLOR_SINGLE(_c) { \ + .c = { \ + COLOR_BRIGHTNESS_TO_PCT(_c), \ + 0, 0, 0 \ + }, \ + .channel_count = 1 \ } /** Create LED color initializer for LED turned off. */ #define LED_NOCOLOR() { \ - .c = {0, 0, 0} \ + .c = {0, 0, 0, 0}, \ + .channel_count = 3 \ } /** Create LED turned on effect initializer. diff --git a/subsys/caf/modules/leds.c b/subsys/caf/modules/leds.c index dd0a52ea0f57..e0ec5dff0b10 100644 --- a/subsys/caf/modules/leds.c +++ b/subsys/caf/modules/leds.c @@ -65,10 +65,10 @@ static int set_color_one_channel(struct led *led, struct led_color *color) /* For a single color LED convert color to brightness. */ unsigned int brightness = 0; - for (size_t i = 0; i < ARRAY_SIZE(color->c); i++) { + for (size_t i = 0; i < color->channel_count; i++) { brightness += color->c[i]; } - brightness /= ARRAY_SIZE(color->c); + brightness /= color->channel_count; return led_set_brightness(led->dev, 0, brightness); } @@ -77,7 +77,7 @@ static int set_color_all_channels(struct led *led, struct led_color *color) { int err = 0; - for (size_t i = 0; (i < ARRAY_SIZE(color->c)) && !err; i++) { + for (size_t i = 0; (i < led->color_count) && !err; i++) { err = led_set_brightness(led->dev, i, color->c[i]); } @@ -88,7 +88,7 @@ static void set_color(struct led *led, struct led_color *color) { int err; - if (led->color_count == ARRAY_SIZE(color->c)) { + if (led->color_count == color->channel_count) { err = set_color_all_channels(led, color); } else { err = set_color_one_channel(led, color); @@ -117,7 +117,10 @@ static void work_handler(struct k_work *work) __ASSERT_NO_MSG(effect_step->substep_count > 0); int substeps_left = effect_step->substep_count - led->effect_substep; - for (size_t i = 0; i < ARRAY_SIZE(led->color.c); i++) { + __ASSERT_NO_MSG(effect_step->color.channel_count <= ARRAY_SIZE(effect_step->color.c)); + + led->color.channel_count = effect_step->color.channel_count; + for (size_t i = 0; i < effect_step->color.channel_count; i++) { int diff = (effect_step->color.c[i] - led->color.c[i]) / substeps_left; led->color.c[i] += diff; @@ -184,7 +187,7 @@ static int leds_init(void) for (size_t i = 0; (i < ARRAY_SIZE(leds)) && !err; i++) { struct led *led = &leds[i]; - __ASSERT_NO_MSG((led->color_count == 1) || (led->color_count == 3)); + __ASSERT((led->color_count <= ARRAY_SIZE(led->color.c)), "More colors defined than module can handle"); if (!device_is_ready(led->dev)) { LOG_ERR("Device %s is not ready", led->dev->name);