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 };
23
parse_common_args(const struct shell * sh,char ** argv,const struct device ** dev,uint32_t * led)24 static int parse_common_args(const struct shell *sh, char **argv,
25 const struct device * *dev, uint32_t *led)
26 {
27 char *end_ptr;
28
29 *dev = shell_device_get_binding(argv[arg_idx_dev]);
30 if (!*dev) {
31 shell_error(sh,
32 "LED device %s not found", argv[arg_idx_dev]);
33 return -ENODEV;
34 }
35
36 *led = strtoul(argv[arg_idx_led], &end_ptr, 0);
37 if (*end_ptr != '\0') {
38 shell_error(sh, "Invalid LED number parameter %s",
39 argv[arg_idx_led]);
40 return -EINVAL;
41 }
42
43 return 0;
44 }
45
cmd_off(const struct shell * sh,size_t argc,char ** argv)46 static int cmd_off(const struct shell *sh, size_t argc, char **argv)
47 {
48 const struct device *dev;
49 uint32_t led;
50 int err;
51
52 err = parse_common_args(sh, argv, &dev, &led);
53 if (err < 0) {
54 return err;
55 }
56
57 shell_print(sh, "%s: turning off LED %d", dev->name, led);
58
59 err = led_off(dev, led);
60 if (err) {
61 shell_error(sh, "Error: %d", err);
62 }
63
64 return err;
65 }
66
cmd_on(const struct shell * sh,size_t argc,char ** argv)67 static int cmd_on(const struct shell *sh, size_t argc, char **argv)
68 {
69 const struct device *dev;
70 uint32_t led;
71 int err;
72
73 err = parse_common_args(sh, argv, &dev, &led);
74 if (err < 0) {
75 return err;
76 }
77
78 shell_print(sh, "%s: turning on LED %d", dev->name, led);
79
80 err = led_on(dev, led);
81 if (err) {
82 shell_error(sh, "Error: %d", err);
83 }
84
85 return err;
86 }
87
led_color_to_str(uint8_t color)88 static const char *led_color_to_str(uint8_t color)
89 {
90 switch (color) {
91 case LED_COLOR_ID_WHITE:
92 return "white";
93 case LED_COLOR_ID_RED:
94 return "red";
95 case LED_COLOR_ID_GREEN:
96 return "green";
97 case LED_COLOR_ID_BLUE:
98 return "blue";
99 case LED_COLOR_ID_VIOLET:
100 return "violet";
101 case LED_COLOR_ID_YELLOW:
102 return "yellow";
103 case LED_COLOR_ID_IR:
104 return "IR";
105 default:
106 return "unknown";
107 }
108 }
109
cmd_get_info(const struct shell * sh,size_t argc,char ** argv)110 static int cmd_get_info(const struct shell *sh, size_t argc, char **argv)
111 {
112 const struct device *dev;
113 uint32_t led;
114 int err;
115 const struct led_info *info;
116 int i;
117
118 err = parse_common_args(sh, argv, &dev, &led);
119 if (err < 0) {
120 return err;
121 }
122
123 shell_print(sh, "%s: getting LED %d information", dev->name, led);
124
125 err = led_get_info(dev, led, &info);
126 if (err) {
127 shell_error(sh, "Error: %d", err);
128 return err;
129 }
130
131 shell_print(sh, "Label : %s", info->label ? : "<NULL>");
132 shell_print(sh, "Index : %d", info->index);
133 shell_print(sh, "Num colors : %d", info->num_colors);
134 if (info->color_mapping) {
135 shell_fprintf(sh, SHELL_NORMAL, "Colors : %s",
136 led_color_to_str(info->color_mapping[0]));
137 for (i = 1; i < info->num_colors; i++) {
138 shell_fprintf(sh, SHELL_NORMAL, ":%s",
139 led_color_to_str(info->color_mapping[i]));
140 }
141 shell_fprintf(sh, SHELL_NORMAL, "\n");
142 }
143
144 return 0;
145 }
146
cmd_set_brightness(const struct shell * sh,size_t argc,char ** argv)147 static int cmd_set_brightness(const struct shell *sh,
148 size_t argc, char **argv)
149 {
150 const struct device *dev;
151 uint32_t led;
152 int err;
153 char *end_ptr;
154 unsigned long value;
155
156 err = parse_common_args(sh, argv, &dev, &led);
157 if (err < 0) {
158 return err;
159 }
160
161 value = strtoul(argv[arg_idx_value], &end_ptr, 0);
162 if (*end_ptr != '\0') {
163 shell_error(sh, "Invalid LED brightness parameter %s",
164 argv[arg_idx_value]);
165 return -EINVAL;
166 }
167 if (value > 100) {
168 shell_error(sh, "Invalid LED brightness value %lu (max 100)",
169 value);
170 return -EINVAL;
171 }
172
173 shell_print(sh, "%s: setting LED %d brightness to %lu",
174 dev->name, led, value);
175
176 err = led_set_brightness(dev, led, (uint8_t) value);
177 if (err) {
178 shell_error(sh, "Error: %d", err);
179 }
180
181 return err;
182 }
183
cmd_set_color(const struct shell * sh,size_t argc,char ** argv)184 static int cmd_set_color(const struct shell *sh, size_t argc, char **argv)
185 {
186 const struct device *dev;
187 uint32_t led;
188 int err;
189 size_t num_colors;
190 uint8_t i;
191 uint8_t color[MAX_CHANNEL_ARGS];
192
193 err = parse_common_args(sh, argv, &dev, &led);
194 if (err < 0) {
195 return err;
196 }
197
198 num_colors = argc - arg_idx_value;
199 if (num_colors > MAX_CHANNEL_ARGS) {
200 shell_error(sh,
201 "Invalid number of colors %d (max %d)",
202 num_colors, MAX_CHANNEL_ARGS);
203 return -EINVAL;
204 }
205
206 for (i = 0; i < num_colors; i++) {
207 char *end_ptr;
208 unsigned long col;
209
210 col = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
211 if (*end_ptr != '\0') {
212 shell_error(sh, "Invalid LED color parameter %s",
213 argv[arg_idx_value + i]);
214 return -EINVAL;
215 }
216 if (col > 255) {
217 shell_error(sh,
218 "Invalid LED color value %lu (max 255)",
219 col);
220 return -EINVAL;
221 }
222 color[i] = col;
223 }
224
225 shell_fprintf(sh, SHELL_NORMAL, "%s: setting LED %d color to %d",
226 dev->name, led, color[0]);
227 for (i = 1; i < num_colors; i++) {
228 shell_fprintf(sh, SHELL_NORMAL, ":%d", color[i]);
229 }
230 shell_fprintf(sh, SHELL_NORMAL, "\n");
231
232 err = led_set_color(dev, led, num_colors, color);
233 if (err) {
234 shell_error(sh, "Error: %d", err);
235 }
236
237 return err;
238 }
239
cmd_set_channel(const struct shell * sh,size_t argc,char ** argv)240 static int cmd_set_channel(const struct shell *sh, size_t argc, char **argv)
241 {
242 const struct device *dev;
243 uint32_t channel;
244 int err;
245 char *end_ptr;
246 unsigned long value;
247
248 err = parse_common_args(sh, argv, &dev, &channel);
249 if (err < 0) {
250 return err;
251 }
252
253 value = strtoul(argv[arg_idx_value], &end_ptr, 0);
254 if (*end_ptr != '\0') {
255 shell_error(sh, "Invalid channel value parameter %s",
256 argv[arg_idx_value]);
257 return -EINVAL;
258 }
259 if (value > 255) {
260 shell_error(sh, "Invalid channel value %lu (max 255)",
261 value);
262 return -EINVAL;
263 }
264
265 shell_print(sh, "%s: setting channel %d to %lu",
266 dev->name, channel, value);
267
268 err = led_set_channel(dev, channel, (uint8_t) value);
269 if (err) {
270 shell_error(sh, "Error: %d", err);
271 }
272
273 return err;
274 }
275
276 static int
cmd_write_channels(const struct shell * sh,size_t argc,char ** argv)277 cmd_write_channels(const struct shell *sh, size_t argc, char **argv)
278 {
279 const struct device *dev;
280 uint32_t start_channel;
281 int err;
282 size_t num_channels;
283 uint8_t i;
284 uint8_t value[MAX_CHANNEL_ARGS];
285
286 err = parse_common_args(sh, argv, &dev, &start_channel);
287 if (err < 0) {
288 return err;
289 }
290
291 num_channels = argc - arg_idx_value;
292 if (num_channels > MAX_CHANNEL_ARGS) {
293 shell_error(sh,
294 "Can't write %d channels (max %d)",
295 num_channels, MAX_CHANNEL_ARGS);
296 return -EINVAL;
297 }
298
299 for (i = 0; i < num_channels; i++) {
300 char *end_ptr;
301 unsigned long val;
302
303 val = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
304 if (*end_ptr != '\0') {
305 shell_error(sh,
306 "Invalid channel value parameter %s",
307 argv[arg_idx_value + i]);
308 return -EINVAL;
309 }
310 if (val > 255) {
311 shell_error(sh,
312 "Invalid channel value %lu (max 255)", val);
313 return -EINVAL;
314 }
315 value[i] = val;
316 }
317
318 shell_fprintf(sh, SHELL_NORMAL, "%s: writing from channel %d: %d",
319 dev->name, start_channel, value[0]);
320 for (i = 1; i < num_channels; i++) {
321 shell_fprintf(sh, SHELL_NORMAL, " %d", value[i]);
322 }
323 shell_fprintf(sh, SHELL_NORMAL, "\n");
324
325 err = led_write_channels(dev, start_channel, num_channels, value);
326 if (err) {
327 shell_error(sh, "Error: %d", err);
328 }
329
330 return err;
331 }
332
device_is_led_and_ready(const struct device * dev)333 static bool device_is_led_and_ready(const struct device *dev)
334 {
335 return device_is_ready(dev) && DEVICE_API_IS(led, dev);
336 }
337
device_name_get(size_t idx,struct shell_static_entry * entry)338 static void device_name_get(size_t idx, struct shell_static_entry *entry)
339 {
340 const struct device *dev = shell_device_filter(idx, device_is_led_and_ready);
341
342 entry->syntax = (dev != NULL) ? dev->name : NULL;
343 entry->handler = NULL;
344 entry->help = NULL;
345 entry->subcmd = NULL;
346 }
347
348 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
349
350 SHELL_STATIC_SUBCMD_SET_CREATE(
351 sub_led, SHELL_CMD_ARG(off, &dsub_device_name, "<device> <led>", cmd_off, 3, 0),
352 SHELL_CMD_ARG(on, &dsub_device_name, "<device> <led>", cmd_on, 3, 0),
353 SHELL_CMD_ARG(get_info, &dsub_device_name, "<device> <led>", cmd_get_info, 3, 0),
354 SHELL_CMD_ARG(set_brightness, &dsub_device_name, "<device> <led> <value [0-100]>",
355 cmd_set_brightness, 4, 0),
356 SHELL_CMD_ARG(set_color, &dsub_device_name,
357 "<device> <led> <color 0 [0-255]> ... <color N>", cmd_set_color, 4,
358 MAX_CHANNEL_ARGS - 1),
359 SHELL_CMD_ARG(set_channel, &dsub_device_name, "<device> <channel> <value [0-255]>",
360 cmd_set_channel, 4, 0),
361 SHELL_CMD_ARG(write_channels, &dsub_device_name,
362 "<device> <chan> <value 0 [0-255]> ... <value N>", cmd_write_channels, 4,
363 MAX_CHANNEL_ARGS - 1),
364 SHELL_SUBCMD_SET_END);
365
366 SHELL_CMD_REGISTER(led, &sub_led, "LED commands", NULL);
367