add air530 gps sleep support

pull/449/head
geeksville 2020-09-28 17:04:19 -07:00
rodzic bc50b39a3b
commit fec7a6bf17
10 zmienionych plików z 176 dodań i 58 usunięć

Wyświetl plik

@ -0,0 +1,87 @@
#include "Air530GPS.h"
#include <assert.h>
/*
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
6Command: 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 12 ,
ON time in msecs
Arg3:(), Arg1 12 ,
Sleep time in msecs
Example:
$PGKC105,8*3F<CR><LF>
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() {
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, 0);
pinMode(PIN_GPS_WAKE, OUTPUT);
sendCommand("$PGKC105,4");
#endif
}
/// wake the GPS into normal operation mode
void Air530GPS::wake()
{
#if 0
#ifdef PIN_GPS_WAKE
digitalWrite(PIN_GPS_WAKE, 1);
pinMode(PIN_GPS_WAKE, OUTPUT);
#endif
#else
// For power testing
sleep();
#endif
}

Wyświetl plik

@ -0,0 +1,22 @@
#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();
/// wake the GPS into normal operation mode
virtual void wake();
private:
/// Send a NMEA cmd with checksum
void sendCommand(const char *str);
};

Wyświetl plik

@ -85,3 +85,20 @@ uint32_t getValidTime()
{
return timeSetFromGPS ? getTime() : 0;
}
/**
* 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)
{
if (wantNewLocation != on) {
wantNewLocation = on;
DEBUG_MSG("WANT GPS=%d\n", on);
if (on)
wake();
else
sleep();
}
}

Wyświetl plik

@ -30,6 +30,8 @@ class GPS
protected:
bool hasValidLocation = false; // default to false, until we complete our first read
bool wantNewLocation = false; // true if we want a location right now
public:
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
@ -62,10 +64,24 @@ class GPS
/// 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
*/
void setWantLocation(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;

Wyświetl plik

@ -1,50 +1,6 @@
#include "NMEAGPS.h"
#include "configuration.h"
/*
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
6Command: 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 12 ,
ON time in msecs
Arg3:(), Arg1 12 ,
Sleep time in msecs
Example:
$PGKC105,8*3F<CR><LF>
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.
*/
static int32_t toDegInt(RawDegrees d)
{
@ -68,6 +24,7 @@ bool NMEAGPS::setup()
void NMEAGPS::loop()
{
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
// DEBUG_MSG("%c", c);
@ -78,11 +35,18 @@ void NMEAGPS::loop()
isConnected = true;
}
// If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis();
if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume
// serial chars at whatever rate)
lastUpdateMsec = now;
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()) {
@ -105,6 +69,8 @@ void NMEAGPS::loop()
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
if (reader.location.isUpdated()) {
lastUpdateMsec = now;
if (reader.altitude.isValid())
altitude = reader.altitude.meters();
@ -112,6 +78,9 @@ void NMEAGPS::loop()
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()) {
@ -128,11 +97,14 @@ void NMEAGPS::loop()
// 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;
}
// 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);
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);
}
}
}

Wyświetl plik

@ -183,11 +183,11 @@ void UBloxGPS::doTask()
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
{
if (hasValidLocation) {
wantNewLocation = false;
setWantLocation(false);
// ublox.powerOff();
}
} else // we didn't get a location update, go back to sleep and hope the characters show up
wantNewLocation = true;
setWantLocation(true);
// Notify any status instances that are observing us
const meshtastic::GPSStatus status =

Wyświetl plik

@ -14,8 +14,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
{
SFE_UBLOX_GPS ublox;
bool wantNewLocation = true;
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
public:

Wyświetl plik

@ -62,7 +62,7 @@ void EInkDisplay::display(void)
uint32_t now = millis();
uint32_t sinceLast = now - lastDrawMsec;
if (framePtr && (sinceLast > 30 * 1000 || lastDrawMsec == 0)) {
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) {
lastDrawMsec = now;
// FIXME - only draw bits have changed (use backbuf similar to the other displays)

Wyświetl plik

@ -23,7 +23,7 @@
#include "MeshRadio.h"
#include "MeshService.h"
#include "NMEAGPS.h"
#include "Air530GPS.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "UBloxGPS.h"
@ -259,10 +259,14 @@ void setup()
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.
// dumb NMEA access only work for serial GPSes)
DEBUG_MSG("Hoping that NMEA might work\n");
// dumb NMEA access only work for serial GPSes)
#ifdef HAS_AIR530_GPS
gps = new Air530GPS();
#else
gps = new NMEAGPS();
#endif
gps->setup();
}
}

Wyświetl plik

@ -208,6 +208,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 HAS_AIR530_GPS
#define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX PIN_GPS_RX