/ teensy / Print.cpp
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