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
+33 -20
View File
@@ -923,7 +923,8 @@ yollarini calistirir.
- Firmware nav bit interrupt'lari ile subframe verisini surekli toplar.
- Bir tracking kanali ancak IODC/IODE degerleri eslesen subframe 1, 2 ve 3 seti atomik olarak commit edildikten sonra navigation-ready olur. Subframe 4 ve 5 ilk fix'i bloke etmez; page 18 iyonosfer/UTC ve almanak verisi arka planda toplanmaya devam eder.
- En az 4 satellite icin tutarli ephemeris commit edilince nav-bit snapshot'i yalniz ephemeris uygunlugunu ve kullanilacak kanallari belirler; bu snapshot'tan pozisyon hesaplanmaz.
- Tutarlı ephemerisi hazir olan tracking kanallarinda nav-solve akisi etkinlestirilir:
- Tutarlı ephemerisi hazir olan ve HOW/sample anchor'indan hardware phase seed'i
tamamlanmis tracking kanallarinda nav-solve akisi etkinlestirilir:
- nav bits interrupt/flag acik kalir,
- `NAV_SOLVE_INTR_EN=1`,
- `NAV_SOLVE_FLAG_EN=1`.
@@ -945,10 +946,12 @@ epoch'lara koyar. Coalescent snapshot ayni receiver zamanina ait olcumler ister;
farkli epoch'lari yalniz software interrupt zamanina bakarak birlestirmek
pseudorange ve position scatter hatasi yaratir.
Cached reacquisition yolu bu nedenle su sirayi izler:
HOW-anchor phase seed yolu bu nedenle hem cold ephemeris decode sonrasinda hem
cached reacquisition sonrasinda su sirayi izler:
1. Fresh ephemeris ile birlikte saklanan week-qualified HOW TOW, corrected/raw
RF sample ve CPU systick anchor'i yeni tracking kanalina restore edilir.
1. Cold yolda parity-valid live HOW TOW, corrected/raw RF sample ve CPU systick
anchor'i commit edilir. Cached yolda ayni bilgiler yeni tracking kanalina
restore edilir.
2. Background software kopyasi yerine channel'in en yeni atomik 20 ms hardware
measurement mailbox'i okunur; PRN, valid ve lock alanlari dogrulanir.
3. Anchor, bu measurement'in GPS zamanina tasinir ve global bit numarasi ile
@@ -963,9 +966,10 @@ phase = global_bit mod GPS_NAV_SOLVE_TIMER_TICKS
yazilir. RTL bu yazma darbesiyle `IDLE` durumundan dogrudan `COUNT` durumuna
gecer. Yazma sirasinda mailbox sequence ilerlemisse interrupt acilmaz; yeni
mailbox ile sonraki background turunda yeniden seed edilir.
5. Stable seed sonrasinda nav-solve flag ve interrupt acilir. Her channel'in
lokal counter'i artik ayni global GPS bit numarasinin modulo-N fazini
tasidigi icin sonraki wrap darbeleri ayni coalescent epoch'ta olusur.
5. Stable seed sonrasinda nav-solve flag ve interrupt acilir ve tracking node
`gps_nav_phase_seeded=true` olur. Her channel'in lokal counter'i artik ayni
global GPS bit numarasinin modulo-N fazini tasidigi icin sonraki wrap
darbeleri ayni coalescent epoch'ta olusur.
Bu register ephemeris cache'in yerine gecmez ve TOW uretmez; cache'deki zaman
anchor'ini RTL'nin periodic measurement fazina uygular. Epoch assembler yine
@@ -975,15 +979,16 @@ basina hatali kanallari zorla ayni solution'a sokmaz.
Cold start'ta fresh flash assistance da yoksa RAM cache ve valid HOW/sample
anchor olmadigi icin phase tahmin edilmez. Orijinal parity-valid LNAV/HOW yolu
kullanilir ve SF1/SF2/SF3 ephemerisi decode edilir. Fresh flash ephemerisi
varsa ilk live subframe zaman/issue kontrolunden sonra orbit restore edilir,
fakat power-cycle oncesi HOW/sample anchor yine kullanilmaz. RF sample
counter'in resetlenmesi veya RF clock'un
durmasi halinde CPU systick ile RF elapsed-time kontrolu uyusmaz; ephemeris
cache korunur fakat unsafe phase seed reddedilir ve en fazla bir yeni HOW
beklenerek guvenli hizalama yapilir. `GPS_NAV_SOLVE_TIMER_TICKS`, hem 300-bit
subframe'i hem 30240000-bit GPS haftasini tam bolecek sekilde compile-time'da
kontrol edildigi icin week rollover da ortak fazi bozmaz.
kullanilir, SF1/SF2/SF3 ephemerisi decode edilir ve ayni live HOW/sample
anchor'i ile `NAV_SOLVE_PHASE` seed edilir. Fresh flash ephemerisi varsa ilk
live subframe zaman/issue kontrolunden sonra orbit restore edilir, fakat
power-cycle oncesi HOW/sample anchor yine kullanilmaz. RF sample counter'in
resetlenmesi veya RF clock'un durmasi halinde CPU systick ile RF elapsed-time
kontrolu uyusmaz; ephemeris cache korunur fakat unsafe phase seed reddedilir ve
en fazla bir yeni HOW beklenerek guvenli hizalama yapilir.
`GPS_NAV_SOLVE_TIMER_TICKS`, hem 300-bit subframe'i hem 30240000-bit GPS
haftasini tam bolecek sekilde compile-time'da kontrol edildigi icin week
rollover da ortak fazi bozmaz.
- Ilk pozisyon dahil butun pozisyon hesaplari, kanallardan senkron nav-solve tick ve `ABS_SAMPLE` geldikten sonra olusturulan coherent nav-solve snapshot'i ile yapilir.
- Nav-bit ve nav-solve handler'lari canli ephemeris deposunu ortak kullansa da her kabul edilen nav-solve event'i corrected `ABS_SAMPLE`, TOW ve o anda commit edilmis ephemerisin tam kopyasini aktif epoch snapshot'ina birlikte yazar. WLS daha sonra canli node listesinden ephemeris okumaz; araya giren nav-bit interrupt'i eski olcumle yeni ephemerisi karistiramaz.
@@ -994,9 +999,9 @@ kontrol edildigi icin week rollover da ortak fazi bozmaz.
- Subframe 1 `toc` alani parity bitleri disarida birakilarak 16 bit okunur ve `2^4` ile olceklenir.
- Subframe 4 page 18 henuz alinmadiysa iyonosfer duzeltmesi uygulanmaz. Page 18 hazir oldugunda her navigation solve tek bir `ionoutc` kopyasi kullanir.
- Klobuchar gecikmesi WLS'nin receiver ECEF, azimut ve elevasyon hesabindan uretilir. Ilk unseeded iteration iyonosfersizdir; yaklasik receiver konumu olustuktan sonraki iteration'larda gecikme gozlenen pseudorange'dan cikarilir.
- Bundan sonra periyodik pozisyon hesaplamasi nav-solve interrupt'lari ile tetiklenir. RTL cold/HOW yolunda `subframe_ready`, cached reacquisition yolunda ise `NAV_SOLVE_PHASE` write pulse'u sonrasinda COUNT durumuna girer ve `NAV_SOLVE_TIMER=N` icin N adet navigation `bit_valid` darbesi sayar. Her navigation biti 20 ms oldugu icin periyot `N * 20 ms`'dir; firmware `GPS_NAV_SOLVE_TIMER_TICKS` build ayarini `gps_startup_initialization()` fonksiyonuna verir.
- Bu siralama onemlidir: cold/HOW yolunda RTL `nav_solve_timer` sayaci `NAV_SOLVE_EN` ve ilk gecerli `subframe_ready` ile baslar. `NAV_SOLVE_EN` nav-bit asamasinda acik tutulur; tutarli subframe 1..3 ephemerisi commit edilene kadar yalniz nav-solve interrupt/flag kapali kalir. Cached yol ayni COUNT durumunu explicit global-bit phase ile baslatir. Timer COUNT durumuna girdikten sonra sonraki subframe darbeleri sayaci sifirlamaz veya yeniden fazlamaz.
- Tracking kanallari farkli zamanlarda lock olabilir ve ilk gecerli subframe'lerini 6 saniyenin farkli katlarinda gorebilir. Timer bu nedenle ilk subframe'in HOW alanindaki 17-bit Z-count degerini kullanarak `Z_COUNT * 300 mod NAV_SOLVE_TIMER` baslangic fazini hesaplar. Hesap ALIGN durumunda 26 PCLK cevriminde ard arda modulo ile yapilir; 20 ms'lik ilk navigation bitinden cok once tamamlanir. RTL ayni GPS haftasi icinde keyfi pozitif `N` degerlerini hizalayabilir; firmware hem subframe/HOW hem week rollover boyunca ortak fazi korumak icin `300 mod N == 0` ve `30240000 mod N == 0` kosullarini compile-time'da zorunlu tutar. Ornegin `N=10`, `N=25`, `N=50`, `N=75`, `N=100`, `N=150` ve `N=300` gecerlidir; kosullari saglamayan build acik bir `#error` ile durur.
- Bundan sonra periyodik pozisyon hesaplamasi nav-solve interrupt'lari ile tetiklenir. Current internal-timer RTL'de cold ve cached yollarin ikisi de `NAV_SOLVE_PHASE` write pulse'u sonrasinda ortak global-bit fazina hizalanir; yalniz `NAV_SOLVE_INTR_EN` acmak timer'lari hizalamaz. `NAV_SOLVE_TIMER=N` icin N adet navigation `bit_valid` darbesi sayilir. Her navigation biti 20 ms oldugu icin periyot `N * 20 ms`'dir; firmware `GPS_NAV_SOLVE_TIMER_TICKS` build ayarini `gps_startup_initialization()` fonksiyonuna verir.
- Bu siralama onemlidir: `NAV_SOLVE_EN` nav-bit asamasinda acik tutulabilir, fakat tutarli subframe 1..3 ephemerisi ve hardware phase seed tamamlanmadan kanal navigation-ready sayilmaz. Stable seed sonrasinda nav-solve interrupt/flag acilir. Timer COUNT durumuna girdikten sonra sonraki subframe darbeleri sayaci sifirlamaz veya yeniden fazlamaz.
- Tracking kanallari farkli zamanlarda lock olabilir ve ilk gecerli subframe'lerini 6 saniyenin farkli katlarinda gorebilir. Bu nedenle hepsini counter zero'dan baslatmak farkli fiziksel epoch'larda interrupt uretir. Firmware her kanali live/cached HOW anchor'i ile en yeni 20 ms measurement mailbox'ina tasir ve `round(TOW / 0.020) mod NAV_SOLVE_TIMER` fazini yazar. Firmware hem subframe/HOW hem week rollover boyunca ortak fazi korumak icin `300 mod N == 0` ve `30240000 mod N == 0` kosullarini compile-time'da zorunlu tutar. Ornegin `N=10`, `N=25`, `N=50`, `N=75`, `N=100`, `N=150` ve `N=300` gecerlidir; kosullari saglamayan build acik bir `#error` ile durur.
- Initial position sonrasinda subframe'lerini tamamlayan yeni tracking kanallarinda da nav bits acik tutularak nav-solve otomatik etkinlestirilir.
- Coherence kontrolu sadece software systick ile yapilmaz; periodic snapshot icin tracking node'da saklanan nav-solve interrupt sonrasi raw `ABS_SAMPLE` kullanilir. `GPS_NAV_ABS_SAMPLE_SYNC_WINDOW_MS=25` oldugu icin 4 satellite measurement'i 25 ms'den fazla ayriksa navigation solve calistirilmaz. Bu pencere interrupt skew'den cok uydu path delay farkini kapsamak icindir: 20 ms yaklasik 6000 km, 25 ms yaklasik 7500 km pseudorange farkina denk gelir. 25 ms, dusuk-elevation uydu geometrisi ve tracking jitter icin pay birakir ama 50 ms kadar gevsek degildir.
- Interrupt'lar epoch'a GPS TOW ile degil, butun kanallarda ortak olan 64-bit PPS capture counter ile atanir. Ilk olcum sabit expected maskeyi ve 30 ms bounded holdoff'u baslatir. 25 ms pencereye giren kanallar ayni fiziksel epoch'a katilir; yarim nav periyodundan uzaktaki eski/yeni capture'lar stale veya yeni epoch olarak siniflanir. Boylece bozuk bir gelecek HOW degeri epoch assembler'i kilitleyemez.
@@ -1222,7 +1227,15 @@ olarak yayinlanir.
- `POSTPONE_TOW=0.180` mevcut RTL'nin dokuzuncu takip eden navigation bitinde
yaptigi teslimi duzeltir. `satpos()` ve PPS receive-time anchor bu degeri
tam bir kez ve ayni firmware surumunde kullanir.
- Ilk nav-solve interrupt'i geldiginde o anda allocated, hardware busy ve nav-solve interrupt'i etkin olan kanallar epoch'un sabit bekleme maskesine alinir. Unlock interrupt'i gelen kanal artik tracked olmadigi icin bekleme maskesinden cikarilir; epoch ortasinda navigation-ready olan yeni kanal ise aktif maskeyi buyutmez ve sonraki epoch'tan itibaren beklenir. Kalan beklenen kanallarin tamami gelirse snapshot son interrupt'ta hemen yayinlanir. 30 ms holdoff dolarsa veya daha yeni fiziksel epoch baslarsa eksik eski epoch WLS calistirilmadan discard edilir; eski ve yeni olcumler birlestirilmez.
- Ilk nav-solve interrupt'i geldiginde o anda allocated, hardware busy, lock'lu,
ephemeris-valid, measurement-fresh ve phase-seeded kanallar epoch'un sabit
bekleme maskesine alinir. Unlock interrupt'i gelen kanal artik tracked
olmadigi icin bekleme maskesinden cikarilir; epoch ortasinda
navigation-ready olan yeni kanal ise aktif maskeyi buyutmez ve sonraki
epoch'tan itibaren beklenir. Kalan beklenen kanallarin tamami gelirse
snapshot son interrupt'ta hemen yayinlanir. 30 ms holdoff dolarsa veya daha
yeni fiziksel epoch baslarsa eksik eski epoch WLS calistirilmadan discard
edilir; eski ve yeni olcumler birlestirilmez.
- Interrupt bekleme maskesi tamamlandiktan sonra frozen kanallarin tumu ortak TOW/`ABS_SAMPLE` kumesinde degilse epoch reddedilir. Selector'in buldugu daha kucuk alt kume yalniz diagnostic bilgidir ve WLS girdisi olamaz.
- Dort uydu 3D konum + receiver clock bias icin minimum ve yeterlidir. Bu durumda
`dof=N-4=0` oldugu icin WLS konumu publish edilir fakat residual chi-square
@@ -0,0 +1,22 @@
#ifndef GPS_NAV_PHASE_H
#define GPS_NAV_PHASE_H
#include <stdbool.h>
#include <stdint.h>
#include "gps/gps_ip_defines.h"
static inline bool gps_nav_phase_control_armed(uint32_t control)
{
return ((control & (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS)) != 0u) &&
((control & (1u << GPS_TRCK_NAV_SOLVE_FLAG_EN_POS)) != 0u);
}
static inline bool gps_nav_phase_preserve_seed_after_how(
bool previously_seeded,
uint32_t control)
{
return previously_seeded && gps_nav_phase_control_armed(control);
}
#endif
@@ -7,6 +7,7 @@
#include "gps/Navigation.h"
#include "gps/NavEquations.h"
#include "gps/gps_nav_epoch.h"
#include "gps/gps_nav_phase.h"
#include "gps/gps_pps.h"
#include "gps/gps_time_anchor.h"
#include "gps/gps_visibility.h"
@@ -233,15 +234,35 @@ static bool gps_copy_latest_tracking_measurement(
static uint32_t gps_nav_ready_channel_mask(void)
{
uint32_t ready_mask = 0u;
uint64_t now = gps_get_systick();
for(unsigned int i = 0u ; i < GPS_TRCK_IP_COUNT ; i++)
{
uint32_t status = trck_ips[i]->STATUS_REG;
uint32_t control = trck_ips[i]->CONTROL_REG;
volatile gps_ephem_ll_t* node =
get_element_by_ip_number(&tracking_node, i);
bool busy = (status & (1u << GPS_TRCK_BUSY_POS)) != 0u;
bool locked = (status & (1u << GPS_TRCK_LOCK_POS)) != 0u;
bool nav_irq_enabled =
(control & (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS)) != 0u;
if(tracking_allocated[i] && busy && locked && nav_irq_enabled)
bool usable_ephemeris =
(node != NULL) &&
(node->data_p != NULL) &&
node->data_p->ephemeris_valid &&
(node->data_p->SVID == trck_ips[i]->PRN_NUMBER) &&
(node->data_p->update == 0u) &&
(node->data_p->svhlth == 0u) &&
(node->data_p->sva < 15u) &&
(node->data_p->A > 0.0) &&
(node->data_p->ecc >= 0.0) &&
(node->data_p->ecc < 1.0);
bool fresh_measurement =
(node != NULL) &&
gps_measurement_freshness_usable(
&node->gps_measurement_freshness,
now, GPS_TRK_MEASUREMENT_STALE_TICKS);
if(tracking_allocated[i] && busy && locked &&
gps_nav_phase_control_armed(control) &&
(node != NULL) && node->gps_nav_phase_seeded &&
usable_ephemeris && fresh_measurement)
{
ready_mask |= 1u << i;
}
@@ -1489,6 +1510,10 @@ static void gps_commit_how_anchor(volatile gps_ephem_ll_t* node,
const gps_isr_event_t* event,
bool week_valid)
{
bool preserve_phase_seed =
gps_nav_phase_preserve_seed_after_how(
node->gps_nav_phase_seeded,
event->control);
node->gps_how_tow.week = week;
node->gps_how_tow.sec = tow_sec;
node->gps_how_abs_sample = event->abs_sample_raw;
@@ -1496,7 +1521,11 @@ static void gps_commit_how_anchor(volatile gps_ephem_ll_t* node,
node->gps_how_tick = event->tick;
node->gps_how_anchor_valid = true;
node->gps_how_week_valid = week_valid;
node->gps_nav_phase_seeded = true;
/* A HOW/sample anchor is only the information needed to seed the hardware
* periodic timer. Cold channels reach this point before NAV_SOLVE_PHASE
* has been written, so they must stay unseeded until the background pass
* aligns the timer from the newest 20 ms mailbox. */
node->gps_nav_phase_seeded = preserve_phase_seed;
node->gps_pending_how_valid = false;
if((node->data_p != NULL) && gps_prn_valid(node->data_p->SVID))
{
@@ -2308,7 +2337,7 @@ static unsigned int gps_prn_for_tracking_channel(
return GPS_PRN_INVALID;
}
static void gps_seed_cached_nav_timers(void)
static void gps_seed_nav_timers_from_how_anchor(void)
{
const double bit_period_sec =
(double)GPS_NAV_SOLVE_TIMER_TICK_MS / 1000.0;
@@ -2383,7 +2412,7 @@ static void gps_seed_cached_nav_timers(void)
&local_elapsed_sec))
{
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_NAV,
"cached NAV timer not seeded after RF counter discontinuity: trk=%u prn=%u rf_elapsed=%.3f local_elapsed=%.3f\r\n",
"NAV timer not seeded after RF counter discontinuity: trk=%u prn=%u rf_elapsed=%.3f local_elapsed=%.3f\r\n",
trck_ip_no, node->data_p->SVID,
anchor_elapsed_sec, local_elapsed_sec);
node->gps_how_anchor_valid = false;
@@ -2434,7 +2463,7 @@ static void gps_seed_cached_nav_timers(void)
trck_enable_nav_solve_flag(trck_ips[trck_ip_no]);
trck_enable_nav_solve_intr(trck_ips[trck_ip_no]);
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_NAV,
"phase-seeded cached NAV timer: trk=%u prn=%u phase=%u week=%d tow=%.3f abs=%u\r\n",
"phase-seeded NAV timer: trk=%u prn=%u phase=%u week=%d tow=%.3f abs=%u\r\n",
trck_ip_no, node->data_p->SVID, phase,
measurement_week, measurement_tow_sec,
measurement.absolute_sample);
@@ -2487,7 +2516,7 @@ void gps_background_task(void)
gps_poll_acq_pending_completions();
gps_poll_tracking_pending_events();
gps_process_isr_events();
gps_seed_cached_nav_timers();
gps_seed_nav_timers_from_how_anchor();
if(gps_take_timer_maintenance_pending())
{
gps_pps_service();
+4 -2
View File
@@ -10,6 +10,7 @@
#include "gps/gps_interrupt_handlers.h"
#include "gps/gps_assistance_store.h"
#include "gps/gps_nav_epoch.h"
#include "gps/gps_nav_phase.h"
#include "gps/gps_pps.h"
#include "gps/gps_time_anchor.h"
#include "gps/defines.h"
@@ -576,7 +577,8 @@ static bool gps_node_ready_for_position(volatile gps_ephem_ll_t* node)
}
if(!gps_tracking_ip_alive(node->tracking_ip_no) ||
!gps_node_has_committed_ephemeris(node))
!gps_node_has_committed_ephemeris(node) ||
!node->gps_nav_phase_seeded)
{
return false;
}
@@ -596,7 +598,7 @@ static bool gps_node_ready_for_position(volatile gps_ephem_ll_t* node)
static bool gps_channel_nav_solve_enabled(unsigned char trck_ip_no)
{
return (trck_ips[trck_ip_no]->CONTROL_REG & (1u << GPS_TRCK_NAV_SOLVE_INTR_EN_POS)) != 0u;
return gps_nav_phase_control_armed(trck_ips[trck_ip_no]->CONTROL_REG);
}
static void gps_set_channel_nav_solve_mode(unsigned char trck_ip_no)
+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)