mirror of
https://github.com/meshtastic/firmware.git
synced 2025-02-03 19:29:57 +00:00
130 lines
3.7 KiB
C++
130 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include "FloodingRouter.h"
|
|
#include <unordered_map>
|
|
|
|
/**
|
|
* An identifier for a globalally unique message - a pair of the sending nodenum and the packet id assigned
|
|
* to that message
|
|
*/
|
|
struct GlobalPacketId {
|
|
NodeNum node;
|
|
PacketId id;
|
|
|
|
bool operator==(const GlobalPacketId &p) const { return node == p.node && id == p.id; }
|
|
|
|
explicit GlobalPacketId(const MeshPacket *p)
|
|
{
|
|
node = getFrom(p);
|
|
id = p->id;
|
|
}
|
|
|
|
GlobalPacketId(NodeNum _from, PacketId _id)
|
|
{
|
|
node = _from;
|
|
id = _id;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A packet queued for retransmission
|
|
*/
|
|
struct PendingPacket {
|
|
MeshPacket *packet;
|
|
|
|
/** The next time we should try to retransmit this packet */
|
|
uint32_t nextTxMsec = 0;
|
|
|
|
/** Starts at NUM_RETRANSMISSIONS -1(normally 3) and counts down. Once zero it will be removed from the list */
|
|
uint8_t numRetransmissions = 0;
|
|
|
|
/** True if we have started trying to find a route - for DSR usage
|
|
* While trying to find a route we don't actually send the data packet. We just leave it here pending until
|
|
* we have a route or we've failed to find one.
|
|
*/
|
|
bool wantRoute = false;
|
|
|
|
PendingPacket() {}
|
|
explicit PendingPacket(MeshPacket *p);
|
|
};
|
|
|
|
class GlobalPacketIdHashFunction
|
|
{
|
|
public:
|
|
size_t operator()(const GlobalPacketId &p) const { return (std::hash<NodeNum>()(p.node)) ^ (std::hash<PacketId>()(p.id)); }
|
|
};
|
|
|
|
/**
|
|
* This is a mixin that extends Router with the ability to do (one hop only) reliable message sends.
|
|
*/
|
|
class ReliableRouter : public FloodingRouter
|
|
{
|
|
private:
|
|
std::unordered_map<GlobalPacketId, PendingPacket, GlobalPacketIdHashFunction> pending;
|
|
|
|
public:
|
|
/**
|
|
* Constructor
|
|
*
|
|
*/
|
|
// ReliableRouter();
|
|
|
|
/**
|
|
* Send a packet on a suitable interface. This routine will
|
|
* later free() the packet to pool. This routine is not allowed to stall.
|
|
* If the txmit queue is full it might return an error
|
|
*/
|
|
virtual ErrorCode send(MeshPacket *p) override;
|
|
|
|
/** Do our retransmission handling */
|
|
virtual int32_t runOnce() override
|
|
{
|
|
// Note: We must doRetransmissions FIRST, because it might queue up work for the base class runOnce implementation
|
|
auto d = doRetransmissions();
|
|
|
|
int32_t r = FloodingRouter::runOnce();
|
|
|
|
return min(d, r);
|
|
}
|
|
|
|
protected:
|
|
/**
|
|
* Look for acks/naks or someone retransmitting us
|
|
*/
|
|
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override;
|
|
|
|
/**
|
|
* Try to find the pending packet record for this ID (or NULL if not found)
|
|
*/
|
|
PendingPacket *findPendingPacket(NodeNum from, PacketId id) { return findPendingPacket(GlobalPacketId(from, id)); }
|
|
PendingPacket *findPendingPacket(GlobalPacketId p);
|
|
|
|
/**
|
|
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
|
*/
|
|
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
|
|
|
/**
|
|
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
|
*/
|
|
PendingPacket *startRetransmission(MeshPacket *p);
|
|
|
|
private:
|
|
/**
|
|
* Stop any retransmissions we are doing of the specified node/packet ID pair
|
|
*
|
|
* @return true if we found and removed a transmission with this ID
|
|
*/
|
|
bool stopRetransmission(NodeNum from, PacketId id);
|
|
bool stopRetransmission(GlobalPacketId p);
|
|
|
|
/**
|
|
* Do any retransmissions that are scheduled (FIXME - for the time being called from loop)
|
|
*
|
|
* @return the number of msecs until our next retransmission or MAXINT if none scheduled
|
|
*/
|
|
int32_t doRetransmissions();
|
|
|
|
void setNextTx(PendingPacket *pending);
|
|
};
|