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