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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 =
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue