#include #include #include #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.iodc = iode; ephemeris.ephemeris_valid = true; ephemeris.sva = 2u; ephemeris.sqrta = 5153.6; ephemeris.A = ephemeris.sqrta * ephemeris.sqrta; ephemeris.ecc = 0.008; ephemeris.toe.week = 2430; ephemeris.toe_week_valid = true; ephemeris.toe.sec = 123456.0; ephemeris.toc.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_store_if_new_reports_real_changes_only(void) { gps_ephemeris_cache_t cache; gps_ephemeris_cache_init(&cache, 1000u); gps_ephemeris_t eph = make_ephemeris(9u, 30u); bool changed = true; assert(gps_ephemeris_cache_store_if_new(&cache, 9u, &eph, 10u, &changed)); assert(changed); /* Re-decoding the same data set refreshes the age datum but reports no * change, so no flash write is triggered. */ assert(gps_ephemeris_cache_store_if_new(&cache, 9u, &eph, 20u, &changed)); assert(!changed); gps_ephemeris_t output; assert(gps_ephemeris_cache_restore(&cache, 9u, 1019u, &output)); assert(output.iode == 30u); /* A newer upload is a real change. */ gps_ephemeris_t newer = make_ephemeris(9u, 31u); newer.toe.sec = eph.toe.sec + 7200.0; assert(gps_ephemeris_cache_store_if_new(&cache, 9u, &newer, 30u, &changed)); assert(changed); assert(gps_ephemeris_cache_restore(&cache, 9u, 30u, &output)); assert(output.iode == 31u); /* An out-of-order older upload is rejected outright. */ assert(!gps_ephemeris_cache_store_if_new(&cache, 9u, &eph, 40u, &changed)); assert(!changed); assert(gps_ephemeris_cache_restore(&cache, 9u, 40u, &output)); assert(output.iode == 31u); /* A structurally invalid record never enters the cache. */ gps_ephemeris_t corrupt = make_ephemeris(10u, 5u); corrupt.iodc = 6u; assert(!gps_ephemeris_cache_store_if_new(&cache, 10u, &corrupt, 50u, &changed)); assert(!changed); } static void test_restore_at_applies_fit_window(void) { gps_ephemeris_cache_t cache; gps_ephemeris_cache_init(&cache, 1000000u); gps_ephemeris_t eph = make_ephemeris(12u, 44u); gps_ephemeris_t output; bool changed = false; assert(gps_ephemeris_cache_store_if_new(&cache, 12u, &eph, 0u, &changed)); /* Inside the four hour curve fit. */ assert(gps_ephemeris_cache_restore_at(&cache, 12u, 10u, true, 2430, eph.toe.sec + 3600.0, &output)); assert(output.iode == 44u); /* Without receiver time the record stays available as a candidate. */ assert(gps_ephemeris_cache_restore_at(&cache, 12u, 10u, false, 0, 0.0, &output)); /* Past the fit interval the entry is rejected and dropped, so a later * in-window query cannot resurrect it. */ assert(!gps_ephemeris_cache_restore_at(&cache, 12u, 10u, true, 2430, eph.toe.sec + 9000.0, &output)); assert(!gps_ephemeris_cache_restore_at(&cache, 12u, 10u, true, 2430, eph.toe.sec, &output)); assert(!gps_ephemeris_cache_restore(&cache, 12u, 10u, &output)); } int main(void) { test_store_restore_and_expiry(); test_validation_independence_and_invalidate(); test_store_if_new_reports_real_changes_only(); test_restore_at_applies_fit_window(); puts("gps ephemeris cache tests passed"); return 0; }