1 /*
2  * Copyright (c) 2020 Seagate Technology LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <shell/shell.h>
8 #include <drivers/led.h>
9 #include <stdlib.h>
10 
11 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
12 #include <logging/log.h>
13 LOG_MODULE_REGISTER(led_shell);
14 
15 #define MAX_CHANNEL_ARGS 8
16 
17 enum {
18 	arg_idx_dev		= 1,
19 	arg_idx_led		= 2,
20 	arg_idx_value		= 3,
21 };
22 
parse_common_args(const struct shell * shell,char ** argv,const struct device ** dev,uint32_t * led)23 static int parse_common_args(const struct shell *shell, char **argv,
24 			     const struct device * *dev, uint32_t *led)
25 {
26 	char *end_ptr;
27 
28 	*dev = device_get_binding(argv[arg_idx_dev]);
29 	if (!*dev) {
30 		shell_error(shell,
31 			    "LED device %s not found", argv[arg_idx_dev]);
32 		return -ENODEV;
33 	}
34 
35 	*led = strtoul(argv[arg_idx_led], &end_ptr, 0);
36 	if (*end_ptr != '\0') {
37 		shell_error(shell, "Invalid LED number parameter %s",
38 			    argv[arg_idx_led]);
39 		return -EINVAL;
40 	}
41 
42 	return 0;
43 }
44 
cmd_off(const struct shell * shell,size_t argc,char ** argv)45 static int cmd_off(const struct shell *shell, size_t argc, char **argv)
46 {
47 	const struct device *dev;
48 	uint32_t led;
49 	int err;
50 
51 	err = parse_common_args(shell, argv, &dev, &led);
52 	if (err < 0) {
53 		return err;
54 	}
55 
56 	shell_print(shell, "%s: turning off LED %d", dev->name, led);
57 
58 	err = led_off(dev, led);
59 	if (err) {
60 		shell_error(shell, "Error: %d", err);
61 	}
62 
63 	return err;
64 }
65 
cmd_on(const struct shell * shell,size_t argc,char ** argv)66 static int cmd_on(const struct shell *shell, size_t argc, char **argv)
67 {
68 	const struct device *dev;
69 	uint32_t led;
70 	int err;
71 
72 	err = parse_common_args(shell, argv, &dev, &led);
73 	if (err < 0) {
74 		return err;
75 	}
76 
77 	shell_print(shell, "%s: turning on LED %d", dev->name, led);
78 
79 	err = led_on(dev, led);
80 	if (err) {
81 		shell_error(shell, "Error: %d", err);
82 	}
83 
84 	return err;
85 }
86 
cmd_get_info(const struct shell * shell,size_t argc,char ** argv)87 static int cmd_get_info(const struct shell *shell, size_t argc, char **argv)
88 {
89 	const struct device *dev;
90 	uint32_t led;
91 	int err;
92 	const struct led_info *info;
93 	int i;
94 
95 	err = parse_common_args(shell, argv, &dev, &led);
96 	if (err < 0) {
97 		return err;
98 	}
99 
100 	shell_print(shell, "%s: getting LED %d information", dev->name, led);
101 
102 	err = led_get_info(dev, led, &info);
103 	if (err) {
104 		shell_error(shell, "Error: %d", err);
105 		return err;
106 	}
107 
108 	shell_print(shell, "Label      : %s", info->label ? : "<NULL>");
109 	shell_print(shell, "Index      : %d", info->index);
110 	shell_print(shell, "Num colors : %d", info->num_colors);
111 	if (info->color_mapping) {
112 		shell_fprintf(shell, SHELL_NORMAL, "Colors     : %d",
113 			      info->color_mapping[0]);
114 		for (i = 1; i < info->num_colors; i++) {
115 			shell_fprintf(shell, SHELL_NORMAL, ":%d",
116 				      info->color_mapping[i]);
117 		}
118 		shell_fprintf(shell, SHELL_NORMAL, "\n");
119 	}
120 
121 	return 0;
122 }
123 
cmd_set_brightness(const struct shell * shell,size_t argc,char ** argv)124 static int cmd_set_brightness(const struct shell *shell,
125 			      size_t argc, char **argv)
126 {
127 	const struct device *dev;
128 	uint32_t led;
129 	int err;
130 	char *end_ptr;
131 	unsigned long value;
132 
133 	err = parse_common_args(shell, argv, &dev, &led);
134 	if (err < 0) {
135 		return err;
136 	}
137 
138 	value = strtoul(argv[arg_idx_value], &end_ptr, 0);
139 	if (*end_ptr != '\0') {
140 		shell_error(shell, "Invalid LED brightness parameter %s",
141 			     argv[arg_idx_value]);
142 		return -EINVAL;
143 	}
144 	if (value > 100) {
145 		shell_error(shell, "Invalid LED brightness value %d (max 100)",
146 			    value);
147 		return -EINVAL;
148 	}
149 
150 	shell_print(shell, "%s: setting LED %d brightness to %d",
151 		    dev->name, led, value);
152 
153 	err = led_set_brightness(dev, led, (uint8_t) value);
154 	if (err) {
155 		shell_error(shell, "Error: %d", err);
156 	}
157 
158 	return err;
159 }
160 
cmd_set_color(const struct shell * shell,size_t argc,char ** argv)161 static int cmd_set_color(const struct shell *shell, size_t argc, char **argv)
162 {
163 	const struct device *dev;
164 	uint32_t led;
165 	int err;
166 	size_t num_colors;
167 	uint8_t i;
168 	uint8_t color[MAX_CHANNEL_ARGS];
169 
170 	err = parse_common_args(shell, argv, &dev, &led);
171 	if (err < 0) {
172 		return err;
173 	}
174 
175 	num_colors = argc - arg_idx_value;
176 	if (num_colors > MAX_CHANNEL_ARGS) {
177 		shell_error(shell,
178 			    "Invalid number of colors %d (max %d)",
179 			     num_colors, MAX_CHANNEL_ARGS);
180 		return -EINVAL;
181 	}
182 
183 	for (i = 0; i < num_colors; i++) {
184 		char *end_ptr;
185 		unsigned long col;
186 
187 		col = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
188 		if (*end_ptr != '\0') {
189 			shell_error(shell, "Invalid LED color parameter %s",
190 				    argv[arg_idx_value + i]);
191 			return -EINVAL;
192 		}
193 		if (col > 255) {
194 			shell_error(shell,
195 				    "Invalid LED color value %d (max 255)",
196 				    col);
197 			return -EINVAL;
198 		}
199 		color[i] = col;
200 	}
201 
202 	shell_fprintf(shell, SHELL_NORMAL, "%s: setting LED %d color to %d",
203 		      dev->name, led, color[0]);
204 	for (i = 1; i < num_colors; i++) {
205 		shell_fprintf(shell, SHELL_NORMAL, ":%d", color[i]);
206 	}
207 	shell_fprintf(shell, SHELL_NORMAL, "\n");
208 
209 	err = led_set_color(dev, led, num_colors, color);
210 	if (err) {
211 		shell_error(shell, "Error: %d", err);
212 	}
213 
214 	return err;
215 }
216 
cmd_set_channel(const struct shell * shell,size_t argc,char ** argv)217 static int cmd_set_channel(const struct shell *shell, size_t argc, char **argv)
218 {
219 	const struct device *dev;
220 	uint32_t channel;
221 	int err;
222 	char *end_ptr;
223 	unsigned long value;
224 
225 	err = parse_common_args(shell, argv, &dev, &channel);
226 	if (err < 0) {
227 		return err;
228 	}
229 
230 	value = strtoul(argv[arg_idx_value], &end_ptr, 0);
231 	if (*end_ptr != '\0') {
232 		shell_error(shell, "Invalid channel value parameter %s",
233 			     argv[arg_idx_value]);
234 		return -EINVAL;
235 	}
236 	if (value > 255) {
237 		shell_error(shell, "Invalid channel value %d (max 255)",
238 			    value);
239 		return -EINVAL;
240 	}
241 
242 	shell_print(shell, "%s: setting channel %d to %d",
243 		    dev->name, channel, value);
244 
245 	err = led_set_channel(dev, channel, (uint8_t) value);
246 	if (err) {
247 		shell_error(shell, "Error: %d", err);
248 	}
249 
250 	return err;
251 }
252 
253 static int
cmd_write_channels(const struct shell * shell,size_t argc,char ** argv)254 cmd_write_channels(const struct shell *shell, size_t argc, char **argv)
255 {
256 	const struct device *dev;
257 	uint32_t start_channel;
258 	int err;
259 	size_t num_channels;
260 	uint8_t i;
261 	uint8_t value[MAX_CHANNEL_ARGS];
262 
263 	err = parse_common_args(shell, argv, &dev, &start_channel);
264 	if (err < 0) {
265 		return err;
266 	}
267 
268 	num_channels = argc - arg_idx_value;
269 	if (num_channels > MAX_CHANNEL_ARGS) {
270 		shell_error(shell,
271 			    "Can't write %d channels (max %d)",
272 			     num_channels, MAX_CHANNEL_ARGS);
273 		return -EINVAL;
274 	}
275 
276 	for (i = 0; i < num_channels; i++) {
277 		char *end_ptr;
278 		unsigned long val;
279 
280 		val = strtoul(argv[arg_idx_value + i], &end_ptr, 0);
281 		if (*end_ptr != '\0') {
282 			shell_error(shell,
283 				    "Invalid channel value parameter %s",
284 				    argv[arg_idx_value + i]);
285 			return -EINVAL;
286 		}
287 		if (val > 255) {
288 			shell_error(shell,
289 				    "Invalid channel value %d (max 255)", val);
290 			return -EINVAL;
291 		}
292 		value[i] = val;
293 	}
294 
295 	shell_fprintf(shell, SHELL_NORMAL, "%s: writing from channel %d: %d",
296 		      dev->name, start_channel, value[0]);
297 	for (i = 1; i < num_channels; i++) {
298 		shell_fprintf(shell, SHELL_NORMAL, " %d", value[i]);
299 	}
300 	shell_fprintf(shell, SHELL_NORMAL, "\n");
301 
302 	err = led_write_channels(dev, start_channel, num_channels, value);
303 	if (err) {
304 		shell_error(shell, "Error: %d", err);
305 	}
306 
307 	return err;
308 }
309 
310 SHELL_STATIC_SUBCMD_SET_CREATE(sub_led,
311 	SHELL_CMD_ARG(off, NULL, "<device> <led>", cmd_off, 3, 0),
312 	SHELL_CMD_ARG(on, NULL, "<device> <led>", cmd_on, 3, 0),
313 	SHELL_CMD_ARG(get_info, NULL, "<device> <led>", cmd_get_info, 3, 0),
314 	SHELL_CMD_ARG(set_brightness, NULL, "<device> <led> <value [0-255]>",
315 		      cmd_set_brightness, 4, 0),
316 	SHELL_CMD_ARG(set_color, NULL,
317 		      "<device> <led> <color 0 [0-255]> ... <color N>",
318 		      cmd_set_color, 4, MAX_CHANNEL_ARGS - 1),
319 	SHELL_CMD_ARG(set_channel, NULL, "<device> <channel> <value [0-255]>",
320 		      cmd_set_channel, 4, 0),
321 	SHELL_CMD_ARG(write_channels, NULL,
322 		      "<device> <chan> <value 0 [0-255]> ... <value N>",
323 		      cmd_write_channels, 4, MAX_CHANNEL_ARGS - 1),
324 	SHELL_SUBCMD_SET_END
325 );
326 
327 SHELL_CMD_REGISTER(led, &sub_led, "LED commands", NULL);
328