diff --git a/include/KISS.h b/lib/KISS_TO_TNC2/KISS.h similarity index 100% rename from include/KISS.h rename to lib/KISS_TO_TNC2/KISS.h diff --git a/lib/KISS_TO_TNC2/KISS_TO_TNC2.cpp b/lib/KISS_TO_TNC2/KISS_TO_TNC2.cpp new file mode 100644 index 0000000..3ef8213 --- /dev/null +++ b/lib/KISS_TO_TNC2/KISS_TO_TNC2.cpp @@ -0,0 +1,100 @@ +#include "KISS_TO_TNC2.h" + +bool validateTNC2Frame(const String &tnc2FormattedFrame); + +String encode_address_kiss(String tnc2Address, bool isLast); + +/* + * https://ham.zmailer.org/oh2mqk/aprx/PROTOCOLS + + After successfull login, communication carries "TNC2" format + APRS messages. Namely text encoding of AX.25 UI frames in + what became known as "TNC2 monitor style": + + SOURCE>DESTIN:payload + SOURCE>DESTIN,VIA,VIA:payload + + The SOURCE, DESTIN, and VIA fields are AX.25 address fields, + and have "-SSID" value annexed if the SSID is not zero. + Also in VIA-fields, if the "HAS BEEN DIGIPEATED" bit is set + (AX.25 v2 protocol feature) a star ('*') character is appended. + VIA-fields are separated by comma (',') from DESTIN, and each + other. + + A double-colon (':') separates address data from payload. + The payload is passed _AS_IS_ without altering any message + content bytes, however ending at first CR or LF character + encountered in the packet. + + */ + +String encode_kiss(const String& tnc2FormattedFrame) { + String ax25Frame = ""; + + if (validateTNC2Frame(tnc2FormattedFrame)){ + String address = ""; + for (int p=0;p' || currentChar == ','){ + if (currentChar == '>'){ + // ax25 frame DST SRC + // tnc2 frame SRC DST + ax25Frame = encode_address_kiss(address, currentChar == ':') + ax25Frame; + } else { + ax25Frame += encode_address_kiss(address, currentChar == ':'); + } + } else { + address += currentChar; + } + } + ax25Frame += (char)APRS_CONTROL_FIELD; + ax25Frame += (char)APRS_INFORMATION_FIELD; + ax25Frame += tnc2FormattedFrame.substring(tnc2FormattedFrame.indexOf(':')+1); + } + + String kissFrame = ""; + kissFrame += (char)FEND; // start of frame + kissFrame += (char)CMD_DATA; // TNC0, DATA + for (int i = 0; i < ax25Frame.length(); ++i) { + char currentChar = tnc2FormattedFrame.charAt(i); + if (currentChar == (char)FEND) { + kissFrame += FESC; + kissFrame += TFEND; + } else if (currentChar == (char)FESC){ + kissFrame += FESC; + kissFrame += TFESC; + } else { + kissFrame += currentChar; + } + } + kissFrame += (char)FEND; // end of frame + return kissFrame; +} + +/** + * Encode adress in TNC2 monitor format to ax.25/kiss format + * @param tnc2Address + * @param isLast + * @return + */ +String encode_address_kiss(String tnc2Address, bool isLast) { + if (tnc2Address.indexOf('-') == -1){ + tnc2Address += "-0"; + } + bool hasBeenDigipited = tnc2Address.indexOf('*') != -1; + + int ssid = tnc2Address.substring(tnc2Address.indexOf('-')+1).toInt(); + // TODO: SSID should not be > 16 + String kissAddress = ""; + for (int i = 0; i < 6; ++i) { + if (tnc2Address.length() > i){ + kissAddress += (char)(tnc2Address.charAt(i) << 1); + } else { + kissAddress += ' '; + } + } + kissAddress += (char)((ssid << 1) | 0b01100000 | (isLast ? 1 : 0) | (hasBeenDigipited ? 0b10000000 : 0)); + return kissAddress; +} + +bool validateTNC2Frame(const String &tnc2FormattedFrame) { return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1); } diff --git a/lib/KISS_TO_TNC2/KISS_TO_TNC2.h b/lib/KISS_TO_TNC2/KISS_TO_TNC2.h new file mode 100644 index 0000000..5ae7dd6 --- /dev/null +++ b/lib/KISS_TO_TNC2/KISS_TO_TNC2.h @@ -0,0 +1,9 @@ +#include +#include "KISS.h" + +#define APRS_CONTROL_FIELD 0x03 +#define APRS_INFORMATION_FIELD 0xf0 + +String encode_kiss(const String& tnc2FormattedFrame); + +String decode_kiss(String kissFormattedFrame); diff --git a/src/TTGO_T-Beam_LoRa_APRS.ino b/src/TTGO_T-Beam_LoRa_APRS.ino index 51bf33b..8547c50 100644 --- a/src/TTGO_T-Beam_LoRa_APRS.ino +++ b/src/TTGO_T-Beam_LoRa_APRS.ino @@ -21,7 +21,7 @@ #include #include #include -#include "KISS.h" +#include // I2C LINES #define I2C_SDA 21 @@ -283,23 +283,6 @@ void writedisplaytext(String HeaderTxt, String Line1, String Line2, String Line3 display.display(); smartDelay(warten); } - -void encode_address(){ - -} - -void decode_address(){ - -} - -void encode_kiss(){ - -} - -void decode_kiss(){ - -} - // + SETUP --------------------------------------------------------------+// void setup(){ @@ -405,7 +388,7 @@ void loop() { Serial.println(InputString); #endif #ifdef KISS_PROTOCOLL - //encode_kiss(InputString); + Serial.println(encode_kiss(InputString)); #endif writedisplaytext(" ((RX))","",InputString,"","","",SHOW_RX_TIME); } diff --git a/src/TTGO_T-Beam_LoRa_APRS_config.h b/src/TTGO_T-Beam_LoRa_APRS_config.h index 0b60df5..9b07d54 100644 --- a/src/TTGO_T-Beam_LoRa_APRS_config.h +++ b/src/TTGO_T-Beam_LoRa_APRS_config.h @@ -5,8 +5,8 @@ // licensed under CC BY-NC-SA // USER DATA - USE THESE LINES TO MODIFY YOUR PREFERENCES -//#define KISS_PROTOCOLL // If enabled send and receive data in SIMPLE KISS format -#define TEXT_PROTOCOLL // TEXT outpu data +#define KISS_PROTOCOLL // If enabled send and receive data in SIMPLE KISS format +//#define TEXT_PROTOCOLL // TEXT outpu data #define CALLSIGN "SQ9MDD-11" // enter your callsign here - less then 6 letter callsigns please add "spaces" so total length is 6 (without SSID) //#define LONGITUDE_PRESET "02055.59E" // please in APRS notation DDDMM.mmE or DDDMM.mmW //#define LATIDUDE_PRESET "5215.02N" // please in APRS notation DDMM.mmN or DDMM.mmS