/ teensy / 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    } 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    unsigned long 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      if( c == target[index]){
107      //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
108        if(++index >= targetLen){ // return true if all chars in the target match
109          return true;
110        }
111      }
112      else{
113        index = 0;  // reset index if any char does not match
114      }
115      if(termLen > 0 && c == terminator[termIndex]){
116         if(++termIndex >= termLen)
117           return false;       // return false if terminate string found before target string
118      }
119      else
120          termIndex = 0;
121    }
122    return false;
123  }
124  
125  
126  // returns the first valid (long) integer value from the current position.
127  // initial characters that are not digits (or the minus sign) are skipped
128  // function is terminated by the first character that is not a digit.
129  long Stream::parseInt()
130  {
131    return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
132  }
133  
134  // as above but a given skipChar is ignored
135  // this allows format characters (typically commas) in values to be ignored
136  long Stream::parseInt(char skipChar)
137  {
138    boolean isNegative = false;
139    long value = 0;
140    int c;
141  
142    c = peekNextDigit();
143    // ignore non numeric leading characters
144    if(c < 0)
145      return 0; // zero returned if timeout
146  
147    do{
148      if(c == skipChar)
149        ; // ignore this charactor
150      else if(c == '-')
151        isNegative = true;
152      else if(c >= '0' && c <= '9')        // is c a digit?
153        value = value * 10 + c - '0';
154      read();  // consume the character we got with peek
155      c = timedPeek();
156    }
157    while( (c >= '0' && c <= '9') || c == skipChar );
158  
159    if(isNegative)
160      value = -value;
161    return value;
162  }
163  
164  
165  // as parseInt but returns a floating point value
166  float Stream::parseFloat()
167  {
168    return parseFloat(NO_SKIP_CHAR);
169  }
170  
171  // as above but the given skipChar is ignored
172  // this allows format characters (typically commas) in values to be ignored
173  float Stream::parseFloat(char skipChar){
174    boolean isNegative = false;
175    boolean isFraction = false;
176    long value = 0;
177    char c;
178    float fraction = 1.0;
179  
180    c = peekNextDigit();
181      // ignore non numeric leading characters
182    if(c < 0)
183      return 0; // zero returned if timeout
184  
185    do{
186      if(c == skipChar)
187        ; // ignore
188      else if(c == '-')
189        isNegative = true;
190      else if (c == '.')
191        isFraction = true;
192      else if(c >= '0' && c <= '9')  {      // is c a digit?
193        value = value * 10 + c - '0';
194        if(isFraction)
195           fraction *= 0.1;
196      }
197      read();  // consume the character we got with peek
198      c = timedPeek();
199    }
200    while( (c >= '0' && c <= '9')  || c == '.' || c == skipChar );
201  
202    if(isNegative)
203      value = -value;
204    if(isFraction)
205      return value * fraction;
206    else
207      return value;
208  }
209  
210  // read characters from stream into buffer
211  // terminates if length characters have been read, or timeout (see setTimeout)
212  // returns the number of characters placed in the buffer
213  // the buffer is NOT null terminated.
214  //
215  size_t Stream::readBytes(char *buffer, size_t length)
216  {
217  	size_t count = 0;
218  	while (count < length) {
219  		int c = timedRead();
220  		if (c < 0) {
221  			setReadError();
222  			break;
223  		}
224  		*buffer++ = (char)c;
225  		count++;
226  	}
227  	return count;
228  }
229  
230  
231  // as readBytes with terminator character
232  // terminates if length characters have been read, timeout, or if the terminator character  detected
233  // returns the number of characters placed in the buffer (0 means no valid data found)
234  
235  size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
236  {
237  	if (length < 1) return 0;
238  	length--;
239  	size_t index = 0;
240  	while (index < length) {
241  		int c = timedRead();
242  		if (c == terminator) break;
243  		if (c < 0) {
244  			setReadError();
245  			break;
246  		}
247  		*buffer++ = (char)c;
248  		index++;
249  	}
250  	*buffer = 0;
251  	return index; // return number of characters, not including null terminator
252  }
253  
254  String Stream::readString(size_t max)
255  {
256  	String str;
257  	size_t length = str.length();
258  	while (length < max) {
259  		int c = timedRead();
260  		if (c < 0) {
261  			setReadError();
262  			break;	// timeout
263  		}
264  		if (c == 0) break;
265  		str += (char)c;
266  	}
267  	return str;
268  }
269  
270  String Stream::readStringUntil(char terminator, size_t max)
271  {
272  	String str;
273  	size_t length = str.length();
274  	while (length < max) {
275  		int c = timedRead();
276  		if (c < 0) {
277  			setReadError();
278  			break;	// timeout
279  		}
280  		if (c == 0 || c == terminator) break;
281  		str += (char)c;
282  	}
283  	return str;
284  }
285  
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