Printf in Arduino Due

I recently added this on Teensy 3.0, which uses a similar ARM chip. Here's the code (in Print.cpp), if anyone interested in trying on Arduino Due.

extern "C" {
__attribute__((weak))
int _write(int file, char *ptr, int len)
{
        ((class Print *)file)->write((uint8_t *)ptr, len);
        return 0;
}
}

int Print::printf(const char *format, ...)
{
        va_list ap;
        va_start(ap, format);
        return vdprintf((int)this, format, ap);
}

int Print::printf(const __FlashStringHelper *format, ...)
{
        va_list ap;
        va_start(ap, format);
        return vdprintf((int)this, (const char *)format, ap);
}

Paul,
I replied back to the email you sent me about adding printf support into the Print class for the AVR.
Maybe you didn't get it?
Here is a summary:

It has to take into consideration line endings.
foo.printf("Hello World\n");
should work the same as
foo.println("Hello World");

I ended up having to put a check in the putchar/write routine
to check for a new line and force out a carriage routine just
before sending out the new line to make line wrappings work properly
for serial terminals.
(You can see on the Printf page I updated)


BTW, I hadn't seen vdprintf() before, that will be better than the static
buffer I was using for non AVR processors. It is too bad that the AVR doesn't
include this function, it would have made things much simpler and portable.

--- bill

For now, I'm not really concerned that println() sends CR & LF, but printf("\n") sends on LF.

On Linux, the Arduino Serial Monitor seems to handle LF only pretty well. I haven't tested what it does on Windows and Mac, but if those 2 systems don't treat LF only as a line break, perhaps the best solution is to update the IDE.

I've been wrestling with line ending issues on serial ports for over 30 years.
Most of it because of the way that CPM, Windows, and MAC did things. (vs unix)
The non unix platforms don't have the simple concept of "newlines" or
concept of raw vs cooked modes.
As a result they tend to always send/need both and often screw things up.

You have made the assumption that the only consumer of the character output is the Arduino IDE.
This is not always the case.
Try using using some serial device other than the IDE to monitor the serial port.
maybe putty? or an actual terminal.
Also, there are some embedded devices out there with serial ports that parse serial data, and not all of them
look for to parse the lines.
Some embedded devices only look for the and toss the
since they were designed to be connected to a real teminal which sends a
when user presses the /ENTER button on the keyboard.

There is no one be all answer for this since in order to make it work for
all situations you really need to have both raw and cooked modes.
However, what I've found is that cooked mode, where carriage routines
are inserted, tends to offer the greatest compability.

Just some things to think about.

--- bill

I might still add yet another layer to translate LF to CR & LF. But on my (incredibly long) list of features to develop, this is a pretty low priority.

For now (Teensyduino 1.17), I'm going to leave it as-is without any translation. If someone is using a terminal emulator that can't be configured to deal with only LF, they'll just have to use printf("\r\n"), or stick with the Arduino println() function.

In serial1.c, serial_print() and those other functions at the end are leftover debugging stuff. They were mostly used while I was developing the USB stack. I'm planning to remove them eventually.

I saw that. I was just curious why the translation was thought to be important enough to put in that code
but now it is not in the new printf() for the Print class.
Change of thinking?

--- bill

I was just curious why the translation was thought to be important enough to put in that code
but now it is not in the new printf() for the Print class.

I'm pretty sure that was just a copy and paste from some other project.

That serial code is intended to process data 1 character at a time. The original version (while developing the USB code) didn't use interrupts at all. It doesn't matter if extra time is spent processing each character, since it's just going to busy loop on the UART, and it's never meant to be part of any real program anyway.

The print class code is meant to be in real applications. Performance matters. Processing data as a block is extremely beneficial when the output device is USB or Ethernet. Taking a block of data and processing 1-byte-at-a-time involves a pretty big performance hit if individual bytes are sent to the USB Serial write() function.

There are lots of ways to deal with this, of course, involving more complexity.

So to directly answer your question Bill, my motivation is based on performance and simplicity, and also somewhat laziness (far too many other higher priority software priorities), and also somewhat laziness in that the _write(fd, buf, len) API maps neatly onto the print class write(buf, len). :slight_smile:

Then again, if not translating LF to CR+LF turns out to be a problem for a substantial number of users, I'll certainly respond by elevating the priority from "not likely to ever get around to it" to something likely to happen. Much like supporting printf() at all in the Print class, which has been on my low priority list for many months, I did get around to it, mainly because it's been requested more frequently. With only a limited number of hours in each day and a TODO list longer than I'll ever complete, I have to prioritize somehow. I mostly go with what the most people want, and adding yet another layer for LF translation (without a big performance penalty on USB) is no exception.

:wink: ]:slight_smile: All the time it has taken to write all these forum messages, I am thinking CR/LF could have been implemented in less time :wink:

Regards,

Grham

I understand. I didn't mean to upset you. I was more interested out of curiousity
how you ended up with the different implementations
than any sort of prodding one direction or the other.
I'm a unix guy so I do agree with you.
I believe that unix got line endings correct long before the others
went off in their own different directions,
--- bill

This seems to be a long running issue in a variety of different areas, not just Arduino printf.

http://ascii-table.com/control-chars.php

[Ctrl] J 10 0A LF Line Feed FE A format effector which advances the active position to the same character position of the next line.

[Ctrl] M 13 0D CR Carriage Return FE A format effector which moves the active position to the first character position on the same line.

Try playing with an old EPSON FX80 dot matrix printer, you will find it behaves in the manner as defined above as does Windows Hyperterminal, such that if you want to go down a line AND start at the beginning of that line, you NEED to issue both CR AND LF.

The serial monitor in the IDE doesn't care, but that does not mean that people should not be aware of what CR, CR/LF or LF is actually 'supposed' to do.

Regards,

Graham

I'm not upset. You did ask pointedly about my reasoning, and I took a moment to explain.

I should also add that I might be willing to accept a pull request that adds this translation layer. But if it imposes a lot of overhead, like taking block transfers and turning them into byte-at-a-time writes, it'll need to be disabled by default.

Then again, I could be really swayed by a pull request accompanied by some significant work to benchmark performance over a variety of print(), println() and printf() scenarios.

Well I eluded to this in my previous post, but my 'tuppence worth, is that if you do need to issue "\r\n" then do so, but if the choice is taken away programatically such that "\n" will issue CR/LF regardless.............. what if a user actually requires independent control of "\n" , "\r", "\n\r" or am I missing the point here?

Regards,

Graham

How could I set the output of printf to SerialUSB?

So how I could change the stdout to SerialUSB?

phr3ak:
How could I set the output of printf to SerialUSB?

#define _PRINTF_BUFFER_LENGTH_		96
#define _Stream_Obj_				SerialUSB

static char _pf_buffer_[_PRINTF_BUFFER_LENGTH_];


#define printf(a,...)											\
	do{													\
	snprintf(_pf_buffer_, sizeof(_pf_buffer_), (a), ##__VA_ARGS__);			\
	_Stream_Obj_.print(_pf_buffer_);								\
	}while(0)

#define printfn(a,...)											\
	do{													\
	snprintf(_pf_buffer_, sizeof(_pf_buffer_), a"\r\n", ##__VA_ARGS__);		\
	_Stream_Obj_.print(_pf_buffer_);								\
	}while(0)

Works for me.

where is it?

Make the (minor) change to Print.h suggested here: Arduino Playground - Printf and ALL classes that inherent from Print will support printf directly, so you can simply use "Serial1.printf()".

Regards,
Ray L.