diff --git a/utility/SPIDEV/gpio.cpp b/utility/SPIDEV/gpio.cpp index 94b5453e..4c0bc1cc 100644 --- a/utility/SPIDEV/gpio.cpp +++ b/utility/SPIDEV/gpio.cpp @@ -11,18 +11,16 @@ #include // ioctl() #include // errno, strerror() #include // std::string, strcpy() -#include #include "gpio.h" // instantiate some global structs to setup cache // doing this globally ensures the data struct is zero-ed out -typedef int gpio_fd; // for readability -std::map cachedPins; struct gpio_v2_line_request request; struct gpio_v2_line_values data; -// initialize static member. +// initialize static members. int GPIOChipCache::fd = -1; +std::map GPIOChipCache::cachedPins = std::map(); void GPIOChipCache::openDevice() { @@ -97,8 +95,8 @@ void GPIO::open(rf24_gpio_pin_t port, int DDR) } // check if pin is already in use - std::map::iterator pin = cachedPins.find(port); - if (pin == cachedPins.end()) { // pin not in use; add it to cached request + std::map::iterator pin = gpioCache.cachedPins.find(port); + if (pin == gpioCache.cachedPins.end()) { // pin not in use; add it to cached request request.offsets[0] = port; request.fd = 0; } @@ -127,25 +125,25 @@ void GPIO::open(rf24_gpio_pin_t port, int DDR) throw GPIOException(msg); return; } - cachedPins.insert(std::pair(port, request.fd)); + gpioCache.cachedPins.insert(std::pair(port, request.fd)); } void GPIO::close(rf24_gpio_pin_t port) { - std::map::iterator pin = cachedPins.find(port); - if (pin == cachedPins.end()) { + std::map::iterator pin = gpioCache.cachedPins.find(port); + if (pin == gpioCache.cachedPins.end()) { return; } if (pin->second > 0) { ::close(pin->second); } - cachedPins.erase(pin); + gpioCache.cachedPins.erase(pin); } int GPIO::read(rf24_gpio_pin_t port) { - std::map::iterator pin = cachedPins.find(port); - if (pin == cachedPins.end() || pin->second <= 0) { + std::map::iterator pin = gpioCache.cachedPins.find(port); + if (pin == gpioCache.cachedPins.end() || pin->second <= 0) { throw GPIOException("[GPIO::read] pin not initialized! Use GPIO::open() first"); return -1; } @@ -164,8 +162,8 @@ int GPIO::read(rf24_gpio_pin_t port) void GPIO::write(rf24_gpio_pin_t port, int value) { - std::map::iterator pin = cachedPins.find(port); - if (pin == cachedPins.end() || pin->second <= 0) { + std::map::iterator pin = gpioCache.cachedPins.find(port); + if (pin == gpioCache.cachedPins.end() || pin->second <= 0) { throw GPIOException("[GPIO::write] pin not initialized! Use GPIO::open() first"); return; } diff --git a/utility/SPIDEV/gpio.h b/utility/SPIDEV/gpio.h index 648030e1..09be8800 100644 --- a/utility/SPIDEV/gpio.h +++ b/utility/SPIDEV/gpio.h @@ -15,6 +15,7 @@ #include #include +#include #include "linux/gpio.h" // gpiochip_info typedef uint16_t rf24_gpio_pin_t; @@ -35,6 +36,8 @@ class GPIOException : public std::runtime_error } }; +typedef int gpio_fd; // for readability + /// A struct to manage the GPIO chip file descriptor. /// This struct's destructor should close any cached GPIO pin requests' file descriptors. struct GPIOChipCache @@ -48,6 +51,12 @@ struct GPIOChipCache /// struct use the same file descriptor. static int fd; + /// @brief The map of pin numbers to their corresponding file descriptors. + /// + /// Because this member is static, all instances (& derivative instances) of this + /// struct use the same mapping. + static std::map cachedPins; + /// Open the File Descriptor for the GPIO chip void openDevice(); diff --git a/utility/SPIDEV/interrupt.cpp b/utility/SPIDEV/interrupt.cpp index cee5c76b..88f1f78d 100644 --- a/utility/SPIDEV/interrupt.cpp +++ b/utility/SPIDEV/interrupt.cpp @@ -133,14 +133,21 @@ int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)) IrqPinCache irqPinCache; irqPinCache.fd = request.fd; irqPinCache.function = function; - std::pair::iterator, bool> indexPair = irqCache.insert(std::pair(pin, irqPinCache)); + std::pair::iterator, bool> indexPair = irqCache.insert(std::pair(pin, irqPinCache)); if (!indexPair.second) { // this should not be reached, but indexPair.first needs to be the inserted map element throw IRQException("[attachInterrupt] Could not cache the IRQ pin with function pointer"); return 0; } + std::pair::iterator, bool> gpioPair = irqChipCache.cachedPins.insert(std::pair(pin, request.fd)); + if (!gpioPair.second) { + // this should not be reached, but gpioPair.first needs to be the inserted map element + throw IRQException("[attachInterrupt] Could not cache the GPIO pin's file descriptor"); + return 0; + } + // create and start thread pthread_mutex_lock(&irq_mutex); pthread_create(&indexPair.first->second.id, nullptr, poll_irq, &indexPair.first->second); @@ -157,8 +164,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); irqCache.erase(cachedPin); + // reconfigure the pin for basic `digitalRead()` + GPIO::open(pin, GPIO::DIRECTION_IN); return 1; } diff --git a/utility/SPIDEV/interrupt.h b/utility/SPIDEV/interrupt.h index 8a6e80bf..257f7391 100644 --- a/utility/SPIDEV/interrupt.h +++ b/utility/SPIDEV/interrupt.h @@ -46,7 +46,7 @@ struct IrqPinCache int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)); /** - * Will cancel the interrupt thread, close the filehandle and release the pin. + * Will cancel the interrupt thread and re-configure the pin for `digitalRead()` use. */ int detachInterrupt(rf24_gpio_pin_t pin);