Make GPS navigation epochs interrupt-coherent

Wait for every navigation-ready tracking channel in a GPS epoch, remove unlocked channels without a timeout, and keep late joins for the next epoch. Reset PLIC ownership during warm initialization and extend Linux synthetic, integrity, and fake-MMIO regression coverage.
This commit is contained in:
2026-07-23 19:20:06 +03:00
parent 7cc3eb2a54
commit 516016efb9
16 changed files with 1780 additions and 246 deletions
@@ -19,7 +19,6 @@
// |___|_| |____/|_____|_| |___|_| \_|_____|____/
#define MIN_NEEDED_SATELLITE 4
#define GPS_INITIAL_SUBFRAME_MASK ((1u << 1) | (1u << 2) | (1u << 3) | (1u << 4) | (1u << 5))
#define GPS_TRCK_UNLOCK_TIMEOUT_TICKS 500000000u
#define GPS_PRN_COUNT 32u
#define GPS_PRN_INVALID 0xffu
@@ -318,6 +317,7 @@
double omgkdot; // from subframe 3
double idot; // from subframe 3
unsigned char update; // from subframe 3
bool ephemeris_valid; // true only after a matching SF1/SF2/SF3 set is committed.
unsigned char sf4_data_id; // from subframe 4 word 3.
unsigned char sf4_sv_id; // page identifier encoded in subframe 4 word 3.
unsigned char sf4_page; // decoded page number, or 0 if not mapped.
@@ -0,0 +1,70 @@
#ifndef GPS_NAV_EPOCH_H
#define GPS_NAV_EPOCH_H
#include <stdbool.h>
#include <stdint.h>
/*
* The current receiver exposes nine tracking channels. Keep the epoch
* selector bounded so its exhaustive, allocation-free search has a fixed
* worst-case cost on the embedded target.
*/
#define GPS_NAV_EPOCH_MAX_CANDIDATES 9u
typedef struct {
int week;
double tow_sec;
uint32_t raw_sample;
} gps_nav_epoch_key_t;
typedef struct {
uint32_t selected_mask;
unsigned int selected_count;
unsigned int reference_index;
} gps_nav_epoch_selection_t;
typedef struct {
uint64_t epoch_id;
uint32_t expected_mask;
uint32_t received_mask;
bool active;
} gps_nav_epoch_assembly_t;
typedef enum {
GPS_NAV_EPOCH_EVENT_INVALID = 0,
GPS_NAV_EPOCH_EVENT_ACCEPTED,
GPS_NAV_EPOCH_EVENT_DUPLICATE,
GPS_NAV_EPOCH_EVENT_STALE,
GPS_NAV_EPOCH_EVENT_FUTURE,
GPS_NAV_EPOCH_EVENT_COMPLETE
} gps_nav_epoch_event_result_t;
bool gps_nav_epoch_select(
const gps_nav_epoch_key_t candidates[GPS_NAV_EPOCH_MAX_CANDIDATES],
unsigned int candidate_count,
uint32_t sample_window,
double tow_tolerance_sec,
gps_nav_epoch_selection_t* selection);
bool gps_nav_epoch_id(
int week,
double tow_sec,
unsigned int period_ms,
uint64_t* epoch_id);
void gps_nav_epoch_assembly_reset(gps_nav_epoch_assembly_t* assembly);
gps_nav_epoch_event_result_t gps_nav_epoch_assembly_push(
gps_nav_epoch_assembly_t* assembly,
uint64_t epoch_id,
unsigned int channel,
uint32_t ready_mask);
bool gps_nav_epoch_assembly_remove_channel(
gps_nav_epoch_assembly_t* assembly,
unsigned int channel);
bool gps_nav_epoch_assembly_complete(
const gps_nav_epoch_assembly_t* assembly);
#endif
@@ -15,6 +15,7 @@ typedef struct gps_ephem_ll {
volatile bool gps_how_anchor_valid;
volatile uint32_t gps_nav_solve_sequence;
volatile uint32_t gps_nav_solve_consumed_sequence;
volatile gpstime_t gps_last_nav_solve_tow;
volatile uint32_t gps_last_nav_solve_abs_sample;
volatile double gps_last_nav_solve_corrected_abs_sample;
volatile uint64_t gps_last_nav_solve_local_ticks;