[RTTY] Added support for Arduino flash strings

This commit is contained in:
jgromes 2019-05-26 10:26:25 +02:00
parent ed3eeb0559
commit 9f382f6406
3 changed files with 72 additions and 29 deletions

View file

@ -93,6 +93,9 @@ void loop() {
// character array (C-String) // character array (C-String)
rtty.println("C-String"); rtty.println("C-String");
// string saved in flash
rtty.println(F("Flash String"));
// character // character
rtty.println('c'); rtty.println('c');

View file

@ -21,19 +21,19 @@ ITA2String::~ITA2String() {
size_t ITA2String::length() { size_t ITA2String::length() {
// length returned by this method is different than the length of ASCII-encoded _str // length returned by this method is different than the length of ASCII-encoded _str
// ITA2-encoded string length varies based on how many number and characters the string contains // ITA2-encoded string length varies based on how many number and characters the string contains
if(_ita2Len == 0) { if(_ita2Len == 0) {
// ITA2 length wasn't calculated yet, call byteArr() to calculate it // ITA2 length wasn't calculated yet, call byteArr() to calculate it
byteArr(); byteArr();
} }
return(_ita2Len); return(_ita2Len);
} }
uint8_t* ITA2String::byteArr() { uint8_t* ITA2String::byteArr() {
// create temporary array 2x the string length (figures may be 3 bytes) // create temporary array 2x the string length (figures may be 3 bytes)
uint8_t* temp = new uint8_t[_len*2 + 1]; uint8_t* temp = new uint8_t[_len*2 + 1];
size_t arrayLen = 0; size_t arrayLen = 0;
bool flagFigure = false; bool flagFigure = false;
for(size_t i = 0; i < _len; i++) { for(size_t i = 0; i < _len; i++) {
@ -47,10 +47,10 @@ uint8_t* ITA2String::byteArr() {
flagFigure = true; flagFigure = true;
temp[arrayLen++] = ITA2_FIGS; temp[arrayLen++] = ITA2_FIGS;
} }
// add the character code // add the character code
temp[arrayLen++] = character & 0b11111; temp[arrayLen++] = character & 0b11111;
// check the following character (skip for message end) // check the following character (skip for message end)
if(i < (_len - 1)) { if(i < (_len - 1)) {
uint16_t nextCode = getBits(_str[i+1]); uint16_t nextCode = getBits(_str[i+1]);
@ -69,14 +69,14 @@ uint8_t* ITA2String::byteArr() {
temp[arrayLen++] = character & 0b11111; temp[arrayLen++] = character & 0b11111;
} }
} }
// save ITA2 string length // save ITA2 string length
_ita2Len = arrayLen; _ita2Len = arrayLen;
uint8_t* arr = new uint8_t[arrayLen]; uint8_t* arr = new uint8_t[arrayLen];
memcpy(arr, temp, arrayLen); memcpy(arr, temp, arrayLen);
delete[] temp; delete[] temp;
return(arr); return(arr);
} }
@ -94,7 +94,7 @@ uint16_t ITA2String::getBits(char c) {
break; break;
} }
} }
return(code); return(code);
} }
@ -106,7 +106,7 @@ int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t enc
// save configuration // save configuration
_encoding = encoding; _encoding = encoding;
_stopBits = stopBits; _stopBits = stopBits;
switch(encoding) { switch(encoding) {
case ASCII: case ASCII:
_dataBits = 7; _dataBits = 7;
@ -120,37 +120,37 @@ int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t enc
default: default:
return(ERR_UNSUPPORTED_ENCODING); return(ERR_UNSUPPORTED_ENCODING);
} }
// calculate duration of 1 bit // calculate duration of 1 bit
_bitDuration = (uint32_t)1000000/rate; _bitDuration = (uint32_t)1000000/rate;
// calculate module carrier frequency resolution // calculate module carrier frequency resolution
uint16_t step = round((_phy->getCrystalFreq() * 1000000) / (uint32_t(1) << _phy->getDivExponent())); uint16_t step = round((_phy->getCrystalFreq() * 1000000) / (uint32_t(1) << _phy->getDivExponent()));
// check minimum shift value // check minimum shift value
if(shift < step / 2) { if(shift < step / 2) {
return(ERR_INVALID_RTTY_SHIFT); return(ERR_INVALID_RTTY_SHIFT);
} }
// round shift to multiples of frequency step size // round shift to multiples of frequency step size
if(shift % step < (step / 2)) { if(shift % step < (step / 2)) {
_shift = shift / step; _shift = shift / step;
} else { } else {
_shift = (shift / step) + 1; _shift = (shift / step) + 1;
} }
// calculate 24-bit frequency // calculate 24-bit frequency
_base = (base * (uint32_t(1) << _phy->getDivExponent())) / _phy->getCrystalFreq(); _base = (base * (uint32_t(1) << _phy->getDivExponent())) / _phy->getCrystalFreq();
// set module frequency deviation to 0 // set module frequency deviation to 0
int16_t state = _phy->setFrequencyDeviation(0); int16_t state = _phy->setFrequencyDeviation(0);
return(state); return(state);
} }
void RTTYClient::idle() { void RTTYClient::idle() {
_phy->transmitDirect(); _phy->transmitDirect();
mark(); mark();
} }
@ -171,7 +171,7 @@ size_t RTTYClient::write(uint8_t* buff, size_t len) {
size_t RTTYClient::write(uint8_t b) { size_t RTTYClient::write(uint8_t b) {
space(); space();
for(uint16_t mask = 0x01; mask <= (uint16_t)(0x01 << (_dataBits - 1)); mask <<= 1) { for(uint16_t mask = 0x01; mask <= (uint16_t)(0x01 << (_dataBits - 1)); mask <<= 1) {
if(b & mask) { if(b & mask) {
mark(); mark();
@ -179,14 +179,46 @@ size_t RTTYClient::write(uint8_t b) {
space(); space();
} }
} }
for(uint8_t i = 0; i < _stopBits; i++) { for(uint8_t i = 0; i < _stopBits; i++) {
mark(); mark();
} }
return(1); return(1);
} }
size_t RTTYClient::print(__FlashStringHelper* fstr) {
// read flash string length
size_t len = 0;
PGM_P p = reinterpret_cast<PGM_P>(fstr);
while(true) {
char c = pgm_read_byte(p++);
len++;
if(c == '\0') {
break;
}
}
// dynamically allocate memory
char* str = new char[len];
// copy string from flash
p = reinterpret_cast<PGM_P>(fstr);
for(size_t i = 0; i < len; i++) {
str[i] = pgm_read_byte(p + i);
}
size_t n = 0;
if(_encoding == ITA2) {
ITA2String ita2 = str;
n = RTTYClient::print(ita2);
} else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) {
n = RTTYClient::write((uint8_t*)str, len);
}
delete[] str;
return(n);
}
size_t RTTYClient::print(ITA2String& ita2) { size_t RTTYClient::print(ITA2String& ita2) {
uint8_t* arr = ita2.byteArr(); uint8_t* arr = ita2.byteArr();
size_t n = RTTYClient::write(arr, ita2.length()); size_t n = RTTYClient::write(arr, ita2.length());
@ -277,6 +309,12 @@ size_t RTTYClient::println(void) {
return(n); return(n);
} }
size_t RTTYClient::println(__FlashStringHelper* fstr) {
size_t n = RTTYClient::print(fstr);
n += RTTYClient::println();
return(n);
}
size_t RTTYClient::println(ITA2String& ita2) { size_t RTTYClient::println(ITA2String& ita2) {
size_t n = RTTYClient::print(ita2); size_t n = RTTYClient::print(ita2);
n += RTTYClient::println(); n += RTTYClient::println();
@ -365,7 +403,7 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) {
*--str = c < 10 ? c + '0' : c + 'A' - 10; *--str = c < 10 ? c + '0' : c + 'A' - 10;
} while(n); } while(n);
size_t l = 0; size_t l = 0;
if(_encoding == ITA2) { if(_encoding == ITA2) {
ITA2String ita2 = str; ITA2String ita2 = str;
@ -375,21 +413,21 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) {
} else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) {
l = RTTYClient::write(str); l = RTTYClient::write(str);
} }
return(l); return(l);
} }
// TODO: improve ITA2 float print speed // TODO: improve ITA2 float print speed
// (characters are sent one at a time) // (characters are sent one at a time)
size_t RTTYClient::printFloat(double number, uint8_t digits) { size_t RTTYClient::printFloat(double number, uint8_t digits) {
size_t n = 0; size_t n = 0;
char code[] = {0x00, 0x00, 0x00, 0x00}; char code[] = {0x00, 0x00, 0x00, 0x00};
if (isnan(number)) strcpy(code, "nan"); if (isnan(number)) strcpy(code, "nan");
if (isinf(number)) strcpy(code, "inf"); 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 (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically
if(code[0] != 0x00) { if(code[0] != 0x00) {
if(_encoding == ITA2) { if(_encoding == ITA2) {
ITA2String ita2 = code; ITA2String ita2 = code;
@ -401,7 +439,7 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) {
return(RTTYClient::write(code)); return(RTTYClient::write(code));
} }
} }
// Handle negative numbers // Handle negative numbers
if (number < 0.0) { if (number < 0.0) {
if(_encoding == ITA2) { if(_encoding == ITA2) {
@ -444,8 +482,8 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) {
remainder *= 10.0; remainder *= 10.0;
unsigned int toPrint = (unsigned int)(remainder); unsigned int toPrint = (unsigned int)(remainder);
n += RTTYClient::print(toPrint); n += RTTYClient::print(toPrint);
remainder -= toPrint; remainder -= toPrint;
} }
return n; return n;
} }

View file

@ -112,6 +112,7 @@ class RTTYClient {
size_t write(uint8_t* buff, size_t len); size_t write(uint8_t* buff, size_t len);
size_t write(uint8_t b); size_t write(uint8_t b);
size_t print(__FlashStringHelper*);
size_t print(ITA2String &); size_t print(ITA2String &);
size_t print(const String &); size_t print(const String &);
size_t print(const char[]); size_t print(const char[]);
@ -124,6 +125,7 @@ class RTTYClient {
size_t print(double, int = 2); size_t print(double, int = 2);
size_t println(void); size_t println(void);
size_t println(__FlashStringHelper*);
size_t println(ITA2String &); size_t println(ITA2String &);
size_t println(const String &s); size_t println(const String &s);
size_t println(const char[]); size_t println(const char[]);