fsl_shell.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2018 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. #include <assert.h>
  42. #include <stdarg.h>
  43. #include <stdlib.h>
  44. #include "fsl_str.h"
  45. #include "generic_list.h"
  46. #include "serial_manager.h"
  47. #include "fsl_shell.h"
  48. /*
  49. * The OSA_USED macro can only be defined when the OSA component is used.
  50. * If the source code of the OSA component does not exist, the OSA_USED cannot be defined.
  51. * OR, If OSA component is not added into project event the OSA source code exists, the OSA_USED
  52. * also cannot be defined.
  53. * The source code path of the OSA component is <MCUXpresso_SDK>/components/osa.
  54. *
  55. */
  56. #if defined(OSA_USED)
  57. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  58. #include "common_task.h"
  59. #else
  60. #include "fsl_os_abstraction.h"
  61. #endif
  62. #endif
  63. /*******************************************************************************
  64. * Definitions
  65. ******************************************************************************/
  66. #define KEY_ESC (0x1BU)
  67. #define KET_DEL (0x7FU)
  68. #define SHELL_EVENT_DATA_ARRIVED (1U << 0)
  69. #define SHELL_EVENT_DATA_SENT (1U << 1)
  70. #define SHELL_SPRINTF_BUFFER_SIZE (64U)
  71. /*! @brief A type for the handle special key. */
  72. typedef enum _fun_key_status
  73. {
  74. kSHELL_Normal = 0U, /*!< Normal key */
  75. kSHELL_Special = 1U, /*!< Special key */
  76. kSHELL_Function = 2U, /*!< Function key */
  77. } fun_key_status_t;
  78. /*! @brief Data structure for Shell environment. */
  79. typedef struct _shell_context_handle
  80. {
  81. list_t commandContextListHead; /*!< Command shellContextHandle list queue head */
  82. serial_handle_t serialHandle; /*!< Serial manager handle */
  83. uint8_t
  84. serialWriteHandleBuffer[SERIAL_MANAGER_WRITE_HANDLE_SIZE]; /*!< The buffer for serial manager write handle */
  85. serial_write_handle_t serialWriteHandle; /*!< The serial manager write handle */
  86. uint8_t serialReadHandleBuffer[SERIAL_MANAGER_READ_HANDLE_SIZE]; /*!< The buffer for serial manager read handle */
  87. serial_read_handle_t serialReadHandle; /*!< The serial manager read handle */
  88. char *prompt; /*!< Prompt string */
  89. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  90. #if defined(OSA_USED)
  91. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  92. common_task_message_t commontaskMsg; /*!< Message for common task */
  93. #else
  94. uint8_t event[OSA_EVENT_HANDLE_SIZE]; /*!< Event instance */
  95. uint8_t taskId[OSA_TASK_HANDLE_SIZE]; /*!< Task handle */
  96. #endif
  97. #endif
  98. #endif
  99. char line[SHELL_BUFFER_SIZE]; /*!< Consult buffer */
  100. char hist_buf[SHELL_HISTORY_COUNT][SHELL_BUFFER_SIZE]; /*!< History buffer*/
  101. char printBuffer[SHELL_SPRINTF_BUFFER_SIZE]; /*!< Buffer for print */
  102. uint32_t printLength; /*!< All length has been printed */
  103. uint16_t hist_current; /*!< Current history command in hist buff*/
  104. uint16_t hist_count; /*!< Total history command in hist buff*/
  105. enum _fun_key_status stat; /*!< Special key status */
  106. uint8_t cmd_num; /*!< Number of user commands */
  107. uint8_t l_pos; /*!< Total line position */
  108. uint8_t c_pos; /*!< Current line position */
  109. volatile uint8_t notificationPost; /*!< The serial manager notification is post */
  110. uint8_t exit; /*!< Exit Flag*/
  111. uint8_t printBusy; /*!< Print is busy */
  112. } shell_context_handle_t;
  113. #define SHELL_STRUCT_OFFSET(type, field) ((size_t) & (((type *)0)->field))
  114. #define SHEEL_COMMAND_POINTER(node) ((shell_command_t *)(((uint32_t)node) - SHELL_STRUCT_OFFSET(shell_command_t, link)))
  115. /*******************************************************************************
  116. * Prototypes
  117. ******************************************************************************/
  118. static shell_status_t SHELL_HelpCommand(shell_handle_t shellContextHandle,
  119. int32_t argc,
  120. char **argv); /*!< help command */
  121. static shell_status_t SHELL_ExitCommand(shell_handle_t shellContextHandle,
  122. int32_t argc,
  123. char **argv); /*!< exit command */
  124. static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[]); /*!< parse line command */
  125. static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count); /*!< compare string command */
  126. static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd); /*!< process a command */
  127. static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle,
  128. uint8_t hist_pos); /*!< get commands history */
  129. static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle); /*!< auto complete command */
  130. static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle,
  131. uint8_t *ch); /*!< get a char from communication interface */
  132. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  133. static void SHELL_Task(void *param); /*!< Shell task*/
  134. #endif
  135. /*******************************************************************************
  136. * Variables
  137. ******************************************************************************/
  138. SHELL_COMMAND_DEFINE(help, "\r\n\"help\": List all the registered commands\r\n", SHELL_HelpCommand, 0);
  139. SHELL_COMMAND_DEFINE(exit, "\r\n\"exit\": Exit program\r\n", SHELL_ExitCommand, 0);
  140. static char s_paramBuffer[SHELL_BUFFER_SIZE];
  141. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  142. #if defined(OSA_USED)
  143. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  144. #else
  145. /*
  146. * \brief Defines the serial manager task's stack
  147. */
  148. OSA_TASK_DEFINE(SHELL_Task, SHELL_TASK_PRIORITY, 1, SHELL_TASK_STACK_SIZE, false);
  149. #endif
  150. #endif
  151. #endif
  152. /*******************************************************************************
  153. * Code
  154. ******************************************************************************/
  155. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  156. static void SHELL_SerialManagerTxCallback(void *callbackParam,
  157. serial_manager_callback_message_t *message,
  158. serial_manager_status_t status)
  159. {
  160. if ((NULL == callbackParam) || (NULL == message))
  161. {
  162. return;
  163. }
  164. if (kStatus_SerialManager_Success == status)
  165. {
  166. }
  167. else if (kStatus_SerialManager_Canceled == status)
  168. {
  169. }
  170. else
  171. {
  172. }
  173. }
  174. static void SHELL_SerialManagerRxCallback(void *callbackParam,
  175. serial_manager_callback_message_t *message,
  176. serial_manager_status_t status)
  177. {
  178. shell_context_handle_t *shellHandle;
  179. if ((NULL == callbackParam) || (NULL == message))
  180. {
  181. return;
  182. }
  183. shellHandle = (shell_context_handle_t *)callbackParam;
  184. if (kStatus_SerialManager_Notify == status)
  185. {
  186. if (!shellHandle->notificationPost)
  187. {
  188. shellHandle->notificationPost = 1U;
  189. #if defined(OSA_USED)
  190. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  191. shellHandle->commontaskMsg.callback = SHELL_Task;
  192. shellHandle->commontaskMsg.callbackParam = shellHandle;
  193. COMMON_TASK_post_message(&shellHandle->commontaskMsg);
  194. #else
  195. (void)OSA_EventSet((osa_event_handle_t)shellHandle->event, SHELL_EVENT_DATA_ARRIVED);
  196. #endif
  197. #else
  198. SHELL_Task(shellHandle);
  199. #endif
  200. }
  201. }
  202. else if (kStatus_SerialManager_Success == status)
  203. {
  204. }
  205. else
  206. {
  207. }
  208. }
  209. #endif
  210. static void SHELL_WriteBuffer(char *buffer, int32_t *indicator, char val, int len)
  211. {
  212. shell_context_handle_t *shellContextHandle;
  213. int i = 0;
  214. shellContextHandle = (shell_context_handle_t *)buffer;
  215. for (i = 0; i < len; i++)
  216. {
  217. if ((*indicator + 1) >= SHELL_SPRINTF_BUFFER_SIZE)
  218. {
  219. SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle,
  220. (uint8_t *)shellContextHandle->printBuffer, *indicator);
  221. shellContextHandle->printLength += *indicator;
  222. *indicator = 0U;
  223. }
  224. shellContextHandle->printBuffer[*indicator] = val;
  225. (*indicator)++;
  226. }
  227. }
  228. static int SHELL_Sprintf(void *buffer, const char *formatString, va_list ap)
  229. {
  230. shell_context_handle_t *shellContextHandle;
  231. uint32_t length;
  232. shellContextHandle = (shell_context_handle_t *)buffer;
  233. length = StrFormatPrintf(formatString, ap, (char *)buffer, SHELL_WriteBuffer);
  234. shellContextHandle->printLength += length;
  235. return length;
  236. }
  237. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  238. static void SHELL_Task(void *param)
  239. #else
  240. void SHELL_Task(shell_handle_t shellHandle)
  241. #endif
  242. {
  243. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  244. shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)param;
  245. #else
  246. shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
  247. #endif
  248. uint8_t ch;
  249. if (NULL != shellContextHandle)
  250. {
  251. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  252. #if defined(OSA_USED)
  253. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  254. #else
  255. osa_event_flags_t ev = 0;
  256. do
  257. {
  258. if (KOSA_StatusSuccess == OSA_EventWait((osa_event_handle_t)shellContextHandle->event, osaEventFlagsAll_c,
  259. false, osaWaitForever_c, &ev))
  260. {
  261. if (ev & SHELL_EVENT_DATA_ARRIVED)
  262. #endif
  263. #endif
  264. #endif
  265. {
  266. shellContextHandle->notificationPost = 0;
  267. do
  268. {
  269. if (shellContextHandle->exit)
  270. {
  271. if (shellContextHandle->serialReadHandle)
  272. {
  273. SerialManager_CloseReadHandle(shellContextHandle->serialReadHandle);
  274. shellContextHandle->serialReadHandle = NULL;
  275. }
  276. if (shellContextHandle->serialWriteHandle)
  277. {
  278. SerialManager_CloseWriteHandle(shellContextHandle->serialWriteHandle);
  279. shellContextHandle->serialWriteHandle = NULL;
  280. }
  281. break;
  282. }
  283. if (kStatus_SHELL_Success != SHELL_GetChar(shellContextHandle, &ch))
  284. {
  285. /* If error occurred when getting a char, exit the task and waiting the new data arriving. */
  286. break;
  287. }
  288. /* Special key */
  289. if (ch == KEY_ESC)
  290. {
  291. shellContextHandle->stat = kSHELL_Special;
  292. continue;
  293. }
  294. else if (shellContextHandle->stat == kSHELL_Special)
  295. {
  296. /* Function key */
  297. if (ch == '[')
  298. {
  299. shellContextHandle->stat = kSHELL_Function;
  300. continue;
  301. }
  302. shellContextHandle->stat = kSHELL_Normal;
  303. }
  304. else if (shellContextHandle->stat == kSHELL_Function)
  305. {
  306. shellContextHandle->stat = kSHELL_Normal;
  307. switch ((uint8_t)ch)
  308. {
  309. /* History operation here */
  310. case 'A': /* Up key */
  311. SHELL_GetHistoryCommand(shellContextHandle, shellContextHandle->hist_current);
  312. if (shellContextHandle->hist_current < (shellContextHandle->hist_count - 1))
  313. {
  314. shellContextHandle->hist_current++;
  315. }
  316. break;
  317. case 'B': /* Down key */
  318. SHELL_GetHistoryCommand(shellContextHandle, shellContextHandle->hist_current);
  319. if (shellContextHandle->hist_current > 0)
  320. {
  321. shellContextHandle->hist_current--;
  322. }
  323. break;
  324. case 'D': /* Left key */
  325. if (shellContextHandle->c_pos)
  326. {
  327. SHELL_Write(shellContextHandle, "\b", 1);
  328. shellContextHandle->c_pos--;
  329. }
  330. break;
  331. case 'C': /* Right key */
  332. if (shellContextHandle->c_pos < shellContextHandle->l_pos)
  333. {
  334. SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
  335. 1);
  336. shellContextHandle->c_pos++;
  337. }
  338. break;
  339. default:
  340. break;
  341. }
  342. continue;
  343. }
  344. /* Handle tab key */
  345. else if (ch == '\t')
  346. {
  347. #if SHELL_AUTO_COMPLETE
  348. /* Move the cursor to the beginning of line */
  349. for (int i = 0; i < shellContextHandle->c_pos; i++)
  350. {
  351. SHELL_Write(shellContextHandle, "\b", 1);
  352. }
  353. /* Do auto complete */
  354. SHELL_AutoComplete(shellContextHandle);
  355. /* Move position to end */
  356. shellContextHandle->c_pos = shellContextHandle->l_pos = strlen(shellContextHandle->line);
  357. #endif
  358. continue;
  359. }
  360. /* Handle backspace key */
  361. else if ((ch == KET_DEL) || (ch == '\b'))
  362. {
  363. /* There must be at last one char */
  364. if (shellContextHandle->c_pos == 0)
  365. {
  366. continue;
  367. }
  368. shellContextHandle->l_pos--;
  369. shellContextHandle->c_pos--;
  370. if (shellContextHandle->l_pos > shellContextHandle->c_pos)
  371. {
  372. memmove(&shellContextHandle->line[shellContextHandle->c_pos],
  373. &shellContextHandle->line[shellContextHandle->c_pos + 1],
  374. shellContextHandle->l_pos - shellContextHandle->c_pos);
  375. shellContextHandle->line[shellContextHandle->l_pos] = 0;
  376. SHELL_Write(shellContextHandle, "\b", 1);
  377. SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
  378. strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
  379. SHELL_Write(shellContextHandle, " \b", 3);
  380. /* Reset position */
  381. for (int i = shellContextHandle->c_pos; i <= shellContextHandle->l_pos; i++)
  382. {
  383. SHELL_Write(shellContextHandle, "\b", 1);
  384. }
  385. }
  386. else /* Normal backspace operation */
  387. {
  388. SHELL_Write(shellContextHandle, "\b \b", 3);
  389. shellContextHandle->line[shellContextHandle->l_pos] = 0;
  390. }
  391. continue;
  392. }
  393. else
  394. {
  395. }
  396. /* Input too long */
  397. if (shellContextHandle->l_pos >= (SHELL_BUFFER_SIZE - 1))
  398. {
  399. shellContextHandle->l_pos = 0;
  400. }
  401. /* Handle end of line, break */
  402. if ((ch == '\r') || (ch == '\n'))
  403. {
  404. static char endoflinechar = 0U;
  405. if ((endoflinechar != 0U) && (endoflinechar != ch))
  406. {
  407. continue;
  408. }
  409. else
  410. {
  411. endoflinechar = ch;
  412. SHELL_Write(shellContextHandle, "\r\n", 2);
  413. /* If command line is NULL, will start a new transfer */
  414. if (0U == strlen(shellContextHandle->line))
  415. {
  416. SHELL_Write(shellContextHandle, shellContextHandle->prompt,
  417. strlen(shellContextHandle->prompt));
  418. continue;
  419. }
  420. SHELL_ProcessCommand(shellContextHandle, shellContextHandle->line);
  421. /* Reset all params */
  422. shellContextHandle->c_pos = shellContextHandle->l_pos = 0;
  423. shellContextHandle->hist_current = 0;
  424. SHELL_Write(shellContextHandle, shellContextHandle->prompt, strlen(shellContextHandle->prompt));
  425. memset(shellContextHandle->line, 0, sizeof(shellContextHandle->line));
  426. continue;
  427. }
  428. }
  429. /* Normal character */
  430. if (shellContextHandle->c_pos < shellContextHandle->l_pos)
  431. {
  432. memmove(&shellContextHandle->line[shellContextHandle->c_pos + 1],
  433. &shellContextHandle->line[shellContextHandle->c_pos],
  434. shellContextHandle->l_pos - shellContextHandle->c_pos);
  435. shellContextHandle->line[shellContextHandle->c_pos] = ch;
  436. SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->c_pos],
  437. strlen(&shellContextHandle->line[shellContextHandle->c_pos]));
  438. /* Move the cursor to new position */
  439. for (int i = shellContextHandle->c_pos; i < shellContextHandle->l_pos; i++)
  440. {
  441. SHELL_Write(shellContextHandle, "\b", 1);
  442. }
  443. }
  444. else
  445. {
  446. shellContextHandle->line[shellContextHandle->l_pos] = ch;
  447. SHELL_Write(shellContextHandle, &shellContextHandle->line[shellContextHandle->l_pos], 1);
  448. }
  449. ch = 0;
  450. shellContextHandle->l_pos++;
  451. shellContextHandle->c_pos++;
  452. } while (!shellContextHandle->exit);
  453. }
  454. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  455. #if defined(OSA_USED)
  456. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  457. #else
  458. }
  459. } while (gUseRtos_c);
  460. #endif
  461. #endif
  462. #endif
  463. }
  464. }
  465. static shell_status_t SHELL_HelpCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
  466. {
  467. shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
  468. shell_command_t *shellCommandContextHandle;
  469. list_element_handle_t p = LIST_GetHead(&shellContextHandle->commandContextListHead);
  470. while (p)
  471. {
  472. shellCommandContextHandle = SHEEL_COMMAND_POINTER(p);
  473. if (shellCommandContextHandle->pcHelpString && strlen(shellCommandContextHandle->pcHelpString))
  474. {
  475. SHELL_Write(shellContextHandle, shellCommandContextHandle->pcHelpString,
  476. strlen(shellCommandContextHandle->pcHelpString));
  477. }
  478. p = LIST_GetNext(p);
  479. }
  480. return kStatus_SHELL_Success;
  481. }
  482. static shell_status_t SHELL_ExitCommand(shell_handle_t shellHandle, int32_t argc, char **argv)
  483. {
  484. shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
  485. /* Skip warning */
  486. SHELL_Write(shellContextHandle, "\r\nSHELL exited\r\n", strlen("\r\nSHELL exited\r\n"));
  487. shellContextHandle->exit = true;
  488. return kStatus_SHELL_Success;
  489. }
  490. static void SHELL_ProcessCommand(shell_context_handle_t *shellContextHandle, const char *cmd)
  491. {
  492. shell_command_t *tmpCommand = NULL;
  493. const char *tmpCommandString;
  494. int32_t argc;
  495. char *argv[SHELL_BUFFER_SIZE];
  496. list_element_handle_t p;
  497. uint8_t flag = 1;
  498. uint8_t tmpCommandLen;
  499. uint8_t tmpLen;
  500. uint8_t i = 0;
  501. tmpLen = strlen(cmd);
  502. argc = SHELL_ParseLine(cmd, tmpLen, argv);
  503. if ((tmpCommand == NULL) && (argc > 0))
  504. {
  505. p = LIST_GetHead(&shellContextHandle->commandContextListHead);
  506. while (p)
  507. {
  508. tmpCommand = SHEEL_COMMAND_POINTER(p);
  509. tmpCommandString = tmpCommand->pcCommand;
  510. tmpCommandLen = strlen(tmpCommandString);
  511. /* Compare with space or end of string */
  512. if ((cmd[tmpCommandLen] == ' ') || (cmd[tmpCommandLen] == 0x00))
  513. {
  514. if (SHELL_StringCompare(tmpCommandString, argv[0], tmpCommandLen) == 0)
  515. {
  516. /* support commands with optional number of parameters */
  517. if (tmpCommand->cExpectedNumberOfParameters == SHELL_IGNORE_PARAMETER_COUNT)
  518. {
  519. flag = 0;
  520. }
  521. else if ((tmpCommand->cExpectedNumberOfParameters == 0) && (argc == 1))
  522. {
  523. flag = 0;
  524. }
  525. else if (tmpCommand->cExpectedNumberOfParameters > 0)
  526. {
  527. if ((argc - 1) == tmpCommand->cExpectedNumberOfParameters)
  528. {
  529. flag = 0;
  530. }
  531. }
  532. else
  533. {
  534. flag = 1;
  535. }
  536. break;
  537. }
  538. }
  539. p = LIST_GetNext(p);
  540. }
  541. }
  542. if ((tmpCommand != NULL) && (flag == 1U))
  543. {
  544. SHELL_Write(
  545. shellContextHandle,
  546. "\r\nIncorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n",
  547. strlen(
  548. "\r\nIncorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n"));
  549. tmpCommand = NULL;
  550. }
  551. else if (tmpCommand != NULL)
  552. {
  553. tmpLen = strlen(cmd);
  554. /* Compare with last command. Push back to history buffer if different */
  555. if (tmpLen != SHELL_StringCompare(cmd, shellContextHandle->hist_buf[0], strlen(cmd)))
  556. {
  557. for (i = SHELL_HISTORY_COUNT - 1; i > 0; i--)
  558. {
  559. memset(shellContextHandle->hist_buf[i], '\0', SHELL_BUFFER_SIZE);
  560. tmpLen = strlen(shellContextHandle->hist_buf[i - 1]);
  561. memcpy(shellContextHandle->hist_buf[i], shellContextHandle->hist_buf[i - 1], tmpLen);
  562. }
  563. memset(shellContextHandle->hist_buf[0], '\0', SHELL_BUFFER_SIZE);
  564. tmpLen = strlen(cmd);
  565. memcpy(shellContextHandle->hist_buf[0], cmd, tmpLen);
  566. if (shellContextHandle->hist_count < SHELL_HISTORY_COUNT)
  567. {
  568. shellContextHandle->hist_count++;
  569. }
  570. }
  571. tmpCommand->pFuncCallBack(shellContextHandle, argc, argv);
  572. tmpCommand = NULL;
  573. }
  574. else
  575. {
  576. SHELL_Write(shellContextHandle,
  577. "\r\nCommand not recognized. Enter 'help' to view a list of available commands.\r\n\r\n",
  578. strlen("\r\nCommand not recognized. Enter 'help' to view a list of available commands.\r\n\r\n"));
  579. tmpCommand = NULL;
  580. }
  581. }
  582. static void SHELL_GetHistoryCommand(shell_context_handle_t *shellContextHandle, uint8_t hist_pos)
  583. {
  584. uint8_t i;
  585. uint32_t tmp;
  586. if (shellContextHandle->hist_buf[0][0] == '\0')
  587. {
  588. shellContextHandle->hist_current = 0;
  589. return;
  590. }
  591. if (hist_pos >= SHELL_HISTORY_COUNT)
  592. {
  593. hist_pos = SHELL_HISTORY_COUNT - 1;
  594. }
  595. tmp = strlen(shellContextHandle->line);
  596. /* Clear current if have */
  597. if (tmp > 0)
  598. {
  599. memset(shellContextHandle->line, '\0', tmp);
  600. for (i = 0; i < tmp; i++)
  601. {
  602. SHELL_Write(shellContextHandle, "\b \b", 3);
  603. }
  604. }
  605. shellContextHandle->l_pos = strlen(shellContextHandle->hist_buf[hist_pos]);
  606. shellContextHandle->c_pos = shellContextHandle->l_pos;
  607. memcpy(shellContextHandle->line, shellContextHandle->hist_buf[hist_pos], shellContextHandle->l_pos);
  608. SHELL_Write(shellContextHandle, shellContextHandle->hist_buf[hist_pos],
  609. strlen(shellContextHandle->hist_buf[hist_pos]));
  610. }
  611. static void SHELL_AutoComplete(shell_context_handle_t *shellContextHandle)
  612. {
  613. int32_t len;
  614. int32_t minLen;
  615. list_element_handle_t p;
  616. shell_command_t *tmpCommand = NULL;
  617. const char *namePtr;
  618. const char *cmdName;
  619. minLen = 0;
  620. namePtr = NULL;
  621. if (!strlen(shellContextHandle->line))
  622. {
  623. return;
  624. }
  625. SHELL_Write(shellContextHandle, "\r\n", 2);
  626. /* Empty tab, list all commands */
  627. if (shellContextHandle->line[0] == '\0')
  628. {
  629. SHELL_HelpCommand(shellContextHandle, 0, NULL);
  630. return;
  631. }
  632. /* Do auto complete */
  633. p = LIST_GetHead(&shellContextHandle->commandContextListHead);
  634. while (p)
  635. {
  636. tmpCommand = SHEEL_COMMAND_POINTER(p);
  637. cmdName = tmpCommand->pcCommand;
  638. if (SHELL_StringCompare(shellContextHandle->line, cmdName, strlen(shellContextHandle->line)) == 0)
  639. {
  640. if (minLen == 0)
  641. {
  642. namePtr = cmdName;
  643. minLen = strlen(namePtr);
  644. /* Show possible matches */
  645. SHELL_Write(shellContextHandle, (char *)cmdName, strlen(cmdName));
  646. SHELL_Write(shellContextHandle, "\r\n", 2);
  647. continue;
  648. }
  649. len = SHELL_StringCompare(namePtr, cmdName, strlen(namePtr));
  650. if (len < 0)
  651. {
  652. len = len * (-1);
  653. }
  654. if (len < minLen)
  655. {
  656. minLen = len;
  657. }
  658. }
  659. p = LIST_GetNext(p);
  660. }
  661. /* Auto complete string */
  662. if (namePtr)
  663. {
  664. memcpy(shellContextHandle->line, namePtr, minLen);
  665. }
  666. SHELL_Write(shellContextHandle, shellContextHandle->prompt, strlen(shellContextHandle->prompt));
  667. SHELL_Write(shellContextHandle, shellContextHandle->line, strlen(shellContextHandle->line));
  668. return;
  669. }
  670. static int32_t SHELL_StringCompare(const char *str1, const char *str2, int32_t count)
  671. {
  672. while (count--)
  673. {
  674. if (*str1++ != *str2++)
  675. {
  676. return *(unsigned char *)(str1 - 1) - *(unsigned char *)(str2 - 1);
  677. }
  678. }
  679. return 0;
  680. }
  681. static int32_t SHELL_ParseLine(const char *cmd, uint32_t len, char *argv[])
  682. {
  683. uint32_t argc;
  684. char *p;
  685. uint32_t position;
  686. /* Init params */
  687. memset(s_paramBuffer, '\0', len + 1);
  688. memcpy(s_paramBuffer, cmd, len);
  689. p = s_paramBuffer;
  690. position = 0;
  691. argc = 0;
  692. while (position < len)
  693. {
  694. /* Skip all blanks */
  695. while (((char)(*p) == ' ') && (position < len))
  696. {
  697. *p = '\0';
  698. p++;
  699. position++;
  700. }
  701. /* Process begin of a string */
  702. if (*p == '"')
  703. {
  704. p++;
  705. position++;
  706. argv[argc] = p;
  707. argc++;
  708. /* Skip this string */
  709. while ((*p != '"') && (position < len))
  710. {
  711. p++;
  712. position++;
  713. }
  714. /* Skip '"' */
  715. *p = '\0';
  716. p++;
  717. position++;
  718. }
  719. else /* Normal char */
  720. {
  721. argv[argc] = p;
  722. argc++;
  723. while (((char)*p != ' ') && ((char)*p != '\t') && (position < len))
  724. {
  725. p++;
  726. position++;
  727. }
  728. }
  729. }
  730. return argc;
  731. }
  732. static shell_status_t SHELL_GetChar(shell_context_handle_t *shellContextHandle, uint8_t *ch)
  733. {
  734. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  735. uint32_t length;
  736. if (kStatus_SerialManager_Success == SerialManager_TryRead(shellContextHandle->serialReadHandle, ch, 1, &length))
  737. {
  738. if (length > 0)
  739. {
  740. return kStatus_SHELL_Success;
  741. }
  742. }
  743. return kStatus_SHELL_Error;
  744. #else
  745. return (shell_status_t)SerialManager_ReadBlocking(shellContextHandle->serialReadHandle, ch, 1);
  746. #endif
  747. }
  748. shell_status_t SHELL_Init(shell_handle_t shellHandle, serial_handle_t serialHandle, char *prompt)
  749. {
  750. shell_context_handle_t *shellContextHandle;
  751. assert(shellHandle);
  752. assert(serialHandle);
  753. assert(prompt);
  754. if (SHELL_HANDLE_SIZE < sizeof(shell_context_handle_t))
  755. {
  756. return kStatus_SHELL_Error;
  757. }
  758. shellContextHandle = (shell_context_handle_t *)shellHandle;
  759. /* memory set for shellHandle */
  760. memset(shellHandle, 0, SHELL_HANDLE_SIZE);
  761. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  762. #if defined(OSA_USED)
  763. #if (defined(SHELL_USE_COMMON_TASK) && (SHELL_USE_COMMON_TASK > 0U))
  764. COMMON_TASK_init();
  765. #else
  766. if (KOSA_StatusSuccess != OSA_EventCreate((osa_event_handle_t)shellContextHandle->event, true))
  767. {
  768. return kStatus_SHELL_Error;
  769. }
  770. if (KOSA_StatusSuccess !=
  771. OSA_TaskCreate((osa_task_handle_t)shellContextHandle->taskId, OSA_TASK(SHELL_Task), shellContextHandle))
  772. {
  773. return kStatus_SHELL_Error;
  774. }
  775. #endif
  776. #endif
  777. #endif
  778. shellContextHandle->prompt = prompt;
  779. shellContextHandle->serialHandle = serialHandle;
  780. shellContextHandle->serialWriteHandle = (serial_write_handle_t)&shellContextHandle->serialWriteHandleBuffer[0];
  781. if (kStatus_SerialManager_Success !=
  782. SerialManager_OpenWriteHandle(shellContextHandle->serialHandle, shellContextHandle->serialWriteHandle))
  783. {
  784. return kStatus_SHELL_OpenWriteHandleFailed;
  785. }
  786. else
  787. {
  788. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  789. SerialManager_InstallTxCallback(shellContextHandle->serialWriteHandle, SHELL_SerialManagerTxCallback,
  790. shellContextHandle);
  791. #endif
  792. }
  793. shellContextHandle->serialReadHandle = (serial_read_handle_t)&shellContextHandle->serialReadHandleBuffer[0];
  794. if (kStatus_SerialManager_Success !=
  795. SerialManager_OpenReadHandle(shellContextHandle->serialHandle, shellContextHandle->serialReadHandle))
  796. {
  797. return kStatus_SHELL_OpenReadHandleFailed;
  798. }
  799. else
  800. {
  801. #if (defined(SHELL_NON_BLOCKING_MODE) && (SHELL_NON_BLOCKING_MODE > 0U))
  802. SerialManager_InstallRxCallback(shellContextHandle->serialReadHandle, SHELL_SerialManagerRxCallback,
  803. shellContextHandle);
  804. #endif
  805. }
  806. SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(help));
  807. SHELL_RegisterCommand(shellContextHandle, SHELL_COMMAND(exit));
  808. SHELL_Write(shellContextHandle, "\r\nSHELL build: ", strlen("\r\nSHELL build: "));
  809. SHELL_Write(shellContextHandle, __DATE__, strlen(__DATE__));
  810. SHELL_Write(shellContextHandle, "\r\nCopyright (c) 2018 NXP Semiconductor\r\n",
  811. strlen("\r\nCopyright (c) 2018 NXP Semiconductor\r\n"));
  812. SHELL_Write(shellContextHandle, shellContextHandle->prompt, strlen(shellContextHandle->prompt));
  813. return kStatus_SHELL_Success;
  814. }
  815. shell_status_t SHELL_RegisterCommand(shell_handle_t shellHandle, shell_command_t *command)
  816. {
  817. shell_context_handle_t *shellContextHandle = (shell_context_handle_t *)shellHandle;
  818. assert(shellHandle);
  819. assert(command);
  820. /* memory set for shellHandle */
  821. memset(&command->link, 0, sizeof(command->link));
  822. LIST_AddTail(&shellContextHandle->commandContextListHead, &command->link);
  823. return kStatus_SHELL_Success;
  824. }
  825. shell_status_t SHELL_UnregisterCommand(shell_command_t *command)
  826. {
  827. assert(command);
  828. LIST_RemoveElement(&command->link);
  829. /* memory set for shellHandle */
  830. memset(&command->link, 0, sizeof(command->link));
  831. return kStatus_SHELL_Success;
  832. }
  833. shell_status_t SHELL_Write(shell_handle_t shellHandle, char *buffer, uint32_t length)
  834. {
  835. shell_context_handle_t *shellContextHandle;
  836. uint32_t primask;
  837. assert(shellHandle);
  838. assert(buffer);
  839. if (!length)
  840. {
  841. return kStatus_SHELL_Success;
  842. }
  843. shellContextHandle = (shell_context_handle_t *)shellHandle;
  844. primask = DisableGlobalIRQ();
  845. if (shellContextHandle->printBusy)
  846. {
  847. EnableGlobalIRQ(primask);
  848. return kStatus_SHELL_Error;
  849. }
  850. shellContextHandle->printBusy = 1U;
  851. EnableGlobalIRQ(primask);
  852. if (kStatus_SerialManager_Success ==
  853. SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle, (uint8_t *)buffer, length))
  854. {
  855. shellContextHandle->printBusy = 0U;
  856. return kStatus_SHELL_Success;
  857. }
  858. shellContextHandle->printBusy = 0U;
  859. return kStatus_SHELL_Error;
  860. }
  861. int SHELL_Printf(shell_handle_t shellHandle, const char *formatString, ...)
  862. {
  863. shell_context_handle_t *shellContextHandle;
  864. uint32_t length;
  865. uint32_t primask;
  866. va_list ap;
  867. assert(shellHandle);
  868. assert(formatString);
  869. shellContextHandle = (shell_context_handle_t *)shellHandle;
  870. primask = DisableGlobalIRQ();
  871. if (shellContextHandle->printBusy)
  872. {
  873. EnableGlobalIRQ(primask);
  874. return -1;
  875. }
  876. shellContextHandle->printBusy = 1U;
  877. EnableGlobalIRQ(primask);
  878. va_start(ap, formatString);
  879. shellContextHandle->printLength = 0U;
  880. length = SHELL_Sprintf(shellHandle, formatString, ap);
  881. SerialManager_WriteBlocking(shellContextHandle->serialWriteHandle, (uint8_t *)shellContextHandle->printBuffer,
  882. length);
  883. va_end(ap);
  884. shellContextHandle->printBusy = 0U;
  885. return shellContextHandle->printLength;
  886. }