Hello,
The implementation of the Print enhancement is available for review.
This thread is a follow up of the thread "Adding format control to the Print class methods";
You can find the implementation in my github fork /MichaelJonker/Arduino in the branch review_FormattedPrint :
i.e. https://github.com/MichaelJonker/Arduino/tree/review_FormattedPrint
The relevant files in here are under hardware/arduino/avr/cores/arduino (location conforms to release 1.6)
PrintFormat.h // defines the print format control classes (including the implementation of all methods)
Print.h // defines the print interface (and inline implementations of trivial Print methods)
Print.cpp // implementation of the non trivial Print methods
In short, this code will allow the user to code things like:
Serial.println(3.141592, PRECISION(4) & FIELDSIZE(3)); // 3.1416 ; note FIELDSIZE only concerns integer part, not the fraction
Serial.println(66, HEX); // 42 ;
Serial.println(22, RADIX(5) & FIELDSIZE(8) & ALIGNLEFT); // 42 ;
Serial.println(34, OCT & FIELDSIZE(8) & FORCESIGN & FILLZEROS); // +00000042 ; note forced sign does not consume FIELDSIZE
Serial.println(54, 13); // 42 ; backward compatible base argument
Serial.println(3.141592, 3); // 3.142 ; backward compatible precision argument
There are some more handy features. These can be discovered from the sample code stored in the above mentioned github branch under examples/test_FormattedPrint
testFormattedPrint.ino ino sketch which calls PrintDemo().
PrintDemo.cpp demo showing the usage of the Print and PrintFormat classes.
Notes:
- The file PrintDemo.cpp contains instructions to compile and run the PrintDemo in standalone mode outside the Arduino environment (I used this under Cygwin for a fast development cycle)
- The file PrintSequenceTeaser.cpp, also present, is a teaser (aka preview) of a PrintSequence class (still in the design stage).
(However, please keep this thread focussed on the Print and PrintFormat classes and do not comment features related to the PrintSequence class in this thread.
Discussion related to the PrintSequence class will be launched in different thread soon.)
The Print and PrintFormat classes are functionally complete. I plan to work on optimisation (code reduction) and the implementation of a scientific print format.
I have chosen for the print format syntax in the style: OCT & FIELDSIZE(6) & FILLZEROS.
A syntax style like OCT.withFieldSize(6).withFillZeros() has not been provided (but could be added if this is what the community want).
I have not implemented a PrintFormatter class for custom formatting.
The primary reason is that one cannot define templates for virtual methods making a hypothetical abstract PrintFormatter class in first instance boring and inefficient (large vtable).
Furthermore, such a class makes only sense for basic types, non basic types need to implement a Printable interface for them to become printable. Hence there is already full control over the format.
With the latter in mind, one can easily see that custom formatting of basic types can be readily achieved through an adapter class:
// Using an adapter class IPAddressFormatAdapter
class IPAddressFormatAdapter : public Printable
{
typedef unsigned char IPAdress[4];
IPAdress myIPAddress;
static unsigned long& _asLong(IPAdress& anIPAdress) { return (unsigned long&) anIPAdress;} // interpret an unsigned long as a unsigned char[4]
public:
IPAddressFormatAdapter(unsigned long anIpAddress) { _asLong(myIPAddress)=anIpAddress;}
size_t printTo(Print& out) const
{
unsigned char nc=0;
for(int i=0;i<4; i++) {if(i!=0) nc+=out.print('.'); nc+=out.print(myIPAddress[3-i]);} // I'm an endian, I'm a little endian...
return nc;
}
};
// the following hypothetical (because not available) method invocation:
// Serial.print(0x21428418), myIpAdressFormatter);
// may be implemented as:
Serial.print(IPAddressFormatAdapter(0x21428418));
In particular I would like your advise/comments on:
- is it acceptable that all PrintFormat constants are part of the namespace ArduinoPrint, and that this name space is automatically 'used' by including Print.h
I would prefer a nested namespace like using Arduino::Print, but this change can be made later.
- are the chosen PrintFormat constants acceptable? i.e.: BIN, OCT, DEC, HEX, RADIX(n), FILLZEROS, PRECISION(n), FORCESIGN, FIELDSIZE(n), STRICTSIZE, ALIGNLEFT
- is the chosen PrintFormat merge operator& acceptable (e.g. HEX & FILLZEROES)
- is there a need for method based format modifiers: .asBin(), .asOct(), .asDec(), .asHex(), .withRadix(n), .withFillZeros(n), .withPrecision(n), .withForceSign(n), .withFieldSize(n), .withStrickSize(), .AlignedLeft()
- is it acceptable that FORCESIGN and PRECISION(n) are not accounted to FIELDSIZE (and idem STRICTSIZE)
- is it acceptable that ALIGNLEFT & FILLZEROS does a left padding with dashes (instead of zeros) or is there a more intuitive naming for FILLZEROS (ALTFILL?)
- is there a suggestion for an intuitive operator to remove format qualifier e.g. (myFormat & ~FILLZEROS), where &~ is captured in a single operator e.g. (myFormat != FILLZEROS)
- is it acceptable to break backward compatibility regarding not suppressing the decimal point for PRECISION(0)
- is it acceptable to break backward compatibility for print(item, 0) and print(item, 1) // with item integer or equivalent type
options 1) This implementation: print(item, 0) => print(item) // implies DEC print(item, 1) => print(item, DEC)
2) Fully backward compatible: print(item, 0) => print((char) item) print(item, 1) => print(item, DEC)
3) compromise 1 print(item, 0) => print(item) // implies DEC print(item, 1) => print((char) item)
4) Only reasonable thing : print(item, 0) => print(item) // implies DEC print(item, 1) => print("") // reserved
(for comments on PrintSequence, please wait for the PrintSequence design discussion thread - to be started soon)
Michael Jonker
--
> On March 6, 2015 at 2:54 AM Rob Tillaart <rob.ti...@gmail.com> wrote:
>
>
> I would preferred a standalone formatter
> double p = 3.141592;
> format(buffer, p, PRECISION(4) & FIELDSIZE(3))
> Serial.println(buffer);
>
> A separate formatter would
> - not change print at all,
> - easier to debug as e.g. Serial.println(p); would be possible
> - allow the formatter to be used for other purposes like sending formatted
> data over I2C which does not implement print interface
Two issues:
limited memory space for the buffer (which could be large) ...
print as it now stands may need to block, but does not consume
excess memory
as written, the is no protection from buffer overrun (more likely
to happen with larger strings than expected than with numerics)
buffer overrun is quite a lot harder to debug than it is in
other C/C++ environments due to the limitations of Arduino
debugging; you can imagine in many cases, the sketch just
becomes nonresponsive and you cannot tell why or where the
damage occurred
Peter Olson
HEX & FILLZEROS
HEX | FILLZEROS // same category as operator|, semantically weaker than operator&
HEX + FILLZEROS // good alternative, semantically weaker
HEX , FILLZEROS // very confusing when used in parameter lists, I suspect that this will be very error prone.
HEX.withFillZeros() // leads to implementation complications and (in my humble opinion) is not very Arduino like.
template <typename TYPE_T> String& Format(TYPE_T item, PrintFormat aFormat)
template <typename TYPE_T> size_t print (TYPE_T item, PrintFormat aFormat) { return print(Format(item, aFormat)); }
--
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.
The only downside, is that for type-conversion purposes we'll have to ditch the "print(value, format)" pattern of usage and switch to "print(value & format)" pattern instead. I cannot figure out how to make it work with comma, so that it is all nice, short, extensible and backwards compatible.
--
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.
Hello,I really like the idea. However, I think that implementation can be improved. I'll confess that I have my own formatting library for Arduino. It actually lets me avoid floats altogether. I write all my code using "FixNum" <snip>
Back to formatting. There is an explosion of Print class in this proposal. Actually, I don't like existing Arduino's "Printable" with its virtual "printTo" method, either. The way I do it, it that all my "printable" classes have a "format()" method that returns a temporary char buffer class that has a defined conversion to "char *". Take, for example, my DateTime class for RTC clock. I print the current date and time like this:Serial.println(dt.format());The way I would format a number that is returned by some "getMyValue()" method is:Serial.print(getMyValue().format());Given the fact, that getMyValue() returns an appropriate FixNum object (which just a wrapper upon an appropriate integral type without any extra runtime overhead) . This way I don't even have to keep track of how many digits of precision "getMyValue()" returns. It will be formatted with a many decimal digits as getMyValue had intended to provide. However, I can still provide precision and formatting options explicitly as an argument to "format()" method. However, the way I do this is not as elegant as in your proposal.In order to make it all fit together, Arduino Print class shall define just one new method:template<typename T> inline size_t print(T value) { return print(value.format()); }This way "Print" class can be kept small and nice as it is now, while the formatting of all objects is completely delegated to library writers.How do you define the library for integral and float formatting, then? It is as easy as defining a separate hierarchy of PrintFormat (just as you propose) and _FormattedValue_ classes that encapsulate a pair of typed value and format (their typical use will be inlined by compiler), With an appropriate "&" operations defined between the types, printing can be as easy as writing the following code (I'm expanding your examples):Serial.println(3.141592 & PRECISION(4) & FIELDSIZE(3));Serial.println(66 & HEX);Serial.println(22 & RADIX(5) & FIELDSIZE(8) & ALIGNLEFT);So you have the same ease of use for the end user, no virtual invocations what-so-ever would be needed at run time, but still fully extensible by any library writer to support any other types or formatting options. The only downside, is that for type-conversion purposes we'll have to ditch the "print(value, format)" pattern of usage and switch to "print(value & format)" pattern instead. I cannot figure out how to make it work with comma, so that it is all nice, short, extensible and backwards compatible.Note, that end users will never have to deal with templates. They will be used in Arduino's Print class only for benefits of library writers.
template<typename T, typename F>
inline size_t print(T value, F format) { return format.printTo(*this, value))};
Serial.print(value, aPrintFormat);
Serial.print(66, HEX);
template<typename T> inline size_t print(T item) { return item.printTo(*this): }
--
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.
I think i can locate my printf that was possibly smaller, its for z80, but is plain ansi C.
The alternative printf has already been discussed at length in the above mentioned discussion. Not only is printf very Arduino-_unlike_, for me printf is 'HAS BEEN'. Although I use it a lot, it is not the thing I would teach my kids.
I understand. But perhaps I wasn't clear in what I'm looking for, sorry. I'm looking for examples that are aimed at a general audience, not a technical audience. The difference in pedagogical approach in Massimo's video compared to the ones you posted is, to me, the core of our approach to Arduino. Sorry I wasn't clearer earlier. If the difference isn't clear, let me know and I'll try to be clearer, provide more examples, as needed.
sent on the go. please excuse brevity and mistaken auto corrections