fix(gps): recover when tracking loss IRQ is missed

This commit is contained in:
2026-07-24 20:33:45 +03:00
parent 86dfbeafac
commit 64860d1ced
2 changed files with 137 additions and 3 deletions
@@ -15,13 +15,17 @@ typedef struct {
gps_ephemeris_cache_t cache;
bool visible[GPS_ACQ_MANAGER_PRN_COUNT];
bool tracked[GPS_ACQ_MANAGER_PRN_COUNT];
bool hardware_busy[GPS_ACQ_MANAGER_PRN_COUNT];
uint64_t invisible_since[GPS_ACQ_MANAGER_PRN_COUNT];
unsigned int not_busy_polls[GPS_ACQ_MANAGER_PRN_COUNT];
bool engine_busy;
bool drop_completion_irq;
bool drop_loss_irq;
unsigned int engine_prn;
uint64_t engine_start;
uint64_t tick;
unsigned int polled_completions;
unsigned int polled_losses;
unsigned int cache_restores;
} receiver_sim_t;
@@ -100,6 +104,8 @@ static void sim_complete_engine(receiver_sim_t* sim)
gps_acq_manager_mark_acquired(&sim->manager, prn);
gps_acq_manager_mark_tracking(&sim->manager, prn);
sim->tracked[prn] = true;
sim->hardware_busy[prn] = true;
sim->not_busy_polls[prn] = 0u;
sim->invisible_since[prn] = 0u;
gps_ephemeris_t restored;
if(gps_ephemeris_cache_restore(
@@ -119,6 +125,14 @@ static void sim_complete_engine(receiver_sim_t* sim)
}
}
static void sim_mark_tracking_lost(receiver_sim_t* sim, unsigned int prn)
{
sim->tracked[prn] = false;
sim->not_busy_polls[prn] = 0u;
gps_acq_manager_mark_lost(
&sim->manager, prn, sim->tick);
}
static void sim_update_tracking(receiver_sim_t* sim)
{
for(unsigned int prn = 0u;
@@ -140,9 +154,25 @@ static void sim_update_tracking(receiver_sim_t* sim)
else if((sim->tick - sim->invisible_since[prn]) >=
SIM_UNLOCK_TICKS)
{
sim->tracked[prn] = false;
gps_acq_manager_mark_lost(
&sim->manager, prn, sim->tick);
sim->hardware_busy[prn] = false;
if(!sim->drop_loss_irq)
{
sim_mark_tracking_lost(sim, prn);
}
}
if(!sim->tracked[prn])
{
continue;
}
if(sim->hardware_busy[prn])
{
sim->not_busy_polls[prn] = 0u;
}
else if(++sim->not_busy_polls[prn] >= 2u)
{
sim->polled_losses++;
sim_mark_tracking_lost(sim, prn);
}
}
}
@@ -307,6 +337,36 @@ static void test_missed_completion_interrupt_is_polled(void)
GPS_ACQ_PRN_TRACKING);
}
static void test_missed_tracking_loss_interrupt_is_reconciled(void)
{
receiver_sim_t sim;
sim_init(&sim);
sim.visible[0] = true;
sim_start_engine(&sim);
sim_run(&sim, SIM_SEARCH_TICKS);
assert(sim.tracked[0]);
sim.drop_loss_irq = true;
sim.visible[0] = false;
sim_run(&sim, SIM_UNLOCK_TICKS + 2u);
assert(!sim.tracked[0]);
assert(sim.polled_losses == 1u);
assert(gps_acq_manager_state(&sim.manager, 0u) ==
GPS_ACQ_PRN_HOT);
sim.visible[0] = true;
sim.drop_loss_irq = false;
unsigned int return_tick = (unsigned int)sim.tick;
while(!sim.tracked[0] &&
((sim.tick - return_tick) <= (2u * SIM_SEARCH_TICKS)))
{
sim_step(&sim);
}
assert(sim.tracked[0]);
assert((sim.tick - return_tick) <= (2u * SIM_SEARCH_TICKS));
assert(sim.cache_restores == 1u);
}
int main(void)
{
test_cold_boot_and_short_signal_gap();
@@ -314,6 +374,7 @@ int main(void)
test_long_outage_hot_reacquisition_and_cached_nav();
test_hot_failures_do_not_starve_cold_search();
test_missed_completion_interrupt_is_polled();
test_missed_tracking_loss_interrupt_is_reconciled();
puts("gps receiver hardware-simulation scenarios passed");
return 0;
}