Skip to content

Commit

Permalink
Added support for lambdas in the Timer class (#1378)
Browse files Browse the repository at this point in the history
Using C++11 std::function and std::bind
  • Loading branch information
frankdownunder authored and slaff committed May 15, 2018
1 parent 2946146 commit e71d02c
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 36 deletions.
32 changes: 32 additions & 0 deletions Sming/SmingCore/Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ Timer& Timer::initializeUs(uint32_t microseconds, TimerDelegate delegateFunction
return *this;
}

Timer& Timer::initializeMs(uint32_t milliseconds, TimerDelegateStdFunction delegateFunction)
{
setCallback(delegateFunction);
setIntervalMs(milliseconds);
return *this;
}

Timer& Timer::initializeUs(uint32_t microseconds, TimerDelegateStdFunction delegateFunction)
{
setCallback(delegateFunction);
setIntervalUs(microseconds);
return *this;
}

void Timer::start(bool repeating/* = true*/)
{
this->repeating = repeating;
Expand Down Expand Up @@ -135,6 +149,7 @@ void Timer::setCallback(InterruptCallback interrupt/* = NULL*/)
ETS_INTR_LOCK();
callback = interrupt;
delegate_func = nullptr;
delegate_stdfunc = nullptr;
ETS_INTR_UNLOCK();

if (!interrupt)
Expand All @@ -146,6 +161,19 @@ void Timer::setCallback(TimerDelegate delegateFunction)
ETS_INTR_LOCK();
callback = nullptr;
delegate_func = delegateFunction;
delegate_stdfunc = nullptr;
ETS_INTR_UNLOCK();

if (!delegateFunction)
stop();
}

void Timer::setCallback(const TimerDelegateStdFunction& delegateFunction)
{
ETS_INTR_LOCK();
callback = nullptr;
delegate_func = nullptr;
delegate_stdfunc = delegateFunction;
ETS_INTR_UNLOCK();

if (!delegateFunction)
Expand Down Expand Up @@ -197,6 +225,10 @@ void Timer::tick()
{
delegate_func();
}
else if (delegate_stdfunc)
{
delegate_stdfunc();
}
else{
stop();
}
Expand Down
34 changes: 28 additions & 6 deletions Sming/SmingCore/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#ifndef _SMING_CORE_Timer_H_
#define _SMING_CORE_Timer_H_


#include <functional>
#include "../SmingCore/Interrupts.h"
#include "../SmingCore/Delegate.h"
#include "../Wiring/WiringFrameworkDependencies.h"
Expand All @@ -25,6 +25,7 @@
#define MAX_OS_TIMER_INTERVAL_US 268435000

typedef Delegate<void()> TimerDelegate;
typedef std::function<void()> TimerDelegateStdFunction;

class Timer
{
Expand Down Expand Up @@ -59,16 +60,31 @@ class Timer
* @param milliseconds Duration of timer in milliseconds
* @param delegateFunction Function to call when timer triggers
* @note Delegate callback method
* @deprecated Use initializeMs(xx, TimerDelegateStdFunction); instead.
*/
Timer& IRAM_ATTR initializeMs(uint32_t milliseconds, TimerDelegate delegateFunction = NULL); // Init in Milliseconds.

/** @brief Initialise microsecond timer
* @param microseconds Duration of timer in milliseconds
* @param delegateFunction Function to call when timer triggers
* @note Delegate callback method
* @deprecated Use initializeMs(xx, TimerDelegateStdFunction); instead.
*/
Timer& IRAM_ATTR initializeUs(uint32_t microseconds, TimerDelegate delegateFunction = NULL); // Init in Microseconds.

/** @brief Initialise millisecond timer
* @param milliseconds Duration of timer in milliseconds
* @param delegateFunction Function to call when timer triggers
* @note Delegate callback method
*/
Timer& IRAM_ATTR initializeMs(uint32_t milliseconds, TimerDelegateStdFunction delegateFunction = nullptr); // Init in Milliseconds.

/** @brief Initialise microsecond timer
* @param microseconds Duration of timer in milliseconds
* @param delegateFunction Function to call when timer triggers
* @note Delegate callback method
*/
Timer& IRAM_ATTR initializeUs(uint32_t microseconds, TimerDelegateStdFunction delegateFunction = nullptr); // Init in Microseconds.
/** @brief Start timer running
* @param repeating Set to true for repeating timer. Set to false for one-shot.
*/
Expand Down Expand Up @@ -120,11 +136,16 @@ class Timer
*/
void IRAM_ATTR setCallback(InterruptCallback interrupt = NULL);

/** @brief Set timer trigger function
* @param delegateFunction Function to be called on timer trigger
* @note Delegate callback method
*/
void IRAM_ATTR setCallback(TimerDelegate delegateFunction);
/** @brief Set timer trigger function
* @param delegateFunction Function to be called on timer trigger
* @note Delegate callback method
*/
void IRAM_ATTR setCallback(TimerDelegate delegateFunction);
/** @brief Set timer trigger function
* @param delegateFunction Function to be called on timer trigger
* @note Delegate callback method
*/
void IRAM_ATTR setCallback(const TimerDelegateStdFunction& delegateFunction);


protected:
Expand All @@ -142,6 +163,7 @@ class Timer
uint64_t interval = 0;
InterruptCallback callback = nullptr;
TimerDelegate delegate_func = nullptr;
TimerDelegateStdFunction delegate_stdfunc = nullptr;
bool repeating = false;
bool started = false;

Expand Down
134 changes: 104 additions & 30 deletions samples/Basic_Delegates/app/application.cpp
Original file line number Diff line number Diff line change
@@ -1,45 +1,119 @@
#include <user_config.h>
#include <SmingCore.h>

class LedBlinker
void plainOldOrdinaryFunction()
{
debugf("plainOldOrdinaryFunction");
}

void functionWithMoreComlicatedSignature(int a, String b)
{
debugf("functionWithMoreComlicatedSignature %d %s", a, b.c_str());
}

public :
LedBlinker(int reqPin) : ledPin(reqPin) {
pinMode(ledPin, OUTPUT);
};
bool setTimer(int reqInterval) {
if (reqInterval <= 0) return false;
ledInterval = reqInterval;
class Task
{
public:
Task() {};
bool setTimer(int reqInterval)
{
if (reqInterval <= 0) {
return false;
}
taskInterval = reqInterval;
return true;
}
void blink(bool reqRun) {
if (reqRun) {
ledTimer.initializeMs(ledInterval, TimerDelegate(&LedBlinker::ledBlink,this)).start();
}
else {
ledTimer.stop();
}

// This example show the way delegates have been used in Sming in the past.
void callOldDelegate()
{
taskTimer.initializeMs(taskInterval, TimerDelegate(&Task::doOldDelegate, this)).start();
}
void ledBlink () { ledState = !ledState ; digitalWrite(ledPin, ledState);}

private :
int ledPin = 2;
Timer ledTimer;
int ledInterval = 1000;
bool ledState = true;
};
// This example shows how to use a plain old ordinary function as a callback
void callPlainOldOrdinaryFunction()
{
taskTimer.initializeMs(taskInterval, TimerDelegateStdFunction(plainOldOrdinaryFunction)).start();
// or just
// taskTimer.initializeMs(taskInterval, plainOldOrdinaryFunction).start();
}

// This example shows how to use std::bind to make us of a function that has more parameters than our signature has
void showHowToUseBind()
{
auto b = std::bind(functionWithMoreComlicatedSignature, 2, "parameters");
taskTimer.initializeMs(taskInterval, b).start();
}

#define LEDPIN_1 2 // GPIO2
#define LEDPIN_2 4 // GPIO4
// Sming now allows the use of std::function
// This example shows how to use a lamda expression as a callback
void callLamda()
{
int foo = 123;
taskTimer.initializeMs(taskInterval,
[foo] // capture just foo by value (Note it would be bad to pass by reference as foo would be out of scope when the lamda function runs later)
() // No parameters to the callback
-> void // Returns nothing
{
if (foo == 123) {
debugf("lamda Callback foo is 123");
}
else
{
debugf("lamda Callback foo is not 123, crikey!");
}
}
).start();
}

// This example shows how to use a member function as a callback
void callMemberFunction()
{
// A non-static member function must be called with an object.
// That is, it always implicitly passes "this" pointer as its argument.
// But because our callback specifies that we don't take any arguments (<void(void)>),
// you must use std::bind to bind the first (and the only) argument.

TimerDelegateStdFunction b = std::bind(&Task::callbackMemberFunction, this);
taskTimer.initializeMs(taskInterval, b).start();
}

void doOldDelegate()
{
debugf("doOldDelegate");
}
void callbackMemberFunction()
{
debugf("callMemberFunction");
}

private:
Timer taskTimer;
int taskInterval = 1000;
};

LedBlinker myLed1 = LedBlinker(LEDPIN_1);
LedBlinker myLed2 = LedBlinker(LEDPIN_2);
Task task1;
Task task2;
Task task3;
Task task4;
Task task5;

void init()
{
myLed1.setTimer(1000);
myLed1.blink(true);
myLed2.setTimer(500);
myLed2.blink(true);
Serial.begin(115200);

task1.setTimer(1500);
task1.callOldDelegate();

task2.setTimer(1600);
task2.callPlainOldOrdinaryFunction();

task3.setTimer(1900);
task3.showHowToUseBind();

task4.setTimer(1700);
task4.callMemberFunction();

task5.setTimer(1800);
task5.callLamda();
}

0 comments on commit e71d02c

Please sign in to comment.