From 7c253bfc3c7d4883dd3f86556903fae23187bc26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 4 May 2022 09:58:35 +0200 Subject: [PATCH] Backport T-Echo fix for GPS and Reset Button to 1.2 --- platformio.ini | 3 +- src/GPSStatus.h | 8 +- src/configuration.h | 8 + src/gps/Air530GPS.cpp | 84 ---------- src/gps/Air530GPS.h | 22 --- src/gps/GPS.cpp | 106 ++++++++---- src/gps/GPS.h | 3 - src/gps/NMEAGPS.cpp | 28 ++-- src/gps/UBloxGPS.cpp | 328 -------------------------------------- src/gps/UBloxGPS.h | 72 --------- src/main.cpp | 6 + variants/t-echo/variant.h | 4 +- 12 files changed, 112 insertions(+), 560 deletions(-) delete mode 100644 src/gps/Air530GPS.cpp delete mode 100644 src/gps/Air530GPS.h delete mode 100644 src/gps/UBloxGPS.cpp delete mode 100644 src/gps/UBloxGPS.h diff --git a/platformio.ini b/platformio.ini index 40ba8830e..eb39e70ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -83,9 +83,8 @@ lib_deps = mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git - https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74 - https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79 + https://github.com/meshtastic/TinyGPSPlus.git https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 Wire ; explicitly needed here because the AXP202 library forgets to add it SPI diff --git a/src/GPSStatus.h b/src/GPSStatus.h index bcd371eb8..a15e385a8 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -63,7 +63,7 @@ class GPSStatus : public Status int32_t getLatitude() const { if (radioConfig.preferences.fixed_position){ -#if GPS_EXTRAVERBOSE +#ifdef GPS_EXTRAVERBOSE DEBUG_MSG("WARNING: Using fixed latitude\n"); #endif NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); @@ -75,7 +75,7 @@ class GPSStatus : public Status int32_t getLongitude() const { if (radioConfig.preferences.fixed_position){ -#if GPS_EXTRAVERBOSE +#ifdef GPS_EXTRAVERBOSE DEBUG_MSG("WARNING: Using fixed longitude\n"); #endif NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); @@ -87,7 +87,7 @@ class GPSStatus : public Status int32_t getAltitude() const { if (radioConfig.preferences.fixed_position){ -#if GPS_EXTRAVERBOSE +#ifdef GPS_EXTRAVERBOSE DEBUG_MSG("WARNING: Using fixed altitude\n"); #endif NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); @@ -105,7 +105,7 @@ class GPSStatus : public Status bool matches(const GPSStatus *newStatus) const { -#if GPS_EXTRAVERBOSE +#ifdef GPS_EXTRAVERBOSE DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.pos_timestamp, p.pos_timestamp); #endif diff --git a/src/configuration.h b/src/configuration.h index 252da74dc..cb60609ec 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -100,6 +100,10 @@ along with this program. If not, see . #define GPS_TX_PIN 12 #endif +#ifndef TTGO_T_ECHO +#define GPS_UBLOX +#endif + // ----------------------------------------------------------------------------- // LoRa SPI // ----------------------------------------------------------------------------- @@ -149,6 +153,10 @@ along with this program. If not, see . #define GPS_BAUDRATE 9600 +#ifndef GPS_THREAD_INTERVAL +#define GPS_THREAD_INTERVAL 100 +#endif + #if defined(TBEAM_V10) // This string must exactly match the case used in release file names or the android updater won't work #define HW_VENDOR HardwareModel_TBEAM diff --git a/src/gps/Air530GPS.cpp b/src/gps/Air530GPS.cpp deleted file mode 100644 index 46070eb30..000000000 --- a/src/gps/Air530GPS.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "configuration.h" -#include "Air530GPS.h" -#include - -/* -Helpful translations from the Air530 GPS datasheet - -Sat acquision mode -捕获电流值@3.3v 42.6 mA - -sat tracking mode -跟踪电流值@3.3v 36.7 mA - -Low power mode -低功耗模式@3.3V 0.85 mA -(发送指令:$PGKC051,0) - -Super low power mode -超低功耗模式@3.3V 31 uA -(发送指令:$PGKC105,4) - -To exit sleep use WAKE pin - -Commands to enter sleep -6、Command: 105 -进入周期性低功耗模式 -Arguments: - -Arg1: “0”,正常运行模式 (normal mode) -“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up) -“2”,周期低功耗模式 (periodic low power mode) -“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume) -“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port) -“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume) - -(Arg 2 & 3 only valid if Arg1 is "1" or "2") -Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 -ON time in msecs - -Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用 -Sleep time in msecs - -Example: -$PGKC105,8*3F -This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a -new location. When we wake again in a minute we send a character to wake up. - -*/ - - -void Air530GPS::sendCommand(const char *cmd) { - uint8_t sum = 0; - - // Skip the $ - assert(cmd[0] == '$'); - const char *p = cmd + 1; - while(*p) - sum ^= *p++; - - assert(_serial_gps); - - _serial_gps->write(cmd); - _serial_gps->printf("*%02x\r\n", sum); - - // DEBUG_MSG("xsum %02x\n", sum); -} - -void Air530GPS::sleep() { - NMEAGPS::sleep(); -#ifdef PIN_GPS_WAKE - sendCommand("$PGKC105,4"); -#endif -} - -/// wake the GPS into normal operation mode -void Air530GPS::wake() -{ -#if 1 - NMEAGPS::wake(); -#else - // For power testing - keep GPS sleeping forever - sleep(); -#endif -} \ No newline at end of file diff --git a/src/gps/Air530GPS.h b/src/gps/Air530GPS.h deleted file mode 100644 index 535b08029..000000000 --- a/src/gps/Air530GPS.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "NMEAGPS.h" - -/** - * A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading) - * - * When new data is available it will notify observers. - */ -class Air530GPS : public NMEAGPS -{ - protected: - /// If possible force the GPS into sleep/low power mode - virtual void sleep() override; - - /// wake the GPS into normal operation mode - virtual void wake() override; - - private: - /// Send a NMEA cmd with checksum - void sendCommand(const char *str); -}; diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index c1e480347..a02142697 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -16,12 +16,6 @@ HardwareSerial *GPS::_serial_gps = &Serial1; HardwareSerial *GPS::_serial_gps = NULL; #endif -#ifdef GPS_I2C_ADDRESS -uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS; -#else -uint8_t GPS::i2cAddress = 0; -#endif - GPS *gps; /// Multiple GPS instances might use the same serial port (in sequence), but we can @@ -41,6 +35,75 @@ bool GPS::setupGPS() #endif #ifndef NO_ESP32 _serial_gps->setRxBufferSize(2048); // the default is 256 +#endif +#ifdef TTGO_T_ECHO + // Switch to 4800 baud, then close and reopen port + _serial_gps->write("$PCAS01,0*1C\r\n"); + delay(250); + _serial_gps->end(); + delay(250); + _serial_gps->begin(4800); + delay(250); + // Initialize the L76K Chip, use GPS + GLONASS + _serial_gps->write("$PCAS04,5*1C\r\n"); + delay(250); + // only ask for RMC and GGA + _serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); + delay(250); + // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g + _serial_gps->write("$PCAS11,3*1E\r\n"); + delay(250); + +#endif +#ifdef GPS_UBLOX + // Set the UART port to output NMEA only + byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x91, 0xAF}; + _serial_gps->write(_message_nmea,sizeof(_message_nmea)); + delay(250); + + // disable GGL + byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x05,0x3A}; + _serial_gps->write(_message_GGL,sizeof(_message_GGL)); + delay(250); + + // disable GSA + byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x06,0x41}; + _serial_gps->write(_message_GSA,sizeof(_message_GSA)); + delay(250); + + // disable GSV + byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x07,0x48}; + _serial_gps->write(_message_GSV,sizeof(_message_GSV)); + delay(250); + + // disable VTG + byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x09,0x56}; + _serial_gps->write(_message_VTG,sizeof(_message_VTG)); + delay(250); + + // enable RMC + byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x09,0x54}; + _serial_gps->write(_message_RMC,sizeof(_message_RMC)); + delay(250); + + // enable GGA + byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, + 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x05, 0x38}; + _serial_gps->write(_message_GGA,sizeof(_message_GGA)); + delay(250); #endif } @@ -51,7 +114,7 @@ bool GPS::setup() { // Master power for the GPS #ifdef PIN_GPS_EN - digitalWrite(PIN_GPS_EN, PIN_GPS_EN); + digitalWrite(PIN_GPS_EN, 1); pinMode(PIN_GPS_EN, OUTPUT); #endif @@ -257,7 +320,6 @@ int32_t GPS::runOnce() bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; // Once we get a location we no longer desperately want an update - // or if we got a time and we are in GpsOpTimeOnly mode // DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) { @@ -280,7 +342,7 @@ int32_t GPS::runOnce() // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. - return isAwake ? 100 : 5000; + return isAwake ? GPS_THREAD_INTERVAL : 5000; } void GPS::forceWake(bool on) @@ -318,13 +380,7 @@ int GPS::prepareDeepSleep(void *unused) return 0; } -#ifdef GPS_TX_PIN -#include "UBloxGPS.h" -#endif - -#ifdef HAS_AIR530_GPS -#include "Air530GPS.h" -#elif !defined(NO_GPS) +#ifndef NO_GPS #include "NMEAGPS.h" #endif @@ -339,29 +395,11 @@ GPS *createGps() #else DEBUG_MSG("Using MSL altitude model\n"); #endif -// If we don't have bidirectional comms, we can't even try talking to UBLOX -#ifdef GPS_TX_PIN - // Init GPS - first try ublox - UBloxGPS *ublox = new UBloxGPS(); - - if (!ublox->setup()) { - DEBUG_MSG("ERROR: No UBLOX GPS found\n"); - delete ublox; - ublox = NULL; - } else { - return ublox; - } -#endif - if (GPS::_serial_gps) { // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just // assume NMEA at 9600 baud. DEBUG_MSG("Hoping that NMEA might work\n"); -#ifdef HAS_AIR530_GPS - GPS *new_gps = new Air530GPS(); -#else GPS *new_gps = new NMEAGPS(); -#endif new_gps->setup(); return new_gps; } diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 4764d1fb3..5724889fe 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread /** If !NULL we will use this serial port to construct our GPS */ static HardwareSerial *_serial_gps; - /** If !0 we will attempt to connect to the GPS over I2C */ - static uint8_t i2cAddress; - Position p = Position_init_default; GPS() : concurrency::OSThread("GPS") {} diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index d0d5e46e2..8a8181f3b 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -5,7 +5,7 @@ #include // GPS solutions older than this will be rejected - see TinyGPSDatum::age() -#define GPS_SOL_EXPIRY_MS 300 // in millis +#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) static int32_t toDegInt(RawDegrees d) @@ -64,11 +64,12 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_isdst = false; - DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec); - - perhapsSetRTC(RTCQualityGPS, t); - - return true; + if (t.tm_mon > -1){ + DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); + perhapsSetRTC(RTCQualityGPS, t); + return true; + } else + return false; } else return false; } @@ -116,7 +117,7 @@ bool NMEAGPS::lookForLocation() (reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.date.age() < GPS_SOL_EXPIRY_MS))) { - DEBUG_MSG("SOME data is TOO OLD\n"); + DEBUG_MSG("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age()); return false; } @@ -127,10 +128,17 @@ bool NMEAGPS::lookForLocation() // We know the solution is fresh and valid, so just read the data auto loc = reader.location.value(); - // Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus // Bail out EARLY to avoid overwriting previous good data (like #857) - if(toDegInt(loc.lat) == 0) { - DEBUG_MSG("Ignoring bogus NMEA position\n"); + if (toDegInt(loc.lat) > 900000000) { +#ifdef GPS_EXTRAVERBOSE + DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat)); +#endif + return false; + } + if (toDegInt(loc.lng) > 1800000000) { +#ifdef GPS_EXTRAVERBOSE + DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng)); +#endif return false; } diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp deleted file mode 100644 index 70fc91ecd..000000000 --- a/src/gps/UBloxGPS.cpp +++ /dev/null @@ -1,328 +0,0 @@ -#include "configuration.h" -#include "UBloxGPS.h" -#include "RTC.h" -#include "error.h" -#include "sleep.h" -#include - -// if gps_update_interval below this value, do not powercycle the GPS -#define UBLOX_POWEROFF_THRESHOLD 90 - -#define PDOP_INVALID 9999 - -// #define UBX_MODE_NMEA - -extern RadioConfig radioConfig; - -UBloxGPS::UBloxGPS() {} - -bool UBloxGPS::tryConnect() -{ - bool c = false; - - if (_serial_gps) - c = ublox.begin(*_serial_gps); - - if (!c && i2cAddress) { - extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which - // supports the newer API - neo6M = true; - - c = ublox.begin(Wire, i2cAddress); - } - - if (c) - setConnected(); - - return c; -} - -bool UBloxGPS::setupGPS() -{ - GPS::setupGPS(); - - // uncomment to see debug info - // ublox.enableDebugging(Serial); - - // try a second time, the ublox lib serial parsing is buggy? - // see https://github.com/meshtastic/Meshtastic-device/issues/376 - for (int i = 0; (i < 3) && !tryConnect(); i++) - delay(500); - - if (isConnected()) { -#ifdef UBX_MODE_NMEA - DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n"); - DEBUG_MSG("- GPS errors below are related and safe to ignore\n"); -#else - DEBUG_MSG("Connected to UBLOX GPS successfully\n"); -#endif - - if (!setUBXMode()) - RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug - -#ifdef UBX_MODE_NMEA - return false; -#else - return true; -#endif - - } else { - return false; - } -} - -bool UBloxGPS::setUBXMode() -{ -#ifdef UBX_MODE_NMEA - if (_serial_gps) { - ublox.setUART1Output(COM_TYPE_NMEA, 1000); - } - if (i2cAddress) { - ublox.setI2COutput(COM_TYPE_NMEA, 1000); - } - - return false; // pretend initialization failed to force NMEA mode -#endif - - if (_serial_gps) { - if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API - return false; - } - if (i2cAddress) { - if (!ublox.setI2COutput(COM_TYPE_UBX, 1000)) - return false; - } - - if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low - return false; - - // ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M - // assert(ok); - // ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds - // assert(ok); - - // per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal - // TTGO antennas - // if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight) - // return false; - - if (!ublox.saveConfiguration(3000)) - return false; - - return true; -} - -/** - * Reset our GPS back to factory settings - * - * @return true for success - */ -bool UBloxGPS::factoryReset() -{ - bool ok = false; - - // It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have - // GPS_TX connected) - ublox.factoryReset(); - delay(5000); - tryConnect(); // sets isConnected - - // try a second time, the ublox lib serial parsing is buggy? - for (int i = 0; (i < 3) && !tryConnect(); i++) - delay(500); - - DEBUG_MSG("GPS Factory reset success=%d\n", isConnected()); - if (isConnected()) - ok = setUBXMode(); - - return ok; -} - -/** Idle processing while GPS is looking for lock */ -void UBloxGPS::whileActive() -{ - ublox.flushPVT(); // reset ALL freshness flags first - ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back - - // Ask for a new position fix - hopefully it will have results ready by next time - // the order here is important, because we only check for has latitude when reading - - //ublox.getSIV(maxWait()); // redundant with getPDOP below - ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others - ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others - - // the fixType flag will be checked and updated in lookForLocation() -} - -/** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ -bool UBloxGPS::lookForTime() -{ - if (ublox.moduleQueried.gpsSecond) { - /* Convert to unix time - The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January - 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z). - */ - struct tm t; - t.tm_sec = ublox.getSecond(0); - t.tm_min = ublox.getMinute(0); - t.tm_hour = ublox.getHour(0); - t.tm_mday = ublox.getDay(0); - t.tm_mon = ublox.getMonth(0) - 1; - t.tm_year = ublox.getYear(0) - 1900; - t.tm_isdst = false; - perhapsSetRTC(RTCQualityGPS, t); - return true; - } - - return false; -} - -/** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ -bool UBloxGPS::lookForLocation() -{ - bool foundLocation = false; - - // check if a complete GPS solution set is available for reading - // (some of these, like lat/lon are redundant and can be removed) - if ( ! (ublox.moduleQueried.fixType && - ublox.moduleQueried.latitude && - ublox.moduleQueried.longitude && - ublox.moduleQueried.altitude && - ublox.moduleQueried.pDOP && - ublox.moduleQueried.SIV && - ublox.moduleQueried.gpsDay)) - { - // Not ready? No problem! We'll try again later. - return false; - } - - fixType = ublox.getFixType(); -#ifdef UBLOX_EXTRAVERBOSE - DEBUG_MSG("FixType=%d\n", fixType); -#endif - - - // check if GPS has an acceptable lock - if (! hasLock()) { - ublox.flushPVT(); // reset ALL freshness flags - return false; - } - - // read lat/lon/alt/dop data into temporary variables to avoid - // overwriting global variables with potentially invalid data - int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it - int32_t tmp_lat = ublox.getLatitude(0); - int32_t tmp_lon = ublox.getLongitude(0); - int32_t tmp_alt_msl = ublox.getAltitudeMSL(0); - int32_t tmp_alt_hae = ublox.getAltitude(0); - int32_t max_dop = PDOP_INVALID; - if (radioConfig.preferences.gps_max_dop) - max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling - - // Note: heading is only currently implmented in the ublox for the 8m chipset - therefore - // don't read it here - it will generate an ignored getPVT command on the 6ms - // heading = ublox.getHeading(0); - - // read positional timestamp - struct tm t; - t.tm_sec = ublox.getSecond(0); - t.tm_min = ublox.getMinute(0); - t.tm_hour = ublox.getHour(0); - t.tm_mday = ublox.getDay(0); - t.tm_mon = ublox.getMonth(0) - 1; - t.tm_year = ublox.getYear(0) - 1900; - t.tm_isdst = false; - - time_t tmp_ts = mktime(&t); - - // FIXME - can opportunistically attempt to set RTC from GPS timestamp? - - // bogus lat lon is reported as 0 or 0 (can be bogus just for one) - // Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg! - // FIXME - NULL ISLAND is a real location on Earth! - foundLocation = (tmp_lat != 0) && (tmp_lon != 0) && - (tmp_lat <= 900000000) && (tmp_lat >= -900000000) && - (tmp_dop < max_dop); - - // only if entire dataset is valid, update globals from temp vars - if (foundLocation) { - p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL; - p.longitude_i = tmp_lon; - p.latitude_i = tmp_lat; - if (fixType > 2) { - // if fix is 2d, ignore altitude data - p.altitude = tmp_alt_msl / 1000; - p.altitude_hae = tmp_alt_hae / 1000; - p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000; - } else { -#ifdef GPS_EXTRAVERBOSE - DEBUG_MSG("no altitude data (fixType=%d)\n", fixType); -#endif - // clean up old values in case it's a 3d-2d fix transition - p.altitude = p.altitude_hae = p.alt_geoid_sep = 0; - } - p.pos_timestamp = tmp_ts; - p.PDOP = tmp_dop; - p.fix_type = fixType; - p.sats_in_view = ublox.getSIV(0); - // In debug logs, identify position by @timestamp:stage (stage 1 = birth) - DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts); - } else { - // INVALID solution - should never happen - DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n", - tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop); - } - - ublox.flushPVT(); // reset ALL freshness flags at the end - - return foundLocation; -} - -bool UBloxGPS::hasLock() -{ - if (radioConfig.preferences.gps_accept_2d) - return (fixType >= 2 && fixType <= 4); - else - return (fixType >= 3 && fixType <= 4); -} - -bool UBloxGPS::whileIdle() -{ - // if using i2c or serial look too see if any chars are ready - return ublox.checkUblox(); // See if new data is available. Process bytes as they come in. -} - -/// If possible force the GPS into sleep/low power mode -/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up -void UBloxGPS::sleep() -{ - if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) { - // Tell GPS to power down until we send it characters on serial port (we leave vcc connected) - ublox.powerOff(); - // setGPSPower(false); - } -} - -void UBloxGPS::wake() -{ - if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) { - fixType = 0; // assume we have no fix yet - } - - // this is idempotent - setGPSPower(true); - - // Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff() - // Give time for the GPS to boot - // delay(200); -} \ No newline at end of file diff --git a/src/gps/UBloxGPS.h b/src/gps/UBloxGPS.h deleted file mode 100644 index 3d940832f..000000000 --- a/src/gps/UBloxGPS.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include "GPS.h" -#include "Observer.h" -#include "SparkFun_Ublox_Arduino_Library.h" - -/** - * A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading) - * - * When new data is available it will notify observers. - */ -class UBloxGPS : public GPS -{ - SFE_UBLOX_GPS ublox; - uint8_t fixType = 0; - - public: - UBloxGPS(); - - /** - * Reset our GPS back to factory settings - * - * @return true for success - */ - bool factoryReset() override; - - protected: - /** - * Returns true if we succeeded - */ - virtual bool setupGPS() override; - - /** Subclasses should look for serial rx characters here and feed it to their GPS parser - * - * Return true if we received a valid message from the GPS - */ - virtual bool whileIdle() override; - - /** Idle processing while GPS is looking for lock */ - virtual void whileActive() override; - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a time - */ - virtual bool lookForTime() override; - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ - virtual bool lookForLocation() override; - virtual bool hasLock() override; - - /// If possible force the GPS into sleep/low power mode - virtual void sleep() override; - virtual void wake() override; - - private: - /// Attempt to connect to our GPS, returns false if no gps is present - bool tryConnect(); - - /// Switch to our desired operating mode and save the settings to flash - /// returns true for success - bool setUBXMode(); - - uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ } -}; diff --git a/src/main.cpp b/src/main.cpp index d3804ef2c..00a540b51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -408,6 +408,12 @@ void setup() initDeepSleep(); + // Testing this fix für erratic T-Echo boot behaviour +#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON) + pinMode(PIN_EINK_PWR_ON, OUTPUT); + digitalWrite(PIN_EINK_PWR_ON, HIGH); +#endif + #ifdef VEXT_ENABLE pinMode(VEXT_ENABLE, OUTPUT); digitalWrite(VEXT_ENABLE, 0); // turn on the display power diff --git a/variants/t-echo/variant.h b/variants/t-echo/variant.h index a1471c67b..97e6de985 100644 --- a/variants/t-echo/variant.h +++ b/variants/t-echo/variant.h @@ -226,7 +226,7 @@ External serial flash WP25R1635FZUIL0 #define PIN_SPI1_SCK PIN_EINK_SCLK /* - * Air530 GPS pins + * GPS pins */ #define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake @@ -235,6 +235,8 @@ External serial flash WP25R1635FZUIL0 #define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU #define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS +#define GPS_THREAD_INTERVAL 50 + #define PIN_SERIAL1_RX PIN_GPS_TX #define PIN_SERIAL1_TX PIN_GPS_RX