Hello,
I have been working on an improvement of the Print class that provides control of the output format. I would like to get your comments and feedback.
The work is available in https://github.com/MichaelJonker/Arduino in the branch Print_fieldControl (or more precisely https://github.com/MichaelJonker/Arduino/tree/Print_fieldControl/hardware/arduino)
Essentially it consists of a backward compatible rewrite of the files Print.h and Print.cpp.
The print methods in my version of the Print class accept an optional third parameter to control the output in terms of minimum field width, filling character and sign forcing.
/* fieldControl enhancements
Enhanced the formatting capabilities of the print methods. The optional third parameter of the print() methods allows to control the print output format in terms of minimum field width, filling character selection and sign forcing.
The recommended way of creating the fieldControl parameter is to use the fieldControl method, which has the following signature :
Print::fieldControl(unsigned char size, bool fillZeroes=false, bool forceSign=false);
Examples:
Serial.print("answer="); Serial.println( 42); // answer=42
Serial.print("answer="); Serial.println( 42, 0, Print::fieldControl(4)); // answer= 42
Serial.print("answer="); Serial.println(137, 0, Print::fieldControl(4)); // answer= 137
Serial.print("answer="); Serial.println(137, 0, Print::fieldControl(4,false, true)); // answer= +137
Serial.print("answer=0x"); Serial.println((unsigned) 0xcafe, Print::Radix_HEX, Print::fieldControl(8, true) ); // answer=0x0000cafe
Serial.print("answer="); Serial.println((unsigned) 0xcafe, Print::Radix_HEX, Print::fieldControl(6) ); // answer= cafe
Serial.print("answer="); Serial.println( (signed) 0xcafe, Print::Radix_HEX, Print::fieldControl(6) ); // answer= -3502
const unsigned char myFieldControl = Print::fieldControl(6, false, true );
Serial.print("answer="); Serial.println( (signed) 0xcafe, Print::Radix_HEX, myFieldControl); // answer= -3502
Serial.print("answer="); Serial.println((unsigned) 0xcafe, Print::Radix_HEX, myFieldControl); // answer= +cafe
The field control parameter can also be used for floating numbers to control the format of the integral part:
const unsigned char myFieldControl = Print::fieldControl(4, true, true );
Serial.print("answer="); Serial.println(41.987654321, 0, myFieldControl); // answer=+0042
Serial.print("answer="); Serial.println(41.987654321, 1, myFieldControl); // answer=+0042.0
Serial.print("answer="); Serial.println(41.987654321, 2, myFieldControl); // answer=+0041.99
Serial.print("answer="); Serial.println(41.987654321, 3, myFieldControl); // answer=+0041.988
Serial.print("answer="); Serial.println(41.987654321, 4, myFieldControl); // answer=+0041.9877
Serial.print("answer="); Serial.println(41.987654321, 5, myFieldControl); // answer=+0041.98765
*/
Notes :
My branch on github is a (fully functional) preview. I am working on a new version that further reduces the footprint of the software (and a minor bug fix). The footprint of my version tested with a mix of various print statements is already smaller than the arduino version.
There is one difference with the current version: floating numbers d with abs(d) > 2147483392.0 (=(double)0x7FFFFF00) will be printed as ovf while in the current version this cut-off happens for values where (d) > 4294967040.0 (= (double)0xFFFFFF00ul).
I intend to also add support for scientific format to print(float) in order to resolve the ovl aspect.
This enhancement is a spin-off of the project https://github.com/MichaelJonker/Arduino_HardwareSerial_RS485, a project to support an RS485 transceiver connected to the USART (Tx/Rx pins) in a half-duplex, concurrent multi-drop (i.e. multi-master, multi-slave) environment. The software suite provides capabilities for message addressing and filtering as well as collision detection and avoidance. I will bring this up for discussion in a separate post.
Kind regards ,
Michael Jonker
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
Serial.println(137, 0,
Print::fieldControl(4));
Serial.println(137, 0,
Print::fieldControl(4,false, true));
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.
As long as the class (first arg you would pass) has a print method for a given type, it will call that method.
On 01/19/2015 03:42 PM, Andrew Kroll wrote:
As long as the class (first arg you would pass) has a print method for a given type, it will call that method.
Maybe I missed something in all the shouting about printf().... how exactly would FancyPrint to be able to control how many characters print for variables foo & bar, what radix is used, whether left padding is zeros or spaces, and whether to always print a sign?
While there is a need, I wonder how intuitive these lines are?
Serial.println(137, 0, Print::fieldControl(4));
Serial.println(137, 0, Print::fieldControl(4,false, true));
Serial.println(137, Print::Radix_DEC, Print::formatControl(0, Print::FillSpace, Print::NoForceSign));
Serial.println(137, Print::Radix_DEC, Print::formatControl(0, Print::FillSpace);
Serial.println(137, Print::Radix_DEC, Print::formatControl(0));
Serial.println(137, Print::Radix_DEC);
Serial.println(137);
// Note that the above examples are, because of the default values, all identical.
// A non-trivial example not using default values is:
Serial.println(137, Print::Radix_HEX, Print::formatControl(8,Print::FillZero,Print::ForceSign));
#define FILL_SPACE Print::FillSpace
#define FILL_ZERO Print::FillZero
#define FORCE_SIGN Print::ForceSign
#define PRINT_FORMAT Print::formatControl
static const unsigned char formatControl(unsigned char size, bool fillZeroes=false, bool forceSign=false)
{
return ( (size==0? 0: size>m_fieldSizeMask ? m_fieldSizeMask:size-1) | (fillZeroes ? m_fillZeroes:0) | (forceSign ? m_forceSign:0) );
}
Serial.println(137, DEC);
Serial.println(137, Print::FormatControl(8, Print::Raxid_HEX, Print::FillZero, Print::ForceSign) );
// or maybe:
Serial.println(137, Print::FormatControl(8, Print::Raxid_HEX | Print::FillZero | Print::ForceSign) );
There was a relevant remark from Paul:While there is a need, I wonder how intuitive these lines are?Serial.println(137, 0, Print::fieldControl(4));Serial.println(137, 0, Print::fieldControl(4,false, true));
I don’t think these are intuitive for the beginner at all. The problem isn’t formatControl vs. fieldControl, it’s the Print::commandName(param, param, param) in the midst of a print statement,
We may even consider to combine the radix and formatControl in a single (two byte int) parameter. This can also be made backward compatible.
Serial.println(137, Print::FormatControl(8, Print::Raxid_HEX, Print::FillZero, Print::ForceSign) );
Serial.println(137, HEX+DIGITS(8)+FILLZERO+PLUSMINUS);
But as a matter of syntax, this is incredibly un-Arduino:
Serial.println(137, Print::FormatControl(8, Print::Raxid_HEX, Print::FillZero, Print::ForceSign) );
Perhaps this can be done without the complex use of C++ static class syntax? Maybe simple addition would be intuitive? Tom?
Serial.println(137, HEX+DIGITS(8)+FILLZERO+PLUSMINUS);
Serial.println(137, HEX(8)+FILLZERO+SIGNED);
- backward compatible, hence Print(3.14159, 3) should still output 3.142 and print(42, 4) should output 222 (Eh oui!)
On Jan 21, 2015, at 4:32 PM, Michael Jonker <michael....@gmail.com> wrote:Thanks for all your comments! I will digest it and try out a few things to come up with a few more solid proposal to choose from.There are a few constraint, i.e. the code should be
- backward compatible, hence Print(3.14159, 3) should still output 3.142 and print(42, 4) should output 222 (Eh oui!)
- intuitive Arduino like (but what is Arduino like, do we have a standard)
- efficient and resource economic, this excludes any printf like format control (see my previous posting).
- and last not but not least, possible to implement.
- not depend on macros if possible (my own personal taste)
Il 21/01/2015 13:30, Matthijs Kooijman ha scritto:
This could partly be fixed by making the Print::ForceSign etc. justbitmask values and (probably using templates) make formatControl accept
different number of arguments and just or'ing them together.
and +1 here too. This looks like to move towards Paul's proposal to "sum" options, but with a more clear syntalx like:
Serial.println(137, HEX(8));
Serial.println(137, HEX(8), FILLZERO, SIGNED);
--
Hi all!Just wanted to chime in again:
I like the HEX & FORCESIGN option best and I completely agree with all the arguments given in the pdf.
One more up-side: This allows library authors to provide formatters for type they provide i.e IPADDRESS or maybe even MORSE (just toying now, but having an instance per formatter is good for extensibility).Final nit-picky comment. If a fluent API were to be considered it would be important to differ between as* and with* I think.
HEX.withSize(6).withLeadingZeros() reads better then asHEX().asSize(6).asLeadingZeros().
Best regards,//Alexander
--
the default underlying printf support on the AVR which does not have the floating point support is just under 2k. i would not call that "substantial". adding the floating point about doubles that. so often even using the full floating point version is still acceptable. I use it all the time. there are so many other areas of the core libraries that can be tweaked to get back a few k, so that when those changes are made the extra 2k for printf support can be "free".
You received this message because you are subscribed to a topic in the Google Groups "Developers" group.
To unsubscribe from this topic, visit https://groups.google.com/a/arduino.cc/d/topic/developers/7KpdLDgFsO0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to developers+...@arduino.cc.
The only major drawback of both printf and sprintf, is that the generic versions of these libs are very large...Is it?Considering that you have to support "%f", which will bring in most of floating-point routines, *even if you don't use it*, yes it is.
Even if Arduino does expand the format control to the proprietary routines in the Print class I see no reason why the IDE can't also add printf() support to the Print class.
Yes there are times when either one is more appropriate by why make that decision for the user?
I much prefer the approach that was taken by Teensduino in that printf() support in the Print class is available "out of the box" and it is your option whether or not to use it. If you use it, it comes with the understanding that there is a bit of code size and ram stack price to pay for it.
Just because you can do a thing does not necessarily mean you should do that thing. Just because I do a thing doesn't necessarily mean Arduino should.