1 /*
2 * Copyright (c) 2020 Seagate Technology LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/shell/shell.h>
8 #include <zephyr/drivers/led.h>
9 #include <zephyr/dt-bindings/led/led.h>
10 #include <stdlib.h>
11
12 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(led_shell);
15
16 #define MAX_CHANNEL_ARGS 8
17
18 enum {
19 arg_idx_dev = 1,
20 arg_idx_led = 2,
21 arg_idx_value = 3,
22 arg_idx_delay_on = 3,
23 arg_idx_delay_off = 4,
24 };
25
parse_common_args(const struct shell * sh,char ** argv,const struct device ** dev,uint32_t * led)26 static int parse_common_args(const struct shell *sh, char **argv,
27 const struct device * *dev, uint32_t *led)
28 {
29 char *end_ptr;
30
31 *dev = shell_device_get_binding(argv[arg_idx_dev]);
32 if (*dev == NULL) {
33 shell_error(sh,
34 "LED device %s not found", argv[arg_idx_dev]);
35 return -ENODEV;
36 }
37
38 *led = strtoul(argv[arg_idx_led], &end_ptr, 0);
39 if (*end_ptr != '\0') {
40 shell_error(sh, "Invalid LED number parameter %s",
41 argv[arg_idx_led]);
42 return -EINVAL;
43 }
44
45 return 0;
46 }
47
cmd_off(const struct shell * sh,size_t argc,char ** argv)48 static int cmd_off(const struct shell *sh, size_t argc, char **argv)
49 {
50 const struct device *dev;
51 uint32_t led;
52 int err;
53
54 err = parse_common_args(sh, argv, &dev, &led);
55 if (err < 0) {
56 return err;
57 }
58
59 shell_print(sh, "%s: turning off LED %d", dev->name, led);
60
61 err = led_off(dev, led);
62 if (err) {
63 shell_error(sh, "Error: %d", err);
64 }
65
66 return err;
67 }
68
cmd_on(const struct shell * sh,size_t argc,char ** argv)69 static int cmd_on(const struct shell *sh, size_t argc, char **argv)
70 {
71 const struct device *dev;
72 uint32_t led;
73 int err;
74
75 err = parse_common_args(sh, argv, &dev, &led);
76 if (err < 0) {
77 return err;
78 }
79
80 shell_print(sh, "%s: turning on LED %d", dev->name, led);
81
82 err = led_on(dev, led);
83 if (err) {
84 shell_error(sh, "Error: %d", err);
85 }
86
87 return err;
88 }
89
cmd_blink(const struct shell * sh,size_t argc,char ** argv)90 static int cmd_blink(const struct shell *sh, size_t argc, char **argv)
91 {
92 const struct device *dev;
93 uint32_t led, delay_on, delay_off;
94 char *end_ptr;
95 int err;
96
97 err = parse_common_args(sh, argv, &dev, &led);
98 if (err < 0) {
99 return err;
100 }
101
102 delay_on = strtoul(argv[arg_idx_delay_on], &end_ptr, 0);
103 if (*end_ptr != '\0') {
104 shell_error(sh, "Invalid delay_on parameter %s", argv[arg_idx_delay_on]);
105 return -EINVAL;
106 }
107
108 if (argc > arg_idx_delay_off) {
109 delay_off = strtoul(argv[arg_idx_delay_off], &end_ptr, 0);
110 if (*end_ptr != '\0') {
111 shell_error(sh, "Invalid delay_off parameter %s", argv[arg_idx_delay_off]);
112 return -EINVAL;
113 }
114 } else {
115 delay_off = delay_on;
116 }
117
118 shell_print(sh, "%s: blinking LED %d with %d ms on and %d ms off",
119 dev->name, led, delay_on, delay_off);
120
121 err = led_blink(dev, led, delay_on, delay_off);
122 if (err) {
123 shell_error(sh, "Error: %d", err);
124 }
125
126 return err;
127 }
128
led_color_to_str(uint8_t color)129 static const char *led_color_to_str(uint8_t color)
130 {
131 switch (color) {
132 case LED_COLOR_ID_WHITE:
133 return "white";
134 case LED_COLOR_ID_RED:
135 return "red";
136 case LED_COLOR_ID_GREEN:
137 return "green";
138 case LED_COLOR_ID_BLUE:
139 return "blue";
140 case LED_COLOR_ID_VIOLET:
141 return "violet";
142 case LED_COLOR_ID_YELLOW:
143 return "yellow";
144 case LED_COLOR_ID_IR:
145 return "IR";
146 default:
147 return "unknown";
148 }
149 }
150
cmd_get_info(const struct shell * sh,size_t argc,char ** argv)151 static int cmd_get_info(const struct shell *sh, size_t argc, char **argv)
152 {
153 const struct device *dev;
154 uint32_t led;
155 int err;
156 const struct led_info *info;
157 int i;
158
159 err = parse_common_args(sh, argv, &dev, &led);
160 if (err < 0) {
161 return err;
162 }
163
164 shell_print(sh, "%s: getting LED %d information", dev->name, led);
165
166 err = led_get_info(dev, led, &info);
167 if (err) {
168 shell_error(sh, "Error: %d", err);
169 return err;
170 }
171
172 shell_print(sh, "Label : %s", info->label ? : "<NULL>");
173 shell_print(sh, "Index : %d", info->index);
174 shell_print(sh, "Num colors : %d", info->num_colors);
175 if (info->color_mapping) {
176 shell_fprintf(sh, SHELL_NORMAL, "Colors : %s",
177 led_color_to_str(info->color_mapping[0]));
178 for (i = 1; i < info->num_colors; i++) {
179 shell_fprintf(sh, SHELL_NORMAL, ":%s",
180 led_color_to_str(info->color_mapping[i]));
181 }
182 shell_fprintf(sh, SHELL_NORMAL, "\n");
183 }
184
185 return 0;
186 }
187
cmd_set_brightness(const struct shell * sh,size_t argc,char ** argv)188 static int cmd_set_brightness(const struct shell *sh,
189 size_t argc, char **argv)
190 {
191 const struct device *dev;
192 uint32_t led;
193 int err;
194 char *end_ptr;
195 unsigned long value;
196
197 err = parse_common_args(sh, argv, &dev, &led);
198 if (err < 0) {
199 return err;
200 }
201
202 value = strtoul(argv[arg_idx_value], &end_ptr, 0);
203 if (*end_ptr != '\0') {
204 shell_error(sh, "Invalid LED brightness parameter %s",
205 argv[arg_idx_value]);
206 return -EINVAL;
207 }
208 if (value > LED_BRIGHTNESS_MAX) {
209 shell_error(sh, "Invalid LED brightness value %lu (max 100)",
210 value);
211 return -EINVAL;
212 }
213
214 shell_print(sh, "%s: setting LED %d brightness to %lu",
215 dev->name, led, value);
216
217 err = led_set_brightness(dev, led, (uint8_t) value);
218 if (err) {
219 shell_error(sh, "Error: %d", err);
220 }
221
222 return err;
223 }
224
cmd_set_color(const struct shell * sh,size_t argc,char ** argv)225 static int cmd_set_color(const struct shell *sh, size_t argc, char **argv)
226 {
227 const struct device *dev;
228 uint32_t led;
229 int err;
230 size_t num_colors;
231 uint8_t i;
232 uint8_t color[MAX_CHANNEL_ARGS];
233
234 err = parse_common_args(sh, argv, &dev, &led);
235 if (err < 0) {
236 return err;
237 }
238
239 num_colors = argc - arg_idx_value;
240 if (num_colors > MAX_CHANNEL_ARGS) {
241 shell_error(sh,
242 "Invalid number of colors %d (max %d)",
243 num_colors, MAX_CHANNEL_ARGS);
244 return -EINVAL;
245 }
246
247 for (i = 0; i < num_colors; i++) {
248 char *end_ptr;
249 unsigned long col;
250
251 col = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
252 if (*end_ptr != '\0') {
253 shell_error(sh, "Invalid LED color parameter %s",
254 argv[arg_idx_value + i]);
255 return -EINVAL;
256 }
257 if (col > 255) {
258 shell_error(sh,
259 "Invalid LED color value %lu (max 255)",
260 col);
261 return -EINVAL;
262 }
263 color[i] = col;
264 }
265
266 shell_fprintf(sh, SHELL_NORMAL, "%s: setting LED %d color to %d",
267 dev->name, led, color[0]);
268 for (i = 1; i < num_colors; i++) {
269 shell_fprintf(sh, SHELL_NORMAL, ":%d", color[i]);
270 }
271 shell_fprintf(sh, SHELL_NORMAL, "\n");
272
273 err = led_set_color(dev, led, num_colors, color);
274 if (err) {
275 shell_error(sh, "Error: %d", err);
276 }
277
278 return err;
279 }
280
cmd_set_channel(const struct shell * sh,size_t argc,char ** argv)281 static int cmd_set_channel(const struct shell *sh, size_t argc, char **argv)
282 {
283 const struct device *dev;
284 uint32_t channel;
285 int err;
286 char *end_ptr;
287 unsigned long value;
288
289 err = parse_common_args(sh, argv, &dev, &channel);
290 if (err < 0) {
291 return err;
292 }
293
294 value = strtoul(argv[arg_idx_value], &end_ptr, 0);
295 if (*end_ptr != '\0') {
296 shell_error(sh, "Invalid channel value parameter %s",
297 argv[arg_idx_value]);
298 return -EINVAL;
299 }
300 if (value > 255) {
301 shell_error(sh, "Invalid channel value %lu (max 255)",
302 value);
303 return -EINVAL;
304 }
305
306 shell_print(sh, "%s: setting channel %d to %lu",
307 dev->name, channel, value);
308
309 err = led_set_channel(dev, channel, (uint8_t) value);
310 if (err) {
311 shell_error(sh, "Error: %d", err);
312 }
313
314 return err;
315 }
316
317 static int
cmd_write_channels(const struct shell * sh,size_t argc,char ** argv)318 cmd_write_channels(const struct shell *sh, size_t argc, char **argv)
319 {
320 const struct device *dev;
321 uint32_t start_channel;
322 int err;
323 size_t num_channels;
324 uint8_t i;
325 uint8_t value[MAX_CHANNEL_ARGS];
326
327 err = parse_common_args(sh, argv, &dev, &start_channel);
328 if (err < 0) {
329 return err;
330 }
331
332 num_channels = argc - arg_idx_value;
333 if (num_channels > MAX_CHANNEL_ARGS) {
334 shell_error(sh,
335 "Can't write %d channels (max %d)",
336 num_channels, MAX_CHANNEL_ARGS);
337 return -EINVAL;
338 }
339
340 for (i = 0; i < num_channels; i++) {
341 char *end_ptr;
342 unsigned long val;
343
344 val = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
345 if (*end_ptr != '\0') {
346 shell_error(sh,
347 "Invalid channel value parameter %s",
348 argv[arg_idx_value + i]);
349 return -EINVAL;
350 }
351 if (val > 255) {
352 shell_error(sh,
353 "Invalid channel value %lu (max 255)", val);
354 return -EINVAL;
355 }
356 value[i] = val;
357 }
358
359 shell_fprintf(sh, SHELL_NORMAL, "%s: writing from channel %d: %d",
360 dev->name, start_channel, value[0]);
361 for (i = 1; i < num_channels; i++) {
362 shell_fprintf(sh, SHELL_NORMAL, " %d", value[i]);
363 }
364 shell_fprintf(sh, SHELL_NORMAL, "\n");
365
366 err = led_write_channels(dev, start_channel, num_channels, value);
367 if (err) {
368 shell_error(sh, "Error: %d", err);
369 }
370
371 return err;
372 }
373
device_is_led(const struct device * dev)374 static bool device_is_led(const struct device *dev)
375 {
376 return DEVICE_API_IS(led, dev);
377 }
378
device_name_get(size_t idx,struct shell_static_entry * entry)379 static void device_name_get(size_t idx, struct shell_static_entry *entry)
380 {
381 const struct device *dev = shell_device_filter(idx, device_is_led);
382
383 entry->syntax = (dev != NULL) ? dev->name : NULL;
384 entry->handler = NULL;
385 entry->help = NULL;
386 entry->subcmd = NULL;
387 }
388
389 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
390
391 SHELL_STATIC_SUBCMD_SET_CREATE(
392 sub_led,
393 SHELL_CMD_ARG(off, &dsub_device_name, SHELL_HELP("Turn off LED", "<device> <led>"), cmd_off,
394 3, 0),
395 SHELL_CMD_ARG(on, &dsub_device_name, SHELL_HELP("Turn on LED", "<device> <led>"), cmd_on, 3,
396 0),
397 SHELL_CMD_ARG(blink, &dsub_device_name,
398 SHELL_HELP("Blink LED on and off",
399 "<device> <led> <delay_on_in_ms> [<delay_off_in_ms>]"),
400 cmd_blink, 4, 1),
401 SHELL_CMD_ARG(get_info, &dsub_device_name,
402 SHELL_HELP("Get LED information", "<device> <led>"), cmd_get_info, 3, 0),
403 SHELL_CMD_ARG(set_brightness, &dsub_device_name,
404 SHELL_HELP("Set LED brightness",
405 "<device> <led> <value>\n"
406 "value: 0-100"),
407 cmd_set_brightness, 4, 0),
408 SHELL_CMD_ARG(set_color, &dsub_device_name,
409 SHELL_HELP("Set LED color",
410 "<device> <led> <color0> ... <colorN>\n"
411 "colorN: raw value of the N-th color channel (0-255)"),
412 cmd_set_color, 4, MAX_CHANNEL_ARGS - 1),
413 SHELL_CMD_ARG(set_channel, &dsub_device_name,
414 SHELL_HELP("Set LED channel",
415 "<device> <channel> <value>\n"
416 "value: raw channel value (0-255)"),
417 cmd_set_channel, 4, 0),
418 SHELL_CMD_ARG(write_channels, &dsub_device_name,
419 SHELL_HELP("Write to LED channels",
420 "<device> <channel> <value0> ... <valueN>\n"
421 "valueN: raw value of the N-th channel (0-255)"),
422 cmd_write_channels, 4, MAX_CHANNEL_ARGS - 1),
423 SHELL_SUBCMD_SET_END);
424
425 SHELL_CMD_REGISTER(led, &sub_led, "LED commands", NULL);
426