1 /*
2  * Copyright (c) 2015 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/version.h>
10 #include <zephyr/logging/log.h>
11 #include <stdlib.h>
12 #include <zephyr/drivers/uart.h>
13 #include <zephyr/usb/usb_device.h>
14 #include <ctype.h>
15 
16 #ifdef CONFIG_ARCH_POSIX
17 #include <unistd.h>
18 #else
19 #include <zephyr/posix/unistd.h>
20 #endif
21 
22 LOG_MODULE_REGISTER(app);
23 
24 extern void foo(void);
25 
timer_expired_handler(struct k_timer * timer)26 void timer_expired_handler(struct k_timer *timer)
27 {
28 	LOG_INF("Timer expired.");
29 
30 	/* Call another module to present logging from multiple sources. */
31 	foo();
32 }
33 
34 K_TIMER_DEFINE(log_timer, timer_expired_handler, NULL);
35 
cmd_log_test_start(const struct shell * sh,size_t argc,char ** argv,uint32_t period)36 static int cmd_log_test_start(const struct shell *sh, size_t argc,
37 			      char **argv, uint32_t period)
38 {
39 	ARG_UNUSED(argv);
40 
41 	k_timer_start(&log_timer, K_MSEC(period), K_MSEC(period));
42 	shell_print(sh, "Log test started\n");
43 
44 	return 0;
45 }
46 
cmd_log_test_start_demo(const struct shell * sh,size_t argc,char ** argv)47 static int cmd_log_test_start_demo(const struct shell *sh, size_t argc,
48 				   char **argv)
49 {
50 	return cmd_log_test_start(sh, argc, argv, 200);
51 }
52 
cmd_log_test_start_flood(const struct shell * sh,size_t argc,char ** argv)53 static int cmd_log_test_start_flood(const struct shell *sh, size_t argc,
54 				    char **argv)
55 {
56 	return cmd_log_test_start(sh, argc, argv, 10);
57 }
58 
cmd_log_test_stop(const struct shell * sh,size_t argc,char ** argv)59 static int cmd_log_test_stop(const struct shell *sh, size_t argc,
60 			     char **argv)
61 {
62 	ARG_UNUSED(argc);
63 	ARG_UNUSED(argv);
64 
65 	k_timer_stop(&log_timer);
66 	shell_print(sh, "Log test stopped");
67 
68 	return 0;
69 }
70 
71 SHELL_STATIC_SUBCMD_SET_CREATE(sub_log_test_start,
72 	SHELL_CMD_ARG(demo, NULL,
73 		  "Start log timer which generates log message every 200ms.",
74 		  cmd_log_test_start_demo, 1, 0),
75 	SHELL_CMD_ARG(flood, NULL,
76 		  "Start log timer which generates log message every 10ms.",
77 		  cmd_log_test_start_flood, 1, 0),
78 	SHELL_SUBCMD_SET_END /* Array terminated. */
79 );
80 SHELL_STATIC_SUBCMD_SET_CREATE(sub_log_test,
81 	SHELL_CMD_ARG(start, &sub_log_test_start, "Start log test", NULL, 2, 0),
82 	SHELL_CMD_ARG(stop, NULL, "Stop log test.", cmd_log_test_stop, 1, 0),
83 	SHELL_SUBCMD_SET_END /* Array terminated. */
84 );
85 
86 SHELL_CMD_REGISTER(log_test, &sub_log_test, "Log test", NULL);
87 
cmd_demo_ping(const struct shell * sh,size_t argc,char ** argv)88 static int cmd_demo_ping(const struct shell *sh, size_t argc, char **argv)
89 {
90 	ARG_UNUSED(argc);
91 	ARG_UNUSED(argv);
92 
93 	shell_print(sh, "pong");
94 
95 	return 0;
96 }
97 
cmd_demo_board(const struct shell * sh,size_t argc,char ** argv)98 static int cmd_demo_board(const struct shell *sh, size_t argc, char **argv)
99 {
100 	ARG_UNUSED(argc);
101 	ARG_UNUSED(argv);
102 
103 	shell_print(sh, CONFIG_BOARD);
104 
105 	return 0;
106 }
107 
108 #if defined CONFIG_SHELL_GETOPT
109 /* Thread save usage */
cmd_demo_getopt_ts(const struct shell * sh,size_t argc,char ** argv)110 static int cmd_demo_getopt_ts(const struct shell *sh, size_t argc,
111 			      char **argv)
112 {
113 	struct getopt_state *state;
114 	char *cvalue = NULL;
115 	int aflag = 0;
116 	int bflag = 0;
117 	int c;
118 
119 	while ((c = getopt(argc, argv, "abhc:")) != -1) {
120 		state = getopt_state_get();
121 		switch (c) {
122 		case 'a':
123 			aflag = 1;
124 			break;
125 		case 'b':
126 			bflag = 1;
127 			break;
128 		case 'c':
129 			cvalue = state->optarg;
130 			break;
131 		case 'h':
132 			/* When getopt is active shell is not parsing
133 			 * command handler to print help message. It must
134 			 * be done explicitly.
135 			 */
136 			shell_help(sh);
137 			return SHELL_CMD_HELP_PRINTED;
138 		case '?':
139 			if (state->optopt == 'c') {
140 				shell_print(sh,
141 					"Option -%c requires an argument.",
142 					state->optopt);
143 			} else if (isprint(state->optopt) != 0) {
144 				shell_print(sh,
145 					"Unknown option `-%c'.",
146 					state->optopt);
147 			} else {
148 				shell_print(sh,
149 					"Unknown option character `\\x%x'.",
150 					state->optopt);
151 			}
152 			return 1;
153 		default:
154 			break;
155 		}
156 	}
157 
158 	shell_print(sh, "aflag = %d, bflag = %d", aflag, bflag);
159 	return 0;
160 }
161 
cmd_demo_getopt(const struct shell * sh,size_t argc,char ** argv)162 static int cmd_demo_getopt(const struct shell *sh, size_t argc,
163 			      char **argv)
164 {
165 	char *cvalue = NULL;
166 	int aflag = 0;
167 	int bflag = 0;
168 	int c;
169 
170 	while ((c = getopt(argc, argv, "abhc:")) != -1) {
171 		switch (c) {
172 		case 'a':
173 			aflag = 1;
174 			break;
175 		case 'b':
176 			bflag = 1;
177 			break;
178 		case 'c':
179 			cvalue = optarg;
180 			break;
181 		case 'h':
182 			/* When getopt is active shell is not parsing
183 			 * command handler to print help message. It must
184 			 * be done explicitly.
185 			 */
186 			shell_help(sh);
187 			return SHELL_CMD_HELP_PRINTED;
188 		case '?':
189 			if (optopt == 'c') {
190 				shell_print(sh,
191 					"Option -%c requires an argument.",
192 					optopt);
193 			} else if (isprint(optopt) != 0) {
194 				shell_print(sh, "Unknown option `-%c'.",
195 					optopt);
196 			} else {
197 				shell_print(sh,
198 					"Unknown option character `\\x%x'.",
199 					optopt);
200 			}
201 			return 1;
202 		default:
203 			break;
204 		}
205 	}
206 
207 	shell_print(sh, "aflag = %d, bflag = %d", aflag, bflag);
208 	return 0;
209 }
210 #endif
211 
cmd_demo_params(const struct shell * sh,size_t argc,char ** argv)212 static int cmd_demo_params(const struct shell *sh, size_t argc, char **argv)
213 {
214 	shell_print(sh, "argc = %zd", argc);
215 	for (size_t cnt = 0; cnt < argc; cnt++) {
216 		shell_print(sh, "  argv[%zd] = %s", cnt, argv[cnt]);
217 	}
218 
219 	return 0;
220 }
221 
cmd_demo_hexdump(const struct shell * sh,size_t argc,char ** argv)222 static int cmd_demo_hexdump(const struct shell *sh, size_t argc, char **argv)
223 {
224 	shell_print(sh, "argc = %zd", argc);
225 	for (size_t cnt = 0; cnt < argc; cnt++) {
226 		shell_print(sh, "argv[%zd]", cnt);
227 		shell_hexdump(sh, argv[cnt], strlen(argv[cnt]));
228 	}
229 
230 	return 0;
231 }
232 
cmd_version(const struct shell * sh,size_t argc,char ** argv)233 static int cmd_version(const struct shell *sh, size_t argc, char **argv)
234 {
235 	ARG_UNUSED(argc);
236 	ARG_UNUSED(argv);
237 
238 	shell_print(sh, "Zephyr version %s", KERNEL_VERSION_STRING);
239 
240 	return 0;
241 }
242 
set_bypass(const struct shell * sh,shell_bypass_cb_t bypass)243 static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
244 {
245 	static bool in_use;
246 
247 	if (bypass && in_use) {
248 		shell_error(sh, "Sample supports setting bypass on single instance.");
249 
250 		return -EBUSY;
251 	}
252 
253 	in_use = !in_use;
254 	if (in_use) {
255 		shell_print(sh, "Bypass started, press ctrl-x ctrl-q to escape");
256 		in_use = true;
257 	}
258 
259 	shell_set_bypass(sh, bypass);
260 
261 	return 0;
262 }
263 
264 #define CHAR_1 0x18
265 #define CHAR_2 0x11
266 
bypass_cb(const struct shell * sh,uint8_t * data,size_t len)267 static void bypass_cb(const struct shell *sh, uint8_t *data, size_t len)
268 {
269 	static uint8_t tail;
270 	bool escape = false;
271 
272 	/* Check if escape criteria is met. */
273 	if (tail == CHAR_1 && data[0] == CHAR_2) {
274 		escape = true;
275 	} else {
276 		for (int i = 0; i < (len - 1); i++) {
277 			if (data[i] == CHAR_1 && data[i + 1] == CHAR_2) {
278 				escape = true;
279 				break;
280 			}
281 		}
282 	}
283 
284 	if (escape) {
285 		shell_print(sh, "Exit bypass");
286 		set_bypass(sh, NULL);
287 		tail = 0;
288 		return;
289 	}
290 
291 	/* Store last byte for escape sequence detection */
292 	tail = data[len - 1];
293 
294 	/* Do the data processing. */
295 	for (int i = 0; i < len; i++) {
296 		shell_fprintf(sh, SHELL_INFO, "%02x ", data[i]);
297 	}
298 	shell_fprintf(sh, SHELL_INFO, "| ");
299 
300 	for (int i = 0; i < len; i++) {
301 		shell_fprintf(sh, SHELL_INFO, "%c", data[i]);
302 	}
303 	shell_fprintf(sh, SHELL_INFO, "\n");
304 
305 }
306 
cmd_bypass(const struct shell * sh,size_t argc,char ** argv)307 static int cmd_bypass(const struct shell *sh, size_t argc, char **argv)
308 {
309 	return set_bypass(sh, bypass_cb);
310 }
311 
cmd_dict(const struct shell * sh,size_t argc,char ** argv,void * data)312 static int cmd_dict(const struct shell *sh, size_t argc, char **argv,
313 		    void *data)
314 {
315 	int val = (intptr_t)data;
316 
317 	shell_print(sh, "(syntax, value) : (%s, %d)", argv[0], val);
318 
319 	return 0;
320 }
321 
322 SHELL_SUBCMD_DICT_SET_CREATE(sub_dict_cmds, cmd_dict,
323 	(value_0, 0, "value 0"), (value_1, 1, "value 1"),
324 	(value_2, 2, "value 2"), (value_3, 3, "value 3")
325 );
326 
327 SHELL_STATIC_SUBCMD_SET_CREATE(sub_demo,
328 	SHELL_CMD(dictionary, &sub_dict_cmds, "Dictionary commands", NULL),
329 	SHELL_CMD(hexdump, NULL, "Hexdump params command.", cmd_demo_hexdump),
330 	SHELL_CMD(params, NULL, "Print params command.", cmd_demo_params),
331 	SHELL_CMD(ping, NULL, "Ping command.", cmd_demo_ping),
332 	SHELL_CMD(board, NULL, "Show board name command.", cmd_demo_board),
333 #if defined CONFIG_SHELL_GETOPT
334 	SHELL_CMD(getopt_thread_safe, NULL,
335 		  "Cammand using getopt in thread safe way"
336 		  " looking for: \"abhc:\".",
337 		  cmd_demo_getopt_ts),
338 	SHELL_CMD(getopt, NULL, "Cammand using getopt in non thread safe way"
339 		  " looking for: \"abhc:\".\n", cmd_demo_getopt),
340 #endif
341 	SHELL_SUBCMD_SET_END /* Array terminated. */
342 );
343 SHELL_CMD_REGISTER(demo, &sub_demo, "Demo commands", NULL);
344 
345 SHELL_CMD_ARG_REGISTER(version, NULL, "Show kernel version", cmd_version, 1, 0);
346 
347 SHELL_CMD_ARG_REGISTER(bypass, NULL, "Bypass shell", cmd_bypass, 1, 0);
348 
349 /* Create a set of commands. Commands to this set are added using @ref SHELL_SUBCMD_ADD
350  * and @ref SHELL_SUBCMD_COND_ADD.
351  */
352 SHELL_SUBCMD_SET_CREATE(sub_section_cmd, (section_cmd));
353 
cmd1_handler(const struct shell * sh,size_t argc,char ** argv)354 static int cmd1_handler(const struct shell *sh, size_t argc, char **argv)
355 {
356 	ARG_UNUSED(sh);
357 	ARG_UNUSED(argc);
358 	ARG_UNUSED(argv);
359 
360 	shell_print(sh, "cmd1 executed");
361 
362 	return 0;
363 }
364 
365 /* Create a set of subcommands for "section_cmd cm1". */
366 SHELL_SUBCMD_SET_CREATE(sub_section_cmd1, (section_cmd, cmd1));
367 
368 /* Add command to the set. Subcommand set is identify by parent shell command. */
369 SHELL_SUBCMD_ADD((section_cmd), cmd1, &sub_section_cmd1, "help for cmd1", cmd1_handler, 1, 0);
370 
371 SHELL_CMD_REGISTER(section_cmd, &sub_section_cmd,
372 		   "Demo command using section for subcommand registration", NULL);
373 
main(void)374 int main(void)
375 {
376 #if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_shell_uart), zephyr_cdc_acm_uart)
377 	const struct device *dev;
378 	uint32_t dtr = 0;
379 
380 	dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_uart));
381 	if (!device_is_ready(dev) || usb_enable(NULL)) {
382 		return 0;
383 	}
384 
385 	while (!dtr) {
386 		uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
387 		k_sleep(K_MSEC(100));
388 	}
389 #endif
390 	return 0;
391 }
392