30179df8e6
Remove the fixed pseudorange start offset, preserve per-PRN navigation assistance across RF loss and power cycles, and seed coherent navigation measurement phase on reacquisition. Add full LNAV almanac visibility scheduling, power-safe QSPI journaling, RF-domain reset isolation, and PPS Gray CDC hardening with Linux, sanitizer, RTL, and end-to-end coverage.
141 lines
4.1 KiB
C
141 lines
4.1 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "gps/gps_ephemeris_cache.h"
|
|
|
|
static gps_ephemeris_t make_ephemeris(
|
|
unsigned int prn,
|
|
unsigned char iode)
|
|
{
|
|
gps_ephemeris_t ephemeris;
|
|
memset(&ephemeris, 0, sizeof(ephemeris));
|
|
ephemeris.SVID = (unsigned char)prn;
|
|
ephemeris.iode = iode;
|
|
ephemeris.ephemeris_valid = true;
|
|
ephemeris.toe.week = 2430;
|
|
ephemeris.toe.sec = 123456.0;
|
|
return ephemeris;
|
|
}
|
|
|
|
static void test_store_restore_and_expiry(void)
|
|
{
|
|
gps_ephemeris_cache_t cache;
|
|
gps_ephemeris_cache_init(&cache, 100u);
|
|
gps_ephemeris_t input = make_ephemeris(4u, 17u);
|
|
gps_ephemeris_t output;
|
|
memset(&output, 0, sizeof(output));
|
|
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 4u, &input, 1000u));
|
|
input.iode = 99u;
|
|
assert(gps_ephemeris_cache_restore(
|
|
&cache, 4u, 1100u, &output));
|
|
assert(output.iode == 17u);
|
|
assert(output.SVID == 4u);
|
|
assert(!gps_ephemeris_cache_restore(
|
|
&cache, 4u, 1101u, &output));
|
|
/* Expiration invalidates the slot, not only this read. */
|
|
assert(!gps_ephemeris_cache_restore(
|
|
&cache, 4u, 1001u, &output));
|
|
}
|
|
|
|
static void test_validation_independence_and_invalidate(void)
|
|
{
|
|
gps_ephemeris_cache_t cache;
|
|
gps_ephemeris_cache_init(&cache, 500u);
|
|
gps_ephemeris_t prn4 = make_ephemeris(4u, 21u);
|
|
gps_ephemeris_t prn19 = make_ephemeris(19u, 44u);
|
|
gps_ephemeris_t output;
|
|
|
|
prn4.ephemeris_valid = false;
|
|
assert(!gps_ephemeris_cache_store(
|
|
&cache, 4u, &prn4, 0u));
|
|
prn4.ephemeris_valid = true;
|
|
assert(!gps_ephemeris_cache_store(
|
|
&cache, 5u, &prn4, 0u));
|
|
assert(!gps_ephemeris_cache_store(
|
|
&cache, GPS_PRN_COUNT, &prn4, 0u));
|
|
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 4u, &prn4, 20u));
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 19u, &prn19, 30u));
|
|
assert(gps_ephemeris_cache_restore(
|
|
&cache, 19u, 40u, &output));
|
|
assert(output.iode == 44u);
|
|
|
|
gps_ephemeris_cache_invalidate(&cache, 4u);
|
|
assert(!gps_ephemeris_cache_restore(
|
|
&cache, 4u, 40u, &output));
|
|
assert(gps_ephemeris_cache_restore(
|
|
&cache, 19u, 40u, &output));
|
|
}
|
|
|
|
static void test_repeated_issue_does_not_hide_staleness(void)
|
|
{
|
|
gps_ephemeris_cache_t cache;
|
|
gps_ephemeris_cache_init(&cache, 100u);
|
|
gps_ephemeris_t issue17 = make_ephemeris(6u, 17u);
|
|
gps_ephemeris_t output;
|
|
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 6u, &issue17, 1000u));
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 6u, &issue17, 1090u));
|
|
assert(!gps_ephemeris_cache_restore(
|
|
&cache, 6u, 1101u, &output));
|
|
|
|
/* A changed IOD is a fresh broadcast issue and receives a new TTL. */
|
|
issue17.iode = 18u;
|
|
issue17.iodc = 18u;
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 6u, &issue17, 1200u));
|
|
assert(gps_ephemeris_cache_restore(
|
|
&cache, 6u, 1300u, &output));
|
|
assert(output.iode == 18u);
|
|
}
|
|
|
|
static void test_time_anchor_is_independent_and_short_lived(void)
|
|
{
|
|
gps_ephemeris_cache_t cache;
|
|
gps_ephemeris_cache_init(&cache, 1000u);
|
|
gps_ephemeris_t ephemeris = make_ephemeris(11u, 9u);
|
|
gps_cached_time_anchor_t anchor = {
|
|
.tow = {.week = 2430, .sec = 345678.0},
|
|
.raw_sample = 0xffff0000u,
|
|
.corrected_sample = 4294901759.75,
|
|
.week_valid = true,
|
|
.valid = true
|
|
};
|
|
gps_cached_time_anchor_t restored;
|
|
|
|
/* An anchor cannot outlive or exist without its ephemeris slot. */
|
|
assert(!gps_ephemeris_cache_store_time_anchor(
|
|
&cache, 11u, &anchor, 50u));
|
|
assert(gps_ephemeris_cache_store(
|
|
&cache, 11u, &ephemeris, 50u));
|
|
assert(gps_ephemeris_cache_store_time_anchor(
|
|
&cache, 11u, &anchor, 60u));
|
|
assert(gps_ephemeris_cache_restore_time_anchor(
|
|
&cache, 11u, 170u, 110u, &restored));
|
|
assert(restored.tow.week == 2430);
|
|
assert(restored.raw_sample == 0xffff0000u);
|
|
assert(!gps_ephemeris_cache_restore_time_anchor(
|
|
&cache, 11u, 171u, 110u, &restored));
|
|
/* The two-hour-class ephemeris remains usable after the short counter
|
|
* anchor expires; firmware then waits for one fresh HOW, not SF1/2/3. */
|
|
assert(gps_ephemeris_cache_restore(
|
|
&cache, 11u, 171u, &ephemeris));
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
test_store_restore_and_expiry();
|
|
test_validation_independence_and_invalidate();
|
|
test_repeated_issue_does_not_hide_staleness();
|
|
test_time_anchor_is_independent_and_short_lived();
|
|
puts("gps ephemeris cache tests passed");
|
|
return 0;
|
|
}
|