From 5d04c56fd27ae0f0b2c4cfd4dd3850ffabbeafcb Mon Sep 17 00:00:00 2001 From: Ricardo Guzman Date: Tue, 15 Sep 2026 11:52:09 -0300 Subject: [PATCH] tnc2 added --- data_embed/index.html | 21 +++++++++++-- data_embed/script.js | 1 + include/configuration.h | 1 + src/LoRa_APRS_iGate.cpp | 2 +- src/configuration.cpp | 6 +++- src/tnc_utils.cpp | 68 ++++++++++++++++++++++++++++++----------- src/web_utils.cpp | 1 + 7 files changed, 79 insertions(+), 21 deletions(-) diff --git a/data_embed/index.html b/data_embed/index.html index eefaee3..b7fd316 100644 --- a/data_embed/index.html +++ b/data_embed/index.html @@ -1520,7 +1520,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u Enable Serial @@ -1552,7 +1552,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u Accept own frames @@ -1572,6 +1572,23 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u +
+
+ + +
+
diff --git a/data_embed/script.js b/data_embed/script.js index 1f935cd..848c9c6 100644 --- a/data_embed/script.js +++ b/data_embed/script.js @@ -226,6 +226,7 @@ function loadSettings(settings) { document.getElementById("tnc.enableSerial").checked = settings.tnc.enableSerial; document.getElementById("tnc.acceptOwn").checked = settings.tnc.acceptOwn; document.getElementById("tnc.aprsBridgeActive").checked = settings.tnc.aprsBridgeActive; + document.getElementById("tnc.kissProtocol").value = settings.tnc.kissProtocol ? "KISS" : "TNC2"; } // MQTT diff --git a/include/configuration.h b/include/configuration.h index 3927e12..69e9667 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -132,6 +132,7 @@ public: bool enableSerial; bool acceptOwn; bool aprsBridgeActive; + bool kissProtocol; // true = KISS, false = TNC2 -- applies to both Serial and TCP server }; class OTA { diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index 99f5a6f..fab911f 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -68,7 +68,7 @@ ___________________________________________________________________*/ #endif -String versionDate = "2026-09-07"; +String versionDate = "2026-09-15"; String versionNumber = "4.0.1"; Configuration Config; WiFiClient aprsIsClient; diff --git a/src/configuration.cpp b/src/configuration.cpp index a6ed87f..306045a 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -157,6 +157,7 @@ bool Configuration::writeFile() { data["tnc"]["enableSerial"] = tnc.enableSerial; data["tnc"]["acceptOwn"] = tnc.acceptOwn; data["tnc"]["aprsBridgeActive"] = tnc.aprsBridgeActive; + data["tnc"]["kissProtocol"] = tnc.kissProtocol; data["mqtt"]["active"] = mqtt.active; data["mqtt"]["server"] = mqtt.server; @@ -369,11 +370,13 @@ bool Configuration::readFile() { if (data["tnc"]["enableServer"].isNull() || data["tnc"]["enableSerial"].isNull() || data["tnc"]["acceptOwn"].isNull() || - data["tnc"]["aprsBridgeActive"].isNull()) needsRewrite = true; + data["tnc"]["aprsBridgeActive"].isNull() || + data["tnc"]["kissProtocol"].isNull()) needsRewrite = true; tnc.enableServer = data["tnc"]["enableServer"] | false; tnc.enableSerial = data["tnc"]["enableSerial"] | false; tnc.acceptOwn = data["tnc"]["acceptOwn"] | false; tnc.aprsBridgeActive = data["tnc"]["aprsBridgeActive"] | false; + tnc.kissProtocol = data["tnc"]["kissProtocol"] | true; if (data["mqtt"]["active"].isNull() || data["mqtt"]["server"].isNull() || @@ -538,6 +541,7 @@ void Configuration::setDefaultValues() { tnc.enableSerial = false; tnc.acceptOwn = false; tnc.aprsBridgeActive = false; + tnc.kissProtocol = true; mqtt.active = false; mqtt.server = ""; diff --git a/src/tnc_utils.cpp b/src/tnc_utils.cpp index f53cd14..99f6328 100644 --- a/src/tnc_utils.cpp +++ b/src/tnc_utils.cpp @@ -78,7 +78,23 @@ namespace TNC_Utils { } } - void handleInputData(char character, int bufferIndex) { + void processInputFrame(const String& frame, int bufferIndex, const String& protocolLabel) { + if (bufferIndex != -1) { + Utils::print("<--- Got from TNC (" + protocolLabel + ") : "); + Utils::println(frame); + } + + String sender = frame.substring(0,frame.indexOf(">")); + + if (Config.tnc.acceptOwn || sender != Config.callsign) { + if (Config.loramodule.txActive) STATION_Utils::addToOutputPacketBuffer(frame); + if (Config.tnc.aprsBridgeActive && Config.aprs_is.active && passcodeValid && aprsIsClient.connected()) APRS_IS_Utils::upload(frame); + } else { + Utils::println("Ignored own frame from " + protocolLabel); + } + } + + void handleInputDataKISS(char character, int bufferIndex) { String* data = (bufferIndex == -1) ? &inputSerialBuffer : &inputServerBuffer[bufferIndex]; if (data->length() == 0 && character != (char)FEND) return; @@ -89,19 +105,7 @@ namespace TNC_Utils { const String& frame = decodeKISS(*data, isDataFrame); if (isDataFrame) { - if (bufferIndex != -1) { - Utils::print("<--- Got from TNC : "); - Utils::println(frame); - } - - String sender = frame.substring(0,frame.indexOf(">")); - - if (Config.tnc.acceptOwn || sender != Config.callsign) { - if (Config.loramodule.txActive) STATION_Utils::addToOutputPacketBuffer(frame); - if (Config.tnc.aprsBridgeActive && Config.aprs_is.active && passcodeValid && aprsIsClient.connected()) APRS_IS_Utils::upload(frame); - } else { - Utils::println("Ignored own frame from KISS"); - } + processInputFrame(frame, bufferIndex, "KISS"); } data->clear(); } @@ -111,6 +115,36 @@ namespace TNC_Utils { } } + void handleInputDataTNC2(char character, int bufferIndex) { + String* data = (bufferIndex == -1) ? &inputSerialBuffer : &inputServerBuffer[bufferIndex]; + + if (character == '\r') return; + + if (character == '\n') { + String frame = *data; + frame.trim(); + data->clear(); + + if (frame.length() > 0 && frame.indexOf(':') != -1 && frame.indexOf('>') != -1) { + processInputFrame(frame, bufferIndex, "TNC2"); + } + return; + } + + data->concat(character); + if (data->length() > 255) { + data->clear(); + } + } + + void handleInputData(char character, int bufferIndex) { + if (Config.tnc.kissProtocol) { + handleInputDataKISS(character, bufferIndex); + } else { + handleInputDataTNC2(character, bufferIndex); + } + } + void readFromClients() { for (int i = 0; i < MAX_CLIENTS; i++) { auto client = clients[i]; @@ -138,13 +172,13 @@ namespace TNC_Utils { void sendToClients(const String& packet, bool stripBytes) { String cleanPacket = stripBytes ? packet.substring(3): packet; - const String kissEncoded = encodeKISS(cleanPacket); + const String encoded = Config.tnc.kissProtocol ? encodeKISS(cleanPacket) : (cleanPacket + "\r\n"); for (int i = 0; i < MAX_CLIENTS; i++) { auto client = clients[i]; if (client != nullptr) { if (client->connected()) { - client->print(kissEncoded); + client->print(encoded); client->flush(); } else { delete client; @@ -158,7 +192,7 @@ namespace TNC_Utils { void sendToSerial(const String& packet, bool stripBytes) { String cleanPacket = stripBytes ? packet.substring(3): packet; - Serial.print(encodeKISS(cleanPacket)); + Serial.print(Config.tnc.kissProtocol ? encodeKISS(cleanPacket) : (cleanPacket + "\r\n")); Serial.flush(); } diff --git a/src/web_utils.cpp b/src/web_utils.cpp index 5ed6b36..87b4a55 100644 --- a/src/web_utils.cpp +++ b/src/web_utils.cpp @@ -322,6 +322,7 @@ namespace WEB_Utils { Config.tnc.enableSerial = request->hasParam("tnc.enableSerial", true); Config.tnc.acceptOwn = request->hasParam("tnc.acceptOwn", true); Config.tnc.aprsBridgeActive = request->hasParam("tnc.aprsBridgeActive", true); + Config.tnc.kissProtocol = getParamStringSafe("tnc.kissProtocol", Config.tnc.kissProtocol ? "KISS" : "TNC2") != "TNC2"; Config.mqtt.active = request->hasParam("mqtt.active", true); if (Config.mqtt.active) {