Files
ZephCore/zephcore/adapters/gps/ZephyrGPSManager.h
T
2026-10-06 21:43:35 +02:00

139 lines
5.8 KiB
C

/*
* SPDX-License-Identifier: MIT
* Zephyr GPS Manager - GNSS power management, fix acquisition, constellation config
*
* Event-driven state machine: OFF → ACQUIRING → STANDBY → ACQUIRING → ...
* Uses Zephyr GNSS API with chip-specific drivers (quectel,lc76g / luatos,air530z / gnss-nmea-generic)
*/
#pragma once
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#ifdef __cplusplus
extern "C" {
#endif
/* GPS position data */
struct gps_position {
int64_t latitude_ndeg; /* Latitude in nano-degrees */
int64_t longitude_ndeg; /* Longitude in nano-degrees */
int32_t altitude_mm; /* Altitude in millimeters */
uint16_t satellites; /* Number of satellites */
bool valid; /* True if fix is valid */
int64_t timestamp_ms; /* Timestamp when fix was acquired */
};
/* gps_state_info.state */
#define GPS_STATE_INFO_OFF 0
#define GPS_STATE_INFO_STANDBY 1
#define GPS_STATE_INFO_ACQUIRING 2
/* GPS state info for UI display */
struct gps_state_info {
uint8_t state; /* 0=OFF, 1=STANDBY (sleeping), 2=ACQUIRING (searching) */
uint16_t satellites; /* Current/last satellite count */
uint32_t last_fix_age_s; /* Seconds since last validated fix (UINT32_MAX = never) */
uint32_t next_search_s; /* Seconds until next search (0 = searching now or off) */
};
/* ===== GPS configuration diagnostics (runtime toggle, RAM only) =====
* With diag on, the next GPS enable re-runs the module configuration and
* records the outcome for `get gps diag`. Not persisted. */
void gps_set_diag(bool on);
/* Render the last configuration attempt as a single CLI line. Always
* succeeds; reports "never run" if configuration has not happened yet. */
void gps_get_diag_report(char *buf, size_t len);
/* `gps diag` (upstream's LocationProvider::formatDiagnostics): module on,
* NMEA sentences parsed, satellites, fix, fix age in ms, module power-on /
* power-off counts. Upstream's UART byte and bad-checksum counters have no
* source behind the GNSS API and are left out. */
void gps_format_diagnostics(char *out, size_t out_size);
/* GPS enable callback - called when GPS is enabled/disabled (for power management) */
typedef void (*gps_enable_callback_t)(bool enabled);
void gps_set_enable_callback(gps_enable_callback_t cb);
/* GPS fix callback - called when GPS acquires a validated fix (3 consecutive good fixes)
* Parameters: latitude (degrees), longitude (degrees), utc_time (Unix timestamp,
* 0 if the fix carried no usable date). Runs on the main thread, from
* gps_process_event(), so it may set the clock and prefs directly. */
typedef void (*gps_fix_callback_t)(double lat, double lon, int64_t utc_time);
void gps_set_fix_callback(gps_fix_callback_t cb);
/* GPS event callback: the state machine needs the main thread. Timer work
* handlers must not call blocking GNSS APIs (they would deadlock the system
* work queue), so they signal here and main calls gps_process_event(). */
typedef void (*gps_event_callback_t)(void);
void gps_set_event_callback(gps_event_callback_t cb);
/* Process pending GPS state transitions — MUST be called from the main
* thread (not from system work queue) because GNSS configuration uses
* blocking modem_chat calls. Called by the mesh event loop when
* MESH_EVENT_GPS_ACTION is signaled. */
void gps_process_event(void);
/* Initialize GPS manager (call once at boot) */
int gps_manager_init(void);
/* GPS functions */
bool gps_is_available(void);
bool gps_is_enabled(void);
void gps_enable(bool enable);
/* Ensure GPS power state matches prefs at boot.
* Call this after loading prefs - if GPS should be disabled, powers it off.
* This is needed because GPS hardware starts powered (bootloader/pull-up). */
void gps_ensure_power_state(bool should_be_enabled);
void gps_get_position(struct gps_position *pos);
uint32_t gps_get_poll_interval_sec(void);
void gps_set_poll_interval_sec(uint32_t interval);
/* Every board: duty intervals up to this many seconds keep the module's state
* between fixes (backup sleep, standby pin, VRTC: a fast fix on wake), longer
* ones take the board's full power-off. 0 = always the full power-off. Takes
* effect at the next standby. */
void gps_set_standby_max_sec(uint32_t sec);
/* Get RTC time from GPS (returns Unix timestamp, 0 if no valid time) */
int64_t gps_get_utc_time(void);
/* Check if we have GPS-synced time (used to reject phone time sync attempts) */
bool gps_has_time_sync(void);
/* Get last known GPS position (even when GPS is sleeping/disabled)
* Returns true if a valid last position exists, false otherwise.
* This is useful for telemetry when GPS is in power-save mode. */
bool gps_get_last_known_position(struct gps_position *pos);
/* Trigger GPS wake for a fresh fix (if GPS is enabled but sleeping).
* Call this after telemetry requests so next request has fresh location.
* Does nothing if GPS is disabled or already acquiring. */
void gps_request_fresh_fix(void);
/* GPS state info for UI display */
void gps_get_state_info(struct gps_state_info *info);
/* Drive all GPS power-enable GPIOs LOW for System OFF.
* Safe to call from any context — only touches GPIO, no BLE or SPI.
* Must be called before sys_poweroff() to prevent GPS module drawing
* current while nRF52840 is in System OFF (GPIO latches persist). */
void gps_power_off_for_shutdown(void);
/* Set repeater (time-sync) mode: every acquire window is the fixed 5-minute
* one, then standby for the poll interval (a server's default is
* CONFIG_ZEPHCORE_REPEATER_GPS_INTERVAL_SEC). Mode only: it does not power the
* GPS; gps_enable() does. Call at boot before any gps_enable(). */
void gps_set_repeater_mode(bool repeater);
/* For a role that never uses its GPS (the observer), instead of
* gps_manager_init(): power the module down and release its UART, which would
* otherwise stay powered and armed for the whole uptime. */
void gps_park(void);
#ifdef __cplusplus
}
#endif