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