blob: be6a801fbcaf185aa84d5df42e802df413f253b4 [file] [log] [blame]
/*
* Copyright (c) 2020 Seagate Technology LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/led.h>
#include <zephyr/drivers/led/lp50xx.h>
#include <zephyr/dt-bindings/led/led.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main);
#define MAX_BRIGHTNESS 100
#define SLEEP_DELAY_MS 1000
#define FADE_DELAY_MS 10
#define FADE_DELAY K_MSEC(FADE_DELAY_MS)
#define SLEEP_DELAY K_MSEC(SLEEP_DELAY_MS)
/*
* The following colors are shown in the given order. Each row index is sorted
* in RGB order.
*/
static uint8_t colors[][3] = {
{ 0xFF, 0x00, 0x00 }, /* Red */
{ 0x00, 0xFF, 0x00 }, /* Green */
{ 0x00, 0x00, 0xFF }, /* Blue */
{ 0xFF, 0xFF, 0xFF }, /* White */
{ 0xFF, 0xFF, 0x00 }, /* Yellow */
{ 0xFF, 0x00, 0xFF }, /* Purple */
{ 0x00, 0xFF, 0xFF }, /* Cyan */
{ 0xF4, 0x79, 0x20 }, /* Orange */
};
/*
* Prepare a color buffer for a single LED using its color mapping and the
* desired color index.
*/
static int prepare_color_buffer(const struct led_info *info, uint8_t *buf,
uint8_t color_idx)
{
uint8_t color;
for (color = 0; color < info->num_colors; color++) {
switch (info->color_mapping[color]) {
case LED_COLOR_ID_RED:
buf[color] = colors[color_idx][0];
continue;
case LED_COLOR_ID_GREEN:
buf[color] = colors[color_idx][1];
continue;
case LED_COLOR_ID_BLUE:
buf[color] = colors[color_idx][2];
continue;
default:
LOG_ERR("Invalid color: %d",
info->color_mapping[color]);
return -EINVAL;
}
}
return 0;
}
/**
* @brief Run tests on a single LED using the LED-based API syscalls.
*
* @param lp50xx_dev LP50XX LED controller device.
* @param led Number of the LED to test.
*/
static int run_led_test(const struct device *lp50xx_dev, uint8_t led)
{
const struct led_info *info;
uint8_t idx;
int err;
LOG_INF("Testing LED %d (LED API)", led);
err = led_get_info(lp50xx_dev, led, &info);
if (err < 0) {
LOG_ERR("Failed to get LED %d info", led);
return err;
}
for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
uint16_t level;
uint8_t buf[3];
err = prepare_color_buffer(info, buf, idx);
if (err < 0) {
LOG_ERR("Failed to set color buffer, err=%d", err);
return err;
}
/* Update LED color. */
err = led_set_color(lp50xx_dev, led, 3, buf);
if (err < 0) {
LOG_ERR("Failed to set LED %d color to "
"%02x:%02x:%02x, err=%d", led,
buf[0], buf[1], buf[2], err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Turn LED on. */
err = led_on(lp50xx_dev, led);
if (err < 0) {
LOG_ERR("Failed to turn LED %d on, err=%d", led, err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Turn LED off. */
err = led_off(lp50xx_dev, led);
if (err < 0) {
LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Set LED brightness gradually to the maximum level. */
for (level = 0; level <= MAX_BRIGHTNESS; level++) {
err = led_set_brightness(lp50xx_dev, led, level);
if (err < 0) {
LOG_ERR("Failed to set LED %d brightness to %d"
", err=%d\n", led, level, err);
return err;
}
k_sleep(FADE_DELAY);
}
k_sleep(SLEEP_DELAY);
/* Turn LED off. */
err = led_off(lp50xx_dev, led);
if (err < 0) {
LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
return err;
}
k_sleep(SLEEP_DELAY);
}
return 0;
}
/**
* @brief Run tests on all the LEDs using the channel-based API syscalls.
*
* @param lp50xx_dev LP50XX LED controller device.
*/
static int run_channel_test(const struct device *lp50xx_dev,
const uint8_t max_leds,
const uint8_t bright_chan,
const uint8_t color_chan)
{
uint8_t idx;
uint8_t buffer[LP50XX_COLORS_PER_LED * max_leds];
int err;
LOG_INF("Testing all LEDs (channel API)");
for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
uint8_t led;
uint16_t level;
/* Update LEDs colors. */
memset(buffer, 0, sizeof(buffer));
for (led = 0; led < max_leds; led++) {
const struct led_info *info;
uint8_t *col = &buffer[led * 3];
err = led_get_info(lp50xx_dev, led, &info);
if (err < 0) {
continue;
}
col = &buffer[info->index * 3];
err = prepare_color_buffer(info, col, idx);
if (err < 0) {
LOG_ERR("Failed to set color buffer, err=%d",
err);
return err;
}
}
err = led_write_channels(lp50xx_dev, color_chan,
LP50XX_COLORS_PER_LED *
max_leds,
buffer);
if (err < 0) {
LOG_ERR("Failed to write channels, start=%d num=%d"
" err=%d\n", color_chan,
LP50XX_COLORS_PER_LED * max_leds, err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Turn LEDs on. */
memset(buffer, 0, sizeof(buffer));
for (led = 0; led < max_leds; led++) {
buffer[led] = MAX_BRIGHTNESS;
}
err = led_write_channels(lp50xx_dev,
bright_chan,
max_leds, buffer);
if (err < 0) {
LOG_ERR("Failed to write channels, start=%d num=%d"
" err=%d\n", bright_chan,
max_leds, err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Turn LEDs off. */
for (led = 0; led < max_leds; led++) {
buffer[led] = 0;
}
err = led_write_channels(lp50xx_dev,
bright_chan,
max_leds, buffer);
if (err < 0) {
LOG_ERR("Failed to write channels, start=%d num=%d"
" err=%d\n", bright_chan,
max_leds, err);
return err;
}
k_sleep(SLEEP_DELAY);
/* Set LEDs brightnesses gradually to the maximum level. */
for (level = 0; level <= MAX_BRIGHTNESS; level++) {
for (led = 0; led < max_leds; led++) {
buffer[led] = level;
}
err = led_write_channels(lp50xx_dev,
bright_chan,
max_leds, buffer);
if (err < 0) {
LOG_ERR("Failed to write channels, start=%d"
" num=%d err=%d\n",
bright_chan,
max_leds, err);
return err;
}
k_sleep(FADE_DELAY);
}
k_sleep(SLEEP_DELAY);
/* Turn LEDs off. */
for (led = 0; led < max_leds; led++) {
buffer[led] = 0;
}
err = led_write_channels(lp50xx_dev,
bright_chan,
max_leds, buffer);
if (err < 0) {
LOG_ERR("Failed to write channels, start=%d "
"num=%d err=%d\n", bright_chan,
max_leds, err);
return err;
}
k_sleep(SLEEP_DELAY);
}
return 0;
}
static int run_test(const struct device *const lp50xx_dev,
const uint8_t max_leds,
const uint8_t bright_chan,
const uint8_t color_chan)
{
int err;
uint8_t led;
uint8_t num_leds = 0;
for (led = 0; led < max_leds; led++) {
int col;
const struct led_info *info;
err = led_get_info(lp50xx_dev, led, &info);
if (err < 0) {
LOG_DBG("Failed to get information for LED %d (err=%d)",
led, err);
break;
}
/* Display LED information. */
printk("Found LED %d", led);
if (info->label) {
printk(" - %s", info->label);
}
printk(" - index:%d", info->index);
printk(" - %d colors", info->num_colors);
if (!info->color_mapping) {
continue;
}
printk(" - %d", info->color_mapping[0]);
for (col = 1; col < info->num_colors; col++) {
printk(":%d", info->color_mapping[col]);
}
printk("\n");
}
num_leds = led;
if (!num_leds) {
LOG_ERR("No LEDs found");
return 0;
}
do {
err = run_channel_test(lp50xx_dev, max_leds, bright_chan,
color_chan);
if (err) {
return 0;
}
for (led = 0; led < num_leds; led++) {
err = run_led_test(lp50xx_dev, led);
if (err) {
return 0;
}
}
} while (true);
return 0;
}
int main(void)
{
const struct device *lp50xx_dev;
bool found = false;
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5009);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5009_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5012_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5012);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5012_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5012_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5018);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5018_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5024_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5024);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5024_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5024_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5030);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5030_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5036_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5036);
if (lp50xx_dev) {
LOG_INF("Found LED controller %s", lp50xx_dev->name);
found = true;
if (device_is_ready(lp50xx_dev)) {
run_test(lp50xx_dev,
LP5036_MAX_LEDS,
LP50XX_LED_BRIGHT_CHAN_BASE,
LP5036_LED_COL_CHAN_BASE);
} else {
LOG_ERR("LED controller %s is not ready",
lp50xx_dev->name);
}
}
if (!found) {
LOG_ERR("No LP50XX LED controller found");
}
return 0;
}