From 1cbddc64dad747a5c2cca04d123fb12b268b44cb Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:31:18 +0200 Subject: [PATCH] gps fixes --- zephcore/adapters/gps/ZephyrGPSManager.cpp | 10 +++++ .../helpers/ui-joystick/joystick_ui_task.cpp | 24 ++++++++++++ .../helpers/ui-joystick/joystick_ui_task.h | 6 +++ .../helpers/ui-joystick/screens/system.cpp | 37 +++++++++++++++---- zephcore/helpers/ui/ui_mesh_actions.cpp | 19 ++++++++++ zephcore/helpers/ui/ui_mesh_actions.h | 3 ++ 6 files changed, 92 insertions(+), 7 deletions(-) diff --git a/zephcore/adapters/gps/ZephyrGPSManager.cpp b/zephcore/adapters/gps/ZephyrGPSManager.cpp index 88beca9..3b9a93f 100644 --- a/zephcore/adapters/gps/ZephyrGPSManager.cpp +++ b/zephcore/adapters/gps/ZephyrGPSManager.cpp @@ -1491,6 +1491,16 @@ void gps_enable(bool enable) gps_current_state = GPS_STATE_OFF; consecutive_good_fixes = 0; + /* Zero the stale satellite count so a re-enable doesn't briefly + * report a live fix (e.g. joystick UI showing "3D FIX") off old + * data before any new NMEA sentence arrives. lat/lon/valid are + * deliberately left alone — telemetry/UI "last known position" + * reads (gps_get_position/gps_load_position) intentionally survive + * an on/off toggle; only the live fix-quality indicator resets. */ + k_mutex_lock(&gps_mutex, K_FOREVER); + current_pos.satellites = 0; + k_mutex_unlock(&gps_mutex); + /* Clear first-fix flags so the next enable gets a fresh long * first-acquisition window again — the user explicitly toggled GPS * expecting it to try hard for a fix. */ diff --git a/zephcore/helpers/ui-joystick/joystick_ui_task.cpp b/zephcore/helpers/ui-joystick/joystick_ui_task.cpp index 034e564..15d0aec 100644 --- a/zephcore/helpers/ui-joystick/joystick_ui_task.cpp +++ b/zephcore/helpers/ui-joystick/joystick_ui_task.cpp @@ -916,6 +916,30 @@ void JoystickUITask::toggleGPS() mesh_gps_set_enabled(!gps_is_enabled()); } +uint32_t JoystickUITask::getGpsDutySec() const +{ + return gps_get_poll_interval_sec(); +} + +void JoystickUITask::adjustGpsDuty(int step) +{ + static const uint32_t kPresets[] = { + 0, 10, 30, 60, 120, 300, 600, 900, 1800, 3600, + 7200, 21600, 43200, 86400, 172800, 604800 + }; + const int kCount = (int)(sizeof(kPresets) / sizeof(kPresets[0])); + + uint32_t cur = gps_get_poll_interval_sec(); + int idx = kCount - 1; + for (int i = 0; i < kCount; i++) { + if (kPresets[i] >= cur) { idx = i; break; } + } + idx += step; + if (idx < 0) idx = 0; + if (idx >= kCount) idx = kCount - 1; + mesh_save_gps_duty_sec(kPresets[idx]); +} + void JoystickUITask::playCountdownAlarm() { #ifdef CONFIG_ZEPHCORE_UI_BUZZER diff --git a/zephcore/helpers/ui-joystick/joystick_ui_task.h b/zephcore/helpers/ui-joystick/joystick_ui_task.h index 5ea8127..afd7d87 100644 --- a/zephcore/helpers/ui-joystick/joystick_ui_task.h +++ b/zephcore/helpers/ui-joystick/joystick_ui_task.h @@ -104,6 +104,12 @@ public: bool isGPSAvailable() const; bool getGPSState() const; void toggleGPS(); + /* GPS duty-cycle interval, seconds (0 = always on). Steps through a fixed + * preset ladder (step = +1/-1) rather than raw seconds, since the valid + * range spans 0..604800 — a linear per-press delta would be unusable at + * either end. Applied live + persists to prefs. */ + uint32_t getGpsDutySec() const; + void adjustGpsDuty(int step); bool isSerialEnabled() const { return _ble_enabled; } void disableSerial(); void enableSerial(); diff --git a/zephcore/helpers/ui-joystick/screens/system.cpp b/zephcore/helpers/ui-joystick/screens/system.cpp index 349fccc..866bc05 100644 --- a/zephcore/helpers/ui-joystick/screens/system.cpp +++ b/zephcore/helpers/ui-joystick/screens/system.cpp @@ -722,13 +722,24 @@ int GPSSettingsScreen::render(JoystickDisplay &display) bool gps_enabled = _task->getGPSState(); - char gps_state_line[24]; + char top_line[24]; char satellites_line[32]; char lat_lon_line[40]; char speed_line[32]; - snprintf(gps_state_line, sizeof(gps_state_line), "GPS: %s", - gps_enabled ? "ON" : "OFF"); + /* Line 0 doubles as the GPS on/off toggle and the duty-cycle setting — + * the display only has room for 4 lines total (64px OLED), so rather + * than add a 5th line, _selected swaps what line 0 shows/does. */ + if (_selected == 0) { + snprintf(top_line, sizeof(top_line), "GPS: %s", gps_enabled ? "ON" : "OFF"); + } else { + uint32_t duty = _task->getGpsDutySec(); + if (duty == 0) { + snprintf(top_line, sizeof(top_line), "Duty: Always on"); + } else { + snprintf(top_line, sizeof(top_line), "Duty: %us", (unsigned)duty); + } + } bool has_fix = false; @@ -787,9 +798,9 @@ int GPSSettingsScreen::render(JoystickDisplay &display) } } - const char *lines[4] = { gps_state_line, satellites_line, lat_lon_line, speed_line }; + const char *lines[4] = { top_line, satellites_line, lat_lon_line, speed_line }; - renderScreenHeader(display, "GPS", 0, 1); + renderScreenHeader(display, "GPS", _selected, 2); display.setTextSize(1); int y = kContentY + 2; @@ -803,9 +814,21 @@ int GPSSettingsScreen::render(JoystickDisplay &display) bool GPSSettingsScreen::handleInput(char key) { + if (handleCommonListNavigation(key, _selected, 2)) return true; + if (key == KEY_LEFT || key == KEY_RIGHT) { + if (_selected == 1) { + _task->adjustGpsDuty(key == KEY_RIGHT ? 1 : -1); + return true; + } + return false; + } if (key == KEY_ENTER) { - _task->toggleGPS(); - _task->showAlert(_task->getGPSState() ? "GPS enabled" : "GPS disabled", 1000); + if (_selected == 0) { + _task->toggleGPS(); + _task->showAlert(_task->getGPSState() ? "GPS enabled" : "GPS disabled", 1000); + } else { + _task->adjustGpsDuty(1); + } return true; } if (key == KEY_CANCEL || key == KEY_HOME) { _task->gotoHomeScreen(); return true; } diff --git a/zephcore/helpers/ui/ui_mesh_actions.cpp b/zephcore/helpers/ui/ui_mesh_actions.cpp index 5663ebc..9129d62 100644 --- a/zephcore/helpers/ui/ui_mesh_actions.cpp +++ b/zephcore/helpers/ui/ui_mesh_actions.cpp @@ -43,6 +43,7 @@ LOG_MODULE_REGISTER(zephcore_ui_actions, CONFIG_ZEPHCORE_UI_ACTIONS_LOG_LEVEL); #define UI_ACTION_WAKE_ON_MSG_SAVE BIT(9) #define UI_ACTION_SCREEN_OFF_SAVE BIT(10) #define UI_ACTION_PATH_HASH_MODE_SAVE BIT(11) +#define UI_ACTION_GPS_DUTY_SAVE BIT(12) /* Module-local pointers, set by init */ static CompanionMesh *s_mesh; @@ -68,6 +69,7 @@ static atomic_t pending_brightness; static atomic_t pending_wake_on_msg; static atomic_t pending_screen_off_secs; static atomic_t pending_path_hash_mode; +static atomic_t pending_gps_duty_sec; extern "C" void ui_mesh_actions_init(struct k_event *mesh_events, uint32_t mesh_event_ui_action, @@ -151,6 +153,17 @@ extern "C" void mesh_save_path_hash_mode(uint8_t mode) k_event_post(s_mesh_events, s_mesh_event_ui_action); } +extern "C" void mesh_save_gps_duty_sec(uint32_t sec) +{ + /* Apply immediately (lightweight, no flash) — same split as mesh_gps_set_enabled. */ + gps_set_poll_interval_sec(sec); + + /* Defer the flash write (savePrefs) to mesh thread */ + atomic_set(&pending_gps_duty_sec, (atomic_val_t)sec); + atomic_or(&pending_ui_actions, UI_ACTION_GPS_DUTY_SAVE); + k_event_post(s_mesh_events, s_mesh_event_ui_action); +} + extern "C" void mesh_set_buzzer_quiet(bool quiet) { /* Defer the flash write (savePrefs) to mesh thread */ @@ -289,6 +302,12 @@ extern "C" void mesh_handle_ui_actions(void) need_save = true; } + if (actions & UI_ACTION_GPS_DUTY_SAVE) { + s_mesh->prefs.gps_interval = (uint32_t)atomic_get(&pending_gps_duty_sec); + LOG_INF("gps_interval=%u (button)", s_mesh->prefs.gps_interval); + need_save = true; + } + if (need_save || (actions & UI_ACTION_SAVE_RESTART)) { s_data_store->savePrefs(s_mesh->prefs); LOG_INF("prefs saved (button action)"); diff --git a/zephcore/helpers/ui/ui_mesh_actions.h b/zephcore/helpers/ui/ui_mesh_actions.h index 7f09cc4..922f30e 100644 --- a/zephcore/helpers/ui/ui_mesh_actions.h +++ b/zephcore/helpers/ui/ui_mesh_actions.h @@ -66,6 +66,9 @@ void mesh_set_wake_on_msg(bool enabled); void mesh_save_screen_off_secs(uint16_t secs); /* path_hash_mode: 0/1/2 → 1/2/3 bytes per hop appended to outbound flood path */ void mesh_save_path_hash_mode(uint8_t mode); +/* GPS duty-cycle interval in seconds (0 = always on). Applied live immediately + * (lightweight); the flash write is deferred to the mesh thread. */ +void mesh_save_gps_duty_sec(uint32_t sec); #ifdef __cplusplus }