diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 9c5e16864..b2fbcac8d 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -80,6 +80,12 @@ namespace constexpr uint32_t GPS_PROBE_CACHE_MAGIC = 0x47504348UL; // "GPCH" constexpr uint16_t GPS_PROBE_CACHE_VERSION = 1; 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 { uint32_t magic; @@ -101,6 +107,45 @@ bool isValidProbeBaud(uint32_t baud) return baud >= 1200 && baud <= 921600; } +template 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(gm_mktime(&t)); + const int64_t minEpoch = static_cast(BUILD_EPOCH); + const int64_t maxEpoch = minEpoch + static_cast(FORTY_YEARS); + return candidate >= minEpoch && candidate <= maxEpoch; +#else + return true; +#endif +} + template bool sawNmeaSentenceAtBaud(T *serialGps, uint32_t timeoutMs) { // Lightweight passive check: look for at least one complete @@ -689,6 +734,7 @@ bool GPS::verifyCachedProbePresence() case GNSS_MODEL_AG3352: if (cachedProbeModel == GNSS_MODEL_AG3352) cachedProbeModelName = "AG3352"; + wakeAirohaForActiveProbe(_serial_gps); _serial_gps->write("$PAIR021*39\r\n"); present = (getACK("$PAIR021,", 900) == GNSS_RESPONSE_OK); break; @@ -741,7 +787,6 @@ bool GPS::verifyCachedProbePresence() if (!present) { LOG_WARN("Cached GPS probe is stale (%s @ %d), clearing cache", cachedProbeModelName, cachedProbeBaud); clearProbeCache(); - cachedProbeFailedThisBoot = true; return false; } @@ -762,13 +807,6 @@ bool GPS::setup() { if (!didSerialInit) { 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 (!hasProbeCache && !triedProbeCache) { (void)loadProbeCache(); @@ -777,12 +815,13 @@ bool GPS::setup() if (hasProbeCache && !triedProbeCache) { triedProbeCache = true; if (!verifyCachedProbePresence()) { - // Cache was stale and got wiped; skip scanning this boot - // and let next boot do a full probe. - didSerialInit = true; - return true; + currentStep = 0; + speedSelect = 0; + probeTries = 0; } - } else if (probeTries < GPS_PROBETRIES) { + } + + if (gnssModel == GNSS_MODEL_UNKNOWN && probeTries < GPS_PROBETRIES) { // No usable cache: walk common baud rates first. gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel != GNSS_MODEL_UNKNOWN) { @@ -794,7 +833,7 @@ bool GPS::setup() } // Rare Serial Speeds #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. gnssModel = probe(rareSerialSpeeds[speedSelect]); if (gnssModel != GNSS_MODEL_UNKNOWN) { @@ -1125,6 +1164,15 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) break; if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer 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) writePinEN(true); // Power (EN pin): on setPowerPMU(true); // Power (PMU): on @@ -1383,9 +1431,8 @@ int32_t GPS::runOnce() if (!setup()) return currentDelay; // Setup failed, re-run in two seconds - if (cachedProbeFailedThisBoot || gnssModel == GNSS_MODEL_UNKNOWN) { - LOG_WARN("GPS not detected at cached settings; marked not present " - "for this boot"); + if (gnssModel == GNSS_MODEL_UNKNOWN) { + LOG_WARN("GPS not detected; marked not present for this boot"); return disable(); } @@ -1585,6 +1632,9 @@ GnssModel_t GPS::probe(int serialSpeed) digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms delay(10); digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); +#ifdef TRACKER_T1000_E + delay(100); +#endif // attempt to detect the chip based on boot messages std::vector passive_detect = { @@ -1637,6 +1687,7 @@ GnssModel_t GPS::probe(int serialSpeed) } case 3: { /* 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,3,0*3D\r\n"); // GSV OFF to reduce volume _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_isdst = false; if (t.tm_mon > -1) { + if (!isPlausibleNmeaTime(t)) { + return false; + } 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, t.tm_min, t.tm_sec, ti.age()); diff --git a/src/gps/GPS.h b/src/gps/GPS.h index a0845331d..25de0379a 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -193,8 +193,6 @@ class GPS : private concurrency::OSThread bool hasProbeCache = false; // Ensures cached probe is attempted once per boot. bool triedProbeCache = false; - // Latched when cached presence check fails - bool cachedProbeFailedThisBoot = false; /** * hasValidLocation - indicates that the position variables contain a complete diff --git a/variants/nrf52840/tracker-t1000-e/variant.cpp b/variants/nrf52840/tracker-t1000-e/variant.cpp index 0f7c5adaa..fd2f77e73 100644 --- a/variants/nrf52840/tracker-t1000-e/variant.cpp +++ b/variants/nrf52840/tracker-t1000-e/variant.cpp @@ -45,13 +45,13 @@ void initVariant() digitalWrite(BUZZER_EN_PIN, HIGH); pinMode(PIN_GPS_EN, OUTPUT); - digitalWrite(PIN_GPS_EN, LOW); + digitalWrite(PIN_GPS_EN, GPS_EN_ACTIVE); pinMode(GPS_VRTC_EN, OUTPUT); digitalWrite(GPS_VRTC_EN, HIGH); pinMode(PIN_GPS_RESET, OUTPUT); - digitalWrite(PIN_GPS_RESET, LOW); + digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); pinMode(GPS_SLEEP_INT, OUTPUT); digitalWrite(GPS_SLEEP_INT, HIGH); @@ -59,5 +59,5 @@ void initVariant() pinMode(GPS_RTC_INT, OUTPUT); digitalWrite(GPS_RTC_INT, LOW); - pinMode(GPS_RESETB_OUT, INPUT); -} \ No newline at end of file + pinMode(GPS_RESETB_OUT, INPUT_PULLUP); +}