Skip to content

Commit

Permalink
add interrupt support for Linux utility drivers
Browse files Browse the repository at this point in the history
Also improved exception messages in a few drivers.
  • Loading branch information
2bndy5 committed Mar 26, 2024
1 parent 360f52c commit 8b484dd
Show file tree
Hide file tree
Showing 24 changed files with 1,290 additions and 418 deletions.
8 changes: 8 additions & 0 deletions docs/API/arduino_wrappers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ Arduino GPIOClass
This is library-specific API wrapping the Arduino GPIO interface.

.. cpp-apigen-group:: arduino-gpio


Arduino Interrupts
------------------

This is library-specific API wrapping the Arduino interrupt functionality.

.. cpp-apigen-group:: arduino-irq
2 changes: 2 additions & 0 deletions src/utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ set(CIRQUE_PINNACLE_UTILITY_HEADERS
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/spi.h
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/i2c.h
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/time_keeping.h
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/interrupt.h
)
set(PINNACLE_UTILITY_IMPLEMENTATION_FILES
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/spi.cpp
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/i2c.cpp
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/time_keeping.cpp
${CMAKE_CURRENT_LIST_DIR}/${PINNACLE_DRIVER}/interrupt.cpp
)
if("${PINNACLE_DRIVER}" STREQUAL "bcm2xxx") # use bcm2835 lib
install(FILES
Expand Down
4 changes: 2 additions & 2 deletions src/utility/bcm2xxx/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CIRQUEPINNACLE_UTILITY_TEMPLATE_I2C_H_
#define CIRQUEPINNACLE_UTILITY_TEMPLATE_I2C_H_
#ifndef CIRQUEPINNACLE_UTILITY_BCM2XXX_I2C_H_
#define CIRQUEPINNACLE_UTILITY_BCM2XXX_I2C_H_
#ifndef ARDUINO

#include <cstdint>
Expand Down
112 changes: 112 additions & 0 deletions src/utility/bcm2xxx/interrupt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2023 Brendan Doherty (2bndy5)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef ARDUINO
#include <pthread.h>
#include <map>
#include "bcm2835.h"
#include "interrupt.h"

#ifdef __cplusplus
extern "C" {
#endif

namespace cirque_pinnacle_arduino_wrappers {

static pthread_mutex_t irq_mutex = PTHREAD_MUTEX_INITIALIZER;
std::map<pinnacle_gpio_t, IrqPinCache> irqCache;

void* poll_irq(void* arg)
{
IrqPinCache* pinCache = (IrqPinCache*)(arg);

for (;;) {
int ret = bcm2835_gpio_eds(pinCache->pin);
if (ret > 0) {
bcm2835_gpio_set_eds(pinCache->pin);
pinCache->function();
}
pthread_testcancel();
}
return NULL;
}

int attachInterrupt(pinnacle_gpio_t pin, int mode, void (*function)(void))
{
// ensure pin is not already being used in a separate thread
detachInterrupt(pin);

// create a request object to configure the specified pin
switch (mode) {
case CHANGE:
bcm2835_gpio_ren(pin);
bcm2835_gpio_fen(pin);
break;
case RISING:
bcm2835_gpio_ren(pin);
break;
case FALLING:
bcm2835_gpio_fen(pin);
break;
default:
// bad user input!
return 0; // stop here
}

// cache details
IrqPinCache irqPinCache;
irqPinCache.pin = pin;
irqPinCache.function = function;
std::pair<std::map<pinnacle_gpio_t, IrqPinCache>::iterator, bool> indexPair = irqCache.insert(std::pair<pinnacle_gpio_t, IrqPinCache>(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;
}

// create and start thread
pthread_mutex_lock(&irq_mutex);
pthread_create(&indexPair.first->second.id, nullptr, poll_irq, &indexPair.first->second);
pthread_mutex_unlock(&irq_mutex);

return 1;
}

int detachInterrupt(pinnacle_gpio_t pin)
{
std::map<pinnacle_gpio_t, IrqPinCache>::iterator cachedPin = irqCache.find(pin);
if (cachedPin == irqCache.end()) {
return 0; // pin not in cache; just exit
}
pthread_cancel(cachedPin->second.id); // send cancel request
pthread_join(cachedPin->second.id, NULL); // wait till thread terminates
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;
}

} // namespace cirque_pinnacle_arduino_wrappers

#ifdef __cplusplus
}
#endif

#endif // !defined(ARDUINO)
81 changes: 81 additions & 0 deletions src/utility/bcm2xxx/interrupt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2023 Brendan Doherty (2bndy5)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CIRQUEPINNACLE_UTILITY_BCM2XXX_INTERRUPT_H_
#define CIRQUEPINNACLE_UTILITY_BCM2XXX_INTERRUPT_H_
#ifndef ARDUINO

#include <pthread.h> // pthread_t
#include <stdexcept> // std::exception, std::string
#include "gpio.h" // pinnacle_gpio_t

#ifdef __cplusplus
extern "C" {
#endif

namespace cirque_pinnacle_arduino_wrappers {

enum Edge
{
FALLING,
RISING,
CHANGE,
};

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

/** Details related to a certain pin's ISR. */
struct IrqPinCache
{
/// The pin request's file descriptor
int pin = 0;

/// The posix thread ID.
pthread_t id = 0;

/// The user-designated ISR function (used as a callback)
void (*function)(void) = nullptr;
};

/**
* Take the details and create an interrupt handler that will
* callback to the user-supplied function.
*/
int attachInterrupt(pinnacle_gpio_t pin, int mode, void (*function)(void));

/**
* Will cancel the interrupt thread, close the filehandle and release the pin.
*/
int detachInterrupt(pinnacle_gpio_t pin);

} // namespace cirque_pinnacle_arduino_wrappers

#ifdef __cplusplus
}
#endif

#endif // !defined(ARDUINO)
#endif // CIRQUEPINNACLE_UTILITY_BCM2XXX_INTERRUPT_H_
4 changes: 2 additions & 2 deletions src/utility/bcm2xxx/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CIRQUEPINNACLE_UTILITY_RPI_SPI_H_
#define CIRQUEPINNACLE_UTILITY_RPI_SPI_H_
#ifndef CIRQUEPINNACLE_UTILITY_BCM2XXX_SPI_H_
#define CIRQUEPINNACLE_UTILITY_BCM2XXX_SPI_H_
#ifndef ARDUINO

#include <stdio.h>
Expand Down
1 change: 1 addition & 0 deletions src/utility/includes.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "@PINNACLE_DRIVER@/spi.h"
#include "@PINNACLE_DRIVER@/i2c.h"
#include "@PINNACLE_DRIVER@/time_keeping.h"
#include "@PINNACLE_DRIVER@/interrupt.h"

// clang-format off
// A macro to help execute driver specific code
Expand Down
Loading

0 comments on commit 8b484dd

Please sign in to comment.