From d79ed24a26f61dd704ad0947e26b458d9a61763f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:54:27 +0200 Subject: [PATCH] [RTTY] Use common print class --- src/protocols/RTTY/RTTY.cpp | 455 ++---------------------------------- src/protocols/RTTY/RTTY.h | 114 +-------- 2 files changed, 25 insertions(+), 544 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 21c3243a..6dc66bd3 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -3,118 +3,9 @@ #include #if !defined(RADIOLIB_EXCLUDE_RTTY) -ITA2String::ITA2String(char c) { - asciiLen = 1; - #if !defined(RADIOLIB_STATIC_ONLY) - strAscii = new char[1]; - #endif - strAscii[0] = c; - ita2Len = 0; -} - -ITA2String::ITA2String(const char* str) { - asciiLen = strlen(str); - #if !defined(RADIOLIB_STATIC_ONLY) - strAscii = new char[asciiLen + 1]; - #endif - strcpy(strAscii, str); - ita2Len = 0; -} - -ITA2String::~ITA2String() { - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] strAscii; - #endif -} - -size_t ITA2String::length() { - // length returned by this method is different than the length of ASCII-encoded strAscii - // ITA2-encoded string length varies based on how many number and characters the string contains - - if(ita2Len == 0) { - // ITA2 length wasn't calculated yet, call byteArr() to calculate it - byteArr(); - } - - return(ita2Len); -} - -uint8_t* ITA2String::byteArr() { - // create temporary array 2x the string length (figures may be 3 bytes) - #if defined(RADIOLIB_STATIC_ONLY) - uint8_t temp[RADIOLIB_STATIC_ARRAY_SIZE*2 + 1]; - #else - uint8_t* temp = new uint8_t[asciiLen*2 + 1]; - #endif - - size_t arrayLen = 0; - bool flagFigure = false; - for(size_t i = 0; i < asciiLen; i++) { - uint16_t code = getBits(strAscii[i]); - uint8_t shift = (code >> 5) & 0b11111; - uint8_t character = code & 0b11111; - // check if the code is letter or figure - if(shift == RADIOLIB_ITA2_FIGS) { - // check if this is the first figure in sequence - if(!flagFigure) { - flagFigure = true; - temp[arrayLen++] = RADIOLIB_ITA2_FIGS; - } - - // add the character code - temp[arrayLen++] = character & 0b11111; - - // check the following character (skip for message end) - if(i < (asciiLen - 1)) { - uint16_t nextCode = getBits(strAscii[i+1]); - uint8_t nextShift = (nextCode >> 5) & 0b11111; - if(nextShift == RADIOLIB_ITA2_LTRS) { - // next character is a letter, terminate figure shift - temp[arrayLen++] = RADIOLIB_ITA2_LTRS; - flagFigure = false; - } - } else { - // reached the end of the message, terminate figure shift - temp[arrayLen++] = RADIOLIB_ITA2_LTRS; - flagFigure = false; - } - } else { - temp[arrayLen++] = character & 0b11111; - } - } - - // save ITA2 string length - ita2Len = arrayLen; - - uint8_t* arr = new uint8_t[arrayLen]; - memcpy(arr, temp, arrayLen); - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] temp; - #endif - - return(arr); -} - -uint16_t ITA2String::getBits(char c) { - // search ITA2 table - uint16_t code = 0x0000; - for(uint8_t i = 0; i < RADIOLIB_ITA2_LENGTH; i++) { - if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][0]) == c) { - // character is in letter shift - code = (RADIOLIB_ITA2_LTRS << 5) | i; - break; - } else if(RADIOLIB_NONVOLATILE_READ_BYTE(&ITA2Table[i][1]) == c) { - // character is in figures shift - code = (RADIOLIB_ITA2_FIGS << 5) | i; - break; - } - } - - return(code); -} - RTTYClient::RTTYClient(PhysicalLayer* phy) { phyLayer = phy; + lineFeed = "\r\n"; #if !defined(RADIOLIB_EXCLUDE_AFSK) audioClient = nullptr; #endif @@ -123,31 +14,18 @@ RTTYClient::RTTYClient(PhysicalLayer* phy) { #if !defined(RADIOLIB_EXCLUDE_AFSK) RTTYClient::RTTYClient(AFSKClient* audio) { phyLayer = audio->phyLayer; + lineFeed = "\r\n"; audioClient = audio; } #endif int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc, uint8_t stopBits) { // save configuration - encoding = enc; + RadioLibPrint::encoding = enc; stopBitsNum = stopBits; baseFreqHz = base; shiftFreqHz = shift; - switch(encoding) { - case RADIOLIB_ASCII: - dataBitsNum = 7; - break; - case RADIOLIB_ASCII_EXTENDED: - dataBitsNum = 8; - break; - case RADIOLIB_ITA2: - dataBitsNum = 5; - break; - default: - return(RADIOLIB_ERR_UNSUPPORTED_ENCODING); - } - // calculate duration of 1 bit bitDuration = (uint32_t)1000000/rate; @@ -177,22 +55,21 @@ void RTTYClient::idle() { mark(); } -size_t RTTYClient::write(const char* str) { - if(str == NULL) { - return(0); - } - return(RTTYClient::write((uint8_t *)str, strlen(str))); -} - -size_t RTTYClient::write(uint8_t* buff, size_t len) { - size_t n = 0; - for(size_t i = 0; i < len; i++) { - n += RTTYClient::write(buff[i]); - } - return(n); -} - size_t RTTYClient::write(uint8_t b) { + uint8_t dataBitsNum = 0; + switch(RadioLibPrint::encoding) { + case RADIOLIB_ASCII: + dataBitsNum = 7; + break; + case RADIOLIB_ASCII_EXTENDED: + dataBitsNum = 8; + break; + case RADIOLIB_ITA2: + dataBitsNum = 5; + break; + default: + return(0); + } space(); uint16_t maxDataMask = 0x01 << (dataBitsNum - 1); @@ -211,204 +88,6 @@ size_t RTTYClient::write(uint8_t b) { return(1); } -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t RTTYClient::print(__FlashStringHelper* fstr) { - // read flash string length - size_t len = 0; - PGM_P 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(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str, len); - } - #if !defined(RADIOLIB_STATIC_ONLY) - delete[] str; - #endif - return(n); -} - -size_t RTTYClient::print(const String& str) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str.c_str()); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); - } - return(n); -} -#endif - -size_t RTTYClient::print(ITA2String& ita2) { - uint8_t* arr = ita2.byteArr(); - size_t n = RTTYClient::write(arr, ita2.length()); - delete[] arr; - return(n); -} - -size_t RTTYClient::print(const char str[]) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write((uint8_t*)str, strlen(str)); - } - return(n); -} - -size_t RTTYClient::print(char c) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(c); - n = RTTYClient::print(ita2); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write(c); - } - return(n); -} - -size_t RTTYClient::print(unsigned char b, int base) { - return(RTTYClient::print((unsigned long)b, base)); -} - -size_t RTTYClient::print(int n, int base) { - return(RTTYClient::print((long)n, base)); -} - -size_t RTTYClient::print(unsigned int n, int base) { - return(RTTYClient::print((unsigned long)n, base)); -} - -size_t RTTYClient::print(long n, int base) { - if(base == 0) { - return(RTTYClient::write(n)); - } else if(base == DEC) { - if (n < 0) { - int t = RTTYClient::print('-'); - n = -n; - return(RTTYClient::printNumber(n, DEC) + t); - } - return(RTTYClient::printNumber(n, DEC)); - } else { - return(RTTYClient::printNumber(n, base)); - } -} - -size_t RTTYClient::print(unsigned long n, int base) { - if(base == 0) { - return(RTTYClient::write(n)); - } else { - return(RTTYClient::printNumber(n, base)); - } -} - -size_t RTTYClient::print(double n, int digits) { - return(RTTYClient::printFloat(n, digits)); -} - -size_t RTTYClient::println(void) { - size_t n = 0; - if(encoding == RADIOLIB_ITA2) { - ITA2String lf = ITA2String("\r\n"); - n = RTTYClient::print(lf); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n = RTTYClient::write("\r\n"); - } - return(n); -} - -#if defined(RADIOLIB_BUILD_ARDUINO) -size_t RTTYClient::println(__FlashStringHelper* fstr) { - size_t n = RTTYClient::print(fstr); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(const String& str) { - size_t n = RTTYClient::print(str); - n += RTTYClient::println(); - return(n); -} -#endif - -size_t RTTYClient::println(ITA2String& ita2) { - size_t n = RTTYClient::print(ita2); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(const char* str) { - size_t n = RTTYClient::print(str); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(char c) { - size_t n = RTTYClient::print(c); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned char b, int base) { - size_t n = RTTYClient::print(b, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(int num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned int num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(long num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(unsigned long num, int base) { - size_t n = RTTYClient::print(num, base); - n += RTTYClient::println(); - return(n); -} - -size_t RTTYClient::println(double d, int digits) { - size_t n = RTTYClient::print(d, digits); - n += RTTYClient::println(); - return(n); -} - void RTTYClient::mark() { Module* mod = phyLayer->getMod(); uint32_t start = mod->hal->micros(); @@ -423,106 +102,6 @@ void RTTYClient::space() { mod->waitForMicroseconds(start, bitDuration); } -size_t RTTYClient::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(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(str); - uint8_t* arr = ita2.byteArr(); - l = RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - l = RTTYClient::write(str); - } - - return(l); -} - -/// \todo improve ITA2 float print speed (characters are sent one at a time) -size_t RTTYClient::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(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String(code); - uint8_t* arr = ita2.byteArr(); - n = RTTYClient::write(arr, ita2.length()); - delete[] arr; - return(n); - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - return(RTTYClient::write(code)); - } - } - - // Handle negative numbers - if (number < 0.0) { - if(encoding == RADIOLIB_ITA2) { - ITA2String ita2 = ITA2String("-"); - uint8_t* arr = ita2.byteArr(); - n += RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n += RTTYClient::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 += RTTYClient::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 += RTTYClient::write(arr, ita2.length()); - delete[] arr; - } else if((encoding == RADIOLIB_ASCII) || (encoding == RADIOLIB_ASCII_EXTENDED)) { - n += RTTYClient::print('.'); - } - } - - // Extract digits from the remainder one at a time - while(digits-- > 0) { - remainder *= 10.0; - unsigned int toPrint = (unsigned int)(remainder); - n += RTTYClient::print(toPrint); - remainder -= toPrint; - } - - return n; -} - int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) { #if !defined(RADIOLIB_EXCLUDE_AFSK) if(audioClient != nullptr) { diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index f8ee6934..4ebbc7cc 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -7,81 +7,14 @@ #include "../PhysicalLayer/PhysicalLayer.h" #include "../AFSK/AFSK.h" - -#define RADIOLIB_ITA2_FIGS 0x1B -#define RADIOLIB_ITA2_LTRS 0x1F -#define RADIOLIB_ITA2_LENGTH 32 - -// ITA2 character table: - position in array corresponds to 5-bit ITA2 code -// - characters to the left are in letters shift, characters to the right in figures shift -// - characters marked 0x7F do not have ASCII equivalent -static const char ITA2Table[RADIOLIB_ITA2_LENGTH][2] RADIOLIB_NONVOLATILE = { - {'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'A', '-'}, {' ', ' '}, {'S', '\''}, {'I', '8'}, {'U', '7'}, - {'\r', '\r'}, {'D', 0x05}, {'R', '4'}, {'J', '\a'}, {'N', ','}, {'F', '!'}, {'C', ':'}, {'K', '('}, - {'T', '5'}, {'Z', '+'}, {'L', ')'}, {'W', '2'}, {'H', 0x7F}, {'Y', '6'}, {'P', '0'}, {'Q', '1'}, - {'O', '9'}, {'B', '?'}, {'G', '&'}, {0x7F, 0x7F}, {'M', '.'}, {'X', '/'}, {'V', ';'}, {0x7F, 0x7F} -}; - -/*! - \class ITA2String - \brief ITA2-encoded string. -*/ -class ITA2String { - public: - /*! - \brief Default single-character constructor. - \param c ASCII-encoded character to encode as ITA2. - */ - explicit ITA2String(char c); - - /*! - \brief Default string constructor. - \param str ASCII-encoded string to encode as ITA2. - */ - explicit ITA2String(const char* str); - - /*! - \brief Default destructor. - */ - ~ITA2String(); - - /*! - \brief Gets the length of the ITA2 string. This number is not the same as the length of ASCII-encoded string! - \returns Length of ITA2-encoded string. - */ - size_t length(); - - /*! - \brief Gets the ITA2 representation of the ASCII string set in constructor. - \returns Pointer to dynamically allocated array, which contains ITA2-encoded bytes. - It is the caller's responsibility to deallocate this memory! - */ - uint8_t* byteArr(); - -#if !defined(RADIOLIB_GODMODE) - private: -#endif - #if defined(RADIOLIB_STATIC_ONLY) - char strAscii[RADIOLIB_STATIC_ARRAY_SIZE]; - #else - char* strAscii; - #endif - size_t asciiLen; - size_t ita2Len; - - static uint16_t getBits(char c); -}; - -// supported encoding schemes -#define RADIOLIB_ASCII 0 -#define RADIOLIB_ASCII_EXTENDED 1 -#define RADIOLIB_ITA2 2 +#include "../Print/Print.h" +#include "../Print/ITA2String.h" /*! \class RTTYClient \brief Client for RTTY communication. The public interface is the same as Arduino Serial. */ -class RTTYClient { +class RTTYClient: public RadioLibPrint { public: /*! \brief Constructor for 2-FSK mode. @@ -121,39 +54,13 @@ class RTTYClient { */ int16_t standby(); - size_t write(const char* str); - size_t write(uint8_t* buff, size_t len); + /*! + \brief Write one byte. Implementation of interface of the RadioLibPrint/Print class. + \param b Byte to write. + \returns 1 if the byte was written, 0 otherwise. + */ size_t write(uint8_t b); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t print(__FlashStringHelper*); - size_t print(const String &); - #endif - size_t print(ITA2String &); - 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(void); - #if defined(RADIOLIB_BUILD_ARDUINO) - size_t println(__FlashStringHelper*); - size_t println(const String &); - #endif - size_t println(ITA2String &); - 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); - #if !defined(RADIOLIB_GODMODE) private: #endif @@ -162,19 +69,14 @@ class RTTYClient { AFSKClient* audioClient; #endif - uint8_t encoding = RADIOLIB_ASCII; uint32_t baseFreq = 0, baseFreqHz = 0; uint32_t shiftFreq = 0, shiftFreqHz = 0; uint32_t bitDuration = 0; - uint8_t dataBitsNum = 0; uint8_t stopBitsNum = 0; void mark(); void space(); - size_t printNumber(unsigned long, uint8_t); - size_t printFloat(double, uint8_t); - int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); };