/* * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * o Neither the name of Freescale Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "blsh.h" #include "bllibc.h" #include "host_hardware.h" /******************************************************************************* * Definitions ******************************************************************************/ /*! @brief input buffer size */ #define k_cmdBufferSize 256 /*! @brief input History depth */ #define k_cmdHistoryDepth 16 /*! @brief max input command args */ #define k_cmdMaxArgs 16 /******************************************************************************* * Variables ******************************************************************************/ /*! @brief help command definition */ static void help_func(uint8_t argc, uint8_t **argv); static blsh_cmd_t help_cmd = { "help", "Display commands list and usage", "help", help_func, 0, 0 }; static blsh_cmd_t *root_cmd = &help_cmd; /*! @brief exit command definition */ static void exit_func(uint8_t argc, uint8_t **argv); static blsh_cmd_t exit_cmd = { "exit", "Exit the blsh", "exit", exit_func, 0, 0 }; /*! @brief blsh input buffer and index */ static uint8_t s_inputBuffer[k_cmdHistoryDepth][k_cmdBufferSize + 1] = { 0 }; static uint32_t s_curCmdIndex = 0; static uint32_t s_curBufIndex = 0; /*! @brief blsh exit flag */ static uint8_t s_blsh_exit = 0; /******************************************************************************* * Prototypes ******************************************************************************/ static void blsh_handle(uint8_t c); static void line_execute(uint8_t *line); static uint32_t command_parse(blsh_cmd_t **_cmd, uint8_t **_str); static void command_execute(blsh_cmd_t *cmd, uint8_t *str); /******************************************************************************* * Code ******************************************************************************/ void blsh_init(void) { command_add(&exit_cmd); blsh_printf("\r\n **************************************** "); blsh_printf("\r\n *** Welcome to blsh *** "); blsh_printf("\r\n **************************************** "); blsh_printf("\r\n > "); /* Start a new line */ } void blsh_run(void) { uint8_t c; if (blsh_getchar(&c)) { blsh_handle(c); } } uint8_t blsh_exit(void) { return s_blsh_exit; } void command_add(blsh_cmd_t *cmd) { blsh_cmd_t *index; if (!root_cmd) { root_cmd = cmd; } else { index = root_cmd; while (index->next) index = index->next; index->next = cmd; } } /*! * @brief handle input char * * @param c input char. */ static void blsh_handle(uint8_t c) { uint8_t *line = s_inputBuffer[s_curBufIndex]; if ((c == '\n') || (c == '\r')) /* Confirm the command */ { /* Echo */ blsh_putchar(c); while (*line && (*line == ' ')) line++; if (*line) { microseconds_init(); line_execute(line); microseconds_shutdown(); s_curBufIndex = (s_curBufIndex + 1) % k_cmdHistoryDepth; s_curCmdIndex = 0; s_inputBuffer[s_curBufIndex][0] = 0; } /* Start a new line */ if (!s_blsh_exit) blsh_printf("\r\n > "); } else if ((c == 0x08) || (c == 0x7f)) /* Backspace and delete */ { if (s_curCmdIndex > 0) { line[--s_curCmdIndex] = 0; blsh_printf("\b \b"); } } else if (c == 0x1b) /* Command turning */ { uint8_t key_value[3] = { 0 }; key_value[0] = c; key_value[1] = wait_uart_char_blocking(); key_value[2] = wait_uart_char_blocking(); if (key_value[2] == 0x41) /* Up */ { uint8_t prevLine = (s_curBufIndex + k_cmdHistoryDepth - 1) % k_cmdHistoryDepth; if (s_inputBuffer[prevLine][0]) { while (s_curCmdIndex-- > 0) blsh_printf("\b \b"); line = s_inputBuffer[prevLine]; s_curCmdIndex = strlen((char *)line); s_curBufIndex = prevLine; blsh_printf("\r > %s", line); } } else if (key_value[2] == 0x42) /* Down */ { uint8_t nextLine = (s_curBufIndex + 1) % k_cmdHistoryDepth; if (s_inputBuffer[nextLine][0]) { while (s_curCmdIndex-- > 0) blsh_printf("\b \b"); line = s_inputBuffer[nextLine]; s_curCmdIndex = strlen((char *)line); s_curBufIndex = nextLine; blsh_printf("\r > %s", line); } } else { blsh_printf("%s", key_value); } } else /* Input command */ { if (s_curCmdIndex < k_cmdBufferSize) { /* Echo */ blsh_putchar(c); line[s_curCmdIndex++] = c; line[s_curCmdIndex] = 0; } } } /*! * @brief process input line * * @param line input line. */ static void line_execute(uint8_t *line) { uint8_t *str = line; blsh_cmd_t *cmd = root_cmd; uint32_t ret = 0; while (1) { ret = command_parse(&cmd, &str); if (ret == k_match) { if (cmd) { command_execute(cmd, str); break; } } else if (ret == k_ambig) { blsh_printf("\r\n Error: Ambiguity command: %s", str); break; } else if (ret == k_unmatch) { blsh_printf("\r\n Error: Invalid command: %s", str); break; } else { break; } } } /*! * @brief parse the command line * * @param _cmd command root. * @param _str input command. */ static uint32_t command_parse(blsh_cmd_t **_cmd, uint8_t **_str) { uint8_t *str = *_str; /* uint32_t matched_len = 0; */ blsh_cmd_t *cmd; /* blsh_cmd_t *matched_cmd = 0; */ uint32_t ret = 0; /* Eliminate start blanks */ while (*str == ' ') str++; if (!*str) { *_str = str; return k_nullMatch; } for (cmd = *_cmd; cmd; cmd = cmd->next) { ret = bl_strstart(cmd->name, str); if (ret == k_fullMatch) { while (*str && (*str != ' ')) str++; while (*str == ' ') str++; *_str = str; *_cmd = cmd; return k_match; } else { } } return k_unmatch; } /*! * @brief execute the command * * @param cmd input command. * @param str input string. */ static void command_execute(blsh_cmd_t *cmd, uint8_t *str) { uint8_t temp[k_cmdBufferSize] = { 0 }; uint8_t *string = temp; uint8_t *argv[k_cmdMaxArgs]; uint8_t argc = 0; memcpy(temp, str, strlen((char *)str)); argv[argc++] = cmd->name; while (*string && (argc < k_cmdMaxArgs)) { while (*string == ' ') string++; if (*string == 0) { break; } argv[argc++] = string; while (*string && (*string != ' ')) string++; if (!*string) { break; } *string++ = 0; } if (cmd->function) { cmd->function(argc, argv); } } /*! * @brief process help command * * @param argc the count of arguments inputed to shell. * @param argv the value of arguments inputed to shell. */ static void help_func(uint8_t argc, uint8_t **argv) { blsh_cmd_t *cmd = 0; blsh_printf("\r\n Command List: \r\n "); for (cmd = root_cmd; cmd; cmd = cmd->next) { blsh_printf("%s\r\n \t\t\t %s\r\n ", cmd->usage, cmd->help); } } /*! * @brief process exit command * * @param argc the count of arguments inputed to shell. * @param argv the value of arguments inputed to shell. */ static void exit_func(uint8_t argc, uint8_t **argv) { s_blsh_exit = 1; blsh_printf("\r\n Bye \r\n"); }