Skip to content

Update Print/Stream API #1173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 140 additions & 66 deletions cores/arduino/Print.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
Copyright (c) 2014 Arduino. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand All @@ -9,16 +8,13 @@

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Modified 23 November 2006 by David A. Mellis
Modified 03 August 2015 by Chuck Todd
*/
*/

#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -108,6 +104,31 @@ size_t Print::print(unsigned long n, int base)
}
}

size_t Print::print(long long n, int base)
{
if (base == 0) {
return write(n);
} else if (base == 10) {
if (n < 0) {
int t = print('-');
n = -n;
return printULLNumber(n, 10) + t;
}
return printULLNumber(n, 10);
} else {
return printULLNumber(n, base);
}
}

size_t Print::print(unsigned long long n, int base)
{
if (base == 0) {
return write(n);
} else {
return printULLNumber(n, base);
}
}

size_t Print::print(double n, int digits)
{
return printFloat(n, digits);
Expand Down Expand Up @@ -186,6 +207,20 @@ size_t Print::println(unsigned long num, int base)
return n;
}

size_t Print::println(long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}

size_t Print::println(unsigned long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}

size_t Print::println(double num, int digits)
{
size_t n = print(num, digits);
Expand Down Expand Up @@ -262,6 +297,100 @@ size_t Print::printNumber(unsigned long n, uint8_t base)
return write(str);
}

/*
void Print::printULLNumber(uint64_t n, uint8_t base)
{
unsigned char buf[16 * sizeof(long)];
unsigned int i = 0;

if (n == 0) {
print((char)'0');
return;
}

while (n > 0) {
buf[i++] = n % base;
n /= base;
}

for (; i > 0; i--) {
print((char)(buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
}
}
*/
// REFERENCE IMPLEMENTATION FOR ULL
// size_t Print::printULLNumber(unsigned long long n, uint8_t base)
// {
// // if limited to base 10 and 16 the bufsize can be smaller
// char buf[65];
// char *str = &buf[64];

// *str = '\0';

// // prevent crash if called with base == 1
// if (base < 2) base = 10;

// do {
// unsigned long long t = n / base;
// char c = n - t * base; // faster than c = n%base;
// n = t;
// *--str = c < 10 ? c + '0' : c + 'A' - 10;
// } while(n);

// return write(str);
// }

// FAST IMPLEMENTATION FOR ULL
size_t Print::printULLNumber(unsigned long long n64, uint8_t base)
{
// if limited to base 10 and 16 the bufsize can be 20
char buf[64];
uint8_t i = 0;
uint8_t innerLoops = 0;

// prevent crash if called with base == 1
if (base < 2) {
base = 10;
}

// process chunks that fit in "16 bit math".
uint16_t top = 0xFFFF / base;
uint16_t th16 = 1;
while (th16 < top) {
th16 *= base;
innerLoops++;
}

while (n64 > th16) {
// 64 bit math part
uint64_t q = n64 / th16;
uint16_t r = n64 - q * th16;
n64 = q;

// 16 bit math loop to do remainder. (note buffer is filled reverse)
for (uint8_t j = 0; j < innerLoops; j++) {
uint16_t qq = r / base;
buf[i++] = r - qq * base;
r = qq;
}
}

uint16_t n16 = n64;
while (n16 > 0) {
uint16_t qq = n16 / base;
buf[i++] = n16 - qq * base;
n16 = qq;
}

size_t bytes = i;
for (; i > 0; i--) {
write((char)(buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
return bytes;
}

size_t Print::printFloat(double number, uint8_t digits)
{
size_t n = 0;
Expand Down Expand Up @@ -300,71 +429,16 @@ size_t Print::printFloat(double number, uint8_t digits)

// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
n += print(".");
n += print('.');
}

// Extract digits from the remainder one at a time
while (digits-- > 0) {
remainder *= 10.0;
int toPrint = int(remainder);
unsigned int toPrint = (unsigned int)remainder;
n += print(toPrint);
remainder -= toPrint;
}

return n;
}

#ifdef SUPPORT_LONGLONG

void Print::println(int64_t n, uint8_t base)
{
print(n, base);
println();
}

void Print::print(int64_t n, uint8_t base)
{
if (n < 0) {
print((char)'-');
n = -n;
}
if (base < 2) {
base = 2;
}
print((uint64_t)n, base);
}

void Print::println(uint64_t n, uint8_t base)
{
print(n, base);
println();
}

void Print::print(uint64_t n, uint8_t base)
{
if (base < 2) {
base = 2;
}
printLLNumber(n, base);
}

void Print::printLLNumber(uint64_t n, uint8_t base)
{
unsigned char buf[16 * sizeof(long)];
unsigned int i = 0;

if (n == 0) {
print((char)'0');
return;
}

while (n > 0) {
buf[i++] = n % base;
n /= base;
}

for (; i > 0; i--) {
print((char)(buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
}
}
#endif
}
33 changes: 17 additions & 16 deletions cores/arduino/Print.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
Copyright (c) 2016 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
Expand All @@ -9,8 +8,8 @@

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Expand All @@ -32,16 +31,11 @@
#define OCT 8
#define BIN 2

// uncomment next line to support printing of 64 bit ints.
#define SUPPORT_LONGLONG

class Print {
private:
int write_error;
size_t printNumber(unsigned long, uint8_t);
#ifdef SUPPORT_LONGLONG
void printLLNumber(uint64_t, uint8_t);
#endif
size_t printULLNumber(unsigned long long, uint8_t);
size_t printFloat(double, uint8_t);
protected:
void setWriteError(int err = 1)
Expand Down Expand Up @@ -74,6 +68,13 @@ class Print {
return write((const uint8_t *)buffer, size);
}

// default to zero, meaning "a single write may block"
// should be overriden by subclasses with buffering
virtual int availableForWrite()
{
return 0;
}

size_t print(const __FlashStringHelper *);
size_t print(const String &);
size_t print(const char[]);
Expand All @@ -83,6 +84,8 @@ class Print {
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(long long, int = DEC);
size_t print(unsigned long long, int = DEC);
size_t print(double, int = 2);
size_t print(const Printable &);

Expand All @@ -95,18 +98,16 @@ class Print {
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(long long, int = DEC);
size_t println(unsigned long long, int = DEC);
size_t println(double, int = 2);
size_t println(const Printable &);
size_t println(void);
#ifdef SUPPORT_LONGLONG
void println(int64_t, uint8_t = DEC);
void print(int64_t, uint8_t = DEC);
void println(uint64_t, uint8_t = DEC);
void print(uint64_t, uint8_t = DEC);
#endif

int printf(const char *format, ...);
int printf(const __FlashStringHelper *format, ...);

virtual void flush() { /* Empty implementation for backward compatibility */ }
};

#endif
1 change: 0 additions & 1 deletion cores/arduino/Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class Stream : public Print {
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;

Stream()
{
Expand Down