[RTTY] Added support for Arduino flash strings
This commit is contained in:
parent
ed3eeb0559
commit
9f382f6406
3 changed files with 72 additions and 29 deletions
|
@ -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');
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue