1 /*
2 * Copyright (c) 2020 Seagate Technology LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <zephyr/device.h>
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/led.h>
11 #include <zephyr/drivers/led/lp50xx.h>
12 #include <zephyr/dt-bindings/led/led.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/util.h>
15
16 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(main);
19
20 #define MAX_BRIGHTNESS 100
21
22 #define SLEEP_DELAY_MS 1000
23 #define FADE_DELAY_MS 10
24
25 #define FADE_DELAY K_MSEC(FADE_DELAY_MS)
26 #define SLEEP_DELAY K_MSEC(SLEEP_DELAY_MS)
27
28 /*
29 * The following colors are shown in the given order. Each row index is sorted
30 * in RGB order.
31 */
32 static uint8_t colors[][3] = {
33 { 0xFF, 0x00, 0x00 }, /* Red */
34 { 0x00, 0xFF, 0x00 }, /* Green */
35 { 0x00, 0x00, 0xFF }, /* Blue */
36 { 0xFF, 0xFF, 0xFF }, /* White */
37 { 0xFF, 0xFF, 0x00 }, /* Yellow */
38 { 0xFF, 0x00, 0xFF }, /* Purple */
39 { 0x00, 0xFF, 0xFF }, /* Cyan */
40 { 0xF4, 0x79, 0x20 }, /* Orange */
41 };
42
43 /*
44 * Prepare a color buffer for a single LED using its color mapping and the
45 * desired color index.
46 */
prepare_color_buffer(const struct led_info * info,uint8_t * buf,uint8_t color_idx)47 static int prepare_color_buffer(const struct led_info *info, uint8_t *buf,
48 uint8_t color_idx)
49 {
50 uint8_t color;
51
52 for (color = 0; color < info->num_colors; color++) {
53 switch (info->color_mapping[color]) {
54 case LED_COLOR_ID_RED:
55 buf[color] = colors[color_idx][0];
56 continue;
57 case LED_COLOR_ID_GREEN:
58 buf[color] = colors[color_idx][1];
59 continue;
60 case LED_COLOR_ID_BLUE:
61 buf[color] = colors[color_idx][2];
62 continue;
63 default:
64 LOG_ERR("Invalid color: %d",
65 info->color_mapping[color]);
66 return -EINVAL;
67 }
68 }
69
70 return 0;
71 }
72
73 /**
74 * @brief Run tests on a single LED using the LED-based API syscalls.
75 *
76 * @param lp50xx_dev LP50XX LED controller device.
77 * @param led Number of the LED to test.
78 */
run_led_test(const struct device * lp50xx_dev,uint8_t led)79 static int run_led_test(const struct device *lp50xx_dev, uint8_t led)
80 {
81 const struct led_info *info;
82 uint8_t idx;
83 int err;
84
85 LOG_INF("Testing LED %d (LED API)", led);
86
87 err = led_get_info(lp50xx_dev, led, &info);
88 if (err < 0) {
89 LOG_ERR("Failed to get LED %d info", led);
90 return err;
91 }
92
93 for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
94 uint16_t level;
95 uint8_t buf[3];
96
97 err = prepare_color_buffer(info, buf, idx);
98 if (err < 0) {
99 LOG_ERR("Failed to set color buffer, err=%d", err);
100 return err;
101 }
102
103 /* Update LED color. */
104 err = led_set_color(lp50xx_dev, led, 3, buf);
105 if (err < 0) {
106 LOG_ERR("Failed to set LED %d color to "
107 "%02x:%02x:%02x, err=%d", led,
108 buf[0], buf[1], buf[2], err);
109 return err;
110 }
111 k_sleep(SLEEP_DELAY);
112
113 /* Turn LED on. */
114 err = led_on(lp50xx_dev, led);
115 if (err < 0) {
116 LOG_ERR("Failed to turn LED %d on, err=%d", led, err);
117 return err;
118 }
119 k_sleep(SLEEP_DELAY);
120
121 /* Turn LED off. */
122 err = led_off(lp50xx_dev, led);
123 if (err < 0) {
124 LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
125 return err;
126 }
127 k_sleep(SLEEP_DELAY);
128
129 /* Set LED brightness gradually to the maximum level. */
130 for (level = 0; level <= MAX_BRIGHTNESS; level++) {
131 err = led_set_brightness(lp50xx_dev, led, level);
132 if (err < 0) {
133 LOG_ERR("Failed to set LED %d brightness to %d"
134 ", err=%d\n", led, level, err);
135 return err;
136 }
137 k_sleep(FADE_DELAY);
138 }
139 k_sleep(SLEEP_DELAY);
140
141 /* Turn LED off. */
142 err = led_off(lp50xx_dev, led);
143 if (err < 0) {
144 LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
145 return err;
146 }
147 k_sleep(SLEEP_DELAY);
148 }
149
150 return 0;
151 }
152
153 /**
154 * @brief Run tests on all the LEDs using the channel-based API syscalls.
155 *
156 * @param lp50xx_dev LP50XX LED controller device.
157 */
run_channel_test(const struct device * lp50xx_dev,const uint8_t max_leds,const uint8_t bright_chan,const uint8_t color_chan)158 static int run_channel_test(const struct device *lp50xx_dev,
159 const uint8_t max_leds,
160 const uint8_t bright_chan,
161 const uint8_t color_chan)
162 {
163 uint8_t idx;
164 uint8_t buffer[LP50XX_COLORS_PER_LED * max_leds];
165 int err;
166
167 LOG_INF("Testing all LEDs (channel API)");
168
169 for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
170 uint8_t led;
171 uint16_t level;
172
173 /* Update LEDs colors. */
174 memset(buffer, 0, sizeof(buffer));
175 for (led = 0; led < max_leds; led++) {
176 const struct led_info *info;
177 uint8_t *col = &buffer[led * 3];
178
179 err = led_get_info(lp50xx_dev, led, &info);
180 if (err < 0) {
181 continue;
182 }
183
184 col = &buffer[info->index * 3];
185 err = prepare_color_buffer(info, col, idx);
186 if (err < 0) {
187 LOG_ERR("Failed to set color buffer, err=%d",
188 err);
189 return err;
190 }
191 }
192
193 err = led_write_channels(lp50xx_dev, color_chan,
194 LP50XX_COLORS_PER_LED *
195 max_leds,
196 buffer);
197 if (err < 0) {
198 LOG_ERR("Failed to write channels, start=%d num=%d"
199 " err=%d\n", color_chan,
200 LP50XX_COLORS_PER_LED * max_leds, err);
201 return err;
202 }
203 k_sleep(SLEEP_DELAY);
204
205 /* Turn LEDs on. */
206 memset(buffer, 0, sizeof(buffer));
207 for (led = 0; led < max_leds; led++) {
208 buffer[led] = MAX_BRIGHTNESS;
209 }
210 err = led_write_channels(lp50xx_dev,
211 bright_chan,
212 max_leds, buffer);
213 if (err < 0) {
214 LOG_ERR("Failed to write channels, start=%d num=%d"
215 " err=%d\n", bright_chan,
216 max_leds, err);
217 return err;
218 }
219 k_sleep(SLEEP_DELAY);
220
221 /* Turn LEDs off. */
222 for (led = 0; led < max_leds; led++) {
223 buffer[led] = 0;
224 }
225 err = led_write_channels(lp50xx_dev,
226 bright_chan,
227 max_leds, buffer);
228 if (err < 0) {
229 LOG_ERR("Failed to write channels, start=%d num=%d"
230 " err=%d\n", bright_chan,
231 max_leds, err);
232 return err;
233 }
234 k_sleep(SLEEP_DELAY);
235
236 /* Set LEDs brightnesses gradually to the maximum level. */
237 for (level = 0; level <= MAX_BRIGHTNESS; level++) {
238 for (led = 0; led < max_leds; led++) {
239 buffer[led] = level;
240 }
241 err = led_write_channels(lp50xx_dev,
242 bright_chan,
243 max_leds, buffer);
244 if (err < 0) {
245 LOG_ERR("Failed to write channels, start=%d"
246 " num=%d err=%d\n",
247 bright_chan,
248 max_leds, err);
249 return err;
250 }
251 k_sleep(FADE_DELAY);
252 }
253 k_sleep(SLEEP_DELAY);
254
255 /* Turn LEDs off. */
256 for (led = 0; led < max_leds; led++) {
257 buffer[led] = 0;
258 }
259 err = led_write_channels(lp50xx_dev,
260 bright_chan,
261 max_leds, buffer);
262 if (err < 0) {
263 LOG_ERR("Failed to write channels, start=%d "
264 "num=%d err=%d\n", bright_chan,
265 max_leds, err);
266 return err;
267 }
268 k_sleep(SLEEP_DELAY);
269 }
270
271 return 0;
272 }
273
run_test(const struct device * const lp50xx_dev,const uint8_t max_leds,const uint8_t bright_chan,const uint8_t color_chan)274 static int run_test(const struct device *const lp50xx_dev,
275 const uint8_t max_leds,
276 const uint8_t bright_chan,
277 const uint8_t color_chan)
278 {
279 int err;
280 uint8_t led;
281 uint8_t num_leds = 0;
282
283 for (led = 0; led < max_leds; led++) {
284 int col;
285 const struct led_info *info;
286
287 err = led_get_info(lp50xx_dev, led, &info);
288 if (err < 0) {
289 LOG_DBG("Failed to get information for LED %d (err=%d)",
290 led, err);
291 break;
292 }
293
294 /* Display LED information. */
295 printk("Found LED %d", led);
296 if (info->label) {
297 printk(" - %s", info->label);
298 }
299 printk(" - index:%d", info->index);
300 printk(" - %d colors", info->num_colors);
301 if (!info->color_mapping) {
302 continue;
303 }
304 printk(" - %d", info->color_mapping[0]);
305 for (col = 1; col < info->num_colors; col++) {
306 printk(":%d", info->color_mapping[col]);
307 }
308 printk("\n");
309 }
310
311 num_leds = led;
312 if (!num_leds) {
313 LOG_ERR("No LEDs found");
314 return 0;
315 }
316
317 do {
318 err = run_channel_test(lp50xx_dev, max_leds, bright_chan,
319 color_chan);
320 if (err) {
321 return 0;
322 }
323 for (led = 0; led < num_leds; led++) {
324 err = run_led_test(lp50xx_dev, led);
325 if (err) {
326 return 0;
327 }
328 }
329 } while (true);
330 return 0;
331 }
332
main(void)333 int main(void)
334 {
335 const struct device *lp50xx_dev;
336 bool found = false;
337
338 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5009);
339 if (lp50xx_dev) {
340 LOG_INF("Found LED controller %s", lp50xx_dev->name);
341 found = true;
342
343 if (device_is_ready(lp50xx_dev)) {
344 run_test(lp50xx_dev,
345 LP5009_MAX_LEDS,
346 LP50XX_LED_BRIGHT_CHAN_BASE,
347 LP5012_LED_COL_CHAN_BASE);
348 } else {
349 LOG_ERR("LED controller %s is not ready",
350 lp50xx_dev->name);
351 }
352 }
353
354 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5012);
355 if (lp50xx_dev) {
356 LOG_INF("Found LED controller %s", lp50xx_dev->name);
357 found = true;
358
359 if (device_is_ready(lp50xx_dev)) {
360 run_test(lp50xx_dev,
361 LP5012_MAX_LEDS,
362 LP50XX_LED_BRIGHT_CHAN_BASE,
363 LP5012_LED_COL_CHAN_BASE);
364 } else {
365 LOG_ERR("LED controller %s is not ready",
366 lp50xx_dev->name);
367 }
368 }
369
370 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5018);
371 if (lp50xx_dev) {
372 LOG_INF("Found LED controller %s", lp50xx_dev->name);
373 found = true;
374
375 if (device_is_ready(lp50xx_dev)) {
376 run_test(lp50xx_dev,
377 LP5018_MAX_LEDS,
378 LP50XX_LED_BRIGHT_CHAN_BASE,
379 LP5024_LED_COL_CHAN_BASE);
380 } else {
381 LOG_ERR("LED controller %s is not ready",
382 lp50xx_dev->name);
383 }
384 }
385
386 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5024);
387 if (lp50xx_dev) {
388 LOG_INF("Found LED controller %s", lp50xx_dev->name);
389 found = true;
390
391 if (device_is_ready(lp50xx_dev)) {
392 run_test(lp50xx_dev,
393 LP5024_MAX_LEDS,
394 LP50XX_LED_BRIGHT_CHAN_BASE,
395 LP5024_LED_COL_CHAN_BASE);
396 } else {
397 LOG_ERR("LED controller %s is not ready",
398 lp50xx_dev->name);
399 }
400 }
401
402 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5030);
403 if (lp50xx_dev) {
404 LOG_INF("Found LED controller %s", lp50xx_dev->name);
405 found = true;
406
407 if (device_is_ready(lp50xx_dev)) {
408 run_test(lp50xx_dev,
409 LP5030_MAX_LEDS,
410 LP50XX_LED_BRIGHT_CHAN_BASE,
411 LP5036_LED_COL_CHAN_BASE);
412 } else {
413 LOG_ERR("LED controller %s is not ready",
414 lp50xx_dev->name);
415 }
416 }
417
418 lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5036);
419 if (lp50xx_dev) {
420 LOG_INF("Found LED controller %s", lp50xx_dev->name);
421 found = true;
422
423 if (device_is_ready(lp50xx_dev)) {
424 run_test(lp50xx_dev,
425 LP5036_MAX_LEDS,
426 LP50XX_LED_BRIGHT_CHAN_BASE,
427 LP5036_LED_COL_CHAN_BASE);
428 } else {
429 LOG_ERR("LED controller %s is not ready",
430 lp50xx_dev->name);
431 }
432 }
433
434 if (!found) {
435 LOG_ERR("No LP50XX LED controller found");
436 }
437 return 0;
438 }
439