Skip to content

Commit c926025

Browse files
author
Paulo Costa
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 36c9419 commit c926025

File tree

3 files changed

+38
-62
lines changed

3 files changed

+38
-62
lines changed

hardware/arduino/avr/cores/arduino/Arduino.h

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
140140
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
141141

142142
void attachInterrupt(uint8_t, void (*)(void), int mode);
143+
void attachInterruptParam(uint8_t, void (*)(void*), int mode, void* param);
143144
void detachInterrupt(uint8_t);
144145

145146
void setup(void);

hardware/arduino/avr/cores/arduino/WInterrupts.c

+36-62
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
static void nothing(void) {
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

70-
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
71+
void attachInterrupt(uint8_t interruptNum, voidFuncPtr userFunc, 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] = 0;
274287
}
275288
}
276289

@@ -280,75 +293,37 @@ void attachInterruptTwi(void (*userFunc)(void) ) {
280293
}
281294
*/
282295

283-
#if defined(__AVR_ATmega32U4__)
284-
ISR(INT0_vect) {
285-
intFunc[EXTERNAL_INT_0]();
286-
}
287-
288-
ISR(INT1_vect) {
289-
intFunc[EXTERNAL_INT_1]();
290-
}
291-
292-
ISR(INT2_vect) {
293-
intFunc[EXTERNAL_INT_2]();
294-
}
296+
#define IMPLEMENT_ISR(vect, interrupt) \
297+
ISR(vect) { \
298+
intFunc[interrupt](intFuncParam [interrupt]); \
299+
}
295300

296-
ISR(INT3_vect) {
297-
intFunc[EXTERNAL_INT_3]();
298-
}
301+
#if defined(__AVR_ATmega32U4__)
299302

300-
ISR(INT6_vect) {
301-
intFunc[EXTERNAL_INT_4]();
302-
}
303+
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
304+
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
305+
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
306+
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
307+
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_4)
303308

304309
#elif defined(EICRA) && defined(EICRB)
305310

306-
ISR(INT0_vect) {
307-
intFunc[EXTERNAL_INT_2]();
308-
}
309-
310-
ISR(INT1_vect) {
311-
intFunc[EXTERNAL_INT_3]();
312-
}
313-
314-
ISR(INT2_vect) {
315-
intFunc[EXTERNAL_INT_4]();
316-
}
317-
318-
ISR(INT3_vect) {
319-
intFunc[EXTERNAL_INT_5]();
320-
}
321-
322-
ISR(INT4_vect) {
323-
intFunc[EXTERNAL_INT_0]();
324-
}
325-
326-
ISR(INT5_vect) {
327-
intFunc[EXTERNAL_INT_1]();
328-
}
329-
330-
ISR(INT6_vect) {
331-
intFunc[EXTERNAL_INT_6]();
332-
}
333-
334-
ISR(INT7_vect) {
335-
intFunc[EXTERNAL_INT_7]();
336-
}
311+
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_2)
312+
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_3)
313+
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_4)
314+
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_5)
315+
IMPLEMENT_ISR(INT4_vect, EXTERNAL_INT_0)
316+
IMPLEMENT_ISR(INT5_vect, EXTERNAL_INT_1)
317+
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_6)
318+
IMPLEMENT_ISR(INT7_vect, EXTERNAL_INT_7)
337319

338320
#else
339321

340-
ISR(INT0_vect) {
341-
intFunc[EXTERNAL_INT_0]();
342-
}
343-
344-
ISR(INT1_vect) {
345-
intFunc[EXTERNAL_INT_1]();
346-
}
322+
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
323+
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
347324

348325
#if defined(EICRA) && defined(ISC20)
349-
ISR(INT2_vect) {
350-
intFunc[EXTERNAL_INT_2]();
351-
}
326+
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
352327
#endif
353328

354329
#endif
@@ -359,4 +334,3 @@ ISR(TWI_vect) {
359334
twiIntFunc();
360335
}
361336
*/
362-

hardware/arduino/avr/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)