Skip to content

Ticker with Delegate #6918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 55 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0f00454
Delegate class template.
dok-net Nov 28, 2019
4b6020c
Solves problems with lambdas and std::bind
dok-net Nov 28, 2019
4363ce9
MSVC compiler picked up missing std::forward
dok-net Nov 28, 2019
d133e30
Circular include issue fixed
dok-net Nov 29, 2019
c56fa87
Use function declaration syntax in template type specification
dok-net Nov 29, 2019
48ed02b
Use terse function notation - match std::function, the optional 1st a…
dok-net Nov 29, 2019
bc8a0e6
Performance improvement for Delegate specialization without additiona…
dok-net Dec 4, 2019
05e1811
Updated Delegate and new MultiDelegate template.
dok-net Dec 7, 2019
a5ee065
MultiDelegate template argument to switch queue/event behavior.
dok-net Dec 8, 2019
79c3816
Fix deletion of argument value caused by forwarding to Delegate.
dok-net Dec 8, 2019
edbeeab
Readied MultiDelegate for ESP32 ISR safeness.
dok-net Dec 8, 2019
cda54ff
Completed port of Delegate and MultiDelegate to Non-Arduino platforms
dok-net Dec 9, 2019
c6fb8bc
Add missing LGPL license header.
dok-net Dec 9, 2019
da5f0d4
Directly derive from std::function for DelegateImpl<void, R>, too.
dok-net Dec 10, 2019
15bbc1c
Fixed queue and event multiplexer modes (ISQUEUE template argument) f…
dok-net Dec 11, 2019
e1c3d22
Signed-unsigned mismatch caught by ESP2866 Arduino CI.
dok-net Dec 12, 2019
534d016
Performance and ease of use, more comprehensible ctor and operator=: …
dok-net Dec 13, 2019
ee86f2e
Interface full lockdown: mark implementation details private instead …
dok-net Dec 14, 2019
0db6c95
For use of Delegate as callback in functions that take C-fun ptr and …
dok-net Dec 15, 2019
c5d738c
Optimize casting to fun ptr and argument for "attachInterruptArg"-lik…
dok-net Dec 16, 2019
18f497e
Bug fix: must reinterpret_cast for R() as R(void*) cast (extra argume…
dok-net Dec 16, 2019
e6e60e7
using operator= is required to suppress auto generation.
dok-net Dec 17, 2019
d855cbd
Delegate to fptr helpers must be in IRAM
dok-net Dec 17, 2019
6b3e87b
Delegate refactoring for same ordering of member functions between sp…
dok-net Dec 20, 2019
af76e5f
Bug fix Delegate, custom type converter.
dok-net Dec 22, 2019
2b4a08d
Use explicit initialization in ctor for kind member.
dok-net Dec 23, 2019
c19456c
Fix ctor overloads competing with ctor templates.
dok-net Dec 23, 2019
6bac522
Assignment operator template caused ambiguity error in MSVC build - d…
dok-net Dec 24, 2019
ae7b4f6
Delegate template programming for > 3 platforms is interesting.
dok-net Jan 18, 2020
c25965d
unsigned/int instead of (u)int32_t gives lower memory footprint on 8b…
dok-net Jan 17, 2020
188c3f0
Refactor uses of unsigned for buffer sizes and item counts to size_t.
dok-net Jan 19, 2020
07e52a1
It was found that internal linkage suppresses the effect of the IRAM_…
dok-net Jan 21, 2020
e78885c
std::bind is IRAM cache save, lambda is not.
dok-net Jan 22, 2020
e3888ca
Enhancements to MultiDelegate: event multiplexer mode no longer has a…
dok-net Feb 12, 2020
680abe1
Added forward iterator and begin() and end() functions to MultiDelegate.
dok-net Feb 12, 2020
1f193ab
Change to make MultiDelegate invoke and erase work off iterators.
dok-net Feb 13, 2020
57a87ca
Constness fix for iterator dereference
dok-net Feb 13, 2020
960c8f5
constness on return type warning fix.
dok-net Feb 13, 2020
3cd6b91
Conform to C++ 17 and later.
dok-net Feb 25, 2020
64b06ec
Resolve g++ 9's c++17 deprecation warnings.
dok-net Feb 25, 2020
3b7f2c7
gcc 9.2 is very strict about template inheritance of ctor and assignm…
dok-net Feb 28, 2020
6e17563
Fix both ambiguous operator= and infinite ctor recursion.
dok-net Mar 1, 2020
df02bac
don't cast to rvalue ref if also move'ing
dok-net Mar 23, 2020
81ceebd
Add assignment operators.
dok-net Jan 4, 2021
4fa0dbb
Example as performance test for Delegate vs. std::function
dok-net Jan 27, 2021
6b6dbee
Revert "Add assignment operators."
dok-net Jan 27, 2021
099fc86
Re-apply std::forwards and minor identifier rename.
dok-net Jan 27, 2021
0fd063c
More hints for proper use of Delegate to optimize performance.
dok-net Jan 27, 2021
66d1704
Apply astyle
dok-net Jan 27, 2021
6aa1102
Added preprocessor define NODELEGATE. Use it for side-by-side compari…
dok-net Jan 28, 2021
9644606
Field padding improved
dok-net Jan 30, 2021
8e75ef9
Remove the now-deprecated ICACHE_RAM_ATTR.
dok-net Mar 15, 2021
12c27a4
Ticker ported to Delegate
dok-net Dec 17, 2019
c55ffe6
std::bind is IRAM cache safe, but lambdas are not.
dok-net Jan 22, 2020
1878d6f
Review has proven that Ticker callbacks are documented to occur in SY…
dok-net Apr 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,130 changes: 2,130 additions & 0 deletions cores/esp8266/Delegate.h

Large diffs are not rendered by default.

567 changes: 567 additions & 0 deletions cores/esp8266/MultiDelegate.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ class ExampleClass {
public:
ExampleClass(int pin, int duration) : _pin(pin), _duration(duration) {
pinMode(_pin, OUTPUT);
_myTicker.attach_ms(_duration, std::bind(&ExampleClass::classBlink, this));
_myTicker.attach_ms(_duration, [this]() {
classBlink();
});
}
~ExampleClass() {};

Expand Down Expand Up @@ -52,7 +54,7 @@ void setup() {
scheduledTicker.attach_ms_scheduled(100, scheduledBlink);

pinMode(LED4, OUTPUT);
parameterTicker.attach_ms(100, std::bind(parameterBlink, LED4));
parameterTicker.attach_ms(100, parameterBlink, LED4);

pinMode(LED5, OUTPUT);
lambdaTicker.attach_ms(100, []() {
Expand Down
12 changes: 2 additions & 10 deletions libraries/Ticker/src/Ticker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Ticker::~Ticker()
detach();
}

void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg)
void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t* callback, void* arg)
{
if (_timer)
{
Expand All @@ -43,7 +43,6 @@ void Ticker::_attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t
{
_timer = &_etsTimer;
}

os_timer_setfn(_timer, callback, arg);
os_timer_arm(_timer, milliseconds, repeat);
}
Expand All @@ -55,17 +54,10 @@ void Ticker::detach()

os_timer_disarm(_timer);
_timer = nullptr;
_callback_function = nullptr;
_callback = nullptr;
}

bool Ticker::active() const
{
return _timer;
}

void Ticker::_static_callback(void* arg)
{
Ticker* _this = reinterpret_cast<Ticker*>(arg);
if (_this && _this->_callback_function)
_this->_callback_function();
}
77 changes: 36 additions & 41 deletions libraries/Ticker/src/Ticker.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#ifndef TICKER_H
#define TICKER_H

#include <functional>
#include <Delegate.h>
#include <Schedule.h>
#include <ets_sys.h>

Expand All @@ -32,42 +32,42 @@ class Ticker
Ticker();
~Ticker();

typedef void (*callback_with_arg_t)(void*);
typedef std::function<void(void)> callback_function_t;
using callback_t = Delegate<void(), void*>;
using callback_with_arg_t = void(void*);

// callback will be called at following loop() after ticker fires
void attach_scheduled(float seconds, callback_function_t callback)
void attach_scheduled(float seconds, callback_t callback)
{
_callback_function = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, true);
_callback = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, true, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
void attach(float seconds, callback_function_t callback)
void attach(float seconds, callback_t callback)
{
_callback_function = std::move(callback);
_attach_ms(1000UL * seconds, true);
_callback = std::move(callback);
_attach_ms(1000UL * seconds, true, _callback, _callback.arg());
}

// callback will be called at following loop() after ticker fires
void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
void attach_ms_scheduled(uint32_t milliseconds, callback_t callback)
{
_callback_function = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, true);
_callback = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, true, _callback, _callback.arg());
}

// callback will be called at following yield() after ticker fires
void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_function_t callback)
void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_t callback)
{
_callback_function = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); };
_attach_ms(milliseconds, true);
_callback = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); };
_attach_ms(milliseconds, true, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
void attach_ms(uint32_t milliseconds, callback_function_t callback)
void attach_ms(uint32_t milliseconds, callback_t callback)
{
_callback_function = std::move(callback);
_attach_ms(milliseconds, true);
_callback = std::move(callback);
_attach_ms(milliseconds, true, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
Expand All @@ -77,7 +77,7 @@ class Ticker
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_ms(1000UL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(1000UL * seconds, true, reinterpret_cast<callback_with_arg_t*>(callback), reinterpret_cast<void*>(arg));
#pragma GCC diagnostic pop
}

Expand All @@ -88,67 +88,62 @@ class Ticker
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t*>(callback), reinterpret_cast<void*>(arg));
#pragma GCC diagnostic pop
}

// callback will be called at following loop() after ticker fires
void once_scheduled(float seconds, callback_function_t callback)
void once_scheduled(float seconds, callback_t callback)
{
_callback_function = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, false);
_callback = [callback]() { schedule_function(callback); };
_attach_ms(1000UL * seconds, false, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
void once(float seconds, callback_function_t callback)
void once(float seconds, callback_t callback)
{
_callback_function = std::move(callback);
_attach_ms(1000UL * seconds, false);
_callback = std::move(callback);
_attach_ms(1000UL * seconds, false, _callback, _callback.arg());
}

// callback will be called at following loop() after ticker fires
void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
void once_ms_scheduled(uint32_t milliseconds, callback_t callback)
{
_callback_function = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, false);
_callback = [callback]() { schedule_function(callback); };
_attach_ms(milliseconds, false, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
void once_ms(uint32_t milliseconds, callback_function_t callback)
void once_ms(uint32_t milliseconds, callback_t callback)
{
_callback_function = std::move(callback);
_attach_ms(milliseconds, false);
_callback = std::move(callback);
_attach_ms(milliseconds, false, _callback, _callback.arg());
}

// callback will be called in SYS ctx when ticker fires
template<typename TArg>
void once(float seconds, void (*callback)(TArg), TArg arg)
{
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_ms(1000UL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(1000UL * seconds, false, reinterpret_cast<callback_with_arg_t*>(callback), reinterpret_cast<void*>(arg));
}

// callback will be called in SYS ctx when ticker fires
template<typename TArg>
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
{
static_assert(sizeof(TArg) <= sizeof(void*), "attach() callback argument size must be <= sizeof(void*)");
_attach_ms(milliseconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
_attach_ms(milliseconds, false, reinterpret_cast<callback_with_arg_t*>(callback), reinterpret_cast<void*>(arg));
}

void detach();
bool active() const;

protected:
static void _static_callback(void* arg);
void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, void* arg);
void _attach_ms(uint32_t milliseconds, bool repeat)
{
_attach_ms(milliseconds, repeat, _static_callback, this);
}
void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t* callback, void* arg);

ETSTimer* _timer;
callback_function_t _callback_function = nullptr;
callback_t _callback = nullptr;

private:
ETSTimer _etsTimer;
Expand Down
Loading