1631 lines
61 KiB
C
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. */
|
|
|
|
/*!
|
|
** @}
|
|
*/
|