CLI example for NNN50
Dependencies: NNN50_WIFI_API
Fork of NNN50_WiFi_HelloWorld by
CLI_Source/command-interpreter.cpp
- Committer:
- silviaChen
- Date:
- 2017-09-14
- Revision:
- 9:871fc0231c7f
File content as of revision 9:871fc0231c7f:
/**
* File: command-interpreter.c
* Description: processes commands incoming over the serial port.
*
* Copyright 2014 by CYNTEC Corporation. All rights reserved.
*/
#include <stdint.h>
#include <string.h>
#include "mbed.h"
#include "command-interpreter.h"
extern Serial console;
// Command parsing state
typedef struct {
// Finite-state machine's current state.
uint8_t state;
// The command line is stored in this buffer.
uint8_t buffer[CYNTEC_COMMAND_BUFFER_LENGTH];
// Indices of the tokens (command(s) and arguments) in the above buffer.
uint8_t tokenIndices[MAX_TOKEN_COUNT];
// The number of tokens read in, including the command(s).
uint8_t tokenCount;
// Used while reading in the command line.
uint8_t index;
// First error found in this command.
uint8_t error;
// The token number of the first true argument after possible nested commands.
uint8_t argOffset;
//gill
uint8_t totalBuffer[CYNTEC_COMMAND_BUFFER_LENGTH];
uint8_t totalIndex;
} CyntecCommandState;
static CyntecCommandState commandState;
// Remember the previous character seen by emberProcessCommandString() to ignore
// an LF following a CR.
static uint8_t previousCharacter = 0;
CyntecCommandEntry *cyntecCurrentCommand;
enum {
CMD_AWAITING_ARGUMENT,
CMD_READING_ARGUMENT,
CMD_READING_TO_EOL // clean up after error
};
const char* cyntecCommandErrorNames[] =
{
"",
"No such command;",
"Wrong number of arguments;",
"Argument out of range;",
"Argument syntax error;",
"No matched argument;",
"Wrong command order;",
"Invalid state to perform operation;",
"Function call fail;"
};
/**
* @brief Converts a character representation of a hex to real value.
* @param c is the hex value in char format
* @return the value of the hex otherwise INVALID_HEX_CHARACTER
*/
uint8_t cyntecAtoi(uint8_t *str, uint8_t len)
{
uint8_t result = 0;
uint8_t i = 0;
while( *str != '\0' && i < len)
{
result *= 10;
result = result + ( *str - '0' );
str++;
i++;
}
return result;
}
int cyntecAtoInt(uint8_t *str)
{
int result = 0;
uint8_t i = 0;
bool is_negative = false;
if (*str == '-') {
is_negative = true;
str++;
}
while( *str != '\0')
{
result *= 10;
result = result + ( *str - '0' );
str++;
i++;
}
if (is_negative)
return -result;
else
return result;
}
uint8_t cyntecArgToUint8(uint8_t *str, uint8_t len)
{
uint8_t result = 0;
uint8_t num[2];
uint8_t i;
if ( len != 2 )
{
return 0;
}
for ( i = 0 ; i < 2 ; i++ )
{
if ('0' <= str[i] && str[i] <= '9')
num[i] = str[i] - '0';
else if ('a' <= str[i] && str[i] <= 'f')
num[i] = str[i] - 'a' + 10;
else if ('A' <= str[i] && str[i] <= 'F')
num[i] = str[i] - 'A' + 10;
else
return 0;
}
result |= num[0] << 4;
result |= num[1] << 0;
return result;
}
uint16_t cyntecAtoiUint16(uint8_t *str, uint8_t len)
{
uint16_t result = 0;
uint16_t i = 0;
while( *str != '\0' && i < len)
{
result *= 10;
result = result + ( *str - '0' );
str++;
i++;
}
return result;
}
uint16_t cyntecArgToUint16(uint8_t *str, uint8_t len)
{
uint16_t result = 0;
uint8_t num[4];
uint8_t i;
if ( len != 4 )
{
return 0;
}
for ( i = 0 ; i < 4 ; i++ )
{
if ('0' <= str[i] && str[i] <= '9')
num[i] = str[i] - '0';
else if ('a' <= str[i] && str[i] <= 'f')
num[i] = str[i] - 'a' + 10;
else if ('A' <= str[i] && str[i] <= 'F')
num[i] = str[i] - 'A' + 10;
else
return 0;
}
result |= num[0] << 12;
result |= num[1] << 8;
result |= num[2] << 4;
result |= num[3] << 0;
return result;
}
//gill 20150918
uint32_t cyntecHexToUint32(uint8_t *str, uint8_t len)
{
if (len > 8)
return 0;
uint32_t result = 0;
uint16_t i = 0;
while( *str != '\0' && i < len)
{
result *= 16;
result = result + ( *str - '0' );
str++;
i++;
}
return result;
}
uint8_t cyntecStrCmp(uint8_t *src, uint8_t *dst, uint8_t len)
{
uint8_t i = 0;
while ( *src != '\0' && *dst != '\0' && i < len )
{
if ( *src != *dst )
return 0;
i++;
src++;
dst++;
}
return 1;
}
// Initialize the state machine.
void cyntecCommandReaderInit(void)
{
commandState.state = CMD_AWAITING_ARGUMENT;
commandState.index = 0;
commandState.tokenIndices[0] = 0;
commandState.tokenCount = 0;
commandState.error = CYNTEC_CMD_SUCCESS;
commandState.argOffset = 0;
cyntecCurrentCommand = NULL;
commandState.totalIndex = 0; //gill
}
static uint8_t tokenLength(uint8_t num)
{
return (commandState.tokenIndices[num + 1]
- commandState.tokenIndices[num]);
}
static uint8_t *tokenPointer(uint8_t tokenNum)
{
return (commandState.buffer + commandState.tokenIndices[tokenNum]);
}
void cyntecCommandActionHandler(const CommandAction action)
{
(*action)();
clearBuffer();
}
static bool getNestedCommand(CyntecCommandEntry *entry,
CyntecCommandEntry **nestedCommand)
{
if ( entry -> action == NULL ) {
*nestedCommand = (CyntecCommandEntry*)entry->subMenu;
return true;
} else {
return false;
}
}
static void cyntecPrintCommandUsage(CyntecCommandEntry *entry)
{
CyntecCommandEntry *commandFinger;
if (entry == NULL) {
entry = commandFinger = cyntecCommandTable;
} else {
getNestedCommand(entry, &commandFinger);
console.printf("%s-%s\r\n",entry->name,entry->description);
}
if ( commandFinger != NULL ) {
for (; commandFinger->name != NULL; commandFinger++) {
console.printf("%s - %s\r\n",commandFinger->name,commandFinger->description);
}
}
}
void cyntecCommandErrorHandler(uint8_t status)
{
//Silvia 20161111 modify
console.printf("\r\nERROR;%s\r\n\r\n", cyntecCommandErrorNames[status]);
cyntecPrintCommandUsage(cyntecCurrentCommand);
}
static CyntecCommandEntry *commandLookup(CyntecCommandEntry *commandFinger,
uint8_t tokenNum)
{
uint8_t *inputCommand = tokenPointer(tokenNum);
uint8_t inputLength = tokenLength(tokenNum);
for (; commandFinger->name != NULL; commandFinger++) {
const char *entryFinger = commandFinger->name;
uint8_t *inputFinger = inputCommand;
for (;; entryFinger++, inputFinger++) {
bool endInput = (inputFinger - inputCommand == inputLength);
bool endEntry = (*entryFinger == 0);
if (endInput && endEntry) {
return commandFinger; // Exact match.
} else if ((*inputFinger) != (*entryFinger)) {
break;
}
}
}
return NULL;
}
void callCommandAction(void)
{
CyntecCommandEntry *commandFinger = cyntecCommandTable;
uint8_t tokenNum = 0;
if (commandState.tokenCount == 0) {
cyntecCommandReaderInit();
return;
}
// Lookup the command.
while (true) {
commandFinger = commandLookup(commandFinger, tokenNum);
if (commandFinger == NULL) {
commandState.error = CYNTEC_CMD_ERR_NO_SUCH_COMMAND;
break;
} else {
cyntecCurrentCommand = commandFinger;
tokenNum += 1;
commandState.argOffset += 1;
if ( getNestedCommand(commandFinger, &commandFinger) ) {
if (tokenNum >= commandState.tokenCount) {
commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS;
break;
}
} else {
break;
}
}
}
if (commandState.error == CYNTEC_CMD_SUCCESS) {
cyntecCommandActionHandler(commandFinger->action);
} else {
cyntecCommandErrorHandler(commandState.error);;
}
cyntecCommandReaderInit();
}
/*
*
*/
void cyntecEndArgument(uint8_t input)
{
if (commandState.tokenCount == MAX_TOKEN_COUNT) {
commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS;
commandState.state = CMD_READING_TO_EOL;
}
commandState.tokenCount += 1;
commandState.tokenIndices[commandState.tokenCount] = commandState.index;
commandState.state = CMD_AWAITING_ARGUMENT;
if (input == '\r' || input == '\n') {
callCommandAction();
}
}
/*
*
*/
void cyntecWriteToBuffer(uint8_t input)
{
if (commandState.index == CYNTEC_COMMAND_BUFFER_LENGTH) {
commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS;
commandState.state = CMD_READING_TO_EOL;
} else {
commandState.buffer[commandState.index] = input;
commandState.index += 1;
}
}
/*
* Process the given char as a command.
*/
void cyntecProcessCommandInput(uint8_t input) {
bool isEol = false;
bool isSpace = false;
if (previousCharacter == '\r' && input == '\n') {
previousCharacter = input;
return;
}
previousCharacter = input;
isEol = ((input == '\r') || (input == '\n'));
isSpace = (input == ' ');
switch (commandState.state) {
case CMD_AWAITING_ARGUMENT:
if (!isEol)
cyntecWriteToTotalBuffer(input); // total buffer including space
if (isEol) {
callCommandAction();
} else if (! isSpace) {
commandState.state = CMD_READING_ARGUMENT;
cyntecWriteToBuffer(input);
}
break;
case CMD_READING_ARGUMENT:
if (!isEol)
cyntecWriteToTotalBuffer(input);
if (isEol || isSpace) {
cyntecEndArgument(input);
} else {
cyntecWriteToBuffer(input);
}
break;
case CMD_READING_TO_EOL:
if (isEol) {
if (commandState.error != CYNTEC_CMD_SUCCESS) {
cyntecCommandErrorHandler(commandState.error);
}
cyntecCommandReaderInit();
}
break;
}
}
/** Retrieves unsigned integer arguments. */
uint8_t *cyntecGetCommandArgument(uint8_t argNum, uint8_t *length)
{
uint8_t tokenNum = argNum + commandState.argOffset;
if (length != NULL) {
*length = tokenLength(tokenNum);
}
return tokenPointer(tokenNum);
}
void clearBuffer(void)
{
uint16_t i;
for (i=0;i<CYNTEC_COMMAND_BUFFER_LENGTH;i++)
{
commandState.buffer[i] = NULL;
}
}
/** Retrieves the token count. */
uint8_t cyntecGetCommandTokenCnt()
{
return commandState.tokenCount;
}
/*
gill add for accept blank in name 20150904
uint8_t *cyntecGetCommandBuffer()
void cyntecWriteToTotalBuffer(uint8_t input)
uint8_t *cyntecGetCommandTotalBuffer(void)
uint8_t cyntecGetTotalIndex(void)
*/
void cyntecWriteToTotalBuffer(uint8_t input)
{
if (commandState.totalIndex == CYNTEC_COMMAND_BUFFER_LENGTH) {
commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS;
commandState.state = CMD_READING_TO_EOL;
} else {
commandState.totalBuffer[commandState.totalIndex] = input;
commandState.totalIndex += 1;
}
}
uint8_t *cyntecGetCommandTotalBuffer(void)
{
return commandState.totalBuffer;
}
uint8_t cyntecGetTotalIndex(void)
{
return commandState.totalIndex;
}
