Fix GPS nav-solve phase seeding for cold PVT

This commit is contained in:
Codex
2026-08-04 15:52:36 +03:00
parent 28b55fdfb6
commit dce1dd5ea9
7 changed files with 164 additions and 37 deletions
+12 -1
View File
@@ -8,6 +8,7 @@ TARGETS := test_imu_calibration test_gps_nav_epoch \
test_plic_warm_reset test_gps_acq_manager \
test_gps_ephemeris_cache test_gps_receiver_hardware_sim
TARGETS += test_gps_measurement_freshness
TARGETS += test_gps_nav_phase
TARGETS += test_gps_tracking_measurement
TARGETS += test_gps_satellite_velocity
TARGETS += test_gps_pps_time_filter
@@ -39,6 +40,9 @@ test_gps_measurement_freshness: test_gps_measurement_freshness.c \
$(ROOT)/src/gps/gps_measurement_freshness.c
$(CC) $(CFLAGS) -I$(ROOT)/header $^ -o $@
test_gps_nav_phase: test_gps_nav_phase.c
$(CC) $(CFLAGS) -Wno-comment -Ifake_bsp -I$(ROOT)/header $^ -o $@
test_plic_warm_reset: test_plic_warm_reset.c $(ROOT)/../bsp/drivers/plic.c
$(CC) $(CFLAGS) -Ifake_bsp -I$(ROOT)/../bsp/include $^ -o $@
@@ -115,6 +119,7 @@ run: $(TARGETS)
./test_gps_nav_epoch_coalescing
./test_gps_time_anchor
./test_gps_measurement_freshness
./test_gps_nav_phase
./test_plic_warm_reset
./test_gps_acq_manager
./test_gps_ephemeris_cache
@@ -163,6 +168,12 @@ sanitize:
-o test_gps_measurement_freshness_san
ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \
UBSAN_OPTIONS=halt_on_error=1 ./test_gps_measurement_freshness_san
$(CC) -O1 -g -std=c11 -Wall -Wextra -Werror \
-fsanitize=address,undefined -fno-omit-frame-pointer \
-Wno-comment -Ifake_bsp -I$(ROOT)/header \
test_gps_nav_phase.c -o test_gps_nav_phase_san
ASAN_OPTIONS=detect_leaks=1:halt_on_error=1 \
UBSAN_OPTIONS=halt_on_error=1 ./test_gps_nav_phase_san
$(CC) -O1 -g -std=c11 -Wall -Wextra -Werror \
-fsanitize=address,undefined -fno-omit-frame-pointer \
-I$(ROOT)/header test_gps_acq_manager.c \
@@ -285,7 +296,7 @@ clean:
rm -f $(TARGETS) test_gps_nav_epoch_coalescing_repro \
test_gps_nav_epoch_san test_gps_nav_epoch_coalescing_san \
test_gps_time_anchor_san \
test_gps_measurement_freshness_san \
test_gps_measurement_freshness_san test_gps_nav_phase_san \
test_gps_acq_manager_san test_gps_ephemeris_cache_san \
test_gps_almanac_san \
test_gps_flash_journal_san \
@@ -0,0 +1,45 @@
#include <assert.h>
#include <stdint.h>
#include "gps/gps_nav_phase.h"
static uint32_t tracking_control_without_nav_solve_irq(void)
{
return (1u << GPS_TRCK_INTR_EN_POS) |
(1u << GPS_TRCK_NAV_BITS_INTR_EN_POS) |
(1u << GPS_TRCK_NAV_BITS_FLAG_EN_POS) |
(1u << GPS_TRCK_STOP_UNLOCK_EN_POS) |
(1u << GPS_TRCK_UNLOCK_INTR_EN_POS) |
(1u << GPS_TRCK_UNLOCK_FLAG_EN_POS) |
(1u << GPS_TRCK_NAV_SOLVE_EN_POS) |
(1u << GPS_TRCK_MEASUREMENT_INTR_EN_POS) |
(1u << GPS_TRCK_MEASUREMENT_FLAG_EN_POS);
}
int main(void)
{
uint32_t cold_control = tracking_control_without_nav_solve_irq();
assert(!gps_nav_phase_control_armed(cold_control));
assert(!gps_nav_phase_preserve_seed_after_how(true, cold_control));
assert(!gps_nav_phase_preserve_seed_after_how(false, cold_control));
uint32_t flag_only =
cold_control | (1u << GPS_TRCK_NAV_SOLVE_FLAG_EN_POS);
assert(!gps_nav_phase_control_armed(flag_only));
assert(!gps_nav_phase_preserve_seed_after_how(true, flag_only));
uint32_t irq_only =
cold_control | (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS);
assert(!gps_nav_phase_control_armed(irq_only));
assert(!gps_nav_phase_preserve_seed_after_how(true, irq_only));
uint32_t armed_control =
cold_control |
(1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS) |
(1u << GPS_TRCK_NAV_SOLVE_FLAG_EN_POS);
assert(gps_nav_phase_control_armed(armed_control));
assert(gps_nav_phase_preserve_seed_after_how(true, armed_control));
assert(!gps_nav_phase_preserve_seed_after_how(false, armed_control));
return 0;
}
@@ -13,6 +13,11 @@
#define SIM_NAV_PHASE_SEED_TICKS 1u
#define SIM_EPHEMERIS_DECODE_TICKS 18u
#define SIM_ANCHOR_MAX_AGE_TICKS 110u
/* PVT-ready means an orbit/HOW anchor has also seeded the periodic timer. */
#define SIM_COLD_NAV_READY_TICKS \
(SIM_EPHEMERIS_DECODE_TICKS + SIM_NAV_PHASE_SEED_TICKS)
#define SIM_REPARSED_NAV_READY_TICKS \
(SIM_NAV_SUBFRAME_TICKS + SIM_NAV_PHASE_SEED_TICKS)
typedef struct {
gps_acq_manager_t manager;
@@ -163,13 +168,13 @@ static void sim_complete_engine(receiver_sim_t* sim)
SIM_ANCHOR_MAX_AGE_TICKS, &anchor);
sim->nav_ready_tick[prn] = sim->tick +
(direct_seed ? SIM_NAV_PHASE_SEED_TICKS :
SIM_NAV_SUBFRAME_TICKS);
SIM_REPARSED_NAV_READY_TICKS);
}
else
{
cache_ephemeris(sim, prn);
sim->nav_ready_tick[prn] =
sim->tick + SIM_EPHEMERIS_DECODE_TICKS;
sim->tick + SIM_COLD_NAV_READY_TICKS;
}
}
else
@@ -332,7 +337,7 @@ static void test_power_on_without_signal_then_visibility(void)
assert(sim.cache_restores == 0u);
assert(sim.ephemeris_decodes == 1u);
assert(nav_ready_count(&sim) == 0u);
sim_run(&sim, SIM_EPHEMERIS_DECODE_TICKS);
sim_run(&sim, SIM_COLD_NAV_READY_TICKS);
assert(nav_ready_count(&sim) == 1u);
}
@@ -355,7 +360,7 @@ static void test_counter_ambiguous_outage_uses_cached_ephemeris_and_new_how(void
sim_step(&sim);
}
uint64_t cold_nav_wait = sim.tick - cold_tracking_tick;
assert(cold_nav_wait == SIM_EPHEMERIS_DECODE_TICKS);
assert(cold_nav_wait == SIM_COLD_NAV_READY_TICKS);
assert(sim.ephemeris_decodes == 4u);
memset(sim.visible, 0, sizeof(sim.visible));
@@ -383,7 +388,7 @@ static void test_counter_ambiguous_outage_uses_cached_ephemeris_and_new_how(void
sim_step(&sim);
}
uint64_t cached_nav_wait = sim.tick - reacquired_tracking_tick;
assert(cached_nav_wait == SIM_NAV_SUBFRAME_TICKS);
assert(cached_nav_wait == SIM_REPARSED_NAV_READY_TICKS);
assert(sim.ephemeris_decodes == 4u);
assert(cold_nav_wait > cached_nav_wait);
printf("receiver reacquisition telemetry: cold_nav_wait=%lu cached_nav_wait=%lu saved=%lu cache_restores=%u reparses=%u\n",
@@ -505,7 +510,7 @@ static void test_stale_cache_forces_ephemeris_decode(void)
assert(sim.cache_restores == 0u);
assert(sim.ephemeris_decodes == 2u);
assert(sim.nav_ready_tick[3] ==
sim.tick + SIM_EPHEMERIS_DECODE_TICKS);
sim.tick + SIM_COLD_NAV_READY_TICKS);
}
static void test_hot_failures_do_not_starve_cold_search(void)