Go Down

Topic: No cost streams (Read 5 times) previous topic - next topic


Feb 11, 2009, 09:38 pm Last Edit: Feb 11, 2009, 09:46 pm by mikalhart Reason: 1
Yeah, the generic version is the one with "template"!

Ah, I think I see the problem.  Your old HardwareSerial.h doesn't define a print method for type "const char []".  Here's what you need to do:

1. In HardwareSerial.h, change the two instances of "char []" to "const char []".
2. In HardwareSerial.cpp, change the two instances of "char c[]" to "const char c[]".
3. Add the "HardwareSerial" version of the "template..." line either to the bottom of HardwareSerial.h or, if you prefer, at the top of your sketch.
Code: [Select]
//alternative option for Franky's Sanguino
template<class T>
inline HardwareSerial &operator <<(HardwareSerial &obj, T arg)
{ obj.print(arg); return obj; }

I'm guessing that this will work for you, but if not, I have one last trick up my sleeve.



I think you will have to release your last trick.. same problem with the general template, instantiated from here..

Oh and the const replacement did not work, as the _uart() function needs a pointer, and the casting does not work..


Feb 11, 2009, 10:29 pm Last Edit: Feb 11, 2009, 10:53 pm by mikalhart Reason: 1
Don't give up yet on that idea yet!  :) Keep the const's in there but change

Code: [Select]
   uart_write(_uart, &c[i], 1);


Code: [Select]
   uart_write(_uart, (char *)&c[i], 1);

If that all still doesn't work -- but it will eventually! -- dump the template and manually insert the 7

Code: [Select]
inline HardwareSerial &operator <<(HardwareSerial &obj, char *arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj, char arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj,  uint8_t arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj,  int arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj,  unsigned arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj,  long arg) { obj.print(arg); return obj; }
inline HardwareSerial &operator <<(HardwareSerial &obj,  unsigned long arg) { obj.print(arg); return obj; }


Feb 11, 2009, 11:30 pm Last Edit: Feb 11, 2009, 11:33 pm by Franky Reason: 1
Yeehaa! That works!! Thank you for all your work on this..

Another question: did you think of including the base markers, like hex, dec, bin in the stream? Is it even possible? For what I know about C++, these markers modify all the stream until another marker is found, kind of hard to implement, but maybe by only applying the marker once, on the immediate next value sent on the stream..

Implementing endl newline marker is easy: #define endl "\n"


Feb 11, 2009, 11:41 pm Last Edit: Feb 11, 2009, 11:44 pm by mikalhart Reason: 1
Yes, it would be nice to have hex and bin manipulators, but that would require substantially more than the "single line" template.  I may do it someday if crowds of people beat down my door.

And for other people reading this thread, keep in mind that the last 15 or so posts just deal with Franky's special Sanguino build.  For most people, this is perfectly sufficient:

Code: [Select]
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

I also wrote this up on my Arduino site.



Yeah, and I think a dedicated library is worth it, I just wait to learn a bit more about C++ and I start studying this (I'm in the library-making mood these days..)

I will write to Zach Smith, the author of the Sanguino, to give him the modifications of the core code for its 1.4 release.. And that would be cool to have this feature as native in the cores of the arduino 13 IDE..


Nice! This saved many lines of code, and actually made the binary a wee bit smaller :)

Now if only I could get rid of sprintf and strcpy()... I wouldn't have to import stdio.h and I'd save 2k!


sprintf? What do you use this function for? strcpy is naturally available on the arduino, I use it without having to include stdlib or stdio.


Feb 14, 2009, 09:44 pm Last Edit: Feb 14, 2009, 09:47 pm by JustinHoMi Reason: 1
I *was* using it for string concatenation until you made me realize that I get strcat for free in string.h :)

Oh man... if only there were an embedded version of python....

Anyways, I see no reason not to put streams in the default namespace. It takes up no additional flash, and it still allows people use the standard print statements, keeping it's "pseudo-sideways-compatibility" with Processing.


if only there were an embedded version of python....
Pymite answers that request but unfortunately the Arduino's ATmega168 is not up to the task of running it.


Paul V.

Apr 17, 2009, 11:16 am Last Edit: Apr 17, 2009, 11:23 am by pvercello Reason: 1
So I found myself wanting to have line feeds after printing my variables for easier use over the serial monitor.  I added one more piece (show here in bold) to Mikal's code as to make it a bit more like the C++ std library in this regard:

[font=Courier]template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

enum EndLineCode {  endl  };

inline Print &operator <<(Print &obj, EndLineCode arg) { obj.print(13, BYTE); obj.print(10, BYTE); return obj; }

With this you can do something like:

[font=Courier]  Serial << "Value printing on line one: " << value << endl << "Value2 printing on line two: " << value2 << endl;[/font]

Which prints out

[font=Courier]Value printing on line one: 100
Value2 printing on line two: 200[/font]

This also takes the same amount of space as just writing a println (or writing out the CR & LF combo separately), so there's no overhead with doing it this way.  

I could add to the playground page if it's useful.



Apr 17, 2009, 02:12 pm Last Edit: Apr 18, 2009, 04:13 am by mikalhart Reason: 1
Very good stuff.  I'll add it to my web page and the playground.  Although wouldn't this be better:

Code: [Select]
inline Print &operator <<(Print &obj, EndLineCode arg) { obj.println();  return obj; }



Paul V.

Ah, yeah.  I didn't realize you couldn't call println with no arguments.  Yes, that's better.



Apr 18, 2009, 04:11 am Last Edit: Apr 18, 2009, 04:23 am by mikalhart Reason: 1
Thanks to Paul V. and Ben Combee for their useful suggestions on how to support line endings (C++ "endl") and internal format manipulators, respectively, we now have a bona fide Streaming library.

With it, you can now write code like this:

Code: [Select]
 Serial << "A is " << lettera << "." << endl;
 lcd << "The current date is " << day << "-" << month << "-" << year << "." << endl;
 eth << "You can use modifiers too, for example:" << endl;
 Serial << _BYTE(lettera) << " is " << _HEX(lettera) << " in hex. " << endl;

And thanks very much for all the Arduinians who have used and commented on Streaming.  Cool stuff.

The new library is available at http://arduiniana.org/libraries/streaming.



Arduino version 0018 has added the capability to print floats specifying the number of digits after the decimal point.
Here is a modification to Mikal's library to support this.
Code: [Select]
Streaming.h - Arduino library for supporting the << streaming operator
Copyright (c) 2009 Mikal Hart.  All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


#include <WProgram.h>

#define STREAMING_LIBRARY_VERSION 3  // modifed to support floating point digit argument - mem 20 Feb 2010

// Generic template
template<class T>
inline Print &operator <<(Print &stream, const T arg)
{ stream.print(arg); return stream; }

struct _BASED
 long val;
 int base;
 _BASED(long v, int b): val(v), base(b)

struct _FLOAT
 float val;
 int digits;
 _FLOAT(double v, int d): val(v), digits(d)

#define _HEX(a)     _BASED(a, HEX)
#define _DEC(a)     _BASED(a, DEC)
#define _OCT(a)     _BASED(a, OCT)
#define _BIN(a)     _BASED(a, BIN)
#define _BYTE(a)    _BASED(a, BYTE)

// Specialization for class _BASED
// Thanks to Arduino forum user Ben Combee who suggested this
// clever technique to allow for expressions like
//   Serial << _HEX(a);

inline Print &operator <<(Print &obj, const _BASED &arg)
{ obj.print(arg.val, arg.base); return obj; }

// Specialization for class _FLOAT
inline Print &operator <<(Print &obj, const _FLOAT &arg)
{ obj.print(arg.val, arg.digits); return obj; }

// Specialization for enum _EndLineCode
// Thanks to Arduino forum user Paul V. who suggested this
// clever technique to allow for expressions like
//   Serial << "Hello!" << endl;

enum _EndLineCode { endl };

inline Print &operator <<(Print &obj, _EndLineCode arg)
{ obj.println(); return obj; }


Go Up