diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 1629b16e8..f3a3bd1aa 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -169,6 +169,11 @@ void MeshService::handleToRadio(MeshPacket &p) } } +/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ +bool MeshService::cancelSending(PacketId id) { + return router->cancelSending(nodeDB.getNodeNum(), id); +} + void MeshService::sendToMesh(MeshPacket *p) { nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 5c30339a0..8cba07710 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -79,6 +79,9 @@ class MeshService /// cache void sendToMesh(MeshPacket *p); + /** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ + bool cancelSending(PacketId id); + /// Pull the latest power and time info into my nodeinfo NodeInfo *refreshMyNodeInfo(); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 0d8c7b9b7..c49421d11 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -105,6 +105,9 @@ class RadioInterface */ virtual ErrorCode send(MeshPacket *p) = 0; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id) { return false; } + // methods from radiohead /// Initialise the Driver transport hardware and software. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 27e767bf7..744762c08 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -132,6 +132,13 @@ bool RadioLibInterface::canSleep() return res; } +/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ +bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) { + assert(0); + return false; +} + + /** radio helper thread callback. We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index e762fdcdc..b002f49bc 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -136,6 +136,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual bool isActivelyReceiving() = 0; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id); + private: /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing * the transmit diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3ea6e9138..121d42a21 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -124,6 +124,8 @@ void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) sendLocal(p); // we sometimes send directly to the local node } + + ErrorCode Router::sendLocal(MeshPacket *p) { // No need to deliver externally if the destination is the local node @@ -199,6 +201,13 @@ ErrorCode Router::send(MeshPacket *p) } */ } +/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ +bool Router::cancelSending(NodeNum from, PacketId id) { + return iface ? iface->cancelSending(from, id) : false; +} + + + /** * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index dfc44dfa4..3951f3062 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -55,7 +55,12 @@ class Router : protected concurrency::OSThread */ ErrorCode sendLocal(MeshPacket *p); - /// Allocate and return a meshpacket which defaults as send to broadcast from the current node. + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + bool cancelSending(NodeNum from, PacketId id); + + /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. + * The returned packet is guaranteed to have a unique packet ID already assigned + */ MeshPacket *allocForSending(); /** diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 54aea4cc7..494387dd5 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -28,10 +28,15 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p) void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies) { + // cancel any not yet sent (now stale) position packets + if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + service.cancelSending(prevPacketId); + MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; - + prevPacketId = p->id; + service.sendToMesh(p); } diff --git a/src/plugins/NodeInfoPlugin.h b/src/plugins/NodeInfoPlugin.h index aabeb0059..8b01ea25e 100644 --- a/src/plugins/NodeInfoPlugin.h +++ b/src/plugins/NodeInfoPlugin.h @@ -6,6 +6,9 @@ */ class NodeInfoPlugin : public ProtobufPlugin { + /// The id of the last packet we sent, to allow us to cancel it if we make something fresher + PacketId prevPacketId = 0; + public: /** Constructor * name is for debugging output diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index f9f86bf68..ab89eddc1 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -37,9 +37,14 @@ MeshPacket *PositionPlugin::allocReply() void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) { + // cancel any not yet sent (now stale) position packets + if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + service.cancelSending(prevPacketId); + MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; + prevPacketId = p->id; service.sendToMesh(p); } diff --git a/src/plugins/PositionPlugin.h b/src/plugins/PositionPlugin.h index 6a1eb05f0..9ca2d2082 100644 --- a/src/plugins/PositionPlugin.h +++ b/src/plugins/PositionPlugin.h @@ -6,6 +6,9 @@ */ class PositionPlugin : public ProtobufPlugin { + /// The id of the last packet we sent, to allow us to cancel it if we make something fresher + PacketId prevPacketId = 0; + public: /** Constructor * name is for debugging output