mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-15 08:50:15 +00:00
upstream sync and gps stuff
This commit is contained in:
@@ -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 ?
|
||||
|
||||
@@ -26,8 +26,21 @@
|
||||
};
|
||||
};
|
||||
|
||||
/* L76KB WAKEUP (schematic net GNSS_WAKEUP, P0.02; upstream's
|
||||
* PIN_GPS_STANDBY): HIGH = run, LOW = Standby with the supply kept.
|
||||
* The GPS manager uses it for duty-cycle standby, so a wake is a hot
|
||||
* start; P1.05 is cut on `gps off` and System OFF. */
|
||||
gps_wake: gps-wakeup {
|
||||
compatible = "gpio-leds";
|
||||
gps_wakeup_pin: gps_wakeup {
|
||||
gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
|
||||
label = "GNSS Wakeup";
|
||||
};
|
||||
};
|
||||
|
||||
aliases {
|
||||
gps-enable = &gps_enable_pin;
|
||||
gps-reset = &gps_reset_pin;
|
||||
gps-wakeup = &gps_wakeup_pin;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* - GPS_EN (P1.11) - Main power enable
|
||||
* - GPS_VRTC_EN (P0.8) - RTC voltage regulator (critical!)
|
||||
* - GPS_RESET (P1.15) - Reset control
|
||||
* - GPS_SLEEP_INT (P1.12) - Sleep interrupt
|
||||
* - GPS_SLEEP_INT (P1.12) - Sleep interrupt, hogged LOW (see the end)
|
||||
* - GPS_RTC_INT (P0.15) - pulsed to wake the module from RTC backup sleep
|
||||
*/
|
||||
|
||||
/ {
|
||||
@@ -37,16 +38,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
/* GPS sleep interrupt - P1.12 */
|
||||
gps_sleep: gps-sleep-int {
|
||||
compatible = "gpio-leds";
|
||||
gps_sleep_pin: gps_sleep {
|
||||
gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
|
||||
label = "GPS Sleep Int";
|
||||
};
|
||||
};
|
||||
|
||||
/* GPS RTC interrupt - P0.15 (held LOW during normal operation) */
|
||||
/* GPS RTC interrupt - P0.15 (LOW, pulsed HIGH to wake from backup sleep) */
|
||||
gps_rtcint: gps-rtc-int {
|
||||
compatible = "gpio-leds";
|
||||
gps_rtcint_pin: gps_rtc_int {
|
||||
@@ -73,8 +65,19 @@
|
||||
gps-enable = &gps_enable_pin;
|
||||
gps-vrtc-enable = &gps_vrtc_pin;
|
||||
gps-reset = &gps_reset_pin;
|
||||
gps-sleep-int = &gps_sleep_pin;
|
||||
gps-rtc-int = &gps_rtcint_pin;
|
||||
gps-resetb = &gps_resetb_pin;
|
||||
};
|
||||
};
|
||||
|
||||
/* GPS_SLEEP_INT (P1.12): held LOW at all times, as upstream since the RTC
|
||||
* backup sleep (#3525). No gps-sleep-int alias, so the GPS manager leaves it
|
||||
* alone. */
|
||||
&gpio1 {
|
||||
gps_sleep_int_low {
|
||||
gpio-hog;
|
||||
gpios = <12 GPIO_ACTIVE_HIGH>;
|
||||
output-low;
|
||||
line-name = "gps-sleep-int";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -107,11 +107,13 @@
|
||||
|
||||
/* Onboard NTC thermistor (AIN7) and photocell (AIN5).
|
||||
*
|
||||
* Both dividers hang off the sensor_power rail AND need SENSOR_EN
|
||||
* (P0.4) asserted — Arduino drives both before every read. The driver
|
||||
* switches them per sample fetch; regulator refcounting keeps that
|
||||
* Both dividers hang off the sensor_power rail (P1.06). The driver
|
||||
* switches it per sample fetch; regulator refcounting keeps that
|
||||
* safe alongside the battery read, which shares the rail.
|
||||
*
|
||||
* No power-gpios: P0.04 is "VCC voltage detect" in Seeed's pin table,
|
||||
* not a sensor enable, and upstream stopped driving it (#2065).
|
||||
*
|
||||
* The NTC conversion needs the rail voltage feeding its divider, so
|
||||
* the battery channel is wired in here as "vcc" with the same
|
||||
* multiplier zephyr,user uses. It is clamped to vcc-max-mv, which is
|
||||
@@ -124,7 +126,6 @@
|
||||
vcc-max-mv = <3300>;
|
||||
ntc-series-ohms = <8250>;
|
||||
settle-time-ms = <10>;
|
||||
power-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
|
||||
power-supply = <&sensor_power>;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ description: |
|
||||
scale verbatim as CayenneLPP luminosity, so this driver does the same.
|
||||
The value is a percentage despite the channel's nominal lux units.
|
||||
|
||||
Neither divider outputs a valid voltage until the rail regulator and the
|
||||
sensor-enable GPIO are both asserted and given time to settle, so the driver
|
||||
switches them around each sample fetch rather than leaving them on.
|
||||
Neither divider outputs a valid voltage until the rail regulator is on and
|
||||
given time to settle, so the driver switches it around each sample fetch
|
||||
rather than leaving it on.
|
||||
|
||||
compatible: "seeed,t1000e-analog"
|
||||
|
||||
@@ -57,9 +57,9 @@ properties:
|
||||
power-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
Sensor-enable pin (SENSOR_EN, P0.4 on the T1000-E), asserted for the
|
||||
duration of a sample fetch. This is in addition to power-supply: the
|
||||
T1000-E gates these two sensors behind both.
|
||||
Optional sensor-enable pin, asserted for the duration of a sample fetch,
|
||||
in addition to power-supply. The T1000-E has none (P0.4 is a voltage
|
||||
detect input, not SENSOR_EN) and leaves this unset.
|
||||
|
||||
power-supply:
|
||||
type: phandle
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "ContactInfo.h"
|
||||
|
||||
#define MAX_SEARCH_RESULTS 8
|
||||
#define MAX_SEARCH_RESULTS 24
|
||||
|
||||
#define MSG_SEND_FAILED 0
|
||||
#define MSG_SEND_SENT_FLOOD 1
|
||||
|
||||
@@ -1201,6 +1201,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, const char* command, cha
|
||||
size_t cap = replyCap(sender_timestamp);
|
||||
reply[0] = '>'; reply[1] = ' ';
|
||||
gps_get_diag_report(reply + 2, cap - 2);
|
||||
} else if (memcmp(config, "gps standby", 11) == 0) {
|
||||
if (!gps_has_standby_pin()) strcpy(reply, "> n/a (no GPS standby pin on this board)");
|
||||
else snprintf(reply, CLI_REPLY_SIZE, "> %u", (unsigned)gps_get_standby_max_sec());
|
||||
} else if (memcmp(config, "gps duty", 8) == 0) {
|
||||
uint32_t s = gps_get_poll_interval_sec(); // now-effective value
|
||||
if (s == 0) strcpy(reply, "> always on (0)");
|
||||
@@ -1803,6 +1806,24 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, const char* command, cha
|
||||
} else {
|
||||
strcpy(reply, "usage: set gps diag <0|1|on|off>");
|
||||
}
|
||||
} else if (memcmp(config, "gps standby", 11) == 0) {
|
||||
// set gps standby <seconds> | default (0 = always cut the supply)
|
||||
const char* arg = config + 11;
|
||||
while (*arg == ' ') arg++;
|
||||
char* end = NULL;
|
||||
unsigned long parsed = strtoul(arg, &end, 10);
|
||||
bool is_default = strcmp(arg, "default") == 0;
|
||||
if (!gps_has_standby_pin()) {
|
||||
strcpy(reply, "Error: no GPS standby pin on this board");
|
||||
} else if (!is_default && (*arg == '\0' || end == arg || *end != '\0' || parsed > GPS_INTERVAL_MAX_SEC)) {
|
||||
strcpy(reply, "usage: set gps standby <seconds> | default (0 = always cut the supply)");
|
||||
} else {
|
||||
uint32_t val = is_default ? GPS_STANDBY_MAX_DEFAULT_SEC : (uint32_t)parsed;
|
||||
_prefs->gps_standby_max = val;
|
||||
gps_set_standby_max_sec(val); // applies at the next standby
|
||||
savePrefs();
|
||||
snprintf(reply, CLI_REPLY_SIZE, "OK - gps standby=%u s", (unsigned)val);
|
||||
}
|
||||
} else if (memcmp(config, "gps duty", 8) == 0) {
|
||||
// set gps duty <seconds> | default (0 = always on)
|
||||
const char* arg = config + 8;
|
||||
|
||||
@@ -142,6 +142,9 @@ struct NodePrefs {
|
||||
* without this marker is upgraded to gps_enabled = 1 once. */
|
||||
uint8_t gps_enabled_set;
|
||||
uint32_t gps_interval; // in seconds
|
||||
/* Standby-pin boards: duty intervals up to this (seconds) keep the GPS
|
||||
* supply and use the standby pin, longer ones cut it. 0 = always cut. */
|
||||
uint32_t gps_standby_max;
|
||||
uint8_t advert_loc_policy;
|
||||
uint32_t discovery_mod_timestamp;
|
||||
float adc_multiplier;
|
||||
@@ -327,6 +330,7 @@ static inline void powersaving_upgrade(NodePrefs *p) {
|
||||
|
||||
#define GPS_INTERVAL_MIN_SEC 10u
|
||||
#define GPS_INTERVAL_MAX_SEC 604800u
|
||||
#define GPS_STANDBY_MAX_DEFAULT_SEC 3600u
|
||||
static inline uint32_t clampGpsInterval(uint32_t sec) {
|
||||
if (sec == 0) return 0;
|
||||
if (sec < GPS_INTERVAL_MIN_SEC) return GPS_INTERVAL_MIN_SEC;
|
||||
@@ -426,6 +430,7 @@ static inline void sanitizeNodePrefs(NodePrefs* p) {
|
||||
if (p->ble_pin > 999999) p->ble_pin = 0;
|
||||
/* 0 is always-on, so a corrupt value clamps to the week, not to 0. */
|
||||
p->gps_interval = clampGpsInterval(p->gps_interval);
|
||||
if (p->gps_standby_max > GPS_INTERVAL_MAX_SEC) p->gps_standby_max = GPS_INTERVAL_MAX_SEC;
|
||||
/* 0 = board/Kconfig default on both, else the range the UI offers. */
|
||||
if (p->display_brightness != 0) p->display_brightness = clampPref<uint8_t>(p->display_brightness, 10, 100);
|
||||
if (p->screen_off_secs != 0) p->screen_off_secs = clampPref<uint16_t>(p->screen_off_secs, 5, 300);
|
||||
@@ -495,6 +500,7 @@ static inline void initNodePrefs(NodePrefs* prefs) {
|
||||
prefs->powersaving_set = 1;
|
||||
prefs->gps_enabled = 0;
|
||||
prefs->gps_interval = 300; // 5 minutes
|
||||
prefs->gps_standby_max = GPS_STANDBY_MAX_DEFAULT_SEC;
|
||||
prefs->advert_loc_policy = ADVERT_LOC_NONE;
|
||||
prefs->adc_multiplier = 0.0f;
|
||||
prefs->rx_boost = 1; // Default to boosted RX for better sensitivity
|
||||
|
||||
@@ -72,6 +72,7 @@ protected:
|
||||
def("disp_rot", _p->display_rotate);
|
||||
def("in_rot", _p->input_rotate);
|
||||
def("pwr_sav_set", _p->powersaving_set);
|
||||
def("gps_stby", _p->gps_standby_max);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -39,6 +39,7 @@ static inline void apply_boot_prefs(const NodePrefs *p, bool gps_time_sync)
|
||||
|
||||
if (gps_time_sync && gps_is_available()) {
|
||||
gps_set_poll_interval_sec(p->gps_interval);
|
||||
gps_set_standby_max_sec(p->gps_standby_max);
|
||||
gps_set_repeater_mode(true);
|
||||
if (p->gps_enabled) {
|
||||
gps_enable(true);
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
/**
|
||||
* \brief checks the MAC (in leading bytes of 'src'), then if valid, decrypts remaining bytes in src.
|
||||
* \returns zero if MAC is invalid, otherwise the length of decrypted bytes in 'dest'
|
||||
* \returns zero if MAC is invalid or ciphertext is not block-aligned, otherwise the length of decrypted bytes in 'dest'
|
||||
*/
|
||||
static int MACThenDecrypt(const uint8_t* shared_secret, uint8_t* dest, const uint8_t* src, int src_len);
|
||||
|
||||
|
||||
@@ -189,14 +189,18 @@ int Utils::encryptThenMAC(const uint8_t *shared_secret, uint8_t *dest, const uin
|
||||
int Utils::MACThenDecrypt(const uint8_t *shared_secret, uint8_t *dest, const uint8_t *src, int src_len)
|
||||
{
|
||||
if (src_len <= (int)CIPHER_MAC_SIZE) return 0;
|
||||
|
||||
int enc_len = src_len - CIPHER_MAC_SIZE;
|
||||
if (enc_len % CIPHER_BLOCK_SIZE != 0) return 0; /* reject non-block-aligned ciphertext */
|
||||
|
||||
uint8_t computed_mac[CIPHER_MAC_SIZE];
|
||||
if (compute_hmac_truncated(shared_secret, PUB_KEY_SIZE, src + CIPHER_MAC_SIZE, (size_t)src_len - CIPHER_MAC_SIZE, computed_mac, CIPHER_MAC_SIZE) != 0)
|
||||
if (compute_hmac_truncated(shared_secret, PUB_KEY_SIZE, src + CIPHER_MAC_SIZE, (size_t)enc_len, computed_mac, CIPHER_MAC_SIZE) != 0)
|
||||
return 0;
|
||||
/* Constant-time MAC compare. Runs on every encrypted packet — a
|
||||
* timing oracle here would let attackers forge MACs byte-by-byte
|
||||
* across the entire mesh, bypassing message authentication. */
|
||||
if (!Utils::constantTimeEqual(computed_mac, src, CIPHER_MAC_SIZE)) return 0;
|
||||
return decrypt(shared_secret, dest, src + CIPHER_MAC_SIZE, src_len - CIPHER_MAC_SIZE);
|
||||
return decrypt(shared_secret, dest, src + CIPHER_MAC_SIZE, enc_len);
|
||||
}
|
||||
|
||||
/* See header for rationale. The `volatile` accumulator forces
|
||||
|
||||
@@ -1103,6 +1103,7 @@ int main(void)
|
||||
* state machine if enabled. */
|
||||
if (gps_is_available()) {
|
||||
gps_set_poll_interval_sec(companion_mesh.prefs.gps_interval);
|
||||
gps_set_standby_max_sec(companion_mesh.prefs.gps_standby_max);
|
||||
gps_ensure_power_state(companion_mesh.prefs.gps_enabled);
|
||||
|
||||
if (companion_mesh.prefs.gps_enabled) {
|
||||
|
||||
Reference in New Issue
Block a user