/ teensy3 / Stream.cpp
Stream.cpp
  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    unsigned long startMillis = millis();
 34    do {
 35      c = read();
 36      if (c >= 0) return c;
 37      yield();
 38    } while(millis() - startMillis < _timeout);
 39    return -1;     // -1 indicates timeout
 40  }
 41  
 42  // private method to peek stream with timeout
 43  int Stream::timedPeek()
 44  {
 45    int c;
 46    unsigned long startMillis = millis();
 47    do {
 48      c = peek();
 49      if (c >= 0) return c;
 50      yield();
 51    } while(millis() - startMillis < _timeout);
 52    return -1;     // -1 indicates timeout
 53  }
 54  
 55  // returns peek of the next digit in the stream or -1 if timeout
 56  // discards non-numeric characters
 57  int Stream::peekNextDigit()
 58  {
 59    int c;
 60    while (1) {
 61      c = timedPeek();
 62      if (c < 0) return c;  // timeout
 63      if (c == '-') return c;
 64      if (c >= '0' && c <= '9') return c;
 65      read();  // discard non-numeric
 66    }
 67  }
 68  
 69  // Public Methods
 70  //////////////////////////////////////////////////////////////
 71  
 72  void Stream::setTimeout(unsigned long timeout)  // sets the maximum number of milliseconds to wait
 73  {
 74    _timeout = timeout;
 75  }
 76  
 77   // find returns true if the target string is found
 78  bool  Stream::find(char *target)
 79  {
 80    return findUntil(target, NULL);
 81  }
 82  
 83  // reads data from the stream until the target string of given length is found
 84  // returns true if target string is found, false if timed out
 85  bool Stream::find(char *target, size_t length)
 86  {
 87    return findUntil(target, length, NULL, 0);
 88  }
 89  
 90  // as find but search ends if the terminator string is found
 91  bool  Stream::findUntil(char *target, char *terminator)
 92  {
 93    return findUntil(target, strlen(target), terminator, strlen(terminator));
 94  }
 95  
 96  // reads data from the stream until the target string of the given length is found
 97  // search terminated if the terminator string is found
 98  // returns true if target string is found, false if terminated or timed out
 99  bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
100  {
101    size_t index = 0;  // maximum target string length is 64k bytes!
102    size_t termIndex = 0;
103    int c;
104  
105    if( *target == 0)
106       return true;   // return true if target is a null string
107    while( (c = timedRead()) > 0){
108      if( c == target[index]){
109      //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
110        if(++index >= targetLen){ // return true if all chars in the target match
111          return true;
112        }
113      }
114      else{
115        index = 0;  // reset index if any char does not match
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) {
223  			setReadError();
224  			break;
225  		}
226  		*buffer++ = (char)c;
227  		count++;
228  	}
229  	return count;
230  }
231  
232  
233  // as readBytes with terminator character
234  // terminates if length characters have been read, timeout, or if the terminator character  detected
235  // returns the number of characters placed in the buffer (0 means no valid data found)
236  
237  size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
238  {
239  	if (length < 1) return 0;
240  	length--;
241  	size_t index = 0;
242  	while (index < length) {
243  		int c = timedRead();
244  		if (c == terminator) break;
245  		if (c < 0) {
246  			setReadError();
247  			break;
248  		}
249  		*buffer++ = (char)c;
250  		index++;
251  	}
252  	*buffer = 0;
253  	return index; // return number of characters, not including null terminator
254  }
255  
256  String Stream::readString(size_t max)
257  {
258  	String str;
259  	size_t length = str.length();
260  	while (length < max) {
261  		int c = timedRead();
262  		if (c < 0) {
263  			setReadError();
264  			break;	// timeout
265  		}
266  		if (c == 0) break;
267  		str += (char)c;
268  	}
269  	return str;
270  }
271  
272  String Stream::readStringUntil(char terminator, size_t max)
273  {
274  	String str;
275  	size_t length = str.length();
276  	while (length < max) {
277  		int c = timedRead();
278  		if (c < 0) {
279  			setReadError();
280  			break;	// timeout
281  		}
282  		if (c == 0 || c == terminator) break;
283  		str += (char)c;
284  	}
285  	return str;
286  }
287  
288  
289  
290  
291  
292  
293  
294  
295  
296  
297  
298  
299  
300  
301  
302  
303  
304  
305  
306  
307  
308  
309  
310  
311  
312