Fix GPS acquisition visibility and pull-in edge cases
This commit is contained in:
+2
-2
@@ -213,7 +213,7 @@ always_ff @(posedge acq_clk or negedge acq_rstn)
|
|||||||
S_PULLIN : begin
|
S_PULLIN : begin
|
||||||
pullin_flag <= 1;
|
pullin_flag <= 1;
|
||||||
if (pullin_flag == 0) begin
|
if (pullin_flag == 0) begin
|
||||||
freq_bin_cnt <= max_freq_bin_idx - 1;
|
freq_bin_cnt <= (max_freq_bin_idx == 0) ? 0 : (max_freq_bin_idx - 1);
|
||||||
max_corr <= 0;
|
max_corr <= 0;
|
||||||
//STATE <= S_START;
|
//STATE <= S_START;
|
||||||
STATE <= S_WR_DATA;
|
STATE <= S_WR_DATA;
|
||||||
@@ -314,7 +314,7 @@ always_ff @(posedge afe_clk or negedge afe_rstn) begin
|
|||||||
wr_mem_end <= 0;
|
wr_mem_end <= 0;
|
||||||
if (sample_align_i && wr_mem_start_r2) begin
|
if (sample_align_i && wr_mem_start_r2) begin
|
||||||
wr_mem_en <= 1;
|
wr_mem_en <= 1;
|
||||||
end else if (rf_wr_addr == 2*SAMPLES_PER_CODE) begin // 2 code lenght
|
end else if (rf_wr_addr == 2*SAMPLES_PER_CODE - 1) begin // 2 code length
|
||||||
wr_mem_en <= 0;
|
wr_mem_en <= 0;
|
||||||
wr_mem_end <= 1;
|
wr_mem_end <= 1;
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -895,8 +895,9 @@ era base'i (`2048`) kullanilir. Sonra:
|
|||||||
ile kullanilir ve sonraki issue-bearing page yine mismatch kontrolu yapar,
|
ile kullanilir ve sonraki issue-bearing page yine mismatch kontrolu yapar,
|
||||||
- almanak `WNa/toa` age'i yedi gunden eskiyse, iono/UTC snapshot'i yedi gunden
|
- almanak `WNa/toa` age'i yedi gunden eskiyse, iono/UTC snapshot'i yedi gunden
|
||||||
eskiyse reddedilir; son konum coarse seed olarak en fazla 30 gun tutulur,
|
eskiyse reddedilir; son konum coarse seed olarak en fazla 30 gun tutulur,
|
||||||
- fresh complete almanak + konum varsa sky scheduler live TOW ile hemen
|
- fresh complete almanak + restored konum WLS/coarse seed olarak kullanilir, fakat
|
||||||
guncellenir. Partial/stale almanakta davranis yine tum 32 PRN round-robin'dir.
|
sky scheduler'i PRN suppression moduna sokmaz; bunun icin live position gerekir.
|
||||||
|
Partial/stale almanakta davranis yine tum 32 PRN round-robin'dir.
|
||||||
|
|
||||||
Combined full-device MCS programlama islemi programmer erase politikasi
|
Combined full-device MCS programlama islemi programmer erase politikasi
|
||||||
nedeniyle runtime journal'i silebilir; bu yeni firmware'in normal QSPI runtime
|
nedeniyle runtime journal'i silebilir; bu yeni firmware'in normal QSPI runtime
|
||||||
|
|||||||
@@ -80,8 +80,9 @@
|
|||||||
* Probe one unknown PRN at a controlled rate until tracking capacity is
|
* Probe one unknown PRN at a controlled rate until tracking capacity is
|
||||||
* filled; do not let one failing predicted-visible PRN block discovery. */
|
* filled; do not let one failing predicted-visible PRN block discovery. */
|
||||||
#define GPS_ACQ_UNKNOWN_PROBE_TICKS (GPS_SYSTICK_HZ * 2u)
|
#define GPS_ACQ_UNKNOWN_PROBE_TICKS (GPS_SYSTICK_HZ * 2u)
|
||||||
#define GPS_ACQ_VISIBILITY_PROBE_TICKS (GPS_SYSTICK_HZ * 60u)
|
#define GPS_ACQ_VISIBILITY_PROBE_TICKS (GPS_SYSTICK_HZ * 5u)
|
||||||
#define GPS_ACQ_MIN_ELEVATION_DEG 5.0
|
#define GPS_ACQ_MIN_ELEVATION_DEG 5.0
|
||||||
|
#define GPS_ACQ_MIN_SKY_MODEL_VISIBLE_COUNT 6u
|
||||||
#define GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS \
|
#define GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS \
|
||||||
(GPS_SYSTICK_HZ * 2u * 60u * 60u)
|
(GPS_SYSTICK_HZ * 2u * 60u * 60u)
|
||||||
/* Almanac is a coarse acquisition aid. Reject RAM records that have
|
/* Almanac is a coarse acquisition aid. Reject RAM records that have
|
||||||
@@ -91,6 +92,7 @@
|
|||||||
#define GPS_ACQ_STATUS_LOG_PERIOD_TICKS (GPS_SYSTICK_HZ * 5u)
|
#define GPS_ACQ_STATUS_LOG_PERIOD_TICKS (GPS_SYSTICK_HZ * 5u)
|
||||||
#define GPS_NAV_STATUS_LOG_PERIOD_TICKS GPS_SYSTICK_HZ
|
#define GPS_NAV_STATUS_LOG_PERIOD_TICKS GPS_SYSTICK_HZ
|
||||||
#define GPS_TRK_MEASUREMENT_STALE_TICKS (GPS_SYSTICK_HZ * 3u)
|
#define GPS_TRK_MEASUREMENT_STALE_TICKS (GPS_SYSTICK_HZ * 3u)
|
||||||
|
#define GPS_TRK_MEASUREMENT_LIVENESS_TICKS (GPS_SYSTICK_HZ * 2u)
|
||||||
#define GPS_NAV_ABS_SAMPLE_SYNC_WINDOW_MS 25u
|
#define GPS_NAV_ABS_SAMPLE_SYNC_WINDOW_MS 25u
|
||||||
#define GPS_NAV_EPOCH_HOLDOFF_MS 30u
|
#define GPS_NAV_EPOCH_HOLDOFF_MS 30u
|
||||||
#define GPS_NAV_TOW_CLUSTER_TOLERANCE_SEC 0.001
|
#define GPS_NAV_TOW_CLUSTER_TOLERANCE_SEC 0.001
|
||||||
@@ -113,6 +115,8 @@
|
|||||||
#endif
|
#endif
|
||||||
_Static_assert((GPS_NAV_ENABLE_FDE == 0u) || (GPS_NAV_ENABLE_FDE == 1u),
|
_Static_assert((GPS_NAV_ENABLE_FDE == 0u) || (GPS_NAV_ENABLE_FDE == 1u),
|
||||||
"GPS_NAV_ENABLE_FDE must be zero or one");
|
"GPS_NAV_ENABLE_FDE must be zero or one");
|
||||||
|
_Static_assert(GPS_ACQ_MIN_SKY_MODEL_VISIBLE_COUNT <= GPS_PRN_COUNT,
|
||||||
|
"sky-model visible count threshold exceeds PRN count");
|
||||||
|
|
||||||
#if (ACQ_ENGINE_COUNT < 1UL)
|
#if (ACQ_ENGINE_COUNT < 1UL)
|
||||||
#error "ACQ_ENGINE_COUNT must be at least 1"
|
#error "ACQ_ENGINE_COUNT must be at least 1"
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ static gps_acq_result_t acq_shadow_result[GPS_ACQ_IP_COUNT];
|
|||||||
static gps_tracking_shadow_t trk_shadow[GPS_TRCK_IP_COUNT];
|
static gps_tracking_shadow_t trk_shadow[GPS_TRCK_IP_COUNT];
|
||||||
static gps_tracking_measurement_t
|
static gps_tracking_measurement_t
|
||||||
gps_latest_tracking_measurement[GPS_TRCK_IP_COUNT];
|
gps_latest_tracking_measurement[GPS_TRCK_IP_COUNT];
|
||||||
|
static volatile uint64_t
|
||||||
|
gps_latest_tracking_measurement_tick[GPS_TRCK_IP_COUNT];
|
||||||
|
|
||||||
static volatile unsigned char satellite_tracking_ip[GPS_PRN_COUNT];
|
static volatile unsigned char satellite_tracking_ip[GPS_PRN_COUNT];
|
||||||
static gps_acq_result_t satellite_acq_result[GPS_PRN_COUNT];
|
static gps_acq_result_t satellite_acq_result[GPS_PRN_COUNT];
|
||||||
@@ -200,6 +202,8 @@ static void gps_update_tracking_measurement_isr(
|
|||||||
}
|
}
|
||||||
measurement.local_timestamp_ticks = local_timestamp_ticks;
|
measurement.local_timestamp_ticks = local_timestamp_ticks;
|
||||||
gps_latest_tracking_measurement[tracking_index] = measurement;
|
gps_latest_tracking_measurement[tracking_index] = measurement;
|
||||||
|
gps_latest_tracking_measurement_tick[tracking_index] =
|
||||||
|
gps_get_systick();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool gps_copy_latest_tracking_measurement(
|
static bool gps_copy_latest_tracking_measurement(
|
||||||
@@ -433,6 +437,7 @@ static void gps_clear_tracking_slot(unsigned char trck_ip_no)
|
|||||||
memset((void*)&gps_subframes[trck_ip_no][0], 0, sizeof(gps_subframes[trck_ip_no]));
|
memset((void*)&gps_subframes[trck_ip_no][0], 0, sizeof(gps_subframes[trck_ip_no]));
|
||||||
memset(&gps_latest_tracking_measurement[trck_ip_no], 0,
|
memset(&gps_latest_tracking_measurement[trck_ip_no], 0,
|
||||||
sizeof(gps_latest_tracking_measurement[trck_ip_no]));
|
sizeof(gps_latest_tracking_measurement[trck_ip_no]));
|
||||||
|
gps_latest_tracking_measurement_tick[trck_ip_no] = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gps_set_tracking_nav_bits_mode(unsigned char trck_ip_no)
|
static void gps_set_tracking_nav_bits_mode(unsigned char trck_ip_no)
|
||||||
@@ -666,6 +671,25 @@ void gps_acq_update_visibility_hint(
|
|||||||
predicted_visible, priority);
|
predicted_visible, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(visible_count < GPS_ACQ_MIN_SKY_MODEL_VISIBLE_COUNT)
|
||||||
|
{
|
||||||
|
for(unsigned int prn = 0u ; prn < GPS_PRN_COUNT ; prn++)
|
||||||
|
{
|
||||||
|
(void)gps_acq_manager_set_visibility(
|
||||||
|
&gps_acq_manager, prn, false, false, 0);
|
||||||
|
}
|
||||||
|
gps_acq_manager_set_visibility_mode(
|
||||||
|
&gps_acq_manager, false, now);
|
||||||
|
gps_last_visibility_update_tick = now;
|
||||||
|
gps_acq_schedule_pending = true;
|
||||||
|
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_SCHED,
|
||||||
|
"acquisition sky model rejected: predicted_visible=%u min=%u known=%u ephemeris=%u almanac=%u policy=all_prn_round_robin\r\n",
|
||||||
|
visible_count, GPS_ACQ_MIN_SKY_MODEL_VISIBLE_COUNT,
|
||||||
|
known_count, ephemeris_orbit_count,
|
||||||
|
almanac_orbit_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gps_acq_manager_set_visibility_mode(
|
gps_acq_manager_set_visibility_mode(
|
||||||
&gps_acq_manager, true, now);
|
&gps_acq_manager, true, now);
|
||||||
gps_last_visibility_update_tick = now;
|
gps_last_visibility_update_tick = now;
|
||||||
@@ -873,6 +897,55 @@ static bool gps_tracking_prn_active(unsigned int prn_no)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool gps_tracking_prn_measurement_alive(
|
||||||
|
unsigned int prn_no,
|
||||||
|
unsigned char* trck_ip_no_out)
|
||||||
|
{
|
||||||
|
if(!gps_prn_valid(prn_no))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t now = gps_get_systick();
|
||||||
|
for(unsigned char i = 0 ; i < GPS_TRCK_IP_COUNT ; i++)
|
||||||
|
{
|
||||||
|
volatile gps_trck_t* trk = trck_ips[i];
|
||||||
|
uint32_t status = trk->STATUS_REG;
|
||||||
|
bool busy = (status & (1u << GPS_TRCK_BUSY_POS)) != 0u;
|
||||||
|
bool locked = (status & (1u << GPS_TRCK_LOCK_POS)) != 0u;
|
||||||
|
bool stop_unlock =
|
||||||
|
(status & (1u << GPS_TRCK_STOP_UNLOCK_POS)) != 0u;
|
||||||
|
bool allocated =
|
||||||
|
tracking_allocated[i] || trck_ip_exists(&tracking_node, i);
|
||||||
|
if(!(allocated || busy) || (trk->PRN_NUMBER != prn_no) ||
|
||||||
|
!busy || !locked || stop_unlock)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t irq_state = bsp_irq_save();
|
||||||
|
uint64_t last_tick = gps_latest_tracking_measurement_tick[i];
|
||||||
|
bsp_irq_restore(irq_state);
|
||||||
|
if((last_tick == 0u) || (now < last_tick) ||
|
||||||
|
((now - last_tick) > GPS_TRK_MEASUREMENT_LIVENESS_TICKS))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
gps_tracking_measurement_t measurement;
|
||||||
|
if(gps_copy_latest_tracking_measurement(i, prn_no, &measurement) &&
|
||||||
|
measurement.locked)
|
||||||
|
{
|
||||||
|
if(trck_ip_no_out != NULL)
|
||||||
|
{
|
||||||
|
*trck_ip_no_out = i;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void gps_mark_satellite_tracking(unsigned int prn_no, unsigned char trck_ip_no)
|
static void gps_mark_satellite_tracking(unsigned int prn_no, unsigned char trck_ip_no)
|
||||||
{
|
{
|
||||||
if(gps_prn_valid(prn_no))
|
if(gps_prn_valid(prn_no))
|
||||||
@@ -1507,14 +1580,6 @@ static void gps_process_tracking_nav_bits(const gps_isr_event_t* event)
|
|||||||
(const unsigned int*)gps_subframe, how_tow_sec,
|
(const unsigned int*)gps_subframe, how_tow_sec,
|
||||||
event->tick, &gps_ephemeris_cache, &gps_almanac_cache,
|
event->tick, &gps_ephemeris_cache, &gps_almanac_cache,
|
||||||
&restored_ephemeris, &restored_position, &assistance_time);
|
&restored_ephemeris, &restored_position, &assistance_time);
|
||||||
if(restored_position.valid)
|
|
||||||
{
|
|
||||||
gps_acq_update_visibility_hint(
|
|
||||||
restored_position.ecef_m,
|
|
||||||
restored_position.latitude_deg,
|
|
||||||
restored_position.longitude_deg,
|
|
||||||
assistance_time);
|
|
||||||
}
|
|
||||||
if(restore_approved &&
|
if(restore_approved &&
|
||||||
!gps_frame_parsed->gps_ephems.ephemeris_valid)
|
!gps_frame_parsed->gps_ephems.ephemeris_valid)
|
||||||
{
|
{
|
||||||
@@ -1993,11 +2058,24 @@ static void gps_reconcile_tracked_prns(void)
|
|||||||
{
|
{
|
||||||
for(unsigned int prn = 0 ; prn < GPS_PRN_COUNT ; prn++)
|
for(unsigned int prn = 0 ; prn < GPS_PRN_COUNT ; prn++)
|
||||||
{
|
{
|
||||||
|
gps_acq_prn_state_t state =
|
||||||
|
gps_acq_manager_state(&gps_acq_manager, prn);
|
||||||
|
unsigned char recovered_trk_ip = GPS_PRN_INVALID;
|
||||||
|
bool stale_alive =
|
||||||
|
(state == GPS_ACQ_PRN_STALE) &&
|
||||||
|
gps_tracking_prn_measurement_alive(
|
||||||
|
prn, &recovered_trk_ip);
|
||||||
if(gps_tracking_prn_active(prn) &&
|
if(gps_tracking_prn_active(prn) &&
|
||||||
(gps_acq_manager_state(&gps_acq_manager, prn) !=
|
((state != GPS_ACQ_PRN_STALE) || stale_alive))
|
||||||
GPS_ACQ_PRN_STALE))
|
|
||||||
{
|
{
|
||||||
gps_acq_manager_mark_tracking(&gps_acq_manager, prn);
|
if(state == GPS_ACQ_PRN_STALE)
|
||||||
|
{
|
||||||
|
gps_mark_satellite_tracking(prn, recovered_trk_ip);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gps_acq_manager_mark_tracking(&gps_acq_manager, prn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS ?= -O2 -std=c11 -Wall -Wextra -Werror
|
CFLAGS ?= -O2 -std=c11 -Wall -Wextra -Werror
|
||||||
|
PYTHON ?= python3
|
||||||
|
|
||||||
ROOT := ..
|
ROOT := ..
|
||||||
TARGETS := test_imu_calibration test_gps_nav_epoch \
|
TARGETS := test_imu_calibration test_gps_nav_epoch \
|
||||||
@@ -18,7 +19,7 @@ TARGETS += test_gps_flash_journal
|
|||||||
TARGETS += test_gps_assistance_data
|
TARGETS += test_gps_assistance_data
|
||||||
TARGETS += test_gps_assistance_store
|
TARGETS += test_gps_assistance_store
|
||||||
|
|
||||||
.PHONY: all run sanitize clean
|
.PHONY: all run python-models sanitize clean
|
||||||
|
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
@@ -128,6 +129,10 @@ run: $(TARGETS)
|
|||||||
./test_gps_pps_quality
|
./test_gps_pps_quality
|
||||||
./test_gps_pps_adaptive_loop
|
./test_gps_pps_adaptive_loop
|
||||||
./test_gps_visibility
|
./test_gps_visibility
|
||||||
|
$(PYTHON) test_acq_search_model.py
|
||||||
|
|
||||||
|
python-models:
|
||||||
|
$(PYTHON) test_acq_search_model.py
|
||||||
|
|
||||||
sanitize:
|
sanitize:
|
||||||
$(CC) -O1 -g -std=c11 -Wall -Wextra -Werror \
|
$(CC) -O1 -g -std=c11 -Wall -Wextra -Werror \
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Model-level checks for acquisition search edge cases."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
TEST_DIR = Path(__file__).resolve().parent
|
||||||
|
REPO_ROOT = TEST_DIR.parents[3]
|
||||||
|
DEFINITIONS = REPO_ROOT / "hardware/external/gps/rtl/common/definitions.sv"
|
||||||
|
ACQ_TOP = REPO_ROOT / "hardware/external/gps/rtl/acq_src/acq_top.sv"
|
||||||
|
|
||||||
|
|
||||||
|
def read_parameters(path):
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
params = {}
|
||||||
|
parameter_re = (
|
||||||
|
r"parameter\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([^;]+);"
|
||||||
|
)
|
||||||
|
for match in re.finditer(parameter_re, text):
|
||||||
|
value = match.group(2).strip()
|
||||||
|
if re.fullmatch(r"\d+", value):
|
||||||
|
params[match.group(1)] = int(value)
|
||||||
|
elif re.fullmatch(r"\d+\.\d+", value):
|
||||||
|
params[match.group(1)] = float(value)
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
def check(condition, message):
|
||||||
|
if not condition:
|
||||||
|
raise AssertionError(message)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
params = read_parameters(DEFINITIONS)
|
||||||
|
acq_top = ACQ_TOP.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
samples_per_code = params["SAMPLES_PER_CODE"]
|
||||||
|
num_freq_bin = params["NUM_FREQ_BIN"]
|
||||||
|
freq_bin_wl = params["FREQ_BIN_WL"]
|
||||||
|
dopp_step = params["DOPP_STEP"]
|
||||||
|
pullin_freq_step = params["PULLIN_FREQ_STEP"]
|
||||||
|
num_pullin = params["NUM_PULLIN"]
|
||||||
|
acq_base_freq = params["ACQ_BASE_FREQ"]
|
||||||
|
|
||||||
|
check(samples_per_code == 16368, "unexpected sample count model")
|
||||||
|
check(num_freq_bin == 41, "unexpected coarse Doppler bin count")
|
||||||
|
check(num_pullin == 11, "unexpected pull-in bin count")
|
||||||
|
check(dopp_step == 500, "unexpected coarse Doppler step")
|
||||||
|
check(pullin_freq_step == 100, "unexpected pull-in Doppler step")
|
||||||
|
check(acq_base_freq == 4082000, "unexpected acquisition base frequency")
|
||||||
|
|
||||||
|
check(
|
||||||
|
"freq_bin_cnt <= (max_freq_bin_idx == 0) ? 0 : "
|
||||||
|
"(max_freq_bin_idx - 1);" in acq_top,
|
||||||
|
"RTL must saturate pull-in search at coarse bin zero",
|
||||||
|
)
|
||||||
|
check(
|
||||||
|
"rf_wr_addr == 2*SAMPLES_PER_CODE - 1" in acq_top,
|
||||||
|
"RTL must capture exactly two 1 ms code windows",
|
||||||
|
)
|
||||||
|
|
||||||
|
max_encoded_bin = (1 << freq_bin_wl) - 1
|
||||||
|
legacy_bin_zero_start = (0 - 1) & max_encoded_bin
|
||||||
|
check(
|
||||||
|
legacy_bin_zero_start >= num_freq_bin,
|
||||||
|
"legacy bin-zero decrement no longer demonstrates an out-of-range wrap",
|
||||||
|
)
|
||||||
|
|
||||||
|
covered_frequencies = set()
|
||||||
|
for coarse_bin in range(num_freq_bin):
|
||||||
|
pullin_start = 0 if coarse_bin == 0 else coarse_bin - 1
|
||||||
|
check(0 <= pullin_start < num_freq_bin, "pull-in start out of coarse range")
|
||||||
|
|
||||||
|
coarse_frequency = acq_base_freq + dopp_step * coarse_bin
|
||||||
|
for pullin_bin in range(num_pullin):
|
||||||
|
pullin_frequency = (
|
||||||
|
acq_base_freq +
|
||||||
|
dopp_step * pullin_start +
|
||||||
|
pullin_freq_step * pullin_bin
|
||||||
|
)
|
||||||
|
covered_frequencies.add(pullin_frequency)
|
||||||
|
if coarse_bin == 0:
|
||||||
|
check(
|
||||||
|
pullin_frequency >= acq_base_freq,
|
||||||
|
"coarse bin zero pull-in searched below the table",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
check(
|
||||||
|
coarse_frequency - dopp_step <= pullin_frequency <=
|
||||||
|
coarse_frequency + dopp_step,
|
||||||
|
"pull-in search does not cover the expected +/-500 Hz window",
|
||||||
|
)
|
||||||
|
|
||||||
|
lowest_expected = acq_base_freq
|
||||||
|
highest_expected = (
|
||||||
|
acq_base_freq +
|
||||||
|
dopp_step * (num_freq_bin - 2) +
|
||||||
|
pullin_freq_step * (num_pullin - 1)
|
||||||
|
)
|
||||||
|
check(min(covered_frequencies) == lowest_expected, "unexpected low search edge")
|
||||||
|
check(max(covered_frequencies) == highest_expected, "unexpected high search edge")
|
||||||
|
check(len(covered_frequencies) >= num_freq_bin * 5, "pull-in coverage collapsed")
|
||||||
|
|
||||||
|
last_sample_written = (2 * samples_per_code) - 1
|
||||||
|
check(last_sample_written == 32735, "unexpected two-code capture fencepost")
|
||||||
|
|
||||||
|
print(
|
||||||
|
"ACQ search model PASS: "
|
||||||
|
f"coarse_bins={num_freq_bin} pullin_bins={num_pullin} "
|
||||||
|
f"freq_range={lowest_expected}..{highest_expected}Hz "
|
||||||
|
f"last_sample={last_sample_written}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -21,6 +21,7 @@ typedef struct {
|
|||||||
bool visible[GPS_ACQ_MANAGER_PRN_COUNT];
|
bool visible[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
bool tracked[GPS_ACQ_MANAGER_PRN_COUNT];
|
bool tracked[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
bool hardware_busy[GPS_ACQ_MANAGER_PRN_COUNT];
|
bool hardware_busy[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
|
bool measurement_alive[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
uint64_t invisible_since[GPS_ACQ_MANAGER_PRN_COUNT];
|
uint64_t invisible_since[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
uint64_t nav_ready_tick[GPS_ACQ_MANAGER_PRN_COUNT];
|
uint64_t nav_ready_tick[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
unsigned int not_busy_polls[GPS_ACQ_MANAGER_PRN_COUNT];
|
unsigned int not_busy_polls[GPS_ACQ_MANAGER_PRN_COUNT];
|
||||||
@@ -63,7 +64,9 @@ static unsigned int nav_ready_count(const receiver_sim_t* sim)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sim_init(receiver_sim_t* sim)
|
static void sim_init_with_visibility_probe(
|
||||||
|
receiver_sim_t* sim,
|
||||||
|
uint64_t visibility_probe_ticks)
|
||||||
{
|
{
|
||||||
memset(sim, 0, sizeof(*sim));
|
memset(sim, 0, sizeof(*sim));
|
||||||
const gps_acq_manager_config_t config = {
|
const gps_acq_manager_config_t config = {
|
||||||
@@ -71,7 +74,7 @@ static void sim_init(receiver_sim_t* sim)
|
|||||||
.hot_retry_delay_ticks = 30u,
|
.hot_retry_delay_ticks = 30u,
|
||||||
.hot_window_ticks = 7200u,
|
.hot_window_ticks = 7200u,
|
||||||
.unknown_probe_interval_ticks = 2u,
|
.unknown_probe_interval_ticks = 2u,
|
||||||
.visibility_probe_interval_ticks = 60u,
|
.visibility_probe_interval_ticks = visibility_probe_ticks,
|
||||||
.max_hot_streak = 4u
|
.max_hot_streak = 4u
|
||||||
};
|
};
|
||||||
gps_acq_manager_init(&sim->manager, &config);
|
gps_acq_manager_init(&sim->manager, &config);
|
||||||
@@ -87,6 +90,11 @@ static void sim_init(receiver_sim_t* sim)
|
|||||||
sim->engine_prn = GPS_ACQ_MANAGER_INVALID_PRN;
|
sim->engine_prn = GPS_ACQ_MANAGER_INVALID_PRN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sim_init(receiver_sim_t* sim)
|
||||||
|
{
|
||||||
|
sim_init_with_visibility_probe(sim, 60u);
|
||||||
|
}
|
||||||
|
|
||||||
static void cache_ephemeris(receiver_sim_t* sim, unsigned int prn)
|
static void cache_ephemeris(receiver_sim_t* sim, unsigned int prn)
|
||||||
{
|
{
|
||||||
gps_ephemeris_t ephemeris;
|
gps_ephemeris_t ephemeris;
|
||||||
@@ -141,6 +149,7 @@ static void sim_complete_engine(receiver_sim_t* sim)
|
|||||||
gps_acq_manager_mark_tracking(&sim->manager, prn);
|
gps_acq_manager_mark_tracking(&sim->manager, prn);
|
||||||
sim->tracked[prn] = true;
|
sim->tracked[prn] = true;
|
||||||
sim->hardware_busy[prn] = true;
|
sim->hardware_busy[prn] = true;
|
||||||
|
sim->measurement_alive[prn] = true;
|
||||||
sim->not_busy_polls[prn] = 0u;
|
sim->not_busy_polls[prn] = 0u;
|
||||||
sim->invisible_since[prn] = 0u;
|
sim->invisible_since[prn] = 0u;
|
||||||
gps_ephemeris_t restored;
|
gps_ephemeris_t restored;
|
||||||
@@ -173,6 +182,7 @@ static void sim_complete_engine(receiver_sim_t* sim)
|
|||||||
static void sim_mark_tracking_lost(receiver_sim_t* sim, unsigned int prn)
|
static void sim_mark_tracking_lost(receiver_sim_t* sim, unsigned int prn)
|
||||||
{
|
{
|
||||||
sim->tracked[prn] = false;
|
sim->tracked[prn] = false;
|
||||||
|
sim->measurement_alive[prn] = false;
|
||||||
sim->nav_ready_tick[prn] = 0u;
|
sim->nav_ready_tick[prn] = 0u;
|
||||||
sim->not_busy_polls[prn] = 0u;
|
sim->not_busy_polls[prn] = 0u;
|
||||||
gps_acq_manager_mark_lost(
|
gps_acq_manager_mark_lost(
|
||||||
@@ -201,6 +211,7 @@ static void sim_update_tracking(receiver_sim_t* sim)
|
|||||||
SIM_UNLOCK_TICKS)
|
SIM_UNLOCK_TICKS)
|
||||||
{
|
{
|
||||||
sim->hardware_busy[prn] = false;
|
sim->hardware_busy[prn] = false;
|
||||||
|
sim->measurement_alive[prn] = false;
|
||||||
if(!sim->drop_loss_irq)
|
if(!sim->drop_loss_irq)
|
||||||
{
|
{
|
||||||
sim_mark_tracking_lost(sim, prn);
|
sim_mark_tracking_lost(sim, prn);
|
||||||
@@ -223,6 +234,29 @@ static void sim_update_tracking(receiver_sim_t* sim)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int manager_count_state(
|
||||||
|
const receiver_sim_t* sim,
|
||||||
|
gps_acq_prn_state_t state)
|
||||||
|
{
|
||||||
|
return gps_acq_manager_count_state(&sim->manager, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sim_reconcile_stale_locked_measurements(receiver_sim_t* sim)
|
||||||
|
{
|
||||||
|
for(unsigned int prn = 0u;
|
||||||
|
prn < GPS_ACQ_MANAGER_PRN_COUNT;
|
||||||
|
prn++)
|
||||||
|
{
|
||||||
|
if((gps_acq_manager_state(&sim->manager, prn) ==
|
||||||
|
GPS_ACQ_PRN_STALE) &&
|
||||||
|
sim->hardware_busy[prn] &&
|
||||||
|
sim->measurement_alive[prn])
|
||||||
|
{
|
||||||
|
gps_acq_manager_mark_tracking(&sim->manager, prn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void sim_step(receiver_sim_t* sim)
|
static void sim_step(receiver_sim_t* sim)
|
||||||
{
|
{
|
||||||
sim->tick++;
|
sim->tick++;
|
||||||
@@ -566,6 +600,79 @@ static void test_incomplete_almanac_keeps_full_round_robin(void)
|
|||||||
sim.search_attempts[5u]);
|
sim.search_attempts[5u]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_wrong_sky_model_safety_probe_finds_real_satellites(void)
|
||||||
|
{
|
||||||
|
receiver_sim_t sim;
|
||||||
|
sim_init_with_visibility_probe(&sim, 5u);
|
||||||
|
for(unsigned int prn = 0u;
|
||||||
|
prn < GPS_ACQ_MANAGER_PRN_COUNT;
|
||||||
|
prn++)
|
||||||
|
{
|
||||||
|
assert(gps_acq_manager_set_visibility(
|
||||||
|
&sim.manager, prn, true, false, -900));
|
||||||
|
}
|
||||||
|
for(unsigned int prn = 0u ; prn < 4u ; prn++)
|
||||||
|
{
|
||||||
|
assert(gps_acq_manager_set_visibility(
|
||||||
|
&sim.manager, prn, true, true, 500 - (int)prn));
|
||||||
|
}
|
||||||
|
for(unsigned int prn = 10u ; prn < 14u ; prn++)
|
||||||
|
{
|
||||||
|
sim.visible[prn] = true;
|
||||||
|
}
|
||||||
|
gps_acq_manager_set_visibility_mode(&sim.manager, true, sim.tick);
|
||||||
|
sim_start_engine(&sim);
|
||||||
|
|
||||||
|
uint64_t start_tick = sim.tick;
|
||||||
|
while((tracked_count(&sim) < 4u) &&
|
||||||
|
((sim.tick - start_tick) < 120u))
|
||||||
|
{
|
||||||
|
sim_step(&sim);
|
||||||
|
}
|
||||||
|
assert(tracked_count(&sim) == 4u);
|
||||||
|
for(unsigned int prn = 10u ; prn < 14u ; prn++)
|
||||||
|
{
|
||||||
|
assert(sim.tracked[prn]);
|
||||||
|
assert(sim.search_attempts[prn] != 0u);
|
||||||
|
}
|
||||||
|
printf("wrong-sky-model recovery telemetry: ticks=%lu attempts=[%u,%u,%u,%u]\n",
|
||||||
|
(unsigned long)(sim.tick - start_tick),
|
||||||
|
sim.search_attempts[10u], sim.search_attempts[11u],
|
||||||
|
sim.search_attempts[12u], sim.search_attempts[13u]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stale_locked_measurements_recover_tracking_state(void)
|
||||||
|
{
|
||||||
|
receiver_sim_t sim;
|
||||||
|
sim_init(&sim);
|
||||||
|
for(unsigned int prn = 0u ; prn < GPS_TRCK_IP_COUNT ; prn++)
|
||||||
|
{
|
||||||
|
sim.visible[prn] = true;
|
||||||
|
}
|
||||||
|
sim_start_engine(&sim);
|
||||||
|
while(tracked_count(&sim) < GPS_TRCK_IP_COUNT)
|
||||||
|
{
|
||||||
|
sim_step(&sim);
|
||||||
|
}
|
||||||
|
|
||||||
|
gps_acq_manager_mark_stale(&sim.manager, 7u);
|
||||||
|
gps_acq_manager_mark_stale(&sim.manager, 8u);
|
||||||
|
assert(manager_count_state(&sim, GPS_ACQ_PRN_TRACKING) ==
|
||||||
|
GPS_TRCK_IP_COUNT - 2u);
|
||||||
|
assert(manager_count_state(&sim, GPS_ACQ_PRN_STALE) == 2u);
|
||||||
|
|
||||||
|
sim_reconcile_stale_locked_measurements(&sim);
|
||||||
|
assert(manager_count_state(&sim, GPS_ACQ_PRN_TRACKING) ==
|
||||||
|
GPS_TRCK_IP_COUNT);
|
||||||
|
assert(manager_count_state(&sim, GPS_ACQ_PRN_STALE) == 0u);
|
||||||
|
|
||||||
|
gps_acq_manager_mark_stale(&sim.manager, 8u);
|
||||||
|
sim.measurement_alive[8u] = false;
|
||||||
|
sim_reconcile_stale_locked_measurements(&sim);
|
||||||
|
assert(gps_acq_manager_state(&sim.manager, 8u) ==
|
||||||
|
GPS_ACQ_PRN_STALE);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_missed_completion_interrupt_is_polled(void)
|
static void test_missed_completion_interrupt_is_polled(void)
|
||||||
{
|
{
|
||||||
receiver_sim_t sim;
|
receiver_sim_t sim;
|
||||||
@@ -620,6 +727,8 @@ int main(void)
|
|||||||
test_partial_loss_short_and_15_second_gaps();
|
test_partial_loss_short_and_15_second_gaps();
|
||||||
test_hot_failures_do_not_starve_cold_search();
|
test_hot_failures_do_not_starve_cold_search();
|
||||||
test_incomplete_almanac_keeps_full_round_robin();
|
test_incomplete_almanac_keeps_full_round_robin();
|
||||||
|
test_wrong_sky_model_safety_probe_finds_real_satellites();
|
||||||
|
test_stale_locked_measurements_recover_tracking_state();
|
||||||
test_missed_completion_interrupt_is_polled();
|
test_missed_completion_interrupt_is_polled();
|
||||||
test_missed_tracking_loss_interrupt_is_reconciled();
|
test_missed_tracking_loss_interrupt_is_reconciled();
|
||||||
test_stale_cache_forces_ephemeris_decode();
|
test_stale_cache_forces_ephemeris_decode();
|
||||||
|
|||||||
Reference in New Issue
Block a user