Skip to content

Commit

Permalink
wrap MRAA lib's Gpio::isr() for IRQ support (#970)
Browse files Browse the repository at this point in the history
I also removed MRAA exclusion from examples build. Previously, interruptConfigure.cpp was not built for MRAA driver.

* update example's IRQ_PIN value
* don't arbitrarily link example binaries to pigpio
* improve MRAA exception messages
  • Loading branch information
2bndy5 authored Mar 31, 2024
1 parent 7441eef commit c0cff53
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
20 changes: 9 additions & 11 deletions examples_linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(EXAMPLES_LIST
streamingData
multiceiverDemo
scanner
interruptConfigure
)

project(RF24Examples CXX)
Expand All @@ -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}
Expand All @@ -52,10 +46,14 @@ elseif("${RF24_DRIVER}" STREQUAL "wiringPi")
else()
message(FATAL "Lib ${RF24_DRIVER} not found.")
endif()
elseif(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND")
message(STATUS "linking to ${LibPIGPIO}")
# linking to pigpio requires pthread to be listed as last linked lib
list(APPEND linked_libs ${LibPIGPIO} pthread)
elseif("${RF24_DRIVER}" STREQUAL "pigpio")
if(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND")
message(STATUS "linking to ${LibPIGPIO}")
# linking to pigpio requires pthread to be listed as last linked lib
list(APPEND linked_libs ${LibPIGPIO} pthread)
else()
message(FATAL "Lib ${RF24_DRIVER} not found")
endif()
endif()

foreach(example ${EXAMPLES_LIST})
Expand Down
5 changes: 1 addition & 4 deletions examples_linux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 7 additions & 1 deletion examples_linux/interruptConfigure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@
using namespace std;

// We will be using the nRF24L01's IRQ pin for this example
#define IRQ_PIN 24 // this needs to be a digital input capable pin
#ifdef MRAA
#define IRQ_PIN 18 // GPIO24
#elif defined(RF24_WIRINGPI)
#define IRQ_PIN 5 // GPIO24
#else
#define IRQ_PIN 24 // GPIO24
#endif

// this example is a sequential program. so we need to wait for the event to be handled
volatile bool got_interrupt = false; // used to signify that the event started
Expand Down
4 changes: 3 additions & 1 deletion utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
24 changes: 16 additions & 8 deletions utility/MRAA/gpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include <map>
#include <mraa.h> // mraa_strresult()
#include "gpio.h"

// cache for mraa::Gpio instances
Expand All @@ -25,15 +26,22 @@ GPIO::~GPIO()

void GPIO::open(rf24_gpio_pin_t port, mraa::Dir DDR)
{
mraa::Result status;

// check that mraa::Gpio context doesn't already exist
std::map<rf24_gpio_pin_t, mraa::Gpio*>::iterator i = gpio_cache.find(port);
if (i == gpio_cache.end()) {
mraa::Gpio* gpio_inst = new mraa::Gpio(port);
gpio_cache[port] = gpio_inst;
gpio_inst->dir(DDR);
status = gpio_inst->dir(DDR);
}
else {
i->second->dir(DDR);
status = i->second->dir(DDR);
}
if (status != mraa::SUCCESS) {
std::string msg = "[GPIO::open] Could not set the pin direction; ";
msg += mraa_strresult((mraa_result_t)status);
throw GPIOException(msg);
}
}

Expand All @@ -60,17 +68,17 @@ int GPIO::read(rf24_gpio_pin_t port)

void GPIO::write(rf24_gpio_pin_t port, int value)
{
mraa::Result result = mraa::Result::ERROR_UNSPECIFIED; // a default
// get cache gpio instance
std::map<rf24_gpio_pin_t, mraa::Gpio*>::iterator i = gpio_cache.find(port);
if (i != gpio_cache.end()) {
result = i->second->write(value);
mraa::Result result = i->second->write(value);
if (result != mraa::Result::SUCCESS) {
std::string msg = "[GPIO::write] Could not set pin output value; ";
msg += mraa_strresult((mraa_result_t)result);
throw GPIOException(msg);
}
}
else {
throw GPIOException("[GPIO::write] pin was not initialized with GPIO::open()");
}

if (result != mraa::Result::SUCCESS) {
throw GPIOException("GPIO::write() failed");
}
}
1 change: 1 addition & 0 deletions utility/MRAA/includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
#endif

#include "MRAA/RF24_arch_config.h"
#include "MRAA/interrupt.h"

#endif // RF24_UTILITY_INCLUDES_H_
58 changes: 58 additions & 0 deletions utility/MRAA/interrupt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <map>
#include <mraa.h> // mraa_strresult()
#include <mraa.hpp> // mraa::Gpio
#include "interrupt.h"
#include "gpio.h" // rf24_gpio_pin_t

#ifdef __cplusplus
extern "C" {
#endif

std::map<rf24_gpio_pin_t, mraa::Gpio*> 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<std::map<rf24_gpio_pin_t, mraa::Gpio*>::iterator, bool> indexPair = irqCache.insert(std::pair<rf24_gpio_pin_t, mraa::Gpio*>(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<rf24_gpio_pin_t, mraa::Gpio*>::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
44 changes: 44 additions & 0 deletions utility/MRAA/interrupt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef RF24_UTILITY_MRAA_INTERRUPT_H_
#define RF24_UTILITY_MRAA_INTERRUPT_H_

#include <stdexcept> // 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_
29 changes: 25 additions & 4 deletions utility/MRAA/spi.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

#include <mraa.h> // mraa_strresult(), mraa_result_t
#include "spi.h"
#include "mraa.h"

SPI::SPI()
{
Expand All @@ -12,11 +12,32 @@ void SPI::begin(int busNo, uint32_t spi_speed)
// init mraa spi bus, it will handle chip select internally. For CS pin wiring user must check SPI details in hardware manual
mspi = new mraa::Spi(busNo);

mspi->mode(mraa::SPI_MODE0);
mspi->bitPerWord(8);
mraa::Result result;

result = mspi->mode(mraa::SPI_MODE0);
if (result != mraa::Result::SUCCESS) {
std::string msg = "[SPI::begin] Could not set bus mode;";
msg += mraa_strresult((mraa_result_t)result);
throw SPIException(msg);
return;
}

result = mspi->bitPerWord(8);
if (result != mraa::Result::SUCCESS) {
std::string msg = "[SPI::begin] Could not set bus bits per word;";
msg += mraa_strresult((mraa_result_t)result);
throw SPIException(msg);
return;
}

// Prophet: this will try to set 8MHz, however MRAA will reset to max platform speed and syslog a message of it
mspi->frequency(spi_speed);
result = mspi->frequency(spi_speed);
if (result != mraa::Result::SUCCESS) {
std::string msg = "[SPI::begin] Could not set bus frequency;";
msg += mraa_strresult((mraa_result_t)result);
throw SPIException(msg);
return;
}
}

void SPI::end()
Expand Down
23 changes: 20 additions & 3 deletions utility/MRAA/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,23 @@
* Class declaration for SPI helper files
*/

#include "mraa.h"
#include "mraa.hpp"
#include <stdexcept> // std::exception, std::string
#include <mraa.hpp> // mraa::

#include "../../RF24_config.h" // This is cyclical and should be fixed
/** @brief The default SPI speed (in Hz) */
#ifndef RF24_SPI_SPEED
#define RF24_SPI_SPEED 10000000
#endif

/** Specific exception for SPI errors */
class SPIException : public std::runtime_error
{
public:
explicit SPIException(const std::string& msg)
: std::runtime_error(msg)
{
}
};

class SPI
{
Expand All @@ -34,12 +47,16 @@ class SPI

void end();

// not actually used in Linux
void setBitOrder(uint8_t bit_order);

// not actually used in Linux
void setDataMode(uint8_t data_mode);

// not actually used in Linux
void setClockDivider(uint32_t spi_speed);

// not actually used in Linux
void chipSelect(int csn_pin);
};

Expand Down

0 comments on commit c0cff53

Please sign in to comment.