From 97751df3ea383641119c6c9fa14ab3a8bf9d0747 Mon Sep 17 00:00:00 2001 From: Steve Gilberd Date: Sat, 28 Dec 2024 16:13:41 +1300 Subject: [PATCH] If a packet is heard multiple times, rebroadcast using the highest hop limit Sometimes a packet will be in the TX queue waiting to be transmitted, when it is overheard being rebroadcast by another node, with a higher hop limit remaining. When this occurs, modify the pending packet in the TX queue to avoid unnecessarily wasting hops. --- src/mesh/FloodingRouter.cpp | 4 ++++ src/mesh/MeshPacketQueue.cpp | 13 +++++++++++++ src/mesh/MeshPacketQueue.h | 3 +++ src/mesh/RadioInterface.h | 3 +++ src/mesh/RadioLibInterface.cpp | 12 ++++++++++++ src/mesh/RadioLibInterface.h | 5 +++++ 6 files changed, 40 insertions(+) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index f94540905..64280f3fe 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -29,6 +29,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! if (Router::cancelSending(p->from, p->id)) txRelayCanceled++; + } else if (iface && p->hop_limit > 0) { + // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to + // rebroadcast, then update the hop limit of the packet currently sitting in the TX queue. + iface->clampHopsToMax(getFrom(p), p->id, p->hop_limit - 1); } if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) { iface->clampToLateRebroadcastWindow(getFrom(p), p->id); diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index d7ee65800..282d27b40 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -99,6 +99,19 @@ meshtastic_MeshPacket *MeshPacketQueue::getFront() return p; } +/** Attempt to find a packet in this queue. Returns a pointer to the found packet, or NULL if not found. */ +meshtastic_MeshPacket *MeshPacketQueue::find(NodeNum from, PacketId id) +{ + for (auto it = queue.begin(); it != queue.end(); it++) { + auto p = (*it); + if (getFrom(p) == from && p->id == id) { + return p; + } + } + + return NULL; +} + /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool tx_normal, bool tx_late) { diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index b41a214b9..578280ef7 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -35,6 +35,9 @@ class MeshPacketQueue meshtastic_MeshPacket *getFront(); + /** Attempt to find a packet in this queue. Returns a pointer to the found packet, or NULL if not found. */ + meshtastic_MeshPacket *find(NodeNum from, PacketId id); + /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ meshtastic_MeshPacket *remove(NodeNum from, PacketId id, bool tx_normal = true, bool tx_late = true); }; \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 652b2269c..90f958c00 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -185,6 +185,9 @@ class RadioInterface /** If the packet is not already in the late rebroadcast window, move it there */ virtual void clampToLateRebroadcastWindow(NodeNum from, PacketId id) { return; } + /** Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue */ + virtual void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) { return; } + /** * Calculate airtime per * https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 997b1d6fe..7b972cad4 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -344,6 +344,18 @@ void RadioLibInterface::clampToLateRebroadcastWindow(NodeNum from, PacketId id) } } +/** + * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + */ +void RadioLibInterface::clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) +{ + meshtastic_MeshPacket *p = txQueue.find(from, id); + if (p && p->hop_limit < hop_limit) { + LOG_DEBUG("Increasing hop limit for packet from %d to %d", p->hop_limit, hop_limit); + p->hop_limit = hop_limit; + } +} + void RadioLibInterface::handleTransmitInterrupt() { // This can be null if we forced the device to enter standby mode. In that case diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index dff58c9ad..affb00609 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -204,4 +204,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * If the packet is not already in the late rebroadcast window, move it there */ void clampToLateRebroadcastWindow(NodeNum from, PacketId id); + + /** + * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + */ + void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit); }; \ No newline at end of file