This commit is contained in:
grcasanova 2020-07-06 00:54:30 +02:00
parent 0a6059ba13
commit d5b8038457
16 changed files with 144 additions and 105 deletions

View File

@ -1,43 +0,0 @@
#include "PeriodicTask.h"
#include "Periodic.h"
PeriodicScheduler periodicScheduler;
PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) {}
void PeriodicTask::setup()
{
periodicScheduler.schedule(this);
}
/// call this from loop
void PeriodicScheduler::loop()
{
meshtastic::LockGuard lg(&lock);
uint32_t now = millis();
for (auto t : tasks) {
if (t->period && (now - t->lastMsec) >= t->period) {
t->doTask();
t->lastMsec = now;
}
}
}
void PeriodicScheduler::schedule(PeriodicTask *t)
{
meshtastic::LockGuard lg(&lock);
tasks.insert(t);
}
void PeriodicScheduler::unschedule(PeriodicTask *t)
{
meshtastic::LockGuard lg(&lock);
tasks.erase(t);
}
void Periodic::doTask()
{
uint32_t p = callback();
setPeriod(p);
}

View File

@ -4,7 +4,9 @@
namespace concurrency { namespace concurrency {
// Simple wrapper around FreeRTOS API for implementing a mutex lock. /**
* @brief Simple wrapper around FreeRTOS API for implementing a mutex lock
*/
class Lock class Lock
{ {
public: public:

View File

@ -4,7 +4,9 @@
namespace concurrency { namespace concurrency {
// RAII lock guard. /**
* @brief RAII lock guard
*/
class LockGuard class LockGuard
{ {
public: public:

View File

@ -5,7 +5,7 @@
namespace concurrency { namespace concurrency {
/** /**
* A worker thread that waits on a freertos notification * @brief A worker thread that waits on a freertos notification
*/ */
class NotifiedWorkerThread : public WorkerThread class NotifiedWorkerThread : public WorkerThread
{ {

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include "PeriodicTask.h" #include "PeriodicTask.h"
#include <Arduino.h>
namespace concurrency {
/** /**
* Periodically invoke a callback. * @brief Periodically invoke a callback. This just provides C-style callback conventions
* * rather than a virtual function - FIXME, remove?
* This just provides C style callback conventions rather than a virtual function - FIXME, remove?
*/ */
class Periodic : public PeriodicTask class Periodic : public PeriodicTask
{ {
@ -17,5 +17,10 @@ class Periodic : public PeriodicTask
Periodic(uint32_t (*_callback)()) : callback(_callback) {} Periodic(uint32_t (*_callback)()) : callback(_callback) {}
protected: protected:
void doTask(); void doTask() {
uint32_t p = callback();
setPeriod(p);
}
}; };
} // namespace concurrency

View File

@ -0,0 +1,35 @@
#include "PeriodicScheduler.h"
#include "PeriodicTask.h"
#include "LockGuard.h"
#include "../time.h"
namespace concurrency {
/// call this from loop
void PeriodicScheduler::loop()
{
LockGuard lg(&lock);
uint32_t now = time::millis();
for (auto t : tasks) {
if (t->period && (now - t->lastMsec) >= t->period) {
t->doTask();
t->lastMsec = now;
}
}
}
void PeriodicScheduler::schedule(PeriodicTask *t)
{
LockGuard lg(&lock);
tasks.insert(t);
}
void PeriodicScheduler::unschedule(PeriodicTask *t)
{
LockGuard lg(&lock);
tasks.erase(t);
}
} // namespace concurrency

View File

@ -0,0 +1,40 @@
#pragma once
#include "Lock.h"
#include <cstdint>
#include <unordered_set>
namespace concurrency {
class PeriodicTask;
/**
* @brief Runs all PeriodicTasks in the system. Currently called from main loop()
* but eventually should be its own thread blocked on a freertos timer.
*/
class PeriodicScheduler
{
friend class PeriodicTask;
/**
* This really should be some form of heap, and when the period gets changed on a task it should get
* rescheduled in that heap. Currently it is just a dumb array and everytime we run loop() we check
* _every_ tasks. If it was a heap we'd only have to check the first task.
*/
std::unordered_set<PeriodicTask *> tasks;
// Protects the above variables.
Lock lock;
public:
/// Run any next tasks which are due for execution
void loop();
private:
void schedule(PeriodicTask *t);
void unschedule(PeriodicTask *t);
};
extern PeriodicScheduler periodicScheduler;
} // namespace concurrency

View File

@ -0,0 +1,16 @@
#include "PeriodicTask.h"
#include "Periodic.h"
#include "LockGuard.h"
namespace concurrency {
PeriodicScheduler periodicScheduler;
PeriodicTask::PeriodicTask(uint32_t initialPeriod) : period(initialPeriod) {}
void PeriodicTask::setup()
{
periodicScheduler.schedule(this);
}
} // namespace concurrency

View File

@ -1,41 +1,9 @@
#pragma once #pragma once
#include "lock.h" #include "PeriodicScheduler.h"
#include <Arduino.h> #include "../time.h"
#include <cstdint>
#include <unordered_set>
class PeriodicTask; namespace concurrency {
/**
* Runs all PeriodicTasks in the system.
*
* Currently called from main loop() but eventually should be its own thread blocked on a freertos timer.
*/
class PeriodicScheduler
{
friend class PeriodicTask;
/**
* This really should be some form of heap, and when the period gets changed on a task it should get
* rescheduled in that heap. Currently it is just a dumb array and everytime we run loop() we check
* _every_ tasks. If it was a heap we'd only have to check the first task.
*/
std::unordered_set<PeriodicTask *> tasks;
// Protects the above variables.
meshtastic::Lock lock;
public:
/// Run any next tasks which are due for execution
void loop();
private:
void schedule(PeriodicTask *t);
void unschedule(PeriodicTask *t);
};
extern PeriodicScheduler periodicScheduler;
/** /**
* A base class for tasks that want their doTask() method invoked periodically * A base class for tasks that want their doTask() method invoked periodically
@ -69,7 +37,7 @@ class PeriodicTask
*/ */
void setPeriod(uint32_t p) void setPeriod(uint32_t p)
{ {
lastMsec = millis(); // reset starting from now lastMsec = time::millis(); // reset starting from now
period = p; period = p;
} }
@ -83,3 +51,5 @@ class PeriodicTask
protected: protected:
virtual void doTask() = 0; virtual void doTask() = 0;
}; };
} // namespace concurrency

View File

@ -4,6 +4,9 @@
namespace concurrency { namespace concurrency {
/**
* @brief Base threading
*/
class Thread class Thread
{ {
protected: protected:

View File

@ -5,11 +5,10 @@
namespace concurrency { namespace concurrency {
/** /**
* This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting onlyschool arduino loop() code. * @brief This wraps threading (FreeRTOS for now) with a blocking API intended for efficiently converting
* old-school arduino loop() code. Use as a mixin base class for the classes you want to convert.
* *
* Use as a mixin base class for the classes you want to convert. * @link https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
*
* https://www.freertos.org/RTOS_Task_Notification_As_Mailbox.html
*/ */
class WorkerThread : public Thread class WorkerThread : public Thread
{ {

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Observer.h" #include "Observer.h"
#include "PeriodicTask.h"
#include "sys/time.h" #include "sys/time.h"
/// If we haven't yet set our RTC this boot, set it from a GPS derived time /// If we haven't yet set our RTC this boot, set it from a GPS derived time

View File

@ -25,7 +25,7 @@
#include "MeshService.h" #include "MeshService.h"
#include "NEMAGPS.h" #include "NEMAGPS.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "Periodic.h" #include "concurrency/Periodic.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "UBloxGPS.h" #include "UBloxGPS.h"
#include "configuration.h" #include "configuration.h"
@ -124,7 +124,7 @@ static uint32_t ledBlinker()
return powerStatus.charging ? 1000 : (ledOn ? 2 : 1000); return powerStatus.charging ? 1000 : (ledOn ? 2 : 1000);
} }
Periodic ledPeriodic(ledBlinker); concurrency::Periodic ledPeriodic(ledBlinker);
// Prepare for button presses // Prepare for button presses
#ifdef BUTTON_PIN #ifdef BUTTON_PIN
@ -316,7 +316,7 @@ uint32_t axpDebugRead()
return 30 * 1000; return 30 * 1000;
} }
Periodic axpDebugOutput(axpDebugRead); concurrency::Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup(); axpDebugOutput.setup();
#endif #endif

View File

@ -529,7 +529,7 @@ void Screen::handleSetOn(bool on)
void Screen::setup() void Screen::setup()
{ {
PeriodicTask::setup(); concurrency::PeriodicTask::setup();
// We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device // We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device
// is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device. // is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device.
@ -746,7 +746,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
char channelStr[20]; char channelStr[20];
{ {
LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str()); snprintf(channelStr, sizeof(channelStr), "#%s", channelName.c_str());
// Display power status // Display power status

View File

@ -10,9 +10,9 @@
#include <SSD1306Wire.h> #include <SSD1306Wire.h>
#endif #endif
#include "PeriodicTask.h" #include "concurrency/PeriodicTask.h"
#include "TypedQueue.h" #include "TypedQueue.h"
#include "lock.h" #include "concurrency/Lock.h"
#include "power.h" #include "power.h"
#include <string> #include <string>
@ -32,7 +32,7 @@ class DebugInfo
/// Sets user statistics. /// Sets user statistics.
void setNodeNumbersStatus(int online, int total) void setNodeNumbersStatus(int online, int total)
{ {
LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
nodesOnline = online; nodesOnline = online;
nodesTotal = total; nodesTotal = total;
} }
@ -40,7 +40,7 @@ class DebugInfo
/// Sets the name of the channel. /// Sets the name of the channel.
void setChannelNameStatus(const char *name) void setChannelNameStatus(const char *name)
{ {
LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
channelName = name; channelName = name;
} }
@ -48,7 +48,7 @@ class DebugInfo
// //
void setPowerStatus(const PowerStatus &status) void setPowerStatus(const PowerStatus &status)
{ {
LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
powerStatus = status; powerStatus = status;
} }
@ -59,7 +59,7 @@ class DebugInfo
// TODO(girts): figure out what the format should be. // TODO(girts): figure out what the format should be.
void setGPSStatus(const char *status) void setGPSStatus(const char *status)
{ {
LockGuard guard(&lock); concurrency::LockGuard guard(&lock);
gpsStatus = status; gpsStatus = status;
} }
@ -81,7 +81,7 @@ class DebugInfo
std::string gpsStatus; std::string gpsStatus;
/// Protects all of internal state. /// Protects all of internal state.
Lock lock; concurrency::Lock lock;
}; };
/// Deals with showing things on the screen of the device. /// Deals with showing things on the screen of the device.
@ -91,7 +91,7 @@ class DebugInfo
// //
// This class is thread-safe (as long as drawFrame is not called multiple times // This class is thread-safe (as long as drawFrame is not called multiple times
// simultaneously). // simultaneously).
class Screen : public PeriodicTask class Screen : public concurrency::PeriodicTask
{ {
public: public:
Screen(uint8_t address, int sda = -1, int scl = -1); Screen(uint8_t address, int sda = -1, int scl = -1);

11
src/time.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "freertos.h"
namespace time {
uint32_t millis() {
return xTaskGetTickCount();
}
} // namespace time