/* ################################################################### ** 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 /* 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; i0) { 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 (endAddrstdErr); 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; jstdOut); /* write in ASCII */ io->stdOut(' '); for (j=0; j= ' ' && ch <= 0x7f) { io->stdOut(ch); } else { io->stdOut('.'); /* place holder */ } } for (/*empty*/; jstdOut); 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. */ /*! ** @} */