Files
32343 843447835d Initial commit: TC264 smart car project with IPS200 menu system
- IPS200 display menu with real-time status and parameter settings
- Camera image processing and line tracking
- IMU attitude solution and PID control
- WiFi SPI oscilloscope data transmission
2026-05-10 21:38:49 +08:00

1336 lines
41 KiB
C

/**
* \file Ifx_Shell.c
* \brief shell functions.
*
* \version disabled
* \copyright Copyright (c) 2013 Infineon Technologies AG. All rights reserved.
*
*
* IMPORTANT NOTICE
*
*
* Use of this file is subject to the terms of use agreed between (i) you or
* the company in which ordinary course of business you are acting and (ii)
* Infineon Technologies AG or its licensees. If and as long as no such
* terms of use are agreed, use of this file is subject to following:
* Boost Software License - Version 1.0 - August 17th, 2003
* Permission is hereby granted, free of charge, to any person or
* organization obtaining a copy of the software and accompanying
* documentation covered by this license (the "Software") to use, reproduce,
* display, distribute, execute, and transmit the Software, and to prepare
* derivative works of the Software, and to permit third-parties to whom the
* Software is furnished to do so, all subject to the following:
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer, must
* be included in all copies of the Software, in whole or in part, and all
* derivative works of the Software, unless such copies or derivative works are
* solely in the form of machine-executable object code generated by a source
* language processor.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
//---------------------------------------------------------------------------
#include "Ifx_Shell.h"
#include "_Utilities/Ifx_Assert.h"
#include "Cpu/Std/IfxCpu_Intrinsics.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define IFX_SHELL_LLD "%lld "
#define IFX_SHELL_LLX "%llx "
#define IFX_SHELL_LLU "%llu "
//---------------------------------------------------------------------------
#define IFX_SHELL_MAX_MESSAGE_SIZE 255
//---------------------------------------------------------------------------
/* Macro to detect space character */
#define ISSPACE(c) (((c) == ' ') || ((c) == '\t'))
/* Macro to only execute parameter if echo is enabled for this shell */
#define IFX_SHELL_IF_ECHO(X) {if (shell->control.echo) {X; }}
/* Macro to write lots of spaces */
#define IFX_SHELL_WRITE_SPACES(X) \
{int ii; for (ii = 0; ii < (X); ii++) {IfxStdIf_DPipe_print(shell->io, " "); }}
/* Macro to write lots of backspaces */
#define IFX_SHELL_WRITE_BACKSPACES(X) \
{int ii; for (ii = 0; ii < (X); ii++) {IfxStdIf_DPipe_print(shell->io, "\b"); }}
//---------------------------------------------------------------------------
char Ifx_Shell_cmdBuffer[IFX_CFG_SHELL_CMD_LINE_SIZE * IFX_CFG_SHELL_CMD_HISTORY_SIZE];
//---------------------------------------------------------------------------
void Ifx_Shell_execute(Ifx_Shell *shell, pchar commandLine);
void Ifx_Shell_cmdEscapeProcess(Ifx_Shell *shell, char EscapeChar1, char EscapeChar2);
const Ifx_Shell_Command *Ifx_Shell_commandListFind(Ifx_Shell *shell, pchar commandLine, pchar *args, Ifx_Shell_CommandListConst *commandList);
static boolean Ifx_Shell_matchCommand(pchar *argsPtr, pchar *match);
//---------------------------------------------------------------------------
/**
* \brief Check whether the args is already at the end.
* \param args The argument null-terminated string
*/
boolean Ifx_Shell_isEndOfLine(pchar args)
{
return ((args == NULL_PTR) || (*args == IFX_SHELL_NULL_CHAR)) ? TRUE : FALSE;
}
static boolean Ifx_Shell_writeResult(Ifx_Shell *shell, Ifx_SizeT Code)
{
Ifx_SizeT length = sizeof(Code);
boolean result = IfxStdIf_DPipe_write(shell->io, &Code, &length, TIME_INFINITE);
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, result != FALSE);
return result;
}
//---------------------------------------------------------------------------
boolean Ifx_Shell_showHelpSingle(Ifx_Shell_CommandListConst commandList, IfxStdIf_DPipe *io, boolean briefOnly, boolean singleCommand)
{
const Ifx_Shell_Command *command = commandList;
uint32 index = 0;
pchar space = "";
pchar spaceParam = "";
while (command->commandLine != NULL_PTR)
{
pchar help = command->help;
pchar chunk;
boolean isParam = FALSE;
boolean isSyntax = FALSE;
IfxStdIf_DPipe_print(io, "%s%s", space, command->commandLine);
while (*help != IFX_SHELL_NULL_CHAR)
{
Ifx_SizeT count;
pchar matchp = "/p";
pchar matchs = "/s";
spaceParam = "";
if (Ifx_Shell_matchCommand(&help, &matchp))
{ /* Parameter description found */
isParam = TRUE;
isSyntax = FALSE,
spaceParam = " ";
}
else if (Ifx_Shell_matchCommand(&help, &matchs))
{ /* Parameter description found */
isParam = FALSE;
isSyntax = TRUE,
spaceParam = " SYNTAX: ";
}
else
{ /* Other text */
if (isParam)
{ /* Show param details*/
spaceParam = " ";
}
else if (isSyntax)
{ /* Show param details*/
spaceParam = " ";
}
}
/* Split print by ENDL */
chunk = strstr(help, ENDL);
if (chunk == NULL_PTR)
{
chunk = help + strlen(help);
}
else
{
if (!briefOnly)
{
chunk += strlen(ENDL);
}
}
count = chunk - help;
IfxStdIf_DPipe_print(io, "%s%s", space, spaceParam);
IfxStdIf_DPipe_write(io, (void *)help, &count, TIME_INFINITE);
help += count;
if (briefOnly)
{ /* Print Brief only */
break;
}
}
IfxStdIf_DPipe_print(io, ENDL);
if ((command->call == NULL_PTR) && (index == 0))
{
index = 1;
space = " ";
}
command = &command[1];
if (singleCommand)
{
break;
}
}
return TRUE;
}
boolean Ifx_Shell_showHelpSingleCommand(pchar args, void *shellPtr, IfxStdIf_DPipe *io)
{
Ifx_Shell_CommandListConst commandList;
const Ifx_Shell_Command *shellCommand = Ifx_Shell_commandListFind(shellPtr, args, &args, &commandList);
if (shellCommand != NULL_PTR)
{
if (shellCommand->call == NULL_PTR)
{
Ifx_Shell_showHelpSingle(commandList, io, FALSE, FALSE);
}
else
{
if (commandList->call == NULL_PTR)
{
IfxStdIf_DPipe_print(io, "%s ", commandList->commandLine);
}
Ifx_Shell_showHelpSingle(shellCommand, io, FALSE, TRUE);
}
return TRUE;
}
else
{
IfxStdIf_DPipe_print(io, "unknown command");
return FALSE;
}
}
boolean Ifx_Shell_showHelp(pchar args, void *shellPtr, IfxStdIf_DPipe *io)
{
sint32 i;
Ifx_Shell *shell = shellPtr;
boolean result = TRUE;
if (*args == IFX_SHELL_NULL_CHAR)
{
for (i = 0; i < IFX_CFG_SHELL_COMMAND_LISTS; i++)
{
if (shell->commandList[i] != NULL_PTR)
{
Ifx_Shell_showHelpSingle(shell->commandList[i], io, TRUE, FALSE);
}
}
}
else
{
result = Ifx_Shell_showHelpSingleCommand(args, shellPtr, io);
}
return result;
}
boolean Ifx_Shell_protocolStart(pchar args, void *data, IfxStdIf_DPipe *io)
{
Ifx_Shell *shell = data;
boolean Result = TRUE;
if (Ifx_Shell_matchToken(&args, "?") != FALSE)
{
IfxStdIf_DPipe_print(io, "Syntax : protocol start" ENDL);
IfxStdIf_DPipe_print(io, " > start a protocol" ENDL);
}
else if (Ifx_Shell_matchToken(&args, "start") != FALSE)
{
if ((shell->protocol.start != NULL_PTR) && (shell->protocol.object != NULL_PTR))
{
Result = shell->protocol.start(shell->protocol.object, io);
shell->protocol.started = (Result != FALSE);
if (shell->protocol.onStart != NULL_PTR)
{
shell->protocol.onStart(shell->protocol.object, shell->protocol.onStartData);
}
}
else
{
Result = FALSE;
}
}
else
{}
return Result;
}
boolean Ifx_Shell_bbProtocolStart(pchar args, void *data, IfxStdIf_DPipe *io)
{
boolean result = TRUE;
if (Ifx_Shell_matchToken(&args, "?") != FALSE)
{
IfxStdIf_DPipe_print(io, "Syntax : protocol start" ENDL);
IfxStdIf_DPipe_print(io, " > start a protocol" ENDL);
}
else if (Ifx_Shell_matchToken(&args, "protocol") != FALSE)
{
result = Ifx_Shell_protocolStart(args, data, io);
}
else
{}
return result;
}
//---------------------------------------------------------------------------
void Ifx_Shell_initConfig(Ifx_Shell_Config *config)
{
uint32 i;
for (i = 0; i < IFX_CFG_SHELL_COMMAND_LISTS; i++)
{
config->commandList[i] = NULL_PTR;
}
config->standardIo = NULL_PTR;
config->echo = TRUE;
config->protocol.execute = NULL_PTR;
config->protocol.object = NULL_PTR;
config->protocol.onStart = NULL_PTR;
config->protocol.onStartData = NULL_PTR;
config->protocol.start = NULL_PTR;
config->protocol.started = FALSE;
config->sendResultCode = FALSE;
config->showPrompt = TRUE;
config->standardIo = NULL_PTR;
}
boolean Ifx_Shell_init(Ifx_Shell *shell, const Ifx_Shell_Config *config)
{
sint32 i;
char **CmdHistory = NULL_PTR; /* Pointer to array of pointers for command history items */
/* Ensure state variable is cleared */
memset(shell, 0, sizeof(*shell));
shell->protocol = config->protocol;
shell->protocol.started = FALSE;
shell->io = config->standardIo;
shell->control.showPrompt = config->showPrompt;
shell->control.sendResultCode = config->sendResultCode;
shell->control.echo = config->echo;
shell->control.echoError = TRUE;
shell->control.enabled = TRUE;
shell->locals.escBracketNum = IFX_SHELL_NULL_CHAR; /* Used to cache number in sequence "ESC [ 1/2/3/4 ~" */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_NORMAL;
/* Copy command line buffer pointer into state variable */
shell->cmd.cmdStr = shell->locals.cmdStr;
/* Initialize command history space and cache pointer */
memset(Ifx_Shell_cmdBuffer, 0, sizeof(Ifx_Shell_cmdBuffer));
shell->cmdHistory[0] = &Ifx_Shell_cmdBuffer[0];
for (i = 0; i < IFX_CFG_SHELL_COMMAND_LISTS; i++)
{
shell->commandList[i] = config->commandList[i];
}
/* Initialize command history pointers */
CmdHistory = shell->cmdHistory;
for (i = 1; i < IFX_CFG_SHELL_CMD_HISTORY_SIZE; i++)
{
CmdHistory[i] = &CmdHistory[i - 1][IFX_CFG_SHELL_CMD_LINE_SIZE]; /* Items are just offsets into a large allocated area */
}
shell->cmd.historyItem = IFX_SHELL_CMD_HISTORY_NO_ITEM;
/* Pre-load useful commands into history buffer */
strcpy(CmdHistory[0], "help");
//strcpy(CmdHistory[1], "protocol start");
if (shell->control.showPrompt != 0)
{
IfxStdIf_DPipe_print(shell->io, ENDL);
IfxStdIf_DPipe_print(shell->io, IFX_CFG_SHELL_PROMPT);
}
return TRUE;
}
void Ifx_Shell_process(Ifx_Shell *shell)
{
Ifx_SizeT i, j; /* Loop variables */
Ifx_SizeT count;
Ifx_SizeT readCount;
boolean NormalKeyPress; /* Indicates if this is a normal keypress, i.e. not part of an escape code */
Ifx_Shell_CmdLine *Cmd = &shell->cmd;
char *inputbuffer = shell->locals.inputbuffer;
char *cmdStr = shell->locals.cmdStr;
char **CmdHistory = shell->cmdHistory;
if (shell->control.enabled == 0)
{
return;
}
if ((shell->protocol.object != NULL_PTR) && (shell->protocol.started != FALSE))
{
shell->protocol.execute(shell->protocol.object);
}
else
{
/**** NORMAL MODE ****/
/********************************************************************************/
/* Read all characters until enter inclusive. */
/* If the command is bigger than IFX_SHELL_CMD_SIZE, the command is ignored. */
/* */
/* Escape sequences are handled by a state machine. */
/* The following escape sequences (prefix "ESC [") are supported: */
/* */
/* A - up B - down C - right D - left */
/* 1~ - HOME 2~ - INSERT 3~ - DELETE 5~ - END */
/* */
/* Backspace ('\b') is also supported. */
/********************************************************************************/
count = 0;
readCount = IFX_CFG_SHELL_CMD_LINE_SIZE - count;
IfxStdIf_DPipe_read(shell->io, &inputbuffer[count], &readCount, TIME_NULL);
count += readCount;
for (i = 0; i < count; i++)
{
/* By default, we assume character is part of escape sequence */
NormalKeyPress = FALSE;
/* Process key pressed */
switch (inputbuffer[i])
{
/* New line (ENTER) */
case '\n':
case '\r':
/* Print new line to terminal if requested */
IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, ENDL))
/* Execute command if length is valid - i.e. not an over-full buffer
* (prevents attempted execution of junk) */
if (Cmd->length < IFX_CFG_SHELL_CMD_LINE_SIZE)
{
cmdStr[Cmd->length] = IFX_SHELL_NULL_CHAR; /* Terminate cmdStr */
if (Cmd->historyAdd != FALSE)
{
/* Shuffle history up */
for (j = IFX_CFG_SHELL_CMD_HISTORY_SIZE - 1; j > 0; j--)
{
/* Copy text */
strncpy(CmdHistory[j], CmdHistory[j - 1], IFX_CFG_SHELL_CMD_LINE_SIZE);
}
/* Copy in new entry */
strncpy(CmdHistory[0], cmdStr, IFX_CFG_SHELL_CMD_LINE_SIZE);
}
/* Execute command */
Ifx_Shell_execute(shell, cmdStr);
}
/* Show prompt if in main shell */
if (shell->control.showPrompt != 0)
{
IfxStdIf_DPipe_print(shell->io, IFX_CFG_SHELL_PROMPT);
}
/* Reset command line buffer length */
Cmd->length = 0;
/* Reset command line buffer cursor position */
Cmd->cursor = 0;
/* Clear flag */
Cmd->historyAdd = FALSE;
/* Ensure we're not in command history list */
Cmd->historyItem = IFX_SHELL_CMD_HISTORY_NO_ITEM;
break;
/* Backspace (may occur in middle of text if cursor location is not at end) */
case '\b':
if (Cmd->cursor > 0)
{
/* Update on screen */
if (shell->control.echo != 0)
{
/* Move left one character */
IfxStdIf_DPipe_print(shell->io, "\b");
/* Update line with new characters */
for (j = Cmd->cursor; j < Cmd->length; j++)
{
IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[j]);
}
/* Write over duplicated character at end */
IfxStdIf_DPipe_print(shell->io, " ");
IFX_SHELL_WRITE_BACKSPACES((Cmd->length - Cmd->cursor) + 1)
}
/* Update in command line variable. Shuffle text left */
strncpy(&cmdStr[Cmd->cursor - 1], &cmdStr[Cmd->cursor], Cmd->length - Cmd->cursor);
/* Terminate string at end of shorter string */
cmdStr[Cmd->length - 1] = IFX_SHELL_NULL_CHAR;
Cmd->length--;
Cmd->cursor--;
/* Command line has been modified */
Cmd->historyAdd = TRUE;
}
break;
/* Escape character */
case '\x1B': /*'\x1B': */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_ESCAPE;
break;
/* '[' - check to see if this is second part of an escape sequence */
case '[':
if (shell->locals.cmdState == IFX_SHELL_CMD_STATE_ESCAPE)
{
/* ESC [ pressed */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_ESCAPE_BRACKET;
}
else
{
NormalKeyPress = TRUE;
}
break;
/* Check for supported characters in escape sequences ( ESC [ A/B/C/D ) */
case 'A':
case 'B':
case 'C':
case 'D':
if (shell->locals.cmdState == IFX_SHELL_CMD_STATE_ESCAPE_BRACKET)
{
/* Process arrow keys */
Ifx_Shell_cmdEscapeProcess(shell, inputbuffer[i], 0);
/* End of escape sequence */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_NORMAL;
}
else
{
NormalKeyPress = TRUE;
}
break;
/* Check for supported characters in escape sequences (ESC [ 2/4/5 ~) */
case '1':
case '2':
case '3':
case '4':
if (shell->locals.cmdState == IFX_SHELL_CMD_STATE_ESCAPE_BRACKET)
{
/* Store number for use once complete escape sequence is confirmed (below) */
shell->locals.escBracketNum = inputbuffer[i];
shell->locals.cmdState = IFX_SHELL_CMD_STATE_ESCAPE_BRACKET_NUMBER;
}
else
{
NormalKeyPress = TRUE;
}
break;
/* Check for supported characters in escape sequences (ESC [ 2/4/5 ~) */
case '~':
if (shell->locals.cmdState == IFX_SHELL_CMD_STATE_ESCAPE_BRACKET_NUMBER)
{
/* Process home/delete/end */
Ifx_Shell_cmdEscapeProcess(shell, shell->locals.escBracketNum, '~');
/* End of escape sequence */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_NORMAL;
}
else
{
NormalKeyPress = TRUE;
}
break;
/* Normal character - add to command string */
default:
NormalKeyPress = TRUE;
break;
}
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, Cmd->length >= Cmd->cursor); /* Sanity check */
/* If this was a normal key press (not part of an escape sequence),
* add it to the command string */
if (NormalKeyPress != FALSE)
{
/* Ensure state machine is reset */
shell->locals.cmdState = IFX_SHELL_CMD_STATE_NORMAL;
/* If not filled buffer, add in this character */
if (Cmd->length < (IFX_CFG_SHELL_CMD_LINE_SIZE - 1))
{
/* Command line has been modified */
Cmd->historyAdd = TRUE;
/* Copy into command line */
cmdStr[Cmd->cursor] = inputbuffer[i];
Cmd->cursor++;
/* Update length of buffer */
Cmd->length = __max(Cmd->length, Cmd->cursor);
if (shell->control.echo != 0)
{
/* echo character to shell output if requested */
shell->locals.echo[0] = inputbuffer[i];
IfxStdIf_DPipe_print(shell->io, shell->locals.echo);
}
}
else
{
/* Line too long - ignore further characters */
Cmd->historyAdd = FALSE; /* Invalid command line */
}
}
}
}
}
void Ifx_Shell_deinit(Ifx_Shell *shell)
{
(void)shell; /* ignore compiler warning; */
// tbd free necessary memory
}
pchar Ifx_Shell_skipWhitespace(pchar args)
{
if (args != NULL_PTR)
{
while ((*args != IFX_SHELL_NULL_CHAR) && (ISSPACE(*args)))
{
args = &args[1];
}
}
return args;
}
boolean Ifx_Shell_matchToken(pchar *argsPtr, pchar token)
{
pchar savedArguments = *argsPtr;
char buffer[256];
boolean result = FALSE;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) != FALSE)
{
if (strcmp(token, buffer) == 0)
{
result = TRUE;
}
}
if (result == FALSE)
{
// No match: don't advance pointer
*argsPtr = savedArguments;
}
return result;
}
static boolean Ifx_Shell_matchCommand(pchar *argsPtr, pchar *match)
{
boolean result = FALSE;
pchar savedArguments = *argsPtr;
pchar savedMatch = *match;
char buffer0[256];
char buffer1[256];
if ((Ifx_Shell_parseToken(argsPtr, buffer0, Ifx_COUNTOF(buffer0)) != FALSE)
&& (Ifx_Shell_parseToken(match, buffer1, Ifx_COUNTOF(buffer1)) != FALSE))
{
if (strcmp(buffer1, buffer0) == 0)
{
result = TRUE;
}
}
if (result == FALSE)
{
// No match: don't advance pointer
*argsPtr = savedArguments;
*match = savedMatch;
}
return result;
}
boolean Ifx_Shell_parseToken(pchar *argsPtr, char *tokenBuffer, int bufferLength)
{
int mindex = 0;
pchar args = Ifx_Shell_skipWhitespace(*argsPtr);
tokenBuffer[0] = IFX_SHELL_NULL_CHAR;
if (args == NULL_PTR)
{
return FALSE;
}
if (*args == '\"')
{
args = &args[1];
while ((*args != IFX_SHELL_NULL_CHAR) && (*args != '\"'))
{
if (mindex < bufferLength)
{
tokenBuffer[mindex] = *args;
mindex++;
}
args = &args[1];
}
// error if no closing quote
if (*args != '\"')
{
return FALSE;
}
args = &args[1];
}
else
{
// don't allow unquoted empty tokens
if (*args == IFX_SHELL_NULL_CHAR)
{
return FALSE;
}
while ((*args != IFX_SHELL_NULL_CHAR) && (!ISSPACE(*args)))
{
if (mindex < bufferLength)
{
tokenBuffer[mindex] = *args;
mindex++;
}
args = &args[1];
}
}
// make sure string is zero terminated
if (bufferLength > 0)
{
tokenBuffer[__min(mindex, bufferLength - 1)] = IFX_SHELL_NULL_CHAR;
}
*argsPtr = Ifx_Shell_skipWhitespace(args);
return TRUE;
}
boolean Ifx_Shell_parseAddress(pchar *argsPtr, void **address)
{
char buffer[32];
boolean result;
*address = 0;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
{
result = FALSE;
}
else
{
result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%x ", (unsigned int *)address) == 1);
}
return result;
}
boolean Ifx_Shell_parseSInt32(pchar *argsPtr, sint32 *value)
{
sint64 value64;
boolean result;
*value = 0;
if (Ifx_Shell_parseSInt64(argsPtr, &value64) == FALSE)
{
result = FALSE;
}
else
{
*value = (sint32)value64;
result = TRUE;
}
return result;
}
boolean Ifx_Shell_parseUInt32(pchar *argsPtr, uint32 *value, boolean hex)
{
uint64 value64;
boolean result;
*value = 0;
if (Ifx_Shell_parseUInt64(argsPtr, &value64, hex) == FALSE)
{
result = FALSE;
}
else
{
*value = (uint32)value64;
result = TRUE;
}
return result;
}
boolean Ifx_Shell_parseSInt64(pchar *argsPtr, sint64 *value)
{
char buffer[64];
boolean result;
*value = 0;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
{
result = FALSE;
}
else
{
result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, IFX_SHELL_LLD, value) == 1);
}
return result;
}
boolean Ifx_Shell_parseUInt64(pchar *argsPtr, uint64 *value, boolean hex)
{
char buffer[64];
boolean result;
*value = 0;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
{
result = FALSE;
}
else
{
char *bufferPointer = buffer;
if ((buffer[0] == '0') && (buffer[1] == 'x'))
{
bufferPointer = &bufferPointer[2];
hex = TRUE;
}
if (hex != FALSE)
{
result = (bufferPointer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(bufferPointer, IFX_SHELL_LLX, value) == 1);
}
else
{
result = (bufferPointer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(bufferPointer, IFX_SHELL_LLU, value) == 1);
}
}
return result;
}
boolean Ifx_Shell_parseFloat64(pchar *argsPtr, float64 *value)
{
char buffer[64];
boolean result;
*value = 0;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
{
result = FALSE;
}
else
{
result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%lf ", value) == 1);
}
return result;
}
boolean Ifx_Shell_parseFloat32(pchar *argsPtr, float32 *value)
{
char buffer[64];
boolean result;
*value = 0;
if (Ifx_Shell_parseToken(argsPtr, buffer, Ifx_COUNTOF(buffer)) == FALSE)
{
result = FALSE;
}
else
{
result = (buffer[0] != IFX_SHELL_NULL_CHAR) && (sscanf(buffer, "%f ", value) == 1);
}
return result;
}
const Ifx_Shell_Command *Ifx_Shell_commandFind(Ifx_Shell_CommandListConst commandList, pchar commandLine, pchar *args, uint32 *match)
{
const Ifx_Shell_Command *command = commandList;
const Ifx_Shell_Command *result = NULL_PTR;
pchar cmdLineTemp = commandLine;
uint32 matchInit = 0;
uint32 index = 0;
boolean hasPrefix;
hasPrefix = (command->commandLine != NULL_PTR) && (command->call == NULL_PTR);
*match = 0;
while (command->commandLine != NULL_PTR)
{
pchar commandTemp = command->commandLine;
pchar commandLineTemp = cmdLineTemp;
char buffer[256];
uint32 matchCount = matchInit;
while (Ifx_Shell_matchCommand(&commandLineTemp, &commandTemp) != FALSE)
{
matchCount++;
}
if ((matchCount > *match) && (Ifx_Shell_parseToken(&commandTemp, buffer, Ifx_COUNTOF(buffer)) == FALSE))
{
if ((index == 0) && (command->call == NULL_PTR))
{ /* List has a prefix */
cmdLineTemp = commandLineTemp;
matchInit = matchCount;
}
*match = matchCount;
*args = commandLineTemp;
result = command;
}
else
{
if ((index == 0) && hasPrefix)
{
/* Prefix does not match */
break;
}
}
command = &command[1];
index++;
}
return result;
}
const Ifx_Shell_Command *Ifx_Shell_commandListFind(Ifx_Shell *shell, pchar commandLine, pchar *args, Ifx_Shell_CommandListConst *commandList)
{
int i;
const Ifx_Shell_Command *shellCommand = NULL_PTR;
const Ifx_Shell_Command *Command = NULL_PTR;
uint32 matchMax = 0;
uint32 match;
for (i = 0; i < IFX_CFG_SHELL_COMMAND_LISTS; i++)
{
if (shell->commandList[i] != NULL_PTR)
{
shellCommand = Ifx_Shell_commandFind(shell->commandList[i], commandLine, args, &match);
if ((shellCommand != NULL_PTR) && (match > matchMax))
{
matchMax = match;
Command = shellCommand;
*commandList = shell->commandList[i];
}
}
}
return Command;
}
void Ifx_Shell_execute(Ifx_Shell *shell, pchar commandLine)
{
pchar args = NULL_PTR;
Ifx_Shell_CommandListConst commandList;
const Ifx_Shell_Command *shellCommand = Ifx_Shell_commandListFind(shell, commandLine, &args, &commandList);
if (shellCommand != NULL_PTR)
{
if (shellCommand->call == NULL_PTR)
{
Ifx_Shell_showHelp(commandLine, shell, shell->io);
}
else if (shellCommand->call(args, shellCommand->data, shell->io) != FALSE)
{
if (shell->control.sendResultCode != 0)
{
Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_ok);
}
}
else
{
if (shell->control.sendResultCode != 0)
{
Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_nok);
}
else if (shell->control.echoError != 0)
{
IfxStdIf_DPipe_print(shell->io, "\r\nShell command error: %s" ENDL, commandLine);
}
else
{}
}
}
else
{
if (commandLine[0] != IFX_SHELL_NULL_CHAR)
{
if (shell->control.sendResultCode != 0)
{
Ifx_Shell_writeResult(shell, Ifx_Shell_ResultCode_unknown);
}
else if (shell->control.echoError != 0)
{
IfxStdIf_DPipe_print(shell->io, "\r\nUnknown command: %s" ENDL, commandLine);
}
else
{}
}
}
}
/****************************************************************************************/
/* Processes escape sequences, including handling command history. */
/* The following escape sequences (prefix "ESC [") are supported: */
/* A - up B - down C - right D - left */
/* 1~ - HOME 2~ - INSERT 3~ - DELETE 4~ - END */
/* */
/* Parameters: */
/* EscapeChar1 - First character to follow ESC [ */
/* EscapeChar2 - Second character following ESC [ , if applicable */
/* */
/****************************************************************************************/
void Ifx_Shell_cmdEscapeProcess(Ifx_Shell *shell, char EscapeChar1, char EscapeChar2)
{
Ifx_Shell_CmdLine *Cmd = NULL_PTR; /* Command line editing state */
char *cmdStr = NULL_PTR; /* Cached pointer to command line being edited */
sint32 i = 0; /* Loop variable */
/* Validate parameters */
boolean result = (shell != NULL_PTR);
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, result != FALSE);
if (result == FALSE)
{
return; /* ERROR CASE - no thread data available! */
}
/* Cache command state and command line pointer */
Cmd = &shell->cmd;
cmdStr = Cmd->cmdStr;
/* Validate command line state */
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, cmdStr != NULL_PTR);
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, Cmd->cursor < IFX_CFG_SHELL_CMD_LINE_SIZE);
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, Cmd->length < IFX_CFG_SHELL_CMD_LINE_SIZE);
/* Switch on first character after ESC [ */
switch (EscapeChar1)
{
case 'A': /* Up arrow */
if (Cmd->historyItem == IFX_SHELL_CMD_HISTORY_NO_ITEM)
{
/* Not using list at the moment - take most recent item [0] */
Cmd->historyItem = 0;
}
else
{
if (Cmd->historyItem < (IFX_CFG_SHELL_CMD_HISTORY_SIZE - 1))
{
/* If not already at oldest, go back one in list */
Cmd->historyItem++;
}
}
/* Copy text into buffer */
strncpy(cmdStr, shell->cmdHistory[Cmd->historyItem], IFX_CFG_SHELL_CMD_LINE_SIZE);
/* echo to screen if requested */
if (shell->control.echo != 0)
{
IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
IfxStdIf_DPipe_print(shell->io, cmdStr); /* Copy buffer to screen */
}
Cmd->cursor = (Ifx_SizeT)strlen(cmdStr); /* Store cursor position */
Cmd->length = Cmd->cursor; /* Store command line length */
Cmd->historyAdd = FALSE; /* Don't add back to history unless modified */
break;
case 'B': /* Down arrow */
if ((Cmd->historyItem == IFX_SHELL_CMD_HISTORY_NO_ITEM) || (Cmd->historyItem == 0))
{
/* Not using list at the moment, or have dropped off the end - just clear command line */
if (shell->control.echo != 0)
{
IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
}
Cmd->length = 0; /* Reset command line length */
Cmd->cursor = 0;
Cmd->historyItem = IFX_SHELL_CMD_HISTORY_NO_ITEM; /* Ensure we are not using list */
}
else
{
/* Within list - move to more recent entry */
Cmd->historyItem--;
/* Copy text into buffer */
strncpy(cmdStr, shell->cmdHistory[Cmd->historyItem], IFX_CFG_SHELL_CMD_LINE_SIZE);
if (shell->control.echo != 0)
{
IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) /* Move cursor back to start */
IFX_SHELL_WRITE_SPACES(Cmd->length) /* Overwrite text with spaces */
IFX_SHELL_WRITE_BACKSPACES(Cmd->length) /* Move cursor back to start */
IfxStdIf_DPipe_print(shell->io, cmdStr); /* Copy buffer to screen */
}
Cmd->cursor = (Ifx_SizeT)strlen(cmdStr); /* Store cursor position */
Cmd->length = Cmd->cursor; /* Store command line length */
}
Cmd->historyAdd = FALSE;
break;
case 'C': /* Right arrow */
if (Cmd->cursor < Cmd->length)
{
/* Move cursor one place to right */
IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[Cmd->cursor])) Cmd->cursor++;
}
break;
case 'D': /* Left arrow */
if (Cmd->cursor > 0)
{
/* Move cursor one place to left */
IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "\b")) Cmd->cursor--;
}
break;
default:
break;
}
/* If second character after ESC [ is ~ then switch on number */
if (EscapeChar2 == '~')
{
switch (EscapeChar1)
{
case '1': /* HOME - move to start of buffer */
if (Cmd->cursor > 0)
{
IFX_SHELL_WRITE_BACKSPACES(Cmd->cursor) Cmd->cursor = 0;
}
break;
case '2': /* INSERT - insert blank character at cursor and move all remaining characters right one */
if ((Cmd->cursor < Cmd->length) && (Cmd->length < (IFX_CFG_SHELL_CMD_LINE_SIZE - 1)))
{
/* Update on screen */
if (shell->control.echo != FALSE)
{
/* write over duplicated character at cursor */
IfxStdIf_DPipe_print(shell->io, " ");
/* Update line with new characters */
for (i = Cmd->cursor; i < Cmd->length; i++)
{
IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[i]);
}
/* Move cursor back to new place */
IFX_SHELL_WRITE_BACKSPACES((Cmd->length + 1) - Cmd->cursor)
}
/* Update in command line variable */
for (i = Cmd->length; i > Cmd->cursor; i--)
{
cmdStr[i] = cmdStr[i - 1]; /* Shuffle text right */
}
cmdStr[Cmd->length + 1] = IFX_SHELL_NULL_CHAR; /* Terminate string at end of longer string */
cmdStr[Cmd->cursor] = ' '; /* Blank character at cursor */
Cmd->length++; /* Now one character longer */
}
break;
case '3': /* DELETE - delete character to right and move all remaining characters left one */
if (Cmd->cursor < Cmd->length)
{
/* Update on screen */
if (shell->control.echo != 0)
{
for (i = Cmd->cursor; i < (Cmd->length - 1); i++)
{
/* Update line with new characters */
IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[i + 1]);
}
/* write over duplicated character at end */
IfxStdIf_DPipe_print(shell->io, " ");
/* Move cursor back to right place */
IFX_SHELL_WRITE_BACKSPACES(Cmd->length - Cmd->cursor)
}
/* Update in command line variable. Shuffle text left */
strncpy(&cmdStr[Cmd->cursor], &cmdStr[Cmd->cursor + 1], Cmd->length - Cmd->cursor - 1);
cmdStr[Cmd->length - 1] = IFX_SHELL_NULL_CHAR; /* Terminate string at end of shorter string */
Cmd->length--; /* Now one character shorter */
}
break;
case '4': /* END - ensure cursor is at end */
while (Cmd->cursor < Cmd->length)
{
IFX_SHELL_IF_ECHO(IfxStdIf_DPipe_print(shell->io, "%c", cmdStr[Cmd->cursor])) Cmd->cursor++;
}
break;
default:
break;
}
}
}
void Ifx_Shell_enable(Ifx_Shell *shell)
{
// Clear the Rx buffer!
IfxStdIf_DPipe_clearRx(shell->io);
// Enable the shell
shell->control.enabled = 1;
}
void Ifx_Shell_disable(Ifx_Shell *shell)
{
shell->control.enabled = 0;
}
void Ifx_Shell_printSyntax(const Ifx_Shell_Syntax *syntaxList, IfxStdIf_DPipe *io)
{
const Ifx_Shell_Syntax *syntax = syntaxList;
while (syntax->syntax != NULL_PTR)
{
IfxStdIf_DPipe_print(io, "Syntax : %s" ENDL, syntax->syntax);
IfxStdIf_DPipe_print(io, " > %s" ENDL, syntax->description);
syntax = &syntax[1];
}
}