1 /**
2 *********************************************************************************************************
3 *               Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
4 **********************************************************************************************************
5 * @file     user_cmd_parse.c
6 * @brief    Parse user command from lower Data UART data.
7 * @details  Parse user commands and execute right commands.
8 * @author
9 * @date     2016-02-18
10 * @version  v0.1
11 *********************************************************************************************************
12 */
13 #include <string.h>
14 #include <data_uart.h>
15 #include <user_cmd_parse.h>
16 
17 /**
18  * @brief   Check if a character is a white space.
19  *
20  * @param c     Char data to check.
21  * @return  Check result.
22  * @retval  1  true.
23  * @retval  0  false.
24  */
user_cmd_is_white_space(char c)25 static bool user_cmd_is_white_space(char c)
26 {
27     return (((c >= 9) && (c <= 13)) || (c == 32));
28 }
29 
30 /**
31  * @brief  Skip white spaces in buffer.
32  *
33  * @param  buffer    Address of the buffer.
34  * @return pointer to skipped white spaces' new buffer.
35  */
user_cmd_skip_spaces(char * buffer)36 static char *user_cmd_skip_spaces(char *buffer)
37 {
38     char *p = buffer;
39 
40     while (user_cmd_is_white_space(*p)) /* white space */
41     {
42         p++;
43     }
44     return p;
45 }
46 
47 /**
48  * @brief  Find end of a word.
49  *
50  * @param buffer    Address of the buffer.
51  * @return
52  */
user_cmd_find_end_of_word(char * buffer)53 static char *user_cmd_find_end_of_word(char *buffer)
54 {
55     char *p = buffer;
56 
57     while (!user_cmd_is_white_space(*p) && (*p != '\0'))
58     {
59         p++;
60     }
61     return p;
62 }
63 
64 /**
65  * @brief  Read ASCII string and convert to uint32_t.
66  *
67  * @param p  String address.
68  * @return
69  */
user_cmd_str_to_uint32(char * p)70 static uint32_t user_cmd_str_to_uint32(char *p)
71 {
72     uint32_t result = 0;
73     bool     hex = false;
74 
75     /* check if value is dec */
76     if (p[0] == 'x')
77     {
78         hex = true;
79         p = &p[1];
80     }
81     else if ((p[0] == '0') && (p[1] == 'x'))
82     {
83         hex = true;
84         p = &p[2];
85     }
86 
87     for (;;)
88     {
89         char     ch;
90         ch = *(p++) | 0x20;                 /* convert to lower case */
91 
92         if (hex)                            /* dec value */
93         {
94             /* hex value */
95             if ((ch >= 'a') && (ch <= 'f'))
96             {
97                 ch -= ('a' - 10);
98             }
99             else if ((ch >= '0') && (ch <= '9'))
100             {
101                 ch -= '0';
102             }
103             else
104             {
105                 break;
106             }
107             result = (result << 4);
108             result += (ch & 0x0f);
109         }
110         else
111         {
112             if (ch < '0' || ch > '9')
113             {
114                 break;    /* end of string reached */
115             }
116             result = 10 * result + ch - '0';
117         }
118     }
119     return (result);
120 }
121 
122 /**
123  * @brief  Send result, display in UART Assitant.
124  *
125  * @param result    Command parse result.
126  * @return none
127 */
cmd_send_result(T_USER_CMD_PARSE_RESULT result)128 static void cmd_send_result(T_USER_CMD_PARSE_RESULT result)
129 {
130     switch (result)
131     {
132     case RESULT_ERR:
133         data_uart_print("%s\r\n", "CMD:Error");
134         break;
135     case RESULT_GAP_CAUSE_ALREADY_IN_REQ:
136         data_uart_print("%s\r\n", "GAP_CAUSE_ALREADY_IN_REQ");
137         break;
138     case RESULT_GAP_CAUSE_INVALID_STATE:
139         data_uart_print("%s\r\n", "GAP_CAUSE_INVALID_STATE");
140         break;
141     case RESULT_GAP_CAUSE_INVALID_PARAM:
142         data_uart_print("%s\r\n", "GAP_CAUSE_INVALID_PARAM");
143         break;
144     case RESULT_GAP_CAUSE_NON_CONN:
145         data_uart_print("%s\r\n", "GAP_CAUSE_NON_CONN");
146         break;
147     case RESULT_GAP_CAUSE_NOT_FIND_IRK:
148         data_uart_print("%s\r\n", "GAP_CAUSE_NOT_FIND_IRK");
149         break;
150     case RESULT_GAP_CAUSE_ERROR_CREDITS:
151         data_uart_print("%s\r\n", "GAP_CAUSE_ERROR_CREDITS");
152         break;
153     case RESULT_GAP_CAUSE_SEND_REQ_FAILED:
154         data_uart_print("%s\r\n", "GAP_CAUSE_SEND_REQ_FAILED");
155         break;
156     case RESULT_GAP_CAUSE_NO_RESOURCE:
157         data_uart_print("%s\r\n", "GAP_CAUSE_NO_RESOURCE");
158         break;
159     case RESULT_GAP_CAUSE_INVALID_PDU_SIZE:
160         data_uart_print("%s\r\n", "GAP_CAUSE_INVALID_PDU_SIZE");
161         break;
162     case RESULT_GAP_CAUSE_NOT_FIND:
163         data_uart_print("%s\r\n", "GAP_CAUSE_NOT_FIND");
164         break;
165     case RESULT_GAP_CAUSE_CONN_LIMIT:
166         data_uart_print("%s\r\n", "GAP_CAUSE_CONN_LIMIT");
167         break;
168     case RESULT_CMD_NOT_FOUND:
169         data_uart_print("%s\r\n", "CMD:Command not found");
170         break;
171     case RESULT_CMD_ERR_PARAM_NUM:
172         data_uart_print("%s\r\n", "CMD:Wrong number of parameters");
173         break;
174     case RESULT_CMD_ERR_PARAM:
175         data_uart_print("%s\r\n", "CMD:Wrong parameter");
176         break;
177     case RESULT_CMD_OUT_OF_RANGE:
178         data_uart_print("%s\r\n", "CMD:Value out of range");
179         break;
180     case RESULT_CMD_NOT_SUPPORT:
181         data_uart_print("%s\r\n", "CMD:Not support");
182         break;
183     case RESULT_GAP_CAUSE_ERROR_UNKNOWN:
184         data_uart_print("%s\r\n", "GAP_CAUSE_ERROR_UNKNOWN");
185         break;
186     default:
187         break;
188     }
189 }
190 
191 /**
192  * @brief   List cmd.
193  *
194  * @param p_cmd_table   Command table, include user self-definition command function.
195  * @return  Command execute result.
196 */
user_cmd_list(const T_USER_CMD_TABLE_ENTRY * p_cmd_table)197 static T_USER_CMD_PARSE_RESULT user_cmd_list(const T_USER_CMD_TABLE_ENTRY *p_cmd_table)
198 {
199     int32_t i = 0;
200     T_USER_CMD_PARSE_RESULT result = RESULT_CMD_NOT_FOUND;
201 
202     /* find command in table */
203     while ((p_cmd_table + i)->p_cmd != NULL)
204     {
205         data_uart_print("%s", (p_cmd_table + i)->p_option);
206         data_uart_print("%s", "  *");
207         data_uart_print("%s", (p_cmd_table + i)->p_help);
208         result = RESULT_SUCESS;
209         i++;
210     };
211 
212     data_uart_print(",.\r\n  *up down\r\n");
213     data_uart_print("[]\r\n  *left right\r\n");
214     data_uart_print("/\\\r\n  *home end\r\n");
215     data_uart_print("backspace\r\n  *delete\r\n");
216 
217     return result;
218 }
219 
220 /**
221  * @brief  Execute command.
222  *
223  * @param p_parse_value     Command parse value.
224  * @param p_cmd_table       Command table, include user self-definition command function.
225  * @return  Command execute result.
226 */
user_cmd_execute(T_USER_CMD_PARSED_VALUE * p_parse_value,const T_USER_CMD_TABLE_ENTRY * p_cmd_table)227 static T_USER_CMD_PARSE_RESULT user_cmd_execute(T_USER_CMD_PARSED_VALUE *p_parse_value,
228                                                 const T_USER_CMD_TABLE_ENTRY *p_cmd_table)
229 {
230     int32_t i = 0;
231     T_USER_CMD_PARSE_RESULT result = RESULT_CMD_NOT_FOUND;
232 
233     if (strcmp((const char *)p_parse_value->p_cmd, (const char *)"?") == 0)
234     {
235         user_cmd_list(p_cmd_table);
236         return RESULT_SUCESS;
237     }
238 
239     /* find command in table */
240     while ((p_cmd_table + i)->p_cmd != NULL)
241     {
242         if (strcmp((const char *)(p_cmd_table + i)->p_cmd, (const char *)p_parse_value->p_cmd) == 0)
243         {
244             /* check if user wants help */
245             if (p_parse_value->param_count && *p_parse_value->p_param[0] == '?')
246             {
247                 data_uart_print("%s", (p_cmd_table + i)->p_option);
248                 data_uart_print("%s", "  *");
249                 data_uart_print("%s", (p_cmd_table + i)->p_help);
250                 result = RESULT_SUCESS;
251             }
252             else
253             {
254                 /* execute command function */
255                 result = (p_cmd_table + i)->func(p_parse_value);
256             }
257             /* exit while */
258             break;
259         }
260         i++;
261     };
262 
263     return result;
264 }
265 
266 /**
267  * @brief  Parse a command line and return the found command and parameters in "p_parse_value"
268  *
269  * @param p_user_cmd_if     Command parsed.
270  * @param p_parse_value     Command parse value.
271  * @return  Command parse result.
272 */
user_cmd_parse(T_USER_CMD_IF * p_user_cmd_if,T_USER_CMD_PARSED_VALUE * p_parse_value)273 static T_USER_CMD_PARSE_RESULT user_cmd_parse(T_USER_CMD_IF *p_user_cmd_if,
274                                               T_USER_CMD_PARSED_VALUE *p_parse_value)
275 {
276     int32_t i;
277     char *p, *q;
278 
279     /* clear all results */
280     p_parse_value->p_cmd       = NULL;
281     p_parse_value->param_count = 0;
282     for (i = 0 ; i < USER_CMD_MAX_PARAMETERS; i++)
283     {
284         p_parse_value->p_param[i]  = NULL;
285         p_parse_value->dw_param[i] = 0;
286     }
287 
288     /* Parse line */
289     p = p_user_cmd_if->cmdline_buf;
290 
291     /*ignore leading spaces */
292     p = user_cmd_skip_spaces(p);
293     if (*p == '\0')                     /* empty command line ? */
294     {
295         return RESULT_CMD_EMPTY_LINE;
296     }
297 
298     /* find end of word */
299     q = user_cmd_find_end_of_word(p);
300     if (p == q)                         /* empty command line ? */
301     {
302         return RESULT_CMD_EMPTY_LINE;
303     }
304 
305     p_parse_value->p_cmd = p;
306     *q = '\0';                        /* mark end of command */
307     p = q + 1;
308 
309     /* parse parameters */
310     if (*p != '\0')                   /* end of line ? */
311     {
312         int32_t j;
313 
314         j = 0;
315         do
316         {
317             uint32_t d;
318             /* ignore leading spaces */
319             p = user_cmd_skip_spaces(p);
320             d = user_cmd_str_to_uint32(p);
321 
322             p_parse_value->p_param[j]    = p;
323             p_parse_value->dw_param[j++] = d;
324 
325             if (j >= USER_CMD_MAX_PARAMETERS)
326             {
327                 break;
328             }
329 
330             /* find next parameter */
331             p  = user_cmd_find_end_of_word(p);
332             *p++ = '\0';                        /* mark end of parameter */
333         }
334         while (*p != '\0');
335 
336         p_parse_value->param_count = j;
337     }
338 
339     return RESULT_SUCESS;
340 }
341 
342 /**
343  * @brief  Clear command line buffer.
344  *
345  * @param p_user_cmd_if     Command parsed.
346  * @return none.
347 */
cmd_clear(T_USER_CMD_IF * p_user_cmd_if)348 static void cmd_clear(T_USER_CMD_IF *p_user_cmd_if)
349 {
350     p_user_cmd_if->accum_cmd_len = 0;
351     p_user_cmd_if->cmd_cur = 0;
352     memset(p_user_cmd_if->cmdline_buf, 0, sizeof(p_user_cmd_if->cmdline_buf));
353 }
354 
cmd_move_back(T_USER_CMD_IF * p_user_cmd_if)355 static void cmd_move_back(T_USER_CMD_IF *p_user_cmd_if)
356 {
357     for (uint8_t loop = 0; loop < p_user_cmd_if->accum_cmd_len - p_user_cmd_if->cmd_cur; loop ++)
358     {
359         p_user_cmd_if->cmdline_buf[p_user_cmd_if->accum_cmd_len - loop] =
360             p_user_cmd_if->cmdline_buf[p_user_cmd_if->accum_cmd_len - loop - 1];
361     }
362 }
363 
cmd_move_forward(T_USER_CMD_IF * p_user_cmd_if)364 static void cmd_move_forward(T_USER_CMD_IF *p_user_cmd_if)
365 {
366     for (uint8_t loop = 0; loop < p_user_cmd_if->accum_cmd_len - p_user_cmd_if->cmd_cur; loop ++)
367     {
368         p_user_cmd_if->cmdline_buf[p_user_cmd_if->cmd_cur + loop - 1] =
369             p_user_cmd_if->cmdline_buf[p_user_cmd_if->cmd_cur + loop];
370     }
371 }
cmd_clear_screen(T_USER_CMD_IF * p_user_cmd_if)372 static void cmd_clear_screen(T_USER_CMD_IF *p_user_cmd_if)
373 {
374     if (p_user_cmd_if->cmd_cur < p_user_cmd_if->accum_cmd_len)
375     {
376         data_uart_print("%s", p_user_cmd_if->cmdline_buf + p_user_cmd_if->cmd_cur);
377     }
378 
379     while (p_user_cmd_if->accum_cmd_len != 0)
380     {
381         p_user_cmd_if->accum_cmd_len--;
382         p_user_cmd_if->cmdline_buf[p_user_cmd_if->accum_cmd_len] = '\0';
383         data_uart_print("\b \b");
384     }
385     p_user_cmd_if->cmd_cur = 0;
386 }
387 
388 /**
389  * @brief  Collect command characters.
390  *
391  * @param[in] p_user_cmd_if   Store parsed commands.
392  * @param[in] p_data          Data to be parsed.
393  * @param[in] len             Length of data to be command parsed.
394  * @param[in] p_cmd_table     Command table to execute function.
395  * @return  Command collect result.
396  * @retval 1 true.
397  * @retval 0 false.
398  *
399  * <b>Example usage</b>
400  * \code{.c}
401     void app_handle_io_msg(T_IO_MSG io_msg)
402     {
403         uint16_t msg_type = io_msg.type;
404         uint8_t rx_char;
405 
406         switch (msg_type)
407         {
408         case IO_MSG_TYPE_UART:
409             // We handle user command informations from Data UART in this branch.
410             rx_char = (uint8_t)io_msg.subtype;
411             user_cmd_collect(&user_cmd_if, &rx_char, sizeof(rx_char), user_cmd_table);
412             break;
413         default:
414             break;
415         }
416     }
417  * \endcode
418  */
user_cmd_collect(T_USER_CMD_IF * p_user_cmd_if,uint8_t * p_data,int32_t len,const T_USER_CMD_TABLE_ENTRY * p_cmd_table)419 bool user_cmd_collect(T_USER_CMD_IF *p_user_cmd_if, uint8_t *p_data, int32_t len,
420                       const T_USER_CMD_TABLE_ENTRY *p_cmd_table)
421 {
422     T_USER_CMD_PARSED_VALUE parse_result;
423 
424     while (len--)
425     {
426         char c = *p_data++;
427 
428         if (c != 0x0)                   /* not ESC character received */
429         {
430             switch (c)                  /* Normal handling */
431             {
432             case '\n':
433             case '\r':                  /* end of line */
434                 data_uart_print("\r\n");
435                 p_user_cmd_if->history_cur = USER_CMD_MAX_HISTORY_LINE;
436 
437                 if (p_user_cmd_if->accum_cmd_len > 0)  /* at least one character in command line ? */
438                 {
439                     T_USER_CMD_PARSE_RESULT result;
440 
441                     // save cmd first
442                     if (p_user_cmd_if->history_head == USER_CMD_MAX_HISTORY_LINE)
443                     {
444                         p_user_cmd_if->history_head = 0;
445                         p_user_cmd_if->history_tail = 0;
446                     }
447                     else
448                     {
449                         p_user_cmd_if->history_tail = (p_user_cmd_if->history_tail + 1) % USER_CMD_MAX_HISTORY_LINE;
450                         if (p_user_cmd_if->history_tail == p_user_cmd_if->history_head)
451                         {
452                             p_user_cmd_if->history_head = (p_user_cmd_if->history_head + 1) % USER_CMD_MAX_HISTORY_LINE;
453                         }
454                     }
455                     p_user_cmd_if->cmd_history_len[p_user_cmd_if->history_tail] = p_user_cmd_if->accum_cmd_len;
456                     memcpy(p_user_cmd_if->cmd_history[p_user_cmd_if->history_tail], p_user_cmd_if->cmdline_buf,
457                            p_user_cmd_if->accum_cmd_len);
458 
459                     p_user_cmd_if->cmdline_buf[p_user_cmd_if->accum_cmd_len] = '\0';
460                     result = user_cmd_parse(p_user_cmd_if, &parse_result);
461                     if (result == RESULT_SUCESS)
462                     {
463                         result = user_cmd_execute(&parse_result, p_cmd_table);
464                     }
465 
466                     if (result != RESULT_SUCESS)
467                     {
468                         cmd_send_result(result);
469                     }
470                 }
471 
472                 cmd_clear(p_user_cmd_if);
473                 break;
474 
475             case '\b':                        /* backspace */
476                 if (p_user_cmd_if->accum_cmd_len > 0 && p_user_cmd_if->cmd_cur > 0)
477                 {
478                     uint8_t loop;
479 
480                     cmd_move_forward(p_user_cmd_if);
481                     p_user_cmd_if->accum_cmd_len--;
482                     p_user_cmd_if->cmd_cur--;
483                     p_user_cmd_if->cmdline_buf[p_user_cmd_if->accum_cmd_len] = '\0';
484                     data_uart_print("\b%s", p_user_cmd_if->cmdline_buf + p_user_cmd_if->cmd_cur);
485                     data_uart_print(" \b");
486                     for (loop = 0; loop < p_user_cmd_if->accum_cmd_len - p_user_cmd_if->cmd_cur; loop++)
487                     {
488                         data_uart_print("\b");
489                     }
490                 }
491                 break;
492 
493             case 44:                            /* up: < */
494                 if (p_user_cmd_if->history_head != USER_CMD_MAX_HISTORY_LINE)
495                 {
496                     cmd_clear_screen(p_user_cmd_if);
497                     if (p_user_cmd_if->history_cur == USER_CMD_MAX_HISTORY_LINE)
498                     {
499                         p_user_cmd_if->history_cur = p_user_cmd_if->history_tail;
500                     }
501                     else
502                     {
503                         if (p_user_cmd_if->history_cur != p_user_cmd_if->history_head)
504                         {
505                             p_user_cmd_if->history_cur = (p_user_cmd_if->history_cur + USER_CMD_MAX_HISTORY_LINE - 1) %
506                                                          USER_CMD_MAX_HISTORY_LINE;
507                         }
508                         else
509                         {
510                             p_user_cmd_if->history_cur = USER_CMD_MAX_HISTORY_LINE;
511                             break;
512                         }
513                     }
514                     p_user_cmd_if->accum_cmd_len = p_user_cmd_if->cmd_history_len[p_user_cmd_if->history_cur];
515                     p_user_cmd_if->cmd_cur = p_user_cmd_if->accum_cmd_len;
516                     memcpy(p_user_cmd_if->cmdline_buf, p_user_cmd_if->cmd_history[p_user_cmd_if->history_cur],
517                            p_user_cmd_if->accum_cmd_len);
518                     data_uart_print("%s", p_user_cmd_if->cmdline_buf);
519                 }
520                 break;
521 
522             case 46:                            /* down: > */
523                 if (p_user_cmd_if->history_head != USER_CMD_MAX_HISTORY_LINE)
524                 {
525                     cmd_clear_screen(p_user_cmd_if);
526                     if (p_user_cmd_if->history_cur == USER_CMD_MAX_HISTORY_LINE)
527                     {
528                         p_user_cmd_if->history_cur = p_user_cmd_if->history_head;
529                     }
530                     else
531                     {
532                         if (p_user_cmd_if->history_cur != p_user_cmd_if->history_tail)
533                         {
534                             p_user_cmd_if->history_cur = (p_user_cmd_if->history_cur + 1) % USER_CMD_MAX_HISTORY_LINE;
535                         }
536                         else
537                         {
538                             p_user_cmd_if->history_cur = USER_CMD_MAX_HISTORY_LINE;
539                             break;
540                         }
541                     }
542                     p_user_cmd_if->accum_cmd_len = p_user_cmd_if->cmd_history_len[p_user_cmd_if->history_cur];
543                     p_user_cmd_if->cmd_cur = p_user_cmd_if->accum_cmd_len;
544                     memcpy(p_user_cmd_if->cmdline_buf, p_user_cmd_if->cmd_history[p_user_cmd_if->history_cur],
545                            p_user_cmd_if->accum_cmd_len);
546                     data_uart_print("%s", p_user_cmd_if->cmdline_buf);
547                 }
548                 break;
549 
550             case 91:                           /* left: { */
551                 if (p_user_cmd_if->cmd_cur > 0)
552                 {
553                     data_uart_print("\b");
554                     p_user_cmd_if->cmd_cur--;
555                 }
556                 break;
557 
558             case 93:                           /* right: } */
559                 if (p_user_cmd_if->cmd_cur < p_user_cmd_if->accum_cmd_len)
560                 {
561                     data_uart_print("%c", p_user_cmd_if->cmdline_buf[p_user_cmd_if->cmd_cur]);
562                     p_user_cmd_if->cmd_cur++;
563                 }
564                 break;
565 
566             case 92:                            /* end: \ */
567                 if (p_user_cmd_if->cmd_cur < p_user_cmd_if->accum_cmd_len)
568                 {
569                     data_uart_print("%s", p_user_cmd_if->cmdline_buf + p_user_cmd_if->cmd_cur);
570                     p_user_cmd_if->cmd_cur = p_user_cmd_if->accum_cmd_len;
571                 }
572                 break;
573 
574             case 47:                            /* begin: / */
575                 while (p_user_cmd_if->cmd_cur > 0)
576                 {
577                     data_uart_print("\b");
578                     p_user_cmd_if->cmd_cur--;
579                 }
580                 break;
581 
582             default:
583                 /* Put character in command buffer */
584                 if (p_user_cmd_if->accum_cmd_len < USER_CMD_MAX_COMMAND_LINE)
585                 {
586                     uint8_t loop;
587 
588                     cmd_move_back(p_user_cmd_if);
589                     p_user_cmd_if->cmdline_buf[p_user_cmd_if->cmd_cur] = c;
590                     data_uart_print("%s", p_user_cmd_if->cmdline_buf + p_user_cmd_if->cmd_cur);
591                     p_user_cmd_if->accum_cmd_len++;
592                     p_user_cmd_if->cmd_cur++;
593                     for (loop = 0; loop < p_user_cmd_if->accum_cmd_len - p_user_cmd_if->cmd_cur; loop++)
594                     {
595                         data_uart_print("\b");
596                     }
597                 }
598                 break;
599             }
600         }
601     }
602 
603     return true;
604 }
605 
606 /**
607  * @brief  Initiate command interface structure
608  * @param[in] p_user_cmd_if   Store parsed commands.
609  * @param[in] project_name    Initiate project name.
610  * @return void
611  *
612  * <b>Example usage</b>
613  * \code{.c}
614     void app_main_task(void *p_param)
615     {
616         char event;
617 
618         os_msg_queue_create(&io_queue_handle, MAX_NUMBER_OF_IO_MESSAGE, sizeof(T_IO_MSG));
619         os_msg_queue_create(&evt_queue_handle, MAX_NUMBER_OF_EVENT_MESSAGE, sizeof(unsigned char));
620 
621         gap_start_bt_stack(evt_queue_handle, io_queue_handle, MAX_NUMBER_OF_GAP_MESSAGE);
622 
623         data_uart_init(evt_queue_handle, io_queue_handle);
624         user_cmd_init(&user_cmd_if, "central");
625         ......
626     }
627  * \endcode
628  */
user_cmd_init(T_USER_CMD_IF * p_user_cmd_if,char * project_name)629 void user_cmd_init(T_USER_CMD_IF *p_user_cmd_if, char *project_name)
630 {
631     memset(p_user_cmd_if, 0, sizeof(T_USER_CMD_IF));
632     p_user_cmd_if->history_head = USER_CMD_MAX_HISTORY_LINE;
633     p_user_cmd_if->history_tail = USER_CMD_MAX_HISTORY_LINE;
634     p_user_cmd_if->history_cur  = USER_CMD_MAX_HISTORY_LINE;
635     data_uart_print(">> Command Parse Init (%s) <<\r\n", project_name);
636 }
637 
638