diff --git a/include/station_utils.h b/include/station_utils.h
index af606de..fbc7a4c 100644
--- a/include/station_utils.h
+++ b/include/station_utils.h
@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
- *
+ *
* This file is part of LoRa APRS iGate.
- *
+ *
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see .
*/
@@ -37,8 +37,7 @@ namespace STATION_Utils {
void deleteNotHeard();
void updateLastHeard(const String& station);
bool wasHeard(const String& station);
- void clean25SegBuffer();
- bool check25SegBuffer(const String& station, const String& textMessage);
+ bool isIn25SegHashBuffer(const String& station, const String& textMessage);
void processOutputPacketBufferUltraEcoMode();
void processOutputPacketBuffer();
void addToOutputPacketBuffer(const String& packet, bool flag = false);
diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp
index ec9c0d9..fdc5c65 100644
--- a/src/LoRa_APRS_iGate.cpp
+++ b/src/LoRa_APRS_iGate.cpp
@@ -188,7 +188,6 @@ void loop() {
}
if (Config.loramodule.txActive && (Config.digi.mode == 2 || Config.digi.mode == 3 || backupDigiMode)) { // If Digi enabled
- STATION_Utils::clean25SegBuffer();
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
}
diff --git a/src/digi_utils.cpp b/src/digi_utils.cpp
index a2af2dd..ac73f07 100644
--- a/src/digi_utils.cpp
+++ b/src/digi_utils.cpp
@@ -149,28 +149,28 @@ namespace DIGI_Utils {
if (Sender == stationCallsign) return; // Avoid listening to self packets
if (!thirdPartyPacket && Config.tacticalCallsign == "" && !Utils::callsignIsValid(Sender)) return; // No thirdParty + no tactical y no valid callsign
- if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) {
- STATION_Utils::updateLastHeard(Sender);
- Utils::typeOfPacket(temp, 2); // Digi
- bool queryMessage = false;
- int doubleColonIndex = temp.indexOf("::");
- if (doubleColonIndex > 10) { // it's a message
- String AddresseeAndMessage = temp.substring(doubleColonIndex + 2);
- String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
- Addressee.trim();
- if (Addressee == stationCallsign) { // it's a message for me!
- queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
- }
- }
- if (queryMessage) return; // answer should not be repeated.
+ if (STATION_Utils::isIn25SegHashBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) return;
- String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
- if (loraPacket != "") {
- STATION_Utils::addToOutputPacketBuffer(loraPacket);
- if (Config.digi.ecoMode != 1) displayToggle(true);
- lastScreenOn = millis();
+ STATION_Utils::updateLastHeard(Sender);
+ Utils::typeOfPacket(temp, 2); // Digi
+ bool queryMessage = false;
+ int doubleColonIndex = temp.indexOf("::");
+ if (doubleColonIndex > 10) { // it's a message
+ String AddresseeAndMessage = temp.substring(doubleColonIndex + 2);
+ String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
+ Addressee.trim();
+ if (Addressee == stationCallsign) { // it's a message for me!
+ queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
}
}
+ if (queryMessage) return; // answer should not be repeated.
+
+ String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
+ if (loraPacket != "") {
+ STATION_Utils::addToOutputPacketBuffer(loraPacket);
+ if (Config.digi.ecoMode != 1) displayToggle(true);
+ lastScreenOn = millis();
+ }
}
}
\ No newline at end of file
diff --git a/src/station_utils.cpp b/src/station_utils.cpp
index b538bad..3d8892c 100644
--- a/src/station_utils.cpp
+++ b/src/station_utils.cpp
@@ -1,17 +1,17 @@
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
- *
+ *
* This file is part of LoRa APRS iGate.
- *
+ *
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see .
*/
@@ -45,12 +45,10 @@ std::vector outputPacketBuffer;
struct Packet25SegBuffer {
uint32_t receivedTime;
- String station;
- String payload;
+ uint32_t hash;
};
std::vector packet25SegBuffer;
-
bool saveNewDigiEcoModeConfig = false;
bool packetIsBeacon = false;
@@ -166,18 +164,33 @@ namespace STATION_Utils {
return false;
}
- void clean25SegBuffer() {
- if (!packet25SegBuffer.empty() && (millis() - packet25SegBuffer[0].receivedTime) > 25 * 1000) packet25SegBuffer.erase(packet25SegBuffer.begin());
- }
-
- bool check25SegBuffer(const String& station, const String& textMessage) {
- if (!packet25SegBuffer.empty()) {
- for (int i = 0; i < packet25SegBuffer.size(); i++) {
- if (packet25SegBuffer[i].station == station && packet25SegBuffer[i].payload == textMessage) return false;
+ void clean25SegHashBuffer() {
+ uint32_t currentTime = millis();
+ for (int i = packet25SegBuffer.size() - 1; i >= 0; i--) {
+ if ((currentTime - packet25SegBuffer[i].receivedTime) > 25 * 1000) {
+ packet25SegBuffer.erase(packet25SegBuffer.begin() + i);
}
}
- packet25SegBuffer.emplace_back(Packet25SegBuffer{millis(), station, textMessage});
- return true;
+ }
+
+ uint32_t makeHash(const String& station, const String& payload) { // DJB2 Hash
+ uint32_t h = 5381;
+ for (size_t i = 0; i < station.length(); i++)
+ h = ((h << 5) + h) + station[i];
+ for (size_t i = 0; i < payload.length(); i++)
+ h = ((h << 5) + h) + payload[i];
+ return h;
+ }
+
+ bool isIn25SegHashBuffer(const String& station, const String& textMessage) {
+ uint32_t newHash = makeHash(station, textMessage);
+ uint32_t currentTime = millis();
+ clean25SegHashBuffer();
+ for (int i = 0; i < packet25SegBuffer.size(); i++) {
+ if (packet25SegBuffer[i].hash == newHash) return true;
+ }
+ packet25SegBuffer.push_back({currentTime, newHash});
+ return false;
}
void processOutputPacketBufferUltraEcoMode() {