Skip to content

Commit 641c5cd

Browse files
hreintkedevyte
authored andcommitted
Scheduled Interrupt (#4609)
* Scheduled Interrupt * use capital letter for Schedule.h * Prevent memory leak when attach is called multiple times without detach * Add improved schedule_function * WIP : Integrate FunctionalInterrupt & ScheduledInterrupt * Fix travis error
1 parent 91bb97d commit 641c5cd

5 files changed

+272
-8
lines changed

cores/esp8266/FunctionalInterrupt.cpp

+53-7
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,70 @@
11
#include <FunctionalInterrupt.h>
2-
2+
#include <Schedule.h>
3+
#include "Arduino.h"
4+
#include <ScheduledFunctions.h>
35

46
// Duplicate typedefs from core_esp8266_wiring_digital_c
57
typedef void (*voidFuncPtr)(void);
8+
typedef void (*voidFuncPtrArg)(void*);
69

710
// Helper functions for Functional interrupt routines
811
extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode);
912

10-
// Structure for communication
11-
struct ArgStructure {
12-
std::function<void(void)> reqFunction;
13-
};
1413

1514
void interruptFunctional(void* arg)
1615
{
17-
((ArgStructure*)arg)->reqFunction();
16+
ArgStructure* localArg = (ArgStructure*)arg;
17+
if (localArg->functionInfo->reqScheduledFunction)
18+
{
19+
scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true);
20+
}
21+
if (localArg->functionInfo->reqFunction)
22+
{
23+
localArg->functionInfo->reqFunction();
24+
}
25+
}
26+
27+
extern "C"
28+
{
29+
void cleanupFunctional(void* arg)
30+
{
31+
ArgStructure* localArg = (ArgStructure*)arg;
32+
delete (FunctionInfo*)localArg->functionInfo;
33+
delete (InterruptInfo*)localArg->interruptInfo;
34+
delete localArg;
35+
}
1836
}
1937

2038
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
2139
{
2240
// use the local interrupt routine which takes the ArgStructure as argument
23-
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, new ArgStructure{intRoutine}, mode);
41+
42+
InterruptInfo* ii = nullptr;
43+
44+
FunctionInfo* fi = new FunctionInfo;
45+
fi->reqFunction = intRoutine;
46+
47+
ArgStructure* as = new ArgStructure;
48+
as->interruptInfo = ii;
49+
as->functionInfo = fi;
50+
51+
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
52+
}
53+
54+
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
55+
{
56+
if (!scheduledInterrupts)
57+
{
58+
scheduledInterrupts = new ScheduledFunctions(32);
59+
}
60+
InterruptInfo* ii = new InterruptInfo;
61+
62+
FunctionInfo* fi = new FunctionInfo;
63+
fi->reqScheduledFunction = scheduledIntRoutine;
64+
65+
ArgStructure* as = new ArgStructure;
66+
as->interruptInfo = ii;
67+
as->functionInfo = fi;
68+
69+
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
2470
}

cores/esp8266/FunctionalInterrupt.h

+22
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,34 @@
44
#include <stddef.h>
55
#include <stdint.h>
66
#include <functional>
7+
#include <ScheduledFunctions.h>
78

89
extern "C" {
910
#include "c_types.h"
1011
#include "ets_sys.h"
1112
}
1213

14+
// Structures for communication
15+
16+
struct InterruptInfo {
17+
uint8_t pin = 0;
18+
uint8_t value = 0;
19+
uint32_t micro = 0;
20+
};
21+
22+
struct FunctionInfo {
23+
std::function<void(void)> reqFunction = nullptr;
24+
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
25+
};
26+
27+
struct ArgStructure {
28+
InterruptInfo* interruptInfo = nullptr;
29+
FunctionInfo* functionInfo = nullptr;
30+
};
31+
32+
static ScheduledFunctions* scheduledInterrupts;
1333
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+
1436

1537
#endif //INTERRUPTS_H

cores/esp8266/ScheduledFunctions.cpp

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* ScheduledFunctions.cpp
3+
*
4+
* Created on: 27 apr. 2018
5+
* Author: Herman
6+
*/
7+
#include "ScheduledFunctions.h"
8+
9+
std::list<ScheduledFunctions::ScheduledElement> ScheduledFunctions::scheduledFunctions;
10+
11+
ScheduledFunctions::ScheduledFunctions()
12+
:ScheduledFunctions(UINT_MAX)
13+
{
14+
}
15+
16+
ScheduledFunctions::ScheduledFunctions(unsigned int reqMax)
17+
{
18+
maxElements = reqMax;
19+
}
20+
21+
ScheduledFunctions::~ScheduledFunctions() {
22+
}
23+
24+
ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front)
25+
{
26+
if (countElements >= maxElements)
27+
{
28+
return nullptr;
29+
}
30+
else
31+
{
32+
countElements++;
33+
if (front)
34+
{
35+
scheduledFunctions.push_front(se);
36+
return scheduledFunctions.begin()->registration;
37+
}
38+
else
39+
{
40+
scheduledFunctions.push_back(se);
41+
return scheduledFunctions.rbegin()->registration;
42+
}
43+
}
44+
}
45+
46+
std::list<ScheduledFunctions::ScheduledElement>::iterator ScheduledFunctions::eraseElement(std::list<ScheduledFunctions::ScheduledElement>::iterator it)
47+
{
48+
countElements--;
49+
return scheduledFunctions.erase(it);
50+
}
51+
52+
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front)
53+
{
54+
return (insertElement({this,continuous,nullptr,sf}, front) == nullptr);
55+
}
56+
57+
bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf)
58+
{
59+
return scheduleFunction(sf, false, false);
60+
}
61+
62+
ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front)
63+
{
64+
return insertElement({this,continuous,std::make_shared<int>(1),sf},front);
65+
}
66+
67+
void ScheduledFunctions::runScheduledFunctions()
68+
{
69+
auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions
70+
auto it = scheduledFunctions.begin();
71+
while (it != lastElement)
72+
{
73+
bool erase = false;
74+
if (it->registration == nullptr)
75+
{
76+
it->function();
77+
}
78+
else
79+
{
80+
if (it->registration.use_count() > 1)
81+
{
82+
it->function();
83+
}
84+
else
85+
{
86+
erase = true;
87+
}
88+
}
89+
if ((!it->continuous) || (erase))
90+
{
91+
it = it->_this->eraseElement(it);
92+
}
93+
else
94+
{
95+
it++;
96+
}
97+
}
98+
}
99+
100+
void ScheduledFunctions::removeFunction(ScheduledRegistration sr)
101+
{
102+
auto it = scheduledFunctions.begin();
103+
bool removed = false;
104+
while ((!removed) && (it != scheduledFunctions.end()))
105+
{
106+
if (it->registration == sr)
107+
{
108+
it = eraseElement(it);
109+
removed = true;
110+
}
111+
else
112+
{
113+
it++;
114+
}
115+
}
116+
}
117+

cores/esp8266/ScheduledFunctions.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* ScheduledFunctions.h
3+
*
4+
* Created on: 27 apr. 2018
5+
* Author: Herman
6+
*/
7+
#include "Arduino.h"
8+
#include "Schedule.h"
9+
10+
#include <functional>
11+
#include <memory>
12+
#include <list>
13+
#include <climits>
14+
15+
#ifndef SCHEDULEDFUNCTIONS_H_
16+
#define SCHEDULEDFUNCTIONS_H_
17+
18+
typedef std::function<void(void)> ScheduledFunction;
19+
typedef std::shared_ptr<void> ScheduledRegistration;
20+
21+
class ScheduledFunctions {
22+
23+
public:
24+
ScheduledFunctions();
25+
ScheduledFunctions(unsigned int reqMax);
26+
virtual ~ScheduledFunctions();
27+
28+
struct ScheduledElement
29+
{
30+
ScheduledFunctions* _this;
31+
bool continuous;
32+
ScheduledRegistration registration;
33+
ScheduledFunction function;
34+
};
35+
36+
ScheduledRegistration insertElement(ScheduledElement se, bool front);
37+
std::list<ScheduledElement>::iterator eraseElement(std::list<ScheduledElement>::iterator);
38+
bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front);
39+
bool scheduleFunction(ScheduledFunction sf);
40+
ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front);
41+
static void runScheduledFunctions();
42+
void removeFunction(ScheduledRegistration sr);
43+
44+
45+
static std::list<ScheduledElement> scheduledFunctions;
46+
unsigned int maxElements;
47+
unsigned int countElements = 0;
48+
49+
};
50+
51+
#endif /* SCHEDULEDFUNCTIONS_H_ */

cores/esp8266/core_esp8266_wiring_digital.c

+29-1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ typedef struct {
112112
void * arg;
113113
} interrupt_handler_t;
114114

115+
//duplicate from functionalInterrupt.h keep in sync
116+
typedef struct InterruptInfo {
117+
uint8_t pin;
118+
uint8_t value;
119+
uint32_t micro;
120+
} InterruptInfo;
121+
122+
typedef struct {
123+
InterruptInfo* interruptInfo;
124+
void* functionInfo;
125+
} ArgStructure;
115126

116127
static interrupt_handler_t interrupt_handlers[16];
117128
static uint32_t interrupt_reg = 0;
@@ -134,7 +145,14 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
134145
(handler->mode & 1) == !!(levels & (1 << i)))) {
135146
// to make ISR compatible to Arduino AVR model where interrupts are disabled
136147
// we disable them before we call the client ISR
137-
uint32_t savedPS = xt_rsil(15); // stop other interrupts
148+
uint32_t savedPS = xt_rsil(15); // stop other interrupts
149+
ArgStructure* localArg = (ArgStructure*)handler->arg;
150+
if (localArg->interruptInfo)
151+
{
152+
localArg->interruptInfo->pin = i;
153+
localArg->interruptInfo->value = __digitalRead(i);
154+
localArg->interruptInfo->micro = micros();
155+
}
138156
if (handler->arg)
139157
{
140158
((voidFuncPtrArg)handler->fn)(handler->arg);
@@ -149,12 +167,18 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
149167
ETS_GPIO_INTR_ENABLE();
150168
}
151169

170+
extern void cleanupFunctional(void* arg);
171+
152172
extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
153173
if(pin < 16) {
154174
ETS_GPIO_INTR_DISABLE();
155175
interrupt_handler_t *handler = &interrupt_handlers[pin];
156176
handler->mode = mode;
157177
handler->fn = userFunc;
178+
if (handler->arg) // Clean when new attach without detach
179+
{
180+
cleanupFunctional(handler->arg);
181+
}
158182
handler->arg = arg;
159183
interrupt_reg |= (1 << pin);
160184
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
@@ -179,6 +203,10 @@ extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
179203
interrupt_handler_t *handler = &interrupt_handlers[pin];
180204
handler->mode = 0;
181205
handler->fn = 0;
206+
if (handler->arg)
207+
{
208+
cleanupFunctional(handler->arg);
209+
}
182210
handler->arg = 0;
183211
if (interrupt_reg)
184212
ETS_GPIO_INTR_ENABLE();

0 commit comments

Comments
 (0)