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() {