mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 01:41:29 +00:00
upstream sync and gps stuff
This commit is contained in:
1 parent
5b779478b0
commit
f9d01cf33a
21 files changed
+296
-45
No files matched your search
@@ -23,16 +23,48 @@ static void rtc_save_work_fn(struct k_work *work)
|
||||
static K_WORK_DEFINE(s_rtc_save_work, rtc_save_work_fn);
|
||||
#endif
|
||||
|
||||
/* The last time read, kept across a reset that keeps RAM (reboot, crash,
|
||||
* watchdog), as upstream's ESP32RTCClock does. ESP32 keeps it in RTC slow
|
||||
* memory: the bootloader may reuse ordinary noinit RAM. Power-on leaves
|
||||
* garbage, which the magic rejects. */
|
||||
#if defined(CONFIG_SOC_FAMILY_ESPRESSIF_ESP32)
|
||||
#define RTC_BACKUP_ATTR Z_GENERIC_SECTION(.rtc_noinit)
|
||||
#else
|
||||
#define RTC_BACKUP_ATTR __noinit
|
||||
#endif
|
||||
static RTC_BACKUP_ATTR uint32_t _rtc_backup_time;
|
||||
static RTC_BACKUP_ATTR uint32_t _rtc_backup_magic;
|
||||
#define RTC_BACKUP_MAGIC 0xAA55CC33
|
||||
#define RTC_TIME_MIN 1772323200 // 1 Mar 2026
|
||||
|
||||
ZephyrRTCClock::ZephyrRTCClock()
|
||||
{
|
||||
if (_rtc_backup_magic == RTC_BACKUP_MAGIC && _rtc_backup_time > RTC_TIME_MIN) {
|
||||
epoch_offset = _rtc_backup_time;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ZephyrRTCClock::getCurrentTime()
|
||||
{
|
||||
uint32_t uptime_sec = (uint32_t)(k_uptime_get() / 1000);
|
||||
return epoch_offset + uptime_sec;
|
||||
uint32_t now = epoch_offset + uptime_sec;
|
||||
|
||||
/* upstream does this in tick(), which nothing calls here */
|
||||
if (now > RTC_TIME_MIN && now != _rtc_backup_time) {
|
||||
_rtc_backup_time = now;
|
||||
_rtc_backup_magic = RTC_BACKUP_MAGIC;
|
||||
}
|
||||
return now;
|
||||
}
|
||||
|
||||
void ZephyrRTCClock::seedCurrentTime(uint32_t time)
|
||||
{
|
||||
uint32_t uptime_sec = (uint32_t)(k_uptime_get() / 1000);
|
||||
epoch_offset = time - uptime_sec;
|
||||
/* As upstream's setCurrentTime(): unconditional, so a set below
|
||||
* RTC_TIME_MIN (clkreboot) replaces the backup and is not restored. */
|
||||
_rtc_backup_time = time;
|
||||
_rtc_backup_magic = RTC_BACKUP_MAGIC;
|
||||
}
|
||||
|
||||
void ZephyrRTCClock::setCurrentTime(uint32_t time)
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace mesh {
|
||||
|
||||
class ZephyrRTCClock : public RTCClock {
|
||||
public:
|
||||
/* Starts from the time kept across the last reset, if any (see the .cpp). */
|
||||
ZephyrRTCClock();
|
||||
uint32_t getCurrentTime() override;
|
||||
/* Also written to the board's hardware RTC, if it has one, as upstream's
|
||||
* AutoDiscoverRTCClock does: coalesced on the system work queue, so
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
*
|
||||
* Power strategy:
|
||||
* - Direct GPIO toggle via gps-enable alias (all boards)
|
||||
* - T1000-E warm standby: VRTC stays powered during standby, preserving
|
||||
* ephemeris/almanac/RTC in backup RAM for fast re-acquisition (3-8s vs 15-45s)
|
||||
* - T1000-E / MeshTracker X1: AG3335 RTC backup sleep during standby (VRTC
|
||||
* stays powered, see gps_power.cpp) for fast re-acquisition
|
||||
* - GNSS UARTE suspended (device PM) while GPS is off/standby — releases
|
||||
* HFCLK on nRF52840 (~0.5-1 mA), resumed before every wake
|
||||
* - Full power-off only on user-disable or System OFF
|
||||
@@ -83,6 +83,8 @@ static uint64_t standby_interval_ms = 0; /* How long standby lasts (for next-wak
|
||||
static const uint32_t gps_acquire_timeout_ms = CONFIG_ZEPHCORE_GPS_FIX_TIMEOUT_SEC * 1000U;
|
||||
static const 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;
|
||||
/* prefs.gps_standby_max, see gps_set_standby_max_sec() */
|
||||
static uint32_t gps_standby_max_sec = GPS_STANDBY_MAX_DEFAULT_SEC;
|
||||
|
||||
/* Duty cycle vs always-on: a non-zero standby interval duty-cycles; interval 0
|
||||
* keeps the GPS in continuous acquisition (never sleeps) so it streams fresh
|
||||
@@ -528,7 +530,11 @@ static void gps_go_to_standby(void)
|
||||
* RTC survive the cut and re-acquisition is a warm/hot start, not cold.
|
||||
* Other non-GPIO boards: software sleep via UART commands (PMTK + UBX). */
|
||||
gps_reapply_cancel();
|
||||
gps_module_power(false);
|
||||
/* A standby-pin board keeps the supply only for a short interval: its
|
||||
* Standby draws all the time, a cold start only for a few minutes, so
|
||||
* past gps_standby_max_sec the supply cut is the cheaper one. */
|
||||
gps_module_power(false, !HAS_GPS_WAKEUP ||
|
||||
wake_interval / 1000U <= gps_standby_max_sec);
|
||||
|
||||
/* Module is off/asleep — release the UART until the next wake
|
||||
* (nRF: drops the HFCLK request held by the armed RX). */
|
||||
@@ -878,12 +884,12 @@ void gps_enable(bool enable)
|
||||
k_work_cancel_delayable(&gps_timeout_work);
|
||||
gps_reapply_cancel();
|
||||
|
||||
/* Power off GPS — warm standby if VRTC available (Arduino sleep_gps),
|
||||
* full power off otherwise. Warm standby preserves ephemeris/RTC
|
||||
* in AG3335 backup RAM for fast re-acquisition (1-8s vs 15-45s).
|
||||
/* Power off GPS — AG3335 RTC backup sleep where the board has it
|
||||
* (Arduino stop_gps), full power off otherwise.
|
||||
* Boards with no power line get the UART sleep commands, as in
|
||||
* the duty cycle's standby. */
|
||||
gps_module_power(false);
|
||||
* the duty cycle's standby. A standby-pin board cuts the supply
|
||||
* here: its Standby still draws, and this off has no end. */
|
||||
gps_module_power(false, !HAS_GPS_WAKEUP);
|
||||
|
||||
/* GPS is off until re-enabled — release the UART. */
|
||||
gps_uart_set_power(false);
|
||||
@@ -941,6 +947,29 @@ uint32_t gps_get_poll_interval_sec(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool gps_has_standby_pin(void)
|
||||
{
|
||||
return HAS_GPS_WAKEUP;
|
||||
}
|
||||
|
||||
uint32_t gps_get_standby_max_sec(void)
|
||||
{
|
||||
#if HAS_GNSS
|
||||
return gps_standby_max_sec;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void gps_set_standby_max_sec(uint32_t sec)
|
||||
{
|
||||
#if HAS_GNSS
|
||||
gps_standby_max_sec = sec;
|
||||
#else
|
||||
ARG_UNUSED(sec);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gps_set_poll_interval_sec(uint32_t interval)
|
||||
{
|
||||
#if HAS_GNSS
|
||||
|
||||
@@ -105,6 +105,13 @@ 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);
|
||||
/* Boards with a module standby pin beside a supply switch (gps-wakeup alias):
|
||||
* duty intervals up to this many seconds use the pin (supply kept, hot start
|
||||
* on wake), longer ones cut the supply. 0 = always cut. Takes effect at the
|
||||
* next standby. */
|
||||
bool gps_has_standby_pin(void);
|
||||
uint32_t gps_get_standby_max_sec(void);
|
||||
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);
|
||||
|
||||
@@ -62,6 +62,13 @@
|
||||
#define HAS_GPS_POWER_CONTROL 0
|
||||
#endif
|
||||
|
||||
/* Module standby pin beside a supply switch (gps-wakeup alias, see gps_power.cpp). */
|
||||
#if DT_NODE_EXISTS(DT_ALIAS(gps_wakeup))
|
||||
#define HAS_GPS_WAKEUP 1
|
||||
#else
|
||||
#define HAS_GPS_WAKEUP 0
|
||||
#endif
|
||||
|
||||
/* GPS powered from a PMU regulator rail (chosen zephcore,gps-power). */
|
||||
#if DT_NODE_EXISTS(DT_CHOSEN(zephcore_gps_power))
|
||||
#define HAS_GPS_POWER_REGULATOR 1
|
||||
|
||||
@@ -25,8 +25,8 @@ LOG_MODULE_DECLARE(zephcore_gps, CONFIG_ZEPHCORE_GPS_LOG_LEVEL);
|
||||
* every wake is a warm start, not a cold one. (Backup mode, the deeper
|
||||
* state, requires cutting VCC while V_BCKP holds the RTC domain; this
|
||||
* board has no VCC switch, so Standby is the floor available to us.)
|
||||
* - T1000-E (AG3335): GPS_EN de-asserted + VRTC asserted = warm standby (ephemeris
|
||||
* preserved via backup RAM, ~1-2µA VRTC current)
|
||||
* - T1000-E, MeshTracker X1 (AG3335): RTC backup sleep ($PAIR650,0), then
|
||||
* GPS_EN de-asserted with VRTC kept; a GPS_RTC_INT pulse wakes it
|
||||
* - All boards: gps-enable alias → GPIO power control
|
||||
*
|
||||
* CONFIG_PM_DEVICE is on globally, but nothing suspends automatically —
|
||||
@@ -144,11 +144,50 @@ static const struct gpio_dt_spec gps_resetb_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(gps
|
||||
#define HAS_GPS_RESETB 0
|
||||
#endif
|
||||
|
||||
/* Module standby pin (L76K WAKEUP: asserted = run, de-asserted = Standby, RF
|
||||
* off with the core powered) on a board that ALSO has a supply switch
|
||||
* (gps-enable): standby uses this pin and keeps the supply, so a wake is a
|
||||
* hot start; a full off (`gps off`, boot with GPS disabled, System OFF) cuts
|
||||
* the supply, since Standby still draws. A board whose only control is the
|
||||
* standby pin (Wio Tracker L1) declares it as gps-enable instead. */
|
||||
#if HAS_GPS_WAKEUP
|
||||
static const struct gpio_dt_spec gps_wakeup_gpio = GPIO_DT_SPEC_GET(DT_ALIAS(gps_wakeup), gpios);
|
||||
#endif
|
||||
|
||||
/* T1000-E has extra GPS control pins that require a specific init sequence */
|
||||
#define HAS_T1000_GPS_CONTROL (HAS_GPS_VRTC || HAS_GPS_RESET || HAS_GPS_SLEEP)
|
||||
|
||||
/* AG3335 RTC backup sleep (upstream AirohaSleep.h; T1000-E, MeshTracker X1):
|
||||
* the module is told to save its state and sleep before GPS_EN is cut, VRTC
|
||||
* keeps its RTC domain powered, and a GPS_RTC_INT pulse wakes it. */
|
||||
#define HAS_GPS_BACKUP_SLEEP \
|
||||
(HAS_GPS_POWER_CONTROL && HAS_GPS_VRTC && HAS_GPS_RTCINT && HAS_GPS_UART)
|
||||
|
||||
#if HAS_GPS_POWER_CONTROL
|
||||
static bool gps_gpio_configured = false;
|
||||
/* T1000-E sequence only: the module was powered on by us / is in backup sleep. */
|
||||
static bool gps_module_on = false;
|
||||
static bool gps_backup_sleeping = false;
|
||||
#endif
|
||||
|
||||
#if HAS_GPS_BACKUP_SLEEP
|
||||
/* Upstream stop_gps(). The ack ($PAIR001,650,0) cannot be read here, the GNSS
|
||||
* driver owns the UART RX, so the command goes out blind and upstream's 50 ms
|
||||
* ack window plus 50 ms grace is waited out. A missed command is the old
|
||||
* behaviour: a power cut with VRTC kept. */
|
||||
static void gps_enter_backup_sleep(void)
|
||||
{
|
||||
static const char pair_sleep[] = "$PAIR650,0*25\r\n";
|
||||
|
||||
gpio_pin_configure_dt(&gps_vrtc_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
gpio_pin_configure_dt(&gps_rtcint_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
gps_uart_send((const uint8_t *)pair_sleep, sizeof(pair_sleep) - 1);
|
||||
k_msleep(100);
|
||||
gpio_pin_configure_dt(&gps_enable_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
gps_module_on = false;
|
||||
gps_backup_sleeping = true;
|
||||
LOG_INF("GPS power OFF (RTC backup sleep)");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The off levels, shared by gps_power_control(false) and System OFF: reset
|
||||
@@ -164,6 +203,12 @@ static bool gps_gpio_configured = false;
|
||||
* the power-on path, so the pins may not be outputs yet. */
|
||||
static void gps_drive_off_levels(bool keep_vrtc, bool system_off)
|
||||
{
|
||||
#if HAS_GPS_WAKEUP
|
||||
/* Low before the supply goes: no pin driven into an unpowered module. */
|
||||
if (gpio_is_ready_dt(&gps_wakeup_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_wakeup_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
}
|
||||
#endif
|
||||
#if HAS_GPS_RESET
|
||||
if (gpio_is_ready_dt(&gps_reset_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_reset_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
@@ -231,10 +276,15 @@ void gps_power_control(bool on, bool keep_vrtc)
|
||||
* (driver PM can hang on modem_pipe_close / modem_chat_run_script).
|
||||
* The GNSS driver's modem pipe stays open.
|
||||
*
|
||||
* T1000-E (HAS_GPS_VRTC): Use warm standby (keep VRTC) for app toggle
|
||||
* so UART/chip state is preserved. Matches Arduino sleep_gps().
|
||||
* T1000-E / X1 (HAS_GPS_BACKUP_SLEEP): standby and app toggle use the
|
||||
* AG3335 RTC backup sleep, as Arduino stop_gps().
|
||||
* Simple boards (Wio etc.): Full power off/on via GPS_EN. */
|
||||
if (on) {
|
||||
#if HAS_GPS_WAKEUP
|
||||
if (gpio_is_ready_dt(&gps_wakeup_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_wakeup_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
}
|
||||
#endif
|
||||
#if HAS_T1000_GPS_CONTROL
|
||||
/* T1000-E power-on sequence (from Arduino target.cpp start_gps())
|
||||
* Must follow this exact order with delays. Levels are ASSERTED /
|
||||
@@ -265,7 +315,9 @@ void gps_power_control(bool on, bool keep_vrtc)
|
||||
#endif
|
||||
|
||||
#if HAS_GPS_RESET
|
||||
if (gpio_is_ready_dt(&gps_reset_gpio)) {
|
||||
/* Not when waking from backup sleep: upstream resets the module
|
||||
* once, in begin(), and a reset here would make the wake a restart. */
|
||||
if (!gps_backup_sleeping && gpio_is_ready_dt(&gps_reset_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_reset_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
k_msleep(10);
|
||||
gpio_pin_set_dt(&gps_reset_gpio, 0); /* Release reset (logical) */
|
||||
@@ -279,9 +331,12 @@ void gps_power_control(bool on, bool keep_vrtc)
|
||||
#endif
|
||||
|
||||
#if HAS_GPS_RTCINT
|
||||
/* GPS_RTC_INT (P0.15) — held de-asserted during normal operation */
|
||||
/* GPS_RTC_INT: a 5 ms pulse wakes the AG3335 from RTC backup sleep
|
||||
* (upstream start_gps(), on every power-on); otherwise de-asserted. */
|
||||
if (gpio_is_ready_dt(&gps_rtcint_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_rtcint_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
gpio_pin_configure_dt(&gps_rtcint_gpio, GPIO_OUTPUT_ACTIVE);
|
||||
k_msleep(5);
|
||||
gpio_pin_set_dt(&gps_rtcint_gpio, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -294,7 +349,10 @@ void gps_power_control(bool on, bool keep_vrtc)
|
||||
}
|
||||
#endif
|
||||
gps_gpio_configured = true;
|
||||
LOG_INF("GPS power ON (T1000-E sequence)");
|
||||
LOG_INF("GPS power ON (T1000-E sequence%s)",
|
||||
gps_backup_sleeping ? ", wake from backup sleep" : "");
|
||||
gps_module_on = true;
|
||||
gps_backup_sleeping = false;
|
||||
#else
|
||||
/* Simple boards - just GPS_EN */
|
||||
if (!gps_gpio_configured) {
|
||||
@@ -315,7 +373,29 @@ void gps_power_control(bool on, bool keep_vrtc)
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if HAS_GPS_BACKUP_SLEEP
|
||||
if (keep_vrtc && gps_module_on) {
|
||||
gps_enter_backup_sleep();
|
||||
return;
|
||||
}
|
||||
if (keep_vrtc && gps_backup_sleeping) {
|
||||
return; /* already asleep (disabled while in standby) */
|
||||
}
|
||||
#endif
|
||||
#if HAS_GPS_WAKEUP
|
||||
/* Standby by the module's own pin, supply kept: the wake is a hot
|
||||
* start and skips the reset pulse (gps_backup_sleeping). */
|
||||
if (keep_vrtc && gpio_is_ready_dt(&gps_wakeup_gpio)) {
|
||||
gpio_pin_configure_dt(&gps_wakeup_gpio, GPIO_OUTPUT_INACTIVE);
|
||||
gps_module_on = false;
|
||||
gps_backup_sleeping = true;
|
||||
LOG_INF("GPS standby (WAKEUP pin, supply kept)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
gps_drive_off_levels(keep_vrtc, false);
|
||||
gps_module_on = false;
|
||||
gps_backup_sleeping = false;
|
||||
|
||||
#if HAS_GPS_VRTC
|
||||
LOG_INF("GPS power OFF (%s)", keep_vrtc ?
|
||||
|
||||
Reference in new issue
Block a user