[gnoduino: 72/237] Integrating Stream searching & parsing (Michael Margolis)



commit 893b9deb70c2ae624f9bb66a4fdee938e719f093
Author: David A. Mellis <d mellis arduino cc>
Date:   Wed Aug 17 13:53:49 2011 -0400

    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().

 arduino/cores/arduino/Stream.cpp |  244 ++++++++++++++++++++++++++++++++++++++
 arduino/cores/arduino/Stream.h   |   64 ++++++++++
 2 files changed, 308 insertions(+), 0 deletions(-)
---
diff --git a/arduino/cores/arduino/Stream.cpp b/arduino/cores/arduino/Stream.cpp
new file mode 100644
index 0000000..dea0aff
--- /dev/null
+++ b/arduino/cores/arduino/Stream.cpp
@@ -0,0 +1,244 @@
+/*
+ Stream.cpp - adds parsing methods to Stream class
+ Copyright (c) 2008 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 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
+
+ Created July 2011
+ parsing functions based on TextFinder library by Michael Margolis
+ */
+
+#include "Arduino.h"
+#include "Stream.h"
+
+#define PARSE_TIMEOUT 5  // default number of 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()
+{
+  //Serial.println(_timeout);
+  this->_startMillis = millis();
+  while(millis() - this->_startMillis < (this->_timeout * 1000L))
+  {
+    if (this->available() > 0) {
+      return this->read();
+    }
+  }
+  return -1;     // -1 indicates timeout
+}
+
+// returns the next digit in the stream or -1 if timeout
+// discards non-numeric characters
+int Stream::getNextDigit()
+{
+  int c;
+  do{
+    c = timedRead();
+    if( c < 0)
+      return c;  // timeout
+  }
+  while( c != '-' && (c < '0' || c > '9') ) ;
+
+return c;
+}
+
+// Public Methods
+//////////////////////////////////////////////////////////////
+
+void Stream::setTimeout( long timeout)  // sets the maximum number of seconds to wait
+{
+   this->_timeout = timeout;
+}
+
+ // find returns true if the target string is found
+bool  Stream::find(char *target)
+{
+  return findUntil(target, NULL);
+}
+
+// reads data from the stream until the target string of given length is found
+// returns true if target string is found, false if timed out
+bool Stream::find(char *target, size_t length)
+{
+  return findUntil(target, length, NULL, 0);
+}
+
+// as find but search ends if the terminator string is found
+bool  Stream::findUntil(char *target, char *terminator)
+{
+  return findUntil(target, strlen(target), terminator, strlen(terminator));
+}
+
+// reads data from the stream until the target string of the given length is found
+// search terminated if the terminator string is found
+// returns true if target string is found, false if terminated or timed out
+bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
+{
+  size_t index = 0;  // maximum target string length is 64k bytes!
+  size_t termIndex = 0;
+  int c;
+
+  if( *target == 0)
+     return true;   // return true if target is a null string
+  while( (c = timedRead()) > 0){
+    if( c == target[index]){
+    //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
+      if(++index >= targetLen){ // return true if all chars in the target match
+        return true;
+      }
+    }
+    else{
+      index = 0;  // reset index if any char does not match
+    }
+    if(termLen > 0 && c == terminator[termIndex]){
+       if(++termIndex >= termLen)
+         return false;       // return false if terminate string found before target string
+    }
+    else
+        termIndex = 0;
+  }
+  return false;
+}
+
+
+// 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 = getNextDigit();
+  // ignore non numeric leading characters
+  if(c < 0)
+    return 0; // zero returned if timeout
+
+  do{
+    if(c == skipChar)
+      ; // ignore this charactor
+    else if(c == '-')
+      isNegative = true;
+    else if(c >= '0' && c <= '9')        // is c a digit?
+      value = value * 10 + c - '0';
+    c = timedRead();
+  }
+  while( (c >= '0' && c <= '9')  || c == skipChar );
+
+  if(isNegative)
+    value = -value;
+  return value;
+}
+
+
+// as parseInt but returns a floating point value
+float Stream::parseFloat()
+{
+  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;
+  float fValue;
+  char c;
+  float fraction = 1.0;
+
+  c = getNextDigit();
+    // 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.1;
+    }
+    c = timedRead();
+  }
+  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, null is detected or timeout (see setTimeout)
+// returns the number of characters placed in the buffer (0 means no valid data found)
+int Stream::readChars( char *buffer, size_t length)
+{
+   return readCharsUntil( 0, buffer, length);
+}
+
+
+// as readChars 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)
+
+int Stream::readCharsUntil( char terminator, char *buffer, size_t length)
+{
+ int index = 0;
+    *buffer = 0;
+    while(index < length ){
+      int c = timedRead();
+      if( c <= 0 ){
+        return 0;   // timeout returns 0 !
+      }
+      else if( c == terminator){
+        buffer[index] = 0; // terminate the string
+        return index;               // data got successfully
+      }
+      else{
+        buffer[index++] = (char)c;
+      }
+    }
+    buffer[index] = 0;
+    return index; // here if buffer is full before detecting the terminator
+}
+
+
+// read characters found between pre_string and terminator into a buffer
+// terminated when the terminator character is matched or the buffer is full
+// returns the number of bytes placed in the buffer (0 means no valid data found)
+int Stream::readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length)
+{
+  if( find( pre_string) ){
+    return readCharsUntil(terminator, buffer, length);
+  }
+  return 0;    //failed to find the prestring
+}
diff --git a/arduino/cores/arduino/Stream.h b/arduino/cores/arduino/Stream.h
index 93d8275..3f76392 100644
--- a/arduino/cores/arduino/Stream.h
+++ b/arduino/cores/arduino/Stream.h
@@ -15,6 +15,8 @@
   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
 */
 
 #ifndef Stream_h
@@ -23,13 +25,75 @@
 #include <inttypes.h>
 #include "Print.h"
 
+// compatability 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)
+*/
+
 class Stream : public Print
 {
+  private:
+    long _timeout;      // number of seconds to wait for the next char before aborting timed read
+    long _startMillis;  // used for timeout measurement
+    int timedRead();    // private method to read stream with timeout
+    int getNextDigit(); // 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;
     virtual void flush() = 0;
+
+    Stream() {_timeout=5;}
+
+// parsing methods
+
+  void setTimeout(long timeout);  // sets maximum seconds to wait for stream data, default is 5 seconds
+
+  bool find(char *target);   // reads data from the stream until the target string is found
+  // returns true if target string is found, false if timed out (see setTimeout)
+
+  bool find(char *target, size_t length);   // reads data from the stream until the target string of given length is found
+  // returns true if target string is found, false if timed out
+
+  bool findUntil(char *target, char *terminator);   // as find but search ends if the terminator string is found
+
+  bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen);   // as above but search ends if the terminate string is found
+
+
+  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(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();               // float version of parseInt
+
+  float parseFloat(char skipChar);  // as above but the given skipChar is ignored
+
+  int readChars( char *buffer, size_t length); // read chars from stream into buffer
+  // terminates if length characters have been read or timeout (see setTimeout)
+  // returns the number of characters placed in the buffer (0 means no valid data found)
+
+  int readCharsUntil( char terminator, char *buffer, size_t length); // as readChars 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)
+
+   int readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length);
+  // read characters found between pre_string and terminator into a buffer
+  // terminated when the terminator character is matched or the buffer is full
+  // returns the number of bytes placed in the buffer (0 means no valid data found)
+
+
+  // Arduino String functions to be added here
+
 };
 
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]