Skip to content

Commit

Permalink
caf: modules: leds: fix support GPIO-based LED devicetree definitions
Browse files Browse the repository at this point in the history
When CONFIG_CAF_LEDS_GPIO was chosen over CONFIG_CAF_LEDS_PWM,
an assertion fails that checks whether a gpio-leds compatible
node has either 1 or 3 child nodes to define multi-color LEDs.
However, most Nordic development boards have 4 leds, which
the CAF leds module does not support and hence breaks these
builds. This commit adds support for up to a combination of
4 leds in what could be analogous to an RGBW LED. The changes
are made as such that as little application code as possible
is affected by the change. If user code wants to take full
advantage of the full channel color support it will have to
redefine the OFF, ON, ON_GO_OFF, BLINK, BLINK2, BREATH, and
CLOCK effects since LED_NOCOLOR is only defined for 3 channels.

Signed-off-by: Jelle De Vleeschouwer <[email protected]>
  • Loading branch information
jelledevleeschouwer committed Dec 23, 2024
1 parent 6d1c940 commit 3f29b30
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 11 deletions.
56 changes: 51 additions & 5 deletions include/caf/led_effect.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand All @@ -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.
Expand Down
15 changes: 9 additions & 6 deletions subsys/caf/modules/leds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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]);
}

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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_NO_MSG((led->color_count <= ARRAY_SIZE(led->color.c)));

if (!device_is_ready(led->dev)) {
LOG_ERR("Device %s is not ready", led->dev->name);
Expand Down

0 comments on commit 3f29b30

Please sign in to comment.