Skip to content

Commit fb8e918

Browse files
committed
Bring back FunctionalInterrupt, and ScheduledFunctions from ESP8266, as example code.
It should be decided whether to reinstate these in the core, or make them an optional library.
1 parent 1923fd3 commit fb8e918

9 files changed

+445
-68
lines changed

libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp

Lines changed: 0 additions & 44 deletions
This file was deleted.

libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h

Lines changed: 0 additions & 20 deletions
This file was deleted.

libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
#include <Arduino.h>
2-
#include "FunctionalInterrupt.h"
2+
#include "FunctionalInterrupts.h"
33

4+
#if defined(ESP8266) || defined(ARDUINO_D1_MINI32)
5+
#define BUTTON1 D3
6+
#define BUTTON2 D4
7+
#else
48
#define BUTTON1 16
59
#define BUTTON2 17
10+
#endif
611

712
class Button
813
{
914
public:
10-
Button(uint8_t reqPin) : PIN(reqPin){
15+
Button(uint8_t reqPin) : PIN(reqPin) {
1116
pinMode(PIN, INPUT_PULLUP);
1217
attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING);
1318
};
1419
~Button() {
15-
detachInterrupt(PIN);
20+
detachFunctionalInterrupt(PIN);
1621
}
1722

18-
void IRAM_ATTR isr() {
23+
#if defined(ESP8266)
24+
void ICACHE_RAM_ATTR isr()
25+
#elif defined(ESP32)
26+
void IRAM_ATTR isr()
27+
#endif
28+
{
1929
numberKeyPresses += 1;
2030
pressed = true;
2131
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#include "FunctionalInterrupts.h"
2+
#include "Schedule.h"
3+
#include "Arduino.h"
4+
5+
#if defined(ESP8266)
6+
7+
// Duplicate typedefs from core_esp8266_wiring_digital.cpp
8+
// Keep in sync
9+
typedef void (*voidFuncPtr)(void);
10+
typedef void (*voidFuncPtrArg)(void*);
11+
12+
typedef struct {
13+
uint8_t mode;
14+
voidFuncPtr fn;
15+
void* arg;
16+
} interrupt_handler_t;
17+
18+
// Helper functions for Functional interrupt routines
19+
extern "C" interrupt_handler_t* __getInterruptHandler(uint8_t pin);
20+
21+
#elif defined(ESP32)
22+
23+
// Duplicate typedefs from esp32-hal-gpio.c
24+
// Keep in sync
25+
typedef void (*voidFuncPtr)(void);
26+
typedef void (*voidFuncPtrArg)(void*);
27+
typedef struct {
28+
voidFuncPtr fn;
29+
void* arg;
30+
} InterruptHandle_t;
31+
32+
// Helper functions for Functional interrupt routines
33+
extern "C" InterruptHandle_t* __getInterruptHandler(uint8_t pin);
34+
35+
#endif
36+
37+
void ICACHE_RAM_ATTR interruptFunctional(void* arg)
38+
{
39+
ArgStructure* localArg = static_cast<ArgStructure*>(arg);
40+
if (localArg->interruptInfo)
41+
{
42+
localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin);
43+
localArg->interruptInfo->micro = micros();
44+
}
45+
if (localArg->functionInfo->reqScheduledFunction)
46+
{
47+
schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))));
48+
}
49+
if (localArg->functionInfo->reqFunction)
50+
{
51+
localArg->functionInfo->reqFunction();
52+
}
53+
}
54+
55+
void cleanupFunctional(void* arg)
56+
{
57+
ArgStructure* localArg = static_cast<ArgStructure*>(arg);
58+
delete localArg;
59+
}
60+
61+
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
62+
{
63+
// use the local interrupt routine which takes the ArgStructure as argument
64+
65+
#if defined(ESP8266)
66+
interrupt_handler_t* handler = __getInterruptHandler(pin);
67+
#elif defined(ESP32)
68+
InterruptHandle_t* handler = __getInterruptHandler(pin);
69+
#endif
70+
if (handler->arg)
71+
{
72+
cleanupFunctional(handler->arg);
73+
}
74+
75+
FunctionInfo* fi = new FunctionInfo;
76+
fi->reqFunction = intRoutine;
77+
78+
ArgStructure* as = new ArgStructure;
79+
as->functionInfo = fi;
80+
81+
::attachInterruptArg (pin, static_cast<voidFuncPtrArg>(interruptFunctional), as, mode);
82+
}
83+
84+
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
85+
{
86+
#if defined(ESP8266)
87+
interrupt_handler_t* handler = __getInterruptHandler(pin);
88+
#elif defined(ESP32)
89+
InterruptHandle_t* handler = __getInterruptHandler(pin);
90+
#endif
91+
if (handler->arg)
92+
{
93+
cleanupFunctional(handler->arg);
94+
}
95+
96+
InterruptInfo* ii = new InterruptInfo(pin);
97+
98+
FunctionInfo* fi = new FunctionInfo;
99+
fi->reqScheduledFunction = scheduledIntRoutine;
100+
101+
ArgStructure* as = new ArgStructure;
102+
as->interruptInfo = ii;
103+
as->functionInfo = fi;
104+
105+
::attachInterruptArg (pin, static_cast<voidFuncPtrArg>(interruptFunctional), as, mode);
106+
}
107+
108+
void detachFunctionalInterrupt(uint8_t pin)
109+
{
110+
#if defined(ESP8266)
111+
interrupt_handler_t* handler = __getInterruptHandler(pin);
112+
#elif defined(ESP32)
113+
InterruptHandle_t* handler = __getInterruptHandler(pin);
114+
#endif
115+
if (handler->arg)
116+
{
117+
cleanupFunctional(handler->arg);
118+
}
119+
::detachInterrupt (pin);
120+
}
121+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef FUNCTIONALINTERRUPTS_H
2+
#define FUNCTIONALINTERRUPTS_H
3+
4+
#include <stddef.h>
5+
#include <stdint.h>
6+
#include <functional>
7+
#include "ScheduledFunctions.h"
8+
9+
// Structures for communication
10+
11+
struct InterruptInfo {
12+
InterruptInfo(uint8_t _pin) : pin(_pin) {}
13+
const uint8_t pin;
14+
uint8_t value = 0;
15+
uint32_t micro = 0;
16+
};
17+
18+
struct FunctionInfo {
19+
std::function<void(void)> reqFunction = nullptr;
20+
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
21+
};
22+
23+
struct ArgStructure {
24+
~ArgStructure()
25+
{
26+
delete functionInfo;
27+
delete interruptInfo;
28+
}
29+
InterruptInfo* interruptInfo = nullptr;
30+
FunctionInfo* functionInfo = nullptr;
31+
};
32+
33+
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
34+
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode);
35+
void detachFunctionalInterrupt(uint8_t pin);
36+
37+
#endif //INTERRUPTS_H
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "Schedule.h"
2+
3+
struct scheduled_fn_t
4+
{
5+
scheduled_fn_t* mNext;
6+
std::function<void(void)> mFunc;
7+
};
8+
9+
static scheduled_fn_t* sFirst = 0;
10+
static scheduled_fn_t* sLast = 0;
11+
12+
static scheduled_fn_t* sFirstUnused = 0;
13+
static scheduled_fn_t* sLastUnused = 0;
14+
15+
static int sCount = 0;
16+
17+
static scheduled_fn_t* get_fn() {
18+
scheduled_fn_t* result = NULL;
19+
// try to get an item from unused items list
20+
if (sFirstUnused) {
21+
result = sFirstUnused;
22+
sFirstUnused = result->mNext;
23+
if (sFirstUnused == NULL) {
24+
sLastUnused = NULL;
25+
}
26+
}
27+
// if no unused items, and count not too high, allocate a new one
28+
else if (sCount != SCHEDULED_FN_MAX_COUNT) {
29+
result = new scheduled_fn_t;
30+
result->mNext = NULL;
31+
++sCount;
32+
}
33+
return result;
34+
}
35+
36+
static void recycle_fn(scheduled_fn_t* fn)
37+
{
38+
if (!sLastUnused) {
39+
sFirstUnused = fn;
40+
}
41+
else {
42+
sLastUnused->mNext = fn;
43+
}
44+
fn->mNext = NULL;
45+
sLastUnused = fn;
46+
}
47+
48+
bool schedule_function(std::function<void(void)> fn)
49+
{
50+
scheduled_fn_t* item = get_fn();
51+
if (!item) {
52+
return false;
53+
}
54+
item->mFunc = fn;
55+
item->mNext = NULL;
56+
if (!sFirst) {
57+
sFirst = item;
58+
}
59+
else {
60+
sLast->mNext = item;
61+
}
62+
sLast = item;
63+
return true;
64+
}
65+
66+
void run_scheduled_functions()
67+
{
68+
scheduled_fn_t* rFirst = sFirst;
69+
sFirst = NULL;
70+
sLast = NULL;
71+
while (rFirst) {
72+
scheduled_fn_t* item = rFirst;
73+
rFirst = item->mNext;
74+
item->mFunc();
75+
item->mFunc = std::function<void(void)>();
76+
recycle_fn(item);
77+
}
78+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef ESP_SCHEDULE_H
2+
#define ESP_SCHEDULE_H
3+
4+
#include <functional>
5+
6+
#define SCHEDULED_FN_MAX_COUNT 32
7+
#define SCHEDULED_FN_INITIAL_COUNT 4
8+
9+
// Warning
10+
// This API is not considered stable.
11+
// Function signatures will change.
12+
// You have been warned.
13+
14+
// Run given function next time `loop` function returns,
15+
// or `run_scheduled_functions` is called.
16+
// Use std::bind to pass arguments to a function, or call a class member function.
17+
// Note: there is no mechanism for cancelling scheduled functions.
18+
// Keep that in mind when binding functions to objects which may have short lifetime.
19+
// Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT.
20+
bool schedule_function(std::function<void(void)> fn);
21+
22+
// Run all scheduled functions.
23+
// Use this function if your are not using `loop`, or `loop` does not return
24+
// on a regular basis.
25+
void run_scheduled_functions();
26+
27+
#endif //ESP_SCHEDULE_H

0 commit comments

Comments
 (0)