From d75c88fc912ce64ff225126f982cb642b1575d57 Mon Sep 17 00:00:00 2001 From: Ricardo Guzman Date: Mon, 5 Oct 2026 00:30:59 -0300 Subject: [PATCH] update Status Messages y Acks a APRSPacketLib 109 --- common_settings.ini | 2 +- include/query_utils.h | 3 +- include/utils.h | 1 + src/A7670_utils.cpp | 1 + src/LoRa_APRS_iGate.cpp | 2 +- src/aprs_is_utils.cpp | 76 +++++++++++++---------------------------- src/query_utils.cpp | 42 +++++++++-------------- src/station_utils.cpp | 1 + src/utils.cpp | 21 ++++++------ 9 files changed, 56 insertions(+), 93 deletions(-) diff --git a/common_settings.ini b/common_settings.ini index 83724cf..49ce4ec 100644 --- a/common_settings.ini +++ b/common_settings.ini @@ -37,7 +37,7 @@ lib_deps = ESP32Async/AsyncTCP @ 3.4.10 ESP32Async/ESPAsyncWebServer @ 3.11.1 mikalhart/TinyGPSPlus @ 1.0.3 - richonguzman/APRSPacketLib @ 1.0.8 + richonguzman/APRSPacketLib @ 1.0.9 display_libs = adafruit/Adafruit GFX Library @ 1.12.6 adafruit/Adafruit SSD1306 @ 2.5.17 diff --git a/include/query_utils.h b/include/query_utils.h index 0c89698..e60105b 100644 --- a/include/query_utils.h +++ b/include/query_utils.h @@ -24,7 +24,8 @@ namespace QUERY_Utils { - String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty); + bool isQuery(const String& message); + String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty); } diff --git a/include/utils.h b/include/utils.h index 44167ea..d8a4a82 100644 --- a/include/utils.h +++ b/include/utils.h @@ -40,6 +40,7 @@ namespace Utils { void checkBeaconInterval(); void checkDisplayInterval(); void validateFreqs(); + String padForDisplay(const String& text); void updateLoRaPacketDisplayInfo(APRSPacket& aprsPacket, const uint8_t packetType); void updateAPRSISPacketDisplayInfo(const String& packet); void print(const String& text); diff --git a/src/A7670_utils.cpp b/src/A7670_utils.cpp index 5070e9c..f246a1d 100644 --- a/src/A7670_utils.cpp +++ b/src/A7670_utils.cpp @@ -197,6 +197,7 @@ } void uploadToAPRSIS(const String& packet) { + if (packet == "") return; // never send an empty line to APRS-IS beaconBytesSent = checkATResponse("AT+CIPSEND=0," + String(packet.length()+1)); delay(2000); if (beaconBytesSent) { diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index eb75361..25e0424 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -68,7 +68,7 @@ ___________________________________________________________________*/ #endif -String versionDate = "2026-10-04"; +String versionDate = "2026-10-05"; String versionNumber = "4.0.2"; Configuration Config; WiFiClient aprsIsClient; diff --git a/src/aprs_is_utils.cpp b/src/aprs_is_utils.cpp index 463e21e..e43c654 100644 --- a/src/aprs_is_utils.cpp +++ b/src/aprs_is_utils.cpp @@ -60,6 +60,7 @@ uint32_t lastServerCheck = 0; namespace APRS_IS_Utils { void upload(const String& line) { + if (line == "") return; // never send an empty line to APRS-IS aprsIsClient.print(line + "\r\n"); } @@ -156,37 +157,19 @@ namespace APRS_IS_Utils { int leftCurlyBraceIndex = packet.indexOf("{"); int colonIndex = packet.indexOf(":"); if (leftCurlyBraceIndex > 0) { // ack? - String ackMessage = "ack"; - ackMessage.concat(packet.substring(leftCurlyBraceIndex + 1)); - ackMessage.trim(); - //Serial.println(ackMessage); - - String addToBuffer = Config.callsign; - addToBuffer += ">APLRG1"; - if (lastAprsPacket.header == "") addToBuffer += ",RFONLY"; - if (Config.beacon.path != "") { - addToBuffer += ","; - addToBuffer += Config.beacon.path; - } - addToBuffer += "::"; - - String processedSender = sender; - for (int i = sender.length(); i < 9; i++) { - processedSender += ' '; - } - addToBuffer += processedSender; - - addToBuffer += ":"; - addToBuffer += ackMessage; - STATION_Utils::addToOutputPacketBuffer(addToBuffer); + String ackCallsign = (Config.tacticalCallsign == "") ? Config.callsign : Config.tacticalCallsign; // ack from the callsign the message was addressed to + String ackPath = (lastAprsPacket.header == "") ? "RFONLY," + Config.beacon.path : Config.beacon.path; + String ackPacket = APRSPacketLib::generateAckPacket(ackCallsign, "APLRG1", ackPath, sender, packet); + if (ackPacket != "") STATION_Utils::addToOutputPacketBuffer(ackPacket); receivedMessage = packet.substring(colonIndex + 1, leftCurlyBraceIndex); } else { receivedMessage = packet.substring(colonIndex + 1); } - if (receivedMessage.indexOf("?") == 0) { + if (QUERY_Utils::isQuery(receivedMessage)) { if (!Config.display.alwaysOn && Config.display.timeout != 0) displayToggle(true); - STATION_Utils::addToOutputPacketBuffer(QUERY_Utils::process(receivedMessage, sender, false, lastAprsPacket.header != "")); + String queryAnswer = QUERY_Utils::process(receivedMessage, sender, false, lastAprsPacket.header != ""); + if (queryAnswer != "") STATION_Utils::addToOutputPacketBuffer(queryAnswer); // unknown query: no answer lastScreenOn = millis(); displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, "Callsign = " + sender, "TYPE --> QUERY", 0); return true; @@ -274,21 +257,9 @@ namespace APRS_IS_Utils { } void processAckMessage(const String& sender, const String& message) { - String ackPacket = Config.callsign; - ackPacket += ">APLRG1,TCPIP*::"; - - String senderCallsign = sender; - for (int i = sender.length(); i < 9; i++) { - senderCallsign += ' '; - } - ackPacket += senderCallsign; - ackPacket += ":"; - - String ackMessage = "ack"; - ackMessage += message.substring(message.indexOf("{") + 1); - ackMessage.trim(); - ackPacket += ackMessage; - + String ackPacket = APRSPacketLib::generateAckPacket(Config.callsign, "APLRG1", "", sender, message); + if (ackPacket == "") return; + ackPacket = APRSPacketLib::generateAPRSISPacket(ackPacket); #ifdef HAS_A7670 A7670_Utils::uploadToAPRSIS(ackPacket); #else @@ -314,7 +285,7 @@ namespace APRS_IS_Utils { if (Config.digi.backupDigiMode) lastServerCheck = currentTime; } else { int doubleColonIndex = packet.indexOf("::"); - if (Config.aprs_is.messagesToRF && doubleColonIndex > 0) { + if (doubleColonIndex > 0) { // messages for this station are always answered; messagesToRF only gates forwarding to RF String Sender = packet.substring(0, packet.indexOf(">")); const String& AddresseeAndMessage = packet.substring(doubleColonIndex + 2); int colonIndex = AddresseeAndMessage.indexOf(":"); @@ -329,7 +300,7 @@ namespace APRS_IS_Utils { } else { receivedMessage = AddresseeAndMessage.substring(colonIndex + 1); } - if (receivedMessage.indexOf("?") == 0) { + if (QUERY_Utils::isQuery(receivedMessage)) { Utils::println("Rx Query (APRS-IS) : " + packet); String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false); //Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n"))); @@ -337,24 +308,23 @@ namespace APRS_IS_Utils { displayToggle(true); } lastScreenOn = currentTime; - #ifdef HAS_A7670 - A7670_Utils::uploadToAPRSIS(queryAnswer); - #else - upload(queryAnswer); - #endif - SYSLOG_Utils::logAPRSISTx(queryAnswer); - fifthLine = "APRS-IS ----> APRS-IS"; - sixthLine = Config.callsign; - for (int j = sixthLine.length();j < 9;j++) { - sixthLine += " "; + if (queryAnswer != "") { // unknown query: no answer + #ifdef HAS_A7670 + A7670_Utils::uploadToAPRSIS(queryAnswer); + #else + upload(queryAnswer); + #endif + SYSLOG_Utils::logAPRSISTx(queryAnswer); } + fifthLine = "APRS-IS ----> APRS-IS"; + sixthLine = Utils::padForDisplay(Config.callsign); sixthLine += "> "; sixthLine += Sender; seventhLine = "QUERY = "; seventhLine += receivedMessage; } displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0); - } else { + } else if (Config.aprs_is.messagesToRF) { Utils::print("Rx Message (APRS-IS): " + packet); if (STATION_Utils::wasHeard(Addressee) && packet.indexOf("EQNS.") == -1 && packet.indexOf("UNIT.") == -1 && packet.indexOf("PARM.") == -1) { STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 1)); diff --git a/src/query_utils.cpp b/src/query_utils.cpp index 1383677..1c68240 100644 --- a/src/query_utils.cpp +++ b/src/query_utils.cpp @@ -16,6 +16,7 @@ * along with LoRa APRS iGate. If not, see . */ +#include #include "configuration.h" #include "battery_utils.h" #include "station_utils.h" @@ -36,11 +37,17 @@ extern String versionNumber; namespace QUERY_Utils { + bool isQuery(const String& message) { // "?..." queries, plus "HELP" (any case) without the "?" + String queryQuestion = message; + queryQuestion.toUpperCase(); + return queryQuestion.startsWith("?") || queryQuestion == "HELP"; + } + String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty) { String answer; String queryQuestion = query; queryQuestion.toUpperCase(); - if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") { + if (queryQuestion == "?APRS?" || queryQuestion == "?" || queryQuestion == "HELP") { answer.concat("?APRSV ?APRSP ?APRSL ?APRSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign } else if (queryQuestion == "?APRSV") { answer.concat("CA2RXU_LoRa_iGate v"); @@ -139,32 +146,15 @@ namespace QUERY_Utils { if (answer == "") return ""; - String queryAnswer = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign); - queryAnswer += ">APLRG1"; - if (queryFromAPRSIS) { - queryAnswer += ",TCPIP*"; - } else { - if (!thirdParty) queryAnswer += ",RFONLY"; - if (Config.beacon.path != "") { - queryAnswer += ","; - queryAnswer += Config.beacon.path; - } - } - queryAnswer += "::"; + answer += " *"; + answer += char(random(97, 123)); + answer += char(random(97, 123)); + answer += "*"; - String processedStation = station; - for (int i = station.length(); i < 9; i++) { - processedStation += ' '; - } - queryAnswer += processedStation; - queryAnswer += ":"; - queryAnswer += answer; - - queryAnswer += " *"; - queryAnswer += char(random(97, 123)); - queryAnswer += char(random(97, 123)); - queryAnswer += "*"; - return queryAnswer; + String queryCallsign = (Config.tacticalCallsign == "") ? Config.callsign : Config.tacticalCallsign; + String queryPath = queryFromAPRSIS ? "" : (thirdParty ? Config.beacon.path : "RFONLY," + Config.beacon.path); + String queryAnswer = APRSPacketLib::generateMessagePacket(queryCallsign, "APLRG1", queryPath, station, answer); + return queryFromAPRSIS ? APRSPacketLib::generateAPRSISPacket(queryAnswer) : queryAnswer; } } \ No newline at end of file diff --git a/src/station_utils.cpp b/src/station_utils.cpp index 15deebf..9090ce0 100644 --- a/src/station_utils.cpp +++ b/src/station_utils.cpp @@ -234,6 +234,7 @@ namespace STATION_Utils { } void addToOutputPacketBuffer(const String& packet, bool flag) { + if (packet == "") return; // never queue an empty packet outputPacketBuffer.emplace_back(OutputPacketBuffer{packet, flag}); } diff --git a/src/utils.cpp b/src/utils.cpp index 4c74142..e729d56 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -83,7 +83,8 @@ namespace Utils { return; } - String statusPacket = APRSPacketLib::generateStatusPacket(Config.callsign, "APLRG1", Config.beacon.path, Config.beacon.statusPacket); + String statusCallsign = (Config.tacticalCallsign == "") ? Config.callsign : Config.tacticalCallsign; + String statusPacket = APRSPacketLib::generateStatusPacket(statusCallsign, "APLRG1", Config.beacon.path, Config.beacon.statusPacket); if (sendOverAPRSIS) { String aprsisStatusPacket = APRSPacketLib::generateAPRSISPacket(statusPacket); @@ -322,6 +323,12 @@ namespace Utils { } } + String padForDisplay(const String& text) { // left-aligned, 9 chars wide (callsign column on screen) + char buffer[10]; + snprintf(buffer, sizeof(buffer), "%-9s", text.c_str()); + return String(buffer); + } + void updateLoRaPacketDisplayInfo(APRSPacket& aprsPacket, const uint8_t packetType) { switch (packetType) { case 0: // LoRa-APRS @@ -332,11 +339,7 @@ namespace Utils { break; } - String sender = aprsPacket.sender; - for (int i = sender.length(); i < 9; i++) { - sender += " "; - } - sixthLine = sender; + sixthLine = padForDisplay(aprsPacket.sender); switch (aprsPacket.type) { case 1: // MESSAGE @@ -382,11 +385,7 @@ namespace Utils { void updateAPRSISPacketDisplayInfo(const String& packet) { fifthLine = "APRS-IS ----> LoRa Tx"; - String sender = packet.substring(0,packet.indexOf(">")); - for (int i = sender.length(); i < 9; i++) { - sender += " "; - } - sixthLine = sender; + sixthLine = padForDisplay(packet.substring(0,packet.indexOf(">"))); if (packet.indexOf("::") > 0) { sixthLine += "> MESSAGE";