diff --git a/src/main.cpp b/src/main.cpp index da3ee40a0..1cb40f966 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -297,6 +297,8 @@ void setup() service.init(); + realRouter.setup(); // required for our periodic task (kinda skanky FIXME) + #ifndef NO_ESP32 // MUST BE AFTER service.init, so we have our radio config settings (from nodedb init) radio = new MeshRadio(); diff --git a/src/rf95/FloodingRouter.cpp b/src/rf95/FloodingRouter.cpp index 817870131..9f496cb80 100644 --- a/src/rf95/FloodingRouter.cpp +++ b/src/rf95/FloodingRouter.cpp @@ -5,9 +5,10 @@ /// We clear our old flood record five minute after we see the last of it #define FLOOD_EXPIRE_TIME (5 * 60 * 1000L) -FloodingRouter::FloodingRouter() +FloodingRouter::FloodingRouter() : toResend(MAX_NUM_NODES) { recentBroadcasts.reserve(MAX_NUM_NODES); // Prealloc the worst case # of records - to prevent heap fragmentation + // setup our periodic task } /** @@ -23,6 +24,12 @@ ErrorCode FloodingRouter::send(MeshPacket *p) return Router::send(p); } +// Return a delay in msec before sending the next packet +uint32_t getRandomDelay() +{ + return random(200, 10 * 1000L); // between 200ms and 10s +} + /** * Called from loop() * Handle any packet that is received by an interface on this node. @@ -38,12 +45,14 @@ void FloodingRouter::handleReceived(MeshPacket *p) } else { if (p->to == NODENUM_BROADCAST) { if (p->id != 0) { - DEBUG_MSG("Rebroadcasting received floodmsg to neighbors fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - // FIXME, wait a random delay + uint32_t delay = getRandomDelay(); + + DEBUG_MSG("Rebroadcasting received floodmsg to neighbors in %u msec, fr=0x%x,to=0x%x,id=%d\n", delay, p->from, + p->to, p->id); MeshPacket *tosend = packetPool.allocCopy(*p); - // Note: we are careful to resend using the original senders node id - Router::send(tosend); // We are careful not to call our hooked version of send() + toResend.enqueue(tosend); + setPeriod(delay); // This will work even if we were already waiting a random delay } else { DEBUG_MSG("Ignoring a simple (0 hop) broadcast\n"); } @@ -54,6 +63,24 @@ void FloodingRouter::handleReceived(MeshPacket *p) } } +void FloodingRouter::doTask() +{ + MeshPacket *p = toResend.dequeuePtr(0); + + DEBUG_MSG("Sending delayed message!\n"); + if (p) { + // Note: we are careful to resend using the original senders node id + // We are careful not to call our hooked version of send() - because we don't want to check this again + Router::send(p); + } + + if (toResend.isEmpty()) + disable(); // no more work right now + else { + setPeriod(getRandomDelay()); + } +} + /** * Update recentBroadcasts and return true if we have already seen this packet */ diff --git a/src/rf95/FloodingRouter.h b/src/rf95/FloodingRouter.h index 7ce7541a7..4ca759ecc 100644 --- a/src/rf95/FloodingRouter.h +++ b/src/rf95/FloodingRouter.h @@ -1,5 +1,6 @@ #pragma once +#include "PeriodicTask.h" #include "Router.h" #include @@ -35,11 +36,19 @@ struct BroadcastRecord { Any entries in recentBroadcasts that are older than X seconds (longer than the max time a flood can take) will be discarded. */ -class FloodingRouter : public Router +class FloodingRouter : public Router, public PeriodicTask { private: + /** FIXME: really should be a std::unordered_set with the key being sender,id. + * This would make checking packets in wasSeenRecently faster. + */ std::vector recentBroadcasts; + /** + * Packets we've received that we need to resend after a short delay + */ + PointerQueue toResend; + public: /** * Constructor @@ -64,6 +73,8 @@ class FloodingRouter : public Router */ virtual void handleReceived(MeshPacket *p); + virtual void doTask(); + private: /** * Update recentBroadcasts and return true if we have already seen this packet