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