diff --git a/.vscode/settings.json b/.vscode/settings.json
index cd2a5ca5c2..45052fa77d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -57,6 +57,7 @@
"HFSR",
"Meshtastic",
"NEMAGPS",
+ "NMEAGPS",
"RDEF",
"Ublox",
"bkpt",
diff --git a/bin/version.sh b/bin/version.sh
index a2c90861a9..fb34ea22bb 100644
--- a/bin/version.sh
+++ b/bin/version.sh
@@ -1,3 +1,3 @@
-export VERSION=1.1.0
\ No newline at end of file
+export VERSION=1.1.1
\ No newline at end of file
diff --git a/docs/hardware/WIFI_LoRa_32_V2(868-915).PDF b/docs/hardware/WIFI_LoRa_32_V2(868-915).PDF
new file mode 100644
index 0000000000..11d499e7d8
Binary files /dev/null and b/docs/hardware/WIFI_LoRa_32_V2(868-915).PDF differ
diff --git a/docs/hardware/u-blox6_ReceiverDescrProtSpec_(GPS.G6-SW-10018)_Public.pdf b/docs/hardware/u-blox6_ReceiverDescrProtSpec_(GPS.G6-SW-10018)_Public.pdf
new file mode 100644
index 0000000000..f7231158cc
Binary files /dev/null and b/docs/hardware/u-blox6_ReceiverDescrProtSpec_(GPS.G6-SW-10018)_Public.pdf differ
diff --git a/docs/hardware/u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221).pdf b/docs/hardware/u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221).pdf
new file mode 100644
index 0000000000..032455f2c7
Binary files /dev/null and b/docs/hardware/u-blox8-M8_ReceiverDescrProtSpec_(UBX-13003221).pdf differ
diff --git a/docs/software/TODO.md b/docs/software/TODO.md
index 4a63cf0407..514fda9cf8 100644
--- a/docs/software/TODO.md
+++ b/docs/software/TODO.md
@@ -2,6 +2,16 @@
You probably don't care about this section - skip to the next one.
+Threading tasks:
+
+- Use https://github.com/ivanseidel/ArduinoThread? rather than full coroutines
+- clean up main loop()
+- check that we are mostly asleep, show which thread is causing us to wake
+-
+- use tickless idle on nrf52, and sleep X msec or until an interrupt occurs or the cooperative scheduling changes. https://devzone.nordicsemi.com/f/nordic-q-a/12363/nrf52-freertos-power-consumption-tickless-idle
+- BAD IDEA: use vTaskDelay and https://www.freertos.org/xTaskAbortDelay.html if scheduling changes. (define INCLUDE_xTaskAbortDelay on ESP32 and NRF52 - seems impossible to find?)
+- GOOD IDEA: use xSemaphoreTake to take a semaphore using a timeout. Expect semaphore to not be set, but set it to indicate scheduling has changed.
+
Nimble tasks:
- readerror.txt stress test bug
diff --git a/docs/software/gps-todo.txt b/docs/software/gps-todo.txt
new file mode 100644
index 0000000000..79503ebcda
--- /dev/null
+++ b/docs/software/gps-todo.txt
@@ -0,0 +1,45 @@
+gps todo - bug 376
+
+for taiwan region:
+bin/run.sh --set region 8
+
+time only mode
+./bin/run.sh --set gps_operation 3
+
+increase acquisition time until ublox power management can be improved see 9.3.1
+
+ublox parsing failure
+
+record power measurements and update spreadsheet
+
+fix has_gps based on new logic
+
+make sure we are turning off lora radio in deep sleep
+
+don't send locations if the user has forbidden that (lie to phone so phone won't either)
+
+have loop methods return allowable sleep time (from their perspective)
+increase main cpu sleep time
+
+add set router mode in python tool - it will also set GPS to stationary
+make sure location still gets set once per boot and stays marked as valid on the gui
+send position updates super rarely
+turn off checking for usb power and forcing always on
+(which will shrink DARK and NB period to zero and
+ make light_sleep very long)
+
+warn people about crummy gps antennas - add to faq
+
+
+gps states
+
+Active - for gps_attempt_time seconds
+Sleeping - for (gps_update_rate or sleep forever) seconds
+ForcedSleep - PowerFSM says we don't want to use GPS right now
+(no need for sleep forever state)
+
+gps triggers
+GPS_TRIG_FORCE_SLEEP - from powerfsm
+GPS_TRIG_FORCE_WAKE - from powerfsm
+GPS_SETTINGS - if GPS settings changed, reset params and possibly become active
+
diff --git a/platformio.ini b/platformio.ini
index 8dfc9dc5f7..b48dc39381 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -34,8 +34,10 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n
; leave this commented out to avoid breaking Windows
;upload_port = /dev/ttyUSB0
;monitor_port = /dev/ttyUSB0
-upload_port = /dev/cu.SLAB_USBtoUART
-monitor_port = /dev/cu.SLAB_USBtoUART
+
+; geeksville: I think setting this should not be required - it breaks linux
+;upload_port = /dev/cu.SLAB_USBtoUART
+;monitor_port = /dev/cu.SLAB_USBtoUART
; the default is esptool
; upload_protocol = esp-prog
@@ -60,8 +62,8 @@ lib_deps =
1260 ; OneButton library for non-blocking button debounce
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
https://github.com/meshtastic/arduino-fsm.git
- https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
- https://github.com/meshtastic/RadioLib.git#ac7feac00f5e0bd95a3ac5d5852b4cc7344cf95c
+ https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#cb8353dfddd1b0e205098f5e70d5f2a5f74b4838
+ https://github.com/meshtastic/RadioLib.git#1083c2e76f9906c5f80dfec726facebf8413eef0
https://github.com/meshtastic/TinyGPSPlus.git
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
Wire ; explicitly needed here because the AXP202 library forgets to add it
diff --git a/proto b/proto
index 5cdd7bff56..a0b8d88896 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 5cdd7bff56b0ea54351e5ea0e358e864b061078f
+Subproject commit a0b8d888961720d70ab7467c94d8fa0687e58020
diff --git a/src/Power.cpp b/src/Power.cpp
index f6ae1c691b..90e9881670 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -172,7 +172,7 @@ bool Power::axp192Init()
DEBUG_MSG("----------------------------------------\n");
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA radio
- axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power
+ // axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS main power - now turned on in setGpsPower
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
@@ -204,8 +204,11 @@ bool Power::axp192Init()
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
- axp.enableIRQ(AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ | AXP202_CHARGING_FINISHED_IRQ | AXP202_CHARGING_IRQ |
- AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
+ // we do not look for AXP202_CHARGING_FINISHED_IRQ & AXP202_CHARGING_IRQ because it occurs repeatedly while there is
+ // no battery also it could cause inadvertent waking from light sleep just because the battery filled
+ // we don't look for AXP202_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
+ // we don't look at AXP202_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
+ axp.enableIRQ(AXP202_BATT_CONNECT_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_PEK_SHORTPRESS_IRQ,
1);
axp.clearIRQ();
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index 14f7b996b0..9a949638a7 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -12,7 +12,7 @@
static void sdsEnter()
{
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
- doDeepSleep(radioConfig.preferences.sds_secs * 1000LL);
+ doDeepSleep(getPref_sds_secs() * 1000LL);
}
#include "error.h"
@@ -21,7 +21,7 @@ static uint32_t secsSlept;
static void lsEnter()
{
- DEBUG_MSG("lsEnter begin, ls_secs=%u\n", radioConfig.preferences.ls_secs);
+ DEBUG_MSG("lsEnter begin, ls_secs=%u\n", getPref_ls_secs());
screen.setOn(false);
secsSlept = 0; // How long have we been sleeping this time
@@ -30,13 +30,13 @@ static void lsEnter()
static void lsIdle()
{
- // DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
+ // DEBUG_MSG("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
#ifndef NO_ESP32
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
// Do we have more sleeping to do?
- if (secsSlept < radioConfig.preferences.ls_secs) {
+ if (secsSlept < getPref_ls_secs()) {
// Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30;
@@ -45,7 +45,8 @@ static void lsIdle()
setLed(false); // Never leave led on while in light sleep
wakeCause = doLightSleep(sleepTime * 1000LL);
- if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
+ switch (wakeCause) {
+ case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
setLed(true); // briefly turn on led
@@ -53,12 +54,15 @@ static void lsIdle()
secsSlept += sleepTime;
// DEBUG_MSG("sleeping, flash led!\n");
- }
- if (wakeCause == ESP_SLEEP_WAKEUP_UART) {
+ break;
+
+ case ESP_SLEEP_WAKEUP_UART:
// Not currently used (because uart triggers in hw have problems)
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
- } else {
- // We woke for some other reason (button press, uart, device interrupt)
+ break;
+
+ default:
+ // We woke for some other reason (button press, device interrupt)
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
DEBUG_MSG("wakeCause %d\n", wakeCause);
@@ -72,8 +76,10 @@ static void lsIdle()
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
+ // we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
}
+ break;
}
} else {
// Someone says we can't sleep now, so just save some power by sleeping the CPU for 100ms or so
@@ -91,7 +97,7 @@ static void lsIdle()
static void lsExit()
{
// setGPSPower(true); // restore GPS power
- gps->startLock();
+ gps->forceWake(true);
}
static void nbEnter()
@@ -136,8 +142,6 @@ static void onEnter()
}
}
-static void wakeForPing() {}
-
static void screenPress()
{
screen.onPress();
@@ -157,15 +161,20 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
- // If we already have AC power go to POWER state after init, otherwise go to ON
- bool hasPower = powerStatus && powerStatus->getHasUSB();
+ // If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
+ // We assume routers might be powered all the time, but from a low current (solar) source
+ bool isLowPower = radioConfig.preferences.is_low_power;
+ bool hasPower = !isLowPower && powerStatus && powerStatus->getHasUSB();
+ bool isRouter = radioConfig.preferences.is_router;
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
- powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
+ // wake timer expired or a packet arrived
+ // if we are a router node, we go to NB (no need for bluetooth) otherwise we go to DARK (so we can send message to phone)
+ powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_WAKE_TIMER, NULL, "Wake timer");
- // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB and then
- // it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
+ // Note we don't really use this transition, because when we wake from light sleep we _always_ transition to NB or dark and
+ // then it handles things powerFSM.add_transition(&stateLS, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_RECEIVED_PACKET, NULL, "Received packet, resetting win wake");
@@ -189,24 +198,31 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
powerFSM.add_transition(&stateON, &stateON, EVENT_BLUETOOTH_PAIR, NULL, "Bluetooth pairing");
- powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
- powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
- powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
-
- powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
- powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
- powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
- powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
+ // if we are a router we don't turn the screen on for these things
+ if (!isRouter) {
+ // show the latest node when we get a new node db update
+ powerFSM.add_transition(&stateNB, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
+ powerFSM.add_transition(&stateDARK, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
+ powerFSM.add_transition(&stateON, &stateON, EVENT_NODEDB_UPDATED, NULL, "NodeDB update");
+
+ // Show the received text message
+ powerFSM.add_transition(&stateLS, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
+ powerFSM.add_transition(&stateNB, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
+ powerFSM.add_transition(&stateDARK, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text");
+ powerFSM.add_transition(&stateON, &stateON, EVENT_RECEIVED_TEXT_MSG, NULL, "Received text"); // restarts the sleep timer
+ }
powerFSM.add_transition(&stateLS, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateNB, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateDARK, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
powerFSM.add_transition(&stateON, &stateSERIAL, EVENT_SERIAL_CONNECTED, NULL, "serial API");
- powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
- powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
- powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
- powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
+ if (!isLowPower) {
+ powerFSM.add_transition(&stateLS, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
+ powerFSM.add_transition(&stateNB, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
+ powerFSM.add_transition(&stateDARK, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
+ powerFSM.add_transition(&stateON, &statePOWER, EVENT_POWER_CONNECTED, NULL, "power connect");
+ }
powerFSM.add_transition(&statePOWER, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
powerFSM.add_transition(&stateSERIAL, &stateON, EVENT_POWER_DISCONNECTED, NULL, "power disconnected");
@@ -217,22 +233,22 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateNB, &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Packet for phone");
- powerFSM.add_timed_transition(&stateON, &stateDARK, radioConfig.preferences.screen_on_secs * 1000, NULL, "Screen-on timeout");
+ powerFSM.add_timed_transition(&stateON, &stateDARK, getPref_screen_on_secs() * 1000, NULL, "Screen-on timeout");
- powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout");
+ powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
#ifndef NRF52_SERIES
// We never enter light-sleep state on NRF52 (because the CPU uses so little power normally)
- powerFSM.add_timed_transition(&stateNB, &stateLS, radioConfig.preferences.min_wake_secs * 1000, NULL, "Min wake timeout");
+ powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
- powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL,
- "Bluetooth timeout");
+ powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
#endif
- powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL,
- "mesh timeout");
+ auto meshSds = getPref_mesh_sds_timeout_secs();
+ if (meshSds != UINT32_MAX)
+ powerFSM.add_timed_transition(&stateLS, &stateSDS, meshSds * 1000, NULL, "mesh timeout");
// removing for now, because some users don't even have phones
- // powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.phone_sds_timeout_sec * 1000, NULL, "phone
+ // powerFSM.add_timed_transition(&stateLS, &stateSDS, getPref_phone_sds_timeout_sec() * 1000, NULL, "phone
// timeout");
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
diff --git a/src/configuration.h b/src/configuration.h
index ad783d0d5c..504a7aad8a 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -148,11 +148,6 @@ along with this program. If not, see .
// devices. Comment this out to not rotate screen 180 degrees.
#define FLIP_SCREEN_VERTICALLY
-// DEBUG LED
-#ifndef LED_INVERTED
-#define LED_INVERTED 0 // define as 1 if LED is active low (on)
-#endif
-
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------
@@ -171,6 +166,9 @@ along with this program. If not, see .
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
#define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed
+#define LED_INVERTED 1
+#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
+
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262
#define USE_RF95
@@ -192,8 +190,9 @@ along with this program. If not, see .
// code)
#endif
-// Leave undefined to disable our PMU IRQ handler
-#define PMU_IRQ 35
+// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
+// and waking from light sleep
+// #define PMU_IRQ 35
#define AXP192_SLAVE_ADDRESS 0x34
#elif defined(TBEAM_V07)
@@ -369,6 +368,11 @@ along with this program. If not, see .
#endif
+// DEBUG LED
+#ifndef LED_INVERTED
+#define LED_INVERTED 0 // define as 1 if LED is active low (on)
+#endif
+
#ifdef USE_RF95
#define RF95_RESET LORA_RESET
#define RF95_IRQ LORA_DIO0 // on SX1262 version this is a no connect DIO0
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index f8b29de3dc..ba43041d77 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -1,6 +1,8 @@
#include "GPS.h"
+#include "NodeDB.h"
#include "configuration.h"
+#include "sleep.h"
#include
#include
@@ -44,7 +46,7 @@ void readFromRTC()
}
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
-void perhapsSetRTC(const struct timeval *tv)
+bool perhapsSetRTC(const struct timeval *tv)
{
if (!timeSetFromGPS) {
timeSetFromGPS = true;
@@ -55,10 +57,13 @@ void perhapsSetRTC(const struct timeval *tv)
DEBUG_MSG("ERROR TIME SETTING NOT IMPLEMENTED!\n");
#endif
readFromRTC();
+ return true;
+ } else {
+ return false;
}
}
-void perhapsSetRTC(struct tm &t)
+bool perhapsSetRTC(struct tm &t)
{
/* 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
@@ -70,10 +75,12 @@ void perhapsSetRTC(struct tm &t)
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
// DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
- if (t.tm_year < 0 || t.tm_year >= 300)
- DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
- else
- perhapsSetRTC(&tv);
+ if (t.tm_year < 0 || t.tm_year >= 300) {
+ // DEBUG_MSG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
+ return false;
+ } else {
+ return perhapsSetRTC(&tv);
+ }
}
uint32_t getTime()
@@ -86,19 +93,168 @@ uint32_t getValidTime()
return timeSetFromGPS ? getTime() : 0;
}
+bool GPS::setup()
+{
+ setAwake(true); // Wake GPS power before doing any init
+ bool ok = setupGPS();
+
+ if (ok)
+ notifySleepObserver.observe(¬ifySleep);
+
+ return ok;
+}
+
/**
* 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)
+void GPS::setAwake(bool on)
{
- if (wantNewLocation != on) {
- wantNewLocation = on;
+ if (!wakeAllowed && on) {
+ DEBUG_MSG("Inhibiting because !wakeAllowed\n");
+ on = false;
+ }
+
+ if (isAwake != on) {
DEBUG_MSG("WANT GPS=%d\n", on);
- if (on)
+ if (on) {
+ lastWakeStartMsec = millis();
wake();
- else
+ } else {
+ lastSleepStartMsec = millis();
sleep();
}
-}
\ No newline at end of file
+
+ isAwake = on;
+ }
+}
+
+GpsOperation GPS::getGpsOp() const
+{
+ auto op = radioConfig.preferences.gps_operation;
+
+ if (op == GpsOperation_GpsOpUnset)
+ op = (radioConfig.preferences.location_share == LocationSharing_LocDisabled) ? GpsOperation_GpsOpTimeOnly
+ : GpsOperation_GpsOpMobile;
+
+ return op;
+}
+
+/** Get how long we should stay looking for each aquisition in msecs
+ */
+uint32_t GPS::getWakeTime() const
+{
+ uint32_t t = radioConfig.preferences.gps_attempt_time;
+
+ if (t == UINT32_MAX)
+ return t; // already maxint
+
+ if (t == 0)
+ t = 5 * 60; // Allow up to 5 mins for each attempt (probably will be much less if we can find sats)
+
+ t *= 1000; // msecs
+
+ return t;
+}
+
+/** Get how long we should sleep between aqusition attempts in msecs
+ */
+uint32_t GPS::getSleepTime() const
+{
+ uint32_t t = radioConfig.preferences.gps_update_interval;
+
+ auto op = getGpsOp();
+ if ((timeSetFromGPS && op == GpsOperation_GpsOpTimeOnly) || (op == GpsOperation_GpsOpDisabled))
+ t = UINT32_MAX; // Sleep forever now
+
+ if (t == UINT32_MAX)
+ return t; // already maxint
+
+ if (t == 0)
+ t = 2 * 60; // 2 mins
+
+ t *= 1000;
+
+ return t;
+}
+
+void GPS::publishUpdate()
+{
+ 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::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();
+
+ auto sleepTime = getSleepTime();
+ if (!isAwake && sleepTime != UINT32_MAX && (now - lastSleepStartMsec) > sleepTime) {
+ // We now want to be awake - so wake up the GPS
+ setAwake(true);
+ }
+
+ // While we are awake
+ if (isAwake) {
+ // DEBUG_MSG("looking for location\n");
+ if ((now - lastWhileActiveMsec) > 1000) {
+ lastWhileActiveMsec = now;
+ whileActive();
+ }
+
+ // If we've already set time from the GPS, no need to ask the GPS
+ bool gotTime = timeSetFromGPS || lookForTime();
+ bool gotLoc = lookForLocation();
+
+ // We've been awake too long - force sleep
+ auto wakeTime = getWakeTime();
+ bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
+
+ // Once we get a location we no longer desperately want an update
+ // or if we got a time and we are in GpsOpTimeOnly mode
+ // DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
+ if (gotLoc || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) {
+ if (gotLoc)
+ hasValidLocation = true;
+
+ if (tooLong) {
+ // we didn't get a location during this ack window, therefore declare loss of lock
+ hasValidLocation = false;
+ }
+
+ setAwake(false);
+ publishUpdate(); // publish our update for this just finished acquisition window
+ }
+ }
+}
+
+void GPS::forceWake(bool on)
+{
+ if (on) {
+ DEBUG_MSG("Allowing GPS lock\n");
+ // lastSleepStartMsec = 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;
+}
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 3b81b54f7e..1f8429a44e 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -6,8 +6,8 @@
#include "sys/time.h"
/// If we haven't yet set our RTC this boot, set it from a GPS derived time
-void perhapsSetRTC(const struct timeval *tv);
-void perhapsSetRTC(struct tm &t);
+bool perhapsSetRTC(const struct timeval *tv);
+bool perhapsSetRTC(struct tm &t);
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
@@ -27,11 +27,18 @@ void readFromRTC();
*/
class GPS
{
- protected:
+ private:
+ uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
+
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 notifySleepObserver = CallbackObserver(this, &GPS::prepareSleep);
+ protected:
public:
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
@@ -48,7 +55,7 @@ class GPS
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 */
Observable newStatus;
@@ -56,32 +63,82 @@ class GPS
/**
* 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.
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:
+ /// Do gps chipset specific init, return true for success
+ virtual bool setupGPS() = 0;
+
+ /// 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;
+
+ /** Idle processing while GPS is looking for lock, called once per secondish */
+ virtual void whileActive() {}
+
+ /**
+ * 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
- *
+ *
* 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() {}
+ /** Get how long we should stay looking for each aquisition
+ */
+ uint32_t getWakeTime() const;
-protected:
- /// If possible force the GPS into sleep/low power mode
- virtual void sleep() {}
+ /** Get how long we should sleep between aqusition attempts
+ */
+ uint32_t getSleepTime() const;
- /// wake the GPS into normal operation mode
- virtual void wake() {}
+ GpsOperation getGpsOp() const;
+
+ /**
+ * Tell users we have new GPS readings
+ */
+ void publishUpdate();
};
extern GPS *gps;
diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp
index 2d8af6d72a..1b6bb1b353 100644
--- a/src/gps/NMEAGPS.cpp
+++ b/src/gps/NMEAGPS.cpp
@@ -1,7 +1,6 @@
#include "NMEAGPS.h"
#include "configuration.h"
-
static int32_t toDegInt(RawDegrees d)
{
int32_t degMult = 10000000; // 1e7
@@ -11,7 +10,7 @@ static int32_t toDegInt(RawDegrees d)
return r;
}
-bool NMEAGPS::setup()
+bool NMEAGPS::setupGPS()
{
#ifdef PIN_GPS_PPS
// pulse per second
@@ -22,89 +21,89 @@ bool NMEAGPS::setup()
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()
{
- // 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);
- bool isValid = reader.encode(c);
+ 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);
- // if we have received valid NMEA claim we are connected
- if (isValid)
- isConnected = true;
- }
+ return true;
+ } else
+ return false;
+}
- // 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 && !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
- }
+/**
+ * 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;
- // 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));
- 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.isUpdated()) {
- lastUpdateMsec = now;
+ if (reader.location.isValid()) {
+ auto loc = reader.location.value();
+ latitude = toDegInt(loc.lat);
+ longitude = toDegInt(loc.lng);
+ foundLocation = true;
+ }
- if (reader.altitude.isValid())
- altitude = reader.altitude.meters();
+ // 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();
+ }
- if (reader.location.isValid()) {
- auto loc = reader.location.value();
- latitude = toDegInt(loc.lat);
- longitude = toDegInt(loc.lng);
+ // 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);
+ }
- // 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();
- }
+ return foundLocation;
+}
- // 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;
- }
+bool NMEAGPS::whileIdle()
+{
+ bool isValid = false;
- 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);
- }
+ // 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);
+ isValid |= reader.encode(c);
}
-}
\ No newline at end of file
+
+ return isValid;
+}
diff --git a/src/gps/NMEAGPS.h b/src/gps/NMEAGPS.h
index b46aa0c65e..f411e4d166 100644
--- a/src/gps/NMEAGPS.h
+++ b/src/gps/NMEAGPS.h
@@ -14,10 +14,29 @@ class NMEAGPS : public GPS
{
TinyGPSPlus reader;
- uint32_t lastUpdateMsec = 0;
-
public:
- virtual bool setup();
+ virtual bool setupGPS();
+
+ 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();
- virtual void 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
+ */
+ virtual bool lookForLocation();
};
diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp
index 0d133891e2..1007162b64 100644
--- a/src/gps/UBloxGPS.cpp
+++ b/src/gps/UBloxGPS.cpp
@@ -3,10 +3,7 @@
#include "sleep.h"
#include
-UBloxGPS::UBloxGPS() : concurrency::PeriodicTask()
-{
- notifySleepObserver.observe(¬ifySleep);
-}
+UBloxGPS::UBloxGPS() {}
bool UBloxGPS::tryConnect()
{
@@ -26,7 +23,7 @@ bool UBloxGPS::tryConnect()
return isConnected;
}
-bool UBloxGPS::setup()
+bool UBloxGPS::setupGPS()
{
if (_serial_gps) {
#ifdef GPS_RX_PIN
@@ -34,15 +31,12 @@ bool UBloxGPS::setup()
#else
_serial_gps->begin(GPS_BAUDRATE);
#endif
- // _serial_gps.setRxBufferSize(1024); // the default is 256
- }
-
-#ifdef GPS_POWER_EN
- pinMode(GPS_POWER_EN, OUTPUT);
- digitalWrite(GPS_POWER_EN, 1);
- delay(200); // Give time for the GPS to startup after we gave power
+#ifndef NO_ESP32
+ _serial_gps->setRxBufferSize(1024); // the default is 256
#endif
+ }
+ // uncomment to see debug info
// ublox.enableDebugging(Serial);
// try a second time, the ublox lib serial parsing is buggy?
@@ -56,8 +50,6 @@ bool UBloxGPS::setup()
if (!setUBXMode())
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;
} else {
return false;
@@ -120,38 +112,34 @@ bool UBloxGPS::factoryReset()
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)
+/** Idle processing while GPS is looking for lock */
+void UBloxGPS::whileActive()
{
- if (isConnected)
- ublox.powerOff();
-
- return 0;
+ ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
+
+ // Ask for a new position fix - hopefully it will have results ready by next time
+ // the order here is important, because we only check for has latitude when reading
+ ublox.getSIV(maxWait());
+ ublox.getPDOP(maxWait());
+ ublox.getP(maxWait());
+
+ // Update fixtype
+ if (ublox.moduleQueried.fixType) {
+ fixType = ublox.getFixType(0);
+ DEBUG_MSG("GPS fix type %d\n", fixType);
+ }
}
-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::lookForTime()
{
- if (isConnected) {
- // 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 using i2c or serial look too see if any chars are ready
- 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)) {
+ if (fixType >= 2) {
+ if (ublox.moduleQueried.gpsSecond) {
/* 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).
@@ -165,44 +153,69 @@ void UBloxGPS::doTask()
t.tm_year = ublox.getYear(0) - 1900;
t.tm_isdst = false;
perhapsSetRTC(t);
+ return true;
}
+ }
- latitude = ublox.getLatitude(0);
- longitude = ublox.getLongitude(0);
- altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
- dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
- heading = ublox.getHeading(0);
- numSatellites = ublox.getSIV(0);
+ return false;
+}
- // 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!
- hasValidLocation =
- (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 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
+ */
+bool UBloxGPS::lookForLocation()
+{
+ bool foundLocation = false;
- // we only notify if position has changed due to a new fix
- if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only
+ // we only notify if position has changed due to a new fix
+ if ((fixType >= 3 && fixType <= 4)) {
+ if (ublox.moduleQueried.latitude) // 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);
+ latitude = ublox.getLatitude(0);
+ longitude = ublox.getLongitude(0);
+ altitude = ublox.getAltitudeMSL(0) / 1000; // in mm convert to meters
+ dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
+
+ // Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
+ // don't read it here - it will generate an ignored getPVT command on the 6ms
+ // heading = ublox.getHeading(0);
+ numSatellites = ublox.getSIV(0);
+
+ // 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!
+ foundLocation =
+ (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0);
+ }
}
- // Once we have sent a location once we only poll the GPS rarely, otherwise check back every 10s until we have something
- // over the serial
- setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
+ return foundLocation;
+}
+
+bool UBloxGPS::whileIdle()
+{
+ // if using i2c or serial look too see if any chars are ready
+ return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
}
-void UBloxGPS::startLock()
+/// 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()
{
- DEBUG_MSG("Looking for GPS lock\n");
- wantNewLocation = true;
- setPeriod(1);
+ // Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
+ ublox.powerOff();
+ // setGPSPower(false);
}
+
+void UBloxGPS::wake()
+{
+ fixType = 0; // assume we hace no fix yet
+
+ setGPSPower(true);
+
+ // Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
+ // Give time for the GPS to boot
+ // delay(200);
+}
\ No newline at end of file
diff --git a/src/gps/UBloxGPS.h b/src/gps/UBloxGPS.h
index 03f2d2a1c0..9fda4bd0e3 100644
--- a/src/gps/UBloxGPS.h
+++ b/src/gps/UBloxGPS.h
@@ -1,6 +1,5 @@
#pragma once
-#include "../concurrency/PeriodicTask.h"
#include "GPS.h"
#include "Observer.h"
#include "SparkFun_Ublox_Arduino_Library.h"
@@ -10,43 +9,63 @@
*
* When new data is available it will notify observers.
*/
-class UBloxGPS : public GPS, public concurrency::PeriodicTask
+class UBloxGPS : public GPS
{
SFE_UBLOX_GPS ublox;
-
- CallbackObserver notifySleepObserver = CallbackObserver(this, &UBloxGPS::prepareSleep);
+ uint8_t fixType = 0;
public:
UBloxGPS();
+ /**
+ * Reset our GPS back to factory settings
+ *
+ * @return true for success
+ */
+ bool factoryReset();
+
+ protected:
/**
* Returns true if we succeeded
*/
- virtual bool setup();
+ virtual bool setupGPS();
- virtual void doTask();
+ /** 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();
+
+ /** Idle processing while GPS is looking for lock */
+ virtual void whileActive();
/**
- * 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();
+ * 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();
/**
- * Reset our GPS back to factory settings
+ * 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 for success
+ * @return true if we've acquired a new location
*/
- bool factoryReset();
+ virtual bool lookForLocation();
- 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);
+ /// If possible force the GPS into sleep/low power mode
+ virtual void sleep();
+ virtual void wake();
+ private:
/// Attempt to connect to our GPS, returns false if no gps is present
bool tryConnect();
/// Switch to our desired operating mode and save the settings to flash
/// returns true for success
bool setUBXMode();
+
+ uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
};
diff --git a/src/main.cpp b/src/main.cpp
index 37e9077df5..f4e811f545 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -21,9 +21,9 @@
*/
+#include "Air530GPS.h"
#include "MeshRadio.h"
#include "MeshService.h"
-#include "Air530GPS.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "UBloxGPS.h"
@@ -429,7 +429,7 @@ void loop()
// FIXME - until button press handling is done by interrupt (see polling above) we can't sleep very long at all or buttons
// feel slow
- msecstosleep = 10;
+ msecstosleep = 10; // FIXME, stop early if something happens and sleep much longer
// TODO: This should go into a thread handled by FreeRTOS.
handleWebResponse();
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index 8baed24c18..b514b0c5be 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -52,7 +52,7 @@ static uint32_t sendOwnerCb()
{
service.sendOurOwner();
- return radioConfig.preferences.send_owner_interval * radioConfig.preferences.position_broadcast_secs * 1000;
+ return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
}
static concurrency::Periodic sendOwnerPeriod(sendOwnerCb);
@@ -318,7 +318,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;
uint32_t now = millis();
- if (lastGpsSend == 0 || now - lastGpsSend > radioConfig.preferences.position_broadcast_secs * 1000) {
+ if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
lastGpsSend = now;
DEBUG_MSG("Sending position to mesh\n");
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 1f34eb5df5..349e7e67de 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -116,18 +116,9 @@ bool NodeDB::resetRadioConfig()
DEBUG_MSG("Performing factory reset!\n");
installDefaultDeviceState();
didFactoryReset = true;
- } else if (radioConfig.preferences.sds_secs == 0) {
- DEBUG_MSG("Fixing bogus RadioConfig!\n");
-
- radioConfig.preferences.send_owner_interval = 4; // per sw-design.md
- radioConfig.preferences.position_broadcast_secs = 15 * 60;
- radioConfig.preferences.wait_bluetooth_secs = 120;
- radioConfig.preferences.screen_on_secs = 5 * 60;
- radioConfig.preferences.mesh_sds_timeout_secs = 2 * 60 * 60;
- radioConfig.preferences.phone_sds_timeout_sec = 2 * 60 * 60;
- radioConfig.preferences.sds_secs = 365 * 24 * 60 * 60; // one year
- radioConfig.preferences.ls_secs = 60 * 60;
- radioConfig.preferences.phone_timeout_secs = 15 * 60;
+ } else if (!channelSettings.psk.size) {
+ DEBUG_MSG("Setting default preferences!\n");
+
radioConfig.has_channel_settings = true;
radioConfig.has_preferences = true;
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index e1a1b77d61..20dc47cf94 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -47,9 +47,9 @@ class NodeDB
void saveToDisk();
/** Reinit radio config if needed, because either:
- * a) sometimes a buggy android app might send us bogus settings or
+ * a) sometimes a buggy android app might send us bogus settings or
* b) the client set factory_reset
- *
+ *
* @return true if the config was completely reset, in that case, we should send it back to the client
*/
bool resetRadioConfig();
@@ -137,4 +137,18 @@ their nodes
*
* https://github.com/meshtastic/Meshtastic-device/issues/269
*/
-const char *getChannelName();
\ No newline at end of file
+const char *getChannelName();
+
+#define PREF_GET(name, defaultVal) \
+ inline uint32_t getPref_##name() { return radioConfig.preferences.name ? radioConfig.preferences.name : (defaultVal); }
+
+PREF_GET(send_owner_interval, 4)
+PREF_GET(position_broadcast_secs, 15 * 60)
+PREF_GET(wait_bluetooth_secs, 120)
+PREF_GET(screen_on_secs, 60)
+PREF_GET(mesh_sds_timeout_secs, 2 * 60 * 60)
+PREF_GET(phone_sds_timeout_sec, 2 * 60 * 60)
+PREF_GET(sds_secs, 365 * 24 * 60 * 60)
+PREF_GET(ls_secs, 60 * 60)
+PREF_GET(phone_timeout_secs, 15 * 60)
+PREF_GET(min_wake_secs, 10)
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 9ae5955d59..3cbcef1705 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -20,7 +20,7 @@ void PhoneAPI::init()
void PhoneAPI::checkConnectionTimeout()
{
if (isConnected) {
- bool newConnected = (millis() - lastContactMsec < radioConfig.preferences.phone_timeout_secs * 1000L);
+ bool newConnected = (millis() - lastContactMsec < getPref_phone_timeout_secs() * 1000L);
if (!newConnected) {
isConnected = false;
onConnectionChanged(isConnected);
diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp
index 594cec91f3..babd9475f1 100644
--- a/src/mesh/RF95Interface.cpp
+++ b/src/mesh/RF95Interface.cpp
@@ -42,7 +42,7 @@ bool RF95Interface::init()
power = MAX_POWER;
limitPower();
-
+
iface = lora = new RadioLibRF95(&module);
#ifdef RF95_TCXO
@@ -158,7 +158,7 @@ void RF95Interface::startReceive()
isReceiving = true;
- // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
+ // Must be done AFTER, starting receive, because startReceive clears (possibly stale) interrupt pending register bits
enableInterrupt(isrRxLevel0);
}
@@ -171,7 +171,7 @@ bool RF95Interface::isActivelyReceiving()
bool RF95Interface::sleep()
{
// put chipset into sleep mode
- disableInterrupt();
+ setStandby(); // First cancel any active receving/sending
lora->sleep();
return true;
diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp
index 130f340c3b..b17acd9fe9 100644
--- a/src/mesh/SX1262Interface.cpp
+++ b/src/mesh/SX1262Interface.cpp
@@ -179,9 +179,17 @@ void SX1262Interface::startReceive()
/** Could we send right now (i.e. either not actively receving or transmitting)? */
bool SX1262Interface::isActivelyReceiving()
{
- // return false; // FIXME
- // FIXME this is not correct? - often always true - need to add an extra conditional
- return lora.getPacketLength() > 0;
+ // The IRQ status will be cleared when we start our read operation. Check if we've started a preamble, but haven't yet
+ // received and handled the interrupt for reading the packet/handling errors.
+
+ uint16_t irq = lora.getIrqStatus();
+ bool hasPreamble = (irq & SX126X_IRQ_PREAMBLE_DETECTED);
+
+ // this is not correct - often always true - need to add an extra conditional
+ // size_t bytesPending = lora.getPacketLength();
+
+ // if (hasPreamble || bytesPending) DEBUG_MSG("rx hasPre %d, bytes %d\n", hasPreamble, bytesPending);
+ return hasPreamble;
}
bool SX1262Interface::sleep()
diff --git a/src/mesh/mesh.pb.c b/src/mesh/mesh.pb.c
index 11ec3f49f5..d799c33d2c 100644
--- a/src/mesh/mesh.pb.c
+++ b/src/mesh/mesh.pb.c
@@ -27,7 +27,7 @@ PB_BIND(MeshPacket, MeshPacket, 2)
PB_BIND(ChannelSettings, ChannelSettings, AUTO)
-PB_BIND(RadioConfig, RadioConfig, AUTO)
+PB_BIND(RadioConfig, RadioConfig, 2)
PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)
@@ -60,3 +60,5 @@ PB_BIND(ManufacturingData, ManufacturingData, AUTO)
+
+
diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h
index b726ab6e1c..01ba5b5dd4 100644
--- a/src/mesh/mesh.pb.h
+++ b/src/mesh/mesh.pb.h
@@ -37,6 +37,19 @@ typedef enum _RegionCode {
RegionCode_TW = 8
} RegionCode;
+typedef enum _GpsOperation {
+ GpsOperation_GpsOpUnset = 0,
+ GpsOperation_GpsOpMobile = 2,
+ GpsOperation_GpsOpTimeOnly = 3,
+ GpsOperation_GpsOpDisabled = 4
+} GpsOperation;
+
+typedef enum _LocationSharing {
+ LocationSharing_LocUnset = 0,
+ LocationSharing_LocEnabled = 1,
+ LocationSharing_LocDisabled = 2
+} LocationSharing;
+
typedef enum _Data_Type {
Data_Type_OPAQUE = 0,
Data_Type_CLEAR_TEXT = 1,
@@ -121,6 +134,12 @@ typedef struct _RadioConfig_UserPreferences {
char wifi_password[64];
bool wifi_ap_mode;
RegionCode region;
+ LocationSharing location_share;
+ GpsOperation gps_operation;
+ uint32_t gps_update_interval;
+ uint32_t gps_attempt_time;
+ bool is_router;
+ bool is_low_power;
bool factory_reset;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
@@ -248,6 +267,14 @@ typedef struct _ToRadio {
#define _RegionCode_MAX RegionCode_TW
#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1))
+#define _GpsOperation_MIN GpsOperation_GpsOpUnset
+#define _GpsOperation_MAX GpsOperation_GpsOpDisabled
+#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1))
+
+#define _LocationSharing_MIN LocationSharing_LocUnset
+#define _LocationSharing_MAX LocationSharing_LocDisabled
+#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
+
#define _Data_Type_MIN Data_Type_OPAQUE
#define _Data_Type_MAX Data_Type_CLEAR_READACK
#define _Data_Type_ARRAYSIZE ((Data_Type)(Data_Type_CLEAR_READACK+1))
@@ -266,7 +293,7 @@ typedef struct _ToRadio {
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
-#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, 0, 0, {0, 0, 0}}
+#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
@@ -282,7 +309,7 @@ typedef struct _ToRadio {
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
-#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, 0, 0, {0, 0, 0}}
+#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
@@ -341,7 +368,13 @@ typedef struct _ToRadio {
#define RadioConfig_UserPreferences_wifi_password_tag 13
#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14
#define RadioConfig_UserPreferences_region_tag 15
+#define RadioConfig_UserPreferences_is_router_tag 37
+#define RadioConfig_UserPreferences_is_low_power_tag 38
#define RadioConfig_UserPreferences_factory_reset_tag 100
+#define RadioConfig_UserPreferences_location_share_tag 32
+#define RadioConfig_UserPreferences_gps_operation_tag 33
+#define RadioConfig_UserPreferences_gps_update_interval_tag 34
+#define RadioConfig_UserPreferences_gps_attempt_time_tag 36
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
#define RouteDiscovery_route_tag 2
#define User_id_tag 1
@@ -498,6 +531,12 @@ X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \
X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \
X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \
X(a, STATIC, SINGULAR, UENUM, region, 15) \
+X(a, STATIC, SINGULAR, UENUM, location_share, 32) \
+X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \
+X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
+X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
+X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
+X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define RadioConfig_UserPreferences_CALLBACK NULL
@@ -635,11 +674,11 @@ extern const pb_msgdesc_t ManufacturingData_msg;
#define SubPacket_size 274
#define MeshPacket_size 313
#define ChannelSettings_size 84
-#define RadioConfig_size 282
-#define RadioConfig_UserPreferences_size 193
+#define RadioConfig_size 308
+#define RadioConfig_UserPreferences_size 219
#define NodeInfo_size 132
#define MyNodeInfo_size 110
-#define DeviceState_size 5434
+#define DeviceState_size 5460
#define DebugString_size 258
#define FromRadio_size 322
#define ToRadio_size 316
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 731273c9be..a6753d8ac8 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -163,6 +163,9 @@ void doDeepSleep(uint64_t msecToWake)
digitalWrite(VEXT_ENABLE, 1); // turn off the display power
#endif
+ // Kill GPS power completely (even if previously we just had it in sleep mode)
+ setGPSPower(false);
+
setLed(false);
#ifdef TBEAM_V10
@@ -176,7 +179,8 @@ void doDeepSleep(uint64_t msecToWake)
// axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // LORA radio
- setGPSPower(false);
+ // now done by UBloxGPS.cpp
+ // setGPSPower(false);
}
#endif
@@ -260,12 +264,20 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
// We treat the serial port as a GPIO for a fast/low power way of waking, if we see a rising edge that means
// someone started to send something
- // Alas - doesn't work reliably, instead need to use the uart specific version (which burns a little power)
- // FIXME: gpio 3 is RXD for serialport 0 on ESP32
+ // gpio 3 is RXD for serialport 0 on ESP32
// Send a few Z characters to wake the port
- gpio_wakeup_enable((gpio_num_t)SERIAL0_RX_GPIO, GPIO_INTR_LOW_LEVEL);
- // uart_set_wakeup_threshold(UART_NUM_0, 3);
- // esp_sleep_enable_uart_wakeup(0);
+
+ // this doesn't work on TBEAMs when the USB is depowered (causes bogus interrupts)
+ // So we disable this "wake on serial" feature - because now when a TBEAM (only) has power connected it
+ // never tries to go to sleep if the user is using the API
+ // gpio_wakeup_enable((gpio_num_t)SERIAL0_RX_GPIO, GPIO_INTR_LOW_LEVEL);
+
+ // doesn't help - I think the USB-UART chip losing power is pulling the signal llow
+ // gpio_pullup_en((gpio_num_t)SERIAL0_RX_GPIO);
+
+ // alas - can only work if using the refclock, which is limited to about 9600 bps
+ // assert(uart_set_wakeup_threshold(UART_NUM_0, 3) == ESP_OK);
+ // assert(esp_sleep_enable_uart_wakeup(0) == ESP_OK);
#endif
#ifdef BUTTON_PIN
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
@@ -274,7 +286,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
gpio_wakeup_enable((gpio_num_t)RF95_IRQ_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
#endif
#ifdef PMU_IRQ
- // FIXME, disable wake due to PMU because it seems to fire all the time?
+ // wake due to PMU can happen repeatedly if there is no battery installed or the battery fills
if (axp192_found)
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL); // pmu irq
#endif