This CLI (Command Line Interface) is based mbed-os. Both NNN50 and NQ620 are supported.
Fork of NNN40_CLI by
BLE CLI Document can be downloaded here .
Note that when evaluate using Windows PC as the host, the Serial driver need to be installed in advance. The instruction is explained in the link below
https://developer.mbed.org/handbook/Windows-serial-configuration
Once installed, a device called 'mbed Serial Port (COM#)' should be recognized in Device Manager, as shown below
Please open the com port at 115200 8n1 as default
CLI_Source/command-interpreter.cpp
- Committer:
- silviaChen
- Date:
- 2016-11-11
- Revision:
- 24:838a0b25934b
- Parent:
- 21:72d7a6e85d7f
File content as of revision 24:838a0b25934b:
/** * 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; }