first fix 5 min timeout for GPS to prevent battery drain

This commit is contained in:
liquidraver
2026-06-17 14:52:00 +02:00
parent 7b3716bd6a
commit 533a2a7e4e
2 changed files with 58 additions and 38 deletions
+13
View File
@@ -587,6 +587,19 @@ config ZEPHCORE_GPS_FIX_TIMEOUT_SEC
before the 3-consecutive-good-fix gate could promote. Only applies
to wake cycles after the first successful fix since enable.
config ZEPHCORE_GPS_FIRST_FIX_TIMEOUT_SEC
int "GPS first-acquisition timeout in seconds"
default 300
range 30 1800
help
Bounded window for the FIRST position fix after GPS is enabled
(cold start). Longer than the normal fix timeout because a cold
start may need to download almanac data. If no fix is acquired in
this window the node drops into the normal duty cycle anyway, so
the GPS can never stay powered indefinitely with no sky view.
Default 300s (5 minutes). Companion mode only; repeaters use a
fixed 5-minute time-sync window.
endmenu
menu "WiFi OTA Update"
+45 -38
View File
@@ -88,6 +88,7 @@ enum gps_state {
static enum gps_state gps_current_state = GPS_STATE_OFF;
static uint8_t consecutive_good_fixes = 0;
static bool first_fix_acquired = false; /* True after first 3-good-fix cycle since enable. Cleared on gps_enable(false) and at boot. */
static bool first_acquire_used = false; /* True once the one-time long cold-start window has ended (fix or timeout). Cleared on gps_enable(false) and at boot. */
static bool gps_time_synced = false; /* True after GPS syncs RTC. Starts false at boot (RTC reset),
* set true after 3 good fixes, cleared when GPS disabled. */
static int64_t last_fix_uptime_ms = 0; /* k_uptime when last validated fix was acquired */
@@ -98,8 +99,9 @@ static uint64_t standby_interval_ms = 0; /* How long standby lasts (for next-wak
#define GPS_MIN_SATELLITES 4 /* Minimum satellites for valid fix */
/* Runtime-configurable intervals, initialized from Kconfig defaults */
static uint32_t gps_acquire_timeout_ms = CONFIG_ZEPHCORE_GPS_FIX_TIMEOUT_SEC * 1000U;
static uint32_t gps_wake_interval_ms = CONFIG_ZEPHCORE_GPS_POLL_INTERVAL_SEC * 1000U;
static uint32_t gps_acquire_timeout_ms = CONFIG_ZEPHCORE_GPS_FIX_TIMEOUT_SEC * 1000U;
static uint32_t gps_first_fix_timeout_ms = CONFIG_ZEPHCORE_GPS_FIRST_FIX_TIMEOUT_SEC * 1000U;
static uint32_t gps_wake_interval_ms = CONFIG_ZEPHCORE_GPS_POLL_INTERVAL_SEC * 1000U;
/* Repeater mode intervals - GPS only for time sync */
#define GPS_REPEATER_SYNC_INTERVAL_MS (48ULL * 60 * 60 * 1000) /* 48 hours */
@@ -959,6 +961,25 @@ static void gps_software_wake(void)
}
#endif /* HAS_GPS_UART && !HAS_GPS_POWER_CONTROL && !HAS_GPS_POWER_REGULATOR */
/* Acquire-window timeout (ms) for the current phase.
* - Repeater: fixed 5-min time-sync window.
* - First acquisition after enable (cold start, no fix yet): a generous but
* bounded window so almanac download has time, without pinning the module
* on forever when there's no sky. Spent once (first_acquire_used set on the
* first standby), after which the node uses the normal duty cycle regardless
* of whether a fix was obtained.
* - All later windows: the normal (warm) acquire timeout. */
static uint32_t gps_acquire_window_ms(void)
{
if (gps_repeater_mode) {
return GPS_REPEATER_SYNC_TIMEOUT_MS;
}
if (!first_fix_acquired && !first_acquire_used) {
return gps_first_fix_timeout_ms;
}
return gps_acquire_timeout_ms;
}
/* Go to standby and schedule next wake.
* GPIO power control only — keep VRTC for warm start on T1000-E,
* FORCE_ON pin LOW for L76K hardware standby. */
@@ -974,6 +995,9 @@ static void gps_go_to_standby(void)
}
gps_current_state = GPS_STATE_STANDBY;
consecutive_good_fixes = 0;
/* The one-time long cold-start window (if any) is now spent — later
* wakes use the normal (warm) acquire timeout via gps_acquire_window_ms(). */
first_acquire_used = true;
/* Record standby timing for UI (next-wake calculation) */
standby_start_ms = k_uptime_get();
@@ -1023,16 +1047,11 @@ static void gps_start_acquiring(void)
gps_software_wake();
#endif
/* Start timeout timer */
if (gps_repeater_mode) {
/* Repeater mode: always use 5 min timeout for time sync */
k_work_schedule(&gps_timeout_work, K_MSEC(GPS_REPEATER_SYNC_TIMEOUT_MS));
} else if (first_fix_acquired) {
/* Companion mode: use short timeout after first fix acquired */
k_work_schedule(&gps_timeout_work, K_MSEC(gps_acquire_timeout_ms));
} else {
LOG_INF("GPS: First fix mode - no timeout");
}
/* Start timeout timer — every window is now bounded (the first
* cold-start window is just longer; see gps_acquire_window_ms). */
uint32_t timeout_ms = gps_acquire_window_ms();
LOG_INF("GPS: Acquire window %u s", timeout_ms / 1000U);
k_work_schedule(&gps_timeout_work, K_MSEC(timeout_ms));
}
/* Work handler: wake GPS for fix.
@@ -1396,12 +1415,10 @@ void gps_enable(bool enable)
* ~300ms to boot after GPIO power restore and calling it
* immediately deadlocks the main thread. */
/* No timeout for first fix after enable - wait as long as needed */
if (first_fix_acquired) {
k_work_schedule(&gps_timeout_work, K_MSEC(gps_acquire_timeout_ms));
} else {
LOG_INF("GPS: First fix mode - no timeout until first successful fix");
}
/* Bounded first-acquisition window, then the normal duty cycle */
uint32_t timeout_ms = gps_acquire_window_ms();
LOG_INF("GPS: Acquire window %u s", timeout_ms / 1000U);
k_work_schedule(&gps_timeout_work, K_MSEC(timeout_ms));
} else {
LOG_INF("GPS disabled - canceling timers and powering off");
@@ -1420,11 +1437,11 @@ void gps_enable(bool enable)
gps_current_state = GPS_STATE_OFF;
consecutive_good_fixes = 0;
/* Clear first-fix flag so the next enable gets the "no timeout"
* grace period again — in marginal signal, a 30120s timeout may
* never be enough, and the user explicitly toggled GPS expecting
* it to try hard for a fix. */
/* 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. */
first_fix_acquired = false;
first_acquire_used = false;
/* Clear time sync flag - time will drift, allow phone sync again */
gps_time_synced = false;
@@ -1574,22 +1591,12 @@ void gps_request_fresh_fix(void)
* telemetry request that arrives 25s into a 30s acquire window
* only has 5s left, which in marginal signal usually means the
* chip goes to standby before producing a fix the requester
* could use. Repeater mode uses its own 5min timeout; companion
* mode pre-first-fix has no timeout (nothing to reschedule). */
uint32_t timeout_ms = 0;
if (gps_repeater_mode) {
timeout_ms = GPS_REPEATER_SYNC_TIMEOUT_MS;
} else if (first_fix_acquired) {
timeout_ms = gps_acquire_timeout_ms;
}
if (timeout_ms > 0) {
LOG_INF("GPS: Fresh fix requested, extending acquire "
"timeout by %u ms", timeout_ms);
k_work_reschedule(&gps_timeout_work, K_MSEC(timeout_ms));
} else {
LOG_DBG("GPS: Fresh fix requested, already acquiring "
"(no timeout active)");
}
* could use. Every phase now has a bounded window
* (gps_acquire_window_ms), so always reschedule from now. */
uint32_t timeout_ms = gps_acquire_window_ms();
LOG_INF("GPS: Fresh fix requested, extending acquire timeout to %u s",
timeout_ms / 1000U);
k_work_reschedule(&gps_timeout_work, K_MSEC(timeout_ms));
}
#endif
}