From d6dcfd70abbded30c3a43ef67527b1ab91e55ed5 Mon Sep 17 00:00:00 2001 From: exepirit Date: Sat, 17 Jan 2026 20:58:47 +0700 Subject: [PATCH 1/5] sx126x: rewrite all functions for libgpiod v2 --- CMakeLists.txt | 3 + rnode.yaml | 12 +- src/config.c | 2 +- src/config.h | 4 +- src/main.c | 12 +- sx126x/sx126x.c | 287 +++++++++++++++++++++++++++++------------------- sx126x/sx126x.h | 12 +- 7 files changed, 197 insertions(+), 135 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1461c66..25190ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,9 @@ set(CMAKE_CXX_FLAGS_DEBUG "-O3") project(rnode) +find_package(PkgConfig REQUIRED) +pkg_check_modules(GPIOD REQUIRED libgpiod>=2.0) + add_executable(${PROJECT_NAME}) target_link_libraries(${PROJECT_NAME} PRIVATE gpiod m cyaml) diff --git a/rnode.yaml b/rnode.yaml index cda0c6b..15a7f07 100644 --- a/rnode.yaml +++ b/rnode.yaml @@ -2,10 +2,10 @@ # Board RNS-Gate spi: /dev/spidev1.0 -cs: { port: 0, pin: 13 } -rst: { port: 0, pin: 6 } -busy: { port: 0, pin: 11 } -dio1: { port: 0, pin: 12 } -rx_en: { port: 0, pin: 2 } -tx_en: { port: 0, pin: 18 } +cs: { chip: /dev/gpiochip0, pin: 13 } +rst: { chip: /dev/gpiochip0, pin: 6 } +busy: { chip: /dev/gpiochip0, pin: 11 } +dio1: { chip: /dev/gpiochip0, pin: 12 } +rx_en: { chip: /dev/gpiochip0, pin: 2 } +tx_en: { chip: /dev/gpiochip0, pin: 18 } tcp_port: 7633 diff --git a/src/config.c b/src/config.c index c9d6ef7..d0f201d 100644 --- a/src/config.c +++ b/src/config.c @@ -11,7 +11,7 @@ #include "config.h" const cyaml_schema_field_t gpio_fields_schema[] = { - CYAML_FIELD_UINT("port", CYAML_FLAG_DEFAULT, config_gpio_t, port), + CYAML_FIELD_STRING_PTR("chip", CYAML_FLAG_POINTER, config_gpio_t, chip, 0, CYAML_UNLIMITED), CYAML_FIELD_UINT("pin", CYAML_FLAG_DEFAULT, config_gpio_t, pin), CYAML_FIELD_END }; diff --git a/src/config.h b/src/config.h index 6cb80ca..b7b5b81 100644 --- a/src/config.h +++ b/src/config.h @@ -13,8 +13,8 @@ #include typedef struct { - uint8_t port; - uint8_t pin; + const char *chip; + uint8_t pin; } config_gpio_t; typedef struct { diff --git a/src/main.c b/src/main.c index 514b647..e358b02 100644 --- a/src/main.c +++ b/src/main.c @@ -28,32 +28,32 @@ int main(int argc, char *argv[]) { return 1; } - if (!sx126x_init_spi(config->spi, config->cs.port, config->cs.pin)) { + if (!sx126x_init_spi(config->spi, config->cs.chip, config->cs.pin)) { syslog(LOG_ERR, "SPI init"); return 1; } - if (!sx126x_init_rst(config->rst.port, config->rst.pin)) { + if (!sx126x_init_rst(config->rst.chip, config->rst.pin)) { syslog(LOG_ERR, "RST pin"); return 1; } - if (!sx126x_init_busy(config->busy.port, config->busy.pin)) { + if (!sx126x_init_busy(config->busy.chip, config->busy.pin)) { syslog(LOG_ERR, "Busy pin"); return 1; } - if (!sx126x_init_dio1(config->dio1.port, config->dio1.pin)) { + if (!sx126x_init_dio1(config->dio1.chip, config->dio1.pin)) { syslog(LOG_ERR, "DIO1 pin"); return 1; } - if (!sx126x_init_tx_en(config->tx_en.port, config->tx_en.pin)) { + if (!sx126x_init_tx_en(config->tx_en.chip, config->tx_en.pin)) { syslog(LOG_ERR, "TX EN pin"); return 1; } - if (!sx126x_init_rx_en(config->rx_en.port, config->rx_en.pin)) { + if (!sx126x_init_rx_en(config->rx_en.chip, config->rx_en.pin)) { syslog(LOG_ERR, "RX EN pin"); return 1; } diff --git a/sx126x/sx126x.c b/sx126x/sx126x.c index c166ede..6cce31a 100644 --- a/sx126x/sx126x.c +++ b/sx126x/sx126x.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,11 @@ #include "sx126x.h" #include "util.h" +typedef struct { + struct gpiod_line_request *req; + unsigned int pin; +} gpio_line_t; + #define PHY_HEADER_LORA_SYMBOLS 20 #define PHY_CRC_LORA_BITS 16 @@ -91,12 +97,12 @@ typedef enum { IRQ_NONE = 0x0000 } irq_t; -static struct gpiod_line *cs_line = NULL; -static struct gpiod_line *rst_line = NULL; -static struct gpiod_line *busy_line = NULL; -static struct gpiod_line *dio1_line = NULL; -static struct gpiod_line *tx_en_line = NULL; -static struct gpiod_line *rx_en_line = NULL; +static gpio_line_t cs = { NULL, 0 }; +static gpio_line_t rst = { NULL, 0 }; +static gpio_line_t busy = { NULL, 0 }; +static gpio_line_t dio1 = { NULL, 0 }; +static gpio_line_t tx_en = { NULL, 0 }; +static gpio_line_t rx_en = { NULL, 0 }; static int spi_fd; static uint8_t fifo_tx_addr_ptr = 0; @@ -130,7 +136,7 @@ static sx126x_timeout_callback_t timeout_callback = NULL; static void wait_on_busy() { uint16_t count = 0; - while (gpiod_line_get_value(busy_line) == 1) { + while (gpiod_line_request_get_value(busy.req, busy.pin) == GPIOD_LINE_VALUE_ACTIVE) { usleep(1000); count++; @@ -149,36 +155,36 @@ static void wait_on_busy() { static void switch_ant() { switch (state) { case SX126X_IDLE: - if (rx_en_line) { - gpiod_line_set_value(rx_en_line, 0); + if (rx_en.req) { + gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_INACTIVE); } - if (tx_en_line) { - gpiod_line_set_value(tx_en_line, 0); + if (tx_en.req) { + gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_INACTIVE); } break; case SX126X_RX_SINGLE: case SX126X_RX_CONTINUOUS: - if (tx_en_line) { - gpiod_line_set_value(tx_en_line, 0); + if (tx_en.req) { + gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_INACTIVE); } usleep(100); - if (rx_en_line) { - gpiod_line_set_value(rx_en_line, 1); + if (rx_en.req) { + gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_ACTIVE); } break; case SX126X_TX: - if (rx_en_line) { - gpiod_line_set_value(rx_en_line, 0); + if (rx_en.req) { + gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_INACTIVE); } usleep(100); - if (tx_en_line) { - gpiod_line_set_value(tx_en_line, 1); + if (tx_en.req) { + gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_ACTIVE); } break; } @@ -196,9 +202,9 @@ static bool write_bytes(const uint8_t *buf, size_t len) { .cs_change = 0, }; - gpiod_line_set_value(cs_line, 0); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &k); - gpiod_line_set_value(cs_line, 1); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); return (l == k.len); } @@ -222,9 +228,9 @@ static bool write_read_bytes(const uint8_t *buf, size_t buf_len, uint8_t *res, s } }; - gpiod_line_set_value(cs_line, 0); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(2), &k); - gpiod_line_set_value(cs_line, 1); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); return (l == (buf_len + res_len)); } @@ -240,9 +246,9 @@ static bool read_bytes(const uint8_t *buf, uint8_t *res, size_t len) { .cs_change = 0, }; - gpiod_line_set_value(cs_line, 0); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &k); - gpiod_line_set_value(cs_line, 1); + gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); return (l == k.len); } @@ -429,8 +435,8 @@ static void set_irq_mask() { /* * */ static void * irq_worker(void *p) { - struct gpiod_line_event event; - bool crc_ok = true; + struct gpiod_edge_event_buffer *buf = gpiod_edge_event_buffer_new(1); + bool crc_ok = true; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -440,12 +446,12 @@ static void * irq_worker(void *p) { } while (true) { - struct timespec timeout; - - timeout.tv_sec = 60; - timeout.tv_nsec = 0; + int res = gpiod_line_request_wait_edge_events(dio1.req, 60000000000); - int res = gpiod_line_event_wait(dio1_line, &timeout); + if (res < 0) { + syslog(LOG_ERR, "IRQ: edge event wait error: %s", strerror(errno)); + break; + } if (res == 0) { syslog(LOG_INFO, "IRQ: Timeout"); @@ -453,12 +459,10 @@ static void * irq_worker(void *p) { if (timeout_callback) { timeout_callback(); } - } else if (res == 1) { - if (gpiod_line_event_read(dio1_line, &event) != 0) { - continue; - } + } else if (gpiod_line_request_read_edge_events(dio1.req, buf, 1) == 1) { + struct gpiod_edge_event *ev = gpiod_edge_event_buffer_get_event(buf, 0); - if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) { + if (gpiod_edge_event_get_event_type(ev) == GPIOD_EDGE_EVENT_RISING_EDGE) { uint16_t status = get_irq_status(); if (status & IRQ_CRC_ERR) { @@ -526,139 +530,196 @@ static void * irq_worker(void *p) { } } } + + gpiod_edge_event_buffer_free(buf); + return NULL; } /* * */ -bool sx126x_init_spi(const char *spidev, uint8_t cs_port, uint8_t cs_pin) { +bool sx126x_init_spi(const char *spidev, const char *cs_chip, uint8_t cs_pin) { spi_fd = open(spidev, O_RDWR); if (spi_fd < 0) { return false; } - syslog(LOG_INFO, "SPI %s, CS GPIO %i:%i", spidev, (int) cs_port, (int) cs_pin); + syslog(LOG_INFO, "SPI %s, CS GPIO %s:%i", spidev, cs_chip, (int) cs_pin); - struct gpiod_chip *chip = gpiod_chip_open_by_number(cs_port); + struct gpiod_chip *c = gpiod_chip_open(cs_chip); - if (!chip) { - return false; - } + if (!c) return false; - cs_line = gpiod_chip_get_line(chip, cs_pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!cs_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_ACTIVE); - gpiod_line_request_output(cs_line, "sx126x_cs", 1); + unsigned int offsets[] = { cs_pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_cs"); - return true; + cs.req = gpiod_chip_request_lines(c, rcfg, lcfg); + cs.pin = cs_pin; + + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + return cs.req != NULL; } -bool sx126x_init_rst(uint8_t port, uint8_t pin) { - struct gpiod_chip *chip = gpiod_chip_open_by_number(port); +bool sx126x_init_rst(const char *chip, uint8_t pin) { + syslog(LOG_INFO, "RST GPIO %s:%i", chip, (int) pin); - syslog(LOG_INFO, "RST GPIO %i:%i", (int) port, (int) pin); + struct gpiod_chip *c = gpiod_chip_open(chip); - if (!chip) { - return false; - } + if (!c) return false; - rst_line = gpiod_chip_get_line(chip, pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!rst_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - gpiod_line_request_output(rst_line, "sx126x_rst", 0); + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_rst"); - return true; + rst.req = gpiod_chip_request_lines(c, rcfg, lcfg); + rst.pin = pin; + + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + return rst.req != NULL; } -bool sx126x_init_busy(uint8_t port, uint8_t pin) { - struct gpiod_chip *chip = gpiod_chip_open_by_number(port); +bool sx126x_init_busy(const char *chip, uint8_t pin) { + syslog(LOG_INFO, "Busy GPIO %s:%i", chip, (int) pin); - syslog(LOG_INFO, "Busy GPIO %i:%i", (int) port, (int) pin); + struct gpiod_chip *c = gpiod_chip_open(chip); - if (!chip) { - return false; - } + if (!c) return false; - busy_line = gpiod_chip_get_line(chip, pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!busy_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_INPUT); - gpiod_line_request_input(busy_line, "sx126x_busy"); + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_busy"); - return true; + busy.req = gpiod_chip_request_lines(c, rcfg, lcfg); + busy.pin = pin; + + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + return busy.req != NULL; } -bool sx126x_init_dio1(uint8_t port, uint8_t pin) { - struct gpiod_chip *chip = gpiod_chip_open_by_number(port); +bool sx126x_init_dio1(const char *chip, uint8_t pin) { + syslog(LOG_INFO, "DIO1 GPIO %s:%i", chip, (int) pin); - syslog(LOG_INFO, "DIO1 GPIO %i:%i", (int) port, (int) pin); + struct gpiod_chip *c = gpiod_chip_open(chip); - if (!chip) { - return false; - } + if (!c) return false; - dio1_line = gpiod_chip_get_line(chip, pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!dio1_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_INPUT); + gpiod_line_settings_set_edge_detection(s, GPIOD_LINE_EDGE_RISING); - gpiod_line_request_both_edges_events(dio1_line, "sx126x_dio1"); + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_dio1"); - pthread_t thread; + dio1.req = gpiod_chip_request_lines(c, rcfg, lcfg); + dio1.pin = pin; + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + if (!dio1.req) return false; + + pthread_t thread; pthread_create(&thread, NULL, irq_worker, NULL); pthread_detach(thread); return true; } -bool sx126x_init_tx_en(uint8_t port, uint8_t pin) { - struct gpiod_chip *chip = gpiod_chip_open_by_number(port); +bool sx126x_init_tx_en(const char *chip, uint8_t pin) { + syslog(LOG_INFO, "TX EN GPIO %s:%i", chip, (int) pin); - syslog(LOG_INFO, "TX EN GPIO %i:%i", (int) port, (int) pin); + struct gpiod_chip *c = gpiod_chip_open(chip); - if (!chip) { - return false; - } + if (!c) return false; - tx_en_line = gpiod_chip_get_line(chip, pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!tx_en_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - gpiod_line_request_output(tx_en_line, "sx126x_tx_en", 0); + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_tx_en"); - return true; + tx_en.req = gpiod_chip_request_lines(c, rcfg, lcfg); + tx_en.pin = pin; + + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + return tx_en.req != NULL; } -bool sx126x_init_rx_en(uint8_t port, uint8_t pin) { - struct gpiod_chip *chip = gpiod_chip_open_by_number(port); +bool sx126x_init_rx_en(const char *chip, uint8_t pin) { + syslog(LOG_INFO, "RX EN GPIO %s:%i", chip, (int) pin); - syslog(LOG_INFO, "RX EN GPIO %i:%i", (int) port, (int) pin); + struct gpiod_chip *c = gpiod_chip_open(chip); - if (!chip) { - return false; - } + if (!c) return false; - rx_en_line = gpiod_chip_get_line(chip, pin); + struct gpiod_line_settings *s = gpiod_line_settings_new(); + struct gpiod_line_config *lcfg = gpiod_line_config_new(); + struct gpiod_request_config *rcfg = gpiod_request_config_new(); - if (!rx_en_line) { - return false; - } + gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - gpiod_line_request_output(rx_en_line, "sx126x_rx_en", 0); + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); + gpiod_request_config_set_consumer(rcfg, "sx126x_rx_en"); - return true; + rx_en.req = gpiod_chip_request_lines(c, rcfg, lcfg); + rx_en.pin = pin; + + gpiod_line_settings_free(s); + gpiod_line_config_free(lcfg); + gpiod_request_config_free(rcfg); + gpiod_chip_close(c); + + return rx_en.req != NULL; } void sx126x_set_rx_done_callback(sx126x_rx_done_callback_t callback) { @@ -678,9 +739,9 @@ void sx126x_set_timeout_callback(sx126x_timeout_callback_t callback) { } bool sx126x_begin() { - gpiod_line_set_value(rst_line, 0); + gpiod_line_request_set_value(rst.req, rst.pin, GPIOD_LINE_VALUE_INACTIVE); usleep(10000); - gpiod_line_set_value(rst_line, 1); + gpiod_line_request_set_value(rst.req, rst.pin, GPIOD_LINE_VALUE_ACTIVE); usleep(10000); state = SX126X_IDLE; @@ -912,11 +973,9 @@ void sx126x_packet_signal_raw(uint8_t *rssi, int8_t *snr, uint8_t *signal_rssi) } int8_t sx126x_current_rssi() { - int8_t rssi; - wait_on_busy(); - return -get_current_rssi(&rssi) / 2; + return -get_current_rssi() / 2; } uint32_t sx126x_air_time(uint16_t len, uint32_t *preamble_ms, uint32_t *data_ms) { diff --git a/sx126x/sx126x.h b/sx126x/sx126x.h index 3263929..1c114b6 100644 --- a/sx126x/sx126x.h +++ b/sx126x/sx126x.h @@ -99,12 +99,12 @@ typedef void (*sx126x_tx_done_callback_t)(void); typedef void (*sx126x_medium_callback_t)(cause_medium_t cause); typedef void (*sx126x_timeout_callback_t)(void); -bool sx126x_init_spi(const char *spidev, uint8_t cs_port, uint8_t cs_pin); -bool sx126x_init_rst(uint8_t port, uint8_t pin); -bool sx126x_init_busy(uint8_t port, uint8_t pin); -bool sx126x_init_dio1(uint8_t port, uint8_t pin); -bool sx126x_init_tx_en(uint8_t port, uint8_t pin); -bool sx126x_init_rx_en(uint8_t port, uint8_t pin); +bool sx126x_init_spi(const char *spidev, const char *cs_chip, uint8_t cs_pin); +bool sx126x_init_rst(const char *chip, uint8_t pin); +bool sx126x_init_busy(const char *chip, uint8_t pin); +bool sx126x_init_dio1(const char *chip, uint8_t pin); +bool sx126x_init_tx_en(const char *chip, uint8_t pin); +bool sx126x_init_rx_en(const char *chip, uint8_t pin); void sx126x_set_rx_done_callback(sx126x_rx_done_callback_t callback); void sx126x_set_tx_done_callback(sx126x_tx_done_callback_t callback); From 64784e0471717b369217c78b8667a406e0466638 Mon Sep 17 00:00:00 2001 From: exepirit Date: Tue, 10 Mar 2026 21:14:17 +0700 Subject: [PATCH 2/5] sx126x: libgpiod version-agnostic GPIO HAL --- CMakeLists.txt | 10 +- sx126x/CMakeLists.txt | 9 ++ sx126x/gpio_hal.h | 42 ++++++ sx126x/gpio_hal_v1.c | 97 +++++++++++++ sx126x/gpio_hal_v2.c | 129 +++++++++++++++++ sx126x/sx126x.c | 320 ++++++++++-------------------------------- 6 files changed, 357 insertions(+), 250 deletions(-) create mode 100644 sx126x/gpio_hal.h create mode 100644 sx126x/gpio_hal_v1.c create mode 100644 sx126x/gpio_hal_v2.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 25190ca..471d101 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,17 @@ cmake_minimum_required(VERSION 3.16) +project(rnode) + set(CMAKE_C_FLAGS_RELEASE "-O3") set(CMAKE_CXX_FLAGS_RELEASE "-O3") - set(CMAKE_C_FLAGS_DEBUG "-O3") set(CMAKE_CXX_FLAGS_DEBUG "-O3") -project(rnode) - find_package(PkgConfig REQUIRED) -pkg_check_modules(GPIOD REQUIRED libgpiod>=2.0) add_executable(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} PRIVATE gpiod m cyaml) +target_include_directories(${PROJECT_NAME} PRIVATE ${GPIOD_INCLUDE_DIRS}) add_subdirectory(src) add_subdirectory(sx126x) @@ -21,5 +19,7 @@ add_subdirectory(sx126x) include_directories(src) include_directories(sx126x) +target_link_libraries(${PROJECT_NAME} PRIVATE ${GPIOD_LIBRARIES} m cyaml) + install(FILES rnode.yaml DESTINATION /mnt/rns) install(TARGETS ${PROJECT_NAME} DESTINATION sbin) diff --git a/sx126x/CMakeLists.txt b/sx126x/CMakeLists.txt index 81608de..c8f7d2d 100644 --- a/sx126x/CMakeLists.txt +++ b/sx126x/CMakeLists.txt @@ -1,3 +1,12 @@ +pkg_check_modules(GPIOD libgpiod>=2.0) + +if(GPIOD_FOUND) + target_sources(${PROJECT_NAME} PRIVATE gpio_hal_v2.c) +else() + pkg_check_modules(GPIOD REQUIRED libgpiod) + target_sources(${PROJECT_NAME} PRIVATE gpio_hal_v1.c) +endif() + target_sources(${PROJECT_NAME} PUBLIC sx126x.c ) diff --git a/sx126x/gpio_hal.h b/sx126x/gpio_hal.h new file mode 100644 index 0000000..b1c91f4 --- /dev/null +++ b/sx126x/gpio_hal.h @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * GPIO HAL + */ + +#pragma once + +typedef struct gpio_line gpio_line_t; + +typedef enum { + GPIO_DIR_OUTPUT, + GPIO_DIR_INPUT, + GPIO_DIR_INPUT_EDGE_RISING +} gpio_dir_t; + +typedef enum { + GPIO_VALUE_INACTIVE = 0, + GPIO_VALUE_ACTIVE = 1 +} gpio_value_t; + +/* Allocate and configure a GPIO line. Returns NULL on failure. */ +gpio_line_t *gpio_request(const char *chip, + unsigned int pin, + gpio_dir_t dir, + gpio_value_t initial, + const char *consumer); + +/* Release a line obtained with gpio_request(). */ +void gpio_release(gpio_line_t *line); + +/* Read the current level of an input line. */ +gpio_value_t gpio_get(gpio_line_t *line); + +/* Drive an output line to the given level. */ +void gpio_set(gpio_line_t *line, gpio_value_t val); + +/* + * Block until one edge event is available on an edge-detection line. + * Returns: 1 - event received; 0 - no event (timeout); <0 - error + */ +int gpio_read_edge_rising(gpio_line_t *line); \ No newline at end of file diff --git a/sx126x/gpio_hal_v1.c b/sx126x/gpio_hal_v1.c new file mode 100644 index 0000000..e9a7031 --- /dev/null +++ b/sx126x/gpio_hal_v1.c @@ -0,0 +1,97 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * GPIO HAL (libgpiod v1 backend) + */ + +#include +#include +#include + +#include "gpio_hal.h" + +struct gpio_line { + struct gpiod_line *line; +}; + +gpio_line_t *gpio_request(const char *chip_path, + unsigned int pin, + gpio_dir_t dir, + gpio_value_t initial, + const char *consumer) +{ + struct gpiod_chip *chip = gpiod_chip_open(chip); + if (!chip) return NULL; + + struct gpiod_line *line = gpiod_chip_get_line(chip, pin); + if (!line) { + gpiod_chip_close(chip); + return NULL; + } + + int result; + + switch (dir) { + case GPIO_DIR_OUTPUT: + result = gpiod_line_request_output(line, consumer, + initial == GPIO_VALUE_ACTIVE ? 1 : 0); + break; + case GPIO_DIR_INPUT: + result = gpiod_line_request_input(line, consumer); + break; + case GPIO_DIR_INPUT_EDGE_RISING: { + struct gpiod_line_request_config cfg = { + .consumer = consumer, + .request_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE, + .flags = 0, + }; + result = gpiod_line_request(line, &cfg, 0); + break; + } + default: + result = -1; + break; + } + + gpiod_chip_close(chip); + + if (result < 0) return NULL; + + gpio_line_t *gpio = malloc(sizeof(*gpio)); + if (!gpio) { + gpiod_line_release(line); + return NULL; + } + + gpio->line = line; + return gpio; +} + +void gpio_release(gpio_line_t *line) { + if (!line) return; + gpiod_line_release(line->line); + free(line); +} + +gpio_value_t gpio_get(gpio_line_t *line) { + return gpiod_line_get_value(line->line) == 1 + ? GPIO_VALUE_ACTIVE + : GPIO_VALUE_INACTIVE; +} + +void gpio_set(gpio_line_t *line, gpio_value_t val) { + gpiod_line_set_value(line->line, val == GPIO_VALUE_ACTIVE ? 1 : 0); +} + +int gpio_read_edge_rising(gpio_line_t *line) { + struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 }; + int res = gpiod_line_event_wait(line->line, &timeout); + + if (res < 0) return -1; + if (res == 0) return 0; // timeout, no event + + struct gpiod_line_event event; + if (gpiod_line_event_read(line->line, &event) < 0) return -1; + + return (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) ? 1 : 0; +} diff --git a/sx126x/gpio_hal_v2.c b/sx126x/gpio_hal_v2.c new file mode 100644 index 0000000..e031b78 --- /dev/null +++ b/sx126x/gpio_hal_v2.c @@ -0,0 +1,129 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * GPIO HAL (libgpiod v2 backend) + */ + +#include +#include +#include + +#include "gpio_hal.h" + +struct gpio_line { + struct gpiod_line_request *req; + unsigned int pin; + struct gpiod_edge_event_buffer *event_buf; +}; + +gpio_line_t *gpio_request(const char *chip, + unsigned int pin, + gpio_dir_t dir, + gpio_value_t initial, + const char *consumer) +{ + struct gpiod_chip *chip_h = gpiod_chip_open(chip); + if (!chip_h) return NULL; + + struct gpiod_line_settings *settings = gpiod_line_settings_new(); + if (!settings) { + gpiod_chip_close(chip_h); + return NULL; + } + + struct gpiod_line_config *line_cfg = gpiod_line_config_new(); + if (!line_cfg) { + gpiod_line_settings_free(settings); + gpiod_chip_close(chip_h); + return NULL; + } + + struct gpiod_request_config *req_cfg = gpiod_request_config_new(); + if (!req_cfg) { + gpiod_line_config_free(line_cfg); + gpiod_line_settings_free(settings); + gpiod_chip_close(chip_h); + return NULL; + } + + switch (dir) { + case GPIO_DIR_OUTPUT: + gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT); + gpiod_line_settings_set_output_value(settings, + initial == GPIO_VALUE_ACTIVE + ? GPIOD_LINE_VALUE_ACTIVE + : GPIOD_LINE_VALUE_INACTIVE); + break; + case GPIO_DIR_INPUT: + gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT); + break; + case GPIO_DIR_INPUT_EDGE_RISING: + gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT); + gpiod_line_settings_set_edge_detection(settings, GPIOD_LINE_EDGE_RISING); + break; + } + + unsigned int offsets[] = { pin }; + gpiod_line_config_add_line_settings(line_cfg, offsets, 1, settings); + gpiod_request_config_set_consumer(req_cfg, consumer); + + gpio_line_t *gpio = malloc(sizeof(*gpio)); + if (gpio) { + gpio->req = gpiod_chip_request_lines(chip_h, req_cfg, line_cfg); + gpio->pin = pin; + gpio->event_buf = NULL; + + if (!gpio->req) { + free(gpio); + gpio = NULL; + } else if (dir == GPIO_DIR_INPUT_EDGE_RISING) { + gpio->event_buf = gpiod_edge_event_buffer_new(1); + if (!gpio->event_buf) { + gpiod_line_request_release(gpio->req); + free(gpio); + gpio = NULL; + } + } + } + + gpiod_line_settings_free(settings); + gpiod_line_config_free(line_cfg); + gpiod_request_config_free(req_cfg); + gpiod_chip_close(chip_h); + + return gpio; +} + +void gpio_release(gpio_line_t *line) { + if (!line) return; + + if (line->event_buf) { + gpiod_edge_event_buffer_free(line->event_buf); + } + gpiod_line_request_release(line->req); + free(line); +} + +gpio_value_t gpio_get(gpio_line_t *line) { + return gpiod_line_request_get_value(line->req, line->pin) + == GPIOD_LINE_VALUE_ACTIVE + ? GPIO_VALUE_ACTIVE + : GPIO_VALUE_INACTIVE; +} + +void gpio_set(gpio_line_t *line, gpio_value_t val) { + gpiod_line_request_set_value(line->req, line->pin, + val == GPIO_VALUE_ACTIVE + ? GPIOD_LINE_VALUE_ACTIVE + : GPIOD_LINE_VALUE_INACTIVE); +} + +int gpio_read_edge_rising(gpio_line_t *line) { + int res = gpiod_line_request_read_edge_events(line->req, line->event_buf, 1); + + if (res < 0) return -1; + if (res == 0) return 0; + + struct gpiod_edge_event *event = gpiod_edge_event_buffer_get_event(line->event_buf, 0); + return (gpiod_edge_event_get_event_type(event) == GPIOD_EDGE_EVENT_RISING_EDGE) ? 1 : 0; +} diff --git a/sx126x/sx126x.c b/sx126x/sx126x.c index 6cce31a..0058614 100644 --- a/sx126x/sx126x.c +++ b/sx126x/sx126x.c @@ -17,17 +17,12 @@ #include #include #include -#include +#include "gpio_hal.h" #include #include "sx126x.h" #include "util.h" -typedef struct { - struct gpiod_line_request *req; - unsigned int pin; -} gpio_line_t; - #define PHY_HEADER_LORA_SYMBOLS 20 #define PHY_CRC_LORA_BITS 16 @@ -97,12 +92,12 @@ typedef enum { IRQ_NONE = 0x0000 } irq_t; -static gpio_line_t cs = { NULL, 0 }; -static gpio_line_t rst = { NULL, 0 }; -static gpio_line_t busy = { NULL, 0 }; -static gpio_line_t dio1 = { NULL, 0 }; -static gpio_line_t tx_en = { NULL, 0 }; -static gpio_line_t rx_en = { NULL, 0 }; +static gpio_line_t *cs = NULL; +static gpio_line_t *rst = NULL; +static gpio_line_t *busy = NULL; +static gpio_line_t *dio1 = NULL; +static gpio_line_t *tx_en = NULL; +static gpio_line_t *rx_en = NULL; static int spi_fd; static uint8_t fifo_tx_addr_ptr = 0; @@ -136,7 +131,7 @@ static sx126x_timeout_callback_t timeout_callback = NULL; static void wait_on_busy() { uint16_t count = 0; - while (gpiod_line_request_get_value(busy.req, busy.pin) == GPIOD_LINE_VALUE_ACTIVE) { + while (gpio_get(busy) == GPIO_VALUE_ACTIVE) { usleep(1000); count++; @@ -155,37 +150,21 @@ static void wait_on_busy() { static void switch_ant() { switch (state) { case SX126X_IDLE: - if (rx_en.req) { - gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_INACTIVE); - } - if (tx_en.req) { - gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_INACTIVE); - } + if (rx_en) gpio_set(rx_en, GPIO_VALUE_INACTIVE); + if (tx_en) gpio_set(tx_en, GPIO_VALUE_INACTIVE); break; case SX126X_RX_SINGLE: case SX126X_RX_CONTINUOUS: - if (tx_en.req) { - gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_INACTIVE); - } - + if (tx_en) gpio_set(tx_en, GPIO_VALUE_INACTIVE); usleep(100); - - if (rx_en.req) { - gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_ACTIVE); - } + if (rx_en) gpio_set(rx_en, GPIO_VALUE_ACTIVE); break; case SX126X_TX: - if (rx_en.req) { - gpiod_line_request_set_value(rx_en.req, rx_en.pin, GPIOD_LINE_VALUE_INACTIVE); - } - + if (rx_en) gpio_set(rx_en, GPIO_VALUE_INACTIVE); usleep(100); - - if (tx_en.req) { - gpiod_line_request_set_value(tx_en.req, tx_en.pin, GPIOD_LINE_VALUE_ACTIVE); - } + if (tx_en) gpio_set(tx_en, GPIO_VALUE_ACTIVE); break; } } @@ -202,9 +181,9 @@ static bool write_bytes(const uint8_t *buf, size_t len) { .cs_change = 0, }; - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); + gpio_set(cs, GPIO_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &k); - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); + gpio_set(cs, GPIO_VALUE_ACTIVE); return (l == k.len); } @@ -228,9 +207,9 @@ static bool write_read_bytes(const uint8_t *buf, size_t buf_len, uint8_t *res, s } }; - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); + gpio_set(cs, GPIO_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(2), &k); - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); + gpio_set(cs, GPIO_VALUE_ACTIVE); return (l == (buf_len + res_len)); } @@ -246,9 +225,9 @@ static bool read_bytes(const uint8_t *buf, uint8_t *res, size_t len) { .cs_change = 0, }; - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_INACTIVE); + gpio_set(cs, GPIO_VALUE_INACTIVE); int l = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &k); - gpiod_line_request_set_value(cs.req, cs.pin, GPIOD_LINE_VALUE_ACTIVE); + gpio_set(cs, GPIO_VALUE_ACTIVE); return (l == k.len); } @@ -435,8 +414,7 @@ static void set_irq_mask() { /* * */ static void * irq_worker(void *p) { - struct gpiod_edge_event_buffer *buf = gpiod_edge_event_buffer_new(1); - bool crc_ok = true; + bool crc_ok = true; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -446,7 +424,7 @@ static void * irq_worker(void *p) { } while (true) { - int res = gpiod_line_request_wait_edge_events(dio1.req, 60000000000); + int res = gpio_read_edge_rising(dio1); if (res < 0) { syslog(LOG_ERR, "IRQ: edge event wait error: %s", strerror(errno)); @@ -459,70 +437,64 @@ static void * irq_worker(void *p) { if (timeout_callback) { timeout_callback(); } - } else if (gpiod_line_request_read_edge_events(dio1.req, buf, 1) == 1) { - struct gpiod_edge_event *ev = gpiod_edge_event_buffer_get_event(buf, 0); + } else { + uint16_t status = get_irq_status(); - if (gpiod_edge_event_get_event_type(ev) == GPIOD_EDGE_EVENT_RISING_EDGE) { - uint16_t status = get_irq_status(); + if (status & IRQ_CRC_ERR) { + syslog(LOG_INFO, "IRQ: CRC ERR"); + crc_ok = false; + } - if (status & IRQ_CRC_ERR) { - syslog(LOG_INFO, "IRQ: CRC ERR"); + if (status & IRQ_PREAMBLE_DETECTED) { + syslog(LOG_INFO, "IRQ: PREAMBLE DETECTED"); + crc_ok = true; - crc_ok = false; + if (medium_callback) { + medium_callback(CAUSE_PREAMBLE_DETECTED); } + } - if (status & IRQ_PREAMBLE_DETECTED) { - syslog(LOG_INFO, "IRQ: PREAMBLE DETECTED"); - crc_ok = true; + if (status & IRQ_HEADER_VALID) { + syslog(LOG_INFO, "IRQ: HEADER VALID"); - if (medium_callback) { - medium_callback(CAUSE_PREAMBLE_DETECTED); - } + if (medium_callback) { + medium_callback(CAUSE_HEADER_VALID); } + } - if (status & IRQ_HEADER_VALID) { - syslog(LOG_INFO, "IRQ: HEADER VALID"); + if (status & IRQ_HEADER_ERR) { + syslog(LOG_INFO, "IRQ: HEADER ERR"); - if (medium_callback) { - medium_callback(CAUSE_HEADER_VALID); - } + if (medium_callback) { + medium_callback(CAUSE_HEADER_ERR); } + } - if (status & IRQ_HEADER_ERR) { - syslog(LOG_INFO, "IRQ: HEADER ERR"); + if (status & IRQ_RX_DONE) { + syslog(LOG_INFO, "IRQ: RX DONE"); - if (medium_callback) { - medium_callback(CAUSE_HEADER_ERR); - } + if (medium_callback) { + medium_callback(CAUSE_RX_DONE); } - if (status & IRQ_RX_DONE) { - syslog(LOG_INFO, "IRQ: RX DONE"); - - if (medium_callback) { - medium_callback(CAUSE_RX_DONE); - } - - if (crc_ok) { - payload_tx_rx = get_rx_buffer_status(); - - if (rx_done_callback) { - rx_done_callback(payload_tx_rx); - } + if (crc_ok) { + payload_tx_rx = get_rx_buffer_status(); + if (rx_done_callback) { + rx_done_callback(payload_tx_rx); } } + } - if (status & IRQ_TX_DONE) { - syslog(LOG_INFO, "IRQ: TX DONE"); + if (status & IRQ_TX_DONE) { + syslog(LOG_INFO, "IRQ: TX DONE"); - if (medium_callback) { - medium_callback(CAUSE_TX_DONE); - } + if (medium_callback) { + medium_callback(CAUSE_TX_DONE); + } - if (tx_done_callback) { - tx_done_callback(); - } + if (tx_done_callback) { + tx_done_callback(); } clear_irq_status(0x7F); @@ -531,7 +503,6 @@ static void * irq_worker(void *p) { } } - gpiod_edge_event_buffer_free(buf); return NULL; } @@ -539,187 +510,46 @@ static void * irq_worker(void *p) { bool sx126x_init_spi(const char *spidev, const char *cs_chip, uint8_t cs_pin) { spi_fd = open(spidev, O_RDWR); - - if (spi_fd < 0) { - return false; - } + if (spi_fd < 0) return false; syslog(LOG_INFO, "SPI %s, CS GPIO %s:%i", spidev, cs_chip, (int) cs_pin); - - struct gpiod_chip *c = gpiod_chip_open(cs_chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); - gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_ACTIVE); - - unsigned int offsets[] = { cs_pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_cs"); - - cs.req = gpiod_chip_request_lines(c, rcfg, lcfg); - cs.pin = cs_pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - return cs.req != NULL; + cs = gpio_request(cs_chip, cs_pin, GPIO_DIR_OUTPUT, GPIO_VALUE_ACTIVE, "sx126x_cs"); + return cs != NULL; } bool sx126x_init_rst(const char *chip, uint8_t pin) { syslog(LOG_INFO, "RST GPIO %s:%i", chip, (int) pin); - - struct gpiod_chip *c = gpiod_chip_open(chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); - gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - - unsigned int offsets[] = { pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_rst"); - - rst.req = gpiod_chip_request_lines(c, rcfg, lcfg); - rst.pin = pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - return rst.req != NULL; + rst = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rst"); + return rst != NULL; } bool sx126x_init_busy(const char *chip, uint8_t pin) { syslog(LOG_INFO, "Busy GPIO %s:%i", chip, (int) pin); - - struct gpiod_chip *c = gpiod_chip_open(chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_INPUT); - - unsigned int offsets[] = { pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_busy"); - - busy.req = gpiod_chip_request_lines(c, rcfg, lcfg); - busy.pin = pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - return busy.req != NULL; + busy = gpio_request(chip, pin, GPIO_DIR_INPUT, GPIO_VALUE_INACTIVE, "sx126x_busy"); + return busy != NULL; } bool sx126x_init_dio1(const char *chip, uint8_t pin) { syslog(LOG_INFO, "DIO1 GPIO %s:%i", chip, (int) pin); - - struct gpiod_chip *c = gpiod_chip_open(chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_INPUT); - gpiod_line_settings_set_edge_detection(s, GPIOD_LINE_EDGE_RISING); - - unsigned int offsets[] = { pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_dio1"); - - dio1.req = gpiod_chip_request_lines(c, rcfg, lcfg); - dio1.pin = pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - if (!dio1.req) return false; + dio1 = gpio_request(chip, pin, GPIO_DIR_INPUT_EDGE_RISING, GPIO_VALUE_INACTIVE, "sx126x_dio1"); + if (!dio1) return false; pthread_t thread; pthread_create(&thread, NULL, irq_worker, NULL); pthread_detach(thread); - return true; } bool sx126x_init_tx_en(const char *chip, uint8_t pin) { syslog(LOG_INFO, "TX EN GPIO %s:%i", chip, (int) pin); - - struct gpiod_chip *c = gpiod_chip_open(chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); - gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - - unsigned int offsets[] = { pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_tx_en"); - - tx_en.req = gpiod_chip_request_lines(c, rcfg, lcfg); - tx_en.pin = pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - return tx_en.req != NULL; + tx_en = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_tx_en"); + return tx_en != NULL; } bool sx126x_init_rx_en(const char *chip, uint8_t pin) { syslog(LOG_INFO, "RX EN GPIO %s:%i", chip, (int) pin); - - struct gpiod_chip *c = gpiod_chip_open(chip); - - if (!c) return false; - - struct gpiod_line_settings *s = gpiod_line_settings_new(); - struct gpiod_line_config *lcfg = gpiod_line_config_new(); - struct gpiod_request_config *rcfg = gpiod_request_config_new(); - - gpiod_line_settings_set_direction(s, GPIOD_LINE_DIRECTION_OUTPUT); - gpiod_line_settings_set_output_value(s, GPIOD_LINE_VALUE_INACTIVE); - - unsigned int offsets[] = { pin }; - gpiod_line_config_add_line_settings(lcfg, offsets, 1, s); - gpiod_request_config_set_consumer(rcfg, "sx126x_rx_en"); - - rx_en.req = gpiod_chip_request_lines(c, rcfg, lcfg); - rx_en.pin = pin; - - gpiod_line_settings_free(s); - gpiod_line_config_free(lcfg); - gpiod_request_config_free(rcfg); - gpiod_chip_close(c); - - return rx_en.req != NULL; + rx_en = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rx_en"); + return rx_en != NULL; } void sx126x_set_rx_done_callback(sx126x_rx_done_callback_t callback) { @@ -739,9 +569,9 @@ void sx126x_set_timeout_callback(sx126x_timeout_callback_t callback) { } bool sx126x_begin() { - gpiod_line_request_set_value(rst.req, rst.pin, GPIOD_LINE_VALUE_INACTIVE); + gpio_set(rst, GPIO_VALUE_INACTIVE); usleep(10000); - gpiod_line_request_set_value(rst.req, rst.pin, GPIOD_LINE_VALUE_ACTIVE); + gpio_set(rst, GPIO_VALUE_ACTIVE); usleep(10000); state = SX126X_IDLE; From 4ba087b87faf5fd98679f19fa708bcaf76d93d59 Mon Sep 17 00:00:00 2001 From: exepirit Date: Wed, 11 Mar 2026 22:29:26 +0700 Subject: [PATCH 3/5] build: only sx126x must depends on libgpiod --- CMakeLists.txt | 6 +----- sx126x/CMakeLists.txt | 3 +++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 471d101..498ecf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,19 +7,15 @@ set(CMAKE_CXX_FLAGS_RELEASE "-O3") set(CMAKE_C_FLAGS_DEBUG "-O3") set(CMAKE_CXX_FLAGS_DEBUG "-O3") -find_package(PkgConfig REQUIRED) - add_executable(${PROJECT_NAME}) -target_include_directories(${PROJECT_NAME} PRIVATE ${GPIOD_INCLUDE_DIRS}) - add_subdirectory(src) add_subdirectory(sx126x) include_directories(src) include_directories(sx126x) -target_link_libraries(${PROJECT_NAME} PRIVATE ${GPIOD_LIBRARIES} m cyaml) +target_link_libraries(${PROJECT_NAME} PRIVATE m cyaml) install(FILES rnode.yaml DESTINATION /mnt/rns) install(TARGETS ${PROJECT_NAME} DESTINATION sbin) diff --git a/sx126x/CMakeLists.txt b/sx126x/CMakeLists.txt index c8f7d2d..64ce194 100644 --- a/sx126x/CMakeLists.txt +++ b/sx126x/CMakeLists.txt @@ -1,3 +1,4 @@ +find_package(PkgConfig REQUIRED) pkg_check_modules(GPIOD libgpiod>=2.0) if(GPIOD_FOUND) @@ -7,6 +8,8 @@ else() target_sources(${PROJECT_NAME} PRIVATE gpio_hal_v1.c) endif() +target_link_libraries(${PROJECT_NAME} PRIVATE ${GPIOD_LIBRARIES}) + target_sources(${PROJECT_NAME} PUBLIC sx126x.c ) From 04bb9ab17b0d14838c627ba4d5f0fe474e0fc545 Mon Sep 17 00:00:00 2001 From: exepirit Date: Wed, 11 Mar 2026 22:31:05 +0700 Subject: [PATCH 4/5] sx126x: increase timeout --- sx126x/gpio_hal_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sx126x/gpio_hal_v1.c b/sx126x/gpio_hal_v1.c index e9a7031..62c7916 100644 --- a/sx126x/gpio_hal_v1.c +++ b/sx126x/gpio_hal_v1.c @@ -84,7 +84,7 @@ void gpio_set(gpio_line_t *line, gpio_value_t val) { } int gpio_read_edge_rising(gpio_line_t *line) { - struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 }; + struct timespec timeout = { .tv_sec = 60, .tv_nsec = 0 }; int res = gpiod_line_event_wait(line->line, &timeout); if (res < 0) return -1; From 4e6b6a806bf1a9417fcc57d5d6e392deacca43f2 Mon Sep 17 00:00:00 2001 From: exepirit Date: Wed, 18 Mar 2026 21:09:23 +0700 Subject: [PATCH 5/5] config: use chip number instead of chip path --- rnode.yaml | 12 ++++++------ src/config.c | 2 +- src/config.h | 4 ++-- src/main.c | 12 ++++++------ sx126x/gpio_hal.h | 2 +- sx126x/gpio_hal_v1.c | 10 +++++----- sx126x/gpio_hal_v2.c | 8 ++++++-- sx126x/sx126x.c | 36 ++++++++++++++++++------------------ sx126x/sx126x.h | 12 ++++++------ 9 files changed, 51 insertions(+), 47 deletions(-) diff --git a/rnode.yaml b/rnode.yaml index 15a7f07..556cd43 100644 --- a/rnode.yaml +++ b/rnode.yaml @@ -2,10 +2,10 @@ # Board RNS-Gate spi: /dev/spidev1.0 -cs: { chip: /dev/gpiochip0, pin: 13 } -rst: { chip: /dev/gpiochip0, pin: 6 } -busy: { chip: /dev/gpiochip0, pin: 11 } -dio1: { chip: /dev/gpiochip0, pin: 12 } -rx_en: { chip: /dev/gpiochip0, pin: 2 } -tx_en: { chip: /dev/gpiochip0, pin: 18 } +cs: { port: 0, pin: 13 } +rst: { port: 0, pin: 6 } +busy: { port: 0, pin: 11 } +dio1: { port: 0, pin: 12 } +rx_en: { port: 0, pin: 2 } +tx_en: { port: 0, pin: 18 } tcp_port: 7633 diff --git a/src/config.c b/src/config.c index d0f201d..c9d6ef7 100644 --- a/src/config.c +++ b/src/config.c @@ -11,7 +11,7 @@ #include "config.h" const cyaml_schema_field_t gpio_fields_schema[] = { - CYAML_FIELD_STRING_PTR("chip", CYAML_FLAG_POINTER, config_gpio_t, chip, 0, CYAML_UNLIMITED), + CYAML_FIELD_UINT("port", CYAML_FLAG_DEFAULT, config_gpio_t, port), CYAML_FIELD_UINT("pin", CYAML_FLAG_DEFAULT, config_gpio_t, pin), CYAML_FIELD_END }; diff --git a/src/config.h b/src/config.h index b7b5b81..6cb80ca 100644 --- a/src/config.h +++ b/src/config.h @@ -13,8 +13,8 @@ #include typedef struct { - const char *chip; - uint8_t pin; + uint8_t port; + uint8_t pin; } config_gpio_t; typedef struct { diff --git a/src/main.c b/src/main.c index e358b02..514b647 100644 --- a/src/main.c +++ b/src/main.c @@ -28,32 +28,32 @@ int main(int argc, char *argv[]) { return 1; } - if (!sx126x_init_spi(config->spi, config->cs.chip, config->cs.pin)) { + if (!sx126x_init_spi(config->spi, config->cs.port, config->cs.pin)) { syslog(LOG_ERR, "SPI init"); return 1; } - if (!sx126x_init_rst(config->rst.chip, config->rst.pin)) { + if (!sx126x_init_rst(config->rst.port, config->rst.pin)) { syslog(LOG_ERR, "RST pin"); return 1; } - if (!sx126x_init_busy(config->busy.chip, config->busy.pin)) { + if (!sx126x_init_busy(config->busy.port, config->busy.pin)) { syslog(LOG_ERR, "Busy pin"); return 1; } - if (!sx126x_init_dio1(config->dio1.chip, config->dio1.pin)) { + if (!sx126x_init_dio1(config->dio1.port, config->dio1.pin)) { syslog(LOG_ERR, "DIO1 pin"); return 1; } - if (!sx126x_init_tx_en(config->tx_en.chip, config->tx_en.pin)) { + if (!sx126x_init_tx_en(config->tx_en.port, config->tx_en.pin)) { syslog(LOG_ERR, "TX EN pin"); return 1; } - if (!sx126x_init_rx_en(config->rx_en.chip, config->rx_en.pin)) { + if (!sx126x_init_rx_en(config->rx_en.port, config->rx_en.pin)) { syslog(LOG_ERR, "RX EN pin"); return 1; } diff --git a/sx126x/gpio_hal.h b/sx126x/gpio_hal.h index b1c91f4..1f8125d 100644 --- a/sx126x/gpio_hal.h +++ b/sx126x/gpio_hal.h @@ -20,7 +20,7 @@ typedef enum { } gpio_value_t; /* Allocate and configure a GPIO line. Returns NULL on failure. */ -gpio_line_t *gpio_request(const char *chip, +gpio_line_t *gpio_request(unsigned int chip, unsigned int pin, gpio_dir_t dir, gpio_value_t initial, diff --git a/sx126x/gpio_hal_v1.c b/sx126x/gpio_hal_v1.c index 62c7916..4db8d79 100644 --- a/sx126x/gpio_hal_v1.c +++ b/sx126x/gpio_hal_v1.c @@ -14,18 +14,18 @@ struct gpio_line { struct gpiod_line *line; }; -gpio_line_t *gpio_request(const char *chip_path, +gpio_line_t *gpio_request(unsigned int chip, unsigned int pin, gpio_dir_t dir, gpio_value_t initial, const char *consumer) { - struct gpiod_chip *chip = gpiod_chip_open(chip); + struct gpiod_chip *chip_h = gpiod_chip_open_by_number(chip); if (!chip) return NULL; - struct gpiod_line *line = gpiod_chip_get_line(chip, pin); + struct gpiod_line *line = gpiod_chip_get_line(chip_h, pin); if (!line) { - gpiod_chip_close(chip); + gpiod_chip_close(chip_h); return NULL; } @@ -53,7 +53,7 @@ gpio_line_t *gpio_request(const char *chip_path, break; } - gpiod_chip_close(chip); + gpiod_chip_close(chip_h); if (result < 0) return NULL; diff --git a/sx126x/gpio_hal_v2.c b/sx126x/gpio_hal_v2.c index e031b78..db56e67 100644 --- a/sx126x/gpio_hal_v2.c +++ b/sx126x/gpio_hal_v2.c @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -16,13 +17,16 @@ struct gpio_line { struct gpiod_edge_event_buffer *event_buf; }; -gpio_line_t *gpio_request(const char *chip, +gpio_line_t *gpio_request(unsigned int chip, unsigned int pin, gpio_dir_t dir, gpio_value_t initial, const char *consumer) { - struct gpiod_chip *chip_h = gpiod_chip_open(chip); + char chip_path[32]; + snprintf(chip_path, sizeof(chip_path), "/dev/gpiochip%u", chip); + + struct gpiod_chip *chip_h = gpiod_chip_open(chip_path); if (!chip_h) return NULL; struct gpiod_line_settings *settings = gpiod_line_settings_new(); diff --git a/sx126x/sx126x.c b/sx126x/sx126x.c index 0058614..371114d 100644 --- a/sx126x/sx126x.c +++ b/sx126x/sx126x.c @@ -508,30 +508,30 @@ static void * irq_worker(void *p) { /* * */ -bool sx126x_init_spi(const char *spidev, const char *cs_chip, uint8_t cs_pin) { +bool sx126x_init_spi(const char *spidev, uint8_t cs_port, uint8_t cs_pin) { spi_fd = open(spidev, O_RDWR); if (spi_fd < 0) return false; - syslog(LOG_INFO, "SPI %s, CS GPIO %s:%i", spidev, cs_chip, (int) cs_pin); - cs = gpio_request(cs_chip, cs_pin, GPIO_DIR_OUTPUT, GPIO_VALUE_ACTIVE, "sx126x_cs"); + syslog(LOG_INFO, "SPI %s, CS GPIO chip%u:%u", spidev, (unsigned) cs_port, (unsigned) cs_pin); + cs = gpio_request(cs_port, cs_pin, GPIO_DIR_OUTPUT, GPIO_VALUE_ACTIVE, "sx126x_cs"); return cs != NULL; } -bool sx126x_init_rst(const char *chip, uint8_t pin) { - syslog(LOG_INFO, "RST GPIO %s:%i", chip, (int) pin); - rst = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rst"); +bool sx126x_init_rst(uint8_t port, uint8_t pin) { + syslog(LOG_INFO, "RST GPIO chip%u:%u", (unsigned) port, (unsigned) pin); + rst = gpio_request(port, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rst"); return rst != NULL; } -bool sx126x_init_busy(const char *chip, uint8_t pin) { - syslog(LOG_INFO, "Busy GPIO %s:%i", chip, (int) pin); - busy = gpio_request(chip, pin, GPIO_DIR_INPUT, GPIO_VALUE_INACTIVE, "sx126x_busy"); +bool sx126x_init_busy(uint8_t port, uint8_t pin) { + syslog(LOG_INFO, "Busy GPIO chip%u:%u", (unsigned) port, (unsigned) pin); + busy = gpio_request(port, pin, GPIO_DIR_INPUT, GPIO_VALUE_INACTIVE, "sx126x_busy"); return busy != NULL; } -bool sx126x_init_dio1(const char *chip, uint8_t pin) { - syslog(LOG_INFO, "DIO1 GPIO %s:%i", chip, (int) pin); - dio1 = gpio_request(chip, pin, GPIO_DIR_INPUT_EDGE_RISING, GPIO_VALUE_INACTIVE, "sx126x_dio1"); +bool sx126x_init_dio1(uint8_t port, uint8_t pin) { + syslog(LOG_INFO, "DIO1 GPIO chip%u:%u", (unsigned) port, (unsigned) pin); + dio1 = gpio_request(port, pin, GPIO_DIR_INPUT_EDGE_RISING, GPIO_VALUE_INACTIVE, "sx126x_dio1"); if (!dio1) return false; pthread_t thread; @@ -540,15 +540,15 @@ bool sx126x_init_dio1(const char *chip, uint8_t pin) { return true; } -bool sx126x_init_tx_en(const char *chip, uint8_t pin) { - syslog(LOG_INFO, "TX EN GPIO %s:%i", chip, (int) pin); - tx_en = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_tx_en"); +bool sx126x_init_tx_en(uint8_t port, uint8_t pin) { + syslog(LOG_INFO, "TX EN GPIO chip%u:%u", (unsigned) port, (unsigned) pin); + tx_en = gpio_request(port, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_tx_en"); return tx_en != NULL; } -bool sx126x_init_rx_en(const char *chip, uint8_t pin) { - syslog(LOG_INFO, "RX EN GPIO %s:%i", chip, (int) pin); - rx_en = gpio_request(chip, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rx_en"); +bool sx126x_init_rx_en(uint8_t port, uint8_t pin) { + syslog(LOG_INFO, "RX EN GPIO chip%u:%u", (unsigned) port, (unsigned) pin); + rx_en = gpio_request(port, pin, GPIO_DIR_OUTPUT, GPIO_VALUE_INACTIVE, "sx126x_rx_en"); return rx_en != NULL; } diff --git a/sx126x/sx126x.h b/sx126x/sx126x.h index 1c114b6..3263929 100644 --- a/sx126x/sx126x.h +++ b/sx126x/sx126x.h @@ -99,12 +99,12 @@ typedef void (*sx126x_tx_done_callback_t)(void); typedef void (*sx126x_medium_callback_t)(cause_medium_t cause); typedef void (*sx126x_timeout_callback_t)(void); -bool sx126x_init_spi(const char *spidev, const char *cs_chip, uint8_t cs_pin); -bool sx126x_init_rst(const char *chip, uint8_t pin); -bool sx126x_init_busy(const char *chip, uint8_t pin); -bool sx126x_init_dio1(const char *chip, uint8_t pin); -bool sx126x_init_tx_en(const char *chip, uint8_t pin); -bool sx126x_init_rx_en(const char *chip, uint8_t pin); +bool sx126x_init_spi(const char *spidev, uint8_t cs_port, uint8_t cs_pin); +bool sx126x_init_rst(uint8_t port, uint8_t pin); +bool sx126x_init_busy(uint8_t port, uint8_t pin); +bool sx126x_init_dio1(uint8_t port, uint8_t pin); +bool sx126x_init_tx_en(uint8_t port, uint8_t pin); +bool sx126x_init_rx_en(uint8_t port, uint8_t pin); void sx126x_set_rx_done_callback(sx126x_rx_done_callback_t callback); void sx126x_set_tx_done_callback(sx126x_tx_done_callback_t callback);