fsl_shell.c 41 KB

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