CLI example for NNN50
Dependencies: NNN50_WIFI_API
Fork of NNN50_WiFi_HelloWorld by
Diff: CLI_Source/command-interpreter.cpp
- Revision:
- 9:871fc0231c7f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CLI_Source/command-interpreter.cpp Thu Sep 14 01:48:08 2017 +0000 @@ -0,0 +1,501 @@ +/** + * 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; +} + +