diff --git a/TODO.md b/TODO.md index 0e214e89..78b689e2 100644 --- a/TODO.md +++ b/TODO.md @@ -5,6 +5,7 @@ Items to complete before the first alpha release. * implement CustomRF95::canSleep * document rules for sleep wrt lora/bluetooth/screen/gps. also: if I have text messages (only) for the phone, then give a few seconds in the hopes BLE can get it across before we have to go back to sleep. * wake from light sleep as needed for our next scheduled periodic task (needed for gps position broadcasts etc) +* turn bluetooth off based on our sleep policy * if the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs for it (because it will redownload the nodedb when it comes back) * don't enter light sleep while the screen is on diff --git a/src/GPS.cpp b/src/GPS.cpp index e8fe51fc..c89a5536 100644 --- a/src/GPS.cpp +++ b/src/GPS.cpp @@ -11,8 +11,9 @@ uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated onc RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock (even across sleeps) GPS gps; +bool hasValidLocation; // default to false, until we complete our first read -GPS::GPS() : PeriodicTask(30 * 1000) +GPS::GPS() : PeriodicTask() { } @@ -57,8 +58,23 @@ void GPS::perhapsSetRTC(const struct timeval *tv) void GPS::loop() { PeriodicTask::loop(); +} +uint32_t GPS::getTime() +{ + return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; +} + +uint32_t GPS::getValidTime() +{ + return timeSetFromGPS ? getTime() : 0; +} + +uint32_t GPS::doTask() +{ #ifdef GPS_RX_PIN + // Consume all characters that have arrived + while (_serial_gps.available()) { encode(_serial_gps.read()); @@ -86,25 +102,16 @@ void GPS::loop() perhapsSetRTC(&tv); } #endif -} -uint32_t GPS::getTime() -{ - return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs; -} - -uint32_t GPS::getValidTime() -{ - return timeSetFromGPS ? getTime() : 0; -} - -void GPS::doTask() -{ if (location.isValid() && location.isUpdated()) { // we only notify if position has changed // DEBUG_MSG("new gps pos\n"); + hasValidLocation = true; notifyObservers(); } + + // Once we have sent a location we only poll the GPS rarely, otherwise check back every 100ms until we have something over the serial + return hasValidLocation ? 30 * 1000 : 100; } String GPS::getTimeStr() diff --git a/src/GPS.h b/src/GPS.h index 9ff98cca..1a2c82ad 100644 --- a/src/GPS.h +++ b/src/GPS.h @@ -27,7 +27,7 @@ public: virtual void loop(); - virtual void doTask(); + virtual uint32_t doTask(); /// If we haven't yet set our RTC this boot, set it from a GPS derived time void perhapsSetRTC(const struct timeval *tv); diff --git a/src/MeshService.cpp b/src/MeshService.cpp index 271ed03b..7b321d7a 100644 --- a/src/MeshService.cpp +++ b/src/MeshService.cpp @@ -8,6 +8,7 @@ #include "NodeDB.h" #include "GPS.h" #include "screen.h" +#include "Periodic.h" /* receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone. @@ -60,7 +61,9 @@ void MeshService::init() DEBUG_MSG("radio init failed\n"); gps.addObserver(this); - sendOurOwner(); + + // No need to call this here, our periodic task will fire quite soon + // sendOwnerPeriod(); } void MeshService::sendOurOwner(NodeNum dest) @@ -165,6 +168,16 @@ void MeshService::handleFromRadio() bluetoothNotifyFromNum(fromNum); } + +uint32_t sendOwnerCb() +{ + service.sendOurOwner(); + + return radioConfig.preferences.send_owner_secs * 1000; +} + +Periodic sendOwnerPeriod(sendOwnerCb); + /// Do idle processing (mostly processing messages which have been queued from the radio) void MeshService::loop() { @@ -173,13 +186,7 @@ void MeshService::loop() handleFromRadio(); // occasionally send our owner info - static uint32_t lastsend; - uint32_t now = millis(); - if (now - lastsend > radioConfig.preferences.send_owner_secs * 1000) - { - lastsend = now; - sendOurOwner(); - } + sendOwnerPeriod.loop(); } /// The radioConfig object just changed, call this to force the hw to change to the new settings diff --git a/src/Periodic.h b/src/Periodic.h index fe7b67df..92d66241 100644 --- a/src/Periodic.h +++ b/src/Periodic.h @@ -1,32 +1,22 @@ #pragma once #include +#include "PeriodicTask.h" /** * Periodically invoke a callback. * - * FIXME: currently just syntatic sugar for polling in loop (you must call .loop), but eventually - * generalize with the freertos scheduler so we can save lots of power by having everything either in - * something like this or triggered off of an irq. + * This just provides C style callback conventions rather than a virtual function - FIXME, remove? */ -class Periodic +class Periodic : public PeriodicTask { - uint32_t lastMsec = 0; - uint32_t period = 1; // call soon after creation uint32_t (*callback)(); public: // callback returns the period for the next callback invocation (or 0 if we should no longer be called) Periodic(uint32_t (*_callback)()) : callback(_callback) {} - // for the time being this must be called from loop - void loop() - { - uint32_t now = millis(); - if (period && (now - lastMsec) >= period) - { - lastMsec = now; - period = (*callback)(); - } - } +protected: + + uint32_t doTask(); }; diff --git a/src/PeriodicTask.cpp b/src/PeriodicTask.cpp new file mode 100644 index 00000000..bb46d1ce --- /dev/null +++ b/src/PeriodicTask.cpp @@ -0,0 +1,19 @@ +#include "PeriodicTask.h" +#include "Periodic.h" + +PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) +{ +} + +/// call this from loop +void PeriodicTask::loop() +{ + uint32_t now = millis(); + if (period && (now - lastMsec) >= period) + { + lastMsec = now; + period = doTask(); + } +} + + uint32_t Periodic::doTask() { return callback(); } \ No newline at end of file diff --git a/src/PeriodicTask.h b/src/PeriodicTask.h index fa68e805..5ac90e29 100644 --- a/src/PeriodicTask.h +++ b/src/PeriodicTask.h @@ -3,34 +3,28 @@ #include #include "configuration.h" +/** + * A base class for tasks that want their doTask() method invoked periodically + * + * FIXME: currently just syntatic sugar for polling in loop (you must call .loop), but eventually + * generalize with the freertos scheduler so we can save lots of power by having everything either in + * something like this or triggered off of an irq. + */ class PeriodicTask { - /// we use prevMsec rather than nextMsec because it is easier to handle the uint32 rollover in that case, also changes in periodMsec take effect immediately - uint32_t prevMsec; + uint32_t lastMsec = 0; + uint32_t period = 1; // call soon after creation public: uint32_t periodMsec; virtual ~PeriodicTask() {} - PeriodicTask(uint32_t period) : periodMsec(period) - { - prevMsec = millis(); - } + PeriodicTask(uint32_t initialPeriod = 1); /// call this from loop - virtual void loop() - { - uint32_t now = millis(); - if (now > (prevMsec + periodMsec)) - { - // FIXME, this lets period slightly drift based on scheduling - not sure if that is always good - prevMsec = now; + virtual void loop(); - // DEBUG_MSG("Calling periodic task\n"); - doTask(); - } - } - - virtual void doTask() = 0; +protected: + virtual uint32_t doTask() = 0; };