Files
MSE-SoftwEng/pico-sensor/McuLib/src/McuShell.c
2025-05-06 13:07:01 +00:00

1631 lines
61 KiB
C

/* ###################################################################
** This component module is generated by Processor Expert. Do not modify it.
** Filename : McuShell.h
** Project : FRDM-K64F_Generator
** Processor : MK64FN1M0VLL12
** Component : Shell
** Version : Component 01.115, Driver 01.00, CPU db: 3.00.000
** Compiler : GNU C Compiler
** Date/Time : 2025-01-16, 10:11, # CodeGen: 850
** Abstract :
** Module implementing a command line shell.
** Settings :
** Component name : McuShell
** Echo : no
** Prompt : "CMD> "
** Project Name : My Project Name
** Silent Mode Prefix : #
** Buffer Size : 48
** Blocking Send : Enabled
** Wait : McuWait
** Timeout (ms) : 20
** Wait Time (ms) : 5
** RTOS Wait : yes
** Status Colon Pos : 13
** Help Semicolon Pos : 26
** Multi Command : Disabled
** Utility : McuUtility
** Default Serial : Disabled
** Semaphore : no
** Critical Section : McuCriticalSection
** History : no
** Kinetis SDK : McuLib
** Contents :
** PrintPrompt - void McuShell_PrintPrompt(McuShell_ConstStdIOType *io);
** SendNum8u - void McuShell_SendNum8u(uint8_t val, McuShell_StdIO_OutErr_FctType io);
** SendNum8s - void McuShell_SendNum8s(int8_t val, McuShell_StdIO_OutErr_FctType io);
** SendNum16u - void McuShell_SendNum16u(uint16_t val, McuShell_StdIO_OutErr_FctType io);
** SendNum16s - void McuShell_SendNum16s(int16_t val, McuShell_StdIO_OutErr_FctType io);
** SendNum32u - void McuShell_SendNum32u(uint32_t val, McuShell_StdIO_OutErr_FctType io);
** SendNum32s - void McuShell_SendNum32s(int32_t val, McuShell_StdIO_OutErr_FctType io);
** SendCh - void McuShell_SendCh(uint8_t ch, McuShell_StdIO_OutErr_FctType io);
** SendStr - void McuShell_SendStr(const uint8_t *str, McuShell_StdIO_OutErr_FctType io);
** PrintMemory - uint8_t McuShell_PrintMemory(void *hndl, uint32_t startAddr, uint32_t...
** printfIO - unsigned McuShell_printfIO(McuShell_ConstStdIOType *io, const char *fmt, ...);
** printf - unsigned McuShell_printf(const char *fmt, ...);
** SendData - void McuShell_SendData(const uint8_t *data, uint16_t dataSize,...
** PrintStatus - uint8_t McuShell_PrintStatus(McuShell_ConstStdIOType *io);
** ParseCommand - uint8_t McuShell_ParseCommand(const uint8_t *cmd, bool *handled,...
** IsHistoryCharacter - bool McuShell_IsHistoryCharacter(uint8_t ch, uint8_t *cmdBuf, size_t...
** ProcessConsoleInput - int McuShell_ProcessConsoleInput(char *buf, size_t bufSize);
** ReadLine - bool McuShell_ReadLine(uint8_t *bufStart, uint8_t *buf, size_t bufSize,...
** PrintCommandFailed - void McuShell_PrintCommandFailed(const uint8_t *cmd, McuShell_ConstStdIOType...
** IterateTable - uint8_t McuShell_IterateTable(const uint8_t *cmd, bool *handled,...
** SetStdio - uint8_t McuShell_SetStdio(McuShell_ConstStdIOTypePtr stdio);
** GetStdio - McuShell_ConstStdIOTypePtr McuShell_GetStdio(void);
** RequestSerial - void McuShell_RequestSerial(void);
** ReleaseSerial - void McuShell_ReleaseSerial(void);
** ReadAndParseWithCommandTableExt - uint8_t McuShell_ReadAndParseWithCommandTableExt(uint8_t *cmdBuf, size_t...
** ReadCommandLine - uint8_t McuShell_ReadCommandLine(uint8_t *cmdBuf, size_t cmdBufSize,...
** ReadAndParseWithCommandTable - uint8_t McuShell_ReadAndParseWithCommandTable(uint8_t *cmdBuf, size_t...
** ParseWithCommandTableExt - uint8_t McuShell_ParseWithCommandTableExt(const uint8_t *cmd,...
** ParseWithCommandTable - uint8_t McuShell_ParseWithCommandTable(const uint8_t *cmd,...
** GetSemaphore - void* McuShell_GetSemaphore(void);
** SendStatusStr - void McuShell_SendStatusStr(const uint8_t *strItem, const uint8_t *strStatus,...
** SendHelpStr - void McuShell_SendHelpStr(const uint8_t *strCmd, const uint8_t *strHelp,...
** ReadChar - void McuShell_ReadChar(uint8_t *c);
** SendChar - void McuShell_SendChar(uint8_t ch);
** KeyPressed - bool McuShell_KeyPressed(void);
** SendCharFct - void McuShell_SendCharFct(uint8_t ch, uint8_t (*fct)(uint8_t ch));
** Init - void McuShell_Init(void);
** Deinit - void McuShell_Deinit(void);
**
** * Copyright (c) 2014-2025, Erich Styger
** * Web: https://mcuoneclipse.com
** * SourceForge: https://sourceforge.net/projects/mcuoneclipse
** * Git: https://github.com/ErichStyger/McuOnEclipse_PEx
** * All rights reserved.
** *
** * Redistribution and use in source and binary forms, with or without modification,
** * are permitted provided that the following conditions are met:
** *
** * - Redistributions of source code must retain the above copyright notice, this list
** * of conditions and the following disclaimer.
** *
** * - 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.
** *
** * 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.
** ###################################################################*/
/*!
** @file McuShell.h
** @version 01.00
** @brief
** Module implementing a command line shell.
*/
/*!
** @addtogroup McuShell_module McuShell module documentation
** @{
*/
/* MODULE McuShell. */
#include <ctype.h> /* for isalnum*/
#include "McuShell.h"
#include "McuXFormat.h"
#include "McuUtility.h"
#include "McuCriticalSection.h"
#include "McuWait.h"
#if McuShell_DEFAULT_SERIAL
#include McuShell_CONFIG_DEFAULT_SERIAL_INCLUDE
#endif
uint8_t McuShell_DefaultShellBuffer[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /* default buffer which can be used by the application */
#if McuShell_CONFIG_HISTORY_ENABLED
static uint8_t McuShell_history[McuShell_CONFIG_HISTORY_NOF_ITEMS][McuShell_CONFIG_HISTORY_ITEM_LENGTH]; /* History buffers */
static uint8_t McuShell_history_index = 0; /* Selected command */
#endif
#if McuShell_CONFIG_ECHO_ENABLED
static bool McuShell_EchoEnabled = TRUE;
#endif
#if McuShell_CONFIG_USE_MUTEX
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#endif
#ifdef __HC08__
#pragma MESSAGE DISABLE C3303 /* implicit concatenation of strings */
#endif
#if McuShell_CONFIG_USE_MUTEX
static SemaphoreHandle_t ShellSem = NULL; /* Semaphore to protect shell SCI access */
#endif
#if McuShell_DEFAULT_SERIAL
McuShell_ConstStdIOType McuShell_stdio =
{
(McuShell_StdIO_In_FctType)McuShell_ReadChar, /* stdin */
(McuShell_StdIO_OutErr_FctType)McuShell_SendChar, /* stdout */
(McuShell_StdIO_OutErr_FctType)McuShell_SendChar, /* stderr */
McuShell_KeyPressed /* if input is not empty */
};
static McuShell_ConstStdIOType *McuShell_currStdIO = &McuShell_stdio;
#else
static McuShell_ConstStdIOType *McuShell_currStdIO = NULL; /* needs to be set through McuShell_SetStdio(); */
#endif
/* Internal method prototypes */
static void SendSeparatedStrings(const uint8_t *strA, const uint8_t *strB, uint8_t tabChar, uint8_t tabPos, McuShell_StdIO_OutErr_FctType io);
/*
** ===================================================================
** Method : SendCh (component Shell)
**
** Description :
** Prints a character using an I/O function
** Parameters :
** NAME - DESCRIPTION
** ch - Character to send
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendCh(uint8_t ch, McuShell_StdIO_OutErr_FctType io)
{
if (io==NULL) {
return;
}
io(ch);
}
/*
** ===================================================================
** Method : SendStr (component Shell)
**
** Description :
** Prints a string using an I/O function
** Parameters :
** NAME - DESCRIPTION
** * str - Pointer to string (zero terminated) to be
** printed.
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
/*!
* \brief Prints a string using I/O callbacks
* \param[in] str String (zero terminated) to be printed
* \param[in] io I/O function to be used for printing
*/
void McuShell_SendStr(const uint8_t *str, McuShell_StdIO_OutErr_FctType io)
{
if (io==NULL) {
return;
}
while(*str!='\0') {
io(*str++);
}
}
/*
** ===================================================================
** Method : SendNum32s (component Shell)
**
** Description :
** Sends a 32bit signed number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum32s(int32_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("-1234567890")];
McuUtility_Num32sToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : SendNum32u (component Shell)
**
** Description :
** Sends a 32bit unsigned number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum32u(uint32_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("1234567890")];
McuUtility_Num32uToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : SendNum16s (component Shell)
**
** Description :
** Sends a 16bit signed number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum16s(int16_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("-12345")];
McuUtility_Num16sToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : SendNum16u (component Shell)
**
** Description :
** Sends a 16bit unsigned number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum16u(uint16_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("12345")];
McuUtility_Num16uToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : SendNum8u (component Shell)
**
** Description :
** Sends an 8bit unsigned number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum8u(uint8_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("123")];
McuUtility_Num8uToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : SendNum8s (component Shell)
**
** Description :
** Sends an 8bit signed number to the given I/O
** Parameters :
** NAME - DESCRIPTION
** val - number to print
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendNum8s(int8_t val, McuShell_StdIO_OutErr_FctType io)
{
unsigned char buf[sizeof("-123")];
McuUtility_Num8sToStr(buf, sizeof(buf), val);
McuShell_SendStr(buf, io);
}
/*
** ===================================================================
** Method : ParseCommand (component Shell)
**
** Description :
** Parses a shell command. Use 'help' to get a list of
** supported commands.
** Parameters :
** NAME - DESCRIPTION
** * cmd - Pointer to command string
** * handled - Pointer to variable to indicate if
** the command has been handled. The caller
** passes this variable to the command scanner
** to find out if the passed command has been
** handled. The variable is initialized by the
** caller.
** * io - Pointer to I/O callbacks
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_ParseCommand(const uint8_t *cmd, bool *handled, McuShell_ConstStdIOType *io)
{
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "McuShell help")==0) {
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
McuShell_SendStr((unsigned char*)McuShell_DASH_LINE, io->stdOut);
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
McuShell_SendStr((unsigned char*)McuShell_CONFIG_PROJECT_NAME_STRING, io->stdOut);
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
McuShell_SendStr((unsigned char*)McuShell_DASH_LINE, io->stdOut);
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)"McuShell", (const unsigned char*)"Group of McuShell commands\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" help|status", (const unsigned char*)"Print help or status information\r\n", io->stdOut);
#if McuShell_CONFIG_ECHO_ENABLED
McuShell_SendHelpStr((unsigned char*)" echo (on|off)", (const unsigned char*)"Turn echo on or off\r\n", io->stdOut);
#endif
*handled = TRUE;
return ERR_OK;
#if McuShell_CONFIG_ECHO_ENABLED
} else if ((McuUtility_strcmp((char*)cmd, "McuShell echo on")==0)) {
*handled = TRUE;
McuShell_EchoEnabled = TRUE;
return ERR_OK;
} else if ((McuUtility_strcmp((char*)cmd, "McuShell echo off")==0)) {
*handled = TRUE;
McuShell_EchoEnabled = FALSE;
return ERR_OK;
#endif
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "McuShell status")==0)) {
*handled = TRUE;
return McuShell_PrintStatus(io);
}
return ERR_OK; /* no error */
}
/*
** ===================================================================
** Method : PrintPrompt (component Shell)
**
** Description :
** Prints the prompt to the stdOut channel
** Parameters :
** NAME - DESCRIPTION
** * io - Pointer to IO to be used
** Returns : Nothing
** ===================================================================
*/
void McuShell_PrintPrompt(McuShell_ConstStdIOType *io)
{
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut); /* ensure that there is a new line */
McuShell_SendStr((unsigned char*)McuShell_CONFIG_PROMPT_STRING, io->stdOut);
}
/*
** ===================================================================
** Method : IsHistoryCharacter (component Shell)
**
** Description :
** Returns TRUE if character is a history character
** Parameters :
** NAME - DESCRIPTION
** ch - current command character
** * cmdBuf - Pointer to command line buffer read
** so far
** cmdBufIdx - Index of character into cmdBuf
** * isPrev - Pointer to return value, if it is
** 'previous' history or not
** Returns :
** --- - TRUE if it is an accepted history character
** ===================================================================
*/
bool McuShell_IsHistoryCharacter(uint8_t ch, uint8_t *cmdBuf, size_t cmdBufIdx, bool *isPrev)
{
*isPrev = FALSE;
#if McuShell_CONFIG_HISTORY_ENABLED
if ( cmdBufIdx==0 /* first character on command line */
|| (McuUtility_strcmp((const char*)cmdBuf, (const char*)McuShell_history[McuShell_history_index])==0) /* pressing prev/next character on previous history element */
)
{
if (ch==McuShell_CONFIG_HISTORY_CHAR_PREV) {
*isPrev = TRUE;
return TRUE;
} else if (ch==McuShell_CONFIG_HISTORY_CHAR_NEXT) {
*isPrev = FALSE;
return TRUE;
}
}
#if 0
if (cmdBufIdx==0 || cmdBufIdx==2) { /* accept only first character or sequence as history sequence */
if (cmdBufIdx==2 && cmdBuf[0]==0x1b && cmdBuf[1]==0x5b) {
/* up: 0x27 0x5b 0x41
* down: 0x27 0x5b 0x42
* right: 0x27 0x5b 0x43
* left: 0x27 0x5b 0x44
*/
if (cmdBuf[2]==0x41 /* up */ || cmdBuf[2]==0x44 /* left */) {
*isPrev = TRUE;
return TRUE;
} else if (cmdBuf[2]==0x42 /* down */ || cmdBuf[2]==0x43 /* right */) {
*isPrev = FALSE;
return TRUE;
}
}
/* NYI: handle TAB and SHIFT-TAB */
}
#endif
#else
(void)ch; /* not used */
(void)cmdBuf; /* not used */
(void)cmdBufIdx; /* not used */
#endif
return FALSE;
}
/*
** ===================================================================
** Method : ReadLine (component Shell)
**
** Description :
** Reads a line from stdIn and returns TRUE if we have a line,
** FALSE otherwise.
** Parameters :
** NAME - DESCRIPTION
** * bufStart - Pointer to start of buffer
** * buf - Pointer to buffer where to read in the
** information
** bufSize - size of buffer
** * io - Pointer to I/O callbacks
** Returns :
** --- - TRUE if something has been read, FALSE
** otherwise
** ===================================================================
*/
bool McuShell_ReadLine(uint8_t *bufStart, uint8_t *buf, size_t bufSize, McuShell_ConstStdIOType *io)
{
uint8_t c;
bool isBackwardHistory;
if (io->keyPressed()) {
for(;;) { /* while not '\r' or '\n' */
c = '\0'; /* initialize character */
io->stdIn(&c); /* read character */
if (c=='\0') { /* nothing in rx buffer? Something is wrong... */
break; /* get out of loop */
}
if (c=='\b' || c=='\177') { /* check for backspace */
if (buf > bufStart) { /* Avoid buffer underflow */
#if McuShell_CONFIG_ECHO_ENABLED
if (McuShell_EchoEnabled && io->echoEnabled) {
io->stdOut('\b'); /* delete character on terminal */
io->stdOut(' ');
io->stdOut('\b');
}
#endif
buf--; /* delete last character in buffer */
*buf = '\0';
bufSize++;
}
} else if (McuShell_IsHistoryCharacter(c, bufStart, (size_t)(buf-bufStart), &isBackwardHistory)) {
#if McuShell_CONFIG_HISTORY_ENABLED
uint8_t cBuf[3]={'\0','\0','\0'}, cBufIdx = 0;
bool prevInHistory;
#endif
while (c!='\0') { /* empty the rx buffer (escape sequence) */
#if McuShell_CONFIG_HISTORY_ENABLED
cBuf[cBufIdx] = c;
cBufIdx++;
if (cBufIdx==sizeof(cBuf)) {
cBufIdx = 0; /* ring buffer */
}
#endif
c = '\0'; /* initialize character */
io->stdIn(&c); /* read character */
}
#if McuShell_CONFIG_HISTORY_ENABLED
/* if not an alphanumeric switch to history */
prevInHistory = cBufIdx==0 && cBuf[0]==0x1b && cBuf[1]==0x5b && (cBuf[2]==0x41 /*up*/ || cBuf[2]==0x44 /*left*/);
/* up: 0x27 0x5b 0x41
* down: 0x27 0x5b 0x42
* right: 0x27 0x5b 0x43
* left: 0x27 0x5b 0x44
*/
if (prevInHistory) {
McuUtility_strcpy(bufStart, McuShell_CONFIG_HISTORY_ITEM_LENGTH, McuShell_history[McuShell_history_index]);
McuShell_history_index++; /* update the index */
if (McuShell_history_index==McuShell_CONFIG_HISTORY_NOF_ITEMS) {
McuShell_history_index = 0;
}
} else {
if (McuShell_history_index==0) {
McuShell_history_index = (McuShell_CONFIG_HISTORY_NOF_ITEMS-1);
} else {
McuShell_history_index--;
}
McuUtility_strcpy(bufStart, McuShell_CONFIG_HISTORY_ITEM_LENGTH, McuShell_history[McuShell_history_index]);
}
bufSize = bufSize + buf - bufStart - McuUtility_strlen((const char*)bufStart); /* update the buffer */
buf = bufStart + McuUtility_strlen((const char*)bufStart);
#endif
#if McuShell_CONFIG_ECHO_ENABLED
if (McuShell_EchoEnabled && io->echoEnabled) {
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
McuShell_PrintPrompt(io);
McuShell_SendStr(bufStart, io->stdOut);
}
#endif
} else {
#if McuShell_CONFIG_ECHO_ENABLED
if (McuShell_EchoEnabled && io->echoEnabled) {
#if McuLib_CONFIG_CPU_IS_ESP32
if (c=='\r') { /* idf.py monitor uses '\r' for '\n'? */
c = '\n';
}
#endif
io->stdOut(c); /* echo character */
}
#endif
*buf = (uint8_t)c; /* append character to the string */
buf++;
bufSize--;
if ((c=='\r') || (c=='\n')) {
#if McuShell_CONFIG_ECHO_ENABLED
if (McuShell_EchoEnabled && io->echoEnabled) {
#if McuLib_CONFIG_CPU_IS_ESP32
McuShell_SendStr((unsigned char*)" \n", io->stdOut); /* for ESP32 idf.py monitor it uses '\r' at the end, plus we need a space */
#else
McuShell_SendStr((unsigned char*)"\n", io->stdOut);
#endif
}
#endif
#if McuShell_CONFIG_HISTORY_ENABLED
if ((bufStart[0] != '\0') && (bufStart[0] != '\r') && (bufStart[0] != '\n')) {
int i;
for(i=McuShell_CONFIG_HISTORY_NOF_ITEMS-1; i>0;i--) {
McuUtility_strcpy(McuShell_history[i], McuShell_CONFIG_HISTORY_ITEM_LENGTH, McuShell_history[i-1]); /* move previous commands */
}
McuShell_history_index = 0; /* update the history with the current command */
McuUtility_strcpy(McuShell_history[0], McuShell_CONFIG_HISTORY_ITEM_LENGTH, bufStart); /* add the current command to the history */
if (buf-bufStart <= McuShell_CONFIG_HISTORY_ITEM_LENGTH) { /* size check */
McuShell_history[0][buf-bufStart-1] = '\0';
} else {
McuShell_history[0][McuShell_CONFIG_HISTORY_ITEM_LENGTH-1] = '\0';
}
}
#endif
break;
}
if (bufSize <= 1) { /* buffer full */
break;
}
}
} /* for */
*buf = '\0'; /* zero terminate string */
return TRUE;
} else {
return FALSE;
}
}
/*
** ===================================================================
** Method : PrintStatus (component Shell)
**
** Description :
** Prints various available system status information
** Parameters :
** NAME - DESCRIPTION
** * io - Pointer to I/O callbacks
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_PrintStatus(McuShell_ConstStdIOType *io)
{
unsigned char buf[32];
McuShell_SendStatusStr((const unsigned char*)"McuShell", (const unsigned char*)"Commandline shell status\r\n", io->stdOut);
McuShell_SendStatusStr((const unsigned char*)" Build", (const unsigned char*)__DATE__, io->stdOut);
McuShell_SendStr((unsigned char*)" ", io->stdOut);
McuShell_SendStr((unsigned char*)__TIME__, io->stdOut);
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
#if McuShell_CONFIG_ECHO_ENABLED
McuShell_SendStatusStr((const unsigned char*)" echo", McuShell_EchoEnabled?(const unsigned char*)"On\r\n":(const unsigned char*)"Off\r\n", io->stdOut);
#endif
buf[0] = '\0';
if (McuShell_CONFIG_SILENT_PREFIX_CHAR!=McuShell_NO_SILENT_PREFIX_CHAR) {
McuUtility_chcat(buf, sizeof(buf), McuShell_CONFIG_SILENT_PREFIX_CHAR);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
} else {
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"none\r\n");
}
McuShell_SendStatusStr((const unsigned char*)" silent", buf, io->stdOut);
#if McuShell_CONFIG_MULTI_CMD_ENABLED
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"yes: '");
McuUtility_chcat(buf, sizeof(buf), McuShell_CONFIG_MULTI_CMD_CHAR);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"', size: ");
McuUtility_strcatNum32u(buf, sizeof(buf), McuShell_CONFIG_MULTI_CMD_SIZE);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
McuShell_SendStatusStr((const unsigned char*)" multiCmd", buf, io->stdOut);
#else
McuShell_SendStatusStr((const unsigned char*)" multiCmd", (unsigned char*)"no\r\n", io->stdOut);
#endif
McuUtility_Num32uToStr(buf, sizeof(buf), McuShell_CONFIG_DEFAULT_SHELL_BUFFER_SIZE);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" bytes default size\r\n");
McuShell_SendStatusStr((const unsigned char*)" size", buf, io->stdOut);
return ERR_OK;
}
/*
** ===================================================================
** Method : PrintCommandFailed (component Shell)
**
** Description :
** Prints a standard message for failed or unknown commands
** Parameters :
** NAME - DESCRIPTION
** * cmd - Pointer to command which was failing
** * io - Pointer to I/O callbacks
** Returns : Nothing
** ===================================================================
*/
void McuShell_PrintCommandFailed(const uint8_t *cmd, McuShell_ConstStdIOType *io)
{
McuShell_SendStr((unsigned char*)"*** Failed or unknown command: ", io->stdErr);
McuShell_SendStr(cmd, io->stdErr);
McuShell_SendStr((unsigned char*)"\r\n", io->stdErr);
McuShell_SendStr((unsigned char*)"*** Type ", io->stdErr);
McuShell_SendStr((unsigned char*)McuShell_CMD_HELP, io->stdErr);
McuShell_SendStr((unsigned char*)" to get a list of available commands\r\n", io->stdErr);
}
/*
** ===================================================================
** Method : IterateTable (component Shell)
**
** Description :
** Parses a shell command. It handles first the internal
** commands and will call the provided callback.
** Parameters :
** NAME - DESCRIPTION
** * cmd - Pointer to command string
** * handled - Pointer to boolean which is set to
** TRUE if a command parser has handled the
** command.
** * io - Pointer to I/O callbacks
** * parserTable - Pointer to callback which
** will be called to parse commands in the
** user application, or NULL if not used.
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_IterateTable(const uint8_t *cmd, bool *handled, McuShell_ConstStdIOType *io, McuShell_ConstParseCommandCallback *parserTable)
{
uint8_t res = ERR_OK;
if (parserTable==NULL) { /* no table??? */
return ERR_FAILED;
}
if (io==NULL) { /* no IO handler??? */
return ERR_FAILED;
}
/* iterate through all parser functions in table */
while(*parserTable!=NULL) {
if ((*parserTable)(cmd, handled, io)!=ERR_OK) {
res = ERR_FAILED;
}
parserTable++;
}
return res;
}
/*
** ===================================================================
** Method : ParseWithCommandTableExt (component Shell)
**
** Description :
** Parses a shell command. It handles first the internal
** commands and will call the provided callback.
** Parameters :
** NAME - DESCRIPTION
** * cmd - Pointer to command string
** * io - Pointer to I/O callbacks
** * parseCallback - Pointer to callback
** which will be called to parse commands in
** the user application, or NULL if not used.
** silent - If handling shall be silent, i.e. no
** command prompt printed
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_ParseWithCommandTableExt(const uint8_t *cmd, McuShell_ConstStdIOType *io, McuShell_ConstParseCommandCallback *parseCallback, bool silent)
{
uint8_t res = ERR_OK;
bool handled;
#if McuShell_SILENT_PREFIX_CHAR_ENABLED
bool silentPrefix = FALSE;
#endif
#if McuShell_CONFIG_MULTI_CMD_ENABLED
uint8_t buf[McuShell_CONFIG_MULTI_CMD_SIZE];
size_t i;
bool parseBuffer, finished;
bool insideDoubleQuotes = FALSE; /* with multi-commands: allow the McuShell_CONFIG_MULTI_CMD_CHAR inside double quoted strings */
#endif
if (io==NULL) { /* no I/O handler? */
return ERR_FAILED;
}
if (*cmd=='\0') { /* empty command */
return ERR_OK;
}
#if McuShell_CONFIG_MULTI_CMD_ENABLED
parseBuffer = FALSE;
finished = FALSE;
i = 0;
for(;;) { /* breaks */
if (i>sizeof(buf)-2) {
res = ERR_FAILED;
McuShell_PrintCommandFailed(buf, io);
break; /* buffer overflow */
}
buf[i] = *cmd;
if (buf[i]=='"') {
if (insideDoubleQuotes) { /* already had a double quote? */
insideDoubleQuotes = FALSE; /* note: we do not support nested double quotes */
} else {
insideDoubleQuotes = TRUE; /* mark that we are inside double quotes */
}
}
cmd++; i++;
#if McuShell_SILENT_PREFIX_CHAR_ENABLED
if (i==1 && buf[0]==McuShell_CONFIG_SILENT_PREFIX_CHAR) { /* first character is silent character */
silentPrefix |= (bool)(buf[0]==McuShell_CONFIG_SILENT_PREFIX_CHAR);
buf[0] = *cmd; /* skip silent character */
cmd++;
}
#endif
if (!insideDoubleQuotes && buf[i-1] == McuShell_CONFIG_MULTI_CMD_CHAR) { /* found separator, but not inside double quoted string */
buf[i-1] = '\0';
parseBuffer = TRUE;
} else if (buf[i-1]=='\0') {
parseBuffer = TRUE;
finished = TRUE;
}
if (parseBuffer) {
handled = FALSE;
res = McuShell_IterateTable(buf, &handled, io, parseCallback); /* iterate through all parser functions in table */
if (!handled || res!=ERR_OK) { /* no handler has handled the command, or error? */
McuShell_PrintCommandFailed(buf, io);
res = ERR_FAILED;
}
parseBuffer = FALSE;
i = 0; /* restart */
}
if (finished) {
break; /* get out of loop */
}
} /* for */
#else
#if McuShell_SILENT_PREFIX_CHAR_ENABLED
silentPrefix = (bool)(*cmd==McuShell_CONFIG_SILENT_PREFIX_CHAR);
if (silentPrefix) {
cmd++; /* skip silent character */
}
#endif
handled = FALSE;
res = McuShell_IterateTable(cmd, &handled, io, parseCallback); /* iterate through all parser functions in table */
if (!handled || res!=ERR_OK) { /* no handler has handled the command? */
McuShell_PrintCommandFailed(cmd, io);
res = ERR_FAILED;
}
#endif
#if McuShell_SILENT_PREFIX_CHAR_ENABLED
if (!silentPrefix && !silent) {
McuShell_PrintPrompt(io);
}
#else
if (!silent) {
McuShell_PrintPrompt(io);
}
#endif
return res;
}
/*
** ===================================================================
** Method : ParseWithCommandTable (component Shell)
**
** Description :
** Parses a shell command. It handles first the internal
** commands and will call the provided callback.
** Parameters :
** NAME - DESCRIPTION
** * cmd - Pointer to command string
** * io - Pointer to I/O callbacks
** * parseCallback - Pointer to callback
** which will be called to parse commands in
** the user application, or NULL if not used.
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_ParseWithCommandTable(const uint8_t *cmd, McuShell_ConstStdIOType *io, McuShell_ConstParseCommandCallback *parseCallback)
{
return McuShell_ParseWithCommandTableExt(cmd, io, parseCallback, FALSE);
}
/*
** ===================================================================
** Method : SetStdio (component Shell)
**
** Description :
** Sets an StdIO structure which is returned by GetStdio()
** Parameters :
** NAME - DESCRIPTION
** stdio - New stdio structure to be used.
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_SetStdio(McuShell_ConstStdIOTypePtr stdio)
{
McuShell_currStdIO = stdio;
return ERR_OK;
}
/*
** ===================================================================
** Method : GetStdio (component Shell)
**
** Description :
** Returns the default stdio channel. This method is only
** available if a shell is enabled in the component properties.
** Parameters : None
** Returns :
** --- - Pointer to the stdio descriptor
** ===================================================================
*/
McuShell_ConstStdIOTypePtr McuShell_GetStdio(void)
{
return McuShell_currStdIO;
}
/*
** ===================================================================
** Method : ReadAndParseWithCommandTableExt (component Shell)
**
** Description :
** Reads characters from the default input channel and appends
** it to the buffer. Once a new line has been detected, the
** line will be parsed using the handlers in the table.
** Parameters :
** NAME - DESCRIPTION
** * cmdBuf - Pointer to buffer provided by the
** caller where to store the command to read
** in. Characters will be appended, so make
** sure string buffer is initialized with a
** zero byte at the beginning.
** cmdBufSize - Size of buffer
** * io - Pointer to I/O channels to be used
** * parseCallback - Pointer to callback
** table provided by the user application to
** parse commands. The table has a NULL
** sentinel.
** silent - If handling shall be silent, i.e. no
** command prompt printed
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_ReadAndParseWithCommandTableExt(uint8_t *cmdBuf, size_t cmdBufSize, McuShell_ConstStdIOType *io, McuShell_ConstParseCommandCallback *parseCallback, bool silent)
{
/* IMPORTANT NOTE: this function *appends* to the buffer, so the buffer needs to be initialized first! */
uint8_t res = ERR_OK;
size_t len;
if (io==NULL) { /* no I/O handler? */
return ERR_FAILED;
}
len = McuUtility_strlen((const char*)cmdBuf);
if (McuShell_ReadLine(cmdBuf, cmdBuf+len, cmdBufSize-len, io)) {
len = McuUtility_strlen((const char*)cmdBuf); /* length of buffer string */
if (len==0) { /* error case */
return ERR_FAILED;
} else if (len==1 && (cmdBuf[0]=='\n' || cmdBuf[0]=='\r')) { /* eat preceding newline characters */
cmdBuf[0] = '\0';
}
if (len>=cmdBufSize-1) { /* buffer overflow? Parse what we have, will be likely return an error */
(void)McuShell_ParseWithCommandTableExt(cmdBuf, io, parseCallback, silent);
cmdBuf[0] = '\0'; /* start again */
res = ERR_OVERFLOW;
} else if (cmdBuf[len-1]=='\n' || cmdBuf[len-1]=='\r') { /* line end: parse command */
cmdBuf[len-1] = '\0'; /* remove line end character for parser */
res = McuShell_ParseWithCommandTableExt(cmdBuf, io, parseCallback, silent);
cmdBuf[0] = '\0'; /* start again */
} else {
/* continue to append to buffer */
}
}
return res;
}
/*
** ===================================================================
** Method : ReadCommandLine (component Shell)
**
** Description :
** Similar to ReadAndParseWithCommandTableExt, but does not
** call the parser. Reads characters from the default input
** channel and appends it to the buffer. Once a new line has
** been detected, it removes it and returns ERR_OK
** Parameters :
** NAME - DESCRIPTION
** * cmdBuf - Pointer to buffer provided by the
** caller where to store the command to read
** in. Characters will be appended, so make
** sure string buffer is initialized with a
** zero byte at the beginning.
** cmdBufSize - Size of buffer
** * io - Pointer to I/O channels to be used
** Returns :
** --- - Error code, ERR_OK if a complete line has
** been detected
** ===================================================================
*/
uint8_t McuShell_ReadCommandLine(uint8_t *cmdBuf, size_t cmdBufSize, McuShell_ConstStdIOType *io)
{
/* IMPORTANT NOTE: this function *appends* to the buffer, so the buffer needs to be initialized first! */
size_t len;
if (io==NULL) { /* no I/O handler? */
return ERR_FAILED;
}
len = McuUtility_strlen((const char*)cmdBuf);
if (McuShell_ReadLine(cmdBuf, cmdBuf+len, cmdBufSize-len, io)) {
len = McuUtility_strlen((const char*)cmdBuf); /* length of buffer string */
if (len==0) { /* error case */
return ERR_FAILED;
} else if (len==1 && (cmdBuf[0]=='\n' || cmdBuf[0]=='\r')) { /* eat preceding newline characters */
cmdBuf[0] = '\0';
}
if (len>=cmdBufSize-1) { /* buffer overflow? Parse what we have, will be likely return an error */
cmdBuf[0] = '\0'; /* start again */
return ERR_OVERFLOW;
} else if (cmdBuf[len-1]=='\n' || cmdBuf[len-1]=='\r') { /* line end: parse command */
cmdBuf[len-1] = '\0'; /* remove line end character for parser */
return ERR_OK;
} else {
/* continue to append to buffer */
}
}
return ERR_BUSY;
}
/*
** ===================================================================
** Method : ReadAndParseWithCommandTable (component Shell)
**
** Description :
** Reads characters from the default input channel and appends
** it to the buffer. Once a new line has been detected, the
** line will be parsed using the handlers in the table.
** Parameters :
** NAME - DESCRIPTION
** * cmdBuf - Pointer to buffer provided by the
** caller where to store the command to read
** in. Characters will be appended, so make
** sure string buffer is initialized with a
** zero byte at the beginning.
** cmdBufSize - Size of buffer
** * io - Pointer to I/O channels to be used
** * parseCallback - Pointer to callback
** table provided by the user application to
** parse commands. The table has a NULL
** sentinel.
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_ReadAndParseWithCommandTable(uint8_t *cmdBuf, size_t cmdBufSize, McuShell_ConstStdIOType *io, McuShell_ConstParseCommandCallback *parseCallback)
{
return McuShell_ReadAndParseWithCommandTableExt(cmdBuf, cmdBufSize, io, parseCallback, FALSE);
}
/*
** ===================================================================
** Method : RequestSerial (component Shell)
**
** Description :
** Used to get mutual access to the shell console. Only has an
** effect if using an RTOS with semaphore for the console
** access.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
void McuShell_RequestSerial(void)
{
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreTakeRecursive(ShellSem, portMAX_DELAY);
#endif
}
/*
** ===================================================================
** Method : ReleaseSerial (component Shell)
**
** Description :
** Used to release mutual access to the shell console. Only has
** an effect if using an RTOS with semaphore for the console
** access.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
void McuShell_ReleaseSerial(void)
{
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreGiveRecursive(ShellSem);
#endif
}
/*
** ===================================================================
** Method : GetSemaphore (component Shell)
**
** Description :
** Return the semaphore of the shell.
** Parameters : None
** Returns :
** --- - semaphore, or NULL if not used or not
** allocated.
** ===================================================================
*/
void* McuShell_GetSemaphore(void)
{
#if McuShell_CONFIG_USE_MUTEX
return ShellSem;
#else
return NULL;
#endif
}
/*
** ===================================================================
** Method : SendSeparatedStrings (component Shell)
**
** Description :
** This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static void SendSeparatedStrings(const uint8_t *strA, const uint8_t *strB, uint8_t tabChar, uint8_t tabPos, McuShell_StdIO_OutErr_FctType io)
{
/* write command part */
if (strA!=NULL) {
while(*strA!='\0' && tabPos>0) {
io(*strA++);
tabPos--;
}
}
/* fill up until ';' */
while(tabPos>0) {
io(' ');
tabPos--;
}
/* write separator */
io(tabChar);
io(' ');
if (strB!=NULL) {
/* write help text */
McuShell_SendStr(strB, io);
}
}
/*
** ===================================================================
** Method : SendHelpStr (component Shell)
**
** Description :
** Prints a string using an I/O function, formated for the
** 'help' command
** Parameters :
** NAME - DESCRIPTION
** * strCmd - Pointer to string of the command
** * strHelp - Pointer to help text string
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendHelpStr(const uint8_t *strCmd, const uint8_t *strHelp, McuShell_StdIO_OutErr_FctType io)
{
SendSeparatedStrings(strCmd, strHelp, ';', McuShell_CONFIG_HELP_SEMICOLON_POS, io);
}
/*
** ===================================================================
** Method : SendStatusStr (component Shell)
**
** Description :
** Prints a status string using an I/O function, formated for
** the 'status' command
** Parameters :
** NAME - DESCRIPTION
** * strItem - Pointer to string of the command
** * strStatus - Pointer to help text string
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendStatusStr(const uint8_t *strItem, const uint8_t *strStatus, McuShell_StdIO_OutErr_FctType io)
{
SendSeparatedStrings(strItem, strStatus, ':', McuShell_CONFIG_STATUS_COLON_POS, io);
}
/*
** ===================================================================
** Method : ReadChar (component Shell)
**
** Description :
** Reads a character (blocking)
** Parameters :
** NAME - DESCRIPTION
** * c - Pointer to character to be used to store the
** result
** Returns : Nothing
** ===================================================================
*/
void McuShell_ReadChar(uint8_t *c)
{
#if McuShell_CONFIG_DEFAULT_SERIAL
uint8_t res;
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreTakeRecursive(ShellSem, portMAX_DELAY);
#endif
res = McuShell_CONFIG_DEFAULT_SERIAL_RECEIVE_FCT_NAME((uint8_t*)c);
if (res==ERR_RXEMPTY) {
/* no character in buffer */
*c = '\0';
}
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreGiveRecursive(ShellSem);
#endif
#else
*c = '\0';
return; /* no serial component set up in properties */
#endif
}
/*
** ===================================================================
** Method : SendChar (component Shell)
**
** Description :
** Sends a character (blocking)
** Parameters :
** NAME - DESCRIPTION
** ch - character to be sent
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendChar(uint8_t ch)
{
#if McuShell_CONFIG_DEFAULT_SERIAL
McuShell_SendCharFct(ch, McuShell_CONFIG_DEFAULT_SERIAL_SEND_FCT_NAME);
#else
(void)ch; /* avoid compiler warning about unused argument */
#endif
}
/*
** ===================================================================
** Method : KeyPressed (component Shell)
**
** Description :
** Checks if a key has been pressed (a character is present in
** the input buffer)
** Parameters : None
** Returns :
** --- - Error code
** ===================================================================
*/
bool McuShell_KeyPressed(void)
{
#if McuShell_CONFIG_DEFAULT_SERIAL
bool res;
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreTakeRecursive(ShellSem, portMAX_DELAY);
#endif
#if McuShell_CONFIG_DEFAULT_SERIAL
res = (bool)((McuShell_CONFIG_DEFAULT_SERIAL_RXAVAIL_FCT_NAME()==0U) ? FALSE : TRUE); /* true if there are characters in receive buffer */
#endif
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreGiveRecursive(ShellSem);
#endif
return res;
#else
return FALSE; /* no serial component set up in properties */
#endif
}
/*
** ===================================================================
** Method : Init (component Shell)
**
** Description :
** Initializes the module, especially creates the mutex
** semaphore if an RTOS is used.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
void McuShell_Init(void)
{
#if McuShell_CONFIG_USE_MUTEX
#if configSUPPORT_STATIC_ALLOCATION
static StaticSemaphore_t xMutexBuffer;
#endif
bool schedulerStarted;
McuCriticalSection_CriticalVariable();
schedulerStarted = (bool)(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED);
if (!schedulerStarted) { /* FreeRTOS not started yet. We are called in PE_low_level_init(), and interrupts are disabled */
McuCriticalSection_EnterCritical();
}
#if configSUPPORT_STATIC_ALLOCATION
ShellSem = xSemaphoreCreateRecursiveMutexStatic(&xMutexBuffer);
#else
ShellSem = xSemaphoreCreateRecursiveMutex();
#endif
if (!schedulerStarted) { /* above RTOS call might have enabled interrupts! Make sure we restore the state */
McuCriticalSection_ExitCritical();
}
if (ShellSem==NULL) { /* semaphore creation failed */
for(;;) {} /* error, not enough memory? */
}
vQueueAddToRegistry(ShellSem, "McuShell_Sem");
#endif
#if McuShell_CONFIG_HISTORY_ENABLED
{
int i;
McuShell_history_index = 0;
for(i=0; i<McuShell_CONFIG_HISTORY_NOF_ITEMS;i++) {
McuShell_history[i][0] = '\0';
}
}
#endif
#if McuShell_CONFIG_ECHO_ENABLED
McuShell_EchoEnabled = TRUE;
#endif
}
/*
** ===================================================================
** Method : Deinit (component Shell)
**
** Description :
** De-Initializes the module, especially frees the mutex
** semaphore if an RTOS is used.
** Parameters : None
** Returns : Nothing
** ===================================================================
*/
void McuShell_Deinit(void)
{
#if McuShell_CONFIG_USE_MUTEX
vQueueUnregisterQueue(ShellSem);
vSemaphoreDelete(ShellSem);
ShellSem = NULL;
#endif
}
/*
** ===================================================================
** Method : SendData (component Shell)
**
** Description :
** Sends data using an I/O function. Unlike SendStr(), with
** this method it is possible to send binary data, including
** zero bytes.
** Parameters :
** NAME - DESCRIPTION
** * data - Pointer to data to be sent
** dataSize - Number of bytes to be sent.
** io - I/O callbacks to be used for printing.
** Returns : Nothing
** ===================================================================
*/
/*!
* \brief Sends data using I/O callbacks
* \param[in] data Pointer to data to be sent
* \param[in] io I/O function to be used for sending
*/
void McuShell_SendData(const uint8_t *data, uint16_t dataSize, McuShell_StdIO_OutErr_FctType io)
{
while(dataSize>0) {
io(*data++);
dataSize--;
}
}
/*
** ===================================================================
** Method : McuShell_printfPutChar (component Shell)
**
** Description :
** This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
void McuShell_printfPutChar(void *arg, char c)
{
McuShell_StdIO_OutErr_FctType fct = (McuShell_StdIO_OutErr_FctType)arg;
fct(c); /* print character */
}
/*
** ===================================================================
** Method : printfIO (component Shell)
**
** Description :
** Printf() style function using XFormat component, using a
** custom I/O handler.
** Parameters :
** NAME - DESCRIPTION
** * io - Pointer to
** fmt - printf style format string
** Returns :
** --- - number of characters written
** ===================================================================
*/
unsigned McuShell_printfIO(McuShell_ConstStdIOType *io, const char *fmt, ...)
{
va_list args;
unsigned int count = 0;
va_start(args,fmt);
count = McuXFormat_xvformat(McuShell_printfPutChar, (void*)io->stdOut, fmt, args);
va_end(args);
return count;
}
/*
** ===================================================================
** Method : printf (component Shell)
**
** Description :
** Printf() style function using XFormat component, using the
** shell default I/O handler.
** Parameters :
** NAME - DESCRIPTION
** fmt - printf style format string
** Returns :
** --- - number of characters written
** ===================================================================
*/
unsigned McuShell_printf(const char *fmt, ...)
{
va_list args;
unsigned int count = 0;
va_start(args,fmt);
count = McuXFormat_xvformat(McuShell_printfPutChar, (void*)McuShell_GetStdio()->stdOut, fmt, args);
va_end(args);
return count;
}
/*
** ===================================================================
** Method : SendCharFct (component Shell)
**
** Description :
** Method to send a character using a standard I/O handle.
** Parameters :
** NAME - DESCRIPTION
** ch - character to be sent
** * fct - Function pointer to output function: takes
** a byte to write and returns error code.
** Returns : Nothing
** ===================================================================
*/
void McuShell_SendCharFct(uint8_t ch, uint8_t (*fct)(uint8_t ch))
{
#if McuShell_CONFIG_BLOCKING_SEND_ENABLED
uint8_t res;
#if McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_MS>0
int timeoutMs = McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_MS;
#endif
#endif
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreTakeRecursive(ShellSem, portMAX_DELAY);
#endif
#if McuShell_CONFIG_BLOCKING_SEND_ENABLED
do {
res = fct((uint8_t)ch); /* Send char, returns error code */
#if McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_MS>0
if (res==ERR_TXFULL) {
#if McuShell_CONFIG_BLOCKING_SEND_RTOS_WAIT
McuWait_WaitOSms(McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_WAIT_MS);
#else
McuWait_Waitms(McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_WAIT_MS);
#endif
}
#endif
#if McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_MS>0
if(timeoutMs<=0) {
break; /* timeout */
}
timeoutMs -= McuShell_CONFIG_BLOCKING_SEND_TIMEOUT_WAIT_MS;
#endif
} while(res==ERR_TXFULL);
#else
(void)fct((uint8_t)ch); /* non blocking send */
#endif
#if McuShell_CONFIG_USE_MUTEX
(void)xSemaphoreGiveRecursive(ShellSem);
#endif
}
/*
** ===================================================================
** Method : PrintMemory (component Shell)
**
** Description :
** Prints a chunk of memory bytes in a formatted way.
** Parameters :
** NAME - DESCRIPTION
** * hndl - Pointer to
** startAddr - Memory start address
** endAddr - Memory end address
** addrSize - Number of bytes for the address
** (1, 2, 3 or 4)
** bytesPerLine - Number of bytes per line
** readfp - Function pointer to read the memory.
** Returns error code, uses a device handle,
** 32bit address with a pointer to a buffer
** and a buffer size.
** * io - Pointer to I/O to be used
** Returns :
** --- - Error code
** ===================================================================
*/
uint8_t McuShell_PrintMemory(void *hndl, uint32_t startAddr, uint32_t endAddr, uint8_t addrSize, uint8_t bytesPerLine, uint8_t (*readfp)(void *, uint32_t, uint8_t*, size_t), McuShell_ConstStdIOType *io)
{
#define NOF_BYTES_PER_LINE 32 /* how many bytes are shown on a line. This defines as well the chunk size we read from memory */
#define MAX_NOF_BYTES_PER_LINE 32
uint8_t buf[MAX_NOF_BYTES_PER_LINE]; /* this is the chunk of data we get (per line in output) */
uint8_t str[3*MAX_NOF_BYTES_PER_LINE+((MAX_NOF_BYTES_PER_LINE+1)/8)+1]; /* maximum string for output:
- '3*' because each byte is 2 hex digits plus a space
- '(NOF_BYTES_PER_LINE+1)/8' because we add a space between every 8 byte block
- '+1' for the final zero byte */
uint32_t addr;
uint8_t res=0, j, bufSize;
uint8_t ch;
if (endAddr<startAddr) {
McuShell_SendStr((unsigned char*)"\r\n*** End address must be larger or equal than start address\r\n", io->stdErr);
return ERR_RANGE;
}
for(addr=startAddr; addr<=endAddr; /* nothing */ ) {
if (endAddr-addr+1 >= bytesPerLine) { /* read only part of buffer */
bufSize = bytesPerLine; /* read full buffer */
} else {
bufSize = (uint8_t)(endAddr-addr+1);
}
if (readfp(hndl, addr, buf, bufSize)!=ERR_OK) {
McuShell_SendStr((unsigned char*)"\r\n*** Read failed!\r\n", io->stdErr);
return ERR_FAILED;
}
if (res != ERR_OK) {
McuShell_SendStr((unsigned char*)"\r\n*** Failure reading memory block!\r\n", io->stdErr);
return ERR_FAULT;
}
/* write address */
McuUtility_strcpy(str, sizeof(str), (unsigned char*)"0x");
McuUtility_strcatNumHex(str, sizeof(str), addr, addrSize);
McuUtility_chcat(str, sizeof(str), ':');
McuShell_SendStr((unsigned char*)str, io->stdOut);
/* write data in hex */
str[0] = '\0';
for (j=0; j<bufSize; j++) {
if ((j)==0) {
McuUtility_chcat(str, sizeof(str), ' ');
}
McuUtility_strcatNum8Hex(str, sizeof(str), buf[j]);
McuUtility_chcat(str, sizeof(str), ' ');
}
for (/*empty*/; j<bytesPerLine; j++) { /* fill up line */
McuUtility_strcat(str, sizeof(str), (unsigned char*)"-- ");
}
McuShell_SendStr((unsigned char*)str, io->stdOut);
/* write in ASCII */
io->stdOut(' ');
for (j=0; j<bufSize; j++) {
ch = buf[j];
if (ch >= ' ' && ch <= 0x7f) {
io->stdOut(ch);
} else {
io->stdOut('.'); /* place holder */
}
}
for (/*empty*/; j<bytesPerLine; j++) { /* fill up line */
McuUtility_strcat(str, sizeof(str), (unsigned char*)"-- ");
}
McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);
addr += bytesPerLine;
}
return ERR_OK;
}
/*
** ===================================================================
** Method : ProcessConsoleInput (component Shell)
**
** Description :
** Processes a string received from a console which can include
** backspace characters.
** Parameters :
** NAME - DESCRIPTION
** * buf - Pointer to character buffer
** bufSize - Size of buffer
** Returns :
** --- - Number of characters in the buffer
** ===================================================================
*/
int McuShell_ProcessConsoleInput(char *buf, size_t bufSize)
{
/* - convert '\r' at the end to '\n'
* - handle '\b' backspace in input
*/
char *src, *dst; /* dst is the current cursor in the string, changed as well by '\b' */
size_t len;
if (bufSize<2) {
return 0; /* buffer size needs room for at least two bytes: '\n' and '\0' */
}
src = (char*)buf;
dst = (char*)buf;
while(*src!='\0') {
if (*src=='\r' && *(src+1)=='\0') {
*src = '\n'; /* convert '\r' at the end to '\n' */
}
if (*src=='\b') { /* backspace */
if (dst!=buf) { /* go back only if not at start */
dst--; /* move cursor backward */
}
src++;
continue; /* jump to while condition */
}
*dst++ = *src++; /* copy char */
}
*dst = '\0'; /* terminate resulting string */
len = McuUtility_strlen(buf);
if (buf[len-1]!='\n') { /* no line ending? */
McuUtility_chcat((unsigned char*)buf, bufSize, '\n');
}
return McuUtility_strlen(buf);
}
/* END McuShell. */
/*!
** @}
*/