editable serial input line buffer
Dependents: MAX5715BOB_Tester MAX11131BOB_Tester MAX5171BOB_Tester MAX11410BOB_Tester ... more
Diff: CmdLine.cpp
- Revision:
- 0:4d7de8b5c800
- Child:
- 1:5b33e7447601
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CmdLine.cpp Thu May 23 22:08:35 2019 +0000 @@ -0,0 +1,697 @@ +// /******************************************************************************* +// * Copyright (C) 2019 Maxim Integrated Products, Inc., All Rights Reserved. +// * +// * Permission is hereby granted, free of charge, to any person obtaining a +// * copy of this software and associated documentation files (the "Software"), +// * to deal in the Software without restriction, including without limitation +// * the rights to use, copy, modify, merge, publish, distribute, sublicense, +// * and/or sell copies of the Software, and to permit persons to whom the +// * Software is furnished to do so, subject to the following conditions: +// * +// * The above copyright notice and this permission notice shall be included +// * in all copies or substantial portions of the Software. +// * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES +// * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// * OTHER DEALINGS IN THE SOFTWARE. +// * +// * Except as contained in this notice, the name of Maxim Integrated +// * Products, Inc. shall not be used except as stated in the Maxim Integrated +// * Products, Inc. Branding Policy. +// * +// * The mere transfer of this software does not imply any licenses +// * of trade secrets, proprietary technology, copyrights, patents, +// * trademarks, maskwork rights, or any other form of intellectual +// * property whatsoever. Maxim Integrated Products, Inc. retains all +// * ownership rights. +// ******************************************************************************* +// */ +// ********************************************************************* +// @file CmdLine.cpp +// ********************************************************************* + +#include "CmdLine.h" + +CmdLine::CmdLine(Stream& AssociatedSerialPort, const char *Name) + : associatedSerialPort(AssociatedSerialPort) + , name(Name) + , onEOLcommandParser() +{ + indexOfNextEmptyCell = 0; + memset(buf, 0, COMMAND_BUFFER_LENGTH); +} +/** CmdLine::clear empties the command-line buffer */ +void CmdLine::clear(void) +{ + indexOfNextEmptyCell = 0; + memset(buf, 0, COMMAND_BUFFER_LENGTH); +} +//void CmdLine::idleAppendIfReadable() +//{ +// // append ch to buf, unless BS or EOL or other editing character +// // Polymorphism fail: associatedSerialPort.readable() +// if (associatedSerialPort.readable()) { +// append(associatedSerialPort.getc()); +// // +// // TODO1: set EOL timeout, so that we don't get lingering buffer cruft +// // +// } +//} +/** CmdLine::append handles an input character by appending the buffer, + * or handling an immediate function like backspace/delete + * or other custom immediate motor control functions. + */ +void CmdLine::append(char ch) +{ + void diagnostic_led_EOF(); + void main_menu_status(CmdLine & cmdLine); + + // append ch to buf, unless BS or EOL or other editing character + switch (ch) + { + case '\b': // Unicode (U+0008) BS BACKSPACE as destructive backspace + case '\x7f': // Unicode (U+007F) DEL DELETE as destructive backspace + if (indexOfNextEmptyCell > 0) + { + buf[--indexOfNextEmptyCell] = '\0'; // pre-decrement index, overwrite with null + associatedSerialPort.printf("\b \b"); // tty: backspace, overwrite with space, backspace + } + break; + case '\r': // Unicode (U+000D) CR CARRIAGE RETURN(CR) as EOL end of line + case '\n': // Unicode (U+000A) LF LINE FEED(LF) as EOL end of line + //associatedSerialPort.printf("%c", ch); // echo line end + associatedSerialPort.printf("\r\n"); // echo line end + //~ associatedSerialPort.printf("\r\n~%s~\r\n", buf); // DIAGNOSTIC: print line buffer + // parse and handle the command by invoking onEOLcommandParser callback + if (onEOLcommandParser) { + onEOLcommandParser(*this); + } + clear(); + break; +#define ECHO_EOF_IMMEDIATELY 1 +#if ECHO_EOF_IMMEDIATELY + case '\x04': // Unicode (U+0004) EOT END OF TRANSMISSION = CTRL+D as EOF end of file + diagnostic_led_EOF(); + //~ main_menu_status(*this); + associatedSerialPort.printf("** U+0004 EOT = EOF **"); // immediately echo EOF for test scripting + diagnostic_led_EOF(); + associatedSerialPort.printf("\r\n\x04\r\n"); // immediately echo EOF for test scripting + //~ associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting + //~ associatedSerialPort.printf("\x04"); // immediately echo EOF for test scripting + //~ associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting + clear(); // EOF discard any pending commands, to avoid surprise + break; + case '\x1a': // Unicode (U+001A) SUB SUBSTITUTE = CTRL+Z as EOF end of file + diagnostic_led_EOF(); + //~ main_menu_status(*this); + associatedSerialPort.printf("** U+001A SUB = EOF **"); // immediately echo EOF for test scripting + diagnostic_led_EOF(); + associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting + associatedSerialPort.printf("\x04"); // immediately echo EOF for test scripting + associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting + associatedSerialPort.printf("\x04"); // immediately echo EOF for test scripting + clear(); // EOF discard any pending commands, to avoid surprise + break; +#endif + // + // Support commands that get handled immediately w/o waiting for EOL + // Avoid using characters that may appear in other commands, + // such as 0-9 A-Z a-z and some punctuation %*+-./= + // so these 25 characters are available: !"#$&'(),:;<>?@[\]^_`{|}~ + //case '!': // immediate command !) example + // do_some_immediate_action(); + // clear(); + // break; + //case ' ': + // on_immediate_0x20(); // Unicode (U+0020) SPACE + // break; + case '!': + on_immediate_0x21(); // Unicode (U+0021) ! EXCLAMATION MARK + break; // handled as immediate command, do not append to buffer + case '{': + on_immediate_0x7b(); // Unicode (U+007B) { LEFT CURLY BRACKET + break; // handled as immediate command, do not append to buffer + case '}': + on_immediate_0x7d(); // Unicode (U+007D) } RIGHT CURLY BRACKET + break; // handled as immediate command, do not append to buffer + // + // default: + case '"': + //~ on_immediate_0x22(); // Unicode (U+0022) " QUOTATION MARK + //~ break; // handled as immediate command, do not append to buffer + case '#': + //~ on_immediate_0x23(); // Unicode (U+0023) # NUMBER SIGN = pound sign, hash, crosshatch + //~ break; // handled as immediate command, do not append to buffer + case '$': + //~ on_immediate_0x24(); // Unicode (U+0024) $ DOLLAR SIGN + //~ break; // handled as immediate command, do not append to buffer + //case '%': + // on_immediate_0x25(); // Unicode (U+0025) % PERCENT SIGN + // break; + case '&': + //~ on_immediate_0x26(); // Unicode (U+0026) & AMPERSAND + //~ break; // handled as immediate command, do not append to buffer + case '\'': + //~ on_immediate_0x27(); // Unicode (U+0027) ' APOSTROPHE + //~ break; // handled as immediate command, do not append to buffer + case '(': + //~ on_immediate_0x28(); // Unicode (U+0028) ( LEFT PARENTHESIS + //~ break; // handled as immediate command, do not append to buffer + case ')': + //~ on_immediate_0x29(); // Unicode (U+0029) ) RIGHT PARENTHESIS + //~ break; // handled as immediate command, do not append to buffer + //case '*': + // on_immediate_0x2a(); // Unicode (U+002A) * ASTERISK + // break; + //case '+': + // on_immediate_0x2b(); // Unicode (U+002B) + PLUS SIGN + // break; + case ',': + //~ on_immediate_0x2c(); // Unicode (U+002C) , COMMA + //~ break; // handled as immediate command, do not append to buffer + //case '-': + // on_immediate_0x2d(); // Unicode (U+002D) - HYPHEN-MINUS + // break; + //case '.': + // on_immediate_0x2e(); // Unicode (U+002E) . FULL STOP + // break; + //case '/': + // on_immediate_0x2f(); // Unicode (U+002F) / SOLIDUS =SLASH + // break; + case ':': + //~ on_immediate_0x3a(); // Unicode (U+003A) : COLON + //~ break; // handled as immediate command, do not append to buffer + case ';': + //~ on_immediate_0x3b(); // Unicode (U+003B) ; SEMICOLON + //~ break; // handled as immediate command, do not append to buffer + case '<': + //~ on_immediate_0x3c(); // Unicode (U+003C) < LESS-THAN SIGN + //~ break; // handled as immediate command, do not append to buffer + //case '=': + // on_immediate_0x3d(); // Unicode (U+003D) = EQUALS SIGN + // break; + case '>': + //~ on_immediate_0x3e(); // Unicode (U+003E) > GREATER-THAN SIGN + //~ break; // handled as immediate command, do not append to buffer + case '?': + //~ on_immediate_0x3f(); // Unicode (U+003F) ? QUESTION MARK + //~ break; // handled as immediate command, do not append to buffer + case '@': + //~ on_immediate_0x40(); // Unicode (U+0040) @ COMMERCIAL AT = at sign + //~ break; // handled as immediate command, do not append to buffer + case '[': + //~ on_immediate_0x5b(); // Unicode (U+005B) [ LEFT SQUARE BRACKET + //~ break; // handled as immediate command, do not append to buffer + case '\\': + //~ on_immediate_0x5c(); // Unicode (U+005C) \ REVERSE SOLIDUS + //~ break; // handled as immediate command, do not append to buffer + case ']': + //~ on_immediate_0x5d(); // Unicode (U+005D) ] RIGHT SQUARE BRACKET + //~ break; // handled as immediate command, do not append to buffer + case '^': + //~ on_immediate_0x5e(); // Unicode (U+005E) ^ CIRCUMFLEX ACCENT + //~ break; // handled as immediate command, do not append to buffer + case '_': + //~ on_immediate_0x5f(); // Unicode (U+005F) _ LOW LINE =SPACING UNDERSCORE + //~ break; // handled as immediate command, do not append to buffer + case '`': + //~ on_immediate_0x60(); // Unicode (U+0060) ` GRAVE ACCENT (also called backtick) + //~ break; // handled as immediate command, do not append to buffer + case '|': + //~ on_immediate_0x7c(); // Unicode (U+007C) | VERTICAL LINE + //~ break; // handled as immediate command, do not append to buffer + case '~': + //~ on_immediate_0x7e(); // Unicode (U+007E) ~ TILDE + //~ break; // handled as immediate command, do not append to buffer + // + default: + MBED_ASSERT(indexOfNextEmptyCell <= COMMAND_BUFFER_LENGTH - 2); + buf[indexOfNextEmptyCell++] = ch; // append character, post-increment index + buf[indexOfNextEmptyCell] = '\0'; // null-terminate the buffer + MBED_ASSERT(indexOfNextEmptyCell <= COMMAND_BUFFER_LENGTH - 1); + associatedSerialPort.printf("%c", ch); // echo + if (indexOfNextEmptyCell == COMMAND_BUFFER_LENGTH - 1) + { + // buffer is full, parse what we've got + if (onEOLcommandParser) { + onEOLcommandParser(*this); + } + clear(); + } + break; + } +} +# if HAS_DAPLINK_SERIAL +CmdLine cmdLine_DAPLINKserial(DAPLINKserial, "DAPLINK"); +# endif // HAS_DAPLINK_SERIAL +// TODO1: diagnostic: define HAS_MICROUSBSERIAL 0 +//~ #define HAS_MICROUSBSERIAL 0 +# if HAS_MICROUSBSERIAL +CmdLine cmdLine_microUSBserial(microUSBserial, "microUSB"); +# endif // HAS_MICROUSBSERIAL + +/** CmdLine::parse_and_remove_key matches "key" + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] valueBuf buffer is populated with the substring between key= and the first space delimiter (or end of string) + * @param[in] valueBufLen limits the size of valueBuf + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_and_remove_key(const char *key, char *valueBuf, size_t valueBufLen) +{ + // serial().printf("\r\n parse_and_remove_key(\"%s\")...", key); + // match key inside buf[]? + for (unsigned int idxSearch = 0; idxSearch < indexOfNextEmptyCell; idxSearch++) + { + if (buf[idxSearch] == '\0') { + // serial().printf("\r\n parse_and_remove_key(\"%s\") no match", key); + return false; /* no match */ + } + if (buf[idxSearch] != key[0]) { continue; } + // possible match; compare buf[idxSearch..] to key[0..] + unsigned int idxKey = idxSearch; // test whether buf[idxKey..] == key[0..] + unsigned int idxEqualSign = idxSearch; // test whether key=value pair + unsigned int idxSpace = idxSearch; // end of key=value word + for (unsigned int offset = 0; offset < strlen(key); offset++) + { + if (buf[idxKey + offset] != key[offset]) { idxKey = 0; break; } + idxSpace = idxKey + offset + 1; + idxEqualSign = idxKey + offset + 1; + if (buf[idxEqualSign] != '=') { idxEqualSign = 0; } + } + if (idxKey == 0) continue; // no match at idxSearch but keep searching + // ASSERT buf[idxKey..] == key[0..] + while ((buf[idxSpace] != ' ') && idxSpace < indexOfNextEmptyCell) { idxSpace++; } + // serial().printf("\r\n parse_and_remove_key(\"%s\") match at index %d length %d, '=' index %d, ' ' index %d", + // key, idxKey, strlen(key), idxEqualSign, idxSpace); + if (idxEqualSign != 0) { + // found key=value: copy buf[idxEqualSign+1..' '-1] into valueBuf[0..valueBufLen-1] + for (unsigned int offset = 0; offset < valueBufLen - 1; offset++) + { + if (buf[idxEqualSign + 1 + offset] == ' ') break; + valueBuf[offset] = buf[idxEqualSign + 1 + offset]; + valueBuf[offset + 1] = '\0'; + } + } else { + // found key but no =value: valueBuf[] = "" + valueBuf[0] = '\0'; + } + // on successful match, the key=value should be deleted from cmdbuf + //serial().printf("\r\n parse_and_remove_key(\"%s\") buf=\"%s\" valueBuf=\"%s\" before deleting key", + // key, buf, valueBuf); + for (unsigned int offset = 0; offset < indexOfNextEmptyCell; offset++) + { + unsigned int idxCopyDst = idxKey + offset; + unsigned int idxCopySrc = idxSpace + 1 + offset; + if (idxCopyDst > indexOfNextEmptyCell) break; + if (idxCopySrc > indexOfNextEmptyCell) break; + buf[idxCopyDst] = buf[idxCopySrc]; + } + // serial().printf("\r\n parse_and_remove_key(\"%s\") buf=\"%s\" valueBuf=\"%s\" after deleting key", + // key, buf, valueBuf); + // serial().printf("\r\n parse_and_remove_key(\"%s\") returning true: valueBuf=\"%s\"", key, valueBuf); + return true; + } + // serial().printf("\r\n parse_and_remove_key(\"%s\") no match", key); + return false; // no match +} + +/** CmdLine::parse_frequency_Hz matches "key"=digits + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] frequency_Hz updated from value string if match "key"=value, + * optional suffix kHz or MHz scales the value by 1000 or 10000000 + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_frequency_Hz(const char *key, uint32_t& frequency_Hz) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (SCLK=\d+(kHZ|MHZ)?)? --> g_SPI_SCLK_Hz + frequency_Hz = strtoul(valueBuf, NULL, 10); + if (strstr(valueBuf, "M")) { + frequency_Hz = frequency_Hz * 1000000; + } + if (strstr(valueBuf, "k")) { + frequency_Hz = frequency_Hz * 1000; + } + return true; + } + return false; // no match +} + +/** CmdLine::parse_flag matches "key"=0 or 1 + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] nFlagVar variable to be updated by setting or clearing bits specified by nFlagBitMask. + * If match "key"=0 then the nFlagBitMask bits in nFlagVar are cleared. + * If match "key"=1 then the nFlagBitMask bits in nFlagVar are set. + * @param[in] nFlagBitMask bit mask contains binary 1 in the bit to be controlled by the key=value setting + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_flag(const char *key, uint8_t& nFlagVar, const uint8_t nFlagBitMask) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (CPHA=\d)? --> g_SPI_dataMode | SPI_MODE1 + int x = strtoul(valueBuf, NULL, 10); + if (x) + { + nFlagVar |= nFlagBitMask; + } + else + { + nFlagVar &= ~nFlagBitMask; + } + return true; + } + return false; // no match +} + +/** CmdLine::parse_byte_hex matches "key"=value + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] nByteVar updated from value string if match "key"=value + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_byte_hex(const char *key, uint8_t& nByteVar) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress + // TODO1: parse_byte_hex take hex prefix 0x 0X or suffix $ h H + if (valueBuf[0] == '$') + { + nByteVar = strtoul(valueBuf + 1, NULL, 16); + return true; + } + if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x')) + { + nByteVar = strtoul(valueBuf + 2, NULL, 16); + return true; + } + nByteVar = strtoul(valueBuf, NULL, 16); + return true; + } + return false; // no match +} + +/** CmdLine::parse_byte_dec matches "key"=value + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] nByteVar updated from value string if match "key"=value + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_byte_dec(const char *key, uint8_t& nByteVar) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress + // TODO1: parse_byte_dec take hex prefix 0x 0X or suffix $ h H + if (valueBuf[0] == '$') + { + nByteVar = strtoul(valueBuf + 1, NULL, 16); + return true; + } + if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x')) + { + nByteVar = strtoul(valueBuf + 2, NULL, 16); + return true; + } + nByteVar = strtoul(valueBuf, NULL, 10); + return true; + } + return false; // no match +} + +/** CmdLine::parse_uint16_hex matches "key"=value + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] uint16Var updated from value string if match "key"=value + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_uint16_hex(const char *key, uint16_t& uint16Var) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress + // TODO1: parse_byte_hex take hex prefix 0x 0X or suffix $ h H + if (valueBuf[0] == '$') + { + uint16Var = strtoul(valueBuf + 1, NULL, 16); + return true; + } + if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x')) + { + uint16Var = strtoul(valueBuf + 2, NULL, 16); + return true; + } + uint16Var = strtoul(valueBuf, NULL, 16); + return true; + } + return false; // no match +} + +/** CmdLine::parse_int16_hex matches "key"=value + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] int16Var updated from value string if match "key"=value + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_int16_hex(const char *key, int16_t& int16Var) +{ + char valueBuf[16]; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + // ASSERT: buf[matched_index] contains '=' followed by value + // parse cmdLine arg (CMD=\d)? --> g_I2C_command_regAddress + // TODO1: parse_byte_hex take hex prefix 0x 0X or suffix $ h H + if (valueBuf[0] == '$') + { + int16Var = strtoul(valueBuf + 1, NULL, 16); + return true; + } + if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x')) + { + int16Var = strtoul(valueBuf + 2, NULL, 16); + return true; + } + int16Var = strtoul(valueBuf, NULL, 16); + return true; + } + return false; // no match +} + +/** CmdLine::parse_float matches "key"=value + * + * @return true if keyword was found in buffer + * @param[in] key string value to match + * @param[out] floatVar updated from value string if match "key"=value + * + * @post on successful match, the key=value substring is deleted from cmdbuf + * + */ +bool CmdLine::parse_float(const char *key, float& floatVar) +{ + char valueBuf[16]; + char *end; + // bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen); + if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf))) + { + floatVar = strtof(valueBuf, &end); + return true; + } + return false; // no match +} + +/** CmdLine::parse_byteCount_byteList_hex matches hexadecimal digits separated by spaces. + * The 0x / 0X prefix is optional. The numbers must be hexadecimal. + * + * @return true if more than one hex byte found in buffer + * @param[out] byteCount is populated with the number of hex bytes found + * @param[out] mosiDataBuf buffer mosiDataBuf[0..byteCount-1] is populated with the hex bytes found + * @param[in] mosiDataBufSize limits the number of bytes that will be used + * + */ +bool CmdLine::parse_byteCount_byteList_hex(size_t& byteCount, char *mosiDataBuf, size_t mosiDataBufSize) +{ + //serial().printf("\r\n parse_byteCount_byteList_hex (buf=\"%s\")...", buf); + // parse cmdLine hex byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT]; + byteCount = 0; + bool got_value = false; + uint8_t nybbleValue; + uint8_t temp_value = 0; + for (unsigned int idxSearch = 0; idxSearch < indexOfNextEmptyCell; idxSearch++) + { + if (buf[idxSearch] == '\0') { + break; // end of buffer + } + switch (buf[idxSearch]) + { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + nybbleValue = buf[idxSearch] - '0'; + temp_value = temp_value * 0x10; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + nybbleValue = buf[idxSearch] - 'a' + 0x0a; + temp_value = temp_value * 0x10; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + nybbleValue = buf[idxSearch] - 'A' + 0x0a; + temp_value = temp_value * 0x10; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'x': case 'X': + temp_value = 0; + break; + case ' ': case ',': + if ((got_value) && (byteCount < mosiDataBufSize)) + { + //serial().printf("\r\n parse_byteCount_byteList_hex mosiDataBuf[%d] = 0x%2.2x", byteCount, temp_value); + mosiDataBuf[byteCount++] = temp_value; + temp_value = 0; + got_value = false; + } + break; + } + } // for idxSearch + if ((got_value) && (byteCount < mosiDataBufSize)) + { + //serial().printf("\r\n parse_byteCount_byteList_hex mosiDataBuf[%d] = 0x%2.2x", byteCount, temp_value); + mosiDataBuf[byteCount++] = temp_value; + temp_value = 0; + got_value = false; + } + //serial().printf("\r\n parse_byteCount_byteList_hex (buf=\"%s\") returning: byteCount=%d", buf, byteCount); + return (byteCount > 0); +} + +/** CmdLine::parse_byteCount_byteList_dec matches a list of numbers, separated by spaces. + * The 0x / 0X prefix may be used to select hexadecimal instead of decimal. + * + * @return true if more than one number found in buffer + * @param[out] byteCount is populated with the number of numbers found + * @param[out] mosiDataBuf buffer mosiDataBuf[0..byteCount-1] is populated with the numbers found + * @param[in] mosiDataBufSize limits the number of bytes that will be used + * + */ +bool CmdLine::parse_byteCount_byteList_dec(size_t& byteCount, char *mosiDataBuf, size_t mosiDataBufSize) +{ + //serial().printf("\r\n parse_byteCount_byteList_dec (buf=\"%s\")...", buf); + // parse cmdLine hex byte list --> int byteCount; int mosiData[MAX_SPI_BYTE_COUNT]; + byteCount = 0; + bool got_value = false; + uint8_t nybbleValue; + uint8_t temp_value = 0; + uint8_t radix = 10; + for (unsigned int idxSearch = 0; idxSearch < indexOfNextEmptyCell; idxSearch++) + { + if (buf[idxSearch] == '\0') { + break; // end of buffer + } + switch (buf[idxSearch]) + { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + nybbleValue = buf[idxSearch] - '0'; + temp_value = temp_value * radix; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + nybbleValue = buf[idxSearch] - 'a' + 0x0a; + radix = 0x10; + temp_value = temp_value * radix; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + nybbleValue = buf[idxSearch] - 'A' + 0x0a; + radix = 0x10; + temp_value = temp_value * radix; + temp_value = temp_value + nybbleValue; + got_value = true; + break; + case 'x': case 'X': + temp_value = 0; + radix = 0x10; + break; + case ' ': case ',': + if ((got_value) && (byteCount < mosiDataBufSize)) + { + //serial().printf("\r\n parse_byteCount_byteList_dec mosiDataBuf[%d] = 0x%2.2x", byteCount, temp_value); + mosiDataBuf[byteCount++] = temp_value; + temp_value = 0; + radix = 10; + got_value = false; + } + break; + } + } // for idxSearch + if ((got_value) && (byteCount < mosiDataBufSize)) + { + //serial().printf("\r\n parse_byteCount_byteList_dec mosiDataBuf[%d] = 0x%2.2x", byteCount, temp_value); + mosiDataBuf[byteCount++] = temp_value; + temp_value = 0; + got_value = false; + } + //serial().printf("\r\n parse_byteCount_byteList_dec (buf=\"%s\") returning: byteCount=%d", buf, byteCount); + return (byteCount > 0); +} + + +// End of file +