AvrPrintStimmer.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. Print.cpp - Base class that provides print() and println()
  3. Copyright (c) 2008 David A. Mellis. All right reserved.
  4. many modifications, by Paul Stoffregen <paul@pjrc.com>
  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. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. Modified 23 November 2006 by David A. Mellis
  17. */
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <inttypes.h>
  21. #include <math.h>
  22. #include <avr/pgmspace.h>
  23. #include "Arduino.h" // (was wiring.h)
  24. #include "Print.h"
  25. #if ARDUINO >= 100
  26. #else
  27. void Print::write(const char *str)
  28. {
  29. write((const uint8_t *)str, strlen(str));
  30. }
  31. #endif
  32. #if ARDUINO >= 100
  33. size_t Print::write(const uint8_t *buffer, size_t size)
  34. {
  35. size_t count = 0;
  36. while (size--) count += write(*buffer++);
  37. return count;
  38. }
  39. #else
  40. void Print::write(const uint8_t *buffer, size_t size)
  41. {
  42. while (size--) write(*buffer++);
  43. }
  44. #endif
  45. #if ARDUINO >= 100
  46. size_t Print::print(const String &s)
  47. {
  48. uint8_t buffer[33];
  49. size_t count = 0;
  50. unsigned int index = 0;
  51. unsigned int len = s.length();
  52. while (len > 0) {
  53. s.getBytes(buffer, sizeof(buffer), index);
  54. unsigned int nbytes = len;
  55. if (nbytes > sizeof(buffer)-1) nbytes = sizeof(buffer)-1;
  56. index += nbytes;
  57. len -= nbytes;
  58. count += write(buffer, nbytes);
  59. }
  60. return count;
  61. }
  62. #else
  63. void Print::print(const String &s)
  64. {
  65. unsigned int len = s.length();
  66. for (unsigned int i=0; i < len; i++) {
  67. write(s[i]);
  68. }
  69. }
  70. #endif
  71. #if ARDUINO >= 100
  72. size_t Print::print(const __FlashStringHelper *ifsh)
  73. {
  74. uint8_t buffer[32];
  75. size_t count = 0;
  76. const char PROGMEM *p = (const char PROGMEM *)ifsh;
  77. unsigned int len = strlen_P(p);
  78. while (len > 0) {
  79. unsigned int nbytes = len;
  80. if (nbytes > sizeof(buffer)) nbytes = sizeof(buffer);
  81. memcpy_P(buffer, p, nbytes);
  82. p += nbytes;
  83. len -= nbytes;
  84. count += write(buffer, nbytes);
  85. }
  86. return count;
  87. }
  88. #else
  89. void Print::print(const __FlashStringHelper *ifsh)
  90. {
  91. const char PROGMEM *p = (const char PROGMEM *)ifsh;
  92. while (1) {
  93. unsigned char c = pgm_read_byte(p++);
  94. if (c == 0) return;
  95. write(c);
  96. }
  97. }
  98. #endif
  99. #if ARDUINO >= 100
  100. size_t Print::print(long n)
  101. {
  102. uint8_t sign=0;
  103. if (n < 0) {
  104. sign = 1;
  105. n = -n;
  106. }
  107. return printNumber(n, sign, 10);
  108. }
  109. #else
  110. void Print::print(long n)
  111. {
  112. uint8_t sign=0;
  113. if (n < 0) {
  114. sign = 1;
  115. n = -n;
  116. }
  117. printNumber(n, sign, 10);
  118. }
  119. #endif
  120. #if ARDUINO >= 100
  121. size_t Print::println(void)
  122. {
  123. uint8_t buf[2]={'\r', '\n'};
  124. return write(buf, 2);
  125. }
  126. #else
  127. void Print::println(void)
  128. {
  129. uint8_t buf[2]={'\r', '\n'};
  130. write(buf, 2);
  131. }
  132. #endif
  133. //#define USE_HACKER_DELIGHT_OPTIMIZATION
  134. #define USE_STIMMER_OPTIMIZATION
  135. #define USE_BENCHMARK_CODE
  136. #ifdef USE_HACKER_DELIGHT_OPTIMIZATION
  137. // Adapted from Hacker's Delight (Henry Warren, ISBN 0321842685) www.hackersdelight.org
  138. // by Rob Tillaart, Tom Carpenter, "genom2" with input from others...
  139. // http://forum.arduino.cc/index.php?topic=167414.0
  140. //
  141. #define divmod10_asm(in32, tmp32, mod8) \
  142. asm volatile ( \
  143. "mov %2, %A0 \n\t" /* mod = in */ \
  144. "ori %A0, 1 \n\t" /* q = in | 1 */ \
  145. "movw %A1, %A0 \n\t" /* x = q */ \
  146. "movw %C1, %C0 \n\t" \
  147. "lsr %D1 \n\t" /* x = x >> 2 */ \
  148. "ror %C1 \n\t" \
  149. "ror %B1 \n\t" \
  150. "ror %A1 \n\t" \
  151. "lsr %D1 \n\t" \
  152. "ror %C1 \n\t" \
  153. "ror %B1 \n\t" \
  154. "ror %A1 \n\t" \
  155. "sub %A0, %A1 \n\t" /* q = q - x */ \
  156. "sbc %B0, %B1 \n\t" \
  157. "sbc %C0, %C1 \n\t" \
  158. "sbc %D0, %D1 \n\t" \
  159. "movw %A1, %A0 \n\t" /* x = q */ \
  160. "movw %C1, %C0 \n\t" \
  161. "lsr %D1 \n\t" /* x = x >> 4 */ \
  162. "ror %C1 \n\t" \
  163. "ror %B1 \n\t" \
  164. "ror %A1 \n\t" \
  165. "lsr %D1 \n\t" \
  166. "ror %C1 \n\t" \
  167. "ror %B1 \n\t" \
  168. "ror %A1 \n\t" \
  169. "lsr %D1 \n\t" \
  170. "ror %C1 \n\t" \
  171. "ror %B1 \n\t" \
  172. "ror %A1 \n\t" \
  173. "lsr %D1 \n\t" \
  174. "ror %C1 \n\t" \
  175. "ror %B1 \n\t" \
  176. "ror %A1 \n\t" \
  177. "add %A1, %A0 \n\t" /* x = x + q */ \
  178. "adc %B1, %B0 \n\t" \
  179. "adc %C1, %C0 \n\t" \
  180. "adc %D1, %D0 \n\t" \
  181. "movw %A0, %A1 \n\t" /* q = x */ \
  182. "movw %C0, %C1 \n\t" \
  183. "add %A0, %B1 \n\t" /* q = q + (x >> 8) */ \
  184. "adc %B0, %C1 \n\t" \
  185. "adc %C0, %D1 \n\t" \
  186. "adc %D0, r1 \n\t" \
  187. "mov %A0, %B0 \n\t" /* q = q >> 8 */ \
  188. "mov %B0, %C0 \n\t" \
  189. "mov %C0, %D0 \n\t" \
  190. "eor %D0, %D0 \n\t" \
  191. "add %A0, %A1 \n\t" /* q = q + x */ \
  192. "adc %B0, %B1 \n\t" \
  193. "adc %C0, %C1 \n\t" \
  194. "adc %D0, %D1 \n\t" \
  195. "mov %A0, %B0 \n\t" /* q = q >> 8 */ \
  196. "mov %B0, %C0 \n\t" \
  197. "mov %C0, %D0 \n\t" \
  198. "eor %D0, %D0 \n\t" \
  199. "add %A0, %A1 \n\t" /* q = q + x */ \
  200. "adc %B0, %B1 \n\t" \
  201. "adc %C0, %C1 \n\t" \
  202. "adc %D0, %D1 \n\t" \
  203. "mov %A0, %B0 \n\t" /* q = q >> 8 */ \
  204. "mov %B0, %C0 \n\t" \
  205. "mov %C0, %D0 \n\t" \
  206. "eor %D0, %D0 \n\t" \
  207. "add %A0, %A1 \n\t" /* q = q + x */ \
  208. "adc %B0, %B1 \n\t" \
  209. "adc %C0, %C1 \n\t" \
  210. "adc %D0, %D1 \n\t" \
  211. "andi %A0, 0xF8 \n\t" /* q = q & ~0x7 */ \
  212. "sub %2, %A0 \n\t" /* mod = mod - q */ \
  213. "lsr %D0 \n\t" /* q = q >> 2 */ \
  214. "ror %C0 \n\t" \
  215. "ror %B0 \n\t" \
  216. "ror %A0 \n\t" \
  217. "lsr %D0 \n\t" \
  218. "ror %C0 \n\t" \
  219. "ror %B0 \n\t" \
  220. "ror %A0 \n\t" \
  221. "sub %2, %A0 \n\t" /* mod = mod - q */ \
  222. "lsr %D0 \n\t" /* q = q >> 1 */ \
  223. "ror %C0 \n\t" \
  224. "ror %B0 \n\t" \
  225. "ror %A0 \n\t" \
  226. : "+d" (in32), "=r" (tmp32), "=r" (mod8) : : "r0" \
  227. )
  228. #endif // USE_HACKER_DELIGHT_OPTIMIZATION
  229. #ifdef USE_STIMMER_OPTIMIZATION
  230. // http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
  231. #define divmod10_asm32(in32, mod8, tmp8) \
  232. asm volatile ( \
  233. " ldi %2,51 \n\t" \
  234. " mul %A0,%2 \n\t" \
  235. " clr %A0 \n\t" \
  236. " add r0,%2 \n\t" \
  237. " adc %A0,r1 \n\t" \
  238. " mov %1,r0 \n\t" \
  239. " mul %B0,%2 \n\t" \
  240. " clr %B0 \n\t" \
  241. " add %A0,r0 \n\t" \
  242. " adc %B0,r1 \n\t" \
  243. " mul %C0,%2 \n\t" \
  244. " clr %C0 \n\t" \
  245. " add %B0,r0 \n\t" \
  246. " adc %C0,r1 \n\t" \
  247. " mul %D0,%2 \n\t" \
  248. " clr %D0 \n\t" \
  249. " add %C0,r0 \n\t" \
  250. " adc %D0,r1 \n\t" \
  251. " clr r1 \n\t" \
  252. " add %1,%A0 \n\t" \
  253. " adc %A0,%B0 \n\t" \
  254. " adc %B0,%C0 \n\t" \
  255. " adc %C0,%D0 \n\t" \
  256. " adc %D0,r1 \n\t" \
  257. " add %1,%B0 \n\t" \
  258. " adc %A0,%C0 \n\t" \
  259. " adc %B0,%D0 \n\t" \
  260. " adc %C0,r1 \n\t" \
  261. " adc %D0,r1 \n\t" \
  262. " add %1,%D0 \n\t" \
  263. " adc %A0,r1 \n\t" \
  264. " adc %B0,r1 \n\t" \
  265. " adc %C0,r1 \n\t" \
  266. " adc %D0,r1 \n\t" \
  267. " lsr %D0 \n\t" \
  268. " ror %C0 \n\t" \
  269. " ror %B0 \n\t" \
  270. " ror %A0 \n\t" \
  271. " ror %1 \n\t" \
  272. " ldi %2,10 \n\t" \
  273. " mul %1,%2 \n\t" \
  274. " mov %1,r1 \n\t" \
  275. " clr r1 \n\t" \
  276. :"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
  277. #define divmod10_asm24(in32, mod8, tmp8) \
  278. asm volatile ( \
  279. " ldi %2,51 \n\t" \
  280. " mul %A0,%2 \n\t" \
  281. " clr %A0 \n\t" \
  282. " add r0,%2 \n\t" \
  283. " adc %A0,r1 \n\t" \
  284. " mov %1,r0 \n\t" \
  285. " mul %B0,%2 \n\t" \
  286. " clr %B0 \n\t" \
  287. " add %A0,r0 \n\t" \
  288. " adc %B0,r1 \n\t" \
  289. " mul %C0,%2 \n\t" \
  290. " clr %C0 \n\t" \
  291. " add %B0,r0 \n\t" \
  292. " adc %C0,r1 \n\t" \
  293. " clr r1 \n\t" \
  294. " add %1,%A0 \n\t" \
  295. " adc %A0,%B0 \n\t" \
  296. " adc %B0,%C0 \n\t" \
  297. " adc %C0,r1 \n\t" \
  298. " add %1,%B0 \n\t" \
  299. " adc %A0,%C0 \n\t" \
  300. " adc %B0,r1 \n\t" \
  301. " adc %C0,r1 \n\t" \
  302. " lsr %C0 \n\t" \
  303. " ror %B0 \n\t" \
  304. " ror %A0 \n\t" \
  305. " ror %1 \n\t" \
  306. " ldi %2,10 \n\t" \
  307. " mul %1,%2 \n\t" \
  308. " mov %1,r1 \n\t" \
  309. " clr r1 \n\t" \
  310. :"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
  311. #define divmod10_asm16(in32, mod8, tmp8) \
  312. asm volatile ( \
  313. " ldi %2,51 \n\t" \
  314. " mul %A0,%2 \n\t" \
  315. " clr %A0 \n\t" \
  316. " add r0,%2 \n\t" \
  317. " adc %A0,r1 \n\t" \
  318. " mov %1,r0 \n\t" \
  319. " mul %B0,%2 \n\t" \
  320. " clr %B0 \n\t" \
  321. " add %A0,r0 \n\t" \
  322. " adc %B0,r1 \n\t" \
  323. " clr r1 \n\t" \
  324. " add %1,%A0 \n\t" \
  325. " adc %A0,%B0 \n\t" \
  326. " adc %B0,r1 \n\t" \
  327. " add %1,%B0 \n\t" \
  328. " adc %A0,r1 \n\t" \
  329. " adc %B0,r1 \n\t" \
  330. " lsr %B0 \n\t" \
  331. " ror %A0 \n\t" \
  332. " ror %1 \n\t" \
  333. " ldi %2,10 \n\t" \
  334. " mul %1,%2 \n\t" \
  335. " mov %1,r1 \n\t" \
  336. " clr r1 \n\t" \
  337. :"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
  338. #define divmod10_asm8(in32, mod8, tmp8) \
  339. asm volatile ( \
  340. " ldi %2,51 \n\t" \
  341. " mul %A0,%2 \n\t" \
  342. " clr %A0 \n\t" \
  343. " add r0,%2 \n\t" \
  344. " adc %A0,r1 \n\t" \
  345. " mov %1,r0 \n\t" \
  346. " clr r1 \n\t" \
  347. " add %1,%A0 \n\t" \
  348. " adc %A0,r1 \n\t" \
  349. " lsr %A0 \n\t" \
  350. " ror %1 \n\t" \
  351. " ldi %2,10 \n\t" \
  352. " mul %1,%2 \n\t" \
  353. " mov %1,r1 \n\t" \
  354. " clr r1 \n\t" \
  355. :"+r"(in32),"=d"(mod8),"=d"(tmp8) : : "r0")
  356. #endif // USE_STIMMER_OPTIMIZATION
  357. #ifdef USE_BENCHMARK_CODE
  358. uint32_t usec_print = 0;
  359. #endif
  360. #if ARDUINO >= 100
  361. size_t Print::printNumberDec(unsigned long n, uint8_t sign)
  362. #else
  363. void Print::printNumberDec(unsigned long n, uint8_t sign)
  364. #endif
  365. {
  366. uint8_t digit, buf[11], *p;
  367. uint32_t tmp32;
  368. uint8_t tmp8;
  369. #ifdef USE_BENCHMARK_CODE
  370. uint32_t usec = micros();
  371. #endif
  372. p = buf + (sizeof(buf)-1);
  373. #if defined(USE_STIMMER_OPTIMIZATION)
  374. while(n & 0xff000000){divmod10_asm32(n, digit, tmp8);*--p = digit + '0';}
  375. while(n & 0xff0000){divmod10_asm24(n, digit, tmp8);*--p = digit + '0';}
  376. while(n & 0xff00){divmod10_asm16(n, digit, tmp8);*--p = digit + '0';}
  377. while((n & 0xff)>9){divmod10_asm8(n, digit, tmp8);*--p = digit + '0';}
  378. *--p = n + '0';
  379. #else
  380. do {
  381. #if defined(USE_HACKER_DELIGHT_OPTIMIZATION)
  382. divmod10_asm(n, tmp32, digit);
  383. #else
  384. tmp32 = n;
  385. n = n / 10;
  386. digit = tmp32 - n * 10;
  387. #endif
  388. *--p = digit + '0';
  389. } while (n);
  390. #endif
  391. if (sign) *--p = '-';
  392. #ifdef USE_BENCHMARK_CODE
  393. usec_print += micros() - usec;
  394. #endif
  395. #if ARDUINO >= 100
  396. return write(p, sizeof(buf)-1 - (p - buf));
  397. #else
  398. write(p, sizeof(buf)-1 - (p - buf));
  399. #endif
  400. }
  401. #if ARDUINO >= 100
  402. size_t Print::printNumberHex(unsigned long n)
  403. #else
  404. void Print::printNumberHex(unsigned long n)
  405. #endif
  406. {
  407. uint8_t digit, buf[8], *p;
  408. p = buf + (sizeof(buf)-1);
  409. do {
  410. digit = n & 15;
  411. *--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
  412. n >>= 4;
  413. } while (n);
  414. #if ARDUINO >= 100
  415. return write(p, sizeof(buf)-1 - (p - buf));
  416. #else
  417. write(p, sizeof(buf)-1 - (p - buf));
  418. #endif
  419. }
  420. #if ARDUINO >= 100
  421. size_t Print::printNumberBin(unsigned long n)
  422. #else
  423. void Print::printNumberBin(unsigned long n)
  424. #endif
  425. {
  426. uint8_t buf[32], *p;
  427. p = buf + (sizeof(buf)-1);
  428. do {
  429. *--p = '0' + ((uint8_t)n & 1);
  430. n >>= 1;
  431. } while (n);
  432. #if ARDUINO >= 100
  433. return write(p, sizeof(buf)-1 - (p - buf));
  434. #else
  435. write(p, sizeof(buf)-1 - (p - buf));
  436. #endif
  437. }
  438. #if ARDUINO >= 100
  439. size_t Print::printNumberAny(unsigned long n, uint8_t base)
  440. #else
  441. void Print::printNumberAny(unsigned long n, uint8_t base)
  442. #endif
  443. {
  444. uint8_t digit, buf[21], *p;
  445. uint32_t tmp;
  446. //uint32_t usec;
  447. //usec = micros();
  448. p = buf + (sizeof(buf)-1);
  449. do {
  450. tmp = n;
  451. n = n / base;
  452. digit = tmp - n * base;
  453. *--p = (digit < 10) ? '0' + digit : 'A' + digit - 10;
  454. } while (n);
  455. //usec_print += micros() - usec;
  456. #if ARDUINO >= 100
  457. return write(p, sizeof(buf)-1 - (p - buf));
  458. #else
  459. write(p, sizeof(buf)-1 - (p - buf));
  460. #endif
  461. }
  462. #if ARDUINO >= 100
  463. size_t Print::printFloat(double number, uint8_t digits)
  464. #else
  465. void Print::printFloat(double number, uint8_t digits)
  466. #endif
  467. {
  468. uint8_t sign=0;
  469. #if ARDUINO >= 100
  470. size_t count=0;
  471. #endif
  472. // Handle negative numbers
  473. if (number < 0.0) {
  474. sign = 1;
  475. number = -number;
  476. }
  477. // Round correctly so that print(1.999, 2) prints as "2.00"
  478. double rounding = 0.5;
  479. for (uint8_t i=0; i<digits; ++i) {
  480. rounding *= 0.1;
  481. }
  482. number += rounding;
  483. // Extract the integer part of the number and print it
  484. unsigned long int_part = (unsigned long)number;
  485. double remainder = number - (double)int_part;
  486. #if ARDUINO >= 100
  487. count += printNumber(int_part, sign, 10);
  488. #else
  489. printNumber(int_part, sign, 10);
  490. #endif
  491. // Print the decimal point, but only if there are digits beyond
  492. if (digits > 0) {
  493. uint8_t n, buf[8], count=1;
  494. buf[0] = '.';
  495. // Extract digits from the remainder one at a time
  496. if (digits > sizeof(buf) - 1) digits = sizeof(buf) - 1;
  497. while (digits-- > 0) {
  498. remainder *= 10.0;
  499. n = (uint8_t)(remainder);
  500. buf[count++] = '0' + n;
  501. remainder -= n;
  502. }
  503. #if ARDUINO >= 100
  504. count += write(buf, count);
  505. #else
  506. write(buf, count);
  507. #endif
  508. }
  509. #if ARDUINO >= 100
  510. return count;
  511. #endif
  512. }