diff --git a/TODO.md b/TODO.md index 520f36d7..44c249cb 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,7 @@ Items to complete before the first alpha release. +* have gps implement canSleep(), print nmea for debugging and discard buffers on the way into sleep * implement CustomRF95::canSleep * document rules for sleep wrt lora/bluetooth/screen/gps. also: if I have text messages (only) for the phone, then give a few seconds in the hopes BLE can get it across before we have to go back to sleep. * make gps prevent light sleep if we are waiting for data diff --git a/docs/README.md b/docs/README.md index bed0560f..1358cd36 100644 --- a/docs/README.md +++ b/docs/README.md @@ -66,6 +66,7 @@ For a nice Heltec 3D printable case see this [design](https://www.thingiverse.co This project is still pretty young but moving at a pretty good pace. Not all features are fully implemented in the current alpha builds. Most of these problems should be solved by the beta release: +* We don't make these devices and they haven't been tested by UL or the FCC. If you use them you are experimenting and we can't promise they won't burn your house down ;-) * Encryption is turned off for now * A number of (straightforward) software work items have to be completed before battery life matches our measurements, currently battery life is about two days. Join us on chat if you want the spreadsheet of power measurements/calculations. * The current Android GUI is pretty ugly still diff --git a/src/GPS.cpp b/src/GPS.cpp index 6b89e632..9465c571 100644 --- a/src/GPS.cpp +++ b/src/GPS.cpp @@ -8,12 +8,13 @@ HardwareSerial _serial_gps(GPS_SERIAL_NUM); uint32_t timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock -RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock (even across sleeps) +RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock (even across sleeps) GPS gps; bool hasValidLocation; // default to false, until we complete our first read +bool wantNewLocation; -GPS::GPS() : PeriodicTask() +GPS::GPS() : PeriodicTask() { } @@ -70,6 +71,25 @@ uint32_t GPS::getValidTime() return timeSetFromGPS ? getTime() : 0; } +/// Returns true if we think the board can enter deep or light sleep now (we might be trying to get a GPS lock) +bool GPS::canSleep() +{ + return !wantNewLocation; +} + +/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs +void GPS::prepareSleep() +{ + // discard all rx serial bytes so we don't try to parse them when we come back + while (_serial_gps.available()) + { + _serial_gps.read(); + } + + // make the parser bail on whatever it was parsing + encode('\n'); +} + void GPS::doTask() { #ifdef GPS_RX_PIN @@ -107,11 +127,14 @@ void GPS::doTask() { // we only notify if position has changed // DEBUG_MSG("new gps pos\n"); hasValidLocation = true; + wantNewLocation = false; notifyObservers(); } + else // we didn't get a location update, go back to sleep and hope the characters show up + wantNewLocation = true; - // Once we have sent a location we only poll the GPS rarely, otherwise check back every 100ms until we have something over the serial - setPeriod(hasValidLocation ? 30 * 1000 : 100); + // Once we have sent a location once we only poll the GPS rarely, otherwise check back every 100ms until we have something over the serial + setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 100); } String GPS::getTimeStr() diff --git a/src/GPS.h b/src/GPS.h index 9ff98cca..fe30b9d2 100644 --- a/src/GPS.h +++ b/src/GPS.h @@ -32,6 +32,12 @@ public: /// If we haven't yet set our RTC this boot, set it from a GPS derived time void perhapsSetRTC(const struct timeval *tv); + /// Returns true if we think the board can enter deep or light sleep now (we might be trying to get a GPS lock) + bool canSleep(); + + /// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs + void prepareSleep(); + private: void readFromRTC(); }; diff --git a/src/main.ino b/src/main.ino index 45a9ece9..8cb2953d 100644 --- a/src/main.ino +++ b/src/main.ino @@ -88,6 +88,14 @@ static void setLed(bool ledOn) #endif } +void setGPSPower(bool on) +{ +#ifdef T_BEAM_V10 + if (axp192_found) + axp.setPowerOutPut(AXP192_LDO3, on ? AXP202_ON : AXP202_OFF); // GPS main power +#endif +} + void doDeepSleep(uint64_t msecToWake) { DEBUG_MSG("Entering deep sleep for %llu seconds\n", msecToWake / 1000); @@ -126,7 +134,7 @@ void doDeepSleep(uint64_t msecToWake) // axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio - axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // GPS main power + setGPSPower(false); } #endif @@ -213,7 +221,8 @@ void doLightSleep(uint32_t sleepMsec = 20 * 1000) // FIXME, use a more reasonabl DEBUG_MSG("Enter light sleep\n"); uint64_t sleepUsec = sleepMsec * 1000LL; - setLed(false); // Never leave led on while in light sleep + gps.prepareSleep(); // abandon in-process parsing + setLed(false); // Never leave led on while in light sleep // NOTE! ESP docs say we must disable bluetooth and wifi before light sleep @@ -621,7 +630,7 @@ void loop() // while we have bluetooth on, we can't do light sleep, but once off stay in light_sleep all the time // we will wake from light sleep on button press or interrupt from the RF95 radio - if (!bluetoothOn && !is_screen_on() && service.radio.rf95.canSleep()) + if (!bluetoothOn && !is_screen_on() && service.radio.rf95.canSleep() && gps.canSleep()) doLightSleep(60 * 1000); // FIXME, wake up to briefly flash led, then go back to sleep (without repowering bluetooth) else {