Skip to content

Commit 932f1e6

Browse files
committed
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.
1 parent 6ba4fd3 commit 932f1e6

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

cores/arduino/Arduino.h

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
148148
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
149149

150150
void attachInterrupt(uint8_t, void (*)(void), int mode);
151+
void attachInterruptParam(uint8_t, void (*)(void*), int mode, void* param);
151152
void detachInterrupt(uint8_t);
152153

153154
void setup(void);

cores/arduino/WInterrupts.c

+16-3
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232

3333
#include "wiring_private.h"
3434

35-
static void nothing(void) {
35+
static void nothing(void* arg) {
3636
}
3737

38-
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
38+
static volatile voidFuncPtrParam intFunc[EXTERNAL_NUM_INTERRUPTS] = {
3939
#if EXTERNAL_NUM_INTERRUPTS > 8
4040
#warning There are more than 8 external interrupts. Some callbacks may not be initialized.
4141
nothing,
@@ -65,11 +65,23 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
6565
nothing,
6666
#endif
6767
};
68+
static volatile void* intFuncParam[EXTERNAL_NUM_INTERRUPTS];
6869
// volatile static voidFuncPtr twiIntFunc;
6970

7071
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
72+
// THIS IMPLEMENTATION IS NOT PORTABLE!
73+
//
74+
// On AVR's calling convention, calling a function with more arguments than it declares
75+
// is OK - The extra parameter is ignored and causes no harm
76+
//
77+
// This implementation takes advantage of it to support callbacks with and without parameters with minimum overhead.
78+
attachInterruptParam(interruptNum, (voidFuncPtrParam)userFunc, mode, NULL);
79+
}
80+
81+
void attachInterruptParam(uint8_t interruptNum, voidFuncPtrParam userFunc, int mode, void* param) {
7182
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
7283
intFunc[interruptNum] = userFunc;
84+
intFuncParam[interruptNum] = param;
7385

7486
// Configure the interrupt mode (trigger on low input, any change, rising
7587
// edge, or falling edge). The mode constants were chosen to correspond
@@ -271,6 +283,7 @@ void detachInterrupt(uint8_t interruptNum) {
271283
}
272284

273285
intFunc[interruptNum] = nothing;
286+
intFuncParam[interruptNum] = NULL;
274287
}
275288
}
276289

@@ -282,7 +295,7 @@ void attachInterruptTwi(void (*userFunc)(void) ) {
282295

283296
#define IMPLEMENT_ISR(vect, interrupt) \
284297
ISR(vect) { \
285-
intFunc[interrupt](); \
298+
intFunc[interrupt]((void*)intFuncParam[interrupt]); \
286299
}
287300

288301
#if defined(__AVR_ATmega32U4__)

cores/arduino/wiring_private.h

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, u
6464
#endif
6565

6666
typedef void (*voidFuncPtr)(void);
67+
typedef void (*voidFuncPtrParam)(void*);
6768

6869
#ifdef __cplusplus
6970
} // extern "C"

0 commit comments

Comments
 (0)