Awesome
PrintEx
Library for Arduino
Written by: Christopher Andrews.
Copyright: 2013(GString
)-2016(PrintEx
), Christopher Andrews, Released under GNU GPLv3 licence (Feel free to contact me via the issues if you would like to discuss a different licence).
Supported Platforms:
About
This library is the descendant of a library I wrote called GString
.
This library allows extending any Stream
or Print
derived library with feature rich printing and formatting capabilities. You can directly use streaming (in & out), printf
, chainable interfaces and repitition. You can even create a library which provides the enhanced capabilities by default. Or alongside Stream
for a bidirectional implementation.
The printf
implementation found in this library is unique. It has been built directly on top of the Arduino Print
library rather than as a separate code base simply called from within. All the features found in printf
use a feature already implemented in Print
. This means floating point support is actually using Print::print( float );
. It also contains additional functionality like support for EEPROM/PROGMEM data, repetition and chaining calls.
This tool set also replaces the globally available version of sprintf
with a version providing all the features of this library. Included in this package is a selection of helper objects I have created over the years. These include tools for validation, security, stability, and diagnostics.
A sample of Arduino libraries which can be extended are as follows:
Serial
- Ethernet (
EthernetClient
,Server
) - WiFi (
WiFiClient
,Server
) SoftwareSerial
LiquidCrystal
Wire
SD
- Any other library that inherits
Print
orStream
.
Contents:
A limited number of features require C++11. The basic Arduino's now have this support in IDE versions 1.6.6 and above. The Arduino Zero & ESP8266 already has this enabled. If you are using an old IDE there is some info here explaining how to enable C++11. However if you are attempting to use an IDE below 1.5.8 you will have to upgrade to make use of the additional features.
- Basic Usage.
- Helpers & Tools
- Core Interfaces
- Custom Configuration
- Licence terms and conditions (GNU GPLv3)
- Credits
Basic Usage
1. Enhancing any Stream
or Print
based object.
To extend an already existing object like Serial
, or EthernetClient
you'll need to make use of either StreamEx
or PrintEx
.
Note: This section does not apply to streaming functionality, it is available by default (see the next section for more info).
-
StreamEx
This extends thePrint
interface while maintaining the ability to read. All existingPrint
andStream
functions are available for use. To use this class simply create a variable of typeStreamEx
and initialize it with yourStream
based object.StreamEx myStream = Serial;
-
PrintEx
This extends thePrint
interface. Only existing and enhancedPrint
functions are available for use. The ability to read is not available, however if the object you want enhanced is aStream
, you can use it in combination with thePrintEx
object. To use this class create a variable of typePrintEx
and initialize it with yourPrint
based object.PrintEx myPrint = Serial;
If you need to use any functions specific to the object you are using (not found in Print
or Stream
) you will have to use the real object. For example, Serial
implements begin()
which is not part of Stream
:
#include <PrintEx.h>
StreamEx mySerial = Serial;
void setup(){
Serial.begin(9600);
mySerial.printf("The compile time & date is: %s, %s", __TIME__, __DATE__);
}
void loop() {}
2. Streaming (in/out).
NOTE: Streaming is a C++11 only feature, you can enable it manually or wait for the IDE version 1.6.6 where is has been enabled by default.
Streaming functionality is built into the PrintEx library, however you do not need to extend your object to use it (this will be done automatically). You can use any Print
or Stream
based object directly. Of course, a Print
library does not have read capabilities and can only stream out data.
The benefit of streaming is, the code produced is smaller than the equivalent written using multiple print()
/println()
statements.
#include <PrintEx.h>
using namespace ios;
void setup(){
Serial.begin( 9600 );
//Stream out formatted data.
Serial << "A hexidecimal number: " << hex << 43981 << endl;
//Read two objects from Serial.
int a;
float f;
Serial >> a >> f;
}
void loop(){}
Built in manipulators are listed below. If you do not include the namespace ios
you will need to prefix these manipulators accordingly: ios::hex
.
Manipulator | Description |
---|---|
bin | Sets an output stream to print integers in binary. |
oct | Sets an output stream to print integers in octal format. |
dec | Sets an output stream to print integers in base 10. |
hex | Sets an output stream to print integers in hexidecimal base. |
precision | Takes a single parameter: Sets the output stream to print floating point data with a certain precision (decimal places). |
endl | Prints a new line. |
repeat | Accepts two parameters: the item to print, and how many times to repeat. The item can be a character or string. |
Stream buffers can be used to read data directly, for instance, you can stream a string directly into EEPROM:
EString e( 0, 10 ); //Create a buffer starting at EEPROM cell 0, with 10 bytes length.
Serial >> e;
An alternative method for streaming data out uses the function printx
(only available from extended interfaces ). It uses the same manipulators above:
PrintEx printer = Serial;
printer.printx( "A hexidecimal number: ", hex, 4398, endl );
3. Using chainable functions.
Every interface using this library incorporates an additional set of functions specifically designed for creating a chain like syntax. For example a series of print()
/println()
calls can be replaced with a chain.
The functions provided are as follows:
Member | Description |
---|---|
concat(...) | This functions exactly the same as print() however it does not return a count of bytes printed, but a reference to the calling object. This allows a chain of calls to be written. |
concatln(...) | This is the println() equivalent of concat() . |
repeat(char,count) | Writes a character count times to the output. |
repeatln(char,count) | This is almost the same as repeat() however it also appends a new line at the end of the repeated character (\r\n ). |
repeat(str,repeatCount) | Writes a string (str) repeatCount` times to the output. The string must be null terminated. |
repeatln(str,repeatCount) | Similar to repeat(str, repeatCount) , just appends a new line at the end. |
repeat(str,size,repeatCount) | Writes a string repeatCount times to the output. The length of the string is specified by size . This allows writing part of a string or one that is not null terminated. |
repeatln(str,size,repeatCount) | Similar to repeat(str, size, repeatCount) , just appends a new line at the end. |
Here is the basic idea behind chaining. Typically you'd be limited to writing code like this:
Serial.print( "ADC0 value: " );
Serial.println( analogRead(A0), DEC );
Now, when using a PrintEx based object you can replace the code with:
mySerial.concat( "ADC0 value: " ).concatln( analogRead(A0), DEC );
The usefulness of these functions is determined by your coding preference. Only repeat()
and repeatln()
are providing new functionality in terms of actual printing.
#include <PrintEx.h>
StreamEx serial = Serial;
void setup(){
Serial.begin(9600);
serial.repeatln( '=', 20 )
.concat("Chainable functions test: ")
.concatln(3.1415f, 3)
.repeat( '=', 20 );
}
void loop() {}
4. printf
formatting.
This library has a custom printf
method for use with all interfaces found in this library. It is not as complete as a standard implementation, however it does support some custom features specific to Arduino. Basic support for the precision parameter is available, however it only affects floating point data. To request further implementation, please open an issue here.
Formatting options use the following syntax:
%[flags][width][.precision][length]specifier
Each element and their set of options is described in the tables below.
-
Flags
One or more of the flags below can be used. However each one used must be in the order used in this table.Flag Description -
Left-justify within the given field width; Right justification is the default. 0
When padding is specified, zeros are used instead of spaces. -
Width
This option allows padding out data. It is also used to specify data for custom routines.Value Description (number)
Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger. *
The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.
Some specifiers require additional data provided using the
width
parameter.Specifier Description r
The number of characters to read from the EEPROM. n
Number of times to run repeat function. -
Precision
To use this option the precision value must be preceeded by a period ('.'). This option only affects floating point data. Its value is the number of decimal places to use. For additional precision support (non floating point data), please open an issue to request this feature.
-
Length
This only has one value:
l
(not the number one, but the alphabetical letter 'l'). If this value is present the behaviour of certain specifiers is changed.Specifier Description d
ori
Use long
instead ofint
.u
orx
Use unsigned long
instead ofunsigned int
.n
Repeat a string, instead of a character. -
Specifiers
Name Description s
String ( null terminated ). p
PROGMEM string. No formatting takes place, the string is printed directly. r
EEPROM string. No formatting takes place, the string is printed directly. d
Signed decimal integer ( 32bits max ). i
Same as d
.u
Unsigned decimal integer ( 32bits max ). f
Decimal floating point number. x
Unsigned decimal integer ( 32bits max ). c
Character. n
Repeat function ( default character, see length ). %
Escape character for printing %
.
#include <PrintEx.h>
StreamEx mySerial = Serial;
void setup() {
Serial.begin(9600);
mySerial.printf( "%20n\nFirst printf use!\n%20n", '=', '=' );
}
void loop() {}
Helpers & Tools
All of these objects have the PrintEx functionality built in, there is no need to use PrintEx
or StreamEx
with these.
The helpers and tools documentation is still under construction. This is just an overview of what is available.
Object | Description |
---|---|
BufferedPrinter | Useful for buffering output to send all at once, or to prevent sending 'packets' or transfers that are too long for the interface. |
DualPrinter | Allows calling multiple Print interfaces through a single object. |
Base64Encoder | Any input this object receives is converted using Base64 encoding and written to its assigned Print interface. |
URIEncoder | Anything printed to this object will be URI encoded based on strictness. It supports URL encoding, HTML forms, and encoding the entire stream. |
CRCStream | This object calculates a running CRC for the input and output data streams of a Stream object associated with it. |
RxTxCoutner | This object keeps track of how much data passes through its interfaces. |
NullStream | A data stream with origins unknown. |
PrintAdapter | Converts a Print object into a Stream object. |
Core Interfaces
The objects listed in this section provide the core functionality for all interfaces inherting PrintExtension
.
Type | Description |
---|---|
PrintEx | This object provides an easy method of enhancing other Print based objects with the capabilities provided by PrintExtension . |
StreamEx | This object provides an easy method of enhancing other Stream based objects with the capabilities provided by PrintExtension while maintaining the bidirectional interface. |
GString | This object provides printing and formatting capabilities for blocks of memory (SRAM). The object can be passed to other Print functions. |
EString | This is the EEPROM equivalent of GString . This essentially allows formatted printing of strings to the EEPROM. It also allows other Print based classes to print EEPROM data easily. |
PString | This is a PROGMEM read-only version of GString . It allows printing of flash based strings. |
PrintExtension | This is a core interface for PrintEx . It provides the formatting features such as concat() and printf() . It also includes OStream which provides streaming capabilites (output only). |
StreamExtension | This core library encapsulates the functionality found in the PrintExtension interface, however it also provides an IStream interface allowing streaming into arbitrary elements. |
NonStreamingIO | This interface provides an extension to the Print class. It allows IO capabilities for derived objects that may not be streams. As in, the data printed to the object is still available for use. |
Custom Configuration.
For normal use this section is not necessary. However the library can be tweaked if needed.
The available customizations can be used by defining one, or a combination of the options listed below. They can be defined either in the PrintExtension.h file, or passed as a compiler option using -D
. Unfortunately defining these in your sketch will not have any effect.
Global library flags.
These settings affect all library functions that use the features described.
Define | Action if defined |
---|---|
PRINTEX_NO_SPRINTF | Do not override the global sprintf with a version supporting all the features present in PrintEx. |
PRINTEX_LARGE_COUNTER | Use a 16-bit value for print counters, instead of 8 bits (how many characters printed). If you do not care about the return count of print functions, leave the setting as is. This will allow more efficient code, however writes larger than 255 characters will have incorrect counts returned.. |
printf
specific flags.
These settings only affect the printf
implementation. To avoid inclusion outside of the printf
/sprintf
implementation, simply do not use the PrintEx
function providing the feature (The compiler will remove unused code).
Define | Action if defined |
---|---|
PRINTEX_NO_WIDTH_PARAM | The width parameter must be specified inline and cannot be set to * specifying an additional input for the width. |
PRINTEX_NO_PRECISION_PARAM | Do not use precision handling (currently only affects floating point resolution). |
PRINTEX_NO_PROGMEM | Do not include PROGMEM functionality (%p ). |
PRINTEX_NO_EEPROM | Do not include EEPROM functionality (%r ). |
PRINTEX_NO_FLOATING_POINT | Do not include support for floating point data (%f ). |
PRINTEX_NO_REPEAT | Do not include character repeat functionality (%n ). |
PRINTEX_NO_ERROR_CONDITION | Do not include error handling (Error is printed on bad inputs/failed operation). |
Special Thanks
Some people who have helped develop ideas & proposals.