sforkowany z mirror/meshtastic-firmware
add air530 gps sleep support
rodzic
bc50b39a3b
commit
fec7a6bf17
|
@ -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
|
||||||
|
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<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
|
||||||
|
}
|
|
@ -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);
|
||||||
|
};
|
|
@ -85,3 +85,20 @@ uint32_t getValidTime()
|
||||||
{
|
{
|
||||||
return timeSetFromGPS ? getTime() : 0;
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,8 @@ class GPS
|
||||||
protected:
|
protected:
|
||||||
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
|
||||||
|
|
||||||
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;
|
||||||
|
@ -62,10 +64,24 @@ class GPS
|
||||||
/// 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; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Restart our lock attempt - try to get and broadcast a GPS reading ASAP
|
||||||
* called after the CPU wakes from light-sleep state */
|
* called after the CPU wakes from light-sleep state */
|
||||||
virtual void startLock() {}
|
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,50 +1,6 @@
|
||||||
#include "NMEAGPS.h"
|
#include "NMEAGPS.h"
|
||||||
#include "configuration.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
|
|
||||||
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<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)
|
static int32_t toDegInt(RawDegrees d)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +24,7 @@ bool NMEAGPS::setup()
|
||||||
|
|
||||||
void NMEAGPS::loop()
|
void NMEAGPS::loop()
|
||||||
{
|
{
|
||||||
|
// 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);
|
||||||
|
@ -78,11 +35,18 @@ void NMEAGPS::loop()
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we are overdue for an update, turn on the GPS and at least publish the current status
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if ((now - lastUpdateMsec) > 20 * 1000) { // Ugly hack for now - limit update checks to once every 20 secs (but still consume
|
bool mustPublishUpdate = false;
|
||||||
// serial chars at whatever rate)
|
if ((now - lastUpdateMsec) > 30 * 1000 && !wantNewLocation) {
|
||||||
lastUpdateMsec = now;
|
// 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 ti = reader.time;
|
||||||
auto d = reader.date;
|
auto d = reader.date;
|
||||||
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
if (ti.isUpdated() && ti.isValid() && d.isValid()) {
|
||||||
|
@ -105,6 +69,8 @@ void NMEAGPS::loop()
|
||||||
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
hasValidLocation = ((fixtype >= 1) && (fixtype <= 5));
|
||||||
|
|
||||||
if (reader.location.isUpdated()) {
|
if (reader.location.isUpdated()) {
|
||||||
|
lastUpdateMsec = now;
|
||||||
|
|
||||||
if (reader.altitude.isValid())
|
if (reader.altitude.isValid())
|
||||||
altitude = reader.altitude.meters();
|
altitude = reader.altitude.meters();
|
||||||
|
|
||||||
|
@ -112,6 +78,9 @@ void NMEAGPS::loop()
|
||||||
auto loc = reader.location.value();
|
auto loc = reader.location.value();
|
||||||
latitude = toDegInt(loc.lat);
|
latitude = toDegInt(loc.lat);
|
||||||
longitude = toDegInt(loc.lng);
|
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
|
// 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()) {
|
if (reader.hdop.isValid()) {
|
||||||
|
@ -128,11 +97,14 @@ void NMEAGPS::loop()
|
||||||
// expect gps pos lat=37.520825, lon=-122.309162, alt=158
|
// 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,
|
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);
|
altitude, dop * 1e-2, heading * 1e-5);
|
||||||
|
mustPublishUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify any status instances that are observing us
|
if (mustPublishUpdate) {
|
||||||
const meshtastic::GPSStatus status =
|
// Notify any status instances that are observing us
|
||||||
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
const meshtastic::GPSStatus status =
|
||||||
newStatus.notifyObservers(&status);
|
meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
|
||||||
|
newStatus.notifyObservers(&status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -183,11 +183,11 @@ void UBloxGPS::doTask()
|
||||||
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
|
||||||
{
|
{
|
||||||
if (hasValidLocation) {
|
if (hasValidLocation) {
|
||||||
wantNewLocation = false;
|
setWantLocation(false);
|
||||||
// ublox.powerOff();
|
// ublox.powerOff();
|
||||||
}
|
}
|
||||||
} else // we didn't get a location update, go back to sleep and hope the characters show up
|
} 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
|
// Notify any status instances that are observing us
|
||||||
const meshtastic::GPSStatus status =
|
const meshtastic::GPSStatus status =
|
||||||
|
|
|
@ -14,8 +14,6 @@ class UBloxGPS : public GPS, public concurrency::PeriodicTask
|
||||||
{
|
{
|
||||||
SFE_UBLOX_GPS ublox;
|
SFE_UBLOX_GPS ublox;
|
||||||
|
|
||||||
bool wantNewLocation = true;
|
|
||||||
|
|
||||||
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
|
CallbackObserver<UBloxGPS, void *> notifySleepObserver = CallbackObserver<UBloxGPS, void *>(this, &UBloxGPS::prepareSleep);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -62,7 +62,7 @@ void EInkDisplay::display(void)
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
uint32_t sinceLast = now - lastDrawMsec;
|
uint32_t sinceLast = now - lastDrawMsec;
|
||||||
|
|
||||||
if (framePtr && (sinceLast > 30 * 1000 || lastDrawMsec == 0)) {
|
if (framePtr && (sinceLast > 60 * 1000 || lastDrawMsec == 0)) {
|
||||||
lastDrawMsec = now;
|
lastDrawMsec = now;
|
||||||
|
|
||||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NMEAGPS.h"
|
#include "Air530GPS.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "UBloxGPS.h"
|
#include "UBloxGPS.h"
|
||||||
|
@ -259,10 +259,14 @@ void setup()
|
||||||
if (GPS::_serial_gps) {
|
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
|
// 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.
|
// assume NMEA at 9600 baud.
|
||||||
|
// dumb NMEA access only work for serial GPSes)
|
||||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
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();
|
gps = new NMEAGPS();
|
||||||
|
#endif
|
||||||
gps->setup();
|
gps->setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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 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_RX PIN_GPS_TX
|
||||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue