您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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