diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 038a476a..0bc89eb4 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -68,6 +68,7 @@ jobs: - "--driver=SPIDEV" - "--driver=MRAA" - "--driver=pigpio" + # disable wiringPi due to needing cross-compiled deps (see comment below) # - "--soc=BCM2835 --driver=wiringPi" env: @@ -83,18 +84,20 @@ jobs: arm-linux-gnueabihf-gcc -v arm-linux-gnueabihf-g++ -v - - name: provide WiringPi - if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi' }} - env: - CC: /usr/bin/arm-linux-gnueabihf-gcc - CFLAGS: "-I /usr/local/include -L /usr/local/lib -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -lcrypt -lrt" - run: | - git clone https://github.com/WiringPi/WiringPi - cd WiringPi - ./build + # NOTE: To cross-compile wiringPi, there needs to be cross-compiled `crypt` and `rt` libs + # Skip cross-compiling wiringPi to avoid this headache. + # - name: provide WiringPi + # if: ${{ matrix.config-options == '--soc=BCM2835 --driver=wiringPi' }} + # env: + # CC: /usr/bin/arm-linux-gnueabihf-gcc + # CFLAGS: "-I /usr/local/include -L /usr/local/lib -marm -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -lcrypt -lrt" + # run: | + # git clone https://github.com/WiringPi/WiringPi + # cd WiringPi + # ./build - name: provide pigpio - if: ${{ matrix.config-options == '--driver=pigpio' || endsWith(matrix.config-options, '--driver=RPi') }} + if: ${{ matrix.config-options == '--driver=pigpio' }} run: | git clone https://github.com/joan2937/pigpio.git cd pigpio @@ -118,7 +121,11 @@ jobs: cd mraa mkdir build cd build - cmake .. -D BUILDSWIGNODE=OFF -D BUILDARCH=arm + cmake .. \ + -D BUILDSWIGNODE=OFF \ + -D BUILDARCH=arm \ + -D CMAKE_INSTALL_PREFIX=/usr/arm-linux-gnueabihf \ + -D CMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/toolchains/armhf.cmake sudo make install sudo bash -c 'echo "/usr/local/lib/arm-linux-gnueabihf" >> /etc/ld.so.conf' sudo ldconfig @@ -133,10 +140,6 @@ jobs: run: sudo make install - name: make linux examples - # compiling examples for wiringPi is broken see issue #669 - # executables linked to wiringPi additionally need to be linked to crypt and shm_open - # interruptConfigure.cpp example is incompatible with MRAA & wiringPi drivers - if: ${{ matrix.config-options != '--soc=BCM2835 --driver=wiringPi' && matrix.config-options != '--driver=MRAA' }} run: | cd examples_linux make diff --git a/CMakeLists.txt b/CMakeLists.txt index 399c98b0..8887fc7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,17 +137,12 @@ if(DEFINED RF24_SPI_SPEED) ) endif() # allow user customization of default GPIO chip used with the SPIDEV driver -if(DEFINED RF24_SPIDEV_GPIO_CHIP) - message(STATUS "RF24_SPIDEV_GPIO_CHIP set to ${RF24_SPIDEV_GPIO_CHIP}") +if(DEFINED RF24_LINUX_GPIO_CHIP) + message(STATUS "RF24_LINUX_GPIO_CHIP set to ${RF24_LINUX_GPIO_CHIP}") target_compile_definitions(${LibTargetName} PUBLIC - RF24_SPIDEV_GPIO_CHIP="${RF24_SPIDEV_GPIO_CHIP}" + RF24_LINUX_GPIO_CHIP="${RF24_LINUX_GPIO_CHIP}" ) endif() -# conditionally disable interruot support (a pigpio specific feature) -if("${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND" OR DEFINED RF24_NO_INTERRUPT) - message(STATUS "Disabling IRQ pin support") - target_compile_definitions(${LibTargetName} PUBLIC RF24_NO_INTERRUPT) -endif() ##################################### diff --git a/Makefile b/Makefile index ada2ffec..84b15d47 100644 --- a/Makefile +++ b/Makefile @@ -21,15 +21,9 @@ OBJECTS=RF24.o ifeq ($(DRIVER), MRAA) OBJECTS+=spi.o gpio.o compatibility.o else ifeq ($(DRIVER), RPi) -OBJECTS+=spi.o bcm2835.o compatibility.o -ifneq (,$(findstring -lpigpio,$(SHARED_LINKER_LIBS))) -OBJECTS+=interrupt.o -endif +OBJECTS+=spi.o bcm2835.o compatibility.o interrupt.o else ifeq ($(DRIVER), SPIDEV) -OBJECTS+=spi.o gpio.o compatibility.o -ifneq (,$(findstring -lpigpio,$(SHARED_LINKER_LIBS))) -OBJECTS+=interrupt.o -endif +OBJECTS+=spi.o gpio.o compatibility.o interrupt.o else ifeq ($(DRIVER), wiringPi) OBJECTS+=spi.o else ifeq ($(DRIVER), pigpio) diff --git a/configure b/configure index 84dd4593..418bbb68 100755 --- a/configure +++ b/configure @@ -3,8 +3,6 @@ CROSS_CC=arm-linux-gnueabihf-gcc CROSS_CXX=arm-linux-gnueabihf-g++ -pigpio_detected=0 - function help { cat < 500) { + cout << "\tIRQ NOT received" << endl; + break; + } /* * IRQ pin is LOW when activated. Otherwise it is always HIGH * Wait in this empty loop until IRQ pin is activated. diff --git a/examples_linux/manualAcknowledgements.cpp b/examples_linux/manualAcknowledgements.cpp index 5f35e483..83bf77ba 100644 --- a/examples_linux/manualAcknowledgements.cpp +++ b/examples_linux/manualAcknowledgements.cpp @@ -32,6 +32,8 @@ using namespace std; #define CSN_PIN 0 #ifdef MRAA #define CE_PIN 15 // GPIO22 +#elif defined(RF24_WIRINGPI) + #define CE_PIN 3 // GPIO22 #else #define CE_PIN 22 #endif diff --git a/examples_linux/multiceiverDemo.cpp b/examples_linux/multiceiverDemo.cpp index 86e8a148..d46463c9 100644 --- a/examples_linux/multiceiverDemo.cpp +++ b/examples_linux/multiceiverDemo.cpp @@ -30,6 +30,8 @@ using namespace std; #define CSN_PIN 0 #ifdef MRAA #define CE_PIN 15 // GPIO22 +#elif defined(RF24_WIRINGPI) + #define CE_PIN 3 // GPIO22 #else #define CE_PIN 22 #endif diff --git a/examples_linux/ncurses/CMakeLists.txt b/examples_linux/ncurses/CMakeLists.txt index d7718e1b..65943dc3 100644 --- a/examples_linux/ncurses/CMakeLists.txt +++ b/examples_linux/ncurses/CMakeLists.txt @@ -18,6 +18,3 @@ target_link_libraries(${example} PUBLIC ${linked_libs} ${CURSES_LIBRARIES} ) -if("${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND" OR DEFINED RF24_NO_INTERRUPT) - target_compile_definitions(${example} PUBLIC RF24_NO_INTERRUPT) -endif() diff --git a/examples_linux/ncurses/scanner_curses.cpp b/examples_linux/ncurses/scanner_curses.cpp index 1c45bf3d..28270198 100644 --- a/examples_linux/ncurses/scanner_curses.cpp +++ b/examples_linux/ncurses/scanner_curses.cpp @@ -33,6 +33,8 @@ using namespace std; #define CSN_PIN 0 #ifdef MRAA #define CE_PIN 15 // GPIO22 +#elif defined(RF24_WIRINGPI) + #define CE_PIN 3 // GPIO22 #else #define CE_PIN 22 #endif diff --git a/examples_linux/readme.md b/examples_linux/readme.md index 4728bd32..0fcad99a 100644 --- a/examples_linux/readme.md +++ b/examples_linux/readme.md @@ -1,3 +1,3 @@ Note: These examples were originally designed for RPi, but should work on any supported Linux platform, with the proper pin configuration. -See http://tmrh20.github.io/RF24 for more information \ No newline at end of file +See http://nRF24.github.io/RF24 for more information \ No newline at end of file diff --git a/examples_linux/scanner.cpp b/examples_linux/scanner.cpp index e50becc5..4f35f4fe 100644 --- a/examples_linux/scanner.cpp +++ b/examples_linux/scanner.cpp @@ -58,6 +58,8 @@ using namespace std; #define CSN_PIN 0 #ifdef MRAA #define CE_PIN 15 // GPIO22 +#elif defined(RF24_WIRINGPI) + #define CE_PIN 3 // GPIO22 #else #define CE_PIN 22 #endif diff --git a/examples_linux/streamingData.cpp b/examples_linux/streamingData.cpp index d63a888e..f7b1c543 100644 --- a/examples_linux/streamingData.cpp +++ b/examples_linux/streamingData.cpp @@ -28,6 +28,8 @@ using namespace std; #define CSN_PIN 0 #ifdef MRAA #define CE_PIN 15 // GPIO22 +#elif defined(RF24_WIRINGPI) + #define CE_PIN 3 // GPIO22 #else #define CE_PIN 22 #endif diff --git a/pyRF24/setup.py b/pyRF24/setup.py index bc9f0f7f..10129b07 100644 --- a/pyRF24/setup.py +++ b/pyRF24/setup.py @@ -35,7 +35,6 @@ os.environ[identifier] = value except FileNotFoundError: # assuming lib was built & installed with CMake - # get LIB_VERSION from library.properties file for Arduino IDE with open(os.path.join(git_dir, "library.properties"), "r", encoding="utf-8") as f: for line in f.read().splitlines(): @@ -44,7 +43,6 @@ # check C++ RF24 lib is installed finally: - # check for possible linker flags set via CFLAGS environment variable for flag in cflags.split("-"): if flag.startswith("L"): @@ -71,13 +69,6 @@ ) ) - # avoid IRQ support if pigpio is not available; link to pigpio if it is found - found_pigpio = False - for symlink_loc in symlink_directory: - if os.path.exists(symlink_loc + "/libpigpio.so"): - found_pigpio = True - # IRQ pin features will be implemented in python via pigpio's python API or RPi.GPIO - cflags += " -DRF24_NO_INTERRUPT" # append any additionally found compiler flags os.environ["CFLAGS"] = cflags @@ -114,7 +105,7 @@ Extension( "RF24", sources=["pyRF24.cpp"], - libraries=["rf24", BOOST_LIB] + (["pigpio"] if found_pigpio else []) + libraries=["rf24", BOOST_LIB], ) ], ) diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt index 656c89b1..d18bce7a 100644 --- a/utility/CMakeLists.txt +++ b/utility/CMakeLists.txt @@ -8,12 +8,14 @@ if ("${RF24_DRIVER}" STREQUAL "wiringPi") # Use wiringPi ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/spi.cpp ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/RF24_arch_config.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/interrupt.h PARENT_SCOPE ) install(FILES ${RF24_DRIVER}/includes.h ${RF24_DRIVER}/spi.h ${RF24_DRIVER}/RF24_arch_config.h + ${RF24_DRIVER}/interrupt.h DESTINATION include/RF24/utility/${RF24_DRIVER} ) elseif("${RF24_DRIVER}" STREQUAL "RPi") # use RPi @@ -23,34 +25,18 @@ elseif("${RF24_DRIVER}" STREQUAL "RPi") # use RPi ${RF24_DRIVER}/spi.h ${RF24_DRIVER}/compatibility.h ${RF24_DRIVER}/RF24_arch_config.h + ${RF24_DRIVER}/interrupt.h DESTINATION include/RF24/utility/${RF24_DRIVER} ) - if(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND" AND NOT DEFINED RF24_NO_INTERRUPT) - set(RF24_LINKED_DRIVER ${LibPIGPIO} PARENT_SCOPE) - message(STATUS "linking to pigpio lib for interrupt functionality") - install(FILES - ${RF24_DRIVER}/interrupt.h - DESTINATION include/RF24/utility/${RF24_DRIVER} - ) - set(RF24_DRIVER_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/bcm2835.c - ${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 - ) - else() - set(RF24_DRIVER_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/bcm2835.c - ${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 - PARENT_SCOPE - ) - endif() + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/bcm2835.c + ${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 + ) elseif("${RF24_DRIVER}" STREQUAL "SPIDEV") # use SPIDEV if(NOT SPIDEV_EXISTS) message(WARNING "Detecting /dev/spidev0.0 failed - continuing anyway. Please make sure SPI is enabled.") @@ -61,34 +47,18 @@ elseif("${RF24_DRIVER}" STREQUAL "SPIDEV") # use SPIDEV ${RF24_DRIVER}/spi.h ${RF24_DRIVER}/compatibility.h ${RF24_DRIVER}/RF24_arch_config.h + ${RF24_DRIVER}/interrupt.h DESTINATION include/RF24/utility/${RF24_DRIVER} ) - if(NOT "${LibPIGPIO}" STREQUAL "LibPIGPIO-NOTFOUND" AND NOT DEFINED RF24_NO_INTERRUPT) - set(RF24_LINKED_DRIVER ${LibPIGPIO} PARENT_SCOPE) - message(STATUS "linking to pigpio lib for interrupt functionality") - install(FILES - ${RF24_DRIVER}/interrupt.h - DESTINATION include/RF24/utility/${RF24_DRIVER} - ) - set(RF24_DRIVER_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/gpio.cpp - ${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 - ) - else() - set(RF24_DRIVER_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h - ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/gpio.cpp - ${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 - PARENT_SCOPE - ) - endif() + set(RF24_DRIVER_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/includes.h + ${CMAKE_CURRENT_LIST_DIR}/${RF24_DRIVER}/gpio.cpp + ${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 + ) elseif("${RF24_DRIVER}" STREQUAL "MRAA") # use MRAA set(RF24_LINKED_DRIVER ${LibMRAA} PARENT_SCOPE) set(RF24_DRIVER_SOURCES diff --git a/utility/MRAA/RF24_arch_config.h b/utility/MRAA/RF24_arch_config.h index 72a783c4..a3c63629 100644 --- a/utility/MRAA/RF24_arch_config.h +++ b/utility/MRAA/RF24_arch_config.h @@ -1,21 +1,14 @@ #ifndef RF24_UTILITY_MRAA_RF24_ARCH_CONFIG_H_ #define RF24_UTILITY_MRAA_RF24_ARCH_CONFIG_H_ +#include // uint16_t +#include // printf +#include // strlen #include "mraa.h" #include "spi.h" #include "gpio.h" #include "compatibility.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - //#include // Precompiled arduino x86 based utiltime for timing functions // GCC a Arduino Missing diff --git a/utility/MRAA/compatibility.cpp b/utility/MRAA/compatibility.cpp index 1b1eac31..68f99b31 100644 --- a/utility/MRAA/compatibility.cpp +++ b/utility/MRAA/compatibility.cpp @@ -1,12 +1,7 @@ -#include "compatibility.h" #include #include +#include "compatibility.h" -/**********************************************************************/ -/** - * This function is added in order to simulate arduino delay() function - * @param milisec - */ void __msleep(int milisec) { struct timespec req; // = {0}; @@ -23,9 +18,6 @@ void __usleep(int microsec) clock_nanosleep(CLOCK_REALTIME, 0, &req, NULL); } -/** - * This function is added in order to simulate arduino millis() function - */ void __start_timer() { } diff --git a/utility/MRAA/compatibility.h b/utility/MRAA/compatibility.h index 8e55ae8b..3658033b 100644 --- a/utility/MRAA/compatibility.h +++ b/utility/MRAA/compatibility.h @@ -12,9 +12,6 @@ extern "C" { #endif -#include -#include -#include #include void __msleep(int milisec); diff --git a/utility/MRAA/gpio.h b/utility/MRAA/gpio.h index 4252d3f2..7d343f73 100644 --- a/utility/MRAA/gpio.h +++ b/utility/MRAA/gpio.h @@ -1,13 +1,11 @@ /** - * @file spi.h + * @file gpio.h * @author TMRh20 2015 * Class declaration for GPIO helper files */ #ifndef RF24_UTILITY_MRAA_GPIO_H_ #define RF24_UTILITY_MRAA_GPIO_H_ -#include -#include #include "mraa.hpp" class GPIO diff --git a/utility/MRAA/spi.h b/utility/MRAA/spi.h index a27fdeb1..f5fb246c 100644 --- a/utility/MRAA/spi.h +++ b/utility/MRAA/spi.h @@ -10,7 +10,6 @@ * Class declaration for SPI helper files */ -#include #include "mraa.h" #include "mraa.hpp" diff --git a/utility/RPi/RF24_arch_config.h b/utility/RPi/RF24_arch_config.h index bdd70364..bb74c600 100644 --- a/utility/RPi/RF24_arch_config.h +++ b/utility/RPi/RF24_arch_config.h @@ -3,13 +3,9 @@ #define RF24_LINUX -#include -#include -#include -#include -#include -#include - +#include // uint8_t +#include // printf +#include // strlen #include "bcm2835.h" #include "spi.h" #include "compatibility.h" @@ -31,6 +27,14 @@ typedef uint8_t rf24_gpio_pin_t; #define RF24_PIN_INVALID 0xFF +#ifndef RF24_LINUX_GPIO_CHIP + /** + * The default GPIO chip to use. Defaults to `/dev/gpiochip4` (for RPi5). + * Falls back to `/dev/gpiochip0` if this value is somehow incorrect. + */ + #define RF24_LINUX_GPIO_CHIP "/dev/gpiochip4" +#endif + #define PSTR(x) (x) #define printf_P printf #define strlen_P strlen diff --git a/utility/RPi/compatibility.cpp b/utility/RPi/compatibility.cpp index 7363ec28..1573eddb 100644 --- a/utility/RPi/compatibility.cpp +++ b/utility/RPi/compatibility.cpp @@ -1,5 +1,9 @@ -#include "compatibility.h" #include +#include "compatibility.h" + +#ifdef __cplusplus +extern "C" { +#endif auto start = std::chrono::steady_clock::now(); @@ -9,3 +13,7 @@ uint32_t millis(void) return std::chrono::duration_cast(end - start).count(); } + +#ifdef __cplusplus +} +#endif diff --git a/utility/RPi/compatibility.h b/utility/RPi/compatibility.h index 58562bea..0a17471a 100644 --- a/utility/RPi/compatibility.h +++ b/utility/RPi/compatibility.h @@ -1,14 +1,13 @@ #ifndef RF24_UTILITY_RPI_COMPATIBLITY_H_ #define RF24_UTILITY_RPI_COMPATIBLITY_H_ -#include #include -#include #ifdef __cplusplus extern "C" { #endif -extern uint32_t millis(void); + +uint32_t millis(void); #ifdef __cplusplus } diff --git a/utility/RPi/includes.h b/utility/RPi/includes.h index d73f5cf6..e5eb025a 100644 --- a/utility/RPi/includes.h +++ b/utility/RPi/includes.h @@ -3,10 +3,9 @@ #define RF24_RPi +#include // memcpy() used in RF24.cpp #include "RPi/bcm2835.h" #include "RPi/RF24_arch_config.h" -#ifndef RF24_NO_INTERRUPT - #include "RPi/interrupt.h" -#endif +#include "RPi/interrupt.h" #endif // RF24_UTILITY_INCLUDES_H_ diff --git a/utility/RPi/interrupt.cpp b/utility/RPi/interrupt.cpp index 31a5f894..a2e6ea12 100644 --- a/utility/RPi/interrupt.cpp +++ b/utility/RPi/interrupt.cpp @@ -1,19 +1,191 @@ -/* -Interrupt functions -*/ - +/** + * Interrupt implementations + */ +#include +#include // close() +#include // open() +#include // ioctl() +#include // errno, strerror() +#include // std::string, strcpy() +#include +#include #include "interrupt.h" -#include -int attachInterrupt(int pin, int mode, void (*function)(void)) +#ifdef __cplusplus +extern "C" { +#endif + +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); + } + } +} + +void IrqChipCache::closeDevice() +{ + if (fd >= 0) { + close(fd); + fd = -1; + } +} + +IrqChipCache::IrqChipCache() { - gpioInitialise(); - return gpioSetISRFunc(pin, mode, 0, (gpioISRFunc_t)function); } -int detachInterrupt(int pin) +IrqChipCache::~IrqChipCache() { - return gpioSetISRFunc(pin, 0, 0, NULL); + 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; + pinCache->function(); + } + pthread_testcancel(); + } + return NULL; +} + +int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)) +{ + // ensure pin is not already being used in a separate thread + detachInterrupt(pin); + + try { + irqChipCache.openDevice(); + } + catch (IRQException& exc) { + 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; + switch (mode) { + case INT_EDGE_BOTH: + case INT_EDGE_RISING: + case INT_EDGE_FALLING: + request.config.flags |= mode; + 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.function = function; + 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; + } + + // 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(rf24_gpio_pin_t pin) +{ + std::map::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 + close(cachedPin->second.fd); + irqCache.erase(cachedPin); + return 1; } void rfNoInterrupts() @@ -22,4 +194,8 @@ void rfNoInterrupts() void rfInterrupts() { -} \ No newline at end of file +} + +#ifdef __cplusplus +} +#endif diff --git a/utility/RPi/interrupt.h b/utility/RPi/interrupt.h index 00e6dca5..7fe7dcf0 100644 --- a/utility/RPi/interrupt.h +++ b/utility/RPi/interrupt.h @@ -1,48 +1,86 @@ -/* -Interrupt functions -*/ -#ifndef __RF24_INTERRUPT_H__ -#define __RF24_INTERRUPT_H__ +/** + * Interrupt functions + */ +#ifndef RF24_UTILITY_RPI_INTERRUPT_H_ +#define RF24_UTILITY_RPI_INTERRUPT_H_ -#include "RF24_arch_config.h" -#include +#include // pthread_t +#include +#include // GPIO_V2_LINE_FLAG_EDGE_*** +#include "RF24_arch_config.h" // rf24_gpio_pin_t -#define INT_EDGE_SETUP 0 -#define INT_EDGE_FALLING FALLING_EDGE -#define INT_EDGE_RISING RISING_EDGE -#define INT_EDGE_BOTH EITHER_EDGE +#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 -/* - * attachInterrupt (Original: wiringPiISR): - * Pi Specific. - * Take the details and create an interrupt handler that will do a call- - * back to the user supplied function. - ********************************************************************************* - */ -extern int attachInterrupt(int pin, int mode, void (*function)(void)); - -/* - * detachInterrupt: - * Pi Specific detachInterrupt. - * Will cancel the interrupt thread, close the filehandle and - * setting wiringPi back to 'none' mode. - ********************************************************************************* - */ -extern int detachInterrupt(int pin); +/** Specific exception for IRQ errors */ +class IRQException : public std::runtime_error +{ +public: + explicit IRQException(const std::string& msg) + : std::runtime_error(msg) + { + } +}; + +/// 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; + + /// 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(); -/* Deprecated, no longer functional + /// 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 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. */ -extern void rfNoInterrupts(); +int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)); -/* Deprecated, no longer functional +/** + * Will cancel the interrupt thread, close the filehandle and release the pin. */ -extern void rfInterrupts(); +int detachInterrupt(rf24_gpio_pin_t pin); + +/** Deprecated, no longer functional */ +void rfNoInterrupts(); + +/** Deprecated, no longer functional */ +void rfInterrupts(); #ifdef __cplusplus } #endif -#endif +#endif // RF24_UTILITY_RPI_INTERRUPT_H_ diff --git a/utility/SPIDEV/RF24_arch_config.h b/utility/SPIDEV/RF24_arch_config.h index 219bc051..33280d4e 100644 --- a/utility/SPIDEV/RF24_arch_config.h +++ b/utility/SPIDEV/RF24_arch_config.h @@ -11,15 +11,13 @@ #define RF24_LINUX -#include +#include // uint16_t +#include // printf +#include // strlen #include "spi.h" #include "gpio.h" #include "compatibility.h" -#include -#include -#include -#include -#include +#include "interrupt.h" //#define RF24_SPI_SPEED RF24_SPIDEV_SPEED diff --git a/utility/SPIDEV/compatibility.cpp b/utility/SPIDEV/compatibility.cpp index 20107d85..14b0b518 100644 --- a/utility/SPIDEV/compatibility.cpp +++ b/utility/SPIDEV/compatibility.cpp @@ -1,15 +1,15 @@ +#include +#include #include "compatibility.h" +#ifdef __cplusplus +extern "C" { +#endif + long long mtime, seconds, useconds; //static struct timeval start, end; //struct timespec start, end; -#include -#include -/**********************************************************************/ -/** - * This function is added in order to simulate arduino delay() function - * @param milisec - */ + void __msleep(int milisec) { struct timespec req; // = {0}; @@ -46,3 +46,7 @@ uint32_t __millis() return std::chrono::duration_cast(end - start).count(); } + +#ifdef __cplusplus +} +#endif diff --git a/utility/SPIDEV/compatibility.h b/utility/SPIDEV/compatibility.h index 70153233..6158d0ad 100644 --- a/utility/SPIDEV/compatibility.h +++ b/utility/SPIDEV/compatibility.h @@ -14,9 +14,6 @@ extern "C" { #endif #include // for uintXX_t types -#include -#include -#include void __msleep(int milisec); diff --git a/utility/SPIDEV/gpio.cpp b/utility/SPIDEV/gpio.cpp index f27e2c9b..e153444b 100644 --- a/utility/SPIDEV/gpio.cpp +++ b/utility/SPIDEV/gpio.cpp @@ -20,7 +20,6 @@ typedef int gpio_fd; // for readability std::map cachedPins; struct gpio_v2_line_request request; struct gpio_v2_line_values data; -struct gpiochip_info chipMeta; void GPIOChipCache::openDevice() { @@ -46,26 +45,9 @@ void GPIOChipCache::closeDevice() GPIOChipCache::GPIOChipCache() { - try { - openDevice(); - } - catch (GPIOException& exc) { - chip = "/dev/gpiochip0"; - openDevice(); - } request.num_lines = 1; strcpy(request.consumer, "RF24 lib"); data.mask = 1ULL; // only change value for specified pin - - // cache chip info - int ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chipMeta); - if (ret < 0) { - std::string msg = "Could not gather info about "; - msg += chip; - throw GPIOException(msg); - return; - } - closeDevice(); // in case other apps want to access it } GPIOChipCache::~GPIOChipCache() @@ -91,7 +73,26 @@ GPIO::~GPIO() void GPIO::open(rf24_gpio_pin_t port, int DDR) { - if (port > chipMeta.lines) { + try { + gpioCache.openDevice(); + } + catch (GPIOException& exc) { + gpioCache.chip = "/dev/gpiochip0"; + gpioCache.openDevice(); + } + + // get chip info + gpiochip_info info; + memset(&info, 0, sizeof(info)); + int ret = ioctl(gpioCache.fd, GPIO_GET_CHIPINFO_IOCTL, &info); + if (ret < 0) { + std::string msg = "Could not gather info about "; + msg += gpioCache.chip; + throw GPIOException(msg); + return; + } + + if (port > info.lines) { std::string msg = "pin number " + std::to_string(port) + " not available for " + gpioCache.chip; throw GPIOException(msg); return; @@ -107,8 +108,6 @@ void GPIO::open(rf24_gpio_pin_t port, int DDR) request.fd = pin->second; } - gpioCache.openDevice(); - int ret; if (request.fd <= 0) { ret = ioctl(gpioCache.fd, GPIO_V2_GET_LINE_IOCTL, &request); if (ret == -1 || request.fd <= 0) { @@ -135,8 +134,14 @@ void GPIO::open(rf24_gpio_pin_t port, int DDR) void GPIO::close(rf24_gpio_pin_t port) { - // This is not really used in RF24 convention (designed for embedded apps). - // Instead rely on gpioCache destructor (see above) + std::map::iterator pin = cachedPins.find(port); + if (pin == cachedPins.end()) { + return; + } + if (pin->second > 0) { + ::close(pin->second); + } + cachedPins.erase(pin); } int GPIO::read(rf24_gpio_pin_t port) diff --git a/utility/SPIDEV/gpio.h b/utility/SPIDEV/gpio.h index 006d5d2c..e780244d 100644 --- a/utility/SPIDEV/gpio.h +++ b/utility/SPIDEV/gpio.h @@ -13,23 +13,22 @@ #ifndef RF24_UTILITY_SPIDEV_GPIO_H_ #define RF24_UTILITY_SPIDEV_GPIO_H_ -#include -#include #include #include +#include // gpiochip_info typedef uint16_t rf24_gpio_pin_t; #define RF24_PIN_INVALID 0xFFFF -#ifndef RF24_SPIDEV_GPIO_CHIP +#ifndef RF24_LINUX_GPIO_CHIP /** * The default GPIO chip to use. Defaults to `/dev/gpiochip4` (for RPi5). * Falls back to `/dev/gpiochip0` if this value is somehow incorrect. */ - #define RF24_SPIDEV_GPIO_CHIP "/dev/gpiochip4" + #define RF24_LINUX_GPIO_CHIP "/dev/gpiochip4" #endif -/** Specific exception for SPI errors */ +/** Specific exception for GPIO errors */ class GPIOException : public std::runtime_error { public: @@ -43,7 +42,7 @@ class GPIOException : public std::runtime_error /// This struct's destructor should close any cached GPIO pin requests' file descriptors. struct GPIOChipCache { - const char* chip = RF24_SPIDEV_GPIO_CHIP; + const char* chip = RF24_LINUX_GPIO_CHIP; int fd = -1; /// Open the File Descriptor for the GPIO chip diff --git a/utility/SPIDEV/includes.h b/utility/SPIDEV/includes.h index fd82fd5d..8473f541 100644 --- a/utility/SPIDEV/includes.h +++ b/utility/SPIDEV/includes.h @@ -3,9 +3,7 @@ #define RF24_SPIDEV +#include // memcpy() used in RF24.cpp #include "SPIDEV/RF24_arch_config.h" -#ifndef RF24_NO_INTERRUPT - #include "SPIDEV/interrupt.h" -#endif #endif // RF24_UTILITY_INCLUDES_H_ diff --git a/utility/SPIDEV/interrupt.cpp b/utility/SPIDEV/interrupt.cpp index 4893dc51..98a28136 100644 --- a/utility/SPIDEV/interrupt.cpp +++ b/utility/SPIDEV/interrupt.cpp @@ -1,19 +1,171 @@ -/* -Interrupt functions -*/ - +/** + * Interrupt implementations + */ +#include +#include // close() +#include // open() +#include // ioctl() +#include // errno, strerror() +#include // std::string, strcpy() +#include +#include #include "interrupt.h" -#include +#include "gpio.h" // GPIOChipCache, GPIOException + +#ifdef __cplusplus +extern "C" { +#endif + +static pthread_mutex_t irq_mutex = PTHREAD_MUTEX_INITIALIZER; +std::map irqCache; + +struct IrqChipCache : public GPIOChipCache +{ + IrqChipCache() : GPIOChipCache() {}; + ~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; -int attachInterrupt(int pin, int mode, void (*function)(void)) +void* poll_irq(void* arg) { - gpioInitialise(); - return gpioSetISRFunc(pin, mode, 0, (gpioISRFunc_t)function); + 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; + pinCache->function(); + } + pthread_testcancel(); + } + return NULL; +} + +int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)) +{ + // ensure pin is not already being used in a separate thread + detachInterrupt(pin); + GPIO::close(pin); + + try { + irqChipCache.openDevice(); + } + catch (GPIOException& exc) { + 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 + struct 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; + switch (mode) { + case INT_EDGE_BOTH: + case INT_EDGE_RISING: + case INT_EDGE_FALLING: + request.config.flags |= mode; + 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.function = function; + 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; + } + + // 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(int pin) +int detachInterrupt(rf24_gpio_pin_t pin) { - return gpioSetISRFunc(pin, 0, 0, NULL); + std::map::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 + close(cachedPin->second.fd); + irqCache.erase(cachedPin); + return 1; } void rfNoInterrupts() @@ -23,3 +175,7 @@ void rfNoInterrupts() void rfInterrupts() { } + +#ifdef __cplusplus +} +#endif diff --git a/utility/SPIDEV/interrupt.h b/utility/SPIDEV/interrupt.h index 00e6dca5..8a6e80bf 100644 --- a/utility/SPIDEV/interrupt.h +++ b/utility/SPIDEV/interrupt.h @@ -1,48 +1,62 @@ -/* -Interrupt functions -*/ -#ifndef __RF24_INTERRUPT_H__ -#define __RF24_INTERRUPT_H__ +/** + * Interrupt functions + */ +#ifndef RF24_UTILITY_SPIDEV_INTERRUPT_H_ +#define RF24_UTILITY_SPIDEV_INTERRUPT_H_ -#include "RF24_arch_config.h" -#include +#include // pthread_t +#include +#include "gpio.h" // rf24_gpio_pin_t -#define INT_EDGE_SETUP 0 -#define INT_EDGE_FALLING FALLING_EDGE -#define INT_EDGE_RISING RISING_EDGE -#define INT_EDGE_BOTH EITHER_EDGE +#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 -/* - * attachInterrupt (Original: wiringPiISR): - * Pi Specific. - * Take the details and create an interrupt handler that will do a call- - * back to the user supplied function. - ********************************************************************************* - */ -extern int attachInterrupt(int pin, int mode, void (*function)(void)); - -/* - * detachInterrupt: - * Pi Specific detachInterrupt. - * Will cancel the interrupt thread, close the filehandle and - * setting wiringPi back to 'none' mode. - ********************************************************************************* +/** 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 fd = 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. */ -extern int detachInterrupt(int pin); +int attachInterrupt(rf24_gpio_pin_t pin, int mode, void (*function)(void)); -/* Deprecated, no longer functional +/** + * Will cancel the interrupt thread, close the filehandle and release the pin. */ -extern void rfNoInterrupts(); +int detachInterrupt(rf24_gpio_pin_t pin); -/* Deprecated, no longer functional - */ -extern void rfInterrupts(); +/** Deprecated, no longer functional */ +void rfNoInterrupts(); + +/** Deprecated, no longer functional */ +void rfInterrupts(); #ifdef __cplusplus } #endif -#endif +#endif // RF24_UTILITY_SPIDEV_INTERRUPT_H_ diff --git a/utility/SPIDEV/spi.cpp b/utility/SPIDEV/spi.cpp index 4fb0113b..4a5ba903 100644 --- a/utility/SPIDEV/spi.cpp +++ b/utility/SPIDEV/spi.cpp @@ -10,15 +10,15 @@ * www.kernel.org/doc/Documentation/spi/spidev_test.c */ -#include "spi.h" - #include #include -#include #include -#include #include #include +#include +#include + +#include "spi.h" #define RF24_SPIDEV_BITS 8 @@ -51,14 +51,13 @@ void SPI::begin(int busNo, uint32_t spi_speed) this->fd = open(device, O_RDWR); if (this->fd < 0) { - throw SPIException("can't open device"); + std::string msg = "[SPI::begin] Can't open device "; + msg += device; + msg += "; "; + msg += strerror(errno); + throw SPIException(msg); } - /* - { - perror("can't open device"); - abort(); - }*/ this->spiIsInitialized = true; init(spi_speed); } @@ -74,62 +73,52 @@ void SPI::init(uint32_t speed) */ ret = ioctl(this->fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) { - throw SPIException("cant set WR spi mode"); + std::string msg = "[SPI::init] Can't set WR spi mode; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set spi mode"); - abort(); - }*/ ret = ioctl(this->fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) { - throw SPIException("can't set RD spi mode"); + std::string msg = "[SPI::init] Can't set RD spi mode; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set spi mode"); - abort(); - }*/ /* * bits per word */ ret = ioctl(this->fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) { - throw SPIException("can't set WR bits per word"); + std::string msg = "[SPI::init] Can't set WR bits per word; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set bits per word"); - abort(); - }*/ ret = ioctl(this->fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) { - throw SPIException("can't set RD bits per word"); + std::string msg = "[SPI::init] Can't set RD bits per word; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set bits per word"); - abort(); - }*/ + /* * max speed hz */ ret = ioctl(this->fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) { - throw SPIException("can't WR set max speed hz"); + std::string msg = "[SPI::init] Can't set max WR speed hz; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set max speed hz"); - abort(); - }*/ ret = ioctl(this->fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) { - throw SPIException("can't RD set max speed hz"); + std::string msg = "[SPI::init] Can't set max RD speed hz; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't set max speed hz"); - abort(); - }*/ + _spi_speed = speed; } @@ -149,12 +138,10 @@ uint8_t SPI::transfer(uint8_t tx) int ret; ret = ioctl(this->fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) { - throw SPIException("can't send spi message"); + std::string msg = "[SPI::transfer] Can't send spi message; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't send spi message"); - abort(); - }*/ return rx; } @@ -174,12 +161,10 @@ void SPI::transfernb(char* tbuf, char* rbuf, uint32_t len) int ret; ret = ioctl(this->fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) { - throw SPIException("can't send spi message"); + std::string msg = "[SPI::transfernb] Can't send spi message; "; + msg += strerror(errno); + throw SPIException(msg); } - /*{ - perror("can't send spi message"); - abort(); - }*/ } void SPI::transfern(char* buf, uint32_t len) diff --git a/utility/SPIDEV/spi.h b/utility/SPIDEV/spi.h index 63ef5e12..8dcc291c 100644 --- a/utility/SPIDEV/spi.h +++ b/utility/SPIDEV/spi.h @@ -10,10 +10,12 @@ #ifndef RF24_UTILITY_SPIDEV_SPI_H_ #define RF24_UTILITY_SPIDEV_SPI_H_ -#include +#include #include -#include "../../RF24_config.h" // This is cyclical and should be fixed +#ifndef RF24_SPI_SPEED + #define RF24_SPI_SPEED 10000000 +#endif /** Specific exception for SPI errors */ class SPIException : public std::runtime_error diff --git a/utility/Template/compatibility.h b/utility/Template/compatibility.h index 1441302e..2408b073 100644 --- a/utility/Template/compatibility.h +++ b/utility/Template/compatibility.h @@ -17,9 +17,7 @@ extern "C" { #endif -#include -#include -#include +#include void __msleep(int milisec); @@ -27,7 +25,7 @@ void __usleep(int milisec); void __start_timer(); -long __millis(); +uint32_t __millis(); #ifdef __cplusplus } diff --git a/utility/Template/includes.h b/utility/Template/includes.h index 064bfe2a..2dd24123 100644 --- a/utility/Template/includes.h +++ b/utility/Template/includes.h @@ -16,12 +16,12 @@ /** * Define a specific platform for this configuration */ -#define RF24_BBB +#define RF24_TEMPLATE /** * Load the correct configuration for this platform */ -#include "BBB/RF24_arch_config.h" +#include "Template/RF24_arch_config.h" /**@}*/ diff --git a/utility/Template/spi.h b/utility/Template/spi.h index ddb8b750..22ac04fe 100644 --- a/utility/Template/spi.h +++ b/utility/Template/spi.h @@ -12,19 +12,7 @@ #ifndef RF24_UTILITY_TEMPLATE_SPI_H_ #define RF24_UTILITY_TEMPLATE_SPI_H_ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; #ifndef DOXYGEN_FORCED // exclude this line from the docs to prevent displaying in the list of classes @@ -71,17 +59,14 @@ class SPI #endif private: - /** Default SPI device */ - string device; + /** SPI bus */ + int bus; /** SPI Mode set */ uint8_t mode; - /** word size*/ + /** SPI word size */ uint8_t bits; - /** Set SPI speed*/ + /** SPI speed */ uint32_t speed; - int fd; - - void init(); }; /**@}*/ diff --git a/utility/pigpio/RF24_arch_config.h b/utility/pigpio/RF24_arch_config.h index f5acdf4a..c310034a 100644 --- a/utility/pigpio/RF24_arch_config.h +++ b/utility/pigpio/RF24_arch_config.h @@ -6,20 +6,17 @@ version 2 as published by the Free Software Foundation. */ -#ifndef __ARCH_CONFIG_H__ -#define __ARCH_CONFIG_H__ +#ifndef RF24_UTILITY_PIGPIO_RF24_ARCH_CONFIG_H_ +#define RF24_UTILITY_PIGPIO_RF24_ARCH_CONFIG_H_ #define RF24_LINUX -#include +#include // uint16_t +#include // printf +#include // strlen #include "spi.h" #include "gpio.h" #include "compatibility.h" -#include -#include -#include -#include -#include //#define RF24_SPI_SPEED RF24_SPIDEV_SPEED @@ -72,4 +69,4 @@ typedef uint8_t rf24_gpio_pin_t; #define delayMicroseconds(usec) __usleep(usec) #define millis() __millis() -#endif // __ARCH_CONFIG_H__ +#endif // RF24_UTILITY_PIGPIO_RF24_ARCH_CONFIG_H_ diff --git a/utility/pigpio/compatibility.cpp b/utility/pigpio/compatibility.cpp index a9deb311..65ba305e 100644 --- a/utility/pigpio/compatibility.cpp +++ b/utility/pigpio/compatibility.cpp @@ -1,15 +1,11 @@ +#include +#include #include "compatibility.h" long long mtime, seconds, useconds; //static struct timeval start, end; //struct timespec start, end; -#include -#include -/**********************************************************************/ -/** - * This function is added in order to simulate arduino delay() function - * @param milisec - */ + void __msleep(int milisec) { struct timespec req; // = {0}; diff --git a/utility/pigpio/compatibility.h b/utility/pigpio/compatibility.h index fff69d2a..25cbd052 100644 --- a/utility/pigpio/compatibility.h +++ b/utility/pigpio/compatibility.h @@ -1,23 +1,15 @@ /* - * File: compatiblity.h - * Author: purinda - * - * Created on 24 June 2012, 3:08 PM - * patch for safer monotonic clock & millis() correction for 64bit LDV 2018 + * Time keeping functions */ +#ifndef RF24_UTILITY_PIGPIO_COMPATIBLITY_H_ +#define RF24_UTILITY_PIGPIO_COMPATIBLITY_H_ -#ifndef COMPATIBLITY_H -#define COMPATIBLITY_H +#include // for uintXX_t types #ifdef __cplusplus extern "C" { #endif -#include // for uintXX_t types -#include -#include -#include - void __msleep(int milisec); void __usleep(int milisec); @@ -30,4 +22,4 @@ uint32_t __millis(); } #endif -#endif /* COMPATIBLITY_H */ +#endif /* RF24_UTILITY_PIGPIO_COMPATIBLITY_H_ */ diff --git a/utility/pigpio/gpio.cpp b/utility/pigpio/gpio.cpp index f57c3e95..3c9a63e1 100644 --- a/utility/pigpio/gpio.cpp +++ b/utility/pigpio/gpio.cpp @@ -1,9 +1,8 @@ /* * GPIO Functions */ - -#include "gpio.h" #include +#include "gpio.h" bool initialized = 0; diff --git a/utility/pigpio/gpio.h b/utility/pigpio/gpio.h index 8247183a..8fe245c0 100644 --- a/utility/pigpio/gpio.h +++ b/utility/pigpio/gpio.h @@ -2,14 +2,12 @@ * */ -#ifndef RF24_GPIO_H -#define RF24_GPIO_H +#ifndef RF24_UTILITY_PIGPIO_GPIO_H_ +#define RF24_UTILITY_PIGPIO_GPIO_H_ -#include -#include #include -/** Specific exception for SPI errors */ +/** Specific exception for GPIO errors */ class GPIOException : public std::runtime_error { public: @@ -19,21 +17,6 @@ class GPIOException : public std::runtime_error } }; -/** - * @file gpio.h - * @cond HIDDEN_SYMBOLS - * Class declaration for GPIO helper files - */ - -/** - * Example GPIO.h file - * - * @defgroup GPIO GPIO Example - * - * See RF24_arch_config.h for additional information - * @{ - */ - class GPIO { public: @@ -76,8 +59,5 @@ class GPIO private: }; -/** - * @endcond - */ -/**@}*/ -#endif /* H */ + +#endif /* RF24_UTILITY_PIGPIO_GPIO_H_ */ diff --git a/utility/pigpio/includes.h b/utility/pigpio/includes.h index b7e76d98..9f4c2e8e 100644 --- a/utility/pigpio/includes.h +++ b/utility/pigpio/includes.h @@ -1,11 +1,10 @@ -#ifndef __RF24_INCLUDES_H__ -#define __RF24_INCLUDES_H__ +#ifndef RF24_UTILITY_INCLUDES_H_ +#define RF24_UTILITY_INCLUDES_H_ #define RF24_PIGPIO +#include // memcpy() used in RF24.cpp #include "pigpio/RF24_arch_config.h" -#ifndef RF24_NO_INTERRUPT - #include "pigpio/interrupt.h" -#endif +#include "pigpio/interrupt.h" #endif diff --git a/utility/pigpio/interrupt.cpp b/utility/pigpio/interrupt.cpp index 3b970c37..ad89af49 100644 --- a/utility/pigpio/interrupt.cpp +++ b/utility/pigpio/interrupt.cpp @@ -1,9 +1,12 @@ -/* - -*/ - -#include "interrupt.h" +/** + * Interrupt implementation wrapped from pigpio library + */ #include +#include "interrupt.h" + +#ifdef __cplusplus +extern "C" { +#endif int attachInterrupt(int pin, int mode, void (*function)(void)) { @@ -22,4 +25,8 @@ void rfNoInterrupts() void rfInterrupts() { -} \ No newline at end of file +} + +#ifdef __cplusplus +} +#endif diff --git a/utility/pigpio/interrupt.h b/utility/pigpio/interrupt.h index 8acdf920..80272cdc 100644 --- a/utility/pigpio/interrupt.h +++ b/utility/pigpio/interrupt.h @@ -1,18 +1,11 @@ -/* -Interrupts functions extruded from wiringPi library by Oitzu. - -wiringPi Copyright (c) 2012 Gordon Henderson -https://projects.drogon.net/raspberry-pi/wiringpi -wiringPi is free software: GNU Lesser General Public License -see -*/ -#ifndef __RF24_INTERRUPT_H__ -#define __RF24_INTERRUPT_H__ - -#include "RF24_arch_config.h" +/** + * Interrupt functions wrapped from pigpio library + */ +#ifndef RF24_UTILITY_PIGPIO_INTERRUPT_H_ +#define RF24_UTILITY_PIGPIO_INTERRUPT_H_ + #include -#define INT_EDGE_SETUP 0 #define INT_EDGE_FALLING FALLING_EDGE #define INT_EDGE_RISING RISING_EDGE #define INT_EDGE_BOTH EITHER_EDGE @@ -21,33 +14,17 @@ see extern "C" { #endif -/* - * attachInterrupt (Original: wiringPiISR): - * Pi Specific. - * Take the details and create an interrupt handler that will do a call- - * back to the user supplied function. - ********************************************************************************* - */ -extern int attachInterrupt(int pin, int mode, void (*function)(void)); - -/* - * detachInterrupt: - * Pi Specific detachInterrupt. - * Will cancel the interrupt thread, close the filehandle and - * setting wiringPi back to 'none' mode. - ********************************************************************************* - */ -extern int detachInterrupt(int pin); +int attachInterrupt(int pin, int mode, void (*function)(void)); -/* Deprecated, no longer functional - */ -extern void rfNoInterrupts(); +int detachInterrupt(int pin); -/* Deprecated, no longer functional - */ -extern void rfInterrupts(); +/* Deprecated, no longer functional */ +void rfNoInterrupts(); + +/* Deprecated, no longer functional */ +void rfInterrupts(); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif // RF24_UTILITY_PIGPIO_INTERRUPT_H_ \ No newline at end of file diff --git a/utility/pigpio/spi.cpp b/utility/pigpio/spi.cpp index 6768f261..cb982426 100644 --- a/utility/pigpio/spi.cpp +++ b/utility/pigpio/spi.cpp @@ -2,8 +2,8 @@ * */ -#include "spi.h" #include +#include "spi.h" SPI::SPI() { diff --git a/utility/pigpio/spi.h b/utility/pigpio/spi.h index 1af63b8a..12f8f06b 100644 --- a/utility/pigpio/spi.h +++ b/utility/pigpio/spi.h @@ -2,29 +2,12 @@ * */ -#ifndef SPI_H -#define SPI_H +#ifndef RF24_UTILITY_PIGPIO_SPI_H_ +#define RF24_UTILITY_PIGPIO_SPI_H_ -/** - * @file spi.h - * \cond HIDDEN_SYMBOLS - * Class declaration for SPI helper files - */ - -/** - * Example GPIO.h file - * - * @defgroup SPI SPI Example - * - * See RF24_arch_config.h for additional information - * @{ - */ - -#include +#include #include -#include "../../RF24_config.h" - /** Specific exception for SPI errors */ class SPIException : public std::runtime_error { @@ -82,8 +65,4 @@ class SPI void init(uint32_t spi_speed); }; -/** - * \endcond - */ -/*@}*/ -#endif /* SPI_H */ +#endif /* RF24_UTILITY_PIGPIO_SPI_H_ */ diff --git a/utility/wiringPi/RF24_arch_config.h b/utility/wiringPi/RF24_arch_config.h index 342809f7..b23aad2d 100644 --- a/utility/wiringPi/RF24_arch_config.h +++ b/utility/wiringPi/RF24_arch_config.h @@ -11,14 +11,11 @@ #define RF24_LINUX -#include +#include // uint16_t +#include // printf +#include // strlen #include "spi.h" #include "wiringPi.h" -#include -#include -#include -#include -#include #define _BV(x) (1 << (x)) #define _SPI spi diff --git a/utility/wiringPi/includes.h b/utility/wiringPi/includes.h index 195c0eb5..d1012e54 100644 --- a/utility/wiringPi/includes.h +++ b/utility/wiringPi/includes.h @@ -1,19 +1,10 @@ -/** - * @file includes.h - * Configuration defines for RF24/Linux - */ - #ifndef RF24_UTILITY_INCLUDES_H_ #define RF24_UTILITY_INCLUDES_H_ -/** - * Define RF24_WIRINGPI configuration for RaspberryPi platform - */ #define RF24_WIRINGPI -/** - * Load the correct configuration for this platform - */ +#include // memcpy() used in RF24.cpp #include "wiringPi/RF24_arch_config.h" +#include "wiringPi/interrupt.h" #endif // RF24_UTILITY_INCLUDES_H_ diff --git a/utility/wiringPi/interrupt.h b/utility/wiringPi/interrupt.h new file mode 100644 index 00000000..8001fe6c --- /dev/null +++ b/utility/wiringPi/interrupt.h @@ -0,0 +1,14 @@ +/** + * Interrupt functions wrapped from pigpio library + */ +#ifndef RF24_UTILITY_WIRINGPI_INTERRUPT_H__ +#define RF24_UTILITY_WIRINGPI_INTERRUPT_H__ + +#include + +#define attachInterrupt wiringPiISR + +// wiringPi has no detachInterrupt() implementation. Therefor, we will not define it here. +// Invoking detachInterrupt() with this wiringPi driver/wrapper should trigger compilation errors + +#endif // RF24_UTILITY_WIRINGPI_INTERRUPT_H__ diff --git a/utility/wiringPi/spi.cpp b/utility/wiringPi/spi.cpp index d6abd4d8..992ae1f2 100644 --- a/utility/wiringPi/spi.cpp +++ b/utility/wiringPi/spi.cpp @@ -8,76 +8,69 @@ * wiringPi/examples/spiSpeed.c */ -#include "spi.h" - -#include -#include - -#include #include #include #include #include -#define RF24_SPI_CHANNEL 0 +#include +#include +#include "spi.h" -SPI::SPI() : fd(-1) +SPI::SPI() : fd(-1), channel(0) { - printf("wiringPi RF24 DRIVER\n"); } void SPI::begin(int csn_pin, uint32_t spi_speed) { + channel = csn_pin % 10; + // initialize the wiringPiSPI wiringPiSetup(); - if ((this->fd = wiringPiSPISetup(RF24_SPI_CHANNEL, spi_speed)) < 0) { - printf("Cannot configure the SPI device!\n"); - fflush(stdout); - abort(); - } - else { - printf("Configured SPI fd: %d - pin: %d\n", fd, csn_pin); + if ((this->fd = wiringPiSPISetup(channel, spi_speed)) < 0) { + std::string msg = "[SPI::begin] Cannot configure the SPI device!; "; + msg += strerror(errno); + throw SPIException(msg); } } uint8_t SPI::transfer(uint8_t tx) { - memset(&msgByte, 0, sizeof(msgByte)); - memcpy(&msgByte, &tx, sizeof(tx)); + memset(&xferByte, 0, sizeof(xferByte)); + memcpy(&xferByte, &tx, sizeof(tx)); - if (wiringPiSPIDataRW(RF24_SPI_CHANNEL, &msgByte, sizeof(tx)) < 0) { - printf("transfer(): Cannot send data: %s\n", strerror(errno)); - fflush(stdout); - abort(); + if (wiringPiSPIDataRW(channel, &xferByte, sizeof(tx)) < 0) { + std::string msg = "[SPI::transfer] Cannot send spi message; "; + msg += strerror(errno); + throw SPIException(msg); + return 0; } - return msgByte; + return xferByte; } void SPI::transfern(char* buf, uint32_t len) { - printf("transfern(tx: %s)\n", buf); - - if (wiringPiSPIDataRW(RF24_SPI_CHANNEL, (uint8_t*)buf, len) < 0) { - printf("transfern(): Cannot send data %s\n", strerror(errno)); - fflush(stdout); - abort(); + if (wiringPiSPIDataRW(channel, (uint8_t*)buf, len) < 0) { + std::string msg = "[SPI::transfern] Cannot send spi message; "; + msg += strerror(errno); + throw SPIException(msg); } } void SPI::transfernb(char* tbuf, char* rbuf, uint32_t len) { // using an auxiliary buffer to keep tx and rx different - memset(msg, 0, sizeof(msg)); - memcpy(msg, tbuf, len); + memset(xferBuf, 0, sizeof(xferBuf)); + memcpy(xferBuf, tbuf, len); - if (wiringPiSPIDataRW(RF24_SPI_CHANNEL, msg, len) < 0) { - printf("transfernb() Cannot send data %s\n", strerror(errno)); - fflush(stdout); - abort(); + if (wiringPiSPIDataRW(channel, xferBuf, len) < 0) { + std::string msg = "[SPI::transfernb] Cannot send spi message; "; + msg += strerror(errno); + throw SPIException(msg); } - memcpy(rbuf, msg, len); + memcpy(rbuf, xferBuf, len); } SPI::~SPI() diff --git a/utility/wiringPi/spi.h b/utility/wiringPi/spi.h index efafce09..30cf61f4 100644 --- a/utility/wiringPi/spi.h +++ b/utility/wiringPi/spi.h @@ -6,12 +6,23 @@ #ifndef RF24_UTILITY_WIRINGPI_SPI_H_ #define RF24_UTILITY_WIRINGPI_SPI_H_ -#include -#include +#include +#include +#include -#include "../../RF24_config.h" // This is cyclical and should be fixed +#ifndef RF24_SPI_SPEED + #define RF24_SPI_SPEED 10000000 +#endif -using namespace std; +/** Specific exception for SPI errors */ +class SPIException : public std::runtime_error +{ +public: + explicit SPIException(const std::string& msg) + : std::runtime_error(msg) + { + } +}; class SPI { @@ -31,8 +42,9 @@ class SPI private: int fd; - uint8_t msg[32 + 1]; - uint8_t msgByte; + int channel; + uint8_t xferBuf[32 + 1]; + uint8_t xferByte; }; #endif // RF24_UTILITY_WIRINGPI_SPI_H_