mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-30 06:31:01 +00:00
Merge branch 'eink' into power
This commit is contained in:
@@ -77,6 +77,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define BUTTON_PIN PIN_BUTTON1
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON2
|
||||
#define BUTTON_PIN_ALT PIN_BUTTON2
|
||||
#endif
|
||||
|
||||
// FIXME, use variant.h defs for all of this!!! (even on the ESP32 targets)
|
||||
#elif defined(CubeCell_BoardPlus)
|
||||
|
||||
|
||||
87
src/gps/Air530GPS.cpp
Normal file
87
src/gps/Air530GPS.cpp
Normal file
@@ -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 1
|
||||
#ifdef PIN_GPS_WAKE
|
||||
digitalWrite(PIN_GPS_WAKE, 1);
|
||||
pinMode(PIN_GPS_WAKE, OUTPUT);
|
||||
#endif
|
||||
#else
|
||||
// For power testing - keep GPS sleeping forever
|
||||
sleep();
|
||||
#endif
|
||||
}
|
||||
22
src/gps/Air530GPS.h
Normal file
22
src/gps/Air530GPS.h
Normal file
@@ -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:
|
||||
|
||||
@@ -56,12 +56,13 @@ uint32_t lastDrawMsec;
|
||||
// Write the buffer to the display memory
|
||||
void EInkDisplay::display(void)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
// No need to grab this lock because we are on our own SPI bus
|
||||
// concurrency::LockGuard g(spiLock);
|
||||
|
||||
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)
|
||||
@@ -76,10 +77,14 @@ void EInkDisplay::display(void)
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay(); // Send image to display and refresh
|
||||
ePaper.Reset(); // wake the screen from sleep
|
||||
|
||||
// Put screen to sleep to save power (if wanted)
|
||||
// ePaper.Sleep();
|
||||
DEBUG_MSG("Updating eink... ");
|
||||
updateDisplay(); // Send image to display and refresh
|
||||
DEBUG_MSG("done\n");
|
||||
|
||||
// Put screen to sleep to save power
|
||||
ePaper.Sleep();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +100,11 @@ bool EInkDisplay::connect()
|
||||
{
|
||||
DEBUG_MSG("Doing EInk init\n");
|
||||
|
||||
#ifdef PIN_EINK_PWR_ON
|
||||
digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef PIN_EINK_EN
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
|
||||
@@ -241,18 +241,17 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
|
||||
}
|
||||
}
|
||||
|
||||
//asdf
|
||||
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
|
||||
{
|
||||
String displayLine = "";
|
||||
if (!gps->getIsConnected()) {
|
||||
//displayLine = "No GPS Module";
|
||||
//display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
// displayLine = "No GPS Module";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else if (!gps->getHasLock()) {
|
||||
//displayLine = "No GPS Lock";
|
||||
//display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
// displayLine = "No GPS Lock";
|
||||
// display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
} else {
|
||||
|
||||
|
||||
displayLine = "Altitude: " + String(gps->getAltitude()) + "m";
|
||||
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
|
||||
}
|
||||
@@ -905,8 +904,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Lost");
|
||||
} else if (WiFi.status() == WL_CONNECT_FAILED) {
|
||||
display->drawString(x, y + FONT_HEIGHT * 1, "Connection Failed");
|
||||
//} else if (WiFi.status() == WL_DISCONNECTED) {
|
||||
// display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected");
|
||||
//} else if (WiFi.status() == WL_DISCONNECTED) {
|
||||
// display->drawString(x, y + FONT_HEIGHT * 1, "Disconnected");
|
||||
} else if (WiFi.status() == WL_IDLE_STATUS) {
|
||||
display->drawString(x, y + FONT_HEIGHT * 1, "Idle ... Reconnecting");
|
||||
} else {
|
||||
@@ -1009,10 +1008,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
display->drawString(x, y, String("USB"));
|
||||
}
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)),
|
||||
y, "Mode " + String(channelSettings.modem_config));
|
||||
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)), y,
|
||||
"Mode " + String(channelSettings.modem_config));
|
||||
|
||||
// Line 2
|
||||
uint32_t currentMillis = millis();
|
||||
@@ -1029,6 +1026,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
String(days) + "d " + (hours < 10 ? "0" : "") + String(hours) + ":" + (minutes < 10 ? "0" : "") +
|
||||
String(minutes) + ":" + (seconds < 10 ? "0" : "") + String(seconds));
|
||||
|
||||
// Line 3
|
||||
drawGPSAltitude(display, x, y + FONT_HEIGHT * 2, gpsStatus);
|
||||
|
||||
// Line 4
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,11 @@ void RadioInterface::applyModemConfig()
|
||||
|
||||
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelSettings.name, channelSettings.modem_config, channel_num,
|
||||
power);
|
||||
DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq);
|
||||
DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing);
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", freq);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +25,8 @@ bool isWifiAvailable()
|
||||
const char *wifiName = radioConfig.preferences.wifi_ssid;
|
||||
const char *wifiPsw = radioConfig.preferences.wifi_password;
|
||||
|
||||
//strcpy(radioConfig.preferences.wifi_ssid, "");
|
||||
//strcpy(radioConfig.preferences.wifi_password, "");
|
||||
// strcpy(radioConfig.preferences.wifi_ssid, "");
|
||||
// strcpy(radioConfig.preferences.wifi_password, "");
|
||||
|
||||
if (*wifiName && *wifiPsw) {
|
||||
|
||||
|
||||
@@ -93,11 +93,6 @@ void nrf52Setup()
|
||||
// This is the recommended setting for Monitor Mode Debugging
|
||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
||||
|
||||
#ifdef PIN_PWR_ON
|
||||
digitalWrite(PIN_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
|
||||
pinMode(PIN_PWR_ON, OUTPUT);
|
||||
#endif
|
||||
|
||||
// Not yet on board
|
||||
// pmu.init();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user