CLI example for NNN50

Dependencies:   NNN50_WIFI_API

Fork of NNN50_WiFi_HelloWorld by Delta

Revision:
9:871fc0231c7f
diff -r 08230913074f -r 871fc0231c7f CLI_Source/command-interpreter.cpp
--- /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;
+}
+
+