6
6
#include " interrupts.h"
7
7
#include " coredecls.h"
8
8
9
- typedef std::function<bool (void )> mFuncT ;
9
+ typedef std::function<void (void )> mSchedFuncT ;
10
+ typedef std::function<bool (void )> mRecFuncT ;
10
11
11
12
struct scheduled_fn_t
12
13
{
13
14
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) { }
15
+ mSchedFuncT mFunc ;
19
16
};
20
17
21
18
static scheduled_fn_t * sFirst = nullptr ;
22
19
static scheduled_fn_t * sLast = nullptr ;
23
20
static scheduled_fn_t * sUnused = nullptr ;
24
21
static int sCount = 0 ;
25
22
23
+ struct recurrent_fn_t
24
+ {
25
+ recurrent_fn_t * mNext = nullptr ;
26
+ mRecFuncT mFunc ;
27
+ esp8266::polledTimeout::periodicFastUs callNow;
28
+ recurrent_fn_t (esp8266::polledTimeout::periodicFastUs interval) : callNow(interval) { }
29
+ };
30
+
31
+ static recurrent_fn_t * rFirst = nullptr ; // stack, fifo not needed
32
+
26
33
IRAM_ATTR // called from ISR
27
34
static scheduled_fn_t * get_fn_unsafe ()
28
35
{
@@ -33,7 +40,6 @@ static scheduled_fn_t* get_fn_unsafe()
33
40
result = sUnused ;
34
41
sUnused = sUnused ->mNext ;
35
42
result->mNext = nullptr ;
36
- result->callNow .reset (esp8266::polledTimeout::periodicFastUs::alwaysExpired);
37
43
}
38
44
// if no unused items, and count not too high, allocate a new one
39
45
else if (sCount < SCHEDULED_FN_MAX_COUNT)
@@ -52,19 +58,14 @@ static void recycle_fn_unsafe(scheduled_fn_t* fn)
52
58
}
53
59
54
60
IRAM_ATTR // (not only) called from ISR
55
- bool schedule_function_us (std::function<bool (void )>&& fn, uint32_t repeat_us, schedule_e policy )
61
+ bool schedule_function_us (std::function<void (void )>&& fn)
56
62
{
57
- assert (repeat_us < decltype (scheduled_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
58
-
59
63
InterruptLock lockAllInterruptsInThisScope;
60
64
61
65
scheduled_fn_t * item = get_fn_unsafe ();
62
66
if (!item)
63
67
return false ;
64
68
65
- if (repeat_us)
66
- item->callNow .reset (repeat_us);
67
- item->policy = policy;
68
69
item->mFunc = fn;
69
70
70
71
if (sFirst )
@@ -76,90 +77,106 @@ bool schedule_function_us(std::function<bool(void)>&& fn, uint32_t repeat_us, sc
76
77
return true ;
77
78
}
78
79
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 )
80
+ IRAM_ATTR // called from ISR
81
+ bool schedule_function (const std::function<void (void )>& fn)
81
82
{
82
- return schedule_function_us (std::function<bool (void )>(fn), repeat_us, policy );
83
+ return schedule_function (std::function<void (void )>(fn));
83
84
}
84
85
85
- IRAM_ATTR // called from ISR
86
- bool schedule_function (std::function<void (void )>&& fn, schedule_e policy )
86
+ IRAM_ATTR // (not only) called from ISR
87
+ bool schedule_recurrent_function_us (std::function<bool (void )>&& fn, uint32_t repeat_us )
87
88
{
88
- return schedule_function_us ([fn]() { fn (); return false ; }, 0 , policy);
89
+ assert (repeat_us < decltype (recurrent_fn_t ::callNow)::neverExpires); // ~26800000us (26.8s)
90
+
91
+ InterruptLock lockAllInterruptsInThisScope;
92
+
93
+ recurrent_fn_t * item = new recurrent_fn_t (repeat_us);
94
+ if (!item)
95
+ return false ;
96
+
97
+ item->mFunc = fn;
98
+
99
+ if (rFirst)
100
+ {
101
+ item->mNext = rFirst;
102
+ rFirst = item;
103
+ }
104
+ else
105
+ rFirst = item;
106
+
107
+ return true ;
89
108
}
90
109
91
- IRAM_ATTR // called from ISR
92
- bool schedule_function (const std::function<void (void )>& fn, schedule_e policy)
110
+ void run_scheduled_functions ()
93
111
{
94
- return schedule_function (std::function<void (void )>(fn), policy);
112
+ esp8266::polledTimeout::periodicFastMs yieldNow (100 ); // yield every 100ms
113
+
114
+ while (sFirst )
115
+ {
116
+ sFirst ->mFunc ();
117
+
118
+ {
119
+ InterruptLock lockAllInterruptsInThisScope;
120
+
121
+ auto to_recycle = sFirst ;
122
+ sFirst = sFirst ->mNext ;
123
+ if (!sFirst )
124
+ sLast = nullptr ;
125
+ recycle_fn_unsafe (to_recycle);
126
+ }
127
+
128
+ if (yieldNow)
129
+ {
130
+ // because scheduled function are allowed to last:
131
+ // this is yield() in cont stack:
132
+ esp_schedule ();
133
+ cont_yield (g_pcont);
134
+ }
135
+ }
95
136
}
96
137
97
- void run_scheduled_functions (schedule_e policy )
138
+ void run_scheduled_recurrent_functions ( )
98
139
{
99
140
// Note to the reader:
100
141
// There is no exposed API to remove a scheduled function:
101
142
// Scheduled functions are removed only from this function, and
102
143
// its purpose is that it is never called from an interrupt
103
144
// (always on cont stack).
104
145
146
+ if (!rFirst)
147
+ return ;
148
+
105
149
static bool fence = false ;
106
150
{
107
151
InterruptLock lockAllInterruptsInThisScope;
108
152
if (fence)
109
153
// prevent recursive calls from yield()
154
+ // (even if they are not allowed)
110
155
return ;
111
156
fence = true ;
112
157
}
113
158
114
- esp8266::polledTimeout::periodicFastMs yieldNow (100 ); // yield every 100ms
115
- scheduled_fn_t * lastRecurring = nullptr ;
116
- scheduled_fn_t * nextCall = sFirst ;
117
- while (nextCall)
118
- {
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 )
130
- {
131
- if (toCall->mFunc ())
132
- {
133
- // function stays in list
134
- lastRecurring = toCall;
135
- }
136
- else
137
- {
138
- // function removed from list
139
- InterruptLock lockAllInterruptsInThisScope;
140
-
141
- if (sFirst == toCall)
142
- sFirst = sFirst ->mNext ;
143
- else if (lastRecurring)
144
- lastRecurring->mNext = toCall->mNext ;
159
+ recurrent_fn_t * prev = nullptr ;
160
+ recurrent_fn_t * current = rFirst;
145
161
146
- if (sLast == toCall)
147
- sLast = lastRecurring;
162
+ while (current)
163
+ if (current->callNow && !current->mFunc ())
164
+ {
165
+ // remove function from stack
166
+ InterruptLock lockAllInterruptsInThisScope;
148
167
149
- recycle_fn_unsafe (toCall);
150
- }
168
+ auto to_ditch = current;
169
+ if (prev)
170
+ prev->mNext = current = current->mNext ;
171
+ else
172
+ current = rFirst = rFirst->mNext ;
173
+ delete (to_ditch);
151
174
}
152
175
else
153
- // function stays in list
154
- lastRecurring = toCall;
155
-
156
- if (policy == SCHEDULED_FUNCTION_ONCE_PER_LOOP && yieldNow)
157
176
{
158
- // this is yield() in cont stack:
159
- esp_schedule ();
160
- cont_yield (g_pcont);
177
+ prev = current;
178
+ current = current->mNext ;
161
179
}
162
- }
163
180
164
181
fence = false ;
165
182
}
0 commit comments