From 089a81faec5b52584fcb87cf5e15786a58815865 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:53:55 +0200 Subject: [PATCH] [Print] Added common print class --- src/protocols/Print/Print.cpp | 309 ++++++++++++++++++++++++++++++++++ src/protocols/Print/Print.h | 64 +++++++ 2 files changed, 373 insertions(+) create mode 100644 src/protocols/Print/Print.cpp create mode 100644 src/protocols/Print/Print.h diff --git a/src/protocols/Print/Print.cpp b/src/protocols/Print/Print.cpp new file mode 100644 index 00000000..9d0fa558 --- /dev/null +++ b/src/protocols/Print/Print.cpp @@ -0,0 +1,309 @@ +#include "Print.h" + +size_t RadioLibPrint::print(ITA2String& ita2) { + uint8_t enc = this->encoding; + this->encoding = RADIOLIB_ITA2; + uint8_t* arr = ita2.byteArr(); + size_t n = write(arr, ita2.length()); + delete[] arr; + this->encoding = enc; + return(n); +} + +size_t RadioLibPrint::println(ITA2String& ita2) { + size_t n = RadioLibPrint::print(ita2); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while (size--) { + if (write(*buffer++)) n++; + else break; + } + return n; +} + +#if defined(RADIOLIB_BUILD_ARDUINO) +size_t RadioLibPrint::print(const __FlashStringHelper* fstr) { + // read flash string length + size_t len = 0; + RADIOLIB_NONVOLATILE_PTR p = reinterpret_cast(fstr); + while(true) { + char c = RADIOLIB_NONVOLATILE_READ_BYTE(p++); + len++; + if(c == '\0') { + break; + } + } + + // dynamically allocate memory + #if defined(RADIOLIB_STATIC_ONLY) + char str[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + char* str = new char[len]; + #endif + + // copy string from flash + p = reinterpret_cast(fstr); + for(size_t i = 0; i < len; i++) { + str[i] = RADIOLIB_NONVOLATILE_READ_BYTE(p + i); + } + + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, len); + } + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] str; + #endif + return(n); +} + +size_t RadioLibPrint::print(const String& str) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str.c_str()); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str.c_str(), str.length()); + } + return(n); +} + +size_t RadioLibPrint::println(const __FlashStringHelper* fstr) { + size_t n = RadioLibPrint::print(fstr); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(const String& str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} +#endif + +size_t RadioLibPrint::print(const char str[]) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + n = RadioLibPrint::print(ita2); + } else { + n = write((uint8_t*)str, strlen(str)); + } + return(n); +} + +size_t RadioLibPrint::print(char c) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(c); + n = RadioLibPrint::print(ita2); + } else { + n = write(c); + } + return(n); +} + +size_t RadioLibPrint::print(unsigned char b, int base) { + return(RadioLibPrint::print((unsigned long)b, base)); +} + +size_t RadioLibPrint::print(int n, int base) { + return(RadioLibPrint::print((long)n, base)); +} + +size_t RadioLibPrint::print(unsigned int n, int base) { + return(RadioLibPrint::print((unsigned long)n, base)); +} + +size_t RadioLibPrint::print(long n, int base) { + if(base == 0) { + return(write(n)); + } else if(base == DEC) { + if (n < 0) { + int t = RadioLibPrint::print('-'); + n = -n; + return(RadioLibPrint::printNumber(n, DEC) + t); + } + return(RadioLibPrint::printNumber(n, DEC)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(unsigned long n, int base) { + if(base == 0) { + return(write(n)); + } else { + return(RadioLibPrint::printNumber(n, base)); + } +} + +size_t RadioLibPrint::print(double n, int digits) { + return(RadioLibPrint::printFloat(n, digits)); +} + +size_t RadioLibPrint::println(const char* str) { + size_t n = RadioLibPrint::print(str); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(char c) { + size_t n = RadioLibPrint::print(c); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned char b, int base) { + size_t n = RadioLibPrint::print(b, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned int num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(unsigned long num, int base) { + size_t n = RadioLibPrint::print(num, base); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(double d, int digits) { + size_t n = RadioLibPrint::print(d, digits); + n += RadioLibPrint::println(); + return(n); +} + +size_t RadioLibPrint::println(void) { + size_t n = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String lf = ITA2String("\r\n"); + n = RadioLibPrint::print(lf); + } else { + n = write("\r\n"); + } + return(n); +} + +size_t RadioLibPrint::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + if(base < 2) { + base = 10; + } + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + size_t l = 0; + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(str); + uint8_t* arr = ita2.byteArr(); + l = write(arr, ita2.length()); + delete[] arr; + } else { + l = write(str); + } + + return(l); +} + +/// \todo improve ITA2 float print speed (characters are sent one at a time) +size_t RadioLibPrint::printFloat(double number, uint8_t digits) { + size_t n = 0; + + char code[] = {0x00, 0x00, 0x00, 0x00}; + if (isnan(number)) strcpy(code, "nan"); + if (isinf(number)) strcpy(code, "inf"); + if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically + + if(code[0] != 0x00) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String(code); + uint8_t* arr = ita2.byteArr(); + n = write(arr, ita2.length()); + delete[] arr; + return(n); + } else { + return(write(code)); + } + } + + // Handle negative numbers + if (number < 0.0) { + if(this->encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("-"); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('-'); + } + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) { + rounding /= 10.0; + } + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + n += RadioLibPrint::print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + if(encoding == RADIOLIB_ITA2) { + ITA2String ita2 = ITA2String("."); + uint8_t* arr = ita2.byteArr(); + n += write(arr, ita2.length()); + delete[] arr; + } else { + n += RadioLibPrint::print('.'); + } + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += RadioLibPrint::print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/src/protocols/Print/Print.h b/src/protocols/Print/Print.h new file mode 100644 index 00000000..0dbc5eda --- /dev/null +++ b/src/protocols/Print/Print.h @@ -0,0 +1,64 @@ +#if !defined(_RADIOLIB_PRINT_H) +#define _RADIOLIB_PRINT_H + +#include "ITA2String.h" + +// supported encoding schemes +#define RADIOLIB_ASCII 0 +#define RADIOLIB_ASCII_EXTENDED 1 +#define RADIOLIB_ITA2 2 + +// based on Arduino Print class +class RadioLibPrint { + public: + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); + } + + size_t print(ITA2String& ita2); + size_t println(ITA2String& ita2); + + #if defined(RADIOLIB_BUILD_ARDUINO) + size_t print(const __FlashStringHelper *); + size_t print(const String &); + + size_t println(const __FlashStringHelper *); + size_t println(const String &); + #endif + + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + + protected: + uint8_t encoding = RADIOLIB_ASCII_EXTENDED; + const char* lineFeed; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + + private: +}; + +#endif