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.
Dependents: MAX5715BOB_Tester MAX11131BOB_Tester MAX5171BOB_Tester MAX11410BOB_Tester ... more
CmdLine.cpp
- Committer:
- whismanoid
- Date:
- 2021-11-30
- Revision:
- 19:b14922500968
- Parent:
- 18:2c3c44a34d81
- Child:
- 20:92a1fb8a5732
File content as of revision 19:b14922500968:
// /*******************************************************************************
// * 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"
// toupper requires include <ctype.h>
#include <ctype.h>
CmdLine::CmdLine(Stream& AssociatedSerialPort, const char *Name)
: associatedSerialPort(AssociatedSerialPort)
, name(Name)
, onEOLcommandParser()
{
indexOfNextEmptyCell = 0;
memset(buf, 0, COMMAND_BUFFER_LENGTH);
chSeparator = 0;
match_is_case_sensitive = false;
quiet = false;
}
/** 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
if (!quiet) 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
if (!quiet) 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
if (diagnostic_led_EOF) { diagnostic_led_EOF(); }
//~ main_menu_status(*this);
if (!quiet) associatedSerialPort.printf("** U+0004 EOT = EOF **"); // immediately echo EOF for test scripting
if (diagnostic_led_EOF) { diagnostic_led_EOF(); }
if (!quiet) 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
if (diagnostic_led_EOF) { diagnostic_led_EOF(); }
//~ main_menu_status(*this);
if (!quiet) associatedSerialPort.printf("** U+001A SUB = EOF **"); // immediately echo EOF for test scripting
if (diagnostic_led_EOF) { diagnostic_led_EOF(); }
if (!quiet) associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting
if (!quiet) associatedSerialPort.printf("\x04"); // immediately echo EOF for test scripting
if (!quiet) associatedSerialPort.printf("\x1a"); // immediately echo EOF for test scripting
if (!quiet) 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;
//
// Note: these on_immediate case may fall through, by design.
// #if __GNUC__
// #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
// #endif
#if 1
case '!':
//~ on_immediate_0x21(); // Unicode (U+0021) ! EXCLAMATION MARK
//~ break; // handled as immediate command, do not append to buffer
if (on_immediate_0x21) {
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
if (on_immediate_0x7b) {
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
if (on_immediate_0x7d) {
on_immediate_0x7d(); // Unicode (U+007D) } RIGHT CURLY BRACKET
break; // handled as immediate command, do not append to buffer
}
//
// default:
case '"':
if (on_immediate_0x22) {
on_immediate_0x22(); // Unicode (U+0022) " QUOTATION MARK
break; // handled as immediate command, do not append to buffer
}
case '#':
if (on_immediate_0x23) {
on_immediate_0x23(); // Unicode (U+0023) # NUMBER SIGN = pound sign, hash, crosshatch
break; // handled as immediate command, do not append to buffer
}
case '$':
if (on_immediate_0x24) {
on_immediate_0x24(); // Unicode (U+0024) $ DOLLAR SIGN
break; // handled as immediate command, do not append to buffer
}
//~ 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 '&':
if (on_immediate_0x26) {
on_immediate_0x26(); // Unicode (U+0026) & AMPERSAND
break; // handled as immediate command, do not append to buffer
}
case '\'':
if (on_immediate_0x27) {
on_immediate_0x27(); // Unicode (U+0027) ' APOSTROPHE
break; // handled as immediate command, do not append to buffer
}
case '(':
if (on_immediate_0x28) {
on_immediate_0x28(); // Unicode (U+0028) ( LEFT PARENTHESIS
break; // handled as immediate command, do not append to buffer
}
case ')':
if (on_immediate_0x29) {
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 ',':
if (on_immediate_0x2c) {
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 ':':
if (on_immediate_0x3a) {
on_immediate_0x3a(); // Unicode (U+003A) : COLON
break; // handled as immediate command, do not append to buffer
}
case ';':
if (on_immediate_0x3b) {
on_immediate_0x3b(); // Unicode (U+003B) ; SEMICOLON
break; // handled as immediate command, do not append to buffer
}
case '<':
if (on_immediate_0x3c) {
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 '>':
if (on_immediate_0x3e) {
on_immediate_0x3e(); // Unicode (U+003E) > GREATER-THAN SIGN
break; // handled as immediate command, do not append to buffer
}
case '?':
if (on_immediate_0x3f) {
on_immediate_0x3f(); // Unicode (U+003F) ? QUESTION MARK
break; // handled as immediate command, do not append to buffer
}
case '@':
if (on_immediate_0x40) {
on_immediate_0x40(); // Unicode (U+0040) @ COMMERCIAL AT = at sign
break; // handled as immediate command, do not append to buffer
}
case '[':
if (on_immediate_0x5b) {
on_immediate_0x5b(); // Unicode (U+005B) [ LEFT SQUARE BRACKET
break; // handled as immediate command, do not append to buffer
}
case '\\':
if (on_immediate_0x5c) {
on_immediate_0x5c(); // Unicode (U+005C) \ REVERSE SOLIDUS
break; // handled as immediate command, do not append to buffer
}
case ']':
if (on_immediate_0x5d) {
on_immediate_0x5d(); // Unicode (U+005D) ] RIGHT SQUARE BRACKET
break; // handled as immediate command, do not append to buffer
}
case '^':
if (on_immediate_0x5e) {
on_immediate_0x5e(); // Unicode (U+005E) ^ CIRCUMFLEX ACCENT
break; // handled as immediate command, do not append to buffer
}
case '_':
if (on_immediate_0x5f) {
on_immediate_0x5f(); // Unicode (U+005F) _ LOW LINE =SPACING UNDERSCORE
break; // handled as immediate command, do not append to buffer
}
case '`':
if (on_immediate_0x60) {
on_immediate_0x60(); // Unicode (U+0060) ` GRAVE ACCENT (also called backtick)
break; // handled as immediate command, do not append to buffer
}
case '|':
if (on_immediate_0x7c) {
on_immediate_0x7c(); // Unicode (U+007C) | VERTICAL LINE
break; // handled as immediate command, do not append to buffer
}
case '~':
if (on_immediate_0x7e) {
on_immediate_0x7e(); // Unicode (U+007E) ~ TILDE
break; // handled as immediate command, do not append to buffer
}
#endif
// #if __GNUC__
// #pragma GCC diagnostic pop
// #endif
// Note: these on_immediate case may fall through, by design.
//
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);
if (!quiet) 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;
}
}
/** 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
* @post chSeparator is populated with the separator character '=' or '?' following key=, or null character if no separator
*
*/
bool CmdLine::parse_and_remove_key(const char *key, char *valueBuf, size_t valueBufLen)
{
bool verbose = false;
if (verbose) { 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') {
if (verbose) { serial().printf("\r\n parse_and_remove_key(\"%s\") no match", key); }
return false; /* no match */
}
if (match_is_case_sensitive) {
// case-sensitive string comparison
if (buf[idxSearch] != key[0]) { continue; }
}
else {
// case-insensitive string comparison using toupper()
if (toupper(buf[idxSearch]) != toupper(key[0])) { continue; }
}
// possible match; compare buf[idxSearch..] to key[0..]
unsigned int idxKey = idxSearch; // test whether buf[idxKey..] == key[0..]
unsigned int idxSeparator = 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 (match_is_case_sensitive) {
// case-sensitive string comparison
if (buf[idxKey + offset] != key[offset]) { idxKey = 0; break; }
}
else {
// case-insensitive string comparison using toupper()
if (toupper(buf[idxKey + offset]) != toupper(key[offset])) { idxKey = 0; break; }
}
idxSpace = idxKey + offset + 1; // assume next char is a word break
idxSeparator = idxKey + offset + 1; // assume next char is a separator
if ((buf[idxSeparator] != '=') && (buf[idxSeparator] != '?')) { idxSeparator = 0; }
}
if (idxKey == 0) continue; // no match at idxSearch but keep searching
// ASSERT buf[idxKey..] == key[0..]
while ((buf[idxSpace] != ' ') && idxSpace < indexOfNextEmptyCell) { idxSpace++; }
if (verbose) {
serial().printf("\r\n parse_and_remove_key(\"%s\") match at index %d length %d, '=' index %d, ' ' index %d",
key, idxKey, strlen(key), idxSeparator, idxSpace);
}
if (idxSeparator != 0) {
// found key=value: copy buf[idxSeparator+1..' '-1] into valueBuf[0..valueBufLen-1]
chSeparator = buf[idxSeparator];
for (unsigned int offset = 0; offset < valueBufLen - 1; offset++)
{
if (buf[idxSeparator + 1 + offset] == ' ') break;
valueBuf[offset] = buf[idxSeparator + 1 + offset];
valueBuf[offset + 1] = '\0';
}
} else {
// found key but no =value: valueBuf[] = ""
chSeparator = '\0';
valueBuf[0] = '\0';
}
// on successful match, the key=value should be deleted from cmdbuf
if (verbose) {
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;
// cmdLine final key=value arg wrongly included in parse_byteCount_byteList_ buffer #358
// if (idxCopySrc > indexOfNextEmptyCell) break;
if (idxCopySrc > indexOfNextEmptyCell)
{
buf[idxCopyDst] = ' ';
continue;
}
buf[idxCopyDst] = buf[idxCopySrc];
}
if (verbose) {
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;
}
if (verbose) { serial().printf("\r\n parse_and_remove_key(\"%s\") no match", key); }
return false; // no match
}
/** CmdLine::parse_and_remove_key_and_arrayIndex matches "key" with array indexing
*
* @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
* @post chSeparator is populated with the separator character '=' or '?' following key=, or null character if no separator
* @post *pindex is populated with the array index value
*
*/
bool CmdLine::parse_and_remove_key_and_arrayIndex(const char *key, size_t *pindex, char *valueBuf, size_t valueBufLen)
{
// WIP #347 - parse_and_remove_key_and_arrayIndex(const char *key, size_t *pindex, char *valueBuf, int valueBufLen) based on parse_and_remove_key
// Work in Progress
// match (key) "[" (index:[0-9]+) "]"
//
bool verbose = false;
if (verbose) { serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\")...", key); }
// match key inside buf[]?
for (unsigned int idxSearch = 0; idxSearch < indexOfNextEmptyCell; idxSearch++)
{
if (buf[idxSearch] == '\0') {
if (verbose) { serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") no match", key); }
return false; /* no match */
}
if (match_is_case_sensitive) {
// case-sensitive string comparison
if (buf[idxSearch] != key[0]) { continue; }
}
else {
// case-insensitive string comparison using toupper()
if (toupper(buf[idxSearch]) != toupper(key[0])) { continue; }
}
// possible match; compare buf[idxSearch..] to key[0..]
unsigned int idxKey = idxSearch; // test whether buf[idxKey..] == key[0..]
unsigned int idxBL = 0; // find such that buf[idxBL] == '[' // bracket left
unsigned int idxBR = 0; // find such that buf[idxBR] == ']' // bracket right
unsigned int idxSeparator = 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 (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") searching idxKey=%d + offset=%d buf[%d]='%c'",
key, idxKey, offset, (idxKey + offset), buf[idxKey + offset]);
}
//
// WIP #347 - handle brackets idxBL '[' idxBR ']'
if (buf[idxKey + offset] == '[') {
idxBL = idxKey + offset;
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") found '[' at index idxBL=%d", key, idxBL);
}
}
//
// WIP #347 - handle brackets idxBL '[' idxBR ']'
//if (buf[idxKey + offset] == ']') {
// idxBR = idxKey + offset;
// if (verbose) {
// serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") found ']' at index idxBR=%d", key, idxBR);
// }
//}
//
if (match_is_case_sensitive) {
// case-sensitive string comparison
if (buf[idxKey + offset] != key[offset]) { idxKey = 0; break; }
}
else {
// case-insensitive string comparison using toupper()
if (toupper(buf[idxKey + offset]) != toupper(key[offset])) { idxKey = 0; break; }
}
idxSpace = idxKey + offset + 1; // assume next char is a word break
idxSeparator = idxKey + offset + 1; // assume next char is a separator
//
if ((buf[idxSeparator] != '=') && (buf[idxSeparator] != '?') && (buf[idxSeparator] != '[') && (buf[idxSeparator] != ']')) { idxSeparator = 0; }
}
if (idxKey == 0) continue; // no match at idxSearch but keep searching
// ASSERT buf[idxKey..] == key[0..]
while ((buf[idxSpace] != ' ') && idxSpace < indexOfNextEmptyCell) { idxSpace++; }
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") match at index %d length %d, '=' index %d, ' ' index %d",
key, idxKey, strlen(key), idxSeparator, idxSpace);
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") buf[idxSeparator=%d]='%c'",
key, idxSeparator, buf[idxSeparator]);
//~ serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") idxBL=%d idxBR=%d",
//~ key, idxBL, idxBR);
//~ serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") [ index= %s ]", key, buf[idxBracket+1] );
}
// WIP #347 - handle brackets idxBL '[' idxBR ']'
if (buf[idxSeparator] == '[') {
idxBL = idxSeparator;
if (verbose) {
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") key[... continuing search from idxKey=%d + offset=%d buf[%d]='%c'",
key, idxKey, idxSeparator + 1, (idxKey + idxSeparator + 1), buf[idxKey + idxSeparator + 1]);
}
//~ serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") idxBL=%d idxBR=%d",
//~ key, idxBL, idxBR);
//~ serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") [ index= %s ]", key, buf[idxBracket+1] );
}
for (unsigned int idxBRsearch = idxBL + 1; (buf[idxBRsearch] != '\0'); idxBRsearch++)
{
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") key[... searching buf[idxBRsearch=%d]='%c'",
key, idxBRsearch, buf[idxBRsearch]);
}
if (buf[idxBRsearch] == '=') {
idxSeparator = idxBRsearch;
idxSpace = idxBRsearch;
break;
}
else if (buf[idxBRsearch] == ']') {
idxBR = idxBRsearch;
idxSeparator = idxBRsearch;
idxSpace = idxBRsearch;
//~ break;
}
else if (buf[idxBRsearch] == '?') {
idxSeparator = idxBRsearch;
idxSpace = idxBRsearch;
break;
}
else {
idxSeparator = 0;
//~ break;
}
}
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") idxBL=%d idxBR=%d",
key, idxBL, idxBR);
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") buf[idxSeparator=%d]='%c'",
key, idxSeparator, buf[idxSeparator]);
//~ serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") [ index= %s ]", key, buf[idxBracket+1] );
}
int arrayIndexValue = strtoul(&(buf[idxBL + 1]), NULL, 10); // default radix decimal
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") arrayIndexValue=%d",
key, arrayIndexValue);
}
if (pindex != NULL) {
*pindex = arrayIndexValue;
}
}
if (idxSeparator != 0) {
// found key=value: copy buf[idxSeparator+1..' '-1] into valueBuf[0..valueBufLen-1]
chSeparator = buf[idxSeparator];
for (unsigned int offset = 0; offset < valueBufLen - 1; offset++)
{
if (buf[idxSeparator + 1 + offset] == ' ') break;
valueBuf[offset] = buf[idxSeparator + 1 + offset];
valueBuf[offset + 1] = '\0';
}
} else {
// found key but no =value: valueBuf[] = ""
chSeparator = '\0';
valueBuf[0] = '\0';
}
// on successful match, the key=value should be deleted from cmdbuf
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") *pindex=%d buf=\"%s\" valueBuf=\"%s\" before deleting key",
key, *pindex, 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;
// cmdLine final key=value arg wrongly included in parse_byteCount_byteList_ buffer #358
// if (idxCopySrc > indexOfNextEmptyCell) break;
if (idxCopySrc > indexOfNextEmptyCell)
{
buf[idxCopyDst] = ' ';
continue;
}
buf[idxCopyDst] = buf[idxCopySrc];
}
if (verbose) {
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") *pindex=%d buf=\"%s\" valueBuf=\"%s\" after deleting key",
key, *pindex, buf, valueBuf);
serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%s\") returning true: valueBuf=\"%s\"", key, valueBuf);
}
return true;
}
if (verbose) { serial().printf("\r\n parse_and_remove_key_and_arrayIndex(\"%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_interval_usec matches "key"=digits
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] interval_usec updated from value string if match "key"=value,
* optional suffix Hz kHz or MHz 1/x inverts and scales the value
* optional suffix s or ms or msec or us or usec scales the value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
bool CmdLine::parse_interval_usec(const char *key, us_timestamp_t& interval_usec)
{
char valueBuf[32];
// 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
interval_usec = strtoul(valueBuf, NULL, 10);
if (strstr(valueBuf, "ms")) {
interval_usec = interval_usec * 1000;
} else if (strstr(valueBuf, "us")) {
// avoid matching "s" which is a subset of "us"
// interval_usec = interval_usec * 1;
} else if (strstr(valueBuf, "s")) {
interval_usec = interval_usec * 1000000;
} else if (strstr(valueBuf, "MHz")) {
interval_usec = 1. / interval_usec;
} else if (strstr(valueBuf, "kHz")) {
interval_usec = 1000. / interval_usec;
} else if (strstr(valueBuf, "Hz")) {
interval_usec = 1000000. / interval_usec;
}
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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-16 hexadecimal.
*/
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); // default radix hex
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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
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); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_byte_dec matches "key"=value with array indexing
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] nByteVar array base pointer
* @param[in] arrayIndexLimit array index limit
*
* @post on successful match, array[index] is updated from value string, and key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_uint8_dec_arrayUpdate(const char *key, uint8_t* nBytearray, size_t arrayIndexLimit)
{
// WIP #347 - parse_uint8_dec_arrayUpdate(const char *key, /*array=*/&AINcode[0], /*arrayIndexLimit=*/10) based on parse_uint8_dec(key, pValue)
// Work in progress
// if (parse_and_remove_key_and_arrayIndex(key, &index, valueBuf, sizeof(valueBuf)))
// match (key) "[" (index:[0-9]+) "]"
// nBytearray[index] = strtoul(valueBuf + 0, NULL, _radix_);
//
char valueBuf[16];
size_t index;
// bool parse_and_remove_key_and_arrayIndex(const char *key, size_t *pindex, char *valueBuf, size_t valueBufLen);
if (parse_and_remove_key_and_arrayIndex(key, &index, valueBuf, sizeof(valueBuf)))
{
if (index >= arrayIndexLimit) { index = arrayIndexLimit-1; }
// 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] == '$')
{
nBytearray[index] = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
nBytearray[index] = strtoul(valueBuf + 2, NULL, 16);
return true;
}
nBytearray[index] = strtoul(valueBuf, NULL, 10); // default radix decimal
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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-16 hexadecimal.
*/
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); // default radix hex
return true;
}
return false; // no match
}
/** CmdLine::parse_uint16_dec 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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_uint16_dec(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, 10); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_uint16_dec_arrayUpdate matches "key"=value with array indexing
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] uint16Var array base pointer
* @param[in] arrayIndexLimit array index limit
*
* @post on successful match, array[index] is updated from value string, and key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_uint16_dec_arrayUpdate(const char *key, uint16_t* uint16array, size_t arrayIndexLimit)
{
// WIP #347 - parse_uint16_dec_arrayUpdate(/*name=*/"AINcode", /*array=*/&AINcode[0], /*arrayIndexLimit=*/10) based on parse_uint16_dec(key, pValue)
// Work in progress
//
char valueBuf[16];
size_t index;
// bool parse_and_remove_key_and_arrayIndex(const char *key, size_t *pindex, char *valueBuf, size_t valueBufLen);
if (parse_and_remove_key_and_arrayIndex(key, &index, valueBuf, sizeof(valueBuf)))
{
if (index >= arrayIndexLimit) { index = arrayIndexLimit-1; }
// 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] == '$')
{
uint16array[index] = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
uint16array[index] = strtoul(valueBuf + 2, NULL, 16);
return true;
}
uint16array[index] = strtoul(valueBuf, NULL, 10); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_int_dec matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] intVar updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_int_dec(const char *key, int& intVar)
{
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] == '$')
{
intVar = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
intVar = strtoul(valueBuf + 2, NULL, 16);
return true;
}
intVar = strtoul(valueBuf, NULL, 10); // default radix decimal
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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-16 hexadecimal.
*/
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); // default radix hex
return true;
}
return false; // no match
}
/** CmdLine::parse_int16_dec 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
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_int16_dec(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, 10); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_uint32_hex matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-16 hexadecimal.
*/
bool CmdLine::parse_uint32_hex(const char *key, uint32_t& uint32Var)
{
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] == '$')
{
uint32Var = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
uint32Var = strtoul(valueBuf + 2, NULL, 16);
return true;
}
uint32Var = strtoul(valueBuf, NULL, 16); // default radix hex
return true;
}
return false; // no match
}
/** CmdLine::parse_uint32_dec matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_uint32_dec(const char *key, uint32_t& uint32Var)
{
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] == '$')
{
uint32Var = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
uint32Var = strtoul(valueBuf + 2, NULL, 16);
return true;
}
uint32Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_int32_hex matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] int32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-16 hexadecimal.
*/
bool CmdLine::parse_int32_hex(const char *key, int32_t& int32Var)
{
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] == '$')
{
int32Var = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
int32Var = strtoul(valueBuf + 2, NULL, 16);
return true;
}
int32Var = strtoul(valueBuf, NULL, 16); // default radix hex
return true;
}
return false; // no match
}
/** CmdLine::parse_int32_dec matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] int32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
* Prefix '$' or '0x' or '0X' selects radix base-16 hexadecimal.
* Default number conversion radix is base-10 decimal.
*/
bool CmdLine::parse_int32_dec(const char *key, int32_t& int32Var)
{
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] == '$')
{
int32Var = strtoul(valueBuf + 1, NULL, 16);
return true;
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
int32Var = strtoul(valueBuf + 2, NULL, 16);
return true;
}
int32Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return true;
}
return false; // no match
}
/** CmdLine::parse_double_or_int16 matches "key"=value
*
* Value will be parsed as double if it contains "." or "V",
* Otherwise,
* Value will be parsed as hexadecimal if it begins with "$" or "0x",
* Otherwise,
* Value will be parsed as decimal
*
* @return 0 if keyword not found in buffer; 1: parsed as integer; 2: parsed as double
* @param[in] key string value to match
* @param[out] doubleVar updated from value string if match "key"=xx.xxx
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
uint8_t CmdLine::parse_double_or_int16(const char *key, double& doubleVar, int16_t& int16Var)
{
char valueBuf[16];
char *end; // buffer required by strtof
// bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen);
if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf)))
{
for (size_t index = 0; valueBuf[index] != '\0' && index < sizeof(valueBuf); index++)
{
switch(valueBuf[index])
{
case '.': case 'V': case 'v':
// valueBuf contains decimal "." or letter "V"
doubleVar = strtod(valueBuf, &end);
return 2; // 2: parsed as double
}
}
if (valueBuf[0] == '$')
{
int16Var = strtoul(valueBuf + 1, NULL, 16);
return 1; // 1: parsed as integer
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
int16Var = strtoul(valueBuf + 2, NULL, 16);
return 1; // 1: parsed as integer
}
int16Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return 1; // 1: parsed as integer
}
return 0; // no match
}
/** CmdLine::parse_double_or_uint16 matches "key"=value
*
* Value will be parsed as double if it contains "." or "V",
* Otherwise,
* Value will be parsed as hexadecimal if it begins with "$" or "0x",
* Otherwise,
* Value will be parsed as decimal
*
* @return 0 if keyword not found in buffer; 1: parsed as integer; 2: parsed as double
* @param[in] key string value to match
* @param[out] doubleVar updated from value string if match "key"=xx.xxx
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
uint8_t CmdLine::parse_double_or_uint16(const char *key, double& doubleVar, uint16_t& uint16Var)
{
char valueBuf[16];
char *end; // buffer required by strtof
// bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen);
if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf)))
{
for (size_t index = 0; valueBuf[index] != '\0' && index < sizeof(valueBuf); index++)
{
switch(valueBuf[index])
{
case '.': case 'V': case 'v':
// valueBuf contains decimal "." or letter "V"
doubleVar = strtod(valueBuf, &end);
return 2; // 2: parsed as double
}
}
if (valueBuf[0] == '$')
{
uint16Var = strtoul(valueBuf + 1, NULL, 16);
return 1; // 1: parsed as integer
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
uint16Var = strtoul(valueBuf + 2, NULL, 16);
return 1; // 1: parsed as integer
}
uint16Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return 1; // 1: parsed as integer
}
return 0; // no match
}
/** CmdLine::parse_double_or_int32 matches "key"=value
*
* Value will be parsed as double if it contains "." or "V",
* Otherwise,
* Value will be parsed as hexadecimal if it begins with "$" or "0x",
* Otherwise,
* Value will be parsed as decimal
*
* @return 0 if keyword not found in buffer; 1: parsed as integer; 2: parsed as double
* @param[in] key string value to match
* @param[out] doubleVar updated from value string if match "key"=xx.xxx
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
uint8_t CmdLine::parse_double_or_int32(const char *key, double& doubleVar, int32_t& int32Var)
{
char valueBuf[16];
char *end; // buffer required by strtof
// bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen);
if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf)))
{
for (size_t index = 0; valueBuf[index] != '\0' && index < sizeof(valueBuf); index++)
{
switch(valueBuf[index])
{
case '.': case 'V': case 'v':
// valueBuf contains decimal "." or letter "V"
doubleVar = strtod(valueBuf, &end);
return 2; // 2: parsed as double
}
}
if (valueBuf[0] == '$')
{
int32Var = strtoul(valueBuf + 1, NULL, 16);
return 1; // 1: parsed as integer
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
int32Var = strtoul(valueBuf + 2, NULL, 16);
return 1; // 1: parsed as integer
}
int32Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return 1; // 1: parsed as integer
}
return 0; // no match
}
/** CmdLine::parse_double_or_uint32 matches "key"=value
*
* Value will be parsed as double if it contains "." or "V",
* Otherwise,
* Value will be parsed as hexadecimal if it begins with "$" or "0x",
* Otherwise,
* Value will be parsed as decimal
*
* @return 0 if keyword not found in buffer; 1: parsed as integer; 2: parsed as double
* @param[in] key string value to match
* @param[out] doubleVar updated from value string if match "key"=xx.xxx
* @param[out] uint32Var updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
uint8_t CmdLine::parse_double_or_uint32(const char *key, double& doubleVar, uint32_t& uint32Var)
{
char valueBuf[16];
char *end; // buffer required by strtof
// bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen);
if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf)))
{
for (size_t index = 0; valueBuf[index] != '\0' && index < sizeof(valueBuf); index++)
{
switch(valueBuf[index])
{
case '.': case 'V': case 'v':
// valueBuf contains decimal "." or letter "V"
doubleVar = strtod(valueBuf, &end);
return 2; // 2: parsed as double
}
}
if (valueBuf[0] == '$')
{
uint32Var = strtoul(valueBuf + 1, NULL, 16);
return 1; // 1: parsed as integer
}
if (valueBuf[0] == '0' && (valueBuf[1] == 'X' || valueBuf[1] == 'x'))
{
uint32Var = strtoul(valueBuf + 2, NULL, 16);
return 1; // 1: parsed as integer
}
uint32Var = strtoul(valueBuf, NULL, 10); // default radix decimal
return 1; // 1: parsed as integer
}
return 0; // no match
}
/** CmdLine::parse_double matches "key"=value
*
* @return true if keyword was found in buffer
* @param[in] key string value to match
* @param[out] doubleVar updated from value string if match "key"=value
*
* @post on successful match, the key=value substring is deleted from cmdbuf
*
*/
bool CmdLine::parse_double(const char *key, double& doubleVar)
{
char valueBuf[16];
char *end; // buffer required by strtof
// bool parse_and_remove_key(const char *key, char *valueBuf, int valueBufLen);
if (parse_and_remove_key(key, valueBuf, sizeof(valueBuf)))
{
doubleVar = strtod(valueBuf, &end);
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; // buffer required by strtof
// 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