mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-25 17:42:48 +00:00
wip gps power fixes #376
This commit is contained in:
parent
56d4250197
commit
bacc6caf04
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -57,6 +57,7 @@
|
|||||||
"HFSR",
|
"HFSR",
|
||||||
"Meshtastic",
|
"Meshtastic",
|
||||||
"NEMAGPS",
|
"NEMAGPS",
|
||||||
|
"NMEAGPS",
|
||||||
"RDEF",
|
"RDEF",
|
||||||
"Ublox",
|
"Ublox",
|
||||||
"bkpt",
|
"bkpt",
|
||||||
|
@ -91,7 +91,7 @@ static void lsIdle()
|
|||||||
static void lsExit()
|
static void lsExit()
|
||||||
{
|
{
|
||||||
// setGPSPower(true); // restore GPS power
|
// setGPSPower(true); // restore GPS power
|
||||||
gps->startLock();
|
gps->forceWake(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbEnter()
|
static void nbEnter()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "sleep.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -86,19 +87,99 @@ uint32_t getValidTime()
|
|||||||
return timeSetFromGPS ? getTime() : 0;
|
return timeSetFromGPS ? getTime() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPS::setup()
|
||||||
|
{
|
||||||
|
notifySleepObserver.observe(¬ifySleep);
|
||||||
|
|
||||||
|
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
|
* 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
|
* calls sleep/wake
|
||||||
*/
|
*/
|
||||||
void GPS::setWantLocation(bool on)
|
void GPS::setAwake(bool on)
|
||||||
{
|
{
|
||||||
if (wantNewLocation != on) {
|
if(!wakeAllowed && on) {
|
||||||
wantNewLocation = on;
|
DEBUG_MSG("Inhibiting because !wakeAllowed\n");
|
||||||
|
on = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAwake != on) {
|
||||||
DEBUG_MSG("WANT GPS=%d\n", on);
|
DEBUG_MSG("WANT GPS=%d\n", on);
|
||||||
if (on)
|
if (on)
|
||||||
wake();
|
wake();
|
||||||
else
|
else
|
||||||
sleep();
|
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;
|
||||||
}
|
}
|
@ -27,11 +27,18 @@ void readFromRTC();
|
|||||||
*/
|
*/
|
||||||
class GPS
|
class GPS
|
||||||
{
|
{
|
||||||
protected:
|
private:
|
||||||
|
uint32_t lastUpdateMsec = 0;
|
||||||
|
|
||||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
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:
|
public:
|
||||||
/** If !NULL we will use this serial port to construct our GPS */
|
/** If !NULL we will use this serial port to construct our GPS */
|
||||||
static HardwareSerial *_serial_gps;
|
static HardwareSerial *_serial_gps;
|
||||||
@ -48,7 +55,7 @@ class GPS
|
|||||||
|
|
||||||
bool isConnected = false; // Do we have a GPS we are talking to
|
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 */
|
/** We will notify this observable anytime GPS state has changed meaningfully */
|
||||||
Observable<const meshtastic::GPSStatus *> newStatus;
|
Observable<const meshtastic::GPSStatus *> newStatus;
|
||||||
@ -56,32 +63,61 @@ class GPS
|
|||||||
/**
|
/**
|
||||||
* Returns true if we succeeded
|
* 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.
|
/// Returns ture if we have acquired GPS lock.
|
||||||
bool hasLock() const { return hasValidLocation; }
|
bool hasLock() const { return hasValidLocation; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
virtual bool whileIdle() = 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 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
* 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
|
* calls sleep/wake
|
||||||
*/
|
*/
|
||||||
void setWantLocation(bool on);
|
void setAwake(bool on);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/// If possible force the GPS into sleep/low power mode
|
|
||||||
virtual void sleep() {}
|
|
||||||
|
|
||||||
/// wake the GPS into normal operation mode
|
|
||||||
virtual void wake() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GPS *gps;
|
extern GPS *gps;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "NMEAGPS.h"
|
#include "NMEAGPS.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
|
||||||
static int32_t toDegInt(RawDegrees d)
|
static int32_t toDegInt(RawDegrees d)
|
||||||
{
|
{
|
||||||
int32_t degMult = 10000000; // 1e7
|
int32_t degMult = 10000000; // 1e7
|
||||||
@ -18,93 +17,94 @@ bool NMEAGPS::setup()
|
|||||||
// FIXME - move into shared GPS code
|
// FIXME - move into shared GPS code
|
||||||
pinMode(PIN_GPS_PPS, INPUT);
|
pinMode(PIN_GPS_PPS, INPUT);
|
||||||
#endif
|
#endif
|
||||||
|
GPS::setup();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NMEAGPS::loop()
|
/**
|
||||||
|
* 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 NMEAGPS::lookForTime()
|
||||||
{
|
{
|
||||||
|
auto ti = reader.time;
|
||||||
|
auto d = reader.date;
|
||||||
|
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
||||||
|
/* 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 = ti.second();
|
||||||
|
t.tm_min = ti.minute();
|
||||||
|
t.tm_hour = ti.hour();
|
||||||
|
t.tm_mday = d.day();
|
||||||
|
t.tm_mon = d.month() - 1;
|
||||||
|
t.tm_year = d.year() - 1900;
|
||||||
|
t.tm_isdst = false;
|
||||||
|
perhapsSetRTC(t);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
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 NMEAGPS::lookForLocation()
|
||||||
|
{
|
||||||
|
bool foundLocation = false;
|
||||||
|
|
||||||
|
// uint8_t fixtype = reader.fixQuality();
|
||||||
|
// hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
||||||
|
|
||||||
|
if (reader.location.isUpdated()) {
|
||||||
|
if (reader.altitude.isValid())
|
||||||
|
altitude = reader.altitude.meters();
|
||||||
|
|
||||||
|
if (reader.location.isValid()) {
|
||||||
|
auto loc = reader.location.value();
|
||||||
|
latitude = toDegInt(loc.lat);
|
||||||
|
longitude = toDegInt(loc.lng);
|
||||||
|
foundLocation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||||
|
if (reader.hdop.isValid()) {
|
||||||
|
dop = reader.hdop.value();
|
||||||
|
}
|
||||||
|
if (reader.course.isValid()) {
|
||||||
|
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
||||||
|
}
|
||||||
|
if (reader.satellites.isValid()) {
|
||||||
|
numSatellites = reader.satellites.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
||||||
|
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude,
|
||||||
|
dop * 1e-2, heading * 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NMEAGPS::whileIdle()
|
||||||
|
{
|
||||||
|
bool isValid = false;
|
||||||
|
|
||||||
// First consume any chars that have piled up at the receiver
|
// First consume any chars that have piled up at the receiver
|
||||||
while (_serial_gps->available() > 0) {
|
while (_serial_gps->available() > 0) {
|
||||||
int c = _serial_gps->read();
|
int c = _serial_gps->read();
|
||||||
// DEBUG_MSG("%c", c);
|
// DEBUG_MSG("%c", c);
|
||||||
bool isValid = reader.encode(c);
|
isValid |= reader.encode(c);
|
||||||
|
|
||||||
// if we have received valid NMEA claim we are connected
|
|
||||||
if (isValid)
|
|
||||||
isConnected = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are overdue for an update, turn on the GPS and at least publish the current status
|
return isValid;
|
||||||
uint32_t now = millis();
|
|
||||||
bool mustPublishUpdate = false;
|
|
||||||
if ((now - lastUpdateMsec) > 30 * 1000 && !wantNewLocation) {
|
|
||||||
// Ugly hack for now - limit update checks to once every 30 secs
|
|
||||||
setWantLocation(true);
|
|
||||||
mustPublishUpdate =
|
|
||||||
true; // Even if we don't have an update this time, we at least want to occasionally publish the current state
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only bother looking at GPS state if we are interested in what it has to say
|
|
||||||
if (wantNewLocation) {
|
|
||||||
auto ti = reader.time;
|
|
||||||
auto d = reader.date;
|
|
||||||
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
|
||||||
/* 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 = ti.second();
|
|
||||||
t.tm_min = ti.minute();
|
|
||||||
t.tm_hour = ti.hour();
|
|
||||||
t.tm_mday = d.day();
|
|
||||||
t.tm_mon = d.month() - 1;
|
|
||||||
t.tm_year = d.year() - 1900;
|
|
||||||
t.tm_isdst = false;
|
|
||||||
perhapsSetRTC(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t fixtype = reader.fixQuality();
|
|
||||||
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
|
||||||
|
|
||||||
if (reader.location.isUpdated()) {
|
|
||||||
lastUpdateMsec = now;
|
|
||||||
|
|
||||||
if (reader.altitude.isValid())
|
|
||||||
altitude = reader.altitude.meters();
|
|
||||||
|
|
||||||
if (reader.location.isValid()) {
|
|
||||||
auto loc = reader.location.value();
|
|
||||||
latitude = toDegInt(loc.lat);
|
|
||||||
longitude = toDegInt(loc.lng);
|
|
||||||
|
|
||||||
// Once we get a location we no longer desperately want an update
|
|
||||||
setWantLocation(false);
|
|
||||||
}
|
|
||||||
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
|
||||||
if (reader.hdop.isValid()) {
|
|
||||||
dop = reader.hdop.value();
|
|
||||||
}
|
|
||||||
if (reader.course.isValid()) {
|
|
||||||
heading =
|
|
||||||
reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
|
||||||
}
|
|
||||||
if (reader.satellites.isValid()) {
|
|
||||||
numSatellites = reader.satellites.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
|
||||||
DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7,
|
|
||||||
altitude, dop * 1e-2, heading * 1e-5);
|
|
||||||
mustPublishUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mustPublishUpdate) {
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -14,10 +14,29 @@ class NMEAGPS : public GPS
|
|||||||
{
|
{
|
||||||
TinyGPSPlus reader;
|
TinyGPSPlus reader;
|
||||||
|
|
||||||
uint32_t lastUpdateMsec = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool setup();
|
virtual bool setup();
|
||||||
|
|
||||||
virtual void loop();
|
protected:
|
||||||
|
/** 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#include "UBloxGPS.h"
|
#include "UBloxGPS.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "sleep.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
UBloxGPS::UBloxGPS() : concurrency::PeriodicTask()
|
UBloxGPS::UBloxGPS()
|
||||||
{
|
{
|
||||||
notifySleepObserver.observe(¬ifySleep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UBloxGPS::tryConnect()
|
bool UBloxGPS::tryConnect()
|
||||||
@ -53,13 +51,15 @@ bool UBloxGPS::setup()
|
|||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||||
|
|
||||||
|
GPS::setup();
|
||||||
|
|
||||||
if (!setUBXMode())
|
if (!setUBXMode())
|
||||||
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
recordCriticalError(UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||||
|
|
||||||
concurrency::PeriodicTask::setup(); // We don't start our periodic task unless we actually found the device
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
// Note: we do not call superclass setup in this case, because we dont want sleep observer registered
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,53 +120,53 @@ bool UBloxGPS::factoryReset()
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
/**
|
||||||
int UBloxGPS::prepareSleep(void *unused)
|
* 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 (isConnected)
|
if (ublox.getT(maxWait())) {
|
||||||
ublox.powerOff();
|
/* 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
|
||||||
return 0;
|
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(t);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBloxGPS::doTask()
|
/**
|
||||||
|
* 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()
|
||||||
{
|
{
|
||||||
if (isConnected) {
|
bool foundLocation = false;
|
||||||
// Consume all characters that have arrived
|
|
||||||
|
|
||||||
uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix
|
// If we don't have a fix (a quick check), don't try waiting for a solution)
|
||||||
|
uint8_t fixtype = ublox.getFixType(maxWait());
|
||||||
// if using i2c or serial look too see if any chars are ready
|
DEBUG_MSG("GPS fix type %d\n", fixtype);
|
||||||
ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
|
||||||
|
|
||||||
// If we don't have a fix (a quick check), don't try waiting for a solution)
|
|
||||||
// Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions
|
|
||||||
// turn off for now
|
|
||||||
uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait
|
|
||||||
fixtype = ublox.getFixType(maxWait);
|
|
||||||
DEBUG_MSG("GPS fix type %d\n", fixtype);
|
|
||||||
|
|
||||||
// DEBUG_MSG("sec %d\n", ublox.getSecond());
|
|
||||||
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
|
|
||||||
|
|
||||||
// any fix that has time
|
|
||||||
|
|
||||||
if (ublox.getT(maxWait)) {
|
|
||||||
/* 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(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// we only notify if position has changed due to a new fix
|
||||||
|
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait())) // rd fixes only
|
||||||
|
{
|
||||||
latitude = ublox.getLatitude(0);
|
latitude = ublox.getLatitude(0);
|
||||||
longitude = ublox.getLongitude(0);
|
longitude = ublox.getLongitude(0);
|
||||||
altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
|
altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
|
||||||
@ -176,33 +176,24 @@ void UBloxGPS::doTask()
|
|||||||
|
|
||||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
// 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!
|
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||||
hasValidLocation =
|
foundLocation =
|
||||||
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
|
(latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
|
||||||
|
|
||||||
// we only notify if position has changed due to a new fix
|
|
||||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
|
||||||
{
|
|
||||||
if (hasValidLocation) {
|
|
||||||
setWantLocation(false);
|
|
||||||
// ublox.powerOff();
|
|
||||||
}
|
|
||||||
} else // we didn't get a location update, go back to sleep and hope the characters show up
|
|
||||||
setWantLocation(true);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 10s until we have something
|
return foundLocation;
|
||||||
// over the serial
|
|
||||||
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBloxGPS::startLock()
|
bool UBloxGPS::whileIdle()
|
||||||
{
|
{
|
||||||
DEBUG_MSG("Looking for GPS lock\n");
|
// if using i2c or serial look too see if any chars are ready
|
||||||
wantNewLocation = true;
|
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
||||||
setPeriod(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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 (isConnected)
|
||||||
|
ublox.powerOff();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../concurrency/PeriodicTask.h"
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "SparkFun_Ublox_Arduino_Library.h"
|
#include "SparkFun_Ublox_Arduino_Library.h"
|
||||||
@ -10,12 +9,10 @@
|
|||||||
*
|
*
|
||||||
* When new data is available it will notify observers.
|
* When new data is available it will notify observers.
|
||||||
*/
|
*/
|
||||||
class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
class UBloxGPS : public GPS
|
||||||
{
|
{
|
||||||
SFE_UBLOX_GPS ublox;
|
SFE_UBLOX_GPS ublox;
|
||||||
|
|
||||||
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UBloxGPS();
|
UBloxGPS();
|
||||||
|
|
||||||
@ -24,13 +21,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
|||||||
*/
|
*/
|
||||||
virtual bool setup();
|
virtual bool setup();
|
||||||
|
|
||||||
virtual void doTask();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset our GPS back to factory settings
|
* Reset our GPS back to factory settings
|
||||||
*
|
*
|
||||||
@ -38,10 +28,33 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
|||||||
*/
|
*/
|
||||||
bool factoryReset();
|
bool factoryReset();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/// If possible force the GPS into sleep/low power mode
|
||||||
|
virtual void sleep();
|
||||||
|
|
||||||
private:
|
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);
|
|
||||||
|
|
||||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
/// Attempt to connect to our GPS, returns false if no gps is present
|
||||||
bool tryConnect();
|
bool tryConnect();
|
||||||
@ -49,4 +62,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
|||||||
/// Switch to our desired operating mode and save the settings to flash
|
/// Switch to our desired operating mode and save the settings to flash
|
||||||
/// returns true for success
|
/// returns true for success
|
||||||
bool setUBXMode();
|
bool setUBXMode();
|
||||||
|
|
||||||
|
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user