1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 * POSIX getopt for Windows
9 * Code given out at the 1985 UNIFORUM conference in Dallas.
10 *
11 * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov 3 14:34:15 1985
12 * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET
13 * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP
14 * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix
15 * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman)
16 * Newsgroups: mod.std.unix
17 * Subject: public domain AT&T getopt source
18 * Message-ID: <3352@ut-sally.UUCP>
19 * Date: 3 Nov 85 19:34:15 GMT
20 * Date-Received: 4 Nov 85 12:25:09 GMT
21 * Organization: IEEE/P1003 Portable Operating System Environment Committee
22 * Lines: 91
23 * Approved: jsq@ut-sally.UUC
24 * Here's something you've all been waiting for: the AT&T public domain
25 * source for getopt(3). It is the code which was given out at the 1985
26 * UNIFORUM conference in Dallas. I obtained it by electronic mail
27 * directly from AT&T. The people there assure me that it is indeed
28 * in the public domain
29 * There is no manual page. That is because the one they gave out at
30 * UNIFORUM was slightly different from the current System V Release 2
31 * manual page. The difference apparently involved a note about the
32 * famous rules 5 and 6, recommending using white space between an option
33 * and its first argument, and not grouping options that have arguments.
34 * Getopt itself is currently lenient about both of these things White
35 * space is allowed, but not mandatory, and the last option in a group can
36 * have an argument. That particular version of the man page evidently
37 * has no official existence, and my source at AT&T did not send a copy.
38 * The current SVR2 man page reflects the actual behavor of this getopt.
39 * However, I am not about to post a copy of anything licensed by AT&T.
40 */
41
42 #include <assert.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46
47 #include "fsl_common.h"
48 #include "fsl_str.h"
49
50 #include "fsl_component_generic_list.h"
51 #include "fsl_component_serial_manager.h"
52
53 #include "fsl_shell.h"
54
55 /*
56 * The OSA_USED macro can only be defined when the OSA component is used.
57 * If the source code of the OSA component does not exist, the OSA_USED cannot be defined.
58 * OR, If OSA component is not added into project event the OSA source code exists, the OSA_USED
59 * also cannot be defined.
60 * The source code path of the OSA component is <MCUXpresso_SDK>/components/osa.
61 *
62 */
63 #if defined(OSA_USED)
64 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
65 #include "fsl_component_common_task.h"
66 #else
67 #include "fsl_os_abstraction.h"
68 #endif
69
70 #endif
71
72 /*******************************************************************************
73 * Definitions
74 ******************************************************************************/
75 #if defined(OSA_USED)
76 #define SHELL_WRITEX SHELL_WriteSynchronization
77 #else
78 #define SHELL_WRITEX SHELL_Write
79 #endif
80
81 #if defined(OSA_USED)
82 #if (defined(USE_RTOS) && (USE_RTOS > 0U))
83 static OSA_MUTEX_HANDLE_DEFINE(s_shellMutex);
84 #define SHELL_MUTEX_CREATE() (void)OSA_MutexCreate(s_shellMutex)
85 #define SHELL_ENTER_CRITICAL() (void)OSA_MutexLock(s_shellMutex, osaWaitForever_c)
86 #define SHELL_EXIT_CRITICAL() (void)OSA_MutexUnlock(s_shellMutex)
87 #else
88 #define SHELL_MUTEX_CREATE()
89 #define SHELL_ENTER_CRITICAL()
90 #define SHELL_EXIT_CRITICAL()
91 #endif
92 #else
93 #ifdef SDK_OS_FREE_RTOS
94 #include "FreeRTOS.h"
95 #include "queue.h"
96 #include "semphr.h"
97 static QueueHandle_t s_shellMutex;
98
99 #define SHELL_MUTEX_CREATE() s_shellMutex = xSemaphoreCreateMutex()
100 #define SHELL_ENTER_CRITICAL() (void)xSemaphoreTakeRecursive(s_shellMutex, portMAX_DELAY)
101 #define SHELL_EXIT_CRITICAL() (void)xSemaphoreGiveRecursive(s_shellMutex)
102 #else /* BM case*/
103 #define SHELL_MUTEX_CREATE()
104 #define SHELL_ENTER_CRITICAL()
105 #define SHELL_EXIT_CRITICAL()
106 #endif
107 #endif
108
109 #define KEY_ESC (0x1BU)
110 #define KET_DEL (0x7FU)
111
112 #define SHELL_EVENT_DATA_ARRIVED (1U << 0)
113 #define SHELL_EVENT_DATA_SENT (1U << 1)
114
115 #define SHELL_SPRINTF_BUFFER_SIZE (64U)
116
117 /*! @brief A type for the handle special key. */
118 typedef enum _fun_key_status
119 {
120 kSHELL_Normal = 0U, /*!< Normal key */
121 kSHELL_Special = 1U, /*!< Special key */
122 kSHELL_Function = 2U, /*!< Function key */
123 } fun_key_status_t;
124
125 /*! @brief Data structure for Shell environment. */
126 typedef struct _shell_context_handle
127 {
128 list_label_t commandContextListHead; /*!< Command shellContextHandle list queue head */
129 serial_handle_t serialHandle; /*!< Serial manager handle */
130 uint8_t
131 serialWriteHandleBuffer[SERIAL_MANAGER_WRITE_HANDLE_SIZE]; /*!< The buffer for serial manager write handle */
132 serial_write_handle_t serialWriteHandle; /*!< The serial manager write handle */
133 uint8_t serialReadHandleBuffer[SERIAL_MANAGER_READ_HANDLE_SIZE]; /*!< The buffer for serial manager read handle */
134 serial_read_handle_t serialReadHandle; /*!< The serial manager read handle */
135 char *prompt; /*!< Prompt string */
136 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
137
138 #if defined(OSA_USED)
139
140 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
141 common_task_message_t commontaskMsg; /*!< Message for common task */
142 #else
143 uint8_t event[OSA_EVENT_HANDLE_SIZE]; /*!< Event instance */
144 uint8_t taskId[OSA_TASK_HANDLE_SIZE]; /*!< Task handle */
145 #endif
146
147 #endif
148
149 #endif
150 char line[SHELL_BUFFER_SIZE]; /*!< Consult buffer */
151 char hist_buf[SHELL_HISTORY_COUNT][SHELL_BUFFER_SIZE]; /*!< History buffer*/
152 char printBuffer[SHELL_SPRINTF_BUFFER_SIZE]; /*!< Buffer for print */
153 uint32_t printLength; /*!< All length has been printed */
154 uint16_t hist_current; /*!< Current history command in hist buff*/
155 uint16_t hist_count; /*!< Total history command in hist buff*/
156 enum _fun_key_status stat; /*!< Special key status */
157 uint8_t cmd_num; /*!< Number of user commands */
158 uint8_t l_pos; /*!< Total line position */
159 uint8_t c_pos; /*!< Current line position */
160 volatile uint8_t notificationPost; /*!< The serial manager notification is post */
161 uint8_t exit; /*!< Exit Flag*/
162 uint8_t printBusy : 1; /*!< Print is busy */
163 uint8_t taskBusy : 1; /*!< Task is busy */
164 } shell_context_handle_t;
165
166 #if 0
167 #define SHELL_STRUCT_OFFSET(type, field) ((size_t) & (((type *)0)->field))
168 #define SHEEL_COMMAND_POINTER(node) \
169 ((shell_command_t *)(((uint32_t)(node)) - SHELL_STRUCT_OFFSET(shell_command_t, link)))
170 #else
171 #define SHEEL_COMMAND_POINTER(node) \
172 ((shell_command_t *)(((uint32_t)(node)) - (sizeof(shell_command_t) - sizeof(list_element_t))))
173 #endif
174 /*******************************************************************************
175 * Prototypes
176 ******************************************************************************/
177 static shell_status_t SHELL_HelpCommand(shell_handle_t shellHandle, int32_t argc, char **argv); /*!< help command */
178
179 static shell_status_t SHELL_ExitCommand(shell_handle_t shellHandle, int32_t argc, char **argv); /*!< exit command */
180
181 static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[]); /*!< parse line command */
182
183 static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count); /*!< compare string command */
184
185 static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd); /*!< process a command */
186
187 static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle,
188 uint8_t hist_pos); /*!< get commands history */
189
190 static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle); /*!< auto complete command */
191
192 static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle,
193 uint8_t *ch); /*!< get a char from communication interface */
194
195 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
196 static void SHELL_Task(void *param); /*!< Shell task*/
197 #endif
198
199 /*******************************************************************************
200 * Variables
201 ******************************************************************************/
202
203 static SHELL_COMMAND_DEFINE(help, "\r\n\"help\": List all the registered commands\r\n", SHELL_HelpCommand, 0);
204 static SHELL_COMMAND_DEFINE(exit, "\r\n\"exit\": Exit program\r\n", SHELL_ExitCommand, 0);
205
206 static char s_paramBuffer[SHELL_BUFFER_SIZE];
207
208 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
209 #if defined(OSA_USED)
210 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
211 #else
212 /*
213 * \brief Defines the serial manager task's stack
214 */
215 static OSA_TASK_DEFINE(SHELL_Task, SHELL_TASK_PRIORITY, 1, SHELL_TASK_STACK_SIZE, false);
216 #endif
217 #endif /* OSA_USED */
218 #endif /* SHELL_NON_BLOCKING_MODE */
219 /*******************************************************************************
220 * Code
221 ******************************************************************************/
222
223 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_SerialManagerRxCallback(void * callbackParam,serial_manager_callback_message_t * message,serial_manager_status_t status)224 static void SHELL_SerialManagerRxCallback(void *callbackParam,
225 serial_manager_callback_message_t *message,
226 serial_manager_status_t status)
227 {
228 shell_context_handle_t *shellHandle;
229
230 assert(callbackParam);
231 assert(message);
232
233 shellHandle = (shell_context_handle_t *)callbackParam;
234
235 if (0U == shellHandle->notificationPost)
236 {
237 shellHandle->notificationPost = 1U;
238 #if defined(OSA_USED)
239
240 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
241 shellHandle->commontaskMsg.callback = SHELL_Task;
242 shellHandle->commontaskMsg.callbackParam = shellHandle;
243 (void)COMMON_TASK_post_message(&shellHandle->commontaskMsg);
244 #else
245 (void)OSA_EventSet((osa_event_handle_t)shellHandle->event, SHELL_EVENT_DATA_ARRIVED);
246 #endif
247
248 #else
249 SHELL_Task(shellHandle);
250 #endif
251 }
252 }
253 #endif
254
SHELL_WriteBuffer(char * buffer,int32_t * indicator,char val,int len)255 static void SHELL_WriteBuffer(char *buffer, int32_t *indicator, char val, int len)
256 {
257 shell_context_handle_t *shellContextHandle;
258 int i = 0;
259 shellContextHandle = (shell_context_handle_t *)(void *)buffer;
260
261 for (i = 0; i < len; i++)
262 {
263 if ((*indicator + 1) >= (int32_t)SHELL_SPRINTF_BUFFER_SIZE)
264 {
265 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
266 if (NULL == shellContextHandle->serialHandle)
267 {
268 for (uint32_t index = 0; index < ((uint32_t)*indicator); index++)
269 {
270 (void)putchar(shellContextHandle->printBuffer[index]);
271 }
272 }
273 else
274 #endif
275 {
276 (void)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle,
277 (uint8_t *)shellContextHandle->printBuffer, (uint32_t)*indicator);
278 }
279
280 shellContextHandle->printLength += (uint32_t)*indicator;
281 *indicator = 0;
282 }
283
284 shellContextHandle->printBuffer[*indicator] = val;
285 (*indicator)++;
286 }
287 }
288
SHELL_Sprintf(void * buffer,const char * formatString,va_list ap)289 static int SHELL_Sprintf(void *buffer, const char *formatString, va_list ap)
290 {
291 shell_context_handle_t *shellContextHandle;
292 uint32_t length;
293 shellContextHandle = (shell_context_handle_t *)buffer;
294
295 length = (uint32_t)StrFormatPrintf(formatString, ap, (char *)buffer, SHELL_WriteBuffer);
296 shellContextHandle->printLength += length;
297 return (int32_t)length;
298 }
299
SHELL_hisOperation(uint8_t ch,shell_context_handle_t * shellContextHandle)300 static void SHELL_hisOperation(uint8_t ch, shell_context_handle_t *shellContextHandle)
301 {
302 switch ((char)ch)
303 {
304 /* History operation here */
305 case 'A': /* Up key */
306 SHELL_GetHistoryCommand(shellContextHandle, (uint8_t)shellContextHandle->hist_current);
307 if (shellContextHandle->hist_current < (shellContextHandle->hist_count - 1U))
308 {
309 shellContextHandle->hist_current++;
310 }
311 break;
312 case 'B': /* Down key */
313 SHELL_GetHistoryCommand(shellContextHandle, (uint8_t)shellContextHandle->hist_current);
314 if (shellContextHandle->hist_current > 0U)
315 {
316 shellContextHandle->hist_current--;
317 }
318 break;
319 case 'D': /* Left key */
320 if ((bool)shellContextHandle->c_pos)
321 {
322 (void)SHELL_WRITEX(shellContextHandle, "\b", 1);
323 shellContextHandle->c_pos--;
324 }
325 break;
326 case 'C': /* Right key */
327 if (shellContextHandle->c_pos < shellContextHandle->l_pos)
328 {
329 (void)SHELL_WRITEX(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos], 1);
330 shellContextHandle->c_pos++;
331 }
332 break;
333 default:
334 /* MISRA C-2012 Rule 16.4 */
335 break;
336 }
337 }
338 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
SHELL_Task(void * param)339 static void SHELL_Task(void *param)
340 #else
341 void SHELL_Task(shell_handle_t shellHandle)
342 #endif
343 {
344 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
345 shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)param;
346 #else
347 shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
348 #endif
349 uint8_t ch;
350
351 if (NULL != shellContextHandle)
352 {
353 uint32_t osaCurrentSr = 0U;
354
355 osaCurrentSr = DisableGlobalIRQ();
356 shellContextHandle->notificationPost = 0U;
357 if (shellContextHandle->taskBusy > 0U)
358 {
359 EnableGlobalIRQ(osaCurrentSr);
360 return;
361 }
362 shellContextHandle->taskBusy = 1U;
363 EnableGlobalIRQ(osaCurrentSr);
364 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
365
366 #if defined(OSA_USED)
367
368 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
369 #else
370 osa_event_flags_t ev = 0;
371
372 do
373 {
374 if (KOSA_StatusSuccess == OSA_EventWait((osa_event_handle_t)shellContextHandle->event, osaEventFlagsAll_c,
375 0U, osaWaitForever_c, &ev))
376 {
377 if (0U != (ev & SHELL_EVENT_DATA_ARRIVED))
378 #endif
379
380 #endif
381
382 #endif
383 {
384 shellContextHandle->notificationPost = 0U;
385 do
386 {
387 if ((bool)shellContextHandle->exit)
388 {
389 if (shellContextHandle->serialReadHandle != NULL)
390 {
391 (void)SerialManager_CloseReadHandle(shellContextHandle->serialReadHandle);
392 shellContextHandle->serialReadHandle = NULL;
393 }
394 if (shellContextHandle->serialWriteHandle != NULL)
395 {
396 (void)SerialManager_CloseWriteHandle(shellContextHandle->serialWriteHandle);
397 shellContextHandle->serialWriteHandle = NULL;
398 }
399 break;
400 }
401 if (kStatus_SHELL_Success != (shell_status_t)SHELL_GetChar(shellContextHandle, &ch))
402 {
403 /* If error occurred when getting a char, exit the task and waiting the new data arriving. */
404 break;
405 }
406
407 /* Special key */
408 if (ch == KEY_ESC)
409 {
410 shellContextHandle->stat = kSHELL_Special;
411 continue;
412 }
413 else if (shellContextHandle->stat == kSHELL_Special)
414 {
415 /* Function key */
416 if ((char)ch == '[')
417 {
418 shellContextHandle->stat = kSHELL_Function;
419 continue;
420 }
421 shellContextHandle->stat = kSHELL_Normal;
422 }
423 else if (shellContextHandle->stat == kSHELL_Function)
424 {
425 shellContextHandle->stat = kSHELL_Normal;
426 SHELL_hisOperation(ch, shellContextHandle);
427 continue;
428 }
429 /* Handle tab key */
430 else if ((char)ch == '\t')
431 {
432 #if SHELL_AUTO_COMPLETE
433 /* Move the cursor to the beginning of line */
434 uint32_t i;
435 for (i = 0; i < (uint32_t)shellContextHandle->c_pos; i++)
436 {
437 (void)SHELL_WRITEX(shellContextHandle, "\b", 1);
438 }
439 /* Do auto complete */
440 SHELL_AutoComplete(shellContextHandle);
441 /* Move position to end */
442 shellContextHandle->l_pos = (uint8_t)strlen(shellContextHandle->line);
443 shellContextHandle->c_pos = shellContextHandle->l_pos;
444 #endif
445 continue;
446 }
447 /* Handle backspace key */
448 else if ((ch == KET_DEL) || ((char)ch == '\b'))
449 {
450 /* There must be at last one char */
451 if (shellContextHandle->c_pos == 0U)
452 {
453 continue;
454 }
455
456 shellContextHandle->l_pos--;
457 shellContextHandle->c_pos--;
458
459 if (shellContextHandle->l_pos > shellContextHandle->c_pos)
460 {
461 (void)memmove(&shellContextHandle->line[shellContextHandle->c_pos],
462 &shellContextHandle->line[shellContextHandle->c_pos + 1U],
463 (uint32_t)shellContextHandle->l_pos - (uint32_t)shellContextHandle->c_pos);
464 shellContextHandle->line[shellContextHandle->l_pos] = '\0';
465 (void)SHELL_WRITEX(shellContextHandle, "\b", 1);
466 (void)SHELL_WRITEX(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
467 strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
468 (void)SHELL_WRITEX(shellContextHandle, " \b", 3);
469
470 /* Reset position */
471 uint32_t i;
472 for (i = (uint32_t)shellContextHandle->c_pos; i <= (uint32_t)shellContextHandle->l_pos; i++)
473 {
474 (void)SHELL_WRITEX(shellContextHandle, "\b", 1);
475 }
476 }
477 else /* Normal backspace operation */
478 {
479 (void)SHELL_WRITEX(shellContextHandle, "\b \b", 3);
480 shellContextHandle->line[shellContextHandle->l_pos] = '\0';
481 }
482 continue;
483 }
484 else
485 {
486 /* MISRA C-2012 Rule 15.7 */
487 }
488
489 /* Input too long */
490 if (shellContextHandle->l_pos >= (SHELL_BUFFER_SIZE - 1U))
491 {
492 shellContextHandle->l_pos = 0U;
493 }
494
495 /* Handle end of line, break */
496 if (((char)ch == '\r') || ((char)ch == '\n'))
497 {
498 static char endoflinechar = '\0';
499
500 if (((uint8_t)endoflinechar != 0U) && ((uint8_t)endoflinechar != ch))
501 {
502 continue;
503 }
504 else
505 {
506 endoflinechar = (char)ch;
507 /* Print new line. */
508 (void)SHELL_WRITEX(shellContextHandle, "\r\n", 2U);
509 /* If command line is not NULL, will start process it. */
510 if (0U != strlen(shellContextHandle->line))
511 {
512 SHELL_ProcessCommand(shellContextHandle, shellContextHandle->line);
513 }
514 /* Print prompt. */
515 (void)SHELL_WRITEX(shellContextHandle, shellContextHandle->prompt,
516 strlen(shellContextHandle->prompt));
517 /* Reset all params */
518 shellContextHandle->c_pos = shellContextHandle->l_pos = 0;
519 shellContextHandle->hist_current = 0;
520 (void)memset(shellContextHandle->line, 0, sizeof(shellContextHandle->line));
521 continue;
522 }
523 }
524
525 /* Normal character */
526 if (shellContextHandle->c_pos < shellContextHandle->l_pos)
527 {
528 (void)memmove(&shellContextHandle->line[shellContextHandle->c_pos + 1U],
529 &shellContextHandle->line[shellContextHandle->c_pos],
530 (uint32_t)shellContextHandle->l_pos - (uint32_t)shellContextHandle->c_pos);
531 shellContextHandle->line[shellContextHandle->c_pos] = (char)ch;
532 (void)SHELL_WRITEX(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
533 strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
534 /* Move the cursor to new position */
535 uint32_t i;
536 for (i = (uint32_t)shellContextHandle->c_pos; i < (uint32_t)shellContextHandle->l_pos; i++)
537 {
538 (void)SHELL_WRITEX(shellContextHandle, "\b", 1);
539 }
540 }
541 else
542 {
543 shellContextHandle->line[shellContextHandle->l_pos] = (char)ch;
544 (void)SHELL_WRITEX(shellContextHandle, &shellContextHandle->line[shellContextHandle->l_pos], 1);
545 }
546
547 ch = 0;
548 shellContextHandle->l_pos++;
549 shellContextHandle->c_pos++;
550 } while (0U == shellContextHandle->exit);
551 }
552 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
553
554 #if defined(OSA_USED)
555
556 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
557 #else
558 }
559 } while (1U == gUseRtos_c); /* USE_RTOS = 0 for BareMetal and 1 for OS */
560 #endif
561
562 #endif
563
564 #endif
565 osaCurrentSr = DisableGlobalIRQ();
566 shellContextHandle->taskBusy = 0U;
567 EnableGlobalIRQ(osaCurrentSr);
568 }
569 }
570
SHELL_HelpCommand(shell_handle_t shellHandle,int32_t argc,char ** argv)571 static shell_status_t SHELL_HelpCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
572 {
573 shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
574 shell_command_t *shellCommandContextHandle;
575 list_element_handle_t p = LIST_GetHead(&shellContextHandle->commandContextListHead);
576
577 while (p != NULL)
578 {
579 shellCommandContextHandle = SHEEL_COMMAND_POINTER(p);
580 if ((shellCommandContextHandle->pcHelpString != NULL) && (bool)strlen(shellCommandContextHandle->pcHelpString))
581 {
582 (void)SHELL_WRITEX(shellContextHandle, shellCommandContextHandle->pcHelpString,
583 strlen(shellCommandContextHandle->pcHelpString));
584 }
585
586 p = LIST_GetNext(p);
587 }
588 return kStatus_SHELL_Success;
589 }
590
SHELL_ExitCommand(shell_handle_t shellHandle,int32_t argc,char ** argv)591 static shell_status_t SHELL_ExitCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
592 {
593 shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
594 /* Skip warning */
595 (void)SHELL_WRITEX(shellContextHandle, "\r\nSHELL exited\r\n", strlen("\r\nSHELL exited\r\n"));
596 shellContextHandle->exit = (uint8_t) true;
597 return kStatus_SHELL_Success;
598 }
599
SHELL_ProcessCommand(shell_context_handle_t * shellContextHandle,const char * cmd)600 static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd)
601 {
602 shell_command_t *tmpCommand = NULL;
603 const char *tmpCommandString;
604 int32_t argc;
605 char *argv[SHELL_BUFFER_SIZE] = {0};
606 list_element_handle_t p;
607 uint8_t flag = 1;
608 uint8_t tmpCommandLen;
609 uint8_t tmpLen;
610 uint8_t i = 0;
611
612 tmpLen = (uint8_t)strlen(cmd);
613 if (tmpLen >= SHELL_BUFFER_SIZE - 1U)
614 {
615 (void)SHELL_Printf(shellContextHandle,
616 "Command line length should not more than SHELL_BUFFER_SIZE, please input command less "
617 "(SHELL_BUFFER_SIZE - 1) characters again!\r\n");
618 return;
619 }
620 else
621 {
622 argc = SHELL_ParseLine(cmd, tmpLen, argv);
623 }
624
625 if ((argc > 0))
626 {
627 p = LIST_GetHead(&shellContextHandle->commandContextListHead);
628 while (p != NULL)
629 {
630 tmpCommand = SHEEL_COMMAND_POINTER(p);
631 tmpCommandString = tmpCommand->pcCommand;
632 tmpCommandLen = (uint8_t)strlen(tmpCommandString);
633 /* Compare with space or end of string */
634 if ((cmd[tmpCommandLen] == ' ') || (cmd[tmpCommandLen] == (char)0x00))
635 {
636 if (SHELL_StringCompare(tmpCommandString, argv[0], (int32_t)tmpCommandLen) == 0)
637 {
638 /* support commands with optional number of parameters */
639 if (tmpCommand->cExpectedNumberOfParameters == (uint8_t)SHELL_IGNORE_PARAMETER_COUNT)
640 {
641 flag = 0;
642 }
643 else if ((tmpCommand->cExpectedNumberOfParameters == 0U) && (argc == 1))
644 {
645 flag = 0;
646 }
647 else if (tmpCommand->cExpectedNumberOfParameters > 0U)
648 {
649 if ((argc - 1) == (int32_t)tmpCommand->cExpectedNumberOfParameters)
650 {
651 flag = 0;
652 }
653 }
654 else
655 {
656 flag = 1;
657 }
658 break;
659 }
660 }
661 p = LIST_GetNext(p);
662 }
663 if (NULL == p)
664 {
665 tmpCommand = NULL;
666 }
667 }
668
669 if ((tmpCommand != NULL) && (flag == 1U))
670 {
671 (void)SHELL_Write(
672 shellContextHandle,
673 "\r\nIncorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n",
674 strlen(
675 "\r\nIncorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n"));
676 }
677 else if (tmpCommand != NULL)
678 {
679 tmpLen = (uint8_t)strlen(cmd);
680 /* Compare with last command. Push back to history buffer if different */
681 if (tmpLen != (uint8_t)SHELL_StringCompare(cmd, shellContextHandle->hist_buf[0], (int32_t)strlen(cmd)))
682 {
683 for (i = SHELL_HISTORY_COUNT - 1U; i > 0U; i--)
684 {
685 (void)memset(shellContextHandle->hist_buf[i], (int)'\0', SHELL_BUFFER_SIZE);
686 tmpLen = (uint8_t)strlen(shellContextHandle->hist_buf[i - 1U]);
687 (void)memcpy(shellContextHandle->hist_buf[i], shellContextHandle->hist_buf[i - 1U], tmpLen);
688 }
689 (void)memset(shellContextHandle->hist_buf[0], (int)'\0', SHELL_BUFFER_SIZE);
690 tmpLen = (uint8_t)strlen(cmd);
691 (void)memcpy(shellContextHandle->hist_buf[0], cmd, tmpLen);
692 if (shellContextHandle->hist_count < SHELL_HISTORY_COUNT)
693 {
694 shellContextHandle->hist_count++;
695 }
696 }
697 if (kStatus_SHELL_RetUsage == tmpCommand->pFuncCallBack(shellContextHandle, argc, argv))
698 {
699 if (NULL != tmpCommand->pcHelpString)
700 {
701 (void)SHELL_WRITEX(shellContextHandle, tmpCommand->pcHelpString, strlen(tmpCommand->pcHelpString));
702 }
703 else
704 {
705 (void)SHELL_HelpCommand(shellContextHandle, 0, NULL);
706 }
707 }
708 }
709 else
710 {
711 (void)SHELL_Write(
712 shellContextHandle,
713 "\r\nCommand not recognized. Enter 'help' to view a list of available commands.\r\n\r\n",
714 strlen("\r\nCommand not recognized. Enter 'help' to view a list of available commands.\r\n\r\n"));
715 }
716 }
717
SHELL_GetHistoryCommand(shell_context_handle_t * shellContextHandle,uint8_t hist_pos)718 static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle, uint8_t hist_pos)
719 {
720 uint32_t i;
721 uint32_t tmp;
722
723 if (shellContextHandle->hist_buf[0][0] == '\0')
724 {
725 shellContextHandle->hist_current = 0;
726 return;
727 }
728
729 #if 0 /*hist_pos is passed from hist_current. And hist_current is only changed in case 'A'/'B',as hist_count is 3 \
730 most, it can't be more than 3 */
731 if (hist_pos >= SHELL_HISTORY_COUNT)
732 {
733 hist_pos = SHELL_HISTORY_COUNT - 1U;
734 }
735 #endif
736
737 tmp = strlen(shellContextHandle->line);
738 /* Clear current if have */
739 if (tmp > 0U)
740 {
741 (void)memset(shellContextHandle->line, (int)'\0', tmp);
742 for (i = 0U; i < tmp; i++)
743 {
744 (void)SHELL_WRITEX(shellContextHandle, "\b \b", 3);
745 }
746 }
747
748 shellContextHandle->l_pos = (uint8_t)strlen(shellContextHandle->hist_buf[hist_pos]);
749 shellContextHandle->c_pos = shellContextHandle->l_pos;
750 (void)memcpy(shellContextHandle->line, shellContextHandle->hist_buf[hist_pos], shellContextHandle->l_pos);
751 (void)SHELL_WRITEX(shellContextHandle, shellContextHandle->hist_buf[hist_pos],
752 strlen(shellContextHandle->hist_buf[hist_pos]));
753 }
754
SHELL_AutoComplete(shell_context_handle_t * shellContextHandle)755 static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle)
756 {
757 int32_t minLen;
758 list_element_handle_t p;
759 shell_command_t *tmpCommand = NULL;
760 const char *namePtr;
761 const char *cmdName;
762
763 minLen = (int32_t)SHELL_BUFFER_SIZE;
764 namePtr = NULL;
765
766 /* Empty tab, list all commands */
767 if (shellContextHandle->line[0] == '\0')
768 {
769 (void)SHELL_HelpCommand(shellContextHandle, 0, NULL);
770 return;
771 }
772
773 (void)SHELL_WRITEX(shellContextHandle, "\r\n", 2);
774
775 /* Do auto complete */
776 p = LIST_GetHead(&shellContextHandle->commandContextListHead);
777 while (p != NULL)
778 {
779 tmpCommand = SHEEL_COMMAND_POINTER(p);
780 cmdName = tmpCommand->pcCommand;
781 if (SHELL_StringCompare(shellContextHandle->line, cmdName, (int32_t)strlen(shellContextHandle->line)) == 0)
782 {
783 /* Show possible matches */
784 (void)SHELL_Printf(shellContextHandle, "%s ", cmdName);
785 if (minLen > ((int32_t)strlen(cmdName)))
786 {
787 namePtr = cmdName;
788 minLen = (int32_t)strlen(namePtr);
789 }
790 }
791 p = LIST_GetNext(p);
792 }
793 /* Auto complete string */
794 if (namePtr != NULL)
795 {
796 (void)memcpy(shellContextHandle->line, namePtr, (uint32_t)minLen);
797 }
798 SHELL_PrintPrompt(shellContextHandle);
799 (void)SHELL_WRITEX(shellContextHandle, shellContextHandle->line, strlen(shellContextHandle->line));
800 return;
801 }
802
SHELL_StringCompare(const char * str1,const char * str2,int32_t count)803 static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count)
804 {
805 while ((bool)(count--))
806 {
807 if (*str1++ != *str2++)
808 {
809 return (int32_t)(*(str1 - 1) - *(str2 - 1));
810 }
811 }
812 return 0;
813 }
814
SHELL_ParseLine(const char * cmd,uint32_t len,char * argv[])815 static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[])
816 {
817 uint32_t argc;
818 char *p;
819 uint32_t position;
820
821 /* Init params */
822 (void)memset(s_paramBuffer, (int)'\0', len + 1U);
823 (void)memcpy(s_paramBuffer, cmd, len);
824
825 p = s_paramBuffer;
826 position = 0;
827 argc = 0;
828
829 while (position < len)
830 {
831 /* Skip all blanks */
832 while ((position < len) && ((char)(*p) == ' '))
833 {
834 *p = '\0';
835 p++;
836 position++;
837 }
838
839 if (position >= len)
840 {
841 break;
842 }
843
844 /* Process begin of a string */
845 if (*p == '"')
846 {
847 p++;
848 position++;
849 argv[argc] = p;
850 argc++;
851 /* Skip this string */
852 while ((*p != '"') && (position < len))
853 {
854 p++;
855 position++;
856 }
857 /* Skip '"' */
858 *p = '\0';
859 p++;
860 position++;
861 }
862 else /* Normal char */
863 {
864 argv[argc] = p;
865 argc++;
866 while (((char)*p != ' ') && (position < len))
867 {
868 p++;
869 position++;
870 }
871 }
872 }
873 return (int32_t)argc;
874 }
875
SHELL_GetChar(shell_context_handle_t * shellContextHandle,uint8_t * ch)876 static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle, uint8_t *ch)
877 {
878 shell_status_t status;
879
880 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
881 if (NULL == shellContextHandle->serialHandle)
882 {
883 int ret;
884 ret = getchar();
885 if (ret > 0)
886 {
887 *ch = (uint8_t)ret;
888 status = kStatus_SHELL_Success;
889 }
890 else
891 {
892 status = kStatus_SHELL_Error;
893 }
894 }
895 else
896 #endif
897 {
898 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
899 uint32_t length = 0;
900
901 (void)SerialManager_TryRead(shellContextHandle->serialReadHandle, ch, 1, &length);
902
903 if (length > 0U)
904 {
905 status = kStatus_SHELL_Success;
906 }
907 else
908 {
909 status = kStatus_SHELL_Error;
910 }
911 #else
912 status = (shell_status_t)SerialManager_ReadBlocking(shellContextHandle->serialReadHandle, ch, 1);
913 #endif
914 }
915
916 return status;
917 }
918
SHELL_Init(shell_handle_t shellHandle,serial_handle_t serialHandle,char * prompt)919 shell_status_t SHELL_Init(shell_handle_t shellHandle, serial_handle_t serialHandle, char *prompt)
920 {
921 shell_context_handle_t *shellContextHandle;
922 serial_manager_status_t status = kStatus_SerialManager_Error;
923 (void)status;
924
925 assert(shellHandle);
926 #if !(!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
927 assert(serialHandle);
928 #endif
929 assert(prompt);
930 assert(SHELL_HANDLE_SIZE >= sizeof(shell_context_handle_t));
931
932 shellContextHandle = (shell_context_handle_t *)shellHandle;
933
934 /* memory set for shellHandle */
935 (void)memset(shellHandle, 0, SHELL_HANDLE_SIZE);
936
937 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
938 if (NULL == serialHandle)
939 {
940 }
941 else
942 #endif
943 {
944 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
945
946 #if defined(OSA_USED)
947
948 #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
949 (void)COMMON_TASK_init();
950 #else
951 if (KOSA_StatusSuccess != OSA_EventCreate((osa_event_handle_t)shellContextHandle->event, 1U))
952 {
953 return kStatus_SHELL_Error;
954 }
955
956 if (KOSA_StatusSuccess !=
957 OSA_TaskCreate((osa_task_handle_t)shellContextHandle->taskId, OSA_TASK(SHELL_Task), shellContextHandle))
958 {
959 return kStatus_SHELL_Error;
960 }
961 #endif
962
963 #endif
964
965 #endif
966 }
967
968 shellContextHandle->prompt = prompt;
969 shellContextHandle->serialHandle = serialHandle;
970
971 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
972 if (NULL == serialHandle)
973 {
974 }
975 else
976 #endif
977 {
978 shellContextHandle->serialWriteHandle = (serial_write_handle_t)&shellContextHandle->serialWriteHandleBuffer[0];
979 status = SerialManager_OpenWriteHandle(shellContextHandle->serialHandle, shellContextHandle->serialWriteHandle);
980 assert(kStatus_SerialManager_Success == status);
981
982 shellContextHandle->serialReadHandle = (serial_read_handle_t)&shellContextHandle->serialReadHandleBuffer[0];
983 status = SerialManager_OpenReadHandle(shellContextHandle->serialHandle, shellContextHandle->serialReadHandle);
984 assert(kStatus_SerialManager_Success == status);
985
986 #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
987 status = SerialManager_InstallRxCallback(shellContextHandle->serialReadHandle, SHELL_SerialManagerRxCallback,
988 shellContextHandle);
989 assert(kStatus_SerialManager_Success == status);
990 #endif
991 (void)status;
992 }
993
994 (void)SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(help));
995 (void)SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(exit));
996 SHELL_MUTEX_CREATE();
997 (void)SHELL_Write(shellContextHandle, "\r\nCopyright 2022 NXP\r\n", strlen("\r\nCopyright 2022 NXP\r\n"));
998 SHELL_PrintPrompt(shellContextHandle);
999
1000 return kStatus_SHELL_Success;
1001 }
1002
SHELL_RegisterCommand(shell_handle_t shellHandle,shell_command_t * shellCommand)1003 shell_status_t SHELL_RegisterCommand(shell_handle_t shellHandle, shell_command_t *shellCommand)
1004 {
1005 shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
1006 assert(shellHandle);
1007 assert(shellCommand);
1008
1009 /* memory set for shellHandle */
1010 (void)memset(&shellCommand->link, 0, sizeof(shellCommand->link));
1011
1012 (void)LIST_AddTail(&shellContextHandle->commandContextListHead, &shellCommand->link);
1013
1014 return kStatus_SHELL_Success;
1015 }
1016
SHELL_UnregisterCommand(shell_command_t * shellCommand)1017 shell_status_t SHELL_UnregisterCommand(shell_command_t *shellCommand)
1018 {
1019 assert(shellCommand);
1020
1021 (void)LIST_RemoveElement(&shellCommand->link);
1022
1023 /* memory set for shellHandle */
1024 (void)memset(&shellCommand->link, 0, sizeof(shellCommand->link));
1025
1026 return kStatus_SHELL_Success;
1027 }
1028
SHELL_Write(shell_handle_t shellHandle,const char * buffer,uint32_t length)1029 shell_status_t SHELL_Write(shell_handle_t shellHandle, const char *buffer, uint32_t length)
1030 {
1031 shell_context_handle_t *shellContextHandle;
1032 uint32_t primask;
1033 shell_status_t status;
1034
1035 assert(shellHandle);
1036 assert(buffer);
1037
1038 if (!(bool)length)
1039 {
1040 return kStatus_SHELL_Success;
1041 }
1042
1043 shellContextHandle = (shell_context_handle_t *)shellHandle;
1044
1045 primask = DisableGlobalIRQ();
1046 if ((bool)shellContextHandle->printBusy)
1047 {
1048 EnableGlobalIRQ(primask);
1049 return kStatus_SHELL_Error;
1050 }
1051 shellContextHandle->printBusy = 1U;
1052 EnableGlobalIRQ(primask);
1053 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
1054 if (NULL == shellContextHandle->serialHandle)
1055 {
1056 status = kStatus_SHELL_Success;
1057 for (uint32_t index = 0; index < length; index++)
1058 {
1059 (void)putchar(buffer[index]);
1060 }
1061 }
1062 else
1063 #endif
1064 {
1065 status = (shell_status_t)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle, (uint8_t *)buffer,
1066 length);
1067 }
1068
1069 shellContextHandle->printBusy = 0U;
1070
1071 return status;
1072 }
1073
SHELL_Printf(shell_handle_t shellHandle,const char * formatString,...)1074 int SHELL_Printf(shell_handle_t shellHandle, const char *formatString, ...)
1075 {
1076 shell_context_handle_t *shellContextHandle;
1077 uint32_t length;
1078 uint32_t primask;
1079 va_list ap;
1080
1081 assert(shellHandle);
1082 assert(formatString);
1083
1084 shellContextHandle = (shell_context_handle_t *)shellHandle;
1085
1086 primask = DisableGlobalIRQ();
1087 if ((bool)shellContextHandle->printBusy)
1088 {
1089 EnableGlobalIRQ(primask);
1090 return -1;
1091 }
1092 shellContextHandle->printBusy = 1U;
1093 EnableGlobalIRQ(primask);
1094
1095 va_start(ap, formatString);
1096
1097 shellContextHandle->printLength = 0U;
1098 length = (uint32_t)SHELL_Sprintf(shellHandle, formatString, ap);
1099 #if (!defined(SDK_DEBUGCONSOLE_UART) && (defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE != 1)))
1100 if (NULL == shellContextHandle->serialHandle)
1101 {
1102 for (uint32_t index = 0; index < length; index++)
1103 {
1104 (void)putchar(shellContextHandle->printBuffer[index]);
1105 }
1106 }
1107 else
1108 #endif
1109 {
1110 (void)SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle,
1111 (uint8_t *)shellContextHandle->printBuffer, length);
1112 }
1113 va_end(ap);
1114
1115 shellContextHandle->printBusy = 0U;
1116 return (int32_t)shellContextHandle->printLength;
1117 }
1118
SHELL_WriteSynchronization(shell_handle_t shellHandle,const char * buffer,uint32_t length)1119 shell_status_t SHELL_WriteSynchronization(shell_handle_t shellHandle, const char *buffer, uint32_t length)
1120 {
1121 shell_status_t status;
1122
1123 assert(SHELL_checkRunningInIsr() == false);
1124
1125 SHELL_ENTER_CRITICAL();
1126 status = SHELL_Write(shellHandle, buffer, length);
1127
1128 SHELL_EXIT_CRITICAL();
1129
1130 return status;
1131 }
1132
SHELL_PrintfSynchronization(shell_handle_t shellHandle,const char * formatString,...)1133 int SHELL_PrintfSynchronization(shell_handle_t shellHandle, const char *formatString, ...)
1134 {
1135 shell_status_t status;
1136 shell_context_handle_t *shellContextHandle;
1137 va_list ap;
1138 uint32_t length;
1139
1140 assert(SHELL_checkRunningInIsr() == false);
1141
1142 shellContextHandle = (shell_context_handle_t *)shellHandle;
1143
1144 SHELL_ENTER_CRITICAL();
1145 va_start(ap, formatString);
1146 length = (uint32_t)SHELL_Sprintf(shellHandle, formatString, ap);
1147
1148 status = SHELL_Write(shellHandle, (const char *)shellContextHandle->printBuffer, length);
1149 va_end(ap);
1150 SHELL_EXIT_CRITICAL();
1151
1152 return (status == kStatus_SHELL_Success) ? (int)length : 0;
1153 }
SHELL_ChangePrompt(shell_handle_t shellHandle,char * prompt)1154 void SHELL_ChangePrompt(shell_handle_t shellHandle, char *prompt)
1155 {
1156 shell_context_handle_t *shellContextHandle;
1157 assert(shellHandle);
1158 assert(prompt);
1159
1160 shellContextHandle = (shell_context_handle_t *)shellHandle;
1161
1162 shellContextHandle->prompt = prompt;
1163 SHELL_PrintPrompt(shellContextHandle);
1164 }
1165
SHELL_PrintPrompt(shell_handle_t shellHandle)1166 void SHELL_PrintPrompt(shell_handle_t shellHandle)
1167 {
1168 shell_context_handle_t *shellContextHandle;
1169 assert(shellHandle);
1170
1171 shellContextHandle = (shell_context_handle_t *)shellHandle;
1172
1173 (void)SHELL_Write(shellContextHandle, "\r\n", 2U);
1174 (void)SHELL_Write(shellContextHandle, shellContextHandle->prompt, strlen(shellContextHandle->prompt));
1175 }
1176