fix(gps): make acquisition and reacquisition deterministic
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gps/gps_acq_manager.h"
|
||||
|
||||
static gps_acq_manager_t make_manager(
|
||||
uint64_t retry_delay,
|
||||
uint64_t hot_retry_delay,
|
||||
uint64_t hot_window,
|
||||
unsigned int max_hot_streak)
|
||||
{
|
||||
gps_acq_manager_t manager;
|
||||
const gps_acq_manager_config_t config = {
|
||||
.retry_delay_ticks = retry_delay,
|
||||
.hot_retry_delay_ticks = hot_retry_delay,
|
||||
.hot_window_ticks = hot_window,
|
||||
.max_hot_streak = max_hot_streak
|
||||
};
|
||||
gps_acq_manager_init(&manager, &config);
|
||||
return manager;
|
||||
}
|
||||
|
||||
static unsigned int start_next(
|
||||
gps_acq_manager_t* manager,
|
||||
uint64_t now,
|
||||
bool expected_hot)
|
||||
{
|
||||
unsigned int prn = GPS_ACQ_MANAGER_INVALID_PRN;
|
||||
bool hot = !expected_hot;
|
||||
assert(gps_acq_manager_start_next(manager, now, &prn, &hot));
|
||||
assert(hot == expected_hot);
|
||||
return prn;
|
||||
}
|
||||
|
||||
static void test_cold_round_robin_and_retry_from_tick_zero(void)
|
||||
{
|
||||
gps_acq_manager_t manager =
|
||||
make_manager(5u, 5u, 100u, 4u);
|
||||
assert(gps_acq_manager_enable_cold(&manager, 0u));
|
||||
assert(gps_acq_manager_enable_cold(&manager, 1u));
|
||||
assert(gps_acq_manager_enable_cold(&manager, 2u));
|
||||
|
||||
assert(start_next(&manager, 0u, false) == 0u);
|
||||
/* A tick-zero attempt is real and must still observe retry delay. */
|
||||
gps_acq_manager_mark_failed(&manager, 0u, 0u);
|
||||
assert(start_next(&manager, 0u, false) == 1u);
|
||||
gps_acq_manager_mark_failed(&manager, 1u, 0u);
|
||||
assert(start_next(&manager, 0u, false) == 2u);
|
||||
gps_acq_manager_mark_failed(&manager, 2u, 0u);
|
||||
|
||||
unsigned int ignored;
|
||||
assert(!gps_acq_manager_start_next(
|
||||
&manager, 4u, &ignored, NULL));
|
||||
assert(start_next(&manager, 5u, false) == 0u);
|
||||
}
|
||||
|
||||
static void test_hot_priority_round_robin_and_cold_fairness(void)
|
||||
{
|
||||
gps_acq_manager_t manager =
|
||||
make_manager(1u, 1u, 100u, 2u);
|
||||
assert(gps_acq_manager_enable_cold(&manager, 0u));
|
||||
assert(gps_acq_manager_enable_cold(&manager, 1u));
|
||||
gps_acq_manager_mark_lost(&manager, 7u, 10u);
|
||||
gps_acq_manager_mark_lost(&manager, 8u, 10u);
|
||||
|
||||
assert(start_next(&manager, 10u, true) == 7u);
|
||||
gps_acq_manager_mark_failed(&manager, 7u, 11u);
|
||||
assert(start_next(&manager, 11u, true) == 8u);
|
||||
gps_acq_manager_mark_failed(&manager, 8u, 12u);
|
||||
|
||||
/* Two hot attempts force one cold discovery attempt. */
|
||||
assert(start_next(&manager, 12u, false) == 0u);
|
||||
gps_acq_manager_mark_failed(&manager, 0u, 13u);
|
||||
assert(start_next(&manager, 13u, true) == 7u);
|
||||
}
|
||||
|
||||
static void test_expired_hot_becomes_cold_and_tracking_is_excluded(void)
|
||||
{
|
||||
gps_acq_manager_t manager =
|
||||
make_manager(1u, 1u, 10u, 4u);
|
||||
assert(gps_acq_manager_enable_cold(&manager, 2u));
|
||||
gps_acq_manager_mark_lost(&manager, 9u, 20u);
|
||||
|
||||
unsigned int prn = start_next(&manager, 31u, false);
|
||||
assert(prn == 2u);
|
||||
gps_acq_manager_mark_tracking(&manager, prn);
|
||||
|
||||
prn = start_next(&manager, 31u, false);
|
||||
assert(prn == 9u);
|
||||
gps_acq_manager_mark_acquired(&manager, prn);
|
||||
unsigned int ignored;
|
||||
assert(!gps_acq_manager_start_next(
|
||||
&manager, 100u, &ignored, NULL));
|
||||
|
||||
gps_acq_manager_mark_tracking(&manager, 9u);
|
||||
gps_acq_manager_mark_stale(&manager, 9u);
|
||||
assert(gps_acq_manager_state(&manager, 9u) ==
|
||||
GPS_ACQ_PRN_STALE);
|
||||
gps_acq_manager_mark_lost(&manager, 9u, 101u);
|
||||
assert(gps_acq_manager_state(&manager, 9u) ==
|
||||
GPS_ACQ_PRN_HOT);
|
||||
}
|
||||
|
||||
static void test_invalid_inputs_are_safe(void)
|
||||
{
|
||||
gps_acq_manager_t manager =
|
||||
make_manager(1u, 1u, 10u, 0u);
|
||||
assert(!gps_acq_manager_enable_cold(
|
||||
&manager, GPS_ACQ_MANAGER_PRN_COUNT));
|
||||
assert(gps_acq_manager_state(
|
||||
&manager, GPS_ACQ_MANAGER_PRN_COUNT) ==
|
||||
GPS_ACQ_PRN_DISABLED);
|
||||
assert(!gps_acq_manager_start_next(NULL, 0u, NULL, NULL));
|
||||
assert(gps_acq_manager_count_searchable(NULL) == 0u);
|
||||
}
|
||||
|
||||
static void test_failed_hot_search_is_backed_off(void)
|
||||
{
|
||||
gps_acq_manager_t manager =
|
||||
make_manager(1u, 30u, 100u, 4u);
|
||||
assert(gps_acq_manager_enable_cold(&manager, 0u));
|
||||
gps_acq_manager_mark_lost(&manager, 20u, 0u);
|
||||
|
||||
assert(start_next(&manager, 0u, true) == 20u);
|
||||
gps_acq_manager_mark_failed(&manager, 20u, 5u);
|
||||
assert(start_next(&manager, 5u, false) == 0u);
|
||||
gps_acq_manager_mark_failed(&manager, 0u, 6u);
|
||||
assert(start_next(&manager, 7u, false) == 0u);
|
||||
gps_acq_manager_mark_failed(&manager, 0u, 8u);
|
||||
|
||||
assert(start_next(&manager, 35u, true) == 20u);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_cold_round_robin_and_retry_from_tick_zero();
|
||||
test_hot_priority_round_robin_and_cold_fairness();
|
||||
test_expired_hot_becomes_cold_and_tracking_is_excluded();
|
||||
test_invalid_inputs_are_safe();
|
||||
test_failed_hot_search_is_backed_off();
|
||||
puts("gps acquisition manager tests passed");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user