upstream sync and gps stuff

This commit is contained in:
liquidraver
2026-10-02 23:10:09 +02:00
parent 5b779478b0
commit f9d01cf33a
21 changed files with 296 additions and 45 deletions
+33 -1
View File
@@ -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)
+2
View File
@@ -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
+37 -8
View File
@@ -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
+7
View File
@@ -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);
+7
View File
@@ -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
+88 -8
View File
@@ -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;
};
};
+15 -12
View File
@@ -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
+1 -1
View File
@@ -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
+21
View File
@@ -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;
+6
View File
@@ -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
+1
View File
@@ -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:
+1
View File
@@ -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);
+1 -1
View File
@@ -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);
+6 -2
View File
@@ -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
+1
View File
@@ -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) {