#include #include #include #include #include #include #include "gps/gps_assistance_data.h" static gps_ephemeris_t make_ephemeris( unsigned int prn, int current_week, double toe_sec, unsigned int issue) { gps_ephemeris_t ephemeris; memset(&ephemeris, 0, sizeof(ephemeris)); ephemeris.WN = (unsigned int)current_week & 0x3ffu; ephemeris.toe.sec = toe_sec; ephemeris.toc.sec = toe_sec; ephemeris.sqrta = 5153.795; ephemeris.A = ephemeris.sqrta * ephemeris.sqrta; ephemeris.ecc = 0.01; ephemeris.iodc = issue; ephemeris.iode = (unsigned char)issue; ephemeris.SVID = (unsigned char)prn; ephemeris.ephemeris_valid = true; ephemeris.abs_sample = 123456789.25; return ephemeris; } static void test_fresh_mixed_ephemeris_restore_and_true_remaining_age(void) { const gpstime_t saved_time = {.week = 2300, .sec = 100000.0}; gps_ephemeris_cache_t source; gps_ephemeris_cache_init(&source, GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS); for(unsigned int prn = 0u ; prn < 7u ; prn++) { double age_sec = (prn == 6u) ? 3.0 * 3600.0 : (double)(prn + 1u) * 600.0; gps_ephemeris_t ephemeris = make_ephemeris( prn, saved_time.week, saved_time.sec - age_sec, 40u + prn); assert(gps_ephemeris_cache_store( &source, prn, &ephemeris, 100u)); } gps_almanac_cache_t source_almanac; gps_almanac_cache_init( &source_almanac, GPS_ALMANAC_CACHE_MAX_AGE_TICKS); gps_assistance_payload_t payload; gps_assistance_payload_build( &payload, &source, &source_almanac, NULL, NULL, saved_time); assert(payload.ephemeris[0].abs_sample == 0.0); gps_ephemeris_cache_t restored_cache; gps_ephemeris_cache_init( &restored_cache, GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS); gps_almanac_cache_t restored_almanac; gps_almanac_cache_init( &restored_almanac, GPS_ALMANAC_CACHE_MAX_AGE_TICKS); gps_assistance_restore_result_t result; const uint64_t boot_now = 10u; assert(gps_assistance_restore( &payload, saved_time, boot_now, &restored_cache, &restored_almanac, &result)); assert(result.ephemeris_mask == UINT32_C(0x3f)); assert(!restored_cache.entry[0].time_anchor.valid); gps_ephemeris_t output; assert(gps_ephemeris_cache_restore( &restored_cache, 0u, boot_now, &output)); /* PRN0 was already 10 minutes old. It has 110 minutes, not a newly * granted two hours, after reboot. */ uint64_t remaining_ticks = GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS - 600u * GPS_SYSTICK_HZ; assert(gps_ephemeris_cache_restore( &restored_cache, 0u, boot_now + remaining_ticks, &output)); assert(!gps_ephemeris_cache_restore( &restored_cache, 0u, boot_now + remaining_ticks + 1u, &output)); } static void test_issue_check_is_per_satellite_and_per_subframe(void) { gps_ephemeris_t ephemeris = make_ephemeris(3u, 2300, 90000.0, 0x155u); unsigned int words[10] = {0}; words[2] = ((ephemeris.iodc >> 8) & 0x03u) << 6; words[7] = (ephemeris.iodc & 0xffu) << 22; assert(gps_assistance_ephemeris_issue_matches( &ephemeris, 1u, words)); words[7] ^= UINT32_C(1) << 22; assert(!gps_assistance_ephemeris_issue_matches( &ephemeris, 1u, words)); memset(words, 0, sizeof(words)); words[2] = (uint32_t)ephemeris.iode << 22; assert(gps_assistance_ephemeris_issue_matches( &ephemeris, 2u, words)); words[2] += UINT32_C(1) << 22; assert(!gps_assistance_ephemeris_issue_matches( &ephemeris, 2u, words)); assert(gps_assistance_ephemeris_issue_matches( &ephemeris, 4u, words)); } static void test_iono_position_and_almanac_independent_staleness(void) { const gpstime_t saved_time = {.week = 2400, .sec = 200000.0}; gps_ephemeris_cache_t source; gps_ephemeris_cache_init(&source, GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS); gps_almanac_cache_t almanac; gps_almanac_cache_init(&almanac, GPS_ALMANAC_CACHE_MAX_AGE_TICKS); almanac.reference_valid = true; almanac.reference_week_mod256 = (unsigned int)saved_time.week & 0xffu; almanac.reference_toa_sec = saved_time.sec - 86400.0; almanac.reference_tick = 50u; ionoutc_t ionoutc = {.enable = true, .vflg = true, .dtls = 18}; gps_assistance_position_t position = { .ecef_m = {4200000.0, 2800000.0, 3900000.0}, .latitude_deg = 41.0, .longitude_deg = 29.0, .height_m = 100.0, .gps_time = saved_time, .valid = true }; gps_assistance_payload_t payload; gps_assistance_payload_build( &payload, &source, &almanac, &ionoutc, &position, saved_time); gps_ephemeris_cache_t output_eph; gps_almanac_cache_t output_almanac; gps_ephemeris_cache_init( &output_eph, GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS); gps_almanac_cache_init( &output_almanac, GPS_ALMANAC_CACHE_MAX_AGE_TICKS); gps_assistance_restore_result_t result; gpstime_t current = saved_time; current.sec += 2.0 * 86400.0; assert(gps_assistance_restore( &payload, current, 20u, &output_eph, &output_almanac, &result)); assert(result.almanac_restored); assert(result.ionoutc_restored); assert(result.position_restored); assert(result.ionoutc.dtls == 18); /* Eight days rejects almanac and iono, while a coarse position remains a * safe acquisition/WLS seed under the separate 30-day policy. */ current = saved_time; current.week += 1; current.sec += 86400.0; if(current.sec >= 604800.0) { current.sec -= 604800.0; current.week++; } gps_ephemeris_cache_init( &output_eph, GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS); gps_almanac_cache_init( &output_almanac, GPS_ALMANAC_CACHE_MAX_AGE_TICKS); assert(gps_assistance_restore( &payload, current, 20u, &output_eph, &output_almanac, &result)); assert(!result.almanac_restored); assert(!result.ionoutc_restored); assert(result.position_restored); } int main(void) { test_fresh_mixed_ephemeris_restore_and_true_remaining_age(); test_issue_check_is_per_satellite_and_per_subframe(); test_iono_position_and_almanac_independent_staleness(); puts("gps assistance freshness/issue tests passed"); return 0; }