|
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 1000 // default number of milli-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 int c; |
|
33 _startMillis = millis(); |
|
34 do { |
|
35 c = read(); |
|
36 if (c >= 0) return c; |
|
37 } while(millis() - _startMillis < _timeout); |
|
38 return -1; // -1 indicates timeout |
|
39 } |
|
40 |
|
41 // private method to peek stream with timeout |
|
42 int Stream::timedPeek() |
|
43 { |
|
44 int c; |
|
45 _startMillis = millis(); |
|
46 do { |
|
47 c = peek(); |
|
48 if (c >= 0) return c; |
|
49 } while(millis() - _startMillis < _timeout); |
|
50 return -1; // -1 indicates timeout |
|
51 } |
|
52 |
|
53 // returns peek of the next digit in the stream or -1 if timeout |
|
54 // discards non-numeric characters |
|
55 int Stream::peekNextDigit() |
|
56 { |
|
57 int c; |
|
58 while (1) { |
|
59 c = timedPeek(); |
|
60 if (c < 0) return c; // timeout |
|
61 if (c == '-') return c; |
|
62 if (c >= '0' && c <= '9') return c; |
|
63 read(); // discard non-numeric |
|
64 } |
|
65 } |
|
66 |
|
67 // Public Methods |
|
68 ////////////////////////////////////////////////////////////// |
|
69 |
|
70 void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait |
|
71 { |
|
72 _timeout = timeout; |
|
73 } |
|
74 |
|
75 // find returns true if the target string is found |
|
76 bool Stream::find(char *target) |
|
77 { |
|
78 return findUntil(target, NULL); |
|
79 } |
|
80 |
|
81 // reads data from the stream until the target string of given length is found |
|
82 // returns true if target string is found, false if timed out |
|
83 bool Stream::find(char *target, size_t length) |
|
84 { |
|
85 return findUntil(target, length, NULL, 0); |
|
86 } |
|
87 |
|
88 // as find but search ends if the terminator string is found |
|
89 bool Stream::findUntil(char *target, char *terminator) |
|
90 { |
|
91 return findUntil(target, strlen(target), terminator, strlen(terminator)); |
|
92 } |
|
93 |
|
94 // reads data from the stream until the target string of the given length is found |
|
95 // search terminated if the terminator string is found |
|
96 // returns true if target string is found, false if terminated or timed out |
|
97 bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) |
|
98 { |
|
99 size_t index = 0; // maximum target string length is 64k bytes! |
|
100 size_t termIndex = 0; |
|
101 int c; |
|
102 |
|
103 if( *target == 0) |
|
104 return true; // return true if target is a null string |
|
105 while( (c = timedRead()) > 0){ |
|
106 |
|
107 if(c != target[index]) |
|
108 index = 0; // reset index if any char does not match |
|
109 |
|
110 if( c == target[index]){ |
|
111 //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); |
|
112 if(++index >= targetLen){ // return true if all chars in the target match |
|
113 return true; |
|
114 } |
|
115 } |
|
116 |
|
117 if(termLen > 0 && c == terminator[termIndex]){ |
|
118 if(++termIndex >= termLen) |
|
119 return false; // return false if terminate string found before target string |
|
120 } |
|
121 else |
|
122 termIndex = 0; |
|
123 } |
|
124 return false; |
|
125 } |
|
126 |
|
127 |
|
128 // returns the first valid (long) integer value from the current position. |
|
129 // initial characters that are not digits (or the minus sign) are skipped |
|
130 // function is terminated by the first character that is not a digit. |
|
131 long Stream::parseInt() |
|
132 { |
|
133 return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) |
|
134 } |
|
135 |
|
136 // as above but a given skipChar is ignored |
|
137 // this allows format characters (typically commas) in values to be ignored |
|
138 long Stream::parseInt(char skipChar) |
|
139 { |
|
140 boolean isNegative = false; |
|
141 long value = 0; |
|
142 int c; |
|
143 |
|
144 c = peekNextDigit(); |
|
145 // ignore non numeric leading characters |
|
146 if(c < 0) |
|
147 return 0; // zero returned if timeout |
|
148 |
|
149 do{ |
|
150 if(c == skipChar) |
|
151 ; // ignore this charactor |
|
152 else if(c == '-') |
|
153 isNegative = true; |
|
154 else if(c >= '0' && c <= '9') // is c a digit? |
|
155 value = value * 10 + c - '0'; |
|
156 read(); // consume the character we got with peek |
|
157 c = timedPeek(); |
|
158 } |
|
159 while( (c >= '0' && c <= '9') || c == skipChar ); |
|
160 |
|
161 if(isNegative) |
|
162 value = -value; |
|
163 return value; |
|
164 } |
|
165 |
|
166 |
|
167 // as parseInt but returns a floating point value |
|
168 float Stream::parseFloat() |
|
169 { |
|
170 return parseFloat(NO_SKIP_CHAR); |
|
171 } |
|
172 |
|
173 // as above but the given skipChar is ignored |
|
174 // this allows format characters (typically commas) in values to be ignored |
|
175 float Stream::parseFloat(char skipChar){ |
|
176 boolean isNegative = false; |
|
177 boolean isFraction = false; |
|
178 long value = 0; |
|
179 char c; |
|
180 float fraction = 1.0; |
|
181 |
|
182 c = peekNextDigit(); |
|
183 // ignore non numeric leading characters |
|
184 if(c < 0) |
|
185 return 0; // zero returned if timeout |
|
186 |
|
187 do{ |
|
188 if(c == skipChar) |
|
189 ; // ignore |
|
190 else if(c == '-') |
|
191 isNegative = true; |
|
192 else if (c == '.') |
|
193 isFraction = true; |
|
194 else if(c >= '0' && c <= '9') { // is c a digit? |
|
195 value = value * 10 + c - '0'; |
|
196 if(isFraction) |
|
197 fraction *= 0.1; |
|
198 } |
|
199 read(); // consume the character we got with peek |
|
200 c = timedPeek(); |
|
201 } |
|
202 while( (c >= '0' && c <= '9') || c == '.' || c == skipChar ); |
|
203 |
|
204 if(isNegative) |
|
205 value = -value; |
|
206 if(isFraction) |
|
207 return value * fraction; |
|
208 else |
|
209 return value; |
|
210 } |
|
211 |
|
212 // read characters from stream into buffer |
|
213 // terminates if length characters have been read, or timeout (see setTimeout) |
|
214 // returns the number of characters placed in the buffer |
|
215 // the buffer is NOT null terminated. |
|
216 // |
|
217 size_t Stream::readBytes(char *buffer, size_t length) |
|
218 { |
|
219 size_t count = 0; |
|
220 while (count < length) { |
|
221 int c = timedRead(); |
|
222 if (c < 0) break; |
|
223 *buffer++ = (char)c; |
|
224 count++; |
|
225 } |
|
226 return count; |
|
227 } |
|
228 |
|
229 |
|
230 // as readBytes with terminator character |
|
231 // terminates if length characters have been read, timeout, or if the terminator character detected |
|
232 // returns the number of characters placed in the buffer (0 means no valid data found) |
|
233 |
|
234 size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) |
|
235 { |
|
236 if (length < 1) return 0; |
|
237 size_t index = 0; |
|
238 while (index < length) { |
|
239 int c = timedRead(); |
|
240 if (c < 0 || c == terminator) break; |
|
241 *buffer++ = (char)c; |
|
242 index++; |
|
243 } |
|
244 return index; // return number of characters, not including null terminator |
|
245 } |
|
246 |
|
247 String Stream::readString() |
|
248 { |
|
249 String ret; |
|
250 int c = timedRead(); |
|
251 while (c >= 0) |
|
252 { |
|
253 ret += (char)c; |
|
254 c = timedRead(); |
|
255 } |
|
256 return ret; |
|
257 } |
|
258 |
|
259 String Stream::readStringUntil(char terminator) |
|
260 { |
|
261 String ret; |
|
262 int c = timedRead(); |
|
263 while (c >= 0 && c != terminator) |
|
264 { |
|
265 ret += (char)c; |
|
266 c = timedRead(); |
|
267 } |
|
268 return ret; |
|
269 } |
|
270 |