Files
bootloader/src/blsh/blsh.c
László Monda e6c1fce5b4 Add KBOOT.
2016-08-10 01:45:15 +02:00

365 lines
9.8 KiB
C

/*
* 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");
}