2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
[![Arduino CI](https://github.com/RobTillaart/printHelpers/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
2021-11-13 12:15:22 -05:00
|
|
|
[![Arduino-lint](https://github.com/RobTillaart/printHelpers/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/printHelpers/actions/workflows/arduino-lint.yml)
|
|
|
|
[![JSON check](https://github.com/RobTillaart/printHelpers/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/printHelpers/actions/workflows/jsoncheck.yml)
|
2021-01-29 06:31:58 -05:00
|
|
|
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/printHelpers/blob/master/LICENSE)
|
|
|
|
[![GitHub release](https://img.shields.io/github/release/RobTillaart/printHelpers.svg?maxAge=3600)](https://github.com/RobTillaart/printHelpers/releases)
|
|
|
|
|
|
|
|
|
|
|
|
# printHelpers
|
|
|
|
|
2021-12-24 07:26:40 -05:00
|
|
|
Arduino library to help formatting data for printing.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
|
|
|
## Description
|
|
|
|
|
|
|
|
The printHelpers library contains a number of functions that help to print
|
|
|
|
data in a way not possible in the standard print library of the Arduino.
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
- **print64()** print **uint64_t** and **int64_t**
|
|
|
|
- **sci()** generates in scientific format - exponent has step 1.
|
|
|
|
- **eng()** generates in engineering format - exponent has step 3.
|
|
|
|
- **scieng()** generated exponential format - exponent has step 1 to 9.
|
|
|
|
- **toBytes()** generates KB MB GB etc.
|
|
|
|
- **hex()** generates hexadecimal output with leading zeros up to **uint64_t**.
|
|
|
|
- **bin()** generates binary output with leading zeros up to **uint64_t**.
|
|
|
|
|
|
|
|
Details, see below.
|
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
|
|
|
|
#### thread safety
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
Note the functions of this library all share an internal buffer, so the library is
|
|
|
|
definitely **not** thread safe.
|
|
|
|
Therefore one should copy / print the data (returned pointer) as fast as possible.
|
2022-11-29 11:12:53 -05:00
|
|
|
|
|
|
|
Thread-safe versions of these print functions might be made in the future.
|
|
|
|
|
|
|
|
|
|
|
|
## Interface
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
```cpp
|
|
|
|
#include "printHelpers.h"
|
|
|
|
```
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
The following functions are implemented:
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
#### print64()
|
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* print64(int64_t value, uint8_t base)** converts a 64 bit integer
|
|
|
|
number to a char array.
|
2021-01-29 06:31:58 -05:00
|
|
|
The plus sign is not printed, neither are leading zero's.
|
|
|
|
Base 10 (DEC) and 16 (HEX) are supported and other bases up to 36 can be used.
|
|
|
|
Note that negative numbers will always get a minus sign for any base.
|
|
|
|
Cast the number to uint64_t to suppress the sign.
|
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* print64(uint64_t value, uint8_t base)** converts a unsigned 64 bit
|
|
|
|
int number to a char array.
|
2021-01-29 06:31:58 -05:00
|
|
|
No sign is printed, neither are leading zero's.
|
|
|
|
Base 10 (DEC) and 16 (HEX) are supported and bases up to 36 can be used.
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
#### sci() eng()
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* sci(double value, uint8_t decimals)** converts a float or double to a
|
|
|
|
char array.
|
2023-01-28 07:52:36 -05:00
|
|
|
E.g. **print(sci(f, 4))** ==> results in "6.7407E+21".
|
2021-01-29 06:31:58 -05:00
|
|
|
The existing Arduino print library only supports printing of floats and
|
2021-12-24 07:26:40 -05:00
|
|
|
doubles up to about 4E9 while the range of floats goes up to ~1E38.
|
2021-01-29 06:31:58 -05:00
|
|
|
The smallest float values will often be printed as 0.00 while floats
|
2023-01-28 07:52:36 -05:00
|
|
|
support down to about 1E-38 (subnormal even to 1E-45).
|
|
|
|
Existing (AVR) library functions **dtostrf()** has no scientific notation
|
|
|
|
and **dtostre()** is limited to 7 decimals. These latter two are faster.
|
|
|
|
Values printed with **sci()** do look pretty in column output.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* eng(double value, uint8_t decimals)** converts a float or double to a
|
|
|
|
char array.
|
2021-01-29 06:31:58 -05:00
|
|
|
E.g. print(eng(f, 4)) ==> results in "6.7407E+21".
|
|
|
|
Note the exponent created by **eng()** is always a multiple of 3.
|
2023-01-28 07:52:36 -05:00
|
|
|
Values printed with **eng()** do not always look pretty in column output.
|
|
|
|
This is due to the exponent power of 3. However its output translates easy to
|
|
|
|
thousands, millions etc which are powers of 3.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* scieng(double value, uint8_t decimals, uint8_t exponentMultiple)** converts a
|
|
|
|
float or double to a char array.
|
2021-01-29 06:31:58 -05:00
|
|
|
**sci()** and **eng()** use the same underlying function called **scieng()**
|
|
|
|
as the initial code for converting was almost identical.
|
|
|
|
Although not intended to be used directly, one can use it.
|
2021-11-13 12:15:22 -05:00
|
|
|
The last parameter **exponentMultiple** defines where the exponent is a multiple of.
|
2021-01-29 06:31:58 -05:00
|
|
|
For the **sci()** function this is 1, for the **eng()** function this is 3.
|
|
|
|
The **scieng()** function works for multiples from 1..9 for the exponent.
|
|
|
|
The usability of other values than 1 and 3 are not known.
|
|
|
|
Personally I like the multiple of 2 as I get 2 orders of magnitude in the
|
|
|
|
mantissa.
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
#### toBytes()
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
- **char \* toBytes(double value, uint8_t decimals = 2)** makes from a big number
|
2021-01-29 06:31:58 -05:00
|
|
|
representing an amount of bytes a shorter string usable for displaying.
|
|
|
|
The number of decimals is max 3
|
2023-01-28 07:52:36 -05:00
|
|
|
Example 3.292.528 ==> "3.140 MB"
|
2021-01-29 06:31:58 -05:00
|
|
|
Value ranges supported are in steps of powers of 1024.
|
|
|
|
These will all be shown in UPPERCASE so KB, MB etc.
|
|
|
|
List of prefixes:
|
|
|
|
- kilo mega giga tera (1024\^4)
|
|
|
|
- peta exa zetta yotta (1024\^8)
|
|
|
|
- xona weka vunda uda (1024\^12)
|
|
|
|
treda Byte == TDB uses 2 chars to indicate the magnitude so that would
|
2023-01-28 07:52:36 -05:00
|
|
|
take extra memory or more complex code.
|
2021-01-29 06:31:58 -05:00
|
|
|
As it is seldom used, "official" support stops with UDA.
|
2021-11-13 12:15:22 -05:00
|
|
|
Should be big enough for some time.
|
2021-01-29 06:31:58 -05:00
|
|
|
To have some support the code uses lowercase for the next 8 levels:
|
|
|
|
treda sorta rinta quexa pepta ocha nena minga luma (1024\^21 ~~ 10\^63)
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
#### hex() bin()
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
The default print() function of Arduino does not have leading zero's
|
|
|
|
for **HEX** and **BIN**.
|
|
|
|
This often causes a "broken" layout especially if one wants to print
|
|
|
|
in columns or so.
|
2022-11-29 11:12:53 -05:00
|
|
|
|
|
|
|
To solve this the following functions are added that will generate a
|
|
|
|
constant length char array.
|
|
|
|
|
|
|
|
- **char \* hex(uint64_t value, uint8_t digits = 16)**
|
|
|
|
- **char \* hex(uint32_t value, uint8_t digits = 8)**
|
|
|
|
- **char \* hex(uint16_t value, uint8_t digits = 4)**
|
|
|
|
- **char \* hex(uint8_t value, uint8_t digits = 2)**
|
|
|
|
- **char \* bin(uint64_t value, uint8_t digits = 64)**
|
|
|
|
- **char \* bin(uint32_t value, uint8_t digits = 32)**
|
|
|
|
- **char \* bin(uint16_t value, uint8_t digits = 16)**
|
|
|
|
- **char \* bin(uint8_t value, uint8_t digits = 8)**
|
|
|
|
|
|
|
|
Note: Data types not supported, must be cast to an supported type.
|
|
|
|
|
|
|
|
Note: There is overlap between **hex(value)** and **print64(value, HEX)**.
|
|
|
|
The latter does not produce the leading zero's or fixed length output.
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
----
|
|
|
|
|
|
|
|
More formatting functions might be added in the future.
|
|
|
|
|
|
|
|
|
|
|
|
## Shared buffer
|
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
The implementation of the function all use a shared buffer to hold the
|
|
|
|
generated string.
|
|
|
|
This is done to reduce the memory overhead of embedding static buffers.
|
|
|
|
**Note this is not thread safe!**
|
|
|
|
In a coming release the functions will be able to pass a buffer to them
|
|
|
|
to become more thread safe.
|
|
|
|
|
|
|
|
The size of this shared buffer is default 66 to be able to print a 64 bit
|
|
|
|
integer in base 2.
|
|
|
|
To save memory one can change this buffer size in the code or compile time
|
2023-01-28 07:52:36 -05:00
|
|
|
by changing **PRINTBUFFERSIZE** in printHelpers.h.
|
2021-01-29 06:31:58 -05:00
|
|
|
Be aware that **sci()** and **eng()** use the same buffer.
|
2023-01-28 07:52:36 -05:00
|
|
|
These functions need about 10 bytes plus one bytes for every decimal used.
|
2021-01-29 06:31:58 -05:00
|
|
|
So for floats one need 15-20 bytes max, for doubles one need up to 30 bytes max.
|
|
|
|
In practice a size of 22 will work for most applications.
|
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
| PRINTBUFFERSIZE | BASE SUPPORTED | nr. decimals | Notes |
|
|
|
|
|:---------------:|:--------------:|:------------:|:----------|
|
|
|
|
| 66 | 02 - 36 | 0 - 50 | (default) |
|
|
|
|
| 34 | 04 - 36 | 0 - 20 |
|
|
|
|
| 24 | 08 - 36 | 0 - 14 |
|
|
|
|
| 22 | 10 - 36 | 0 - 12 |
|
|
|
|
| 18 | 16 - 36 | 0 - 07 |
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
When functions are added, the recommended minimum size might increase.
|
|
|
|
|
|
|
|
|
2021-11-13 12:15:22 -05:00
|
|
|
## Operation
|
|
|
|
|
2021-12-24 07:26:40 -05:00
|
|
|
See examples.
|
2021-11-13 12:15:22 -05:00
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
## Future
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
#### Must
|
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
- check TODO's in the code
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
#### Should
|
|
|
|
|
|
|
|
- documentation
|
|
|
|
- table for toBytes() - values KB, MB etc. (21 entries 3 x 7 ?) range etc.
|
2022-11-29 11:12:53 -05:00
|
|
|
- improve readability of the code
|
|
|
|
|
2023-01-28 07:52:36 -05:00
|
|
|
|
|
|
|
#### Could
|
|
|
|
|
|
|
|
- investigate thread safe version
|
|
|
|
- pass char buffer as parameter (breaking)
|
|
|
|
- could be the log10 pow version?
|
|
|
|
- investigate **toRoman()**
|
|
|
|
- investigate separators in **hex()**
|
|
|
|
- space per 8, 4 or 2
|
|
|
|
- investigate distance print helpers.
|
|
|
|
- feet(float cm) as 3'2" or 3-7/8 feet
|
|
|
|
- inch(float cm) as 32"
|
|
|
|
- yards(float meter),
|
|
|
|
- miles(float kilometre)
|
|
|
|
|
|
|
|
|
|
|
|
#### Wont
|
|
|
|
|
2022-11-29 11:12:53 -05:00
|
|
|
- add **float()** as Arduino limits floats to "MAXLONG" by code.
|
2023-01-28 07:52:36 -05:00
|
|
|
- use dtostrf() - is that portable?
|
2022-11-29 11:12:53 -05:00
|
|
|
- use sci() or eng()
|
2023-01-28 07:52:36 -05:00
|
|
|
- add **base(value, digits, base)** for any base > 1.
|
2022-11-29 11:12:53 -05:00
|
|
|
- only upon request.
|
2023-01-28 07:52:36 -05:00
|
|
|
- investigate separators in **bin()**
|
|
|
|
- point or space, per 8 or 4 or 2
|
|
|
|
- ==> printBuffer too small for bin(64) ==> need 75-100 bytes.
|
|
|
|
- Investigate performance and accuracy
|
|
|
|
- **sci()** and **eng()**.
|
|
|
|
- investigate sci() version based upon use of log()
|
|
|
|
- done => see examples.
|