From 3c6d386b30bd2ad59738c95cf86221c96dd8dcb6 Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Fri, 4 Jan 2019 15:02:44 -0200 Subject: [PATCH] Support extra parameter on `attachInterrupt()` When writing an arduino library, it is difficult to connect interrupt handlers with the component instance that should be notified. In C, the common pattern to fix this is to specifying a `void*` parameter with the callback, where the listener can store any context necessary. This patch adds the new function `attachInterruptParam()` to implement this pattern. --- cores/arduino/Arduino.h | 1 + cores/arduino/WInterrupts.c | 19 ++++++++++++++++--- cores/arduino/wiring_private.h | 2 -- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 09c144895..6a42e4195 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -148,6 +148,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t, void (*)(void), int mode); +void attachInterruptParam(uint8_t, void (*)(void*), int mode, void* param); void detachInterrupt(uint8_t); void setup(void); diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index ac72dda44..c6119075a 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -32,10 +32,12 @@ #include "wiring_private.h" -static void nothing(void) { +typedef void (*voidFuncPtrParam)(void*); + +static void nothing(void* arg) { } -static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { +static volatile voidFuncPtrParam intFunc[EXTERNAL_NUM_INTERRUPTS] = { #if EXTERNAL_NUM_INTERRUPTS > 8 #warning There are more than 8 external interrupts. Some callbacks may not be initialized. nothing, @@ -65,10 +67,20 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { nothing, #endif }; +static volatile void* intFuncParam[EXTERNAL_NUM_INTERRUPTS]; void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { + // To support callbacks with and without parameters with minimum overhead, + // this relies on that fact that in C calling conventions extra argument on a + // function call are safely ignored without side-effects. + + attachInterruptParam(interruptNum, (voidFuncPtrParam)userFunc, mode, NULL); +} + + void attachInterruptParam(uint8_t interruptNum, voidFuncPtrParam userFunc, int mode, void* param) { if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { intFunc[interruptNum] = userFunc; + intFuncParam[interruptNum] = param; // Configure the interrupt mode (trigger on low input, any change, rising // edge, or falling edge). The mode constants were chosen to correspond @@ -270,13 +282,14 @@ void detachInterrupt(uint8_t interruptNum) { } intFunc[interruptNum] = nothing; + intFuncParam[interruptNum] = NULL; } } #define IMPLEMENT_ISR(vect, interrupt) \ ISR(vect) { \ - intFunc[interrupt](); \ + intFunc[interrupt]((void*)intFuncParam[interrupt]); \ } #if defined(__AVR_ATmega32U4__) diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index a277b1484..b49c6f203 100644 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -63,8 +63,6 @@ uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, u #define EXTERNAL_NUM_INTERRUPTS 2 #endif -typedef void (*voidFuncPtr)(void); - #ifdef __cplusplus } // extern "C" #endif