From 62f73e4dd665feb7556494a0e0eb9f03c3e453b0 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Tue, 26 Mar 2024 13:18:15 -0700 Subject: [PATCH] wrap MRAA lib's `Gpio::isr()` for IRQ support I also removed MRAA exclusion from examples build. Previously, interruptConfigure.cpp was not built for MRAA driver. --- Makefile | 2 +- examples_linux/CMakeLists.txt | 8 +---- examples_linux/Makefile | 5 +-- utility/CMakeLists.txt | 4 ++- utility/MRAA/includes.h | 1 + utility/MRAA/interrupt.cpp | 60 +++++++++++++++++++++++++++++++++++ utility/MRAA/interrupt.h | 44 +++++++++++++++++++++++++ 7 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 utility/MRAA/interrupt.cpp create mode 100644 utility/MRAA/interrupt.h diff --git a/Makefile b/Makefile index 84b15d478..fe7280a94 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ include $(CONFIG_FILE) # Objects to compile OBJECTS=RF24.o ifeq ($(DRIVER), MRAA) -OBJECTS+=spi.o gpio.o compatibility.o +OBJECTS+=spi.o gpio.o compatibility.o interrupt.o else ifeq ($(DRIVER), RPi) OBJECTS+=spi.o bcm2835.o compatibility.o interrupt.o else ifeq ($(DRIVER), SPIDEV) diff --git a/examples_linux/CMakeLists.txt b/examples_linux/CMakeLists.txt index 40101a603..cc2ef0898 100644 --- a/examples_linux/CMakeLists.txt +++ b/examples_linux/CMakeLists.txt @@ -8,6 +8,7 @@ set(EXAMPLES_LIST streamingData multiceiverDemo scanner + interruptConfigure ) project(RF24Examples CXX) @@ -23,13 +24,6 @@ include(../cmake/AutoConfig_RF24_DRIVER.cmake) find_library(RF24 rf24 REQUIRED) message(STATUS "using RF24 library: ${RF24}") -# conditionally append "interruptConfigure" to the EXAMPLES_LIST -if("${RF24_DRIVER}" STREQUAL "MRAA") - message(STATUS "Skipping interruptConfigure.cpp example as it is incompatible with selected driver library") -else() # not using MRAA or wiringPi drivers (or pigpio lib was found) - list(APPEND EXAMPLES_LIST interruptConfigure) -endif() - set(linked_libs ${RF24} diff --git a/examples_linux/Makefile b/examples_linux/Makefile index 901a7402c..e3a3c4998 100644 --- a/examples_linux/Makefile +++ b/examples_linux/Makefile @@ -18,9 +18,6 @@ endif include ../Makefile.inc # define all programs -PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo scanner -ifneq ($(DRIVER), MRAA) -PROGRAMS+=interruptConfigure -endif +PROGRAMS = gettingstarted acknowledgementPayloads manualAcknowledgements streamingData multiceiverDemo scanner interruptConfigure include Makefile.examples diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt index d18bce7ab..0ea66b9cf 100644 --- a/utility/CMakeLists.txt +++ b/utility/CMakeLists.txt @@ -67,6 +67,7 @@ elseif("${RF24_DRIVER}" STREQUAL "MRAA") # use MRAA ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/compatibility.cpp ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/interrupt.cpp PARENT_SCOPE ) install(FILES @@ -75,7 +76,8 @@ elseif("${RF24_DRIVER}" STREQUAL "MRAA") # use MRAA ${RF24_DRIVER}/spi.h ${RF24_DRIVER}/compatibility.h ${RF24_DRIVER}/RF24_arch_config.h - DESTINATION include/RF24/utility/${RF24_DRIVER} + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/interrupt.h + DESTINATION include/RF24/utility/${RF24_DRIVER} ) elseif("${RF24_DRIVER}" STREQUAL "pigpio") # use pigpio set(RF24_LINKED_DRIVER ${LibPIGPIO} PARENT_SCOPE) diff --git a/utility/MRAA/includes.h b/utility/MRAA/includes.h index d5d697909..6a46304ef 100644 --- a/utility/MRAA/includes.h +++ b/utility/MRAA/includes.h @@ -6,5 +6,6 @@ #endif #include "MRAA/RF24_arch_config.h" +#include "MRAA/interrupt.h" #endif // RF24_UTILITY_INCLUDES_H_ diff --git a/utility/MRAA/interrupt.cpp b/utility/MRAA/interrupt.cpp new file mode 100644 index 000000000..cf5dda5de --- /dev/null +++ b/utility/MRAA/interrupt.cpp @@ -0,0 +1,60 @@ +#include +#include // mraa_strresult() +#include // mraa::Gpio +#include "interrupt.h" +#include "gpio.h" // rf24_gpio_pin_t + +#ifdef __cplusplus +extern "C" { +#endif + +std::map irqCache; + +int attachInterrupt(rf24_gpio_pin_t pin, uint8_t mode, void (*function)(void)) +{ + // ensure pin is not already being used in a separate thread + detachInterrupt(pin); + GPIO::close(pin); + + mraa::Gpio* gpio = new mraa::Gpio(pin); + mraa::Result status = gpio->dir(mraa::DIR_IN); + if (status != mraa::SUCCESS) { + std::string msg = "[attachInterrupt] Could not set the pin as an input; "; + msg += mraa_strresult((mraa_result_t)status); + throw IRQException(msg); + return 0; + } + status = gpio->isr((mraa::Edge)mode, (void (*)(void*))function, NULL); + if (status != mraa::SUCCESS) { + std::string msg = "[attachInterrupt] Could not setup the ISR; "; + msg += mraa_strresult((mraa_result_t)status); + throw IRQException(msg); + return 0; + } + + std::pair::iterator, bool> indexPair = irqCache.insert(std::pair(pin, gpio)); + if (!indexPair.second) { + // this should not be reached, but indexPair.first needs to be the inserted map element + gpio->close(); + throw IRQException("[attachInterrupt] Could not cache the mraa::Gpio object"); + return 0; + } + return 1; +} + +int detachInterrupt(rf24_gpio_pin_t pin) +{ + std::map::iterator cachedPin = irqCache.find(pin); + if (cachedPin == irqCache.end()) { + return 0; // pin not in cache; just exit + } + cachedPin->second->close(); + irqCache.erase(cachedPin); + return 1; +} + +#ifdef __cplusplus +} +#endif + +#endif // !defined(ARDUINO) diff --git a/utility/MRAA/interrupt.h b/utility/MRAA/interrupt.h new file mode 100644 index 000000000..5fe06ea80 --- /dev/null +++ b/utility/MRAA/interrupt.h @@ -0,0 +1,44 @@ +#ifndef RF24_UTILITY_MRAA_INTERRUPT_H_ +#define RF24_UTILITY_MRAA_INTERRUPT_H_ + +#include // std::exception, std::string +#include "mraa.hpp" // mraa:: +#include "gpio.h" // rf24_gpio_pin_t + +#ifdef __cplusplus +extern "C" { +#endif + +enum Edge +{ + INT_EDGE_FALLING = mraa::Edge::EDGE_FALLING, + INT_EDGE_RISING = mraa::Edge::EDGE_RISING, + INT_EDGE_BOTH = mraa::Edge::EDGE_BOTH, +}; + +/** Specific exception for IRQ errors */ +class IRQException : public std::runtime_error +{ +public: + explicit IRQException(const std::string& msg) + : std::runtime_error(msg) + { + } +}; + +/** + * Take the details and create an interrupt handler that will + * callback to the user-supplied function. + */ +int attachInterrupt(rf24_gpio_pin_t pin, uint8_t mode, void (*function)(void)); + +/** + * Will cancel the interrupt thread, close the filehandle and release the pin. + */ +int detachInterrupt(rf24_gpio_pin_t pin); + +#ifdef __cplusplus +} +#endif + +#endif // RF24_UTILITY_MRAA_INTERRUPT_H_