66#include " interrupts.h"
77#include " coredecls.h"
88
9- typedef std::function<bool (void )> mFuncT ;
10-
9+ typedef std::function<void (void )> mSchedFuncT ;
1110struct scheduled_fn_t
1211{
1312 scheduled_fn_t * mNext = nullptr ;
14- mFuncT mFunc ;
15- esp8266::polledTimeout::periodicFastUs callNow;
16- schedule_e policy;
17-
18- scheduled_fn_t () : callNow(esp8266::polledTimeout::periodicFastUs::alwaysExpired) { }
13+ mSchedFuncT mFunc ;
1914};
2015
2116static scheduled_fn_t * sFirst = nullptr ;
2217static scheduled_fn_t * sLast = nullptr ;
2318static scheduled_fn_t * sUnused = nullptr ;
2419static int sCount = 0 ;
2520
21+ typedef std::function<bool (void )> mRecFuncT ;
22+ struct recurrent_fn_t
23+ {
24+ recurrent_fn_t * mNext = nullptr ;
25+ mRecFuncT mFunc ;
26+ esp8266::polledTimeout::periodicFastUs callNow;
27+ recurrent_fn_t (esp8266::polledTimeout::periodicFastUs interval): callNow(interval) { }
28+ };
29+
30+ static recurrent_fn_t * rFirst = nullptr ; // fifo not needed
31+
32+ // Returns a pointer to an unused sched_fn_t,
33+ // or if none are available allocates a new one,
34+ // or nullptr if limit is reached
2635IRAM_ATTR // called from ISR
27- static scheduled_fn_t * get_fn_unsafe ()
36+ static scheduled_fn_t * get_fn_unsafe ()
2837{
2938 scheduled_fn_t * result = nullptr ;
3039 // try to get an item from unused items list
@@ -33,38 +42,33 @@ static scheduled_fn_t* get_fn_unsafe()
3342 result = sUnused ;
3443 sUnused = sUnused ->mNext ;
3544 result->mNext = nullptr ;
36- result->callNow .reset (esp8266::polledTimeout::periodicFastUs::alwaysExpired);
3745 }
3846 // if no unused items, and count not too high, allocate a new one
3947 else if (sCount < SCHEDULED_FN_MAX_COUNT)
4048 {
41- result = new scheduled_fn_t ;
42- ++sCount ;
49+ result = (scheduled_fn_t *)malloc (sizeof (scheduled_fn_t ));
50+ if (result)
51+ ++sCount ;
4352 }
4453 return result;
4554}
4655
47- static void recycle_fn_unsafe (scheduled_fn_t * fn)
56+ static void recycle_fn_unsafe (scheduled_fn_t * fn)
4857{
4958 fn->mFunc = nullptr ; // special overload in c++ std lib
5059 fn->mNext = sUnused ;
5160 sUnused = fn;
5261}
5362
5463IRAM_ATTR // (not only) called from ISR
55- bool schedule_function_us ( std::function<bool (void )>&& fn, uint32_t repeat_us, schedule_e policy )
64+ bool schedule_function ( const std::function<void (void )>& fn)
5665{
57- assert (repeat_us < decltype (scheduled_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
58-
5966 esp8266::InterruptLock lockAllInterruptsInThisScope;
6067
6168 scheduled_fn_t * item = get_fn_unsafe ();
6269 if (!item)
6370 return false ;
6471
65- if (repeat_us)
66- item->callNow .reset (repeat_us);
67- item->policy = policy;
6872 item->mFunc = fn;
6973
7074 if (sFirst )
@@ -76,88 +80,110 @@ bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us, sc
7680 return true ;
7781}
7882
79- IRAM_ATTR // (not only) called from ISR
80- bool schedule_function_us (const std::function<bool (void )>& fn, uint32_t repeat_us, schedule_e policy)
83+ bool schedule_recurrent_function_us (const std::function<bool (void )>& fn, uint32_t repeat_us)
8184{
82- return schedule_function_us (std::function<bool (void )>(fn), repeat_us, policy);
83- }
85+ assert (repeat_us < decltype (recurrent_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
8486
85- IRAM_ATTR // called from ISR
86- bool schedule_function (std::function<void (void )>&& fn, schedule_e policy)
87- {
88- return schedule_function_us ([fn]() { fn (); return false ; }, 0 , policy);
87+ esp8266::InterruptLock lockAllInterruptsInThisScope;
88+
89+ recurrent_fn_t * item = new recurrent_fn_t (repeat_us);
90+ if (!item)
91+ return false ;
92+
93+ item->mFunc = fn;
94+
95+ if (rFirst)
96+ {
97+ item->mNext = rFirst;
98+ rFirst = item;
99+ }
100+ else
101+ rFirst = item;
102+
103+ return true ;
89104}
90105
91- IRAM_ATTR // called from ISR
92- bool schedule_function (const std::function<void (void )>& fn, schedule_e policy)
106+ void run_scheduled_functions ()
93107{
94- return schedule_function (std::function<void (void )>(fn), policy);
108+ esp8266::polledTimeout::periodicFastMs yieldNow (100 ); // yield every 100ms
109+
110+ while (sFirst )
111+ {
112+ sFirst ->mFunc ();
113+
114+ {
115+ esp8266::InterruptLock lockAllInterruptsInThisScope;
116+
117+ auto to_recycle = sFirst ;
118+ sFirst = sFirst ->mNext ;
119+ if (!sFirst )
120+ sLast = nullptr ;
121+ recycle_fn_unsafe (to_recycle);
122+ }
123+
124+ if (yieldNow)
125+ {
126+ // because scheduled function are allowed to last:
127+ // this is yield() in cont stack:
128+ esp_schedule ();
129+ cont_yield (g_pcont);
130+ }
131+ }
95132}
96133
97- void run_scheduled_functions (schedule_e policy )
134+ void run_scheduled_recurrent_functions ( )
98135{
99136 // Note to the reader:
100137 // There is no exposed API to remove a scheduled function:
101138 // Scheduled functions are removed only from this function, and
102139 // its purpose is that it is never called from an interrupt
103140 // (always on cont stack).
104141
142+ if (!rFirst)
143+ return ;
144+
105145 static bool fence = false ;
106146 {
107- esp8266::InterruptLock lockAllInterruptsInThisScope;
147+ // fence is like a mutex but as we are never called from ISR,
148+ // locking is useless here. Leaving comment for reference.
149+ // esp8266::InterruptLock lockAllInterruptsInThisScope;
150+
108151 if (fence)
109152 // prevent recursive calls from yield()
153+ // (even if they are not allowed)
110154 return ;
111155 fence = true ;
112156 }
113157
114- esp8266::polledTimeout::periodicFastMs yieldNow ( 100 ); // yield every 100ms
115- scheduled_fn_t * lastRecurring = nullptr ;
116- scheduled_fn_t * nextCall = sFirst ;
117- while (nextCall )
158+ recurrent_fn_t * prev = nullptr ;
159+ recurrent_fn_t * current = rFirst ;
160+
161+ while (current )
118162 {
119- scheduled_fn_t * toCall = nextCall;
120- nextCall = nextCall->mNext ;
121-
122- // run scheduled function:
123- // - when its schedule policy allows it anytime
124- // - or if we are called at loop() time
125- // and
126- // - its time policy allows it
127- if ( ( toCall->policy == SCHEDULED_FUNCTION_WITHOUT_YIELDELAYCALLS
128- || policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP)
129- && toCall->callNow )
163+ if (current->callNow && !current->mFunc ())
130164 {
131- if (toCall->mFunc ())
165+ // remove function from stack
166+ esp8266::InterruptLock lockAllInterruptsInThisScope;
167+
168+ auto to_ditch = current;
169+
170+ if (prev)
132171 {
133- // function stays in list
134- lastRecurring = toCall ;
172+ current = current-> mNext ;
173+ prev-> mNext = current ;
135174 }
136175 else
137176 {
138- // function removed from list
139- esp8266::InterruptLock lockAllInterruptsInThisScope;
140-
141- if (sFirst == toCall)
142- sFirst = sFirst ->mNext ;
143- else if (lastRecurring)
144- lastRecurring->mNext = toCall->mNext ;
145-
146- if (sLast == toCall)
147- sLast = lastRecurring;
148-
149- recycle_fn_unsafe (toCall);
177+ rFirst = rFirst->mNext ;
178+ current = rFirst;
150179 }
180+
181+ delete (to_ditch);
151182 }
152183 else
153- // function stays in list
154- lastRecurring = toCall;
155-
156- if (policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP && yieldNow)
157184 {
158- // this is yield() in cont stack:
159- esp_schedule ();
160- cont_yield (g_pcont);
185+ prev = current;
186+ current = current->mNext ;
161187 }
162188 }
163189
0 commit comments