fix(gps): make acquisition and reacquisition deterministic

This commit is contained in:
2026-07-24 20:13:33 +03:00
parent e57b19b4ee
commit 86dfbeafac
18 changed files with 1274 additions and 241 deletions
@@ -9,6 +9,10 @@
#define GPS_AIDED_MAX_AGE_MS 1000u
#ifndef GPS_BUILD_ID
#define GPS_BUILD_ID "unknown"
#endif
void gps_system_uart_publish_location(
const char* source,
double latitude_deg,
@@ -66,9 +70,10 @@ void gps_system_uart_publish_startup(
imu_sensor_diagnostics_t imu;
imu_sensor_get_diagnostics(&imu);
GPS_LOG(DEBUG_STATUS, GPS_LOG_CAT_FUSION,
"init eskf_enabled=%u eskf_ready=%u imu=%u sensor=%s who=0x%02x "
"init build=%s eskf_enabled=%u eskf_ready=%u imu=%u sensor=%s who=0x%02x "
"running=%u target_hz=%lu actual_hz=%lu publish_every=%u "
"nav_ms=%u timebase_hz=%lu\r\n",
GPS_BUILD_ID,
fusion_enabled ? 1u : 0u,
fusion_initialized ? 1u : 0u,
imu_initialized ? 1u : 0u,
@@ -0,0 +1,289 @@
#include "gps/gps_acq_manager.h"
#include <stddef.h>
#include <string.h>
static bool gps_acq_manager_prn_valid(unsigned int prn)
{
return prn < GPS_ACQ_MANAGER_PRN_COUNT;
}
static bool gps_acq_manager_retry_due(
const gps_acq_manager_t* manager,
const gps_acq_prn_entry_t* entry,
uint64_t now,
bool hot)
{
uint64_t retry_delay = hot
? manager->config.hot_retry_delay_ticks
: manager->config.retry_delay_ticks;
return !entry->has_attempted ||
((now - entry->last_attempt_tick) >=
retry_delay);
}
static bool gps_acq_manager_hot_active(
const gps_acq_prn_entry_t* entry,
uint64_t now)
{
return (entry->state == GPS_ACQ_PRN_HOT) &&
(now <= entry->hot_until_tick);
}
static bool gps_acq_manager_find(
const gps_acq_manager_t* manager,
uint64_t now,
bool hot,
unsigned int cursor,
unsigned int* prn_out)
{
for(unsigned int offset = 0u;
offset < GPS_ACQ_MANAGER_PRN_COUNT;
offset++)
{
unsigned int prn =
(cursor + offset) % GPS_ACQ_MANAGER_PRN_COUNT;
const gps_acq_prn_entry_t* entry = &manager->prn[prn];
bool candidate = hot
? gps_acq_manager_hot_active(entry, now)
: ((entry->state == GPS_ACQ_PRN_COLD) ||
((entry->state == GPS_ACQ_PRN_HOT) &&
(now > entry->hot_until_tick)));
if(candidate &&
gps_acq_manager_retry_due(
manager, entry, now, hot))
{
*prn_out = prn;
return true;
}
}
return false;
}
void gps_acq_manager_init(
gps_acq_manager_t* manager,
const gps_acq_manager_config_t* config)
{
if((manager == NULL) || (config == NULL))
{
return;
}
memset(manager, 0, sizeof(*manager));
manager->config = *config;
if(manager->config.max_hot_streak == 0u)
{
manager->config.max_hot_streak = 1u;
}
}
bool gps_acq_manager_enable_cold(
gps_acq_manager_t* manager,
unsigned int prn)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return false;
}
gps_acq_prn_entry_t* entry = &manager->prn[prn];
if(entry->state == GPS_ACQ_PRN_DISABLED)
{
entry->state = GPS_ACQ_PRN_COLD;
return true;
}
return entry->state == GPS_ACQ_PRN_COLD;
}
gps_acq_prn_state_t gps_acq_manager_state(
const gps_acq_manager_t* manager,
unsigned int prn)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return GPS_ACQ_PRN_DISABLED;
}
return manager->prn[prn].state;
}
const char* gps_acq_manager_state_name(gps_acq_prn_state_t state)
{
switch(state)
{
case GPS_ACQ_PRN_DISABLED:
return "disabled";
case GPS_ACQ_PRN_COLD:
return "cold";
case GPS_ACQ_PRN_HOT:
return "hot";
case GPS_ACQ_PRN_ACQUIRING:
return "acquiring";
case GPS_ACQ_PRN_ACQUIRED:
return "acquired";
case GPS_ACQ_PRN_TRACKING:
return "tracking";
case GPS_ACQ_PRN_STALE:
return "stale";
default:
return "unknown";
}
}
void gps_acq_manager_mark_acquired(
gps_acq_manager_t* manager,
unsigned int prn)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return;
}
manager->prn[prn].state = GPS_ACQ_PRN_ACQUIRED;
manager->prn[prn].attempt_was_hot = false;
}
void gps_acq_manager_mark_tracking(
gps_acq_manager_t* manager,
unsigned int prn)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return;
}
manager->prn[prn].state = GPS_ACQ_PRN_TRACKING;
manager->prn[prn].attempt_was_hot = false;
manager->prn[prn].hot_until_tick = 0u;
}
void gps_acq_manager_mark_stale(
gps_acq_manager_t* manager,
unsigned int prn)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return;
}
if(manager->prn[prn].state == GPS_ACQ_PRN_TRACKING)
{
manager->prn[prn].state = GPS_ACQ_PRN_STALE;
}
}
void gps_acq_manager_mark_lost(
gps_acq_manager_t* manager,
unsigned int prn,
uint64_t now)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return;
}
gps_acq_prn_entry_t* entry = &manager->prn[prn];
bool already_hot = entry->state == GPS_ACQ_PRN_HOT;
entry->state = GPS_ACQ_PRN_HOT;
entry->attempt_was_hot = false;
entry->hot_until_tick = now + manager->config.hot_window_ticks;
if(!already_hot)
{
/* A real tracking loss gets one immediate reacquisition attempt.
* Later failures observe the hot retry backoff. */
entry->has_attempted = false;
}
}
void gps_acq_manager_mark_failed(
gps_acq_manager_t* manager,
unsigned int prn,
uint64_t now)
{
if((manager == NULL) || !gps_acq_manager_prn_valid(prn))
{
return;
}
gps_acq_prn_entry_t* entry = &manager->prn[prn];
entry->last_attempt_tick = now;
entry->has_attempted = true;
entry->state =
entry->attempt_was_hot && (now <= entry->hot_until_tick)
? GPS_ACQ_PRN_HOT : GPS_ACQ_PRN_COLD;
entry->attempt_was_hot = false;
}
bool gps_acq_manager_start_next(
gps_acq_manager_t* manager,
uint64_t now,
unsigned int* prn_out,
bool* hot_out)
{
if((manager == NULL) || (prn_out == NULL))
{
return false;
}
unsigned int hot_prn = GPS_ACQ_MANAGER_INVALID_PRN;
unsigned int cold_prn = GPS_ACQ_MANAGER_INVALID_PRN;
bool have_hot = gps_acq_manager_find(
manager, now, true, manager->hot_cursor, &hot_prn);
bool have_cold = gps_acq_manager_find(
manager, now, false, manager->cold_cursor, &cold_prn);
bool choose_hot = have_hot &&
(!have_cold ||
(manager->hot_streak < manager->config.max_hot_streak));
unsigned int prn;
if(choose_hot)
{
prn = hot_prn;
manager->hot_cursor =
(prn + 1u) % GPS_ACQ_MANAGER_PRN_COUNT;
manager->hot_streak++;
}
else if(have_cold)
{
prn = cold_prn;
manager->cold_cursor =
(prn + 1u) % GPS_ACQ_MANAGER_PRN_COUNT;
manager->hot_streak = 0u;
}
else
{
return false;
}
gps_acq_prn_entry_t* entry = &manager->prn[prn];
entry->attempt_was_hot = choose_hot;
entry->last_attempt_tick = now;
entry->has_attempted = true;
entry->state = GPS_ACQ_PRN_ACQUIRING;
*prn_out = prn;
if(hot_out != NULL)
{
*hot_out = choose_hot;
}
return true;
}
unsigned int gps_acq_manager_count_state(
const gps_acq_manager_t* manager,
gps_acq_prn_state_t state)
{
if(manager == NULL)
{
return 0u;
}
unsigned int count = 0u;
for(unsigned int prn = 0u;
prn < GPS_ACQ_MANAGER_PRN_COUNT;
prn++)
{
if(manager->prn[prn].state == state)
{
count++;
}
}
return count;
}
unsigned int gps_acq_manager_count_searchable(
const gps_acq_manager_t* manager)
{
return gps_acq_manager_count_state(manager, GPS_ACQ_PRN_COLD) +
gps_acq_manager_count_state(manager, GPS_ACQ_PRN_HOT);
}
@@ -0,0 +1,68 @@
#include "gps/gps_ephemeris_cache.h"
#include <stddef.h>
#include <string.h>
void gps_ephemeris_cache_init(
gps_ephemeris_cache_t* cache,
uint64_t max_age_ticks)
{
if(cache == NULL)
{
return;
}
memset(cache, 0, sizeof(*cache));
cache->max_age_ticks = max_age_ticks;
}
bool gps_ephemeris_cache_store(
gps_ephemeris_cache_t* cache,
unsigned int prn,
const gps_ephemeris_t* ephemeris,
uint64_t now)
{
if((cache == NULL) || (ephemeris == NULL) ||
(prn >= GPS_PRN_COUNT) ||
!ephemeris->ephemeris_valid ||
(ephemeris->SVID != prn))
{
return false;
}
cache->entry[prn].ephemeris = *ephemeris;
cache->entry[prn].committed_tick = now;
cache->entry[prn].valid = true;
return true;
}
bool gps_ephemeris_cache_restore(
gps_ephemeris_cache_t* cache,
unsigned int prn,
uint64_t now,
gps_ephemeris_t* ephemeris_out)
{
if((cache == NULL) || (ephemeris_out == NULL) ||
(prn >= GPS_PRN_COUNT))
{
return false;
}
gps_ephemeris_cache_entry_t* entry = &cache->entry[prn];
if(!entry->valid ||
((now - entry->committed_tick) > cache->max_age_ticks))
{
entry->valid = false;
return false;
}
*ephemeris_out = entry->ephemeris;
return true;
}
void gps_ephemeris_cache_invalidate(
gps_ephemeris_cache_t* cache,
unsigned int prn)
{
if((cache == NULL) || (prn >= GPS_PRN_COUNT))
{
return;
}
memset(&cache->entry[prn], 0, sizeof(cache->entry[prn]));
}
@@ -1,4 +1,6 @@
#include "gps/linked_list.h"
#include "gps/gps_acq_manager.h"
#include "gps/gps_ephemeris_cache.h"
#include "gps/gps_interrupt_handlers.h"
#include "gps/Navigation.h"
#include "gps/gps_nav_epoch.h"
@@ -56,10 +58,10 @@ static volatile bool acq_shadow_pending[GPS_ACQ_IP_COUNT];
static gps_acq_result_t acq_shadow_result[GPS_ACQ_IP_COUNT];
static gps_tracking_shadow_t trk_shadow[GPS_TRCK_IP_COUNT];
static volatile gps_satellite_state_t satellite_state[GPS_PRN_COUNT];
static volatile unsigned char satellite_tracking_ip[GPS_PRN_COUNT];
static volatile uint64_t satellite_last_acq_tick[GPS_PRN_COUNT];
static gps_acq_result_t satellite_acq_result[GPS_PRN_COUNT];
static gps_acq_manager_t gps_acq_manager;
static gps_ephemeris_cache_t gps_ephemeris_cache;
static gps_isr_event_t gps_event_queue[GPS_EVENT_QUEUE_SIZE];
static volatile unsigned int gps_event_head = 0;
@@ -74,7 +76,7 @@ static gps_nav_epoch_snapshot_t gps_nav_active_snapshot;
static gps_nav_epoch_snapshot_t gps_nav_completed_snapshot;
static bool gps_nav_completed_snapshot_pending;
static volatile gps_runtime_diagnostics_t gps_runtime_diagnostics;
static unsigned int gps_acq_round_robin_prn = 0;
static uint64_t gps_last_acq_status_log_tick = 0u;
static unsigned int gps_external_irq_id = 0u;
static gps_external_irq_handler_t gps_external_irq_handler = NULL;
@@ -104,27 +106,6 @@ static unsigned int gps_mask_count(uint32_t mask)
return count;
}
static const char* gps_satellite_state_name(gps_satellite_state_t state)
{
switch(state)
{
case GPS_SAT_NOT_SEEN:
return "not_seen";
case GPS_SAT_ACQUIRING:
return "acquiring";
case GPS_SAT_ACQUIRED:
return "acquired";
case GPS_SAT_TRACKING:
return "tracking";
case GPS_SAT_LOST:
return "lost";
case GPS_SAT_STALE:
return "stale";
default:
return "unknown";
}
}
static double gps_correct_abs_sample(uint32_t abs_sample, uint32_t rem_code_phase)
{
return (double)abs_sample - ((double)rem_code_phase / CODE_FREQ_BASIS);
@@ -353,6 +334,14 @@ static void gps_set_tracking_nav_bits_mode(unsigned char trck_ip_no)
static void gps_runtime_state_init(void)
{
const gps_acq_manager_config_t acq_config = {
.retry_delay_ticks = GPS_ACQ_RETRY_DELAY_TICKS,
.hot_retry_delay_ticks =
GPS_ACQ_HOT_RETRY_DELAY_TICKS,
.hot_window_ticks = GPS_ACQ_REACQ_PRIORITY_TICKS,
.max_hot_streak = GPS_ACQ_MAX_HOT_STREAK
};
gps_event_head = 0;
gps_event_tail = 0;
gps_event_overflow_count = 0;
@@ -367,9 +356,13 @@ static void gps_runtime_state_init(void)
memset((void*)&gps_runtime_diagnostics, 0, sizeof(gps_runtime_diagnostics));
gps_runtime_diagnostics.last_connected_prn = GPS_PRN_INVALID;
gps_runtime_diagnostics.last_lost_prn = GPS_PRN_INVALID;
gps_acq_round_robin_prn = 0;
gps_last_acq_status_log_tick = 0u;
gps_external_irq_id = 0u;
gps_external_irq_handler = NULL;
gps_acq_manager_init(&gps_acq_manager, &acq_config);
gps_ephemeris_cache_init(
&gps_ephemeris_cache,
GPS_EPHEMERIS_CACHE_MAX_AGE_TICKS);
for(unsigned int i = 0 ; i < GPS_ACQ_IP_COUNT ; i++)
{
@@ -385,9 +378,7 @@ static void gps_runtime_state_init(void)
for(unsigned int i = 0 ; i < GPS_PRN_COUNT ; i++)
{
satellite_state[i] = GPS_SAT_NOT_SEEN;
satellite_tracking_ip[i] = GPS_PRN_INVALID;
satellite_last_acq_tick[i] = 0;
memset(&satellite_acq_result[i], 0, sizeof(satellite_acq_result[i]));
}
@@ -400,6 +391,25 @@ static void gps_runtime_state_init(void)
}
void gps_acq_configure_prns(
const unsigned char* prns,
unsigned int count)
{
if(prns == NULL)
{
return;
}
for(unsigned int i = 0u ; i < count ; i++)
{
if(gps_prn_valid(prns[i]))
{
(void)gps_acq_manager_enable_cold(
&gps_acq_manager, prns[i]);
}
}
gps_acq_schedule_pending = true;
}
bool gps_interrupt_attach_external_source(
unsigned int irq_id,
gps_external_irq_handler_t handler)
@@ -598,18 +608,22 @@ static void gps_mark_satellite_tracking(unsigned int prn_no, unsigned char trck_
{
if(gps_prn_valid(prn_no))
{
gps_satellite_state_t previous_state = satellite_state[prn_no];
gps_acq_prn_state_t previous_state =
gps_acq_manager_state(&gps_acq_manager, prn_no);
unsigned char previous_ip = satellite_tracking_ip[prn_no];
satellite_state[prn_no] = GPS_SAT_TRACKING;
gps_acq_manager_mark_tracking(&gps_acq_manager, prn_no);
satellite_tracking_ip[prn_no] = trck_ip_no;
if((previous_state != GPS_SAT_TRACKING) || (previous_ip != trck_ip_no))
if((previous_state != GPS_ACQ_PRN_TRACKING) ||
(previous_ip != trck_ip_no))
{
gps_runtime_diagnostics.satellite_connected_total++;
gps_runtime_diagnostics.last_connected_prn = prn_no;
gps_runtime_diagnostics.last_connected_tick = gps_get_systick();
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_TRK,
"satellite connected: prn=%u trk=%u previous=%s previous_trk=%u\r\n",
prn_no, trck_ip_no, gps_satellite_state_name(previous_state), previous_ip);
prn_no, trck_ip_no,
gps_acq_manager_state_name(previous_state),
previous_ip);
}
}
}
@@ -618,18 +632,22 @@ static void gps_mark_satellite_lost(unsigned int prn_no)
{
if(gps_prn_valid(prn_no))
{
gps_satellite_state_t previous_state = satellite_state[prn_no];
gps_acq_prn_state_t previous_state =
gps_acq_manager_state(&gps_acq_manager, prn_no);
unsigned char previous_ip = satellite_tracking_ip[prn_no];
satellite_state[prn_no] = GPS_SAT_LOST;
uint64_t now = gps_get_systick();
gps_acq_manager_mark_lost(&gps_acq_manager, prn_no, now);
satellite_tracking_ip[prn_no] = GPS_PRN_INVALID;
if(previous_state != GPS_SAT_LOST)
if(previous_state != GPS_ACQ_PRN_HOT)
{
gps_runtime_diagnostics.satellite_lost_total++;
gps_runtime_diagnostics.last_lost_prn = prn_no;
gps_runtime_diagnostics.last_lost_tick = gps_get_systick();
gps_runtime_diagnostics.last_lost_tick = now;
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_TRK,
"satellite lost: prn=%u previous=%s previous_trk=%u\r\n",
prn_no, gps_satellite_state_name(previous_state), previous_ip);
prn_no,
gps_acq_manager_state_name(previous_state),
previous_ip);
}
}
}
@@ -652,7 +670,6 @@ bool assign_tracking_from_result(const gps_acq_result_t* result)
if(active && (trk->PRN_NUMBER == prn_no))
{
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_TRK, "acquired prn %u is already being tracked\r\n", prn_no);
(void)delete_acq_element_by_prn_number(&acquisition_node, prn_no);
gps_mark_satellite_tracking(prn_no, i);
return false;
}
@@ -666,13 +683,25 @@ bool assign_tracking_from_result(const gps_acq_result_t* result)
{
tracking_allocated[i] = true;
gps_clear_tracking_slot(i);
gps_ephemeris_t cached_ephemeris;
if(gps_ephemeris_cache_restore(
&gps_ephemeris_cache, prn_no,
gps_get_systick(), &cached_ephemeris))
{
gps_frames_parsed[i].gps_ephems =
cached_ephemeris;
gps_runtime_diagnostics
.ephemeris_cache_restore_total++;
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_NAV,
"restored ephemeris cache: prn=%u trk=%u iode=%u\r\n",
prn_no, i, cached_ephemeris.iode);
}
gps_set_tracking_nav_bits_mode(i);
trck_ips[i]->PRN_NUMBER = result->prn;
trck_ips[i]->CODE_PHASE = result->code_phase;
trck_ips[i]->DOPPLER_REG = result->doppler;
trck_ips[i]->CONTROL_REG |= (1u << GPS_TRCK_NAV_BITS_INTR_EN_POS);
trck_ips[i]->CONTROL_REG |= (1u << GPS_TRCK_START_POS);
(void)delete_acq_element_by_prn_number(&acquisition_node, prn_no);
gps_mark_satellite_tracking(prn_no, i);
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_TRK, "tracking started: prn=%u trk=%u code=%u doppler=%u\r\n",
prn_no, i, result->code_phase, result->doppler);
@@ -850,19 +879,16 @@ static void gps_process_acq_result(const gps_acq_result_t* result)
return;
}
satellite_last_acq_tick[prn] = result->tick;
if(!result->acquired)
{
if(satellite_state[prn] == GPS_SAT_ACQUIRING)
{
satellite_state[prn] = GPS_SAT_NOT_SEEN;
}
gps_acq_manager_mark_failed(
&gps_acq_manager, prn, result->tick);
GPS_LOG(DEBUG_DEBUG, GPS_LOG_CAT_ACQ, "satellite search ended: engine=%u prn=%u status=0x%x result=not_acquired\r\n",
result->engine_id, prn, result->status);
return;
}
satellite_state[prn] = GPS_SAT_ACQUIRED;
gps_acq_manager_mark_acquired(&gps_acq_manager, prn);
satellite_acq_result[prn] = *result;
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_ACQ,
"acquired: engine=%u prn=%u code=%u doppler=%u peak=%u\r\n",
@@ -870,8 +896,7 @@ static void gps_process_acq_result(const gps_acq_result_t* result)
if(gps_tracking_prn_active(prn))
{
(void)delete_acq_element_by_prn_number(&acquisition_node, prn);
satellite_state[prn] = GPS_SAT_TRACKING;
gps_acq_manager_mark_tracking(&gps_acq_manager, prn);
return;
}
@@ -962,8 +987,16 @@ static void gps_mark_node_fresh(volatile gps_ephem_ll_t* node, unsigned int stat
((status & (1u << GPS_TRCK_STOP_UNLOCK_POS)) == 0u);
if((node->data_p != NULL) && gps_prn_valid(node->data_p->SVID))
{
satellite_state[node->data_p->SVID] = node->gps_measurement_valid ? GPS_SAT_TRACKING : GPS_SAT_STALE;
satellite_tracking_ip[node->data_p->SVID] = node->tracking_ip_no;
unsigned int prn = node->data_p->SVID;
if(node->gps_measurement_valid)
{
gps_mark_satellite_tracking(prn, node->tracking_ip_no);
}
else
{
gps_acq_manager_mark_stale(&gps_acq_manager, prn);
satellite_tracking_ip[prn] = node->tracking_ip_no;
}
}
}
@@ -987,7 +1020,6 @@ static void gps_process_tracking_drop(const gps_isr_event_t* event)
if(gps_prn_valid(dropped_prn))
{
(void)insert_acq_element(&acquisition_node, dropped_prn);
gps_mark_satellite_lost(dropped_prn);
}
@@ -1083,6 +1115,19 @@ static void gps_process_tracking_nav_bits(const gps_isr_event_t* event)
unsigned char subframe_id = parse_subframe((unsigned int*)gps_subframe,
(gps_frame_t*)gps_frame_parsed,
&how_tow_sec);
if((subframe_id >= 1u) && (subframe_id <= 3u) &&
(gps_frame_parsed->pending_ephemeris_mask == 0u) &&
gps_ephemeris_cache_store(
&gps_ephemeris_cache, event->prn,
(const gps_ephemeris_t*)&gps_frame_parsed->gps_ephems,
event->tick))
{
gps_runtime_diagnostics.ephemeris_cache_store_total++;
GPS_LOG(DEBUG_INFO, GPS_LOG_CAT_NAV,
"stored ephemeris cache: prn=%u trk=%u iode=%u\r\n",
event->prn, trck_ip_no,
gps_frame_parsed->gps_ephems.iode);
}
if((subframe_id >= 1u) && (subframe_id <= 5u) &&
(how_tow_sec < (unsigned int)GPS_TIME_WEEK_SECONDS))
{
@@ -1169,10 +1214,6 @@ static void gps_process_tracking_nav_bits(const gps_isr_event_t* event)
}
gps_mark_node_fresh(node, event->status, event->tick);
if(gps_prn_valid(event->prn))
{
gps_mark_satellite_tracking(event->prn, trck_ip_no);
}
GPS_LOG(DEBUG_TRACE, GPS_LOG_CAT_TRK, "nav bits: trk=%u prn=%u mask=0x%x status=0x%x\r\n",
trck_ip_no, event->prn, node->gps_subframe_mask, event->status);
@@ -1412,7 +1453,7 @@ static void gps_process_tracking_event(const gps_isr_event_t* event)
}
else if(gps_prn_valid(event->prn))
{
(void)insert_acq_element(&acquisition_node, event->prn);
gps_mark_satellite_lost(event->prn);
tracking_allocated[event->index] = false;
if(trck_ip_exists(&tracking_node, event->index))
{
@@ -1502,80 +1543,28 @@ static void gps_promote_acquired_satellites(void)
{
for(unsigned int prn = 0 ; prn < GPS_PRN_COUNT ; prn++)
{
if((satellite_state[prn] == GPS_SAT_ACQUIRED) && !gps_tracking_prn_active(prn))
if((gps_acq_manager_state(&gps_acq_manager, prn) ==
GPS_ACQ_PRN_ACQUIRED) &&
!gps_tracking_prn_active(prn))
{
(void)assign_tracking_from_result(&satellite_acq_result[prn]);
}
}
}
static void gps_remove_tracked_prns_from_acq_list(void)
static void gps_reconcile_tracked_prns(void)
{
for(unsigned int prn = 0 ; prn < GPS_PRN_COUNT ; prn++)
{
if(gps_tracking_prn_active(prn))
if(gps_tracking_prn_active(prn) &&
(gps_acq_manager_state(&gps_acq_manager, prn) !=
GPS_ACQ_PRN_STALE))
{
if(acq_prn_exists(&acquisition_node, prn))
{
(void)delete_acq_element_by_prn_number(&acquisition_node, prn);
}
satellite_state[prn] = GPS_SAT_TRACKING;
gps_acq_manager_mark_tracking(&gps_acq_manager, prn);
}
}
}
static bool gps_prn_schedulable(unsigned int prn, uint64_t now)
{
if(!gps_prn_valid(prn))
{
return false;
}
if((satellite_state[prn] == GPS_SAT_ACQUIRING) ||
(satellite_state[prn] == GPS_SAT_ACQUIRED) ||
gps_tracking_prn_active(prn))
{
return false;
}
if((satellite_last_acq_tick[prn] != 0u) &&
((now - satellite_last_acq_tick[prn]) < GPS_ACQ_RETRY_DELAY_TICKS))
{
return false;
}
return true;
}
static bool gps_find_next_acq_prn(uint64_t now, unsigned int* prn_out)
{
gps_acq_ll_t* iterator = (gps_acq_ll_t*)acquisition_node;
gps_acq_ll_t* wrapped_candidate = NULL;
while(iterator != NULL)
{
unsigned int prn = iterator->prn_no;
if(gps_prn_schedulable(prn, now))
{
if(prn >= gps_acq_round_robin_prn)
{
*prn_out = prn;
gps_acq_round_robin_prn = (prn + 1u) % GPS_PRN_COUNT;
return true;
}
if(wrapped_candidate == NULL)
{
wrapped_candidate = iterator;
}
}
iterator = iterator->next;
}
if(wrapped_candidate != NULL)
{
*prn_out = wrapped_candidate->prn_no;
gps_acq_round_robin_prn = (*prn_out + 1u) % GPS_PRN_COUNT;
return true;
}
return false;
}
static bool gps_acq_engine_available(unsigned int engine_id, volatile gps_acq_t* acq_ip)
{
if((engine_id >= GPS_ACQ_IP_COUNT) || (acq_ip == NULL))
@@ -1604,7 +1593,7 @@ static bool gps_acq_engine_available(unsigned int engine_id, volatile gps_acq_t*
void gps_acq_scheduler_run(void)
{
uint64_t now = gps_get_systick();
gps_remove_tracked_prns_from_acq_list();
gps_reconcile_tracked_prns();
gps_promote_acquired_satellites();
for(unsigned int i = 0 ; i < GPS_ACQ_IP_COUNT ; i++)
@@ -1620,7 +1609,9 @@ void gps_acq_scheduler_run(void)
continue;
}
unsigned int prn;
if(!gps_find_next_acq_prn(now, &prn))
bool hot = false;
if(!gps_acq_manager_start_next(
&gps_acq_manager, now, &prn, &hot))
{
continue;
}
@@ -1629,10 +1620,10 @@ void gps_acq_scheduler_run(void)
acq_engine_prn[i] = (unsigned char)prn;
acq_engine_start_tick[i] = now;
acq_engine_stuck_warned[i] = false;
satellite_state[prn] = GPS_SAT_ACQUIRING;
satellite_last_acq_tick[prn] = now;
acq_start(acq_ip, (unsigned char)prn);
GPS_LOG(DEBUG_DEBUG, GPS_LOG_CAT_SCHED, "satellite search started: engine=%u prn=%u\r\n", i, prn);
GPS_LOG(DEBUG_DEBUG, GPS_LOG_CAT_SCHED,
"satellite search started: engine=%u prn=%u priority=%s\r\n",
i, prn, hot ? "reacquire" : "cold");
}
}
@@ -1641,17 +1632,12 @@ static void gps_check_acq_stuck_busy(void)
uint64_t now = gps_get_systick();
for(unsigned int i = 0 ; i < GPS_ACQ_IP_COUNT ; i++)
{
if((acq_engine_state[i] != GPS_ACQ_ENGINE_BUSY) || acq_engine_stuck_warned[i])
if(acq_engine_state[i] != GPS_ACQ_ENGINE_BUSY)
{
continue;
}
uint64_t age = now - acq_engine_start_tick[i];
if(age <= GPS_ACQ_STUCK_WARN_TICKS)
{
continue;
}
volatile gps_acq_t* acq_ip = gps_get_acq_ip(i);
if(acq_ip == NULL)
{
@@ -1660,15 +1646,68 @@ static void gps_check_acq_stuck_busy(void)
uint32_t control = acq_ip->CONTROL_REG;
uint32_t status = acq_ip->STATUS_REG;
acq_engine_stuck_warned[i] = true;
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_ACQ,
"ACQ engine %u busy for %lu ticks prn=%u status=0x%x control=0x%x; check rf_clk/sample_align/acq_end\r\n",
i, (unsigned long)age, acq_engine_prn[i], status, control);
if((age >= GPS_ACQ_STUCK_WARN_TICKS) &&
!acq_engine_stuck_warned[i])
{
acq_engine_stuck_warned[i] = true;
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_ACQ,
"ACQ engine %u busy for %lu ticks prn=%u status=0x%x control=0x%x; check rf_clk/sample_align/acq_end\r\n",
i, (unsigned long)age, acq_engine_prn[i],
status, control);
}
(void)status;
(void)control;
}
}
static void gps_log_acq_status(void)
{
uint64_t now = gps_get_systick();
if((gps_last_acq_status_log_tick != 0u) &&
((now - gps_last_acq_status_log_tick) <
GPS_ACQ_STATUS_LOG_PERIOD_TICKS))
{
return;
}
gps_last_acq_status_log_tick = now;
unsigned int engine = GPS_PRN_INVALID;
unsigned int engine_prn = GPS_PRN_INVALID;
uint64_t engine_age_ticks = 0u;
for(unsigned int i = 0u ; i < GPS_ACQ_IP_COUNT ; i++)
{
if(acq_engine_state[i] == GPS_ACQ_ENGINE_BUSY)
{
engine = i;
engine_prn = acq_engine_prn[i];
engine_age_ticks = now - acq_engine_start_tick[i];
break;
}
}
unsigned int tracking = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_TRACKING);
unsigned int stale = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_STALE);
unsigned int hot = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_HOT);
unsigned int cold = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_COLD);
unsigned int acquiring = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_ACQUIRING);
unsigned int acquired = gps_acq_manager_count_state(
&gps_acq_manager, GPS_ACQ_PRN_ACQUIRED);
GPS_LOG(DEBUG_STATUS, GPS_LOG_CAT_ACQ,
"state=%s tracked=%u stale=%u hot=%u cold=%u acquiring=%u acquired=%u engine=%u prn=%u age_ms=%lu\r\n",
(tracking >= GPS_NAV_MIN_WLS_SATELLITES)
? "tracking" : "searching",
tracking, stale, hot, cold, acquiring, acquired,
engine, engine_prn,
(unsigned long)((engine_age_ticks * 1000u) /
GPS_SYSTICK_HZ));
}
static void gps_mark_stale_measurements(void)
{
uint64_t now = gps_get_systick();
@@ -1681,7 +1720,9 @@ static void gps_mark_stale_measurements(void)
iterator->gps_measurement_valid = false;
if(iterator->data_p != NULL && gps_prn_valid(iterator->data_p->SVID))
{
satellite_state[iterator->data_p->SVID] = GPS_SAT_STALE;
gps_acq_manager_mark_stale(
&gps_acq_manager,
iterator->data_p->SVID);
}
GPS_LOG(DEBUG_WARNING, GPS_LOG_CAT_TRK, "stale measurement: trk=%u age_ticks=%lu\r\n",
iterator->tracking_ip_no, (unsigned long)(now - iterator->gps_last_measurement_tick));
@@ -1699,6 +1740,7 @@ void gps_background_task(void)
{
gps_mark_stale_measurements();
gps_check_acq_stuck_busy();
gps_log_acq_status();
}
if(gps_take_acq_schedule_pending())
{
+3 -7
View File
@@ -57,7 +57,6 @@ int unsigned gps_subframes[GPS_TRCK_IP_COUNT][10];
volatile gps_frame_t gps_frames_parsed[GPS_TRCK_IP_COUNT];
volatile gps_ephem_ll_t* tracking_node = NULL;
volatile gps_acq_ll_t* acquisition_node = NULL;
static volatile bool gps_initial_position_valid = false;
static volatile bool gps_ionoutc_valid = false;
@@ -1405,12 +1404,6 @@ void gps_startup_initialization(unsigned int nsp_tick)
unsigned char gps_active_satellites[] = GPS_ACTIVE_PRNS;
for(unsigned char i = 0; i < GPS_ACTIVE_SAT_NUM ; i++)
{
unsigned int prn = (unsigned int) gps_active_satellites[i];
(void)insert_acq_element(&acquisition_node, prn);
}
for(unsigned i = 0 ; i < GPS_TRCK_IP_COUNT ; i++)
{
// stop all working tracking ips & disable interrupts.
@@ -1436,6 +1429,9 @@ void gps_startup_initialization(unsigned int nsp_tick)
}
gps_interrupt_init();
gps_acq_configure_prns(
gps_active_satellites,
GPS_ACTIVE_SAT_NUM);
/* The AFE and its sample timebase are shared by all acquisition/tracking
* channels. Start them exactly once; per-PRN acquisition must not rephase it. */
acq_afe_start(acq_ips[0]);
@@ -127,82 +127,3 @@ bool delete_by_ip_number(volatile gps_ephem_ll_t** node, unsigned char trck_ip_n
}
return false;
}
bool acq_prn_exists(volatile gps_acq_ll_t** node, unsigned int prn_no)
{
if(node == NULL)
{
return false;
}
volatile gps_acq_ll_t* iterator = *node;
while(iterator != NULL)
{
if(iterator->prn_no == prn_no)
{
return true;
}
iterator = iterator->next;
}
return false;
}
bool insert_acq_element(volatile gps_acq_ll_t** node, unsigned int prn_no)
{
if((node == NULL) || acq_prn_exists(node, prn_no))
{
return false;
}
gps_acq_ll_t* new_node = (gps_acq_ll_t*)malloc(sizeof(*new_node));
if(new_node == NULL)
{
return false;
}
new_node->prn_no = prn_no;
new_node->next = NULL;
if(*node == NULL)
{
*node = new_node;
return true;
}
volatile gps_acq_ll_t* tail = *node;
while(tail->next != NULL)
{
tail = tail->next;
}
tail->next = new_node;
return true;
}
bool delete_acq_element_by_prn_number(volatile gps_acq_ll_t** node, unsigned int prn_no)
{
if(node == NULL)
{
return false;
}
volatile gps_acq_ll_t* iterator = *node;
volatile gps_acq_ll_t* previous = NULL;
while(iterator != NULL)
{
if(iterator->prn_no == prn_no)
{
if(previous == NULL)
{
*node = iterator->next;
}
else
{
previous->next = iterator->next;
}
free((void*)iterator);
return true;
}
previous = iterator;
iterator = iterator->next;
}
return false;
}