From 9eb8ba034948975955a7c78c4488220292b2dc98 Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Wed, 3 Feb 2016 00:31:38 -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. --- hardware/arduino/avr/cores/arduino/Arduino.h | 1 + .../arduino/avr/cores/arduino/WInterrupts.c | 19 ++++++++++++++++--- .../avr/cores/arduino/wiring_private.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/hardware/arduino/avr/cores/arduino/Arduino.h b/hardware/arduino/avr/cores/arduino/Arduino.h index 09c14489506..6a42e4195a2 100644 --- a/hardware/arduino/avr/cores/arduino/Arduino.h +++ b/hardware/arduino/avr/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/hardware/arduino/avr/cores/arduino/WInterrupts.c b/hardware/arduino/avr/cores/arduino/WInterrupts.c index cef1106e03b..6bc7bdb74fa 100644 --- a/hardware/arduino/avr/cores/arduino/WInterrupts.c +++ b/hardware/arduino/avr/cores/arduino/WInterrupts.c @@ -35,7 +35,7 @@ static void nothing(void) { } -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,11 +65,23 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = { nothing, #endif }; +static volatile void* intFuncParam[EXTERNAL_NUM_INTERRUPTS]; // volatile static voidFuncPtr twiIntFunc; -void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) { +void attachInterrupt(uint8_t interruptNum, voidFuncPtr userFunc, int mode) { + // THIS IMPLEMENTATION IS NOT PORTABLE! + // + // On AVR's calling convention, calling a function with more arguments than it declares + // is OK - The extra parameter is ignored and causes no harm + // + // This implementation takes advantage of it to support callbacks with and without parameters with minimum overhead. + 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 @@ -271,6 +283,7 @@ void detachInterrupt(uint8_t interruptNum) { } intFunc[interruptNum] = nothing; + intFuncParam[interruptNum] = NULL; } } @@ -282,7 +295,7 @@ void attachInterruptTwi(void (*userFunc)(void) ) { #define IMPLEMENT_ISR(vect, interrupt) \ ISR(vect) { \ - intFunc[interrupt](); \ + intFunc[interrupt](intFuncParam [interrupt]); \ } #if defined(__AVR_ATmega32U4__) diff --git a/hardware/arduino/avr/cores/arduino/wiring_private.h b/hardware/arduino/avr/cores/arduino/wiring_private.h index a277b148450..fe05dfce9a2 100644 --- a/hardware/arduino/avr/cores/arduino/wiring_private.h +++ b/hardware/arduino/avr/cores/arduino/wiring_private.h @@ -64,6 +64,7 @@ uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, u #endif typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrParam)(void*); #ifdef __cplusplus } // extern "C"