My Marlin configs for Fabrikator Mini and CTC i3 Pro B
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

Stream.cpp 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. findMulti/findUntil routines written by Jim Leonard/Xuth
  18. */
  19. #include <stdlib.h>
  20. #include <Arduino.h>
  21. #include "Stream.h"
  22. #define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
  23. #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
  24. // private method to read stream with timeout
  25. int Stream::timedRead()
  26. {
  27. int c;
  28. _startMillis = millis();
  29. do {
  30. c = read();
  31. if (c >= 0) return c;
  32. } while(millis() - _startMillis < _timeout);
  33. return -1; // -1 indicates timeout
  34. }
  35. // private method to peek stream with timeout
  36. int Stream::timedPeek()
  37. {
  38. int c;
  39. _startMillis = millis();
  40. do {
  41. c = peek();
  42. if (c >= 0) return c;
  43. } while(millis() - _startMillis < _timeout);
  44. return -1; // -1 indicates timeout
  45. }
  46. // returns peek of the next digit in the stream or -1 if timeout
  47. // discards non-numeric characters
  48. int Stream::peekNextDigit()
  49. {
  50. int c;
  51. while (1) {
  52. c = timedPeek();
  53. if (c < 0) return c; // timeout
  54. if (c == '-') return c;
  55. if (c >= '0' && c <= '9') return c;
  56. read(); // discard non-numeric
  57. }
  58. }
  59. // Public Methods
  60. //////////////////////////////////////////////////////////////
  61. void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
  62. {
  63. _timeout = timeout;
  64. }
  65. // find returns true if the target string is found
  66. bool Stream::find(char *target)
  67. {
  68. return findUntil(target, strlen(target), NULL, 0);
  69. }
  70. // reads data from the stream until the target string of given length is found
  71. // returns true if target string is found, false if timed out
  72. bool Stream::find(char *target, size_t length)
  73. {
  74. return findUntil(target, length, NULL, 0);
  75. }
  76. // as find but search ends if the terminator string is found
  77. bool Stream::findUntil(char *target, char *terminator)
  78. {
  79. return findUntil(target, strlen(target), terminator, strlen(terminator));
  80. }
  81. // reads data from the stream until the target string of the given length is found
  82. // search terminated if the terminator string is found
  83. // returns true if target string is found, false if terminated or timed out
  84. bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
  85. {
  86. if (terminator == NULL) {
  87. MultiTarget t[1] = {{target, targetLen, 0}};
  88. return findMulti(t, 1) == 0 ? true : false;
  89. } else {
  90. MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
  91. return findMulti(t, 2) == 0 ? true : false;
  92. }
  93. }
  94. // returns the first valid (long) integer value from the current position.
  95. // initial characters that are not digits (or the minus sign) are skipped
  96. // function is terminated by the first character that is not a digit.
  97. long Stream::parseInt()
  98. {
  99. return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
  100. }
  101. // as above but a given skipChar is ignored
  102. // this allows format characters (typically commas) in values to be ignored
  103. long Stream::parseInt(char skipChar)
  104. {
  105. bool isNegative = false;
  106. long value = 0;
  107. int c;
  108. c = peekNextDigit();
  109. // ignore non numeric leading characters
  110. if(c < 0)
  111. return 0; // zero returned if timeout
  112. do{
  113. if(c == skipChar)
  114. ; // ignore this charactor
  115. else if(c == '-')
  116. isNegative = true;
  117. else if(c >= '0' && c <= '9') // is c a digit?
  118. value = value * 10 + c - '0';
  119. read(); // consume the character we got with peek
  120. c = timedPeek();
  121. }
  122. while( (c >= '0' && c <= '9') || c == skipChar );
  123. if(isNegative)
  124. value = -value;
  125. return value;
  126. }
  127. // as parseInt but returns a floating point value
  128. float Stream::parseFloat()
  129. {
  130. return parseFloat(NO_SKIP_CHAR);
  131. }
  132. // as above but the given skipChar is ignored
  133. // this allows format characters (typically commas) in values to be ignored
  134. float Stream::parseFloat(char skipChar){
  135. bool isNegative = false;
  136. bool isFraction = false;
  137. long value = 0;
  138. char c;
  139. float fraction = 1.0;
  140. c = peekNextDigit();
  141. // ignore non numeric leading characters
  142. if(c < 0)
  143. return 0; // zero returned if timeout
  144. do{
  145. if(c == skipChar)
  146. ; // ignore
  147. else if(c == '-')
  148. isNegative = true;
  149. else if (c == '.')
  150. isFraction = true;
  151. else if(c >= '0' && c <= '9') { // is c a digit?
  152. value = value * 10 + c - '0';
  153. if(isFraction)
  154. fraction *= 0.1;
  155. }
  156. read(); // consume the character we got with peek
  157. c = timedPeek();
  158. }
  159. while( (c >= '0' && c <= '9') || c == '.' || c == skipChar );
  160. if(isNegative)
  161. value = -value;
  162. if(isFraction)
  163. return value * fraction;
  164. else
  165. return value;
  166. }
  167. // read characters from stream into buffer
  168. // terminates if length characters have been read, or timeout (see setTimeout)
  169. // returns the number of characters placed in the buffer
  170. // the buffer is NOT null terminated.
  171. //
  172. size_t Stream::readBytes(char *buffer, size_t length)
  173. {
  174. size_t count = 0;
  175. while (count < length) {
  176. int c = timedRead();
  177. if (c < 0) break;
  178. *buffer++ = (char)c;
  179. count++;
  180. }
  181. return count;
  182. }
  183. // as readBytes with terminator character
  184. // terminates if length characters have been read, timeout, or if the terminator character detected
  185. // returns the number of characters placed in the buffer (0 means no valid data found)
  186. size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
  187. {
  188. if (length < 1) return 0;
  189. size_t index = 0;
  190. while (index < length) {
  191. int c = timedRead();
  192. if (c < 0 || c == terminator) break;
  193. *buffer++ = (char)c;
  194. index++;
  195. }
  196. return index; // return number of characters, not including null terminator
  197. }
  198. String Stream::readString()
  199. {
  200. String ret;
  201. int c = timedRead();
  202. while (c >= 0)
  203. {
  204. ret += (char)c;
  205. c = timedRead();
  206. }
  207. return ret;
  208. }
  209. String Stream::readStringUntil(char terminator)
  210. {
  211. String ret;
  212. int c = timedRead();
  213. while (c >= 0 && c != terminator)
  214. {
  215. ret += (char)c;
  216. c = timedRead();
  217. }
  218. return ret;
  219. }
  220. int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
  221. // any zero length target string automatically matches and would make
  222. // a mess of the rest of the algorithm.
  223. for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
  224. if (t->len <= 0)
  225. return t - targets;
  226. }
  227. while (1) {
  228. int c = timedRead();
  229. if (c < 0)
  230. return -1;
  231. for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
  232. // the simple case is if we match, deal with that first.
  233. if (c == t->str[t->index]) {
  234. if (++t->index == t->len)
  235. return t - targets;
  236. else
  237. continue;
  238. }
  239. // if not we need to walk back and see if we could have matched further
  240. // down the stream (ie '1112' doesn't match the first position in '11112'
  241. // but it will match the second position so we can't just reset the current
  242. // index to 0 when we find a mismatch.
  243. if (t->index == 0)
  244. continue;
  245. int origIndex = t->index;
  246. do {
  247. --t->index;
  248. // first check if current char works against the new current index
  249. if (c != t->str[t->index])
  250. continue;
  251. // if it's the only char then we're good, nothing more to check
  252. if (t->index == 0) {
  253. t->index++;
  254. break;
  255. }
  256. // otherwise we need to check the rest of the found string
  257. int diff = origIndex - t->index;
  258. size_t i;
  259. for (i = 0; i < t->index; ++i) {
  260. if (t->str[i] != t->str[i + diff])
  261. break;
  262. }
  263. // if we successfully got through the previous loop then our current
  264. // index is good.
  265. if (i == t->index) {
  266. t->index++;
  267. break;
  268. }
  269. // otherwise we just try the next index
  270. } while (t->index);
  271. }
  272. }
  273. // unreachable
  274. return -1;
  275. }