Skip to content

Commit

Permalink
expose GPIO & interrupt functions in new digital_io module
Browse files Browse the repository at this point in the history
  • Loading branch information
2bndy5 committed Mar 23, 2024
1 parent 32de7b4 commit 0178a84
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 6 deletions.
32 changes: 26 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,22 @@ if(NOT "${RF24_LINKED_DRIVER}" STREQUAL "")
endif()

# suplement our copy of linux/gpio.h into SPIDEV & RPi driver sources
set(SUPPLEMEN_LINUX_GPIO_H FALSE)
set(SUPPLEMENT_LINUX_GPIO_H FALSE)
if("${RF24_DRIVER}" STREQUAL "RPi" OR "${RF24_DRIVER}" STREQUAL "SPIDEV")
set(SUPPLEMEN_LINUX_GPIO_H TRUE)
set(SUPPLEMENT_LINUX_GPIO_H TRUE)
message(STATUS "Supplementing ${RF24_DRIVER} driver with linux/gpio.h")
# file(COPY src/linux/gpio.h DESTINATION RF24/utility/${RF24_DRIVER}/linux)
list(APPEND RF24_DRIVER_SOURCES src/linux/gpio.h)
endif()

################################# RF24 #############################
set(CMAKE_VERBOSE_MAKEFILE ON)
pybind11_add_module(rf24 src/pyRF24.cpp)
target_include_directories(rf24 PUBLIC
RF24
RF24/utility
RF24/utility/${RF24_DRIVER}
)
if(SUPPLEMEN_LINUX_GPIO_H)
if(SUPPLEMENT_LINUX_GPIO_H)
target_include_directories(rf24 PUBLIC src)
endif()
target_sources(rf24 PUBLIC
Expand All @@ -56,7 +55,7 @@ target_include_directories(rf24_network PUBLIC
RF24/utility
RF24/utility/${RF24_DRIVER}
)
if(SUPPLEMEN_LINUX_GPIO_H)
if(SUPPLEMENT_LINUX_GPIO_H)
target_include_directories(rf24_network PUBLIC src)
endif()
# don't let source look for an installed RF24 lib
Expand Down Expand Up @@ -84,7 +83,7 @@ target_include_directories(rf24_mesh PUBLIC
RF24/utility
RF24/utility/${RF24_DRIVER}
)
if(SUPPLEMEN_LINUX_GPIO_H)
if(SUPPLEMENT_LINUX_GPIO_H)
target_include_directories(rf24_mesh PUBLIC src)
endif()
# don't let source look for an installed RF24 lib
Expand All @@ -104,10 +103,31 @@ target_sources(rf24_mesh PUBLIC
)
apply_flags(rf24_mesh)

################################# Arduino DigitalIO #############################

pybind11_add_module(digital_io src/pyArduinoAPI.cpp)
target_include_directories(digital_io PUBLIC
RF24
RF24/utility
RF24/utility/${RF24_DRIVER}
)
if(SUPPLEMENT_LINUX_GPIO_H)
target_include_directories(digital_io PUBLIC src)
endif()
# don't let source look for an installed RF24 lib
target_compile_definitions(digital_io PUBLIC USE_RF24_LIB_SRC)
target_sources(digital_io PUBLIC
${RF24_DRIVER_SOURCES}
)
apply_flags(digital_io)

################################ INSTALL RULES ####################################
# these are needed for scikit builds since the resulting .so files are copied into
# the binary distribution wheels (.whl files) for python.
install(TARGETS rf24 DESTINATION .)
install(TARGETS rf24_network DESTINATION .)
install(TARGETS rf24_mesh DESTINATION .)
install(TARGETS digital_io DESTINATION .)

# uncomment to show compiler args used in build logs
# set(CMAKE_VERBOSE_MAKEFILE ON)
122 changes: 122 additions & 0 deletions src/pyArduinoAPI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <pybind11/pybind11.h>
#include <pybind11/functional.h>
#include <RF24.h> // The public API will pull in the backend hardware interface for GPIO

namespace py = pybind11;

#ifndef HIGH
static const int HIGH = 1;
#endif
#ifndef LOW
static const int LOW = 0;
#endif

PYBIND11_MODULE(digital_io, m)
{
m.doc() = "Some Arduino-style API used to expose GPIO interface for digital input and outputs";

// ******************************************** General GPIO
m.attr("HIGH") = HIGH;
m.attr("LOW") = LOW;
m.attr("INPUT") = INPUT;
m.attr("OUTPUT") = OUTPUT;

m.def("pinMode", &GPIO::open, R"docstr(
pinMode(pin: int, direction: int) -> None
Initialize a GPIO pin.
:param pin: The pin number to initialize.
:param direction: The direction of the initialized pin.
This only be either `INPUT` or `OUTPUT`.
)docstr",
py::arg("pin"), py::arg("direction"));
m.def("pinClose", &GPIO::close, R"docstr(
pinClose(pin: int) -> None
Deinitialize a GPIO pin.
:param pin: The pin number to deinitialize.
)docstr",
py::arg("pin"));
m.def("digitalWrite", &GPIO::write, R"docstr(
digitalWrite(pin: int, value: int) -> None
Write a digital output value to a GPIO pin.
:param pin: The pin number to manipulate (as an output).
:param value: The value set to the output pin.
This can only be either `HIGH` or `LOW`.
)docstr",
py::arg("pin"), py::arg("value"));

m.def("digitalRead", &GPIO::read, R"docstr(
digitalRead(pin: int) -> int
Read the current value of a given pin.
:param pin: The GPIO input pin to read.
:returns:
``1`` if the pin is currently `HIGH`, ``0`` if the pin is currently `LOW`.
)docstr",
py::arg("pin"));

#ifndef MRAA

// ******************************************** Interrupt support

#ifndef RF24_WIRINGPI
m.def("detachInterrupt", &detachInterrupt, R"docstr(
detachInterrupt(pin: int)
Discontinue watching the given GPIO input ``pin`` for an event. This is similar to
`pinClose()` but also deallocates the background thread used to monitor the pin for
events.
.. note::
This function is only available for the SPIDEV and RPi drivers.
It is not exposed when the pyrf24 package is built (from source) with the MRAA or
wiringPi drivers.
:param pin: The pin number to watch for events described by ``mode``.
:returns:
``1`` if the pin was un-initialized and the background thread was canceled,
``0`` if there was nothing to do.
)docstr",
py::arg("pin"));
#endif // !defined(RF24_WIRINGPI)

m.attr("FALLING") = INT_EDGE_FALLING;
m.attr("RISING") = INT_EDGE_RISING;
m.attr("CHANGE") = INT_EDGE_BOTH;
m.def(
"attachInterrupt", [](rf24_gpio_pin_t pin, int mode, std::function<void(void)>& func) {
return attachInterrupt(pin, mode, *func.target<void (*)()>());
},
R"docstr(
attachInterrupt(pin: int, mode: int, function: Callable[[], None]) -> int
Attach an Interrupt Service Routine (ISR), a callback function, to a GPIO input pin.
.. note::
This function is only available for the SPIDEV, RPi, and wiringPi drivers.
It is not exposed when the pyrf24 package is built (from source) with the MRAA
driver.
:param pin: The pin number to watch for events described by ``mode``.
:param mode: The event type that triggers a call to the given ``function``.
This value can only be `FALLING`, `RISING`, or `CHANGE`.
:param function: The function to call when an event (described by ``mode``) occurs on
the specified ``pin``. This function signature expects no arguments and returns
nothing.
:returns:
``1`` if pin is successfully setup to watch for an event, ``0`` if the given ``mode``
is malformed. If ``0`` is returned, then specified pin remains un-initialized.
)docstr",
py::arg("pin"), py::arg("mode"), py::arg("function"));

#endif // !defined(MRAA)
};
15 changes: 15 additions & 0 deletions src/pyrf24/digital_io.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Callable

INPUT: int = ...
OUTPUT: int = ...
HIGH: int = ...
LOW: int = ...

FALLING: int = ...
RISING: int = ...
CHANGE: int = ...

def pinMode(pin: int, mode: int) -> None: ...
def pinClose(pin: int) -> None: ...
def detachInterrupt(pin: int) -> None: ...
def attachInterrupt(pin, int, mode: int, function: Callable[[], None]) -> int: ...

0 comments on commit 0178a84

Please sign in to comment.