fix(api): Update Arduino Stream class (#10328)
* fix(api): Update Arduino Stream class Upstream code contains some fixes * Update Stream.h * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
parent
eda6d21d87
commit
648094c733
2 changed files with 219 additions and 209 deletions
|
|
@ -18,14 +18,14 @@
|
|||
|
||||
Created July 2011
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
|
||||
findMulti/findUntil routines written by Jim Leonard/Xuth
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Stream.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead() {
|
||||
|
|
@ -55,18 +55,26 @@ int Stream::timedPeek() {
|
|||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit() {
|
||||
int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal) {
|
||||
int c;
|
||||
while (1) {
|
||||
c = timedPeek();
|
||||
if (c < 0) {
|
||||
return c; // timeout
|
||||
}
|
||||
if (c == '-') {
|
||||
|
||||
if (c < 0 || c == '-' || (c >= '0' && c <= '9') || (detectDecimal && c == '.')) {
|
||||
return c;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c;
|
||||
|
||||
switch (lookahead) {
|
||||
case SKIP_NONE: return -1; // Fail code.
|
||||
case SKIP_WHITESPACE:
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n': break;
|
||||
default: return -1; // Fail code.
|
||||
}
|
||||
case SKIP_ALL: break;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
|
|
@ -79,9 +87,6 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
|
|||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
unsigned long Stream::getTimeout(void) {
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target) {
|
||||
|
|
@ -105,13 +110,142 @@ bool Stream::findUntil(const char *target, const char *terminator) {
|
|||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) {
|
||||
if (terminator == NULL) {
|
||||
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||
return findMulti(t, 1) == 0 ? true : false;
|
||||
return findMulti(t, 1) == 0;
|
||||
} else {
|
||||
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||
return findMulti(t, 2) == 0 ? true : false;
|
||||
return findMulti(t, 2) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// lookahead determines how parseInt looks ahead in the stream.
|
||||
// See LookaheadMode enumeration at the top of the file.
|
||||
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||
long Stream::parseInt(LookaheadMode lookahead, char ignore) {
|
||||
bool isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit(lookahead, false);
|
||||
// ignore non numeric leading characters
|
||||
if (c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if ((char)c == ignore)
|
||||
; // ignore this character
|
||||
else if (c == '-') {
|
||||
isNegative = true;
|
||||
} else if (c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while ((c >= '0' && c <= '9') || (char)c == ignore);
|
||||
|
||||
if (isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat(LookaheadMode lookahead, char ignore) {
|
||||
bool isNegative = false;
|
||||
bool isFraction = false;
|
||||
double value = 0.0;
|
||||
int c;
|
||||
double fraction = 1.0;
|
||||
|
||||
c = peekNextDigit(lookahead, true);
|
||||
// ignore non numeric leading characters
|
||||
if (c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if ((char)c == ignore)
|
||||
; // ignore
|
||||
else if (c == '-') {
|
||||
isNegative = true;
|
||||
} else if (c == '.') {
|
||||
isFraction = true;
|
||||
} else if (c >= '0' && c <= '9') { // is c a digit?
|
||||
if (isFraction) {
|
||||
fraction *= 0.1;
|
||||
value = value + fraction * (c - '0');
|
||||
} else {
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while ((c >= '0' && c <= '9') || (c == '.' && !isFraction) || (char)c == ignore);
|
||||
|
||||
if (isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length) {
|
||||
size_t count = 0;
|
||||
while (count < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char)c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
|
||||
size_t index = 0;
|
||||
while (index < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0 || (char)c == terminator) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char)c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
String Stream::readString() {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0) {
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String Stream::readStringUntil(char terminator) {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0 && (char)c != terminator) {
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Stream::findMulti(struct Stream::MultiTarget *targets, int tCount) {
|
||||
// any zero length target string automatically matches and would make
|
||||
// a mess of the rest of the algorithm.
|
||||
|
|
@ -129,7 +263,7 @@ int Stream::findMulti(struct Stream::MultiTarget *targets, int tCount) {
|
|||
|
||||
for (struct MultiTarget *t = targets; t < targets + tCount; ++t) {
|
||||
// the simple case is if we match, deal with that first.
|
||||
if (c == t->str[t->index]) {
|
||||
if ((char)c == t->str[t->index]) {
|
||||
if (++t->index == t->len) {
|
||||
return t - targets;
|
||||
} else {
|
||||
|
|
@ -149,7 +283,7 @@ int Stream::findMulti(struct Stream::MultiTarget *targets, int tCount) {
|
|||
do {
|
||||
--t->index;
|
||||
// first check if current char works against the new current index
|
||||
if (c != t->str[t->index]) {
|
||||
if ((char)c != t->str[t->index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -182,146 +316,3 @@ int Stream::findMulti(struct Stream::MultiTarget *targets, int tCount) {
|
|||
// unreachable
|
||||
return -1;
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// function is terminated by the first character that is not a digit.
|
||||
long Stream::parseInt() {
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
}
|
||||
|
||||
// as above but a given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
long Stream::parseInt(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if (c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if (c == skipChar) {
|
||||
} // ignore this character
|
||||
else if (c == '-') {
|
||||
isNegative = true;
|
||||
} else if (c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while ((c >= '0' && c <= '9') || c == skipChar);
|
||||
|
||||
if (isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat() {
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
}
|
||||
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
float Stream::parseFloat(char skipChar) {
|
||||
boolean isNegative = false;
|
||||
boolean isFraction = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
float fraction = 1.0;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if (c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if (c == skipChar) {
|
||||
} // ignore
|
||||
else if (c == '-') {
|
||||
isNegative = true;
|
||||
} else if (c == '.') {
|
||||
isFraction = true;
|
||||
} else if (c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if (isFraction) {
|
||||
fraction *= 0.1f;
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while ((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||
|
||||
if (isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
if (isFraction) {
|
||||
return value * fraction;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length) {
|
||||
size_t count = 0;
|
||||
while (count < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char)c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
|
||||
if (length < 1) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
while (index < length) {
|
||||
int c = timedRead();
|
||||
if (c < 0 || c == terminator) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char)c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
String Stream::readString() {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0) {
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String Stream::readStringUntil(char terminator) {
|
||||
String ret;
|
||||
int c = timedRead();
|
||||
while (c >= 0 && c != terminator) {
|
||||
ret += (char)c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,72 +1,83 @@
|
|||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
*/
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
*/
|
||||
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
// compatibility macros for testing
|
||||
/*
|
||||
#define getInt() parseInt()
|
||||
#define getInt(skipChar) parseInt(skipchar)
|
||||
#define getFloat() parseFloat()
|
||||
#define getFloat(skipChar) parseFloat(skipChar)
|
||||
#define getString( pre_string, post_string, buffer, length)
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
#define getInt() parseInt()
|
||||
#define getInt(ignore) parseInt(ignore)
|
||||
#define getFloat() parseFloat()
|
||||
#define getFloat(ignore) parseFloat(ignore)
|
||||
#define getString( pre_string, post_string, buffer, length)
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
|
||||
// This enumeration provides the lookahead options for parseInt(), parseFloat()
|
||||
// The rules set out here are used until either the first valid character is found
|
||||
// or a time out occurs due to lack of input.
|
||||
enum LookaheadMode {
|
||||
SKIP_ALL, // All invalid characters are ignored.
|
||||
SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid.
|
||||
SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped.
|
||||
};
|
||||
|
||||
#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field
|
||||
|
||||
class Stream : public Print {
|
||||
protected:
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
|
||||
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
|
||||
Stream() : _startMillis(0) {
|
||||
Stream() {
|
||||
_timeout = 1000;
|
||||
}
|
||||
virtual ~Stream() {}
|
||||
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
unsigned long getTimeout(void);
|
||||
unsigned long getTimeout(void) {
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target) {
|
||||
return find((char *)target);
|
||||
bool find(const uint8_t *target) {
|
||||
return find((const char *)target);
|
||||
}
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length) {
|
||||
return find((char *)target, length);
|
||||
return find((const char *)target, length);
|
||||
}
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
|
|
@ -76,22 +87,26 @@ public:
|
|||
|
||||
bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator) {
|
||||
return findUntil((char *)target, terminator);
|
||||
return findUntil((const char *)target, terminator);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) {
|
||||
return findUntil((char *)target, targetLen, terminate, termLen);
|
||||
return findUntil((const char *)target, targetLen, terminate, termLen);
|
||||
}
|
||||
|
||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// integer is terminated by the first character that is not a digit.
|
||||
long parseInt(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// lookahead determines how parseInt looks ahead in the stream.
|
||||
// See LookaheadMode enumeration at the top of the file.
|
||||
// Lookahead is terminated by the first character that is not a valid part of an integer.
|
||||
// Once parsing commences, 'ignore' will be skipped in the stream.
|
||||
|
||||
float parseFloat(); // float version of parseInt
|
||||
float parseFloat(LookaheadMode lookahead = SKIP_ALL, char ignore = NO_IGNORE_CHAR);
|
||||
// float version of parseInt
|
||||
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length) {
|
||||
size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
size_t readBytes(uint8_t *buffer, size_t length) {
|
||||
return readBytes((char *)buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
|
|
@ -105,15 +120,19 @@ public:
|
|||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
virtual String readString();
|
||||
String readString();
|
||||
String readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
long parseInt(char ignore) {
|
||||
return parseInt(SKIP_ALL, ignore);
|
||||
}
|
||||
float parseFloat(char ignore) {
|
||||
return parseFloat(SKIP_ALL, ignore);
|
||||
}
|
||||
// These overload exists for compatibility with any class that has derived
|
||||
// Stream and used parseFloat/Int with a custom ignore character. To keep
|
||||
// the public API simple, these overload remains protected.
|
||||
|
||||
struct MultiTarget {
|
||||
const char *str; // string you're searching for
|
||||
|
|
@ -126,4 +145,4 @@ protected:
|
|||
int findMulti(struct MultiTarget *targets, int tCount);
|
||||
};
|
||||
|
||||
#endif
|
||||
#undef NO_IGNORE_CHAR
|
||||
|
|
|
|||
Loading…
Reference in a new issue