This CLI (Command Line Interface) is based mbed-os. Both NNN50 and NQ620 are supported.
Fork of NNN40_CLI by
command-interpreter.cpp
00001 /** 00002 * File: command-interpreter.c 00003 * Description: processes commands incoming over the serial port. 00004 * 00005 * Copyright 2014 by CYNTEC Corporation. All rights reserved. 00006 */ 00007 00008 #include <stdint.h> 00009 #include <string.h> 00010 #include "mbed.h" 00011 #include "command-interpreter.h" 00012 00013 extern Serial console; 00014 00015 // Command parsing state 00016 typedef struct { 00017 00018 // Finite-state machine's current state. 00019 uint8_t state; 00020 00021 // The command line is stored in this buffer. 00022 uint8_t buffer[CYNTEC_COMMAND_BUFFER_LENGTH]; 00023 00024 // Indices of the tokens (command(s) and arguments) in the above buffer. 00025 uint8_t tokenIndices[MAX_TOKEN_COUNT]; 00026 00027 // The number of tokens read in, including the command(s). 00028 uint8_t tokenCount; 00029 00030 // Used while reading in the command line. 00031 uint8_t index; 00032 00033 // First error found in this command. 00034 uint8_t error; 00035 00036 // The token number of the first true argument after possible nested commands. 00037 uint8_t argOffset; 00038 00039 //gill 00040 uint8_t totalBuffer[CYNTEC_COMMAND_BUFFER_LENGTH]; 00041 uint8_t totalIndex; 00042 00043 } CyntecCommandState; 00044 00045 static CyntecCommandState commandState; 00046 00047 // Remember the previous character seen by emberProcessCommandString() to ignore 00048 // an LF following a CR. 00049 static uint8_t previousCharacter = 0; 00050 CyntecCommandEntry *cyntecCurrentCommand; 00051 00052 enum { 00053 CMD_AWAITING_ARGUMENT, 00054 CMD_READING_ARGUMENT, 00055 CMD_READING_TO_EOL // clean up after error 00056 }; 00057 00058 00059 00060 const char* cyntecCommandErrorNames[] = 00061 { 00062 "", 00063 "No such command;", 00064 "Wrong number of arguments;", 00065 "Argument out of range;", 00066 "Argument syntax error;", 00067 "No matched argument;", 00068 "Wrong command order;", 00069 "Invalid state to perform operation;", 00070 "Function call fail;" 00071 }; 00072 00073 /** 00074 * @brief Converts a character representation of a hex to real value. 00075 * @param c is the hex value in char format 00076 * @return the value of the hex otherwise INVALID_HEX_CHARACTER 00077 */ 00078 00079 uint8_t cyntecAtoi(uint8_t *str, uint8_t len) 00080 { 00081 uint8_t result = 0; 00082 uint8_t i = 0; 00083 00084 while( *str != '\0' && i < len) 00085 { 00086 result *= 10; 00087 result = result + ( *str - '0' ); 00088 str++; 00089 i++; 00090 } 00091 00092 return result; 00093 } 00094 int cyntecAtoInt(uint8_t *str) 00095 { 00096 int result = 0; 00097 uint8_t i = 0; 00098 bool is_negative = false; 00099 00100 if (*str == '-') { 00101 is_negative = true; 00102 str++; 00103 } 00104 while( *str != '\0') 00105 { 00106 result *= 10; 00107 result = result + ( *str - '0' ); 00108 str++; 00109 i++; 00110 } 00111 00112 if (is_negative) 00113 return -result; 00114 else 00115 return result; 00116 } 00117 uint8_t cyntecArgToUint8(uint8_t *str, uint8_t len) 00118 { 00119 uint8_t result = 0; 00120 uint8_t num[2]; 00121 uint8_t i; 00122 00123 if ( len != 2 ) 00124 { 00125 return 0; 00126 } 00127 00128 for ( i = 0 ; i < 2 ; i++ ) 00129 { 00130 if ('0' <= str[i] && str[i] <= '9') 00131 num[i] = str[i] - '0'; 00132 else if ('a' <= str[i] && str[i] <= 'f') 00133 num[i] = str[i] - 'a' + 10; 00134 else if ('A' <= str[i] && str[i] <= 'F') 00135 num[i] = str[i] - 'A' + 10; 00136 else 00137 return 0; 00138 } 00139 00140 result |= num[0] << 4; 00141 result |= num[1] << 0; 00142 00143 return result; 00144 } 00145 00146 uint16_t cyntecAtoiUint16(uint8_t *str, uint8_t len) 00147 { 00148 uint16_t result = 0; 00149 uint16_t i = 0; 00150 00151 while( *str != '\0' && i < len) 00152 { 00153 result *= 10; 00154 result = result + ( *str - '0' ); 00155 str++; 00156 i++; 00157 } 00158 00159 return result; 00160 } 00161 00162 uint16_t cyntecArgToUint16(uint8_t *str, uint8_t len) 00163 { 00164 uint16_t result = 0; 00165 uint8_t num[4]; 00166 uint8_t i; 00167 00168 if ( len != 4 ) 00169 { 00170 return 0; 00171 } 00172 00173 for ( i = 0 ; i < 4 ; i++ ) 00174 { 00175 if ('0' <= str[i] && str[i] <= '9') 00176 num[i] = str[i] - '0'; 00177 else if ('a' <= str[i] && str[i] <= 'f') 00178 num[i] = str[i] - 'a' + 10; 00179 else if ('A' <= str[i] && str[i] <= 'F') 00180 num[i] = str[i] - 'A' + 10; 00181 else 00182 return 0; 00183 } 00184 00185 result |= num[0] << 12; 00186 result |= num[1] << 8; 00187 result |= num[2] << 4; 00188 result |= num[3] << 0; 00189 00190 return result; 00191 } 00192 00193 //gill 20150918 00194 uint32_t cyntecHexToUint32(uint8_t *str, uint8_t len) 00195 { 00196 if (len > 8) 00197 return 0; 00198 uint32_t result = 0; 00199 uint16_t i = 0; 00200 00201 while( *str != '\0' && i < len) 00202 { 00203 result *= 16; 00204 result = result + ( *str - '0' ); 00205 str++; 00206 i++; 00207 } 00208 00209 return result; 00210 } 00211 00212 00213 00214 00215 uint8_t cyntecStrCmp(uint8_t *src, uint8_t *dst, uint8_t len) 00216 { 00217 uint8_t i = 0; 00218 00219 while ( *src != '\0' && *dst != '\0' && i < len ) 00220 { 00221 if ( *src != *dst ) 00222 return 0; 00223 i++; 00224 src++; 00225 dst++; 00226 } 00227 00228 return 1; 00229 } 00230 00231 // Initialize the state machine. 00232 void cyntecCommandReaderInit(void) 00233 { 00234 commandState.state = CMD_AWAITING_ARGUMENT; 00235 commandState.index = 0; 00236 commandState.tokenIndices[0] = 0; 00237 commandState.tokenCount = 0; 00238 commandState.error = CYNTEC_CMD_SUCCESS; 00239 commandState.argOffset = 0; 00240 cyntecCurrentCommand = NULL; 00241 commandState.totalIndex = 0; //gill 00242 } 00243 00244 static uint8_t tokenLength(uint8_t num) 00245 { 00246 return (commandState.tokenIndices[num + 1] 00247 - commandState.tokenIndices[num]); 00248 } 00249 00250 static uint8_t *tokenPointer(uint8_t tokenNum) 00251 { 00252 return (commandState.buffer + commandState.tokenIndices[tokenNum]); 00253 } 00254 00255 void cyntecCommandActionHandler(const CommandAction action) 00256 { 00257 (*action)(); 00258 clearBuffer(); 00259 } 00260 00261 static bool getNestedCommand(CyntecCommandEntry *entry, 00262 CyntecCommandEntry **nestedCommand) 00263 { 00264 if ( entry -> action == NULL ) { 00265 *nestedCommand = (CyntecCommandEntry*)entry->subMenu; 00266 return true; 00267 } else { 00268 return false; 00269 } 00270 } 00271 00272 static void cyntecPrintCommandUsage(CyntecCommandEntry *entry) 00273 { 00274 CyntecCommandEntry *commandFinger; 00275 00276 if (entry == NULL) { 00277 entry = commandFinger = cyntecCommandTable; 00278 } else { 00279 getNestedCommand(entry, &commandFinger); 00280 00281 console.printf("%s-%s\r\n",entry->name,entry->description); 00282 } 00283 00284 if ( commandFinger != NULL ) { 00285 for (; commandFinger->name != NULL; commandFinger++) { 00286 console.printf("%s - %s\r\n",commandFinger->name,commandFinger->description); 00287 } 00288 } 00289 00290 } 00291 00292 void cyntecCommandErrorHandler(uint8_t status) 00293 { 00294 //Silvia 20161111 modify 00295 console.printf("\r\nERROR;%s\r\n\r\n", cyntecCommandErrorNames[status]); 00296 cyntecPrintCommandUsage(cyntecCurrentCommand); 00297 } 00298 00299 static CyntecCommandEntry *commandLookup(CyntecCommandEntry *commandFinger, 00300 uint8_t tokenNum) 00301 { 00302 uint8_t *inputCommand = tokenPointer(tokenNum); 00303 uint8_t inputLength = tokenLength(tokenNum); 00304 00305 for (; commandFinger->name != NULL; commandFinger++) { 00306 const char *entryFinger = commandFinger->name; 00307 uint8_t *inputFinger = inputCommand; 00308 for (;; entryFinger++, inputFinger++) { 00309 bool endInput = (inputFinger - inputCommand == inputLength); 00310 bool endEntry = (*entryFinger == 0); 00311 if (endInput && endEntry) { 00312 return commandFinger; // Exact match. 00313 } else if ((*inputFinger) != (*entryFinger)) { 00314 break; 00315 } 00316 } 00317 } 00318 return NULL; 00319 } 00320 00321 void callCommandAction(void) 00322 { 00323 CyntecCommandEntry *commandFinger = cyntecCommandTable; 00324 uint8_t tokenNum = 0; 00325 00326 if (commandState.tokenCount == 0) { 00327 cyntecCommandReaderInit(); 00328 return; 00329 } 00330 00331 // Lookup the command. 00332 while (true) { 00333 commandFinger = commandLookup(commandFinger, tokenNum); 00334 if (commandFinger == NULL) { 00335 commandState.error = CYNTEC_CMD_ERR_NO_SUCH_COMMAND; 00336 break; 00337 } else { 00338 cyntecCurrentCommand = commandFinger; 00339 tokenNum += 1; 00340 commandState.argOffset += 1; 00341 00342 if ( getNestedCommand(commandFinger, &commandFinger) ) { 00343 if (tokenNum >= commandState.tokenCount) { 00344 commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS; 00345 break; 00346 } 00347 } else { 00348 break; 00349 } 00350 } 00351 } 00352 00353 if (commandState.error == CYNTEC_CMD_SUCCESS) { 00354 cyntecCommandActionHandler(commandFinger->action); 00355 } else { 00356 cyntecCommandErrorHandler(commandState.error);; 00357 } 00358 00359 cyntecCommandReaderInit(); 00360 } 00361 00362 /* 00363 * 00364 */ 00365 void cyntecEndArgument(uint8_t input) 00366 { 00367 if (commandState.tokenCount == MAX_TOKEN_COUNT) { 00368 commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS; 00369 commandState.state = CMD_READING_TO_EOL; 00370 } 00371 00372 commandState.tokenCount += 1; 00373 commandState.tokenIndices[commandState.tokenCount] = commandState.index; 00374 commandState.state = CMD_AWAITING_ARGUMENT; 00375 00376 if (input == '\r' || input == '\n') { 00377 callCommandAction(); 00378 } 00379 } 00380 00381 /* 00382 * 00383 */ 00384 void cyntecWriteToBuffer(uint8_t input) 00385 { 00386 if (commandState.index == CYNTEC_COMMAND_BUFFER_LENGTH) { 00387 commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS; 00388 commandState.state = CMD_READING_TO_EOL; 00389 } else { 00390 commandState.buffer[commandState.index] = input; 00391 commandState.index += 1; 00392 } 00393 } 00394 00395 00396 /* 00397 * Process the given char as a command. 00398 */ 00399 void cyntecProcessCommandInput(uint8_t input) { 00400 00401 bool isEol = false; 00402 bool isSpace = false; 00403 00404 if (previousCharacter == '\r' && input == '\n') { 00405 previousCharacter = input; 00406 return; 00407 } 00408 00409 previousCharacter = input; 00410 isEol = ((input == '\r') || (input == '\n')); 00411 isSpace = (input == ' '); 00412 00413 switch (commandState.state) { 00414 case CMD_AWAITING_ARGUMENT: 00415 if (!isEol) 00416 cyntecWriteToTotalBuffer(input); // total buffer including space 00417 if (isEol) { 00418 callCommandAction(); 00419 } else if (! isSpace) { 00420 commandState.state = CMD_READING_ARGUMENT; 00421 cyntecWriteToBuffer(input); 00422 } 00423 break; 00424 case CMD_READING_ARGUMENT: 00425 if (!isEol) 00426 cyntecWriteToTotalBuffer(input); 00427 if (isEol || isSpace) { 00428 cyntecEndArgument(input); 00429 } else { 00430 cyntecWriteToBuffer(input); 00431 } 00432 break; 00433 case CMD_READING_TO_EOL: 00434 if (isEol) { 00435 if (commandState.error != CYNTEC_CMD_SUCCESS) { 00436 cyntecCommandErrorHandler(commandState.error); 00437 } 00438 cyntecCommandReaderInit(); 00439 } 00440 break; 00441 } 00442 } 00443 00444 00445 /** Retrieves unsigned integer arguments. */ 00446 uint8_t *cyntecGetCommandArgument(uint8_t argNum, uint8_t *length) 00447 { 00448 uint8_t tokenNum = argNum + commandState.argOffset; 00449 00450 if (length != NULL) { 00451 *length = tokenLength(tokenNum); 00452 } 00453 return tokenPointer(tokenNum); 00454 } 00455 00456 void clearBuffer(void) 00457 { 00458 uint16_t i; 00459 for (i=0;i<CYNTEC_COMMAND_BUFFER_LENGTH;i++) 00460 { 00461 commandState.buffer[i] = NULL; 00462 } 00463 } 00464 00465 /** Retrieves the token count. */ 00466 uint8_t cyntecGetCommandTokenCnt() 00467 { 00468 return commandState.tokenCount; 00469 } 00470 00471 /* 00472 gill add for accept blank in name 20150904 00473 uint8_t *cyntecGetCommandBuffer() 00474 void cyntecWriteToTotalBuffer(uint8_t input) 00475 uint8_t *cyntecGetCommandTotalBuffer(void) 00476 uint8_t cyntecGetTotalIndex(void) 00477 */ 00478 00479 00480 void cyntecWriteToTotalBuffer(uint8_t input) 00481 { 00482 if (commandState.totalIndex == CYNTEC_COMMAND_BUFFER_LENGTH) { 00483 commandState.error = CYNTEC_CMD_ERR_WRONG_NUMBER_OF_ARGUMENTS; 00484 commandState.state = CMD_READING_TO_EOL; 00485 } else { 00486 commandState.totalBuffer[commandState.totalIndex] = input; 00487 commandState.totalIndex += 1; 00488 } 00489 } 00490 00491 uint8_t *cyntecGetCommandTotalBuffer(void) 00492 { 00493 return commandState.totalBuffer; 00494 } 00495 00496 uint8_t cyntecGetTotalIndex(void) 00497 { 00498 return commandState.totalIndex; 00499 } 00500 00501
Generated on Tue Jul 12 2022 21:48:15 by 1.7.2