Skip to content
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

Scheduled Interrupt #4609

Merged
merged 10 commits into from
Jun 19, 2018
60 changes: 53 additions & 7 deletions cores/esp8266/FunctionalInterrupt.cpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,70 @@
#include <FunctionalInterrupt.h>

#include <Schedule.h>
#include "Arduino.h"
#include <ScheduledFunctions.h>

// Duplicate typedefs from core_esp8266_wiring_digital_c
typedef void (*voidFuncPtr)(void);
typedef void (*voidFuncPtrArg)(void*);

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

// Structure for communication
struct ArgStructure {
std::function<void(void)> reqFunction;
};

void interruptFunctional(void* arg)
{
((ArgStructure*)arg)->reqFunction();
ArgStructure* localArg = (ArgStructure*)arg;
if (localArg->functionInfo->reqScheduledFunction)
{
scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true);
}
if (localArg->functionInfo->reqFunction)
{
localArg->functionInfo->reqFunction();
}
}

extern "C"
{
void cleanupFunctional(void* arg)
{
ArgStructure* localArg = (ArgStructure*)arg;
delete (FunctionInfo*)localArg->functionInfo;
delete (InterruptInfo*)localArg->interruptInfo;
delete localArg;
}
}

void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
{
// use the local interrupt routine which takes the ArgStructure as argument
__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, new ArgStructure{intRoutine}, mode);

InterruptInfo* ii = nullptr;

FunctionInfo* fi = new FunctionInfo;
fi->reqFunction = intRoutine;

ArgStructure* as = new ArgStructure;
as->interruptInfo = ii;
as->functionInfo = fi;

__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
}

void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode)
{
if (!scheduledInterrupts)
{
scheduledInterrupts = new ScheduledFunctions(32);
}
InterruptInfo* ii = new InterruptInfo;

FunctionInfo* fi = new FunctionInfo;
fi->reqScheduledFunction = scheduledIntRoutine;

ArgStructure* as = new ArgStructure;
as->interruptInfo = ii;
as->functionInfo = fi;

__attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode);
}
22 changes: 22 additions & 0 deletions cores/esp8266/FunctionalInterrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,34 @@
#include <stddef.h>
#include <stdint.h>
#include <functional>
#include <ScheduledFunctions.h>

extern "C" {
#include "c_types.h"
#include "ets_sys.h"
}

// Structures for communication

struct InterruptInfo {
uint8_t pin = 0;
uint8_t value = 0;
uint32_t micro = 0;
};

struct FunctionInfo {
std::function<void(void)> reqFunction = nullptr;
std::function<void(InterruptInfo)> reqScheduledFunction = nullptr;
};

struct ArgStructure {
InterruptInfo* interruptInfo = nullptr;
FunctionInfo* functionInfo = nullptr;
};

static ScheduledFunctions* scheduledInterrupts;
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
void attachScheduledInterrupt(uint8_t pin, std::function<void(InterruptInfo)> scheduledIntRoutine, int mode);


#endif //INTERRUPTS_H
117 changes: 117 additions & 0 deletions cores/esp8266/ScheduledFunctions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* ScheduledFunctions.cpp
*
* Created on: 27 apr. 2018
* Author: Herman
*/
#include "ScheduledFunctions.h"

std::list<ScheduledFunctions::ScheduledElement> ScheduledFunctions::scheduledFunctions;

ScheduledFunctions::ScheduledFunctions()
:ScheduledFunctions(UINT_MAX)
{
}

ScheduledFunctions::ScheduledFunctions(unsigned int reqMax)
{
maxElements = reqMax;
}

ScheduledFunctions::~ScheduledFunctions() {
}

ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front)
{
if (countElements >= maxElements)
{
return nullptr;
}
else
{
countElements++;
if (front)
{
scheduledFunctions.push_front(se);
return scheduledFunctions.begin()->registration;
}
else
{
scheduledFunctions.push_back(se);
return scheduledFunctions.rbegin()->registration;
}
}
}

std::list<ScheduledFunctions::ScheduledElement>::iterator ScheduledFunctions::eraseElement(std::list<ScheduledFunctions::ScheduledElement>::iterator it)
{
countElements--;
return scheduledFunctions.erase(it);
}

bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front)
{
return (insertElement({this,continuous,nullptr,sf}, front) == nullptr);
}

bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf)
{
return scheduleFunction(sf, false, false);
}

ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front)
{
return insertElement({this,continuous,std::make_shared<int>(1),sf},front);
}

void ScheduledFunctions::runScheduledFunctions()
{
auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions
auto it = scheduledFunctions.begin();
while (it != lastElement)
{
bool erase = false;
if (it->registration == nullptr)
{
it->function();
}
else
{
if (it->registration.use_count() > 1)
{
it->function();
}
else
{
erase = true;
}
}
if ((!it->continuous) || (erase))
{
it = it->_this->eraseElement(it);
}
else
{
it++;
}
}
}

void ScheduledFunctions::removeFunction(ScheduledRegistration sr)
{
auto it = scheduledFunctions.begin();
bool removed = false;
while ((!removed) && (it != scheduledFunctions.end()))
{
if (it->registration == sr)
{
it = eraseElement(it);
removed = true;
}
else
{
it++;
}
}
}

51 changes: 51 additions & 0 deletions cores/esp8266/ScheduledFunctions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* ScheduledFunctions.h
*
* Created on: 27 apr. 2018
* Author: Herman
*/
#include "Arduino.h"
#include "Schedule.h"

#include <functional>
#include <memory>
#include <list>
#include <climits>

#ifndef SCHEDULEDFUNCTIONS_H_
#define SCHEDULEDFUNCTIONS_H_

typedef std::function<void(void)> ScheduledFunction;
typedef std::shared_ptr<void> ScheduledRegistration;

class ScheduledFunctions {

public:
ScheduledFunctions();
ScheduledFunctions(unsigned int reqMax);
virtual ~ScheduledFunctions();

struct ScheduledElement
{
ScheduledFunctions* _this;
bool continuous;
ScheduledRegistration registration;
ScheduledFunction function;
};

ScheduledRegistration insertElement(ScheduledElement se, bool front);
std::list<ScheduledElement>::iterator eraseElement(std::list<ScheduledElement>::iterator);
bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front);
bool scheduleFunction(ScheduledFunction sf);
ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front);
static void runScheduledFunctions();
void removeFunction(ScheduledRegistration sr);


static std::list<ScheduledElement> scheduledFunctions;
unsigned int maxElements;
unsigned int countElements = 0;

};

#endif /* SCHEDULEDFUNCTIONS_H_ */
30 changes: 29 additions & 1 deletion cores/esp8266/core_esp8266_wiring_digital.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ typedef struct {
void * arg;
} interrupt_handler_t;

//duplicate from functionalInterrupt.h keep in sync
typedef struct InterruptInfo {
uint8_t pin;
uint8_t value;
uint32_t micro;
} InterruptInfo;

typedef struct {
InterruptInfo* interruptInfo;
void* functionInfo;
} ArgStructure;

static interrupt_handler_t interrupt_handlers[16];
static uint32_t interrupt_reg = 0;
Expand All @@ -134,7 +145,14 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
(handler->mode & 1) == !!(levels & (1 << i)))) {
// to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts
uint32_t savedPS = xt_rsil(15); // stop other interrupts
ArgStructure* localArg = (ArgStructure*)handler->arg;
if (localArg->interruptInfo)
{
localArg->interruptInfo->pin = i;
localArg->interruptInfo->value = __digitalRead(i);
localArg->interruptInfo->micro = micros();
}
if (handler->arg)
{
((voidFuncPtrArg)handler->fn)(handler->arg);
Expand All @@ -149,12 +167,18 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
ETS_GPIO_INTR_ENABLE();
}

extern void cleanupFunctional(void* arg);

extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) {
if(pin < 16) {
ETS_GPIO_INTR_DISABLE();
interrupt_handler_t *handler = &interrupt_handlers[pin];
handler->mode = mode;
handler->fn = userFunc;
if (handler->arg) // Clean when new attach without detach
{
cleanupFunctional(handler->arg);
}
handler->arg = arg;
interrupt_reg |= (1 << pin);
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
Expand All @@ -179,6 +203,10 @@ extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
interrupt_handler_t *handler = &interrupt_handlers[pin];
handler->mode = 0;
handler->fn = 0;
if (handler->arg)
{
cleanupFunctional(handler->arg);
}
handler->arg = 0;
if (interrupt_reg)
ETS_GPIO_INTR_ENABLE();
Expand Down