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