Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
