diff --git a/examples/SX127x_RTTY_Transmit/SX127x_RTTY_Transmit.ino b/examples/SX127x_RTTY_Transmit/SX127x_RTTY_Transmit.ino index e65114e2..0ae25c43 100644 --- a/examples/SX127x_RTTY_Transmit/SX127x_RTTY_Transmit.ino +++ b/examples/SX127x_RTTY_Transmit/SX127x_RTTY_Transmit.ino @@ -48,9 +48,9 @@ void setup() { // low frequency: 434.0 MHz // frequency shift: 183 Hz // baud rate: 45 baud - // data bits: 8 (ASCII encoding) + // encoding: ASCII (7-bit) // stop bits: 1 - state = rtty.begin(434, 183, 45, 8); + state = rtty.begin(434, 183, 45); if(state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -58,6 +58,17 @@ void setup() { Serial.println(state); while(true); } + + /* + // KiteLib also provides ITA2 ("Baudot") encoding support + rtty.begin(434, 183, 45, ITA2); + + // All transmissions in loop() (strings and numbers) + // will now be encoded using ITA2 code + + // ASCII characters that do not have ITA2 euqivalent + // will be sent as NUL (including lower case letters!) + */ } void loop() { @@ -73,8 +84,8 @@ void loop() { String aStr = "Arduino String"; rtty.println(aStr); - // character array (C-string) - rtty.println("C-string"); + // character array (C-String) + rtty.println("C-String"); // character rtty.println('c'); @@ -91,35 +102,6 @@ void loop() { // floating point number float f = -3.1415; rtty.println(f, 3); - - /* - // KiteLib also provides ITA2 ("Baudot") code support - // To enable ITA2 encoding, set RTTY client - // to 5 data bits - rtty.begin(434, 183, 45, 5); - - // send synchronization string ("RYRY..." corresponds - // to binary 01010101010101010101... in ITA2 encoding) - rtty.println("RYRYRYRY"); - - // send ITA2-encoded string (all ASCII characters - // that do not have ITA2 equivalent will be replaced - // with NUL - rtty.println("HELLO WORLD!"); - - String aStr = "ARDUINO STRING"; - rtty.println(aStr); - - // character array (C-string) - rtty.println("C-STRING"); - - // character - rtty.println('C'); - - // all numbers can also be sent using ITA2 - float f = -3.1415; - rtty.println(f, 3); - */ // turn transmitter off fsk.standby(); diff --git a/src/TypeDef.h b/src/TypeDef.h index 4212b58a..8d7ad0cf 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -80,7 +80,6 @@ #define ERR_INVALID_PREAMBLE_LENGTH -18 #define ERR_INVALID_GAIN -19 #define ERR_WRONG_MODEM -20 -#define ERR_INVALID_RTTY_SHIFT -21 // RF69-specific status codes #define ERR_INVALID_BIT_RATE -101 @@ -112,4 +111,8 @@ #define ERR_FRAME_INCORRECT_CHECKSUM -303 #define ERR_FRAME_UNEXPECTED_ID -304 +// RTTY status codes +#define ERR_INVALID_RTTY_SHIFT -401 +#define ERR_UNSUPPORTED_ENCODING -402 + #endif diff --git a/src/protocols/RTTY.cpp b/src/protocols/RTTY.cpp index 44b30b5d..edba55fc 100644 --- a/src/protocols/RTTY.cpp +++ b/src/protocols/RTTY.cpp @@ -1,22 +1,22 @@ #include "RTTY.h" -ITA2::ITA2(char c) { +ITA2String::ITA2String(char c) { _len = 1; _str = new char[1]; _str[0] = c; } -ITA2::ITA2(const char* str) { +ITA2String::ITA2String(const char* str) { _len = strlen(str); _str = new char[_len]; strcpy(_str, str); } -ITA2::~ITA2() { +ITA2String::~ITA2String() { delete[] _str; } -size_t ITA2::length() { +size_t ITA2String::length() { // 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 size_t length = 0; @@ -35,7 +35,7 @@ size_t ITA2::length() { return(length); } -uint8_t* ITA2::byteArr() { +uint8_t* ITA2String::byteArr() { // create temporary array 3x the string length (figures may be 3 bytes) uint8_t* temp = new uint8_t[_len*3]; @@ -60,7 +60,7 @@ uint8_t* ITA2::byteArr() { return(arr); } -uint16_t ITA2::getBits(char c) { +uint16_t ITA2String::getBits(char c) { // search ITA2 table uint16_t code = 0x0000; for(uint8_t i = 0; i < ITA2_LENGTH; i++) { @@ -82,7 +82,7 @@ RTTYClient::RTTYClient(PhysicalLayer* phy) { _phy = phy; } -int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t dataBits, uint8_t stopBits) { +int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) { // check supplied values if(shift % 61 != 0) { return(ERR_INVALID_RTTY_SHIFT); @@ -90,9 +90,23 @@ int16_t RTTYClient::begin(float base, uint16_t shift, uint16_t rate, uint8_t dat // save configuration _shift = shift / 61; - _dataBits = dataBits; + _encoding = encoding; _stopBits = stopBits; + switch(encoding) { + case ASCII: + _dataBits = 7; + break; + case ASCII_EXTENDED: + _dataBits = 8; + break; + case ITA2: + _dataBits = 5; + break; + default: + return(ERR_UNSUPPORTED_ENCODING); + } + // calculate duration of 1 bit _bitDuration = (uint32_t)1000000/rate; @@ -145,7 +159,7 @@ size_t RTTYClient::write(uint8_t b) { return(1); } -size_t RTTYClient::print(ITA2& ita2) { +size_t RTTYClient::print(ITA2String& ita2) { uint8_t* arr = ita2.byteArr(); size_t n = RTTYClient::write(arr, ita2.length()); delete[] arr; @@ -154,10 +168,10 @@ size_t RTTYClient::print(ITA2& ita2) { size_t RTTYClient::print(const String& str) { size_t n = 0; - if(_dataBits == 5) { - ITA2 ita2 = str.c_str(); + if(_encoding == ITA2) { + ITA2String ita2 = str.c_str(); n = RTTYClient::print(ita2); - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str.c_str(), str.length()); } return(n); @@ -165,10 +179,10 @@ size_t RTTYClient::print(const String& str) { size_t RTTYClient::print(const char str[]) { size_t n = 0; - if(_dataBits == 5) { - ITA2 ita2 = str; + if(_encoding == ITA2) { + ITA2String ita2 = str; n = RTTYClient::print(ita2); - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write((uint8_t*)str, strlen(str)); } return(n); @@ -176,10 +190,10 @@ size_t RTTYClient::print(const char str[]) { size_t RTTYClient::print(char c) { size_t n = 0; - if(_dataBits == 5) { - ITA2 ita2 = c; + if(_encoding == ITA2) { + ITA2String ita2 = c; n = RTTYClient::print(ita2); - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write(c); } return(n); @@ -226,18 +240,16 @@ size_t RTTYClient::print(double n, int digits) { size_t RTTYClient::println(void) { size_t n = 0; - if(_dataBits == 5) { - // use ITA2 line - ITA2 lf = "\r\n"; + if(_encoding == ITA2) { + ITA2String lf = "\r\n"; n = RTTYClient::print(lf); - } else { - // use ASCII line + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n = RTTYClient::write("\r\n"); } return(n); } -size_t RTTYClient::println(ITA2& ita2) { +size_t RTTYClient::println(ITA2String& ita2) { size_t n = RTTYClient::print(ita2); n += RTTYClient::println(); return(n); @@ -327,14 +339,12 @@ size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { } while(n); size_t l = 0; - if(_dataBits == 5) { - // use ITA2 encoding - ITA2 ita2 = str; + if(_encoding == ITA2) { + ITA2String ita2 = str; uint8_t* arr = ita2.byteArr(); l = RTTYClient::write(arr, ita2.length()); delete[] arr; - } else { - // use ASCII encoding + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { l = RTTYClient::write(str); } @@ -351,25 +361,25 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically if(code[0] != 0x00) { - if(_dataBits == 5) { - ITA2 ita2 = code; + if(_encoding == ITA2) { + ITA2String ita2 = code; uint8_t* arr = ita2.byteArr(); n = RTTYClient::write(arr, ita2.length()); delete[] arr; return(n); - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { return(RTTYClient::write(code)); } } // Handle negative numbers if (number < 0.0) { - if(_dataBits == 5) { - ITA2 ita2 = "-"; + if(_encoding == ITA2) { + ITA2String ita2 = "-"; uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n += RTTYClient::print('-'); } number = -number; @@ -389,12 +399,12 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { // Print the decimal point, but only if there are digits beyond if(digits > 0) { - if(_dataBits == 5) { - ITA2 ita2 = "."; + if(_encoding == ITA2) { + ITA2String ita2 = "."; uint8_t* arr = ita2.byteArr(); n += RTTYClient::write(arr, ita2.length()); delete[] arr; - } else { + } else if((_encoding == ASCII) || (_encoding == ASCII_EXTENDED)) { n += RTTYClient::print('.'); } } diff --git a/src/protocols/RTTY.h b/src/protocols/RTTY.h index be48e0ae..abc2eebe 100644 --- a/src/protocols/RTTY.h +++ b/src/protocols/RTTY.h @@ -16,11 +16,11 @@ const char ITA2Table[ITA2_LENGTH][2] = {{'\0', '\0'}, {'E', '3'}, {'\n', '\n'}, {'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 ITA2 { +class ITA2String { public: - ITA2(char c); - ITA2(const char* str); - ~ITA2(); + ITA2String(char c); + ITA2String(const char* str); + ~ITA2String(); size_t length(); uint8_t* byteArr(); @@ -32,18 +32,23 @@ class ITA2 { uint16_t getBits(char c); }; +// supported ancoding schemes +#define ASCII 0 +#define ASCII_EXTENDED 1 +#define ITA2 2 + class RTTYClient { public: RTTYClient(PhysicalLayer* phy); // basic methods - int16_t begin(float base, uint16_t shift, uint16_t rate, uint8_t dataBits = 8, uint8_t stopBits = 1); + int16_t begin(float base, uint16_t shift, uint16_t rate, uint8_t encoding = ASCII, uint8_t stopBits = 1); void idle(); size_t write(const char* str); size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); - size_t print(ITA2 &); + size_t print(ITA2String &); size_t print(const String &); size_t print(const char[]); size_t print(char); @@ -55,7 +60,7 @@ class RTTYClient { size_t print(double, int = 2); size_t println(void); - size_t println(ITA2 &); + size_t println(ITA2String &); size_t println(const String &s); size_t println(const char[]); size_t println(char); @@ -69,6 +74,7 @@ class RTTYClient { private: PhysicalLayer* _phy; + uint8_t _encoding; uint32_t _base; uint16_t _shift; uint16_t _bitDuration;