From a13b4f95374164cd1c01541777ca239014b967e2 Mon Sep 17 00:00:00 2001
From: jgromes <jgromes@users.noreply.github.com>
Date: Tue, 2 Oct 2018 20:46:52 +0200
Subject: [PATCH] [RTTY] Simplified transmission encoding configuration

---
 .../SX127x_RTTY_Transmit.ino                  | 48 ++++-------
 src/TypeDef.h                                 |  5 +-
 src/protocols/RTTY.cpp                        | 86 +++++++++++--------
 src/protocols/RTTY.h                          | 20 +++--
 4 files changed, 80 insertions(+), 79 deletions(-)

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;