Skip to content

Commit 682b58e

Browse files
committed
Integrating Stream searching & parsing (Michael Margolis)
This from Michael's TextFinder library, incorporated into the Stream class: find(), findUntil(), parseInt(), parseFloat(), readChars(), readCharsUntil(), readCharsBetween(), setTimeout().
1 parent fc90fa7 commit 682b58e

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
Stream.cpp - adds parsing methods to Stream class
3+
Copyright (c) 2008 David A. Mellis. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Created July 2011
20+
parsing functions based on TextFinder library by Michael Margolis
21+
*/
22+
23+
#include "Arduino.h"
24+
#include "Stream.h"
25+
26+
#define PARSE_TIMEOUT 5 // default number of seconds to wait
27+
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
28+
29+
// private method to read stream with timeout
30+
int Stream::timedRead()
31+
{
32+
//Serial.println(_timeout);
33+
this->_startMillis = millis();
34+
while(millis() - this->_startMillis < (this->_timeout * 1000L))
35+
{
36+
if (this->available() > 0) {
37+
return this->read();
38+
}
39+
}
40+
return -1; // -1 indicates timeout
41+
}
42+
43+
// returns the next digit in the stream or -1 if timeout
44+
// discards non-numeric characters
45+
int Stream::getNextDigit()
46+
{
47+
int c;
48+
do{
49+
c = timedRead();
50+
if( c < 0)
51+
return c; // timeout
52+
}
53+
while( c != '-' && (c < '0' || c > '9') ) ;
54+
55+
return c;
56+
}
57+
58+
// Public Methods
59+
//////////////////////////////////////////////////////////////
60+
61+
void Stream::setTimeout( long timeout) // sets the maximum number of seconds to wait
62+
{
63+
this->_timeout = timeout;
64+
}
65+
66+
// find returns true if the target string is found
67+
bool Stream::find(char *target)
68+
{
69+
return findUntil(target, NULL);
70+
}
71+
72+
// reads data from the stream until the target string of given length is found
73+
// returns true if target string is found, false if timed out
74+
bool Stream::find(char *target, size_t length)
75+
{
76+
return findUntil(target, length, NULL, 0);
77+
}
78+
79+
// as find but search ends if the terminator string is found
80+
bool Stream::findUntil(char *target, char *terminator)
81+
{
82+
return findUntil(target, strlen(target), terminator, strlen(terminator));
83+
}
84+
85+
// reads data from the stream until the target string of the given length is found
86+
// search terminated if the terminator string is found
87+
// returns true if target string is found, false if terminated or timed out
88+
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
89+
{
90+
size_t index = 0; // maximum target string length is 64k bytes!
91+
size_t termIndex = 0;
92+
int c;
93+
94+
if( *target == 0)
95+
return true; // return true if target is a null string
96+
while( (c = timedRead()) > 0){
97+
if( c == target[index]){
98+
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
99+
if(++index >= targetLen){ // return true if all chars in the target match
100+
return true;
101+
}
102+
}
103+
else{
104+
index = 0; // reset index if any char does not match
105+
}
106+
if(termLen > 0 && c == terminator[termIndex]){
107+
if(++termIndex >= termLen)
108+
return false; // return false if terminate string found before target string
109+
}
110+
else
111+
termIndex = 0;
112+
}
113+
return false;
114+
}
115+
116+
117+
// returns the first valid (long) integer value from the current position.
118+
// initial characters that are not digits (or the minus sign) are skipped
119+
// function is terminated by the first character that is not a digit.
120+
long Stream::parseInt()
121+
{
122+
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
123+
}
124+
125+
// as above but a given skipChar is ignored
126+
// this allows format characters (typically commas) in values to be ignored
127+
long Stream::parseInt(char skipChar)
128+
{
129+
boolean isNegative = false;
130+
long value = 0;
131+
int c;
132+
133+
c = getNextDigit();
134+
// ignore non numeric leading characters
135+
if(c < 0)
136+
return 0; // zero returned if timeout
137+
138+
do{
139+
if(c == skipChar)
140+
; // ignore this charactor
141+
else if(c == '-')
142+
isNegative = true;
143+
else if(c >= '0' && c <= '9') // is c a digit?
144+
value = value * 10 + c - '0';
145+
c = timedRead();
146+
}
147+
while( (c >= '0' && c <= '9') || c == skipChar );
148+
149+
if(isNegative)
150+
value = -value;
151+
return value;
152+
}
153+
154+
155+
// as parseInt but returns a floating point value
156+
float Stream::parseFloat()
157+
{
158+
parseFloat(NO_SKIP_CHAR);
159+
}
160+
161+
// as above but the given skipChar is ignored
162+
// this allows format characters (typically commas) in values to be ignored
163+
float Stream::parseFloat(char skipChar){
164+
boolean isNegative = false;
165+
boolean isFraction = false;
166+
long value = 0;
167+
float fValue;
168+
char c;
169+
float fraction = 1.0;
170+
171+
c = getNextDigit();
172+
// ignore non numeric leading characters
173+
if(c < 0)
174+
return 0; // zero returned if timeout
175+
176+
do{
177+
if(c == skipChar)
178+
; // ignore
179+
else if(c == '-')
180+
isNegative = true;
181+
else if (c == '.')
182+
isFraction = true;
183+
else if(c >= '0' && c <= '9') { // is c a digit?
184+
value = value * 10 + c - '0';
185+
if(isFraction)
186+
fraction *= 0.1;
187+
}
188+
c = timedRead();
189+
}
190+
while( (c >= '0' && c <= '9') || c == '.' || c == skipChar );
191+
192+
if(isNegative)
193+
value = -value;
194+
if(isFraction)
195+
return value * fraction;
196+
else
197+
return value;
198+
}
199+
200+
// read characters from stream into buffer
201+
// terminates if length characters have been read, null is detected or timeout (see setTimeout)
202+
// returns the number of characters placed in the buffer (0 means no valid data found)
203+
int Stream::readChars( char *buffer, size_t length)
204+
{
205+
return readCharsUntil( 0, buffer, length);
206+
}
207+
208+
209+
// as readChars with terminator character
210+
// terminates if length characters have been read, timeout, or if the terminator character detected
211+
// returns the number of characters placed in the buffer (0 means no valid data found)
212+
213+
int Stream::readCharsUntil( char terminator, char *buffer, size_t length)
214+
{
215+
int index = 0;
216+
*buffer = 0;
217+
while(index < length ){
218+
int c = timedRead();
219+
if( c <= 0 ){
220+
return 0; // timeout returns 0 !
221+
}
222+
else if( c == terminator){
223+
buffer[index] = 0; // terminate the string
224+
return index; // data got successfully
225+
}
226+
else{
227+
buffer[index++] = (char)c;
228+
}
229+
}
230+
buffer[index] = 0;
231+
return index; // here if buffer is full before detecting the terminator
232+
}
233+
234+
235+
// read characters found between pre_string and terminator into a buffer
236+
// terminated when the terminator character is matched or the buffer is full
237+
// returns the number of bytes placed in the buffer (0 means no valid data found)
238+
int Stream::readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length)
239+
{
240+
if( find( pre_string) ){
241+
return readCharsUntil(terminator, buffer, length);
242+
}
243+
return 0; //failed to find the prestring
244+
}

hardware/arduino/cores/arduino/Stream.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
You should have received a copy of the GNU Lesser General Public
1616
License along with this library; if not, write to the Free Software
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
parsing functions based on TextFinder library by Michael Margolis
1820
*/
1921

2022
#ifndef Stream_h
@@ -23,13 +25,75 @@
2325
#include <inttypes.h>
2426
#include "Print.h"
2527

28+
// compatability macros for testing
29+
/*
30+
#define getInt() parseInt()
31+
#define getInt(skipChar) parseInt(skipchar)
32+
#define getFloat() parseFloat()
33+
#define getFloat(skipChar) parseFloat(skipChar)
34+
#define getString( pre_string, post_string, buffer, length)
35+
readBytesBetween( pre_string, terminator, buffer, length)
36+
*/
37+
2638
class Stream : public Print
2739
{
40+
private:
41+
long _timeout; // number of seconds to wait for the next char before aborting timed read
42+
long _startMillis; // used for timeout measurement
43+
int timedRead(); // private method to read stream with timeout
44+
int getNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
45+
2846
public:
2947
virtual int available() = 0;
3048
virtual int read() = 0;
3149
virtual int peek() = 0;
3250
virtual void flush() = 0;
51+
52+
Stream() {_timeout=5;}
53+
54+
// parsing methods
55+
56+
void setTimeout(long timeout); // sets maximum seconds to wait for stream data, default is 5 seconds
57+
58+
bool find(char *target); // reads data from the stream until the target string is found
59+
// returns true if target string is found, false if timed out (see setTimeout)
60+
61+
bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found
62+
// returns true if target string is found, false if timed out
63+
64+
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
65+
66+
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
67+
68+
69+
long parseInt(); // returns the first valid (long) integer value from the current position.
70+
// initial characters that are not digits (or the minus sign) are skipped
71+
// integer is terminated by the first character that is not a digit.
72+
73+
long parseInt(char skipChar); // as above but the given skipChar is ignored
74+
// as above but the given skipChar is ignored
75+
// this allows format characters (typically commas) in values to be ignored
76+
77+
float parseFloat(); // float version of parseInt
78+
79+
float parseFloat(char skipChar); // as above but the given skipChar is ignored
80+
81+
int readChars( char *buffer, size_t length); // read chars from stream into buffer
82+
// terminates if length characters have been read or timeout (see setTimeout)
83+
// returns the number of characters placed in the buffer (0 means no valid data found)
84+
85+
int readCharsUntil( char terminator, char *buffer, size_t length); // as readChars with terminator character
86+
// terminates if length characters have been read, timeout, or if the terminator character detected
87+
// returns the number of characters placed in the buffer (0 means no valid data found)
88+
89+
int readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length);
90+
// read characters found between pre_string and terminator into a buffer
91+
// terminated when the terminator character is matched or the buffer is full
92+
// returns the number of bytes placed in the buffer (0 means no valid data found)
93+
94+
95+
// Arduino String functions to be added here
96+
3397
};
3498

3599
#endif

0 commit comments

Comments
 (0)