Skip to content

Commit

Permalink
wip gps power fixes #376
Browse files Browse the repository at this point in the history
  • Loading branch information
geeksville committed Oct 1, 2020
1 parent 56d4250 commit bacc6ca
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 186 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"HFSR",
"Meshtastic",
"NEMAGPS",
"NMEAGPS",
"RDEF",
"Ublox",
"bkpt",
Expand Down
2 changes: 1 addition & 1 deletion src/PowerFSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static void lsIdle()
static void lsExit()
{
// setGPSPower(true); // restore GPS power
gps->startLock();
gps->forceWake(true);
}

static void nbEnter()
Expand Down
89 changes: 85 additions & 4 deletions src/gps/GPS.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include "GPS.h"
#include "configuration.h"
#include "sleep.h"
#include <assert.h>
#include <time.h>

Expand Down Expand Up @@ -86,19 +87,99 @@ uint32_t getValidTime()
return timeSetFromGPS ? getTime() : 0;
}

bool GPS::setup()
{
notifySleepObserver.observe(&notifySleep);

return true;
}

/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
* calls sleep/wake
*/
void GPS::setWantLocation(bool on)
void GPS::setAwake(bool on)
{
if (wantNewLocation != on) {
wantNewLocation = on;
if(!wakeAllowed && on) {
DEBUG_MSG("Inhibiting because !wakeAllowed\n");
on = false;
}

if (isAwake != on) {
DEBUG_MSG("WANT GPS=%d\n", on);
if (on)
wake();
else
sleep();

isAwake = on;
}
}

void GPS::loop()
{
if (whileIdle()) {
// if we have received valid NMEA claim we are connected
isConnected = true;
}

// If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis();
bool mustPublishUpdate = false;

if ((now - lastUpdateMsec) > 30 * 1000 && !isAwake) {
// We now want to be awake - so wake up the GPS
setAwake(true);

mustPublishUpdate =
true; // Even if we don't have an update this time, we at least want to occasionally publish the current state
}

// While we are awake
if (isAwake) {
DEBUG_MSG("looking for location\n");
bool gotTime = lookForTime();
bool gotLoc = lookForLocation();

if (gotLoc)
hasValidLocation = true;

mustPublishUpdate |= gotLoc;

// Once we get a location we no longer desperately want an update
if (gotLoc) {
lastUpdateMsec = now;
setAwake(false);
}
}
}

if (mustPublishUpdate) {
DEBUG_MSG("publishing GPS lock=%d\n", hasLock());

// Notify any status instances that are observing us
const meshtastic::GPSStatus status =
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status);
}
}

void GPS::forceWake(bool on)
{
if (on) {
DEBUG_MSG("Looking for GPS lock\n");
lastUpdateMsec = 0; // Force an update ASAP
wakeAllowed = true;
} else {
wakeAllowed = false;
setAwake(false);
}
}

/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
int GPS::prepareSleep(void *unused)
{
forceWake(false);

return 0;
}
72 changes: 54 additions & 18 deletions src/gps/GPS.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,18 @@ void readFromRTC();
*/
class GPS
{
protected:
private:
uint32_t lastUpdateMsec = 0;

bool hasValidLocation = false; // default to false, until we complete our first read

bool wantNewLocation = false; // true if we want a location right now
bool isAwake = false; // true if we want a location right now

bool wakeAllowed = true; // false if gps must be forced to sleep regardless of what time it is

CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);

protected:
public:
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
Expand All @@ -48,40 +55,69 @@ class GPS

bool isConnected = false; // Do we have a GPS we are talking to

virtual ~GPS() {}
virtual ~GPS() {} // FIXME, we really should unregister our sleep observer

/** We will notify this observable anytime GPS state has changed meaningfully */
Observable<const meshtastic::GPSStatus *> newStatus;

/**
* Returns true if we succeeded
*/
virtual bool setup() { return true; }
virtual bool setup();

/// A loop callback for subclasses that need it. FIXME, instead just block on serial reads
virtual void loop() {}
virtual void loop();

/// Returns ture if we have acquired GPS lock.
bool hasLock() const { return hasValidLocation; }

/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
* calls sleep/wake
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state
*
* Or set to false, to disallow any sort of waking
* */
void forceWake(bool on);

protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep() {}

/// wake the GPS into normal operation mode
virtual void wake() {}

/** 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
*/
void setWantLocation(bool on);
virtual bool whileIdle() = 0;

/**
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
* called after the CPU wakes from light-sleep state */
virtual void startLock() {}
* 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() = 0;

/**
* 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() = 0;

protected:
/// If possible force the GPS into sleep/low power mode
virtual void sleep() {}
private:
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareSleep(void *unused);

/// wake the GPS into normal operation mode
virtual void wake() {}
/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
* calls sleep/wake
*/
void setAwake(bool on);
};

extern GPS *gps;
Loading

0 comments on commit bacc6ca

Please sign in to comment.