Pages: [1]   Go Down
Author Topic: Add Serial.Printf using va_args and vprinf  (Read 2987 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
God Member
*****
Karma: 0
Posts: 593
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

my title says it all, why not add a simple wrapper for vprintf? Nothing will get broken.
Logged

Freelance engineer, consultant, contractor. Graduated from UW in 2013.

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13072
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Mistakes with printf are very difficult for beginners to debug.  There was a post just today asking for help with sprintf.  Are you willing to assist those who run into trouble?
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 130
Posts: 8620
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the idea of this and was just about to write something the other day because I really hate having 10 Serial.prints in a row just to format a debug print.

As for beginners getting into trouble, true enough.
______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 227
Posts: 14010
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Rob
There allready exists this lib  - http://arduiniana.org/libraries/streaming/ - for easier output C++ style

From this site:

Code:
lcd.print("GPS #");
lcd.print(gpsno);
lcd.print(" date: ");
lcd.print(day);
lcd.print("-");
lcd.print(month);
lcd.print("-");
lcd.println(year); // ugh!!

becomes

Code:
lcd << "GPS #" << gpsno << " date: " <<  day << "-" << month << "-" << year << endl;

With the new library you can also use formatting manipulators like this:

Serial << "Byte value: " << _HEX(b) << endl;
lcd << "The key pressed was " << _BYTE(c) << endl;

This syntax is familiar to many, is easy to read and learn, and, importantly, consumes no resources.  (Because the operator functions are essentially just inline aliases for their print() counterparts, no sketch gets larger or consumes more RAM as a result of their inclusion.)

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 130
Posts: 8620
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, I'll check that out.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Guildford, UK
Offline Offline
Full Member
***
Karma: 0
Posts: 218
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I found this works fine:

http://www.arduino.cc/playground/Main/Printf

As an old school C/C++ programmer this put me back in my comfort zone.
Logged

0
Offline Offline
God Member
*****
Karma: 0
Posts: 593
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I found this works fine:

http://www.arduino.cc/playground/Main/Printf

As an old school C/C++ programmer this put me back in my comfort zone.

Yes, that's exactly what I'm taking about, except I would have liked to see it as a part of the Serial class.

Also the << stream operator should be more well known, or made official, it seems like a good solution. It doesn't look like it works with progmem strings with PSTR yet though, does it?
Logged

Freelance engineer, consultant, contractor. Graduated from UW in 2013.

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 130
Posts: 8620
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I to probably feel more at home with a printf version, but I thought I'd try Streaming.h first.

I LOVE it, no more crappy Serial.print()s.

Thanks a million for the link Rob.
______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Guildford, UK
Offline Offline
Full Member
***
Karma: 0
Posts: 218
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the idea of streaming, especially as I don't need to pull in printf.

However I've no idea how you format a number as you can with printf (e.g. leading zeroes, width etc)
Logged

Offline Offline
Full Member
***
Karma: 11
Posts: 147
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm going to be Contrarian here, but...

Variable lists of parameters is one of the most ill-conceived and poorly executed notions in c.
Overloaded operators is one of the most ill-conceived and poorly executed notions in c++.

They both undermind the notion of a strongly-typed language and make for code that is hard to understand and hard to maintain. There is a reason that subsequent languages have abandonned them.

There's nothing unreasonable about a) using functions to perform the job of functions, rather than operators and format strings; and b) calling a function once for every time you need to use it. Saving keystrokes costs you time in the long run.
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 70
Posts: 2762
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah, well when C++ can create formatted output the simple way C can,
I'll concede but until then xxxprintf() functions are the way to really do formatting.
C++ in all its years of trying to stream i/o has yet to create decent formatting capablities
that are as easy to use as xxxprintf() functions.
(try to output a 4 digit numeric field that is zero filled, as an example)
AND.... todays gcc compilers have knowledge of printf and its formatting strings and check
the types of all the arguments passed to the functions against the expected types
based on the formatting string at compile time.
So you have the type checking of C++ builtin to the compiler with the added
benefit of variable arguments and easy to use formatting capability strings.
Kind of the best of all worlds.
It isn't like the old days where you could easily pass an incorrect format string
or invalid argument to a printf function.
Now you get a warning or even an error depending on your compile options.
So the C++ type checking argument of not using printf() no longer applies
(for most uses of the printf() functions).

===
One of the issues with AVRs and printf() type functions is the RAM usage.
Strings by default end up in the data section when using gcc
and all things in the "data" sections end up in RAM.
This means that all printf formatting strings will consume RAM.


The way to correct this is to move the strings into flash. But that means calling
non standard printf() functions and using a casting element each time you
declare a printf() formatting string.  This is a total pain and most people
simply will not do it.

Here is a collection of functions and macros that I wrote that hides all this complexity
and moves the formatting strings off to FLASH automagically.

Code:
/*
 * Define a REAL printf since Arduino doesn't have one
 *
 * SerialPrintf() will automatically put the format string in AVR program space
 *
 */

#define SerialPrintf(fmt, ...) _SerialPrintf(PSTR(fmt), ##__VA_ARGS__)

extern "C" {
  int serialputc(char c, FILE *fp)
  {
      if(c == '\n')
        Serial.write('\r');
    Serial.write(c);
  }
}


void _SerialPrintf(const char *fmt, ...)
{
FILE stdiostr;
va_list ap;

  fdev_setup_stream(&stdiostr, serialputc, NULL, _FDEV_SETUP_WRITE);

  va_start(ap, fmt);
  vfprintf_P(&stdiostr, fmt, ap);
  va_end(ap);
}

To use it, simple call
SerialPrintf() just like you would use printf().
Thats it.
--- bill

« Last Edit: February 26, 2011, 12:59:40 am by bperrybap » Logged

0
Offline Offline
God Member
*****
Karma: 0
Posts: 593
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hmmm... can you define macros but like a C++ class function?

like this

#define Serial.printf(fmt, ...) fprintf_P(&serstdout, PSTR(fmt), ##__VA_ARGS__)

if that worked, it'll be awesome

Logged

Freelance engineer, consultant, contractor. Graduated from UW in 2013.

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 70
Posts: 2762
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hmmm... can you define macros but like a C++ class function?

like this

#define Serial.printf(fmt, ...) fprintf_P(&serstdout, PSTR(fmt), ##__VA_ARGS__)

if that worked, it'll be awesome



No. The "." is not allowed to be used in that way.
Having played with this quite a bit, using printf() isn't as bad as people think.
It costs about 1.8k of code. The Serial print functions (print class), if you start to use the ones
like print(n, base) or floating pint, you will rapidly eat up more space  than using the
printf functions. The key to using printf() is that if you use it, don't use any of the arduino print class
functions.

--- bill

Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 651
Posts: 50843
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
The key to using printf() is that if you use it, don't use any of the arduino print class
functions.
How do you NOT use the Print class methods?
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 70
Posts: 2762
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess I was a bit vague/confusing there.
What I meant to say is that if you use printf() functions for your formatting,
(as shown in the examples above)
don't also use things like Serial.print() because then you end up with
the code space overhead of both formatting routines.
Stick to one or the other.

One other note is that by default the printf() functions provide no
floating point support, which is the reason that the printf() functions
don't eat up that much space.

Where as some of the print class functions yank in floating point
which eats up quite a bit of code space.

-- bill
Logged

Pages: [1]   Go Up
Jump to: