mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
fix: Use first hop of received path (near sender), not outbound path
Received message path: Sender → hop1 (near sender) → ... → Us Outbound path: Us → hop1 (near us) → ... → Contact Was using outbound path which placed contacts near OUR repeater. Now uses first hop of the received message path — the repeater nearest to the sender. Only triggers on received messages, not sends.
This commit is contained in:
@@ -1176,15 +1176,14 @@ class AppProvider with ChangeNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate location for contacts without GPS using RSSI + last-hop repeater
|
// Estimate location for contacts without GPS using received path
|
||||||
if (senderContact != null &&
|
if (senderContact != null &&
|
||||||
senderContact.displayLocation == null &&
|
senderContact.displayLocation == null &&
|
||||||
receptionDetailsSnapshot?.rssiDbm != null &&
|
receivedPathBytes != null &&
|
||||||
senderContact.routeHasPath &&
|
receivedPathBytes.isNotEmpty) {
|
||||||
senderContact.routeHopCount > 0) {
|
_estimateContactLocationFromReceivedPath(
|
||||||
_estimateContactLocationFromRssi(
|
|
||||||
contact: senderContact,
|
contact: senderContact,
|
||||||
rssiDbm: receptionDetailsSnapshot!.rssiDbm!,
|
receivedPathBytes: receivedPathBytes,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2016,40 +2015,51 @@ class AppProvider with ChangeNotifier {
|
|||||||
return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
|
return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Record RSSI observation from last-hop repeater for trilateration.
|
/// Estimate contact location from the received message path.
|
||||||
void _estimateContactLocationFromRssi({
|
///
|
||||||
|
/// When we receive a message, the path bytes describe how it traveled:
|
||||||
|
/// Sender → first_hop (near sender) → ... → last_hop (near us) → Us
|
||||||
|
///
|
||||||
|
/// The FIRST hop in the received path is the repeater nearest to the sender.
|
||||||
|
/// We don't have the actual RSSI between sender and that repeater, so we
|
||||||
|
/// use a conservative estimate to place them within typical LoRa range.
|
||||||
|
void _estimateContactLocationFromReceivedPath({
|
||||||
required Contact contact,
|
required Contact contact,
|
||||||
required int rssiDbm,
|
required List<int> receivedPathBytes,
|
||||||
}) {
|
}) {
|
||||||
final pathHopCount = contact.routeHopCount;
|
if (receivedPathBytes.isEmpty) return;
|
||||||
final pathHashSize = contact.routeHashSize;
|
|
||||||
if (pathHopCount <= 0 || pathHashSize <= 0) return;
|
|
||||||
|
|
||||||
final pathBytes = contact.routePathBytes;
|
// Infer hash size from the contact's known path encoding, or default to 1
|
||||||
if (pathBytes.length < pathHashSize) return;
|
final hashSize = contact.routeHasPath ? contact.routeHashSize : 1;
|
||||||
final firstHopHash = pathBytes
|
if (receivedPathBytes.length < hashSize) return;
|
||||||
.sublist(0, pathHashSize)
|
|
||||||
|
// First hop in received path = repeater nearest to sender
|
||||||
|
final firstHopHash = receivedPathBytes
|
||||||
|
.sublist(0, hashSize)
|
||||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||||
.join()
|
.join()
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
|
|
||||||
Contact? lastHopRepeater;
|
Contact? nearSenderRepeater;
|
||||||
for (final c in contactsProvider.contacts) {
|
for (final c in contactsProvider.contacts) {
|
||||||
if (c.publicKeyHex.toLowerCase().startsWith(firstHopHash) &&
|
if (c.publicKeyHex.toLowerCase().startsWith(firstHopHash) &&
|
||||||
c.displayLocation != null) {
|
c.displayLocation != null) {
|
||||||
lastHopRepeater = c;
|
nearSenderRepeater = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastHopRepeater == null) return;
|
if (nearSenderRepeater == null) return;
|
||||||
|
|
||||||
|
// We don't have the RSSI between sender and their repeater.
|
||||||
|
// Use -70 dBm as conservative estimate (~300m in open terrain).
|
||||||
|
const int estimatedRssi = -70;
|
||||||
|
|
||||||
// Record observation for trilateration
|
|
||||||
contactsProvider.addRssiObservation(
|
contactsProvider.addRssiObservation(
|
||||||
contactPublicKeyHex: contact.publicKeyHex,
|
contactPublicKeyHex: contact.publicKeyHex,
|
||||||
contactPublicKey: contact.publicKey,
|
contactPublicKey: contact.publicKey,
|
||||||
observation: RssiObservation(
|
observation: RssiObservation(
|
||||||
repeaterLocation: lastHopRepeater.displayLocation!,
|
repeaterLocation: nearSenderRepeater.displayLocation!,
|
||||||
rssiDbm: rssiDbm,
|
rssiDbm: estimatedRssi,
|
||||||
observedAt: DateTime.now(),
|
observedAt: DateTime.now(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user