Files
firmware/src/mesh/PacketHistory.h
2025-09-25 20:01:35 +02:00

79 lines
4.0 KiB
C++

#pragma once
#include "NodeDB.h"
// Number of relayers we keep track of. Use 6 to be efficient with memory alignment of PacketRecord to 20 bytes
#define NUM_RELAYERS 6
#define HOP_LIMIT_HIGHEST_MASK 0x07 // Bits 0-2
#define HOP_LIMIT_OUR_TX_MASK 0x38 // Bits 3-5
#define HOP_LIMIT_OUR_TX_SHIFT 3 // Bits 3-5
/**
* This is a mixin that adds a record of past packets we have seen
*/
class PacketHistory
{
private:
struct PacketRecord { // A record of a recent message broadcast, no need to be visible outside this class.
NodeNum sender;
PacketId id;
uint32_t rxTimeMsec; // Unix time in msecs - the time we received it, 0 means empty
uint8_t next_hop; // The next hop asked for this packet
uint8_t hop_limit; // bit 0-2: Highest hop limit observed for this packet,
// bit 3-5: our hop limit when we first transmitted it
uint8_t relayed_by[NUM_RELAYERS]; // Array of nodes that relayed this packet
}; // 4B + 4B + 4B + 1B + 1B + 6B = 20B
uint32_t recentPacketsCapacity =
0; // Can be set in constructor, no need to recompile. Used to allocate memory for mx_recentPackets.
PacketRecord *recentPackets = NULL; // Simple and fixed in size. Debloat.
/** Find a packet record in history.
* @param sender NodeNum
* @param id PacketId
* @return pointer to PacketRecord if found, NULL if not found */
PacketRecord *find(NodeNum sender, PacketId id);
/** Insert/Replace oldest PacketRecord in mx_recentPackets.
* @param r PacketRecord to insert or replace */
void insert(const PacketRecord &r); // Insert or replace a packet record in the history
/* Check if a certain node was a relayer of a packet in the history given iterator
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
* @return true if node was indeed a relayer, false if not */
bool wasRelayer(const uint8_t relayer, const PacketRecord &r, bool *wasSole = nullptr);
uint8_t getHighestHopLimit(PacketRecord &r);
void setHighestHopLimit(PacketRecord &r, uint8_t hopLimit);
uint8_t getOurTxHopLimit(PacketRecord &r);
void setOurTxHopLimit(PacketRecord &r, uint8_t hopLimit);
PacketHistory(const PacketHistory &); // non construction-copyable
PacketHistory &operator=(const PacketHistory &); // non copyable
public:
explicit PacketHistory(uint32_t size = -1); // Constructor with size parameter, default is PACKETHISTORY_MAX
~PacketHistory();
/**
* Update recentBroadcasts and return true if we have already seen this packet
*
* @param withUpdate if true and not found we add an entry to recentPackets
* @param wasFallback if not nullptr, packet will be checked for fallback to flooding and value will be set to true if so
* @param weWereNextHop if not nullptr, packet will be checked for us being the next hop and value will be set to true if so
* @param wasUpgraded if not nullptr, will be set to true if this packet has better hop_limit than previously seen
*/
bool wasSeenRecently(const meshtastic_MeshPacket *p, bool withUpdate = true, bool *wasFallback = nullptr,
bool *weWereNextHop = nullptr, bool *wasUpgraded = nullptr);
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
* @return true if node was indeed a relayer, false if not */
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole = nullptr);
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
// To check if the PacketHistory was initialized correctly by constructor
bool initOk(void) { return recentPackets != NULL && recentPacketsCapacity != 0; }
};