From bc36c1e98afdc5f05402d129a2dc54184b7db453 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 14 Jun 2024 19:49:19 +0100 Subject: [PATCH] Use lgpio as the RPi HAL --- .github/workflows/main.yml | 7 +- examples/NonArduino/Raspberry/CMakeLists.txt | 2 +- examples/NonArduino/Raspberry/PiHal.h | 164 +++++++++++++------ examples/NonArduino/Raspberry/main.cpp | 8 +- 4 files changed, 126 insertions(+), 55 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 113e8178..4db4aaac 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -259,7 +259,12 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y pigpio cmake + sudo apt-get install -y cmake wget swig python-dev python3-dev python-setuptools python3-setuptools + wget http://abyz.me.uk/lg/lg.zip + unzip lg.zip + cd lg + make + sudo make install - name: Install the library run: | diff --git a/examples/NonArduino/Raspberry/CMakeLists.txt b/examples/NonArduino/Raspberry/CMakeLists.txt index c9d47872..2e6d9349 100644 --- a/examples/NonArduino/Raspberry/CMakeLists.txt +++ b/examples/NonArduino/Raspberry/CMakeLists.txt @@ -15,7 +15,7 @@ add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../../../RadioLib" "${CMAKE_CUR add_executable(${PROJECT_NAME} main.cpp) # link both libraries -target_link_libraries(${PROJECT_NAME} RadioLib pigpio) +target_link_libraries(${PROJECT_NAME} RadioLib lgpio) # you can also specify RadioLib compile-time flags here #target_compile_definitions(RadioLib PUBLIC RADIOLIB_DEBUG_BASIC RADIOLIB_DEBUG_SPI) diff --git a/examples/NonArduino/Raspberry/PiHal.h b/examples/NonArduino/Raspberry/PiHal.h index 5a1b288a..03dded74 100644 --- a/examples/NonArduino/Raspberry/PiHal.h +++ b/examples/NonArduino/Raspberry/PiHal.h @@ -1,55 +1,53 @@ -#ifndef PI_HAL_H -#define PI_HAL_H +#ifndef PI_HAL_LGPIO_H +#define PI_HAL_LGPIO_H // include RadioLib #include // include the library for Raspberry GPIO pins -#include "pigpio.h" +#include -// these should really be swapped, but for some reason, -// it seems like the change directions are inverted in gpioSetAlert functions -#define PI_RISING (FALLING_EDGE) -#define PI_FALLING (RISING_EDGE) +#define PI_RISING (LG_RISING_EDGE) +#define PI_FALLING (LG_FALLING_EDGE) +#define PI_INPUT (0) +#define PI_OUTPUT (1) +#define PI_MAX_USER_GPIO (31) // forward declaration of alert handler that will be used to emulate interrupts -static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata); +static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata); // create a new Raspberry Pi hardware abstraction layer -// using the pigpio library +// using the lgpio library // the HAL must inherit from the base RadioLibHal class // and implement all of its virtual methods class PiHal : public RadioLibHal { public: // default constructor - initializes the base HAL and any needed private members - PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000) - : RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING), + PiHal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0) + : RadioLibHal(PI_INPUT, PI_OUTPUT, LG_LOW, LG_HIGH, PI_RISING, PI_FALLING), + _gpioDevice(gpioDevice), + _spiDevice(spiDevice), _spiChannel(spiChannel), _spiSpeed(spiSpeed) { } void init() override { - // first initialise pigpio library - gpioInitialise(); + // first initialise lgpio library + if((_gpioHandle = lgGpiochipOpen(_gpioDevice)) < 0) { + fprintf(stderr, "Could not open GPIO chip: %s\n", lguErrorText(_gpioHandle)); + return; + } // now the SPI spiBegin(); - - // Waveshare LoRaWAN Hat also needs pin 18 to be pulled high to enable the radio - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_HIGH); } void term() override { // stop the SPI spiEnd(); - // pull the enable pin low - gpioSetMode(18, PI_OUTPUT); - gpioWrite(18, PI_LOW); - - // finally, stop the pigpio library - gpioTerminate(); + // finally, stop the lgpio library + lgGpiochipClose(_gpioHandle); } // GPIO-related methods (pinMode, digitalWrite etc.) should check @@ -59,7 +57,24 @@ class PiHal : public RadioLibHal { return; } - gpioSetMode(pin, mode); + int result; + int flags = 0; + switch(mode) { + case PI_INPUT: + result = lgGpioClaimInput(_gpioHandle, 0, pin); + break; + case PI_OUTPUT: + result = lgGpioClaimOutput(_gpioHandle, flags, pin, LG_HIGH); + break; + default: + fprintf(stderr, "Unknown pinMode mode %" PRIu32 "\n", mode); + return; + } + + if(result < 0) { + fprintf(stderr, "Could not claim pin %" PRIu32 " for mode %" PRIu32 ": %s\n", + pin, mode, lguErrorText(result)); + } } void digitalWrite(uint32_t pin, uint32_t value) override { @@ -67,7 +82,10 @@ class PiHal : public RadioLibHal { return; } - gpioWrite(pin, value); + int result = lgGpioWrite(_gpioHandle, pin, value); + if(result < 0) { + fprintf(stderr, "Error writing value to pin %" PRIu32 ": %s\n", pin, lguErrorText(result)); + } } uint32_t digitalRead(uint32_t pin) override { @@ -75,7 +93,11 @@ class PiHal : public RadioLibHal { return(0); } - return(gpioRead(pin)); + int result = lgGpioRead(_gpioHandle, pin); + if(result < 0) { + fprintf(stderr, "Error writing reading from pin %" PRIu32 ": %s\n", pin, lguErrorText(result)); + } + return result; } void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override { @@ -83,13 +105,19 @@ class PiHal : public RadioLibHal { return; } + // set lgpio alert callback + int result = lgGpioClaimAlert(_gpioHandle, 0, mode, interruptNum, -1); + if(result < 0) { + fprintf(stderr, "Could not claim pin %" PRIu32 " for alert: %s\n", interruptNum, lguErrorText(result)); + return; + } + // enable emulated interrupt interruptEnabled[interruptNum] = true; interruptModes[interruptNum] = mode; interruptCallbacks[interruptNum] = interruptCb; - // set pigpio alert callback - gpioSetAlertFuncEx(interruptNum, pigpioAlertHandler, (void*)this); + lgGpioSetAlertsFunc(_gpioHandle, interruptNum, lgpioAlertHandler, (void *)this); } void detachInterrupt(uint32_t interruptNum) override { @@ -102,27 +130,44 @@ class PiHal : public RadioLibHal { interruptModes[interruptNum] = 0; interruptCallbacks[interruptNum] = NULL; - // disable pigpio alert callback - gpioSetAlertFuncEx(interruptNum, NULL, NULL); + // disable lgpio alert callback + lgGpioFree(_gpioHandle, interruptNum); + lgGpioSetAlertsFunc(_gpioHandle, interruptNum, NULL, NULL); } - void delay(RadioLibTime_t ms) override { - gpioDelay(ms * 1000); + void delay(unsigned long ms) override { + if(ms == 0) { + sched_yield(); + return; + } + + lguSleep(ms / 1000.0); } - void delayMicroseconds(RadioLibTime_t us) override { - gpioDelay(us); + void delayMicroseconds(unsigned long us) override { + if(us == 0) { + sched_yield(); + return; + } + + lguSleep(us / 1000000.0); } - RadioLibTime_t millis() override { - return(gpioTick() / 1000); + void yield() override { + sched_yield(); } - RadioLibTime_t micros() override { - return(gpioTick()); + unsigned long millis() override { + uint32_t time = lguTimestamp() / 1000000UL; + return time; } - long pulseIn(uint32_t pin, uint32_t state, RadioLibTime_t timeout) override { + unsigned long micros() override { + uint32_t time = lguTimestamp() / 1000UL; + return time; + } + + long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override { if(pin == RADIOLIB_NC) { return(0); } @@ -142,25 +187,38 @@ class PiHal : public RadioLibHal { void spiBegin() { if(_spiHandle < 0) { - _spiHandle = spiOpen(_spiChannel, _spiSpeed, 0); + if((_spiHandle = lgSpiOpen(_spiDevice, _spiChannel, _spiSpeed, 0)) < 0) { + fprintf(stderr, "Could not open SPI handle on 0: %s\n", lguErrorText(_spiHandle)); + } } } void spiBeginTransaction() {} void spiTransfer(uint8_t* out, size_t len, uint8_t* in) { - spiXfer(_spiHandle, (char*)out, (char*)in, len); + int result = lgSpiXfer(_spiHandle, (char *)out, (char*)in, len); + if(result < 0) { + fprintf(stderr, "Could not perform SPI transfer: %s\n", lguErrorText(result)); + } } void spiEndTransaction() {} void spiEnd() { if(_spiHandle >= 0) { - spiClose(_spiHandle); + lgSpiClose(_spiHandle); _spiHandle = -1; } } + void tone(uint32_t pin, unsigned int frequency, unsigned long duration = 0) { + lgTxPwm(_gpioHandle, pin, frequency, 50, 0, duration); + } + + void noTone(uint32_t pin) { + lgTxPwm(_gpioHandle, pin, 0, 0, 0, 0); + } + // interrupt emulation bool interruptEnabled[PI_MAX_USER_GPIO + 1]; uint32_t interruptModes[PI_MAX_USER_GPIO + 1]; @@ -170,24 +228,28 @@ class PiHal : public RadioLibHal { private: // the HAL can contain any additional private members const unsigned int _spiSpeed; + const uint8_t _gpioDevice; + const uint8_t _spiDevice; const uint8_t _spiChannel; + int _gpioHandle = -1; int _spiHandle = -1; }; // this handler emulates interrupts -static void pigpioAlertHandler(int event, int level, uint32_t tick, void *userdata) { - if((event > PI_MAX_USER_GPIO) || (!userdata)) { +static void lgpioAlertHandler(int num_alerts, lgGpioAlert_p alerts, void *userdata) { + if(!userdata) return; - } - - // PiHal isntance is passed via the user data + + // PiHal instance is passed via the user data PiHal* hal = (PiHal*)userdata; // check the interrupt is enabled, the level matches and a callback exists - if((hal->interruptEnabled[event]) && - (hal->interruptModes[event] == level) && - (hal->interruptCallbacks[event])) { - hal->interruptCallbacks[event](); + for(lgGpioAlert_t *alert = alerts; alert < (alerts + num_alerts); alert++) { + if((hal->interruptEnabled[alert->report.gpio]) && + (hal->interruptModes[alert->report.gpio] == alert->report.level) && + (hal->interruptCallbacks[alert->report.gpio])) { + hal->interruptCallbacks[alert->report.gpio](); + } } } diff --git a/examples/NonArduino/Raspberry/main.cpp b/examples/NonArduino/Raspberry/main.cpp index 54ae3850..1dfa60bf 100644 --- a/examples/NonArduino/Raspberry/main.cpp +++ b/examples/NonArduino/Raspberry/main.cpp @@ -3,7 +3,8 @@ This example shows how to use RadioLib without Arduino. In this case, a Raspberry Pi with WaveShare SX1302 LoRaWAN Hat - using the pigpio library. + using the lgpio library + https://abyz.me.uk/lg/lgpio.html Can be used as a starting point to port RadioLib to any platform! See this API reference page for details on the RadioLib hardware abstraction @@ -44,10 +45,13 @@ int main(int argc, char** argv) { printf("success!\n"); // loop forever + int count = 0; for(;;) { // send a packet printf("[SX1261] Transmitting packet ... "); - state = radio.transmit("Hello World!"); + char str[64]; + sprintf(str, "Hello World! #%d", count++); + state = radio.transmit(str); if(state == RADIOLIB_ERR_NONE) { // the packet was successfully transmitted printf("success!\n");