mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-01 10:21:59 +00:00
Merge pull request #44 from pmow/feature/advert-loc-precision
feat(companion): advert position precision (privacy)
This commit is contained in:
@@ -334,6 +334,7 @@ static void sanitize(NodePrefs& p) {
|
||||
flag(p.lock_compact, 0);
|
||||
flag(p.ble_off, 0);
|
||||
if (p.msg_alert > NodePrefs::MSG_ALERT_OFF) p.msg_alert = NodePrefs::MSG_ALERT_NORMAL;
|
||||
if (p.advert_loc_prec >= NodePrefs::ADV_LOC_PREC_COUNT) p.advert_loc_prec = 0;
|
||||
if (!p.ch_scope_follow) {
|
||||
for (uint8_t i = 0; i < NodePrefs::MAX_SCOPED_CHANNELS; i++)
|
||||
if (p.ch_scope_idx[i] == 0) p.ch_scope_idx[i] = NodePrefs::CH_SCOPE_DEFAULT;
|
||||
|
||||
@@ -2356,11 +2356,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
}
|
||||
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
|
||||
mesh::Packet* pkt;
|
||||
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
|
||||
pkt = createSelfAdvert(_prefs.node_name);
|
||||
} else {
|
||||
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
|
||||
}
|
||||
pkt = createOwnAdvert();
|
||||
if (pkt) {
|
||||
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
|
||||
unsigned long delay_millis = 0;
|
||||
@@ -2435,11 +2431,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
if (len < 1 + PUB_KEY_SIZE) {
|
||||
// export SELF
|
||||
mesh::Packet* pkt;
|
||||
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
|
||||
pkt = createSelfAdvert(_prefs.node_name);
|
||||
} else {
|
||||
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
|
||||
}
|
||||
pkt = createOwnAdvert();
|
||||
if (pkt) {
|
||||
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
|
||||
|
||||
@@ -3525,22 +3517,40 @@ void MyMesh::loop() {
|
||||
}
|
||||
|
||||
if (_prefs.advert_auto_interval_sec > 0 && millisHasNowPassed(_next_auto_advert_ms)) {
|
||||
// The position only where Privacy lets adverts carry it, and once there is one.
|
||||
mesh::Packet* pkt = (_prefs.advert_loc_policy != ADVERT_LOC_NONE && (sensors.node_lat != 0 || sensors.node_lon != 0))
|
||||
? createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon)
|
||||
: createSelfAdvert(_prefs.node_name);
|
||||
// The position only where Privacy lets adverts carry it, at its precision.
|
||||
mesh::Packet* pkt = createOwnAdvert();
|
||||
if (pkt) sendZeroHop(pkt);
|
||||
_next_auto_advert_ms = futureMillis(_prefs.advert_auto_interval_sec * 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
// Grid step in degrees per precision level. 1 deg lat ~ 111 km, so 0.0009 ~ 100 m,
|
||||
// 0.0045 ~ 500 m, 0.009 ~ 1 km (longitude steps shrink toward the poles, so they're
|
||||
// never coarser).
|
||||
// Snapping to a fixed grid (rather than adding random jitter) means repeated
|
||||
// adverts from one spot always send the same value, so they can't be averaged.
|
||||
static const double ADV_LOC_PREC_STEPS[NodePrefs::ADV_LOC_PREC_COUNT] = { 0.0, 0.0009, 0.0045, 0.009 };
|
||||
|
||||
static double snapToGrid(double v, double step) {
|
||||
if (step <= 0.0) return v;
|
||||
return floor(v / step + 0.5) * step;
|
||||
}
|
||||
|
||||
mesh::Packet* MyMesh::createOwnAdvert() {
|
||||
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE
|
||||
|| (sensors.node_lat == 0 && sensors.node_lon == 0)) {
|
||||
return createSelfAdvert(_prefs.node_name);
|
||||
}
|
||||
const uint8_t prec = _prefs.advert_loc_prec;
|
||||
const double step = ADV_LOC_PREC_STEPS[prec < NodePrefs::ADV_LOC_PREC_COUNT ? prec : 0];
|
||||
return createSelfAdvert(_prefs.node_name,
|
||||
snapToGrid(sensors.node_lat, step),
|
||||
snapToGrid(sensors.node_lon, step));
|
||||
}
|
||||
|
||||
bool MyMesh::advert() {
|
||||
mesh::Packet* pkt;
|
||||
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
|
||||
pkt = createSelfAdvert(_prefs.node_name);
|
||||
} else {
|
||||
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
|
||||
}
|
||||
pkt = createOwnAdvert();
|
||||
if (pkt) {
|
||||
sendZeroHop(pkt);
|
||||
return true;
|
||||
@@ -3554,11 +3564,7 @@ bool MyMesh::advertFlood() {
|
||||
// (createSelfAdvert() + sendFloodScoped() with the default transport
|
||||
// scope key), for the on-device UI and the sim's test harness.
|
||||
mesh::Packet* pkt;
|
||||
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
|
||||
pkt = createSelfAdvert(_prefs.node_name);
|
||||
} else {
|
||||
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
|
||||
}
|
||||
pkt = createOwnAdvert();
|
||||
if (pkt) {
|
||||
TransportKey default_scope;
|
||||
memcpy(&default_scope.key, _prefs.default_scope_key, sizeof(default_scope.key));
|
||||
|
||||
@@ -208,6 +208,10 @@ public:
|
||||
void loop();
|
||||
void handleCmdFrame(size_t len);
|
||||
bool advert(); // zero-hop: only nodes in direct range hear it
|
||||
// Self-advert honouring advert_loc_policy, with the coordinates snapped to
|
||||
// advert_loc_prec's grid. Every advert this node builds goes through it
|
||||
// (manual, flood, auto, phone-app and contact export).
|
||||
mesh::Packet* createOwnAdvert();
|
||||
bool advertFlood(); // flooded (default scope), as the app's "Advert" with flood
|
||||
void sendNodeDiscoverReq();
|
||||
void enterCLIRescue();
|
||||
|
||||
@@ -538,6 +538,12 @@ struct NodePrefs { // persisted to file
|
||||
static const uint8_t MSG_ALERT_NORMAL = 0, MSG_ALERT_COMPACT = 1, MSG_ALERT_OFF = 2;
|
||||
uint8_t msg_alert;
|
||||
|
||||
// ── Advert position precision (Settings > Privacy) ─────────────────────
|
||||
// With "Position in adverts" on, the position is snapped to a fixed grid
|
||||
// (MyMesh::createOwnAdvert): 0 = exact, 1 = ~100 m, 2 = ~500 m, 3 = ~1 km.
|
||||
static const uint8_t ADV_LOC_PREC_COUNT = 4;
|
||||
uint8_t advert_loc_prec;
|
||||
|
||||
// Single source of truth for the live-share option tables (shared by the Map
|
||||
// UI labels and the auto-send engine in UITask).
|
||||
static const uint8_t LOC_SHARE_MOVE_COUNT = 4;
|
||||
|
||||
@@ -16,6 +16,7 @@ struct Key { const char* key; uint16_t offset; uint8_t bit; };
|
||||
#define KB(name, f, mask) { name, (uint16_t)offsetof(NodePrefs, f), mask }
|
||||
static const Key KEYS[] = {
|
||||
K("advert.interval", advert_auto_interval_sec), K("advert.loc", advert_loc_policy),
|
||||
K("advert.loc.precision", advert_loc_prec),
|
||||
K("telemetry.base", telemetry_mode_base), K("telemetry.loc", telemetry_mode_loc), K("telemetry.env", telemetry_mode_env),
|
||||
K("autoadd", manual_add_contacts), KB("autoadd.chat", autoadd_config, 0x02), KB("autoadd.repeater", autoadd_config, 0x04),
|
||||
KB("autoadd.room", autoadd_config, 0x08), KB("autoadd.sensor", autoadd_config, 0x10),
|
||||
|
||||
@@ -161,6 +161,10 @@ static void optAdvertScope(uint8_t v, char* b, int n, const NodePrefs&) {
|
||||
snprintf(b, n, "%s", v == ADVERT_SOUND_SCOPE_ZERO_HOP ? "Direct" : "All");
|
||||
}
|
||||
|
||||
static void optLocPrec(uint8_t v, char* b, int n, const NodePrefs&) {
|
||||
static const char* const L[NodePrefs::ADV_LOC_PREC_COUNT] = { "Exact", "~100 m", "~500 m", "~1 km" };
|
||||
snprintf(b, n, "%s", L[v < NodePrefs::ADV_LOC_PREC_COUNT ? v : 0]);
|
||||
}
|
||||
static void optTelemetry(uint8_t v, char* b, int n, const NodePrefs&) {
|
||||
static const char* const L[] = { "Nobody", "Allowed", "Everyone" }; // TELEM_MODE_*
|
||||
snprintf(b, n, "%s", L[v < 3 ? v : 0]);
|
||||
@@ -281,6 +285,8 @@ static const Setting ALL[] = {
|
||||
IDX("Advert sound for", "Direct: no repeaters", SEC_SOUND_FOR, advert_sound_scope, 2, optAdvertScope, nullptr),
|
||||
|
||||
SW("Position in adverts", "Your adverts carry your location", SEC_PRIVACY, advert_loc_policy, nullptr),
|
||||
IDX("Precision", "Rounded so it can't be pinpointed", SEC_PRIVACY, advert_loc_prec,
|
||||
NodePrefs::ADV_LOC_PREC_COUNT, optLocPrec, nullptr),
|
||||
// TELEM_MODE_*: "Allowed" is the contacts given that permission.
|
||||
IDX("Status", "Battery; the two below need it", SEC_TELEMETRY, telemetry_mode_base, 3, optTelemetry, nullptr),
|
||||
IDX("Location", nullptr, SEC_TELEMETRY, telemetry_mode_loc, 3, optTelemetry, nullptr),
|
||||
@@ -315,7 +321,7 @@ static const struct { uint16_t offset; const char* text; } SHORT_LABELS[] = {
|
||||
{ NP_OFF(notif_melody_ch), "Ch sound" }, { NP_OFF(notif_melody_ad), "AD sound" },
|
||||
{ NP_OFF(advert_sound_scope), "AD scope" },
|
||||
{ NP_OFF(manual_add_contacts), "Auto-add" }, { NP_OFF(autoadd_max_hops), " up to" },
|
||||
{ NP_OFF(advert_loc_policy), "Advert pos" }, { NP_OFF(telemetry_mode_base), "Ask status" },
|
||||
{ NP_OFF(advert_loc_policy), "Advert pos" }, { NP_OFF(advert_loc_prec), " precision" }, { NP_OFF(telemetry_mode_base), "Ask status" },
|
||||
{ NP_OFF(telemetry_mode_loc), "Ask loc" }, { NP_OFF(telemetry_mode_env), "Ask sens" },
|
||||
{ NP_OFF(path_hash_mode), "Hash size" }, { NP_OFF(multi_acks), "Double ACK" },
|
||||
{ NP_OFF(cad_enabled), "LBT (CAD)" }, { NP_OFF(interference_threshold), "Interf." },
|
||||
|
||||
Reference in New Issue
Block a user