Deterministic packets (#11014)
This commit is contained in:
+42
-12
@@ -1201,19 +1201,49 @@ void PhoneAPI::prefetchNodeInfos()
|
||||
onNowHasData(0);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/// Derive a stable id for a replayed satellite-DB record. Unchanged history replayed on
|
||||
/// every reconnect must not look like a new packet to the phone's history/dedup - the id
|
||||
/// only changes when the underlying data (its timestamp) actually changes.
|
||||
// `kind` only needs to distinguish the record types that can otherwise collide (e.g. device
|
||||
// vs. environment metrics both replay as TELEMETRY_APP with the same node/last_heard) - pass
|
||||
// the payload's own variant/port constant.
|
||||
uint32_t makeReplayPacketId(NodeNum num, uint32_t timestamp, uint32_t kind)
|
||||
{
|
||||
uint32_t h = num;
|
||||
h = h * 2654435761u + timestamp;
|
||||
h = h * 2654435761u + kind;
|
||||
return h ? h : 1; // some clients treat id 0 as "unset"
|
||||
}
|
||||
|
||||
/// Populate hop_start/hop_limit from the node's real last-known hop count (if any) so a
|
||||
/// replayed packet doesn't read as "heard directly" when it wasn't.
|
||||
void setReplayHopFields(meshtastic_MeshPacket &pkt, const meshtastic_NodeInfoLite *header)
|
||||
{
|
||||
uint8_t hopLimit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
uint8_t hopsAway = (header && header->has_hops_away) ? header->hops_away : 0;
|
||||
pkt.hop_start = hopLimit;
|
||||
pkt.hop_limit = hopsAway < hopLimit ? (uint8_t)(hopLimit - hopsAway) : 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
meshtastic_MeshPacket PhoneAPI::makeReplayPositionPacket(NodeNum num, const meshtastic_PositionLite &pos)
|
||||
{
|
||||
// Shape this exactly like a fresh live broadcast Position from the peer so the
|
||||
// phone runs it through its normal "live position broadcast" handler path.
|
||||
// to=ourNum would read as a DM-from-peer and never lands in node detail UI.
|
||||
meshtastic_MeshPacket pkt = meshtastic_MeshPacket_init_default;
|
||||
const meshtastic_NodeInfoLite *header = nodeDB->getMeshNode(num);
|
||||
pkt.from = num;
|
||||
pkt.to = NODENUM_BROADCAST;
|
||||
pkt.id = generatePacketId();
|
||||
pkt.rx_time = pos.time;
|
||||
// Stable per-node/per-fix id: replaying the same unchanged history on every
|
||||
// reconnect must not look like a brand new packet to the phone's history/dedup.
|
||||
pkt.id = makeReplayPacketId(num, pkt.rx_time, meshtastic_PortNum_POSITION_APP);
|
||||
pkt.channel = 0;
|
||||
pkt.hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
pkt.hop_start = pkt.hop_limit;
|
||||
pkt.rx_snr = header ? header->snr : 0;
|
||||
setReplayHopFields(pkt, header);
|
||||
pkt.priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
// Mark as if heard over the air, not internally generated
|
||||
pkt.transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA;
|
||||
@@ -1231,13 +1261,13 @@ meshtastic_MeshPacket PhoneAPI::makeReplayTelemetryPacket(NodeNum num, const mes
|
||||
meshtastic_MeshPacket pkt = meshtastic_MeshPacket_init_default;
|
||||
pkt.from = num;
|
||||
pkt.to = NODENUM_BROADCAST;
|
||||
pkt.id = generatePacketId();
|
||||
// No native timestamp on telemetry packets here; use last_heard.
|
||||
const meshtastic_NodeInfoLite *header = nodeDB->getMeshNode(num);
|
||||
pkt.rx_time = header ? header->last_heard : 0;
|
||||
pkt.id = makeReplayPacketId(num, pkt.rx_time, meshtastic_Telemetry_device_metrics_tag);
|
||||
pkt.channel = 0;
|
||||
pkt.hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
pkt.hop_start = pkt.hop_limit;
|
||||
pkt.rx_snr = header ? header->snr : 0;
|
||||
setReplayHopFields(pkt, header);
|
||||
pkt.priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
// Mark as if heard over the air, not internally generated - iOS client filters
|
||||
// TRANSPORT_INTERNAL packets out of broadcast peer state updates.
|
||||
@@ -1337,12 +1367,12 @@ meshtastic_MeshPacket PhoneAPI::makeReplayEnvironmentPacket(uint32_t num, const
|
||||
meshtastic_MeshPacket pkt = meshtastic_MeshPacket_init_default;
|
||||
pkt.from = num;
|
||||
pkt.to = NODENUM_BROADCAST;
|
||||
pkt.id = generatePacketId();
|
||||
const meshtastic_NodeInfoLite *header = nodeDB->getMeshNode(num);
|
||||
pkt.rx_time = header ? header->last_heard : 0;
|
||||
pkt.id = makeReplayPacketId(num, pkt.rx_time, meshtastic_Telemetry_environment_metrics_tag);
|
||||
pkt.channel = 0;
|
||||
pkt.hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
pkt.hop_start = pkt.hop_limit;
|
||||
pkt.rx_snr = header ? header->snr : 0;
|
||||
setReplayHopFields(pkt, header);
|
||||
pkt.priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
// Mark as if heard over the air, not internally generated - iOS client filters
|
||||
// TRANSPORT_INTERNAL packets out of broadcast peer state updates.
|
||||
@@ -1400,13 +1430,13 @@ meshtastic_MeshPacket PhoneAPI::makeReplayStatusPacket(uint32_t num, const mesht
|
||||
meshtastic_MeshPacket pkt = meshtastic_MeshPacket_init_default;
|
||||
pkt.from = num;
|
||||
pkt.to = NODENUM_BROADCAST;
|
||||
pkt.id = generatePacketId();
|
||||
// StatusMessage has no native timestamp; use last_heard.
|
||||
const meshtastic_NodeInfoLite *header = nodeDB->getMeshNode(num);
|
||||
pkt.rx_time = header ? header->last_heard : 0;
|
||||
pkt.id = makeReplayPacketId(num, pkt.rx_time, meshtastic_PortNum_NODE_STATUS_APP);
|
||||
pkt.channel = 0;
|
||||
pkt.hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
|
||||
pkt.hop_start = pkt.hop_limit;
|
||||
pkt.rx_snr = header ? header->snr : 0;
|
||||
setReplayHopFields(pkt, header);
|
||||
pkt.priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
// Mark as if heard over the air, not internally generated - client filters
|
||||
pkt.transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA;
|
||||
|
||||
Reference in New Issue
Block a user