From 05a54588b61e58c8db2d544ff663c1e0583c514a Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Tue, 26 Mar 2024 21:54:33 -0700 Subject: [PATCH] Use BCM2835 lib's Edge Detection Status for IRQ support --- utility/RPi/interrupt.cpp | 141 +++++--------------------------------- utility/RPi/interrupt.h | 46 ++++--------- 2 files changed, 28 insertions(+), 159 deletions(-) diff --git a/utility/RPi/interrupt.cpp b/utility/RPi/interrupt.cpp index de3fc94a..8156e72c 100644 --- a/utility/RPi/interrupt.cpp +++ b/utility/RPi/interrupt.cpp @@ -1,14 +1,9 @@ /** * Interrupt implementations */ -#include "linux/gpio.h" -#include // close() -#include // open() -#include // ioctl() -#include // errno, strerror() -#include // std::string, strcpy() #include #include +#include "bcm2835.h" #include "interrupt.h" #ifdef __cplusplus @@ -18,63 +13,14 @@ extern "C" { static pthread_mutex_t irq_mutex = PTHREAD_MUTEX_INITIALIZER; std::map irqCache; -void IrqChipCache::openDevice() -{ - if (fd < 0) { - fd = open(chip, O_RDONLY); - if (fd < 0) { - std::string msg = "Can't open device "; - msg += chip; - msg += "; "; - msg += strerror(errno); - throw IRQException(msg); - return; - } - } - chipInitialized = true; -} - -void IrqChipCache::closeDevice() -{ - if (fd >= 0) { - close(fd); - fd = -1; - } -} - -IrqChipCache::IrqChipCache() -{ -} - -IrqChipCache::~IrqChipCache() -{ - for (std::map::iterator i = irqCache.begin(); i != irqCache.end(); ++i) { - pthread_cancel(i->second.id); // send cancel request - pthread_join(i->second.id, NULL); // wait till thread terminates - close(i->second.fd); - } - irqCache.clear(); -} - -IrqChipCache irqChipCache; - void* poll_irq(void* arg) { IrqPinCache* pinCache = (IrqPinCache*)(arg); - unsigned int lastEventSeqNo = 0; - gpio_v2_line_event irqEventInfo; - memset(&irqEventInfo, 0, sizeof(irqEventInfo)); for (;;) { - int ret = read(pinCache->fd, &irqEventInfo, sizeof(gpio_v2_line_event)); - if (ret < 0) { - std::string msg = "[poll_irq] Could not read event info; "; - msg += strerror(errno); - throw IRQException(msg); - return NULL; - } - if (ret > 0 && irqEventInfo.line_seqno != lastEventSeqNo) { - lastEventSeqNo = irqEventInfo.line_seqno; + int ret = bcm2835_gpio_eds(pinCache->pin); + if (ret > 0) { + bcm2835_gpio_set_eds(pinCache->pin); pinCache->function(); } pthread_testcancel(); @@ -82,88 +28,31 @@ void* poll_irq(void* arg) return NULL; } -int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)) +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); - try { - irqChipCache.openDevice(); - } - catch (IRQException& exc) { - if (irqChipCache.chipInitialized) { - throw exc; - return 0; - } - irqChipCache.chip = "/dev/gpiochip0"; - irqChipCache.openDevice(); - } - - // get chip info - gpiochip_info info; - memset(&info, 0, sizeof(info)); - int ret = ioctl(irqChipCache.fd, GPIO_GET_CHIPINFO_IOCTL, &info); - if (ret < 0) { - std::string msg = "[attachInterrupt] Could not gather info about "; - msg += irqChipCache.chip; - throw IRQException(msg); - return 0; - } - - if (pin > info.lines) { - std::string msg = "[attachInterrupt] pin " + std::to_string(pin) + " is not available on " + irqChipCache.chip; - throw IRQException(msg); - return 0; - } - - // create a request object to configure the specified pin - gpio_v2_line_request request; - memset(&request, 0, sizeof(request)); - strcpy(request.consumer, "RF24 IRQ"); - request.num_lines = 1U; - request.offsets[0] = pin; - request.event_buffer_size = sizeof(gpio_v2_line_event); - - // set debounce for the pin - // request.config.attrs[0].mask = 1LL; - // request.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; - // request.config.attrs[0].attr.debounce_period_us = 10U; - // request.config.num_attrs = 1U; - - // set pin as input and configure edge detection - request.config.flags = GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME; + // configure the specified pin switch (mode) { case INT_EDGE_BOTH: + bcm2835_gpio_ren(pin); + bcm2835_gpio_fen(pin); + break; case INT_EDGE_RISING: + bcm2835_gpio_ren(pin); + break; case INT_EDGE_FALLING: - request.config.flags |= mode; + bcm2835_gpio_fen(pin); break; default: // bad user input! return 0; // stop here } - // write pin request's config - ret = ioctl(irqChipCache.fd, GPIO_V2_GET_LINE_IOCTL, &request); - if (ret < 0 || request.fd <= 0) { - std::string msg = "[attachInterrupt] Could not get line handle from ioctl; "; - msg += strerror(errno); - throw IRQException(msg); - return 0; - } - irqChipCache.closeDevice(); - - ret = ioctl(request.fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, &request.config); - if (ret < 0) { - std::string msg = "[attachInterrupt] Could not set line config; "; - msg += strerror(errno); - throw IRQException(msg); - return 0; - } - // cache details IrqPinCache irqPinCache; - irqPinCache.fd = request.fd; + irqPinCache.pin = pin; irqPinCache.function = function; std::pair::iterator, bool> indexPair = irqCache.insert(std::pair(pin, irqPinCache)); @@ -189,7 +78,9 @@ int detachInterrupt(rf24_gpio_pin_t pin) } pthread_cancel(cachedPin->second.id); // send cancel request pthread_join(cachedPin->second.id, NULL); // wait till thread terminates - close(cachedPin->second.fd); + bcm2835_gpio_clr_ren(cachedPin->second.pin); + bcm2835_gpio_clr_fen(cachedPin->second.pin); + bcm2835_gpio_set_eds(cachedPin->second.pin); irqCache.erase(cachedPin); return 1; } diff --git a/utility/RPi/interrupt.h b/utility/RPi/interrupt.h index de09cbbb..a2d4c180 100644 --- a/utility/RPi/interrupt.h +++ b/utility/RPi/interrupt.h @@ -4,19 +4,21 @@ #ifndef RF24_UTILITY_RPI_INTERRUPT_H_ #define RF24_UTILITY_RPI_INTERRUPT_H_ -#include // pthread_t -#include -#include "linux/gpio.h" // GPIO_V2_LINE_FLAG_EDGE_*** +#include // pthread_t +#include // std::exception, std::string #include "RF24_arch_config.h" // rf24_gpio_pin_t -#define INT_EDGE_FALLING GPIO_V2_LINE_FLAG_EDGE_FALLING -#define INT_EDGE_RISING GPIO_V2_LINE_FLAG_EDGE_RISING -#define INT_EDGE_BOTH GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING - #ifdef __cplusplus extern "C" { #endif +enum IrqEvent : uint8_t +{ + INT_EDGE_FALLING, + INT_EDGE_RISING, + INT_EDGE_BOTH, +}; + /** Specific exception for IRQ errors */ class IRQException : public std::runtime_error { @@ -27,35 +29,11 @@ class IRQException : public std::runtime_error } }; -/// A struct to manage the GPIO chip file descriptor. -/// This struct's destructor should close any cached GPIO pin requests' file descriptors. -struct IrqChipCache -{ - const char* chip = RF24_LINUX_GPIO_CHIP; - int fd = -1; - bool chipInitialized = false; - - /// Open the File Descriptor for the GPIO chip - void openDevice(); - - /// Close the File Descriptor for the GPIO chip - void closeDevice(); - - /// should be called automatically on program start. - /// Here, we do some one-off configuration. - IrqChipCache(); - - /// Should be called automatically on program exit. - /// What we need here is to make sure that the File Descriptors used to - /// control GPIO pins are properly closed. - ~IrqChipCache(); -}; - /** Details related to a certain pin's ISR. */ struct IrqPinCache { - /// The pin request's file descriptor - int fd = 0; + /// The pin number + rf24_gpio_pin_t pin = 0; /// The posix thread ID. pthread_t id = 0; @@ -68,7 +46,7 @@ struct IrqPinCache * Take the details and create an interrupt handler that will * callback to the user-supplied function. */ -int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)); +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.