Improve GPS stale probe recovery (#10714)
* Improve GPS stale probe recovery * Address GPS review feedback
This commit is contained in:
co-authored by
GitHub
parent
5d1c4f15b7
commit
882ca0a216
+71
-17
@@ -80,6 +80,12 @@ namespace
|
|||||||
constexpr uint32_t GPS_PROBE_CACHE_MAGIC = 0x47504348UL; // "GPCH"
|
constexpr uint32_t GPS_PROBE_CACHE_MAGIC = 0x47504348UL; // "GPCH"
|
||||||
constexpr uint16_t GPS_PROBE_CACHE_VERSION = 1;
|
constexpr uint16_t GPS_PROBE_CACHE_VERSION = 1;
|
||||||
constexpr const char *GPS_PROBE_CACHE_FILE = "/prefs/gps_probe_cache.dat";
|
constexpr const char *GPS_PROBE_CACHE_FILE = "/prefs/gps_probe_cache.dat";
|
||||||
|
constexpr int MIN_PLAUSIBLE_GPS_YEAR = 2020;
|
||||||
|
constexpr int MAX_PLAUSIBLE_GPS_YEAR = 2100;
|
||||||
|
#ifdef TRACKER_T1000_E
|
||||||
|
constexpr uint32_t T1000_E_AIROHA_WAKE_MS = 1000;
|
||||||
|
constexpr uint32_t T1000_E_AIROHA_WAKE_INTERVAL_MS = 40;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct GPSProbeCacheRecord {
|
struct GPSProbeCacheRecord {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
@@ -101,6 +107,45 @@ bool isValidProbeBaud(uint32_t baud)
|
|||||||
return baud >= 1200 && baud <= 921600;
|
return baud >= 1200 && baud <= 921600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> void wakeAirohaForActiveProbe(T *serialGps)
|
||||||
|
{
|
||||||
|
#ifdef TRACKER_T1000_E
|
||||||
|
digitalWrite(PIN_GPS_EN, GPS_EN_ACTIVE);
|
||||||
|
digitalWrite(GPS_RTC_INT, HIGH);
|
||||||
|
delay(3);
|
||||||
|
digitalWrite(GPS_RTC_INT, LOW);
|
||||||
|
delay(50);
|
||||||
|
|
||||||
|
const uint32_t start = millis();
|
||||||
|
do {
|
||||||
|
serialGps->write("$PAIR382,1*2E\r\n");
|
||||||
|
delay(T1000_E_AIROHA_WAKE_INTERVAL_MS);
|
||||||
|
} while (Throttle::isWithinTimespanMs(start, T1000_E_AIROHA_WAKE_MS));
|
||||||
|
#elif defined(GNSS_AIROHA)
|
||||||
|
serialGps->write("$PAIR382,1*2E\r\n");
|
||||||
|
delay(20);
|
||||||
|
#else
|
||||||
|
(void)serialGps;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPlausibleNmeaTime(const struct tm &t)
|
||||||
|
{
|
||||||
|
const int year = t.tm_year + 1900;
|
||||||
|
if (year < MIN_PLAUSIBLE_GPS_YEAR || year > MAX_PLAUSIBLE_GPS_YEAR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BUILD_EPOCH
|
||||||
|
const int64_t candidate = static_cast<int64_t>(gm_mktime(&t));
|
||||||
|
const int64_t minEpoch = static_cast<int64_t>(BUILD_EPOCH);
|
||||||
|
const int64_t maxEpoch = minEpoch + static_cast<int64_t>(FORTY_YEARS);
|
||||||
|
return candidate >= minEpoch && candidate <= maxEpoch;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> bool sawNmeaSentenceAtBaud(T *serialGps, uint32_t timeoutMs)
|
template <typename T> bool sawNmeaSentenceAtBaud(T *serialGps, uint32_t timeoutMs)
|
||||||
{
|
{
|
||||||
// Lightweight passive check: look for at least one complete
|
// Lightweight passive check: look for at least one complete
|
||||||
@@ -689,6 +734,7 @@ bool GPS::verifyCachedProbePresence()
|
|||||||
case GNSS_MODEL_AG3352:
|
case GNSS_MODEL_AG3352:
|
||||||
if (cachedProbeModel == GNSS_MODEL_AG3352)
|
if (cachedProbeModel == GNSS_MODEL_AG3352)
|
||||||
cachedProbeModelName = "AG3352";
|
cachedProbeModelName = "AG3352";
|
||||||
|
wakeAirohaForActiveProbe(_serial_gps);
|
||||||
_serial_gps->write("$PAIR021*39\r\n");
|
_serial_gps->write("$PAIR021*39\r\n");
|
||||||
present = (getACK("$PAIR021,", 900) == GNSS_RESPONSE_OK);
|
present = (getACK("$PAIR021,", 900) == GNSS_RESPONSE_OK);
|
||||||
break;
|
break;
|
||||||
@@ -741,7 +787,6 @@ bool GPS::verifyCachedProbePresence()
|
|||||||
if (!present) {
|
if (!present) {
|
||||||
LOG_WARN("Cached GPS probe is stale (%s @ %d), clearing cache", cachedProbeModelName, cachedProbeBaud);
|
LOG_WARN("Cached GPS probe is stale (%s @ %d), clearing cache", cachedProbeModelName, cachedProbeBaud);
|
||||||
clearProbeCache();
|
clearProbeCache();
|
||||||
cachedProbeFailedThisBoot = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,13 +807,6 @@ bool GPS::setup()
|
|||||||
{
|
{
|
||||||
if (!didSerialInit) {
|
if (!didSerialInit) {
|
||||||
int msglen = 0;
|
int msglen = 0;
|
||||||
if (cachedProbeFailedThisBoot) {
|
|
||||||
// If cached verification failed, suppress further probing until
|
|
||||||
// reboot.
|
|
||||||
didSerialInit = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||||
if (!hasProbeCache && !triedProbeCache) {
|
if (!hasProbeCache && !triedProbeCache) {
|
||||||
(void)loadProbeCache();
|
(void)loadProbeCache();
|
||||||
@@ -777,12 +815,13 @@ bool GPS::setup()
|
|||||||
if (hasProbeCache && !triedProbeCache) {
|
if (hasProbeCache && !triedProbeCache) {
|
||||||
triedProbeCache = true;
|
triedProbeCache = true;
|
||||||
if (!verifyCachedProbePresence()) {
|
if (!verifyCachedProbePresence()) {
|
||||||
// Cache was stale and got wiped; skip scanning this boot
|
currentStep = 0;
|
||||||
// and let next boot do a full probe.
|
speedSelect = 0;
|
||||||
didSerialInit = true;
|
probeTries = 0;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} else if (probeTries < GPS_PROBETRIES) {
|
}
|
||||||
|
|
||||||
|
if (gnssModel == GNSS_MODEL_UNKNOWN && probeTries < GPS_PROBETRIES) {
|
||||||
// No usable cache: walk common baud rates first.
|
// No usable cache: walk common baud rates first.
|
||||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||||
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
||||||
@@ -794,7 +833,7 @@ bool GPS::setup()
|
|||||||
}
|
}
|
||||||
// Rare Serial Speeds
|
// Rare Serial Speeds
|
||||||
#ifndef CONFIG_IDF_TARGET_ESP32C6
|
#ifndef CONFIG_IDF_TARGET_ESP32C6
|
||||||
else if (probeTries == GPS_PROBETRIES) {
|
else if (gnssModel == GNSS_MODEL_UNKNOWN && probeTries == GPS_PROBETRIES) {
|
||||||
// Then try less common baud rates before giving up.
|
// Then try less common baud rates before giving up.
|
||||||
gnssModel = probe(rareSerialSpeeds[speedSelect]);
|
gnssModel = probe(rareSerialSpeeds[speedSelect]);
|
||||||
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
if (gnssModel != GNSS_MODEL_UNKNOWN) {
|
||||||
@@ -1125,6 +1164,15 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
|||||||
break;
|
break;
|
||||||
if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer
|
if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer
|
||||||
clearBuffer();
|
clearBuffer();
|
||||||
|
#ifdef TRACKER_T1000_E
|
||||||
|
pinMode(GPS_VRTC_EN, OUTPUT);
|
||||||
|
digitalWrite(GPS_VRTC_EN, HIGH);
|
||||||
|
pinMode(GPS_SLEEP_INT, OUTPUT);
|
||||||
|
digitalWrite(GPS_SLEEP_INT, HIGH);
|
||||||
|
pinMode(GPS_RTC_INT, OUTPUT);
|
||||||
|
digitalWrite(GPS_RTC_INT, LOW);
|
||||||
|
pinMode(GPS_RESETB_OUT, INPUT_PULLUP);
|
||||||
|
#endif
|
||||||
powerMon->setState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing)
|
powerMon->setState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing)
|
||||||
writePinEN(true); // Power (EN pin): on
|
writePinEN(true); // Power (EN pin): on
|
||||||
setPowerPMU(true); // Power (PMU): on
|
setPowerPMU(true); // Power (PMU): on
|
||||||
@@ -1383,9 +1431,8 @@ int32_t GPS::runOnce()
|
|||||||
if (!setup())
|
if (!setup())
|
||||||
return currentDelay; // Setup failed, re-run in two seconds
|
return currentDelay; // Setup failed, re-run in two seconds
|
||||||
|
|
||||||
if (cachedProbeFailedThisBoot || gnssModel == GNSS_MODEL_UNKNOWN) {
|
if (gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||||
LOG_WARN("GPS not detected at cached settings; marked not present "
|
LOG_WARN("GPS not detected; marked not present for this boot");
|
||||||
"for this boot");
|
|
||||||
return disable();
|
return disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1585,6 +1632,9 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||||
delay(10);
|
delay(10);
|
||||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
|
#ifdef TRACKER_T1000_E
|
||||||
|
delay(100);
|
||||||
|
#endif
|
||||||
|
|
||||||
// attempt to detect the chip based on boot messages
|
// attempt to detect the chip based on boot messages
|
||||||
std::vector<ChipInfo> passive_detect = {
|
std::vector<ChipInfo> passive_detect = {
|
||||||
@@ -1637,6 +1687,7 @@ GnssModel_t GPS::probe(int serialSpeed)
|
|||||||
}
|
}
|
||||||
case 3: {
|
case 3: {
|
||||||
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
|
/* Airoha (Mediatek) AG3335A/M/S, A3352Q, Quectel L89 2.0, SimCom SIM65M */
|
||||||
|
wakeAirohaForActiveProbe(_serial_gps);
|
||||||
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
|
_serial_gps->write("$PAIR062,2,0*3C\r\n"); // GSA OFF to reduce volume
|
||||||
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
|
_serial_gps->write("$PAIR062,3,0*3D\r\n"); // GSV OFF to reduce volume
|
||||||
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
|
_serial_gps->write("$PAIR513*3D\r\n"); // save configuration
|
||||||
@@ -1968,6 +2019,9 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
|||||||
t.tm_year = d.year() - 1900;
|
t.tm_year = d.year() - 1900;
|
||||||
t.tm_isdst = false;
|
t.tm_isdst = false;
|
||||||
if (t.tm_mon > -1) {
|
if (t.tm_mon > -1) {
|
||||||
|
if (!isPlausibleNmeaTime(t)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultSuccess) {
|
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultSuccess) {
|
||||||
LOG_DEBUG("NMEA GPS time set %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour,
|
LOG_DEBUG("NMEA GPS time set %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour,
|
||||||
t.tm_min, t.tm_sec, ti.age());
|
t.tm_min, t.tm_sec, ti.age());
|
||||||
|
|||||||
@@ -193,8 +193,6 @@ class GPS : private concurrency::OSThread
|
|||||||
bool hasProbeCache = false;
|
bool hasProbeCache = false;
|
||||||
// Ensures cached probe is attempted once per boot.
|
// Ensures cached probe is attempted once per boot.
|
||||||
bool triedProbeCache = false;
|
bool triedProbeCache = false;
|
||||||
// Latched when cached presence check fails
|
|
||||||
bool cachedProbeFailedThisBoot = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hasValidLocation - indicates that the position variables contain a complete
|
* hasValidLocation - indicates that the position variables contain a complete
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ void initVariant()
|
|||||||
digitalWrite(BUZZER_EN_PIN, HIGH);
|
digitalWrite(BUZZER_EN_PIN, HIGH);
|
||||||
|
|
||||||
pinMode(PIN_GPS_EN, OUTPUT);
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
digitalWrite(PIN_GPS_EN, LOW);
|
digitalWrite(PIN_GPS_EN, GPS_EN_ACTIVE);
|
||||||
|
|
||||||
pinMode(GPS_VRTC_EN, OUTPUT);
|
pinMode(GPS_VRTC_EN, OUTPUT);
|
||||||
digitalWrite(GPS_VRTC_EN, HIGH);
|
digitalWrite(GPS_VRTC_EN, HIGH);
|
||||||
|
|
||||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
digitalWrite(PIN_GPS_RESET, LOW);
|
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||||
|
|
||||||
pinMode(GPS_SLEEP_INT, OUTPUT);
|
pinMode(GPS_SLEEP_INT, OUTPUT);
|
||||||
digitalWrite(GPS_SLEEP_INT, HIGH);
|
digitalWrite(GPS_SLEEP_INT, HIGH);
|
||||||
@@ -59,5 +59,5 @@ void initVariant()
|
|||||||
pinMode(GPS_RTC_INT, OUTPUT);
|
pinMode(GPS_RTC_INT, OUTPUT);
|
||||||
digitalWrite(GPS_RTC_INT, LOW);
|
digitalWrite(GPS_RTC_INT, LOW);
|
||||||
|
|
||||||
pinMode(GPS_RESETB_OUT, INPUT);
|
pinMode(GPS_RESETB_OUT, INPUT_PULLUP);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user