From f0cf7ff9122b0f975f1ecc97a76d345d6c1de8fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 29 Apr 2023 22:53:33 +0200 Subject: [PATCH] [Print] Added standalone ITA2 --- src/protocols/Print/ITA2String.cpp | 111 +++++++++++++++++++++++++++++ src/protocols/Print/ITA2String.h | 70 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 src/protocols/Print/ITA2String.cpp create mode 100644 src/protocols/Print/ITA2String.h diff --git a/src/protocols/Print/ITA2String.cpp b/src/protocols/Print/ITA2String.cpp new file mode 100644 index 00000000..0c93da2e --- /dev/null +++ b/src/protocols/Print/ITA2String.cpp @@ -0,0 +1,111 @@ +#include "ITA2String.h" + +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); +} diff --git a/src/protocols/Print/ITA2String.h b/src/protocols/Print/ITA2String.h new file mode 100644 index 00000000..556c0a3b --- /dev/null +++ b/src/protocols/Print/ITA2String.h @@ -0,0 +1,70 @@ +#if !defined(_RADIOLIB_ITA2_STRING_H) +#define _RADIOLIB_ITA2_STRING_H + +#include "../../TypeDef.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. + */ + ITA2String(char c); + + /*! + \brief Default string constructor. + \param str ASCII-encoded string to encode as ITA2. + */ + 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); +}; + +#endif