From 57f5346427c25a71493b78761ed052572a0a8658 Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Tue, 23 Jun 2026 23:37:30 +0200 Subject: [PATCH] refactor: rename Geo Alert feature to Locator Pure rename, no behavior change: GeoAlertScreen -> LocatorScreen (file + class), NodePrefs geo_alert_* fields -> locator_*, UITask engine functions (evaluateGeoAlert/fireGeoAlert/geoAlertDistance/geoProximityBeeper) and state -> evaluateLocator/fireLocator/locatorDistance/locatorProximityBeeper, Tools menu entry and screen header text -> "Locator", plus matching docs/README updates. NodePrefs field renames don't affect on-disk layout (DataStore serializes by position, not name). Co-Authored-By: Claude Sonnet 4.6 --- README.md | 4 +- .../tools_screen/tools_screen.md | 6 +- examples/companion_radio/DataStore.cpp | 60 ++++++------- examples/companion_radio/LiveTrack.h | 2 +- examples/companion_radio/NodePrefs.h | 46 +++++----- .../{GeoAlertScreen.h => LocatorScreen.h} | 64 ++++++------- examples/companion_radio/ui-new/ToolsScreen.h | 6 +- examples/companion_radio/ui-new/UITask.cpp | 90 +++++++++---------- examples/companion_radio/ui-new/UITask.h | 32 +++---- 9 files changed, 155 insertions(+), 155 deletions(-) rename examples/companion_radio/ui-new/{GeoAlertScreen.h => LocatorScreen.h} (80%) diff --git a/README.md b/README.md index fcd1350f..7929fc70 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ All firmware files are published on the [releases page](https://github.com/Marek - [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) — lock the device to prevent accidental keypresses, with a lock screen showing time and sensor data -- [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) — GPS trail & waypoints, compass, nearby nodes (with ping & navigate), ringtone editor, auto-reply bot, auto-advert, live location sharing, geo-alert, diagnostics, repeater +- [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) — GPS trail & waypoints, compass, nearby nodes (with ping & navigate), ringtone editor, auto-reply bot, auto-advert, live location sharing, locator, diagnostics, repeater - **Battery saving (radio)** — two optional, independent toggles under Settings › Radio: - **Pwr save** — hardware duty-cycle receive (SX126x `SetRxDutyCycle`): the radio cycles RX↔sleep on its own and wakes on a preamble, cutting average RX current with only a little added receive latency @@ -99,7 +99,7 @@ Updating to a newer version usually does not require erasing flash unless the re | [Clock Screen](./docs/solo_features/clock_screen/clock_screen.md) | Clock page, date, configurable data fields | | [Settings Screen](./docs/solo_features/settings_screen/settings_screen.md) | All settings sections with values and interactions | | [Screen Lock](./docs/solo_features/screen_lock/screen_lock.md) | Lock/unlock sequence, lock screen, auto-lock | -| [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) | GPS trail & waypoints, compass, navigation, nearby nodes, ringtone editor, auto-reply bot, auto-advert, live location sharing, geo-alert, diagnostics, repeater | +| [Tools Screen](./docs/solo_features/tools_screen/tools_screen.md) | GPS trail & waypoints, compass, navigation, nearby nodes, ringtone editor, auto-reply bot, auto-advert, live location sharing, locator, diagnostics, repeater | ### Upstream MeshCore diff --git a/docs/solo_features/tools_screen/tools_screen.md b/docs/solo_features/tools_screen/tools_screen.md index 1aa852e6..df857161 100644 --- a/docs/solo_features/tools_screen/tools_screen.md +++ b/docs/solo_features/tools_screen/tools_screen.md @@ -8,7 +8,7 @@ | :-----------------------: | :-----------------------: | | ![](./tls_scr_1_oled.png) | ![](./tls_scr_1_eink.png) | -The Tools screen is a hub for GPS trail recording, nearby node browsing, ringtone editing, auto-reply bot, auto-advert, live location sharing, geo-alert, compass, device diagnostics, and repeater mode. Tools are grouped into collapsible **Location** / **Comms** / **System** sections — the same fold-in-place model as Settings; Tools always opens folded back to the section list. Navigate with **UP/DOWN**, press **Enter** on a section header to expand or collapse it, or on a tool to open it. +The Tools screen is a hub for GPS trail recording, nearby node browsing, ringtone editing, auto-reply bot, auto-advert, live location sharing, locator, compass, device diagnostics, and repeater mode. Tools are grouped into collapsible **Location** / **Comms** / **System** sections — the same fold-in-place model as Settings; Tools always opens folded back to the section list. Navigate with **UP/DOWN**, press **Enter** on a section header to expand or collapse it, or on a tool to open it. --- @@ -225,7 +225,7 @@ The tool holds both directions of sharing in one flat list. Navigate with **UP/D --- -## Geo Alert +## Locator A single **geofence** that beeps and shows an alert when you cross **into** or **out of** a radius. The target can be a **saved waypoint** (a fixed place — "tell me when I'm back at camp") or a **live contact** (a person sharing their position via Live Share — "alert me when my friend gets near / falls behind"). A waypoint target is a **snapshot** (coordinate + label copied), so it keeps working even if you later edit or delete that waypoint; a contact target follows the person's latest shared position. @@ -246,7 +246,7 @@ Navigate with **UP/DOWN**, change a value with **LEFT/RIGHT** (or **Enter**); ** **Proximity beeper.** With **Beeper** on, the device also ticks while you're inside the radius and **shortens the gap between ticks the closer you get to the target** — slow near the edge, rapid near the centre — like a homing beeper guiding you to the exact spot. It's silent outside the radius. Because the beeper is its own opt-in toggle, turning it on **overrides the global buzzer mute** (**Settings › Sound › Buzzer**) — it's an explicit "I want to hear this". It works independently of the arrive/leave crossing alert (which does follow the mute), so you can use either or both. > [!TIP] -> Mark the spot first with **Tools › Trail → Hold Enter → Mark here** (or **+ Add by coords**), then set it as the Geo Alert target. +> Mark the spot first with **Tools › Trail → Hold Enter → Mark here** (or **+ Add by coords**), then set it as the Locator target. --- diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index f41011a9..9ab113e6 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -376,29 +376,29 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no if (_prefs.loc_share_move_idx >= NodePrefs::LOC_SHARE_MOVE_COUNT) _prefs.loc_share_move_idx = 1; if (_prefs.loc_share_interval_idx >= NodePrefs::LOC_SHARE_INTERVAL_COUNT) _prefs.loc_share_interval_idx = 1; if (_prefs.loc_share_heartbeat_idx >= NodePrefs::LOC_SHARE_HEARTBEAT_COUNT) _prefs.loc_share_heartbeat_idx = 0; - // → 0xC0DE0013: geo-alert + trail auto-pause. Pre-0x13 files leave stray bytes + // → 0xC0DE0013: locator + trail auto-pause. Pre-0x13 files leave stray bytes // here; clamp each back to its default so upgraders start with both off. - rd(&_prefs.geo_alert_enabled, sizeof(_prefs.geo_alert_enabled)); - rd(&_prefs.geo_alert_has_target, sizeof(_prefs.geo_alert_has_target)); - rd(&_prefs.geo_alert_radius_idx, sizeof(_prefs.geo_alert_radius_idx)); - rd(&_prefs.geo_alert_mode, sizeof(_prefs.geo_alert_mode)); - rd(&_prefs.geo_alert_lat_1e6, sizeof(_prefs.geo_alert_lat_1e6)); - rd(&_prefs.geo_alert_lon_1e6, sizeof(_prefs.geo_alert_lon_1e6)); - rd(_prefs.geo_alert_label, sizeof(_prefs.geo_alert_label)); + rd(&_prefs.locator_enabled, sizeof(_prefs.locator_enabled)); + rd(&_prefs.locator_has_target, sizeof(_prefs.locator_has_target)); + rd(&_prefs.locator_radius_idx, sizeof(_prefs.locator_radius_idx)); + rd(&_prefs.locator_mode, sizeof(_prefs.locator_mode)); + rd(&_prefs.locator_lat_1e6, sizeof(_prefs.locator_lat_1e6)); + rd(&_prefs.locator_lon_1e6, sizeof(_prefs.locator_lon_1e6)); + rd(_prefs.locator_label, sizeof(_prefs.locator_label)); rd(&_prefs.trail_autopause_idx, sizeof(_prefs.trail_autopause_idx)); - if (_prefs.geo_alert_enabled > 1) _prefs.geo_alert_enabled = 0; - if (_prefs.geo_alert_has_target > 1) _prefs.geo_alert_has_target = 0; - if (_prefs.geo_alert_radius_idx >= NodePrefs::GEO_ALERT_RADIUS_COUNT) _prefs.geo_alert_radius_idx = 1; - if (_prefs.geo_alert_mode >= NodePrefs::GEO_ALERT_MODE_COUNT) _prefs.geo_alert_mode = 0; + if (_prefs.locator_enabled > 1) _prefs.locator_enabled = 0; + if (_prefs.locator_has_target > 1) _prefs.locator_has_target = 0; + if (_prefs.locator_radius_idx >= NodePrefs::LOCATOR_RADIUS_COUNT) _prefs.locator_radius_idx = 1; + if (_prefs.locator_mode >= NodePrefs::LOCATOR_MODE_COUNT) _prefs.locator_mode = 0; if (_prefs.trail_autopause_idx >= NodePrefs::TRAIL_AUTOPAUSE_COUNT) _prefs.trail_autopause_idx = 0; - _prefs.geo_alert_label[sizeof(_prefs.geo_alert_label) - 1] = '\0'; - // → 0xC0DE0014: geo-alert proximity beeper. - rd(&_prefs.geo_alert_beeper, sizeof(_prefs.geo_alert_beeper)); - if (_prefs.geo_alert_beeper > 1) _prefs.geo_alert_beeper = 0; - // → 0xC0DE0015: geo-alert can target a live contact (kind + pubkey prefix). - rd(&_prefs.geo_alert_target_kind, sizeof(_prefs.geo_alert_target_kind)); - rd(_prefs.geo_alert_key, sizeof(_prefs.geo_alert_key)); - if (_prefs.geo_alert_target_kind > 1) _prefs.geo_alert_target_kind = 0; + _prefs.locator_label[sizeof(_prefs.locator_label) - 1] = '\0'; + // → 0xC0DE0014: locator proximity beeper. + rd(&_prefs.locator_beeper, sizeof(_prefs.locator_beeper)); + if (_prefs.locator_beeper > 1) _prefs.locator_beeper = 0; + // → 0xC0DE0015: locator can target a live contact (kind + pubkey prefix). + rd(&_prefs.locator_target_kind, sizeof(_prefs.locator_target_kind)); + rd(_prefs.locator_key, sizeof(_prefs.locator_key)); + if (_prefs.locator_target_kind > 1) _prefs.locator_target_kind = 0; // Pre-0x10 files leave stray sentinel bytes here, same as a never-configured // device. Either way there's no valid saved profile, so default to a profile // in the same band as the companion's own network (_prefs.freq, already read @@ -586,17 +586,17 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.loc_share_move_idx, sizeof(_prefs.loc_share_move_idx)); file.write((uint8_t *)&_prefs.loc_share_interval_idx, sizeof(_prefs.loc_share_interval_idx)); file.write((uint8_t *)&_prefs.loc_share_heartbeat_idx, sizeof(_prefs.loc_share_heartbeat_idx)); - file.write((uint8_t *)&_prefs.geo_alert_enabled, sizeof(_prefs.geo_alert_enabled)); - file.write((uint8_t *)&_prefs.geo_alert_has_target, sizeof(_prefs.geo_alert_has_target)); - file.write((uint8_t *)&_prefs.geo_alert_radius_idx, sizeof(_prefs.geo_alert_radius_idx)); - file.write((uint8_t *)&_prefs.geo_alert_mode, sizeof(_prefs.geo_alert_mode)); - file.write((uint8_t *)&_prefs.geo_alert_lat_1e6, sizeof(_prefs.geo_alert_lat_1e6)); - file.write((uint8_t *)&_prefs.geo_alert_lon_1e6, sizeof(_prefs.geo_alert_lon_1e6)); - file.write((uint8_t *)_prefs.geo_alert_label, sizeof(_prefs.geo_alert_label)); + file.write((uint8_t *)&_prefs.locator_enabled, sizeof(_prefs.locator_enabled)); + file.write((uint8_t *)&_prefs.locator_has_target, sizeof(_prefs.locator_has_target)); + file.write((uint8_t *)&_prefs.locator_radius_idx, sizeof(_prefs.locator_radius_idx)); + file.write((uint8_t *)&_prefs.locator_mode, sizeof(_prefs.locator_mode)); + file.write((uint8_t *)&_prefs.locator_lat_1e6, sizeof(_prefs.locator_lat_1e6)); + file.write((uint8_t *)&_prefs.locator_lon_1e6, sizeof(_prefs.locator_lon_1e6)); + file.write((uint8_t *)_prefs.locator_label, sizeof(_prefs.locator_label)); file.write((uint8_t *)&_prefs.trail_autopause_idx, sizeof(_prefs.trail_autopause_idx)); - file.write((uint8_t *)&_prefs.geo_alert_beeper, sizeof(_prefs.geo_alert_beeper)); - file.write((uint8_t *)&_prefs.geo_alert_target_kind, sizeof(_prefs.geo_alert_target_kind)); - file.write((uint8_t *)_prefs.geo_alert_key, sizeof(_prefs.geo_alert_key)); + file.write((uint8_t *)&_prefs.locator_beeper, sizeof(_prefs.locator_beeper)); + file.write((uint8_t *)&_prefs.locator_target_kind, sizeof(_prefs.locator_target_kind)); + file.write((uint8_t *)_prefs.locator_key, sizeof(_prefs.locator_key)); // Tail sentinel — must be last. See NodePrefs::SCHEMA_SENTINEL. uint32_t sentinel = NodePrefs::SCHEMA_SENTINEL; diff --git a/examples/companion_radio/LiveTrack.h b/examples/companion_radio/LiveTrack.h index 8301f5f5..3fe45e21 100644 --- a/examples/companion_radio/LiveTrack.h +++ b/examples/companion_radio/LiveTrack.h @@ -79,7 +79,7 @@ public: } // Latest active position for a verified (DM/pubkey) share, or null if that - // node hasn't shared recently. Used by the geo-alert engine to follow a + // node hasn't shared recently. Used by the locator engine to follow a // moving contact. const Entry* activeByKey(const uint8_t* key, uint32_t now) const { if (!key) return nullptr; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index c8bc3935..45b131b6 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -235,34 +235,34 @@ struct NodePrefs { // persisted to file uint8_t loc_share_interval_idx; // min send interval (index into locShareIntervalSecs) uint8_t loc_share_heartbeat_idx; // stationary heartbeat (index into locShareHeartbeatSecs) - // Geo-alert — a single geofence around a saved point. When enabled the device + // Locator — a single geofence around a saved point. When enabled the device // watches its own GPS fix and beeps + shows an alert when it crosses into // (arrive) or out of (leave) the radius. The target coordinate/label is a // snapshot of a chosen waypoint, so the alert survives the waypoint being - // edited or deleted. Configured from Tools › Geo Alert. - uint8_t geo_alert_enabled; // 0=off (default), 1=armed - uint8_t geo_alert_has_target; // 0=no target chosen yet, 1=target set - uint8_t geo_alert_radius_idx; // index into geoAlertRadiusMeters - uint8_t geo_alert_mode; // 0=arrive, 1=leave, 2=both - int32_t geo_alert_lat_1e6; // target latitude (1e6-scaled; last-known for a contact) - int32_t geo_alert_lon_1e6; // target longitude (1e6-scaled; last-known for a contact) - char geo_alert_label[12]; // target name for the alert text (WAYPOINT_LABEL_LEN) + // edited or deleted. Configured from Tools › Locator. + uint8_t locator_enabled; // 0=off (default), 1=armed + uint8_t locator_has_target; // 0=no target chosen yet, 1=target set + uint8_t locator_radius_idx; // index into locatorRadiusMeters + uint8_t locator_mode; // 0=arrive, 1=leave, 2=both + int32_t locator_lat_1e6; // target latitude (1e6-scaled; last-known for a contact) + int32_t locator_lon_1e6; // target longitude (1e6-scaled; last-known for a contact) + char locator_label[12]; // target name for the alert text (WAYPOINT_LABEL_LEN) // Target can be a static waypoint or a live contact: for a contact the engine // re-reads the latest [LOC] position each evaluation (keyed by pubkey prefix), // so the geofence follows a moving person ("alert when my friend is near"). - uint8_t geo_alert_target_kind; // 0=waypoint (static), 1=live contact - uint8_t geo_alert_key[6]; // contact pubkey prefix when target_kind==1 + uint8_t locator_target_kind; // 0=waypoint (static), 1=live contact + uint8_t locator_key[6]; // contact pubkey prefix when target_kind==1 // Trail auto-pause — when tracking, automatically freeze the trail (timer + // sampling) after the device has sat still for this long, and resume on the // next real movement. 0 = off. Index into trailAutoPauseSecs. uint8_t trail_autopause_idx; - // Geo-alert proximity beeper — when on (and the alert is armed with a target), + // Locator proximity beeper — when on (and the alert is armed with a target), // the device ticks while inside the radius and shortens the gap between ticks // the closer it gets to the target, like a homing beeper. Independent of the - // discrete arrive/leave alert (geo_alert_mode). - uint8_t geo_alert_beeper; // 0=off (default), 1=on + // discrete arrive/leave alert (locator_mode). + uint8_t locator_beeper; // 0=off (default), 1=on // Single source of truth for the live-share option tables (shared by the Map // UI labels and the auto-send engine in UITask). @@ -282,17 +282,17 @@ struct NodePrefs { // persisted to file return H[idx < LOC_SHARE_HEARTBEAT_COUNT ? idx : 0]; } - // Geo-alert option tables (shared by the Tools › Geo Alert UI labels and the + // Locator option tables (shared by the Tools › Locator UI labels and the // evaluation engine in UITask). - static const uint8_t GEO_ALERT_RADIUS_COUNT = 5; - static uint16_t geoAlertRadiusMeters(uint8_t idx) { - static const uint16_t R[GEO_ALERT_RADIUS_COUNT] = { 50, 100, 250, 500, 1000 }; - return R[idx < GEO_ALERT_RADIUS_COUNT ? idx : 1]; + static const uint8_t LOCATOR_RADIUS_COUNT = 5; + static uint16_t locatorRadiusMeters(uint8_t idx) { + static const uint16_t R[LOCATOR_RADIUS_COUNT] = { 50, 100, 250, 500, 1000 }; + return R[idx < LOCATOR_RADIUS_COUNT ? idx : 1]; } - static const uint8_t GEO_ALERT_MODE_COUNT = 3; // 0=arrive, 1=leave, 2=both - static const char* geoAlertModeLabel(uint8_t m) { - static const char* L[GEO_ALERT_MODE_COUNT] = { "Arrive", "Leave", "Both" }; - return L[m < GEO_ALERT_MODE_COUNT ? m : 0]; + static const uint8_t LOCATOR_MODE_COUNT = 3; // 0=arrive, 1=leave, 2=both + static const char* locatorModeLabel(uint8_t m) { + static const char* L[LOCATOR_MODE_COUNT] = { "Arrive", "Leave", "Both" }; + return L[m < LOCATOR_MODE_COUNT ? m : 0]; } // Trail auto-pause delays (seconds). 0 = off. diff --git a/examples/companion_radio/ui-new/GeoAlertScreen.h b/examples/companion_radio/ui-new/LocatorScreen.h similarity index 80% rename from examples/companion_radio/ui-new/GeoAlertScreen.h rename to examples/companion_radio/ui-new/LocatorScreen.h index a82af229..717e2b34 100644 --- a/examples/companion_radio/ui-new/GeoAlertScreen.h +++ b/examples/companion_radio/ui-new/LocatorScreen.h @@ -1,11 +1,11 @@ #pragma once -// Geo-alert config tool. Tools › Geo Alert. +// Locator config tool. Tools › Locator. // A single geofence whose target is either a saved waypoint (a place) or a // person — a favourite/contact or a live [LOC] sender, keyed by pubkey prefix. // When armed the device beeps / alerts as it crosses into (arrive/near) or out // of (leave/away) the radius. A waypoint target is snapshotted (coord + label); // a person target follows their latest shared position. The crossing engine -// lives in UITask::evaluateGeoAlert(). The Target row's Enter opens a picker +// lives in UITask::evaluateLocator(). The Target row's Enter opens a picker // (favourites first, then active live senders, then waypoints); LEFT/RIGHT // quick-cycles the same set. // Included by UITask.cpp after LiveShareScreen.h. @@ -15,7 +15,7 @@ #include "../LiveTrack.h" #include "icons.h" // drawList (shared scrolling-list helper) -class GeoAlertScreen : public UIScreen { +class LocatorScreen : public UIScreen { UITask* _task; NodePrefs* _prefs; bool _dirty = false; @@ -46,36 +46,36 @@ class GeoAlertScreen : public UIScreen { } public: - GeoAlertScreen(UITask* task, NodePrefs* prefs) : _task(task), _prefs(prefs) {} + LocatorScreen(UITask* task, NodePrefs* prefs) : _task(task), _prefs(prefs) {} void enter() { _dirty = false; _sel = 0; _scroll = 0; _picking = false; } void valueLabel(Kind k, char* buf, int n) { switch (k) { case K_ENABLE: - snprintf(buf, n, "%s", (_prefs && _prefs->geo_alert_enabled) ? "ON" : "OFF"); + snprintf(buf, n, "%s", (_prefs && _prefs->locator_enabled) ? "ON" : "OFF"); break; case K_TARGET: - if (_prefs && _prefs->geo_alert_has_target) { - const char* nm = _prefs->geo_alert_label[0] ? _prefs->geo_alert_label : "(unnamed)"; + if (_prefs && _prefs->locator_has_target) { + const char* nm = _prefs->locator_label[0] ? _prefs->locator_label : "(unnamed)"; // '@' prefix marks a live contact target (a moving person) vs a waypoint. - if (_prefs->geo_alert_target_kind == 1) snprintf(buf, n, "@%s", nm); + if (_prefs->locator_target_kind == 1) snprintf(buf, n, "@%s", nm); else snprintf(buf, n, "%s", nm); } else { snprintf(buf, n, "none"); } break; case K_RADIUS: { - uint16_t r = NodePrefs::geoAlertRadiusMeters(_prefs ? _prefs->geo_alert_radius_idx : 1); + uint16_t r = NodePrefs::locatorRadiusMeters(_prefs ? _prefs->locator_radius_idx : 1); if (r < 1000) snprintf(buf, n, "%um", (unsigned)r); else snprintf(buf, n, "%.1fkm", r / 1000.0f); break; } case K_MODE: - snprintf(buf, n, "%s", NodePrefs::geoAlertModeLabel(_prefs ? _prefs->geo_alert_mode : 0)); + snprintf(buf, n, "%s", NodePrefs::locatorModeLabel(_prefs ? _prefs->locator_mode : 0)); break; case K_BEEPER: - snprintf(buf, n, "%s", (_prefs && _prefs->geo_alert_beeper) ? "ON" : "OFF"); + snprintf(buf, n, "%s", (_prefs && _prefs->locator_beeper) ? "ON" : "OFF"); break; default: buf[0] = '\0'; } @@ -85,7 +85,7 @@ public: display.setTextSize(1); display.setColor(DisplayDriver::LIGHT); if (_picking) { renderPicker(display); return 400; } - display.drawCenteredHeader("GEO ALERT"); + display.drawCenteredHeader("LOCATOR"); const int valx = display.width() / 2 + 6; drawList(display, ROW_COUNT, _sel, _scroll, [&](int i, int y, bool sel, int reserve) { @@ -106,8 +106,8 @@ public: if (!_prefs) return; switch (rows(_sel).kind) { case K_ENABLE: - _prefs->geo_alert_enabled ^= 1; - if (_prefs->geo_alert_enabled && !_prefs->geo_alert_has_target) + _prefs->locator_enabled ^= 1; + if (_prefs->locator_enabled && !_prefs->locator_has_target) _task->showAlert("Pick a target", 1200); _dirty = true; break; @@ -115,23 +115,23 @@ public: cycleTarget(dir); break; case K_RADIUS: - _prefs->geo_alert_radius_idx = (uint8_t)((_prefs->geo_alert_radius_idx - + (dir >= 0 ? 1 : NodePrefs::GEO_ALERT_RADIUS_COUNT - 1)) % NodePrefs::GEO_ALERT_RADIUS_COUNT); + _prefs->locator_radius_idx = (uint8_t)((_prefs->locator_radius_idx + + (dir >= 0 ? 1 : NodePrefs::LOCATOR_RADIUS_COUNT - 1)) % NodePrefs::LOCATOR_RADIUS_COUNT); _dirty = true; break; case K_MODE: - _prefs->geo_alert_mode = (uint8_t)((_prefs->geo_alert_mode - + (dir >= 0 ? 1 : NodePrefs::GEO_ALERT_MODE_COUNT - 1)) % NodePrefs::GEO_ALERT_MODE_COUNT); + _prefs->locator_mode = (uint8_t)((_prefs->locator_mode + + (dir >= 0 ? 1 : NodePrefs::LOCATOR_MODE_COUNT - 1)) % NodePrefs::LOCATOR_MODE_COUNT); _dirty = true; break; case K_BEEPER: - _prefs->geo_alert_beeper ^= 1; + _prefs->locator_beeper ^= 1; _dirty = true; break; } // Re-seed the crossing engine after any change so editing the target/radius // while armed can't fire a stale arrive/leave before the screen is closed. - _task->resetGeoAlert(); + _task->resetLocator(); } // Build the selectable target set into _targets: favourites first (the quick @@ -179,25 +179,25 @@ public: // Index of the currently-configured target within _targets, or -1. int currentTargetIndex() const { for (int i = 0; i < _target_n; i++) { - if (_targets[i].kind == 1 && _prefs->geo_alert_target_kind == 1) { - if (memcmp(_targets[i].key, _prefs->geo_alert_key, 6) == 0) return i; - } else if (_targets[i].kind == 0 && _prefs->geo_alert_target_kind == 0) { - if (_targets[i].lat == _prefs->geo_alert_lat_1e6 && - _targets[i].lon == _prefs->geo_alert_lon_1e6) return i; + if (_targets[i].kind == 1 && _prefs->locator_target_kind == 1) { + if (memcmp(_targets[i].key, _prefs->locator_key, 6) == 0) return i; + } else if (_targets[i].kind == 0 && _prefs->locator_target_kind == 0) { + if (_targets[i].lat == _prefs->locator_lat_1e6 && + _targets[i].lon == _prefs->locator_lon_1e6) return i; } } return -1; } void applyTarget(const Target& t) { - _prefs->geo_alert_target_kind = t.kind; - if (t.kind == 1) memcpy(_prefs->geo_alert_key, t.key, 6); - _prefs->geo_alert_lat_1e6 = t.lat; - _prefs->geo_alert_lon_1e6 = t.lon; - snprintf(_prefs->geo_alert_label, sizeof(_prefs->geo_alert_label), "%s", t.name); - _prefs->geo_alert_has_target = 1; + _prefs->locator_target_kind = t.kind; + if (t.kind == 1) memcpy(_prefs->locator_key, t.key, 6); + _prefs->locator_lat_1e6 = t.lat; + _prefs->locator_lon_1e6 = t.lon; + snprintf(_prefs->locator_label, sizeof(_prefs->locator_label), "%s", t.name); + _prefs->locator_has_target = 1; _dirty = true; - _task->resetGeoAlert(); + _task->resetLocator(); } // LEFT/RIGHT quick-cycle over the same set the picker shows. diff --git a/examples/companion_radio/ui-new/ToolsScreen.h b/examples/companion_radio/ui-new/ToolsScreen.h index 9d89d9b8..3fd06b38 100644 --- a/examples/companion_radio/ui-new/ToolsScreen.h +++ b/examples/companion_radio/ui-new/ToolsScreen.h @@ -13,7 +13,7 @@ class ToolsScreen : public UIScreen { UITask* _task; enum Action { - ACT_NEARBY, ACT_LIVESHARE, ACT_TRAIL, ACT_GEOALERT, ACT_COMPASS, + ACT_NEARBY, ACT_LIVESHARE, ACT_TRAIL, ACT_LOCATOR, ACT_COMPASS, ACT_BOT, ACT_AUTOADVERT, ACT_REPEATER, ACT_RINGTONE, ACT_DIAGNOSTICS }; @@ -44,7 +44,7 @@ class ToolsScreen : public UIScreen { case ACT_NEARBY: _task->gotoNearbyScreen(); break; case ACT_LIVESHARE: _task->gotoLiveShareScreen(); break; case ACT_TRAIL: _task->gotoTrailScreen(); break; - case ACT_GEOALERT: _task->gotoGeoAlertScreen(); break; + case ACT_LOCATOR: _task->gotoLocatorScreen(); break; case ACT_COMPASS: _task->gotoCompassScreen(); break; case ACT_BOT: _task->gotoBotScreen(); break; case ACT_AUTOADVERT: _task->gotoAutoAdvertScreen(); break; @@ -113,7 +113,7 @@ const ToolsScreen::Tool ToolsScreen::LOCATION_TOOLS[] = { { "Nearby Nodes", &ICON_MAP_CONTACT, ACT_NEARBY }, { "Live Share", &ICON_ADVERT, ACT_LIVESHARE }, { "Trail", &ICON_TRAIL, ACT_TRAIL }, - { "Geo Alert", &ICON_MAP_WAYPOINT, ACT_GEOALERT }, + { "Locator", &ICON_MAP_WAYPOINT, ACT_LOCATOR }, { "Compass", &ICON_MAP_NORTH, ACT_COMPASS }, }; const ToolsScreen::Tool ToolsScreen::COMMS_TOOLS[] = { diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 06deba3c..3a9fc11b 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -124,7 +124,7 @@ static const int QUICK_MSGS_MAX = 10; #include "DashboardConfigScreen.h" #include "AutoAdvertScreen.h" #include "LiveShareScreen.h" -#include "GeoAlertScreen.h" +#include "LocatorScreen.h" #include "TrailScreen.h" #include "CompassScreen.h" #include "DiagnosticsScreen.h" @@ -1423,7 +1423,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no dashboard_config = new DashboardConfigScreen(this, node_prefs); auto_advert_screen = new AutoAdvertScreen(this, node_prefs); live_share_screen = new LiveShareScreen(this, node_prefs); - geo_alert_screen = new GeoAlertScreen(this, node_prefs); + locator_screen = new LocatorScreen(this, node_prefs); trail_screen = new TrailScreen(this, &_trail); compass_screen = new CompassScreen(this); diag_screen = new DiagnosticsScreen(this); @@ -1494,9 +1494,9 @@ void UITask::gotoLiveShareScreen() { setCurrScreen(live_share_screen); } -void UITask::gotoGeoAlertScreen() { - ((GeoAlertScreen*)geo_alert_screen)->enter(); - setCurrScreen(geo_alert_screen); +void UITask::gotoLocatorScreen() { + ((LocatorScreen*)locator_screen)->enter(); + setCurrScreen(locator_screen); } void UITask::gotoAutoAdvertScreen() { @@ -2240,70 +2240,70 @@ void UITask::loop() { } } - // Geo-alert — beep + alert when the device crosses into / out of the armed + // Locator — beep + alert when the device crosses into / out of the armed // geofence. Cheap; a few seconds of latency at the boundary is fine. - if ((int32_t)(millis() - _next_geo_alert_ms) >= 0) { - _next_geo_alert_ms = millis() + 3000UL; - evaluateGeoAlert(); + if ((int32_t)(millis() - _next_locator_ms) >= 0) { + _next_locator_ms = millis() + 3000UL; + evaluateLocator(); } - // Geo-alert proximity beeper — ticks faster the closer to the target. Runs on + // Locator proximity beeper — ticks faster the closer to the target. Runs on // its own short cadence (the crossing check above is too coarse for this). - geoProximityBeeper(); + locatorProximityBeeper(); } // Evaluate the single geofence against the current GPS fix. Crossing the radius -// fires fireGeoAlert() according to the configured mode; a hysteresis band on +// fires fireLocator() according to the configured mode; a hysteresis band on // the "leave" edge stops it chattering at the boundary, and the first reading // after arming only seeds the inside/outside state (no spurious alert). -// Distance (m) from the current GPS fix to the geo-alert target, plus the +// Distance (m) from the current GPS fix to the locator target, plus the // configured radius (m). Returns false when no target is set or there's no fix // — the single place the target-distance maths lives, shared by the crossing // evaluator and the proximity beeper. -bool UITask::geoAlertDistance(float& dist_m, float& radius_m) const { - if (!_node_prefs || !_node_prefs->geo_alert_has_target) return false; +bool UITask::locatorDistance(float& dist_m, float& radius_m) const { + if (!_node_prefs || !_node_prefs->locator_has_target) return false; int32_t tlat, tlon; - if (_node_prefs->geo_alert_target_kind == 1) { + if (_node_prefs->locator_target_kind == 1) { // Live contact: follow the latest [LOC] position. No recent share → no // distance to evaluate (engine waits rather than using a stale fix). const LiveTrackStore::Entry* e = - _livetrack.activeByKey(_node_prefs->geo_alert_key, (uint32_t)rtc_clock.getCurrentTime()); + _livetrack.activeByKey(_node_prefs->locator_key, (uint32_t)rtc_clock.getCurrentTime()); if (!e) return false; tlat = e->lat_1e6; tlon = e->lon_1e6; } else { - tlat = _node_prefs->geo_alert_lat_1e6; tlon = _node_prefs->geo_alert_lon_1e6; + tlat = _node_prefs->locator_lat_1e6; tlon = _node_prefs->locator_lon_1e6; } int32_t lat, lon; if (!currentLocation(lat, lon)) return false; dist_m = geo::haversineKm(lat, lon, tlat, tlon) * 1000.0f; - radius_m = (float)NodePrefs::geoAlertRadiusMeters(_node_prefs->geo_alert_radius_idx); + radius_m = (float)NodePrefs::locatorRadiusMeters(_node_prefs->locator_radius_idx); return true; } -void UITask::evaluateGeoAlert() { - if (!_node_prefs || !_node_prefs->geo_alert_enabled || !_node_prefs->geo_alert_has_target) { - _geo_alert_known = false; +void UITask::evaluateLocator() { + if (!_node_prefs || !_node_prefs->locator_enabled || !_node_prefs->locator_has_target) { + _locator_known = false; return; } float dist, r; - if (!geoAlertDistance(dist, r)) return; // armed but no fix yet — keep state + if (!locatorDistance(dist, r)) return; // armed but no fix yet — keep state bool inside; - if (!_geo_alert_known) inside = dist <= r; // seed state - else if (_geo_alert_inside) inside = dist <= r * 1.25f; // leave past band + if (!_locator_known) inside = dist <= r; // seed state + else if (_locator_inside) inside = dist <= r * 1.25f; // leave past band else inside = dist <= r; // arrive at edge - if (_geo_alert_known && inside != _geo_alert_inside) { - uint8_t mode = _node_prefs->geo_alert_mode; // 0=arrive,1=leave,2=both + if (_locator_known && inside != _locator_inside) { + uint8_t mode = _node_prefs->locator_mode; // 0=arrive,1=leave,2=both bool fire = inside ? (mode == 0 || mode == 2) : (mode == 1 || mode == 2); - if (fire) fireGeoAlert(inside); + if (fire) fireLocator(inside); } - _geo_alert_inside = inside; - _geo_alert_known = true; + _locator_inside = inside; + _locator_known = true; } -void UITask::fireGeoAlert(bool arrived) { - const char* lbl = _node_prefs->geo_alert_label[0] ? _node_prefs->geo_alert_label : "target"; - bool person = _node_prefs->geo_alert_target_kind == 1; +void UITask::fireLocator(bool arrived) { + const char* lbl = _node_prefs->locator_label[0] ? _node_prefs->locator_label : "target"; + bool person = _node_prefs->locator_target_kind == 1; char msg[40]; // "Near/Away" reads naturally for a moving person; "Arrived/Left" for a place. snprintf(msg, sizeof(msg), @@ -2311,37 +2311,37 @@ void UITask::fireGeoAlert(bool arrived) { : (person ? "Away: %s" : "Left: %s"), lbl); showAlert(msg, 3000); if (!isBuzzerQuiet()) - playMelody(arrived ? "geoarr:d=8,o=6,b=140:c,e,g" : "geolv:d=8,o=6,b=140:g,e,c"); + playMelody(arrived ? "locarr:d=8,o=6,b=140:c,e,g" : "loclv:d=8,o=6,b=140:g,e,c"); } // Homing beeper: while armed with a target and inside the radius, emit a short // tick whose interval shrinks linearly with distance — slow at the edge, rapid // near the centre. Polls distance a few times a second; silent outside the -// radius. The beeper has its own toggle (geo_alert_beeper), so turning it on is +// radius. The beeper has its own toggle (locator_beeper), so turning it on is // an explicit "I want to hear this" — it deliberately overrides the global // buzzer mute (playMelody → buzzer.playForced ignores the quiet flag). -void UITask::geoProximityBeeper() { +void UITask::locatorProximityBeeper() { static const uint32_t BEEP_MIN_MS = 150; // fastest cadence (at the target) static const uint32_t BEEP_MAX_MS = 2000; // slowest cadence (at the edge) - if (!_node_prefs || !_node_prefs->geo_alert_enabled || !_node_prefs->geo_alert_beeper - || !_node_prefs->geo_alert_has_target) { + if (!_node_prefs || !_node_prefs->locator_enabled || !_node_prefs->locator_beeper + || !_node_prefs->locator_has_target) { return; } - if ((int32_t)(millis() - _geo_beep_check_ms) < 0) return; - _geo_beep_check_ms = millis() + 250UL; + if ((int32_t)(millis() - _locator_beep_check_ms) < 0) return; + _locator_beep_check_ms = millis() + 250UL; float dist, r; - if (!geoAlertDistance(dist, r)) return; + if (!locatorDistance(dist, r)) return; if (dist > r) { // outside the zone: stay quiet, beep on re-entry - _geo_beep_next_ms = millis(); + _locator_beep_next_ms = millis(); return; } - if ((int32_t)(millis() - _geo_beep_next_ms) < 0) return; + if ((int32_t)(millis() - _locator_beep_next_ms) < 0) return; float frac = (r > 0) ? dist / r : 0; // 0 at centre, 1 at edge if (frac < 0) frac = 0; else if (frac > 1) frac = 1; uint32_t interval = BEEP_MIN_MS + (uint32_t)(frac * (BEEP_MAX_MS - BEEP_MIN_MS)); - playMelody("geop:d=32,o=7,b=200:c"); - _geo_beep_next_ms = millis() + interval; + playMelody("locp:d=32,o=7,b=200:c"); + _locator_beep_next_ms = millis() + interval; } // Insert a GPS fix into the course-over-ground ring, rejecting gross outliers diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index 84457e22..1e9d1498 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -79,7 +79,7 @@ class UITask : public AbstractUITask { UIScreen* dashboard_config; UIScreen* auto_advert_screen; UIScreen* live_share_screen; - UIScreen* geo_alert_screen; + UIScreen* locator_screen; UIScreen* trail_screen; UIScreen* compass_screen; UIScreen* diag_screen; @@ -106,20 +106,20 @@ class UITask : public AbstractUITask { bool _trail_pause_has_ref = false; uint32_t _trail_last_move_ms = 0; - // Geo-alert engine state. _geo_alert_known guards the first evaluation after + // Locator engine state. _locator_known guards the first evaluation after // arming (initialise inside/outside silently, fire only on later crossings). - uint32_t _next_geo_alert_ms = 0; - bool _geo_alert_inside = false; - bool _geo_alert_known = false; + uint32_t _next_locator_ms = 0; + bool _locator_inside = false; + bool _locator_known = false; // Proximity beeper: ticks while inside the radius, faster the nearer the - // target. _geo_beep_check_ms throttles the distance poll; _geo_beep_next_ms + // target. _locator_beep_check_ms throttles the distance poll; _locator_beep_next_ms // is when the next tick is due. - uint32_t _geo_beep_check_ms = 0; - uint32_t _geo_beep_next_ms = 0; - bool geoAlertDistance(float& dist_m, float& radius_m) const; - void evaluateGeoAlert(); - void fireGeoAlert(bool arrived); - void geoProximityBeeper(); + uint32_t _locator_beep_check_ms = 0; + uint32_t _locator_beep_next_ms = 0; + bool locatorDistance(float& dist_m, float& radius_m) const; + void evaluateLocator(); + void fireLocator(bool arrived); + void locatorProximityBeeper(); // Course-over-ground ring — a heading source independent of trail recording. // Filled from the same periodic GPS poll regardless of _trail.isActive(). @@ -189,11 +189,11 @@ public: void gotoDashboardConfig(); void gotoAutoAdvertScreen(); void gotoLiveShareScreen(); - void gotoGeoAlertScreen(); - // Re-arm the geo-alert state machine so the next evaluation initialises - // silently (called by the Geo Alert tool after the target/radius changes, + void gotoLocatorScreen(); + // Re-arm the locator state machine so the next evaluation initialises + // silently (called by the Locator tool after the target/radius changes, // so re-entering the zone doesn't fire on a stale inside/outside state). - void resetGeoAlert() { _geo_alert_known = false; } + void resetLocator() { _locator_known = false; } void gotoTrailScreen(); void gotoMapScreen(); // opens the Trail screen directly in its Map view void gotoCompassScreen();