Files

317 lines
8.4 KiB
C
Raw Permalink Normal View History

/*
* CommandLine.c
2013-12-22 16:48:15 +01:00
*
* Created on: 04.05.2013
* Author: skuser
2013-12-22 16:48:15 +01:00
*/
#include "CommandLine.h"
#define CHAR_GET_MODE '?' /* <Command>? */
#define CHAR_SET_MODE '=' /* <Command>=<Param> */
#define CHAR_EXEC_MODE '\0' /* <Command> */
#define IS_COMMAND_DELIMITER(c) ( \
((c) == CHAR_EXEC_MODE) || ((c) == CHAR_GET_MODE) || ((c) == CHAR_SET_MODE) \
)
#define IS_CHARACTER(c) ( \
( ((c) >= 'A') && ((c) <= 'Z') ) || \
( ((c) >= 'a') && ((c) <= 'z') ) || \
( ((c) >= '0') && ((c) <= '9') ) || \
( ((c) == '_') ) || \
( ((c) == CHAR_GET_MODE) || ((c) == CHAR_SET_MODE) ) \
)
#define IS_LOWERCASE(c) ( ((c) >= 'a') && ((c) <= 'z') )
#define TO_UPPERCASE(c) ( (c) - 'a' + 'A' )
#define NO_FUNCTION ((void*) 0)
#define STATUS_MESSAGE_TRAILER "\r\n"
#define OPTIONAL_ANSWER_TRAILER "\r\n"
/* Include all command functions */
#include "Commands.h"
const PROGMEM CommandEntryType CommandTable[] = {
{
.Command = COMMAND_VERSION,
.ExecFunc = NO_FUNCTION,
.SetFunc = NO_FUNCTION,
.GetFunc = CommandGetVersion,
},
{
.Command = COMMAND_CONFIG,
.ExecFunc = CommandExecConfig,
.SetFunc = CommandSetConfig,
.GetFunc = CommandGetConfig
},
{
.Command = COMMAND_UID,
.ExecFunc = NO_FUNCTION,
.SetFunc = CommandSetUid,
.GetFunc = CommandGetUid
},
{
.Command = COMMAND_READONLY,
.ExecFunc = NO_FUNCTION,
.GetFunc = CommandGetReadOnly,
.SetFunc = CommandSetReadOnly
},
{
.Command = COMMAND_UPLOAD,
.ExecFunc = CommandExecUpload,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
{
.Command = COMMAND_DOWNLOAD,
.ExecFunc = CommandExecDownload,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
{
.Command = COMMAND_RESET,
.ExecFunc = CommandExecReset,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
#ifdef SUPPORT_FIRMWARE_UPGRADE
{
.Command = COMMAND_UPGRADE,
.ExecFunc = CommandExecUpgrade,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
#endif
{
.Command = COMMAND_MEMSIZE,
.ExecFunc = NO_FUNCTION,
.SetFunc = NO_FUNCTION,
.GetFunc = CommandGetMemSize
},
{
.Command = COMMAND_UIDSIZE,
.ExecFunc = NO_FUNCTION,
.SetFunc = NO_FUNCTION,
.GetFunc = CommandGetUidSize
},
{
.Command = COMMAND_BUTTON,
.ExecFunc = CommandExecButton,
.SetFunc = CommandSetButton,
.GetFunc = CommandGetButton
},
{
.Command = COMMAND_BUTTON_LONG,
.ExecFunc = CommandExecButtonLong,
.SetFunc = CommandSetButtonLong,
.GetFunc = CommandGetButtonLong
},
{
.Command = COMMAND_LEDGREEN,
.ExecFunc = CommandExecLedGreen,
.SetFunc = CommandSetLedGreen,
.GetFunc = CommandGetLedGreen
},
{
.Command = COMMAND_LEDRED,
.ExecFunc = CommandExecLedRed,
.SetFunc = CommandSetLedRed,
.GetFunc = CommandGetLedRed
},
{
.Command = COMMAND_LOGMODE,
.ExecFunc = CommandExecLogMode,
.SetFunc = CommandSetLogMode,
.GetFunc = CommandGetLogMode
},
{
.Command = COMMAND_LOGMEM,
.ExecFunc = CommandExecLogMem,
.SetFunc = CommandSetLogMem,
.GetFunc = CommandGetLogMem
},
2013-12-22 16:48:15 +01:00
{
.Command = COMMAND_SETTING,
.ExecFunc = NO_FUNCTION,
.SetFunc = CommandSetSetting,
.GetFunc = CommandGetSetting
},
{
.Command = COMMAND_CLEAR,
.ExecFunc = CommandExecClear,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
{
.Command = COMMAND_HELP,
.ExecFunc = CommandExecHelp,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
},
{
.Command = COMMAND_RSSI,
.ExecFunc = NO_FUNCTION,
.SetFunc = NO_FUNCTION,
.GetFunc = CommandGetRssi
},
{ /* This has to be last element */
.Command = COMMAND_LIST_END,
.ExecFunc = NO_FUNCTION,
.SetFunc = NO_FUNCTION,
.GetFunc = NO_FUNCTION
}
};
#define STATUS_TABLE_ENTRY(Id, Text) \
{ Id, STRINGIFY(Id) ":" Text }
typedef struct {
CommandStatusIdType Id;
CommandStatusMessageType Message;
} CommandStatusType;
static const CommandStatusType PROGMEM StatusTable[] = {
STATUS_TABLE_ENTRY(COMMAND_INFO_OK_ID, COMMAND_INFO_OK),
STATUS_TABLE_ENTRY(COMMAND_INFO_OK_WITH_TEXT_ID, COMMAND_INFO_OK_WITH_TEXT),
STATUS_TABLE_ENTRY(COMMAND_INFO_XMODEM_WAIT_ID, COMMAND_INFO_XMODEM_WAIT),
STATUS_TABLE_ENTRY(COMMAND_ERR_UNKNOWN_CMD_ID, COMMAND_ERR_UNKNOWN_CMD),
STATUS_TABLE_ENTRY(COMMAND_ERR_INVALID_USAGE_ID, COMMAND_ERR_INVALID_USAGE),
STATUS_TABLE_ENTRY(COMMAND_ERR_INVALID_PARAM_ID, COMMAND_ERR_INVALID_PARAM),
};
static uint16_t BufferIdx;
static const char* GetStatusMessageP(CommandStatusIdType StatusId)
{
uint8_t i;
for (i=0; i<(sizeof(StatusTable)/sizeof(*StatusTable)); i++) {
if (pgm_read_byte(&StatusTable[i].Id) == StatusId)
return StatusTable[i].Message;
}
return (void*) 0;
}
static CommandStatusIdType CallCommandFunc(
const CommandEntryType* CommandEntry, char CommandDelimiter, char* pParam) {
char* pTerminalBuffer = (char*) TerminalBuffer;
/* Call appropriate function depending on CommandDelimiter */
if (CommandDelimiter == CHAR_GET_MODE) {
CommandGetFuncType GetFunc = pgm_read_ptr(&CommandEntry->GetFunc);
if (GetFunc != NO_FUNCTION) {
return GetFunc(pTerminalBuffer);
}
} else if (CommandDelimiter == CHAR_SET_MODE) {
CommandSetFuncType SetFunc = pgm_read_ptr(&CommandEntry->SetFunc);
if (SetFunc != NO_FUNCTION) {
return SetFunc(pParam);
}
} else if (CommandDelimiter == CHAR_EXEC_MODE){
CommandExecFuncType ExecFunc = pgm_read_ptr(&CommandEntry->ExecFunc);
if (ExecFunc != NO_FUNCTION) {
return ExecFunc(pTerminalBuffer);
}
} else {
/* This should not happen (TM) */
}
/* This delimiter has not been registered with this command */
return COMMAND_ERR_INVALID_USAGE_ID;
}
static void DecodeCommand(void)
{
uint8_t i;
bool CommandFound = false;
CommandStatusIdType StatusId = COMMAND_ERR_UNKNOWN_CMD_ID;
char* pTerminalBuffer = (char*) TerminalBuffer;
/* Do some sanity check first */
if (!IS_COMMAND_DELIMITER(pTerminalBuffer[0])) {
char* pCommandDelimiter = pTerminalBuffer;
char CommandDelimiter = '\0';
/* Search for command delimiter, store it and replace with '\0' */
while(!(IS_COMMAND_DELIMITER(*pCommandDelimiter)))
pCommandDelimiter++;
CommandDelimiter = *pCommandDelimiter;
*pCommandDelimiter = '\0';
/* Search in command table */
for (i=0; i<(sizeof(CommandTable) / sizeof(*CommandTable)); i++) {
if (strcmp_P(pTerminalBuffer, CommandTable[i].Command) == 0) {
/* Command found. Clear buffer, and call appropriate function */
char* pParam = ++pCommandDelimiter;
pTerminalBuffer[0] = '\0';
CommandFound = true;
StatusId = CallCommandFunc(&CommandTable[i], CommandDelimiter, pParam);
break;
}
}
}
/* Send command status message */
TerminalSendStringP(GetStatusMessageP(StatusId));
TerminalSendStringP(PSTR(STATUS_MESSAGE_TRAILER));
if (CommandFound && (pTerminalBuffer[0] != '\0') ) {
/* Send optional answer */
TerminalSendString(pTerminalBuffer);
TerminalSendStringP(PSTR(OPTIONAL_ANSWER_TRAILER));
}
}
void CommandLineInit(void)
{
BufferIdx = 0;
}
bool CommandLineProcessByte(uint8_t Byte) {
if (IS_CHARACTER(Byte)){
/* Store uppercase character */
if (IS_LOWERCASE(Byte)) {
Byte = TO_UPPERCASE(Byte);
}
/* Prevent buffer overflow and account for '\0' */
if (BufferIdx < (sizeof(TerminalBuffer) / sizeof(*TerminalBuffer) - 1)) {
TerminalBuffer[BufferIdx++] = Byte;
}
}else if (Byte == '\r') {
/* Process on \r. Terminate string and decode. */
TerminalBuffer[BufferIdx] = '\0';
BufferIdx = 0;
DecodeCommand();
}else if (Byte == '\b') {
/* Backspace. Delete last character in buffer. */
if (BufferIdx > 0) {
BufferIdx--;
}
} else if (Byte == 0x1B){
/* Drop buffer on escape */
BufferIdx = 0;
} else {
/* Ignore other chars */
}
return true;
}
void CommandLineTick(void)
{
}