From 410b277b2275ec1a1ce4faba933e8de947616d4c Mon Sep 17 00:00:00 2001 From: "i.ostanin" Date: Sun, 16 Feb 2025 13:17:40 +0300 Subject: [PATCH 1/4] added libsx1262 example --- examples/sx1262_test/Kconfig | 29 +++++++++++++++++++++++++++++ examples/sx1262_test/Make.defs | 23 +++++++++++++++++++++++ examples/sx1262_test/Makefile | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 examples/sx1262_test/Kconfig create mode 100644 examples/sx1262_test/Make.defs create mode 100644 examples/sx1262_test/Makefile diff --git a/examples/sx1262_test/Kconfig b/examples/sx1262_test/Kconfig new file mode 100644 index 00000000000..e61c3b19760 --- /dev/null +++ b/examples/sx1262_test/Kconfig @@ -0,0 +1,29 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_SX1262_TEST + tristate "\"Sx1262_test, World!\" example" + default n + ---help--- + Enable the \"Sx1262_test, World!\" example + +if EXAMPLES_SX1262_TEST + +config EXAMPLES_SX1262_TEST_PROGNAME + string "Program name" + default "sx1262_test" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_SX1262_TEST_PRIORITY + int "Sx1262_test task priority" + default 100 + +config EXAMPLES_SX1262_TEST_STACKSIZE + int "Sx1262_test stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/examples/sx1262_test/Make.defs b/examples/sx1262_test/Make.defs new file mode 100644 index 00000000000..296636f5aae --- /dev/null +++ b/examples/sx1262_test/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/sx1262_test/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_SX1262_TEST),) +CONFIGURED_APPS += $(APPDIR)/examples/sx1262_test +endif diff --git a/examples/sx1262_test/Makefile b/examples/sx1262_test/Makefile new file mode 100644 index 00000000000..67e0ed6e700 --- /dev/null +++ b/examples/sx1262_test/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/examples/sx1262_test/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# Sx1262_test, World! built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_SX1262_TEST_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_SX1262_TEST_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_SX1262_TEST_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_SX1262_TEST) + +# Sx1262_test, World! Example + +MAINSRC = sx1262_test_main.c + +include $(APPDIR)/Application.mk \ No newline at end of file From a101b41a8cdb0c0919a866a53709f4e4d910548f Mon Sep 17 00:00:00 2001 From: "i.ostanin" Date: Sun, 16 Feb 2025 15:47:18 +0300 Subject: [PATCH 2/4] sx1262_test works but driver doesn't --- examples/sx1262_test/sx1262_test_main.c | 432 ++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 examples/sx1262_test/sx1262_test_main.c diff --git a/examples/sx1262_test/sx1262_test_main.c b/examples/sx1262_test/sx1262_test_main.c new file mode 100644 index 00000000000..28d7c1a91d1 --- /dev/null +++ b/examples/sx1262_test/sx1262_test_main.c @@ -0,0 +1,432 @@ +/**************************************************************************** + * apps/examples/sx1262_test/sx1262_test_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +// Demo Program for LoRa SX1262 on NuttX +#include +#include +#include +#include +#include +#include "../../../nuttx/libs/libsx1262/include/radio.h" +#include "../../../nuttx/libs/libsx1262/include/sx126x-board.h" + +/// TODO: We are using LoRa Frequency 923 MHz for Singapore. Change this for your region. +#define USE_BAND_923 + +#if defined(USE_BAND_433) + #define RF_FREQUENCY 434000000 /* Hz */ +#elif defined(USE_BAND_780) + #define RF_FREQUENCY 780000000 /* Hz */ +#elif defined(USE_BAND_868) + #define RF_FREQUENCY 868000000 /* Hz */ +#elif defined(USE_BAND_915) + #define RF_FREQUENCY 915000000 /* Hz */ +#elif defined(USE_BAND_923) + #define RF_FREQUENCY 923000000 /* Hz */ +#else + #error "Please define a frequency band in the compiler options." +#endif + +/// LoRa Parameters +#define LORAPING_TX_OUTPUT_POWER 14 /* dBm */ + +#define LORAPING_BANDWIDTH 0 /* [0: 125 kHz, */ + /* 1: 250 kHz, */ + /* 2: 500 kHz, */ + /* 3: Reserved] */ +#define LORAPING_SPREADING_FACTOR 7 /* [SF7..SF12] */ +#define LORAPING_CODINGRATE 1 /* [1: 4/5, */ + /* 2: 4/6, */ + /* 3: 4/7, */ + /* 4: 4/8] */ +#define LORAPING_PREAMBLE_LENGTH 8 /* Same for Tx and Rx */ +#define LORAPING_SYMBOL_TIMEOUT 5 /* Symbols */ +#define LORAPING_FIX_LENGTH_PAYLOAD_ON false +#define LORAPING_IQ_INVERSION_ON false + +#define LORAPING_TX_TIMEOUT_MS 3000 /* ms */ +#define LORAPING_RX_TIMEOUT_MS 10000 /* ms */ +#define LORAPING_BUFFER_SIZE 64 /* LoRa message size */ + +const uint8_t loraping_ping_msg[] = "PING"; // We send a "PING" message +const uint8_t loraping_pong_msg[] = "PONG"; // We expect a "PONG" response + +static uint8_t loraping_buffer[LORAPING_BUFFER_SIZE]; // 64-byte buffer for our LoRa messages +static int loraping_rx_size; + +/// LoRa Statistics +struct { + int rx_timeout; + int rx_ping; + int rx_pong; + int rx_other; + int rx_error; + int tx_timeout; + int tx_success; +} loraping_stats; + +/////////////////////////////////////////////////////////////////////////////// +// Main Function + +static void read_registers(void); +static void init_driver(void); +static void send_message(void); +static void receive_message(void); +static void create_task(void); + +int main(int argc, FAR char *argv[]) { + + /* Call SX1262 Library */ + + test_libsx1262(); + +// Uncomment to read SX1262 registers +// #define READ_REGISTERS +#ifdef READ_REGISTERS + // Read SX1262 registers 0x00 to 0x0F + read_registers(); +#endif // READ_REGISTERS + + // TODO: Create a Background Thread to handle LoRa Events + create_task(); + + // Init SX1262 driver + init_driver(); + + // TODO: Do we need to wait? + sleep(1); + +// Uncomment to send a LoRa message +// #define SEND_MESSAGE +#ifdef SEND_MESSAGE + // Send a LoRa message + send_message(); +#endif // SEND_MESSAGE + +// Uncomment to receive a LoRa message +#define RECEIVE_MESSAGE +#ifdef RECEIVE_MESSAGE + // Handle LoRa events for the next 10 seconds + for (int i = 0; i < 10; i++) { + // Prepare to receive a LoRa message + receive_message(); + + // Process the received LoRa message, if any + RadioOnDioIrq(NULL); + + // Sleep for 1 second + usleep(1000 * 1000); + } +#endif // RECEIVE_MESSAGE + + // TODO: Close the SPI Bus + // close(spi); + puts("Done!"); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// LoRa Commands + +static void send_once(int is_ping); +static void on_tx_done(void); +static void on_rx_done(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr); +static void on_tx_timeout(void); +static void on_rx_timeout(void); +static void on_rx_error(void); + +/// Read SX1262 registers +static void read_registers(void) { + puts("read_registers"); + + // Init the SPI port + SX126xIoInit(); + + // Read and print the first 16 registers: 0 to 15 + for (uint16_t addr = 0; addr < 0x10; addr++) { + // Read the register + uint8_t val = SX126xReadRegister(addr); // For SX1262 + // uint8_t val = SX1276Read(addr); // For SX1276 + + // Print the register value + printf("Register 0x%02x = 0x%02x\n", addr, val); + } +} + +/// Initialise the SX1262 driver. +/// Assume that create_task has been called to init the Event Queue. +static void init_driver(void) { + puts("init_driver"); + + // Set the LoRa Callback Functions + RadioEvents_t radio_events; + memset(&radio_events, 0, sizeof(radio_events)); // Must init radio_events to null, because radio_events lives on stack! + radio_events.TxDone = on_tx_done; + radio_events.RxDone = on_rx_done; + radio_events.TxTimeout = on_tx_timeout; + radio_events.RxTimeout = on_rx_timeout; + radio_events.RxError = on_rx_error; + + // Init the SPI Port and the LoRa Transceiver + Radio.Init(&radio_events); + + // Set the LoRa Frequency + Radio.SetChannel(RF_FREQUENCY); + + // Configure the LoRa Transceiver for transmitting messages + Radio.SetTxConfig( + MODEM_LORA, + LORAPING_TX_OUTPUT_POWER, + 0, // Frequency deviation: Unused with LoRa + LORAPING_BANDWIDTH, + LORAPING_SPREADING_FACTOR, + LORAPING_CODINGRATE, + LORAPING_PREAMBLE_LENGTH, + LORAPING_FIX_LENGTH_PAYLOAD_ON, + true, // CRC enabled + 0, // Frequency hopping disabled + 0, // Hop period: N/A + LORAPING_IQ_INVERSION_ON, + LORAPING_TX_TIMEOUT_MS + ); + + // Configure the LoRa Transceiver for receiving messages + Radio.SetRxConfig( + MODEM_LORA, + LORAPING_BANDWIDTH, + LORAPING_SPREADING_FACTOR, + LORAPING_CODINGRATE, + 0, // AFC bandwidth: Unused with LoRa + LORAPING_PREAMBLE_LENGTH, + LORAPING_SYMBOL_TIMEOUT, + LORAPING_FIX_LENGTH_PAYLOAD_ON, + 0, // Fixed payload length: N/A + true, // CRC enabled + 0, // Frequency hopping disabled + 0, // Hop period: N/A + LORAPING_IQ_INVERSION_ON, + true // Continuous receive mode + ); +} + +/// Send a LoRa message. Assume that SX1262 driver has been initialised. +static void send_message(void) { + puts("send_message"); + + // Send the "PING" message + send_once(1); +} + +/// Send a LoRa message. If is_ping is 0, send "PONG". Otherwise send "PING". +static void send_once(int is_ping) { + // Copy the "PING" or "PONG" message to the transmit buffer + if (is_ping) { + memcpy(loraping_buffer, loraping_ping_msg, 4); + } else { + memcpy(loraping_buffer, loraping_pong_msg, 4); + } + + // Fill up the remaining space in the transmit buffer (64 bytes) with values 0, 1, 2, ... + for (int i = 4; i < sizeof loraping_buffer; i++) { + loraping_buffer[i] = i - 4; + } + + // We send the transmit buffer (64 bytes) + Radio.Send(loraping_buffer, sizeof loraping_buffer); +} + +/// Receive a LoRa message. Assume that SX1262 driver has been initialised. +/// Assume that create_task has been called to init the Event Queue. +static void receive_message(void) { + puts("receive_message"); + + // Receive a LoRa message within the timeout period + Radio.Rx(LORAPING_RX_TIMEOUT_MS); +} + +/////////////////////////////////////////////////////////////////////////////// +// LoRa Callback Functions + +/// Callback Function that is called when our LoRa message has been transmitted +static void on_tx_done(void) +{ + puts("Tx done"); + + // Log the success status + loraping_stats.tx_success++; + + // Switch the LoRa Transceiver to low power, sleep mode + Radio.Sleep(); + + // TODO: Receive a "PING" or "PONG" LoRa message + // os_eventq_put(os_eventq_dflt_get(), &loraping_ev_rx); +} + +/// Callback Function that is called when a LoRa message has been received +static void on_rx_done( + uint8_t *payload, // Buffer containing received LoRa message + uint16_t size, // Size of the LoRa message + int16_t rssi, // Signal strength + int8_t snr) // Signal To Noise ratio +{ + puts("Rx done:"); + + // Switch the LoRa Transceiver to low power, sleep mode + Radio.Sleep(); + + // Copy the received packet + if (size > sizeof loraping_buffer) { + size = sizeof loraping_buffer; + } + loraping_rx_size = size; + memcpy(loraping_buffer, payload, size); + + // Log the signal strength, signal to noise ratio + // TODO: loraping_rxinfo_rxed(rssi, snr); + + // Dump the contents of the received packet + for (int i = 0; i < loraping_rx_size; i++) { + printf("%02x ", loraping_buffer[i]); + } + puts(""); + + // TODO: Send a "PING" or "PONG" LoRa message + // os_eventq_put(os_eventq_dflt_get(), &loraping_ev_tx); +} + +/// Callback Function that is called when our LoRa message couldn't be transmitted due to timeout +static void on_tx_timeout(void) { + puts("Tx timeout"); + + // Switch the LoRa Transceiver to low power, sleep mode + Radio.Sleep(); + + // Log the timeout + loraping_stats.tx_timeout++; + + // TODO: Receive a "PING" or "PONG" LoRa message + // os_eventq_put(os_eventq_dflt_get(), &loraping_ev_rx); +} + +/// Callback Function that is called when no LoRa messages could be received due to timeout +static void on_rx_timeout(void) { + puts("Rx timeout"); + + // Switch the LoRa Transceiver to low power, sleep mode + Radio.Sleep(); + + // Log the timeout + loraping_stats.rx_timeout++; + // TODO: loraping_rxinfo_timeout(); + + // TODO: Send a "PING" or "PONG" LoRa message + // os_eventq_put(os_eventq_dflt_get(), &loraping_ev_tx); +} + +/// Callback Function that is called when we couldn't receive a LoRa message due to error +static void on_rx_error(void) { + puts("Rx error"); + + // Log the error + loraping_stats.rx_error++; + + // Switch the LoRa Transceiver to low power, sleep mode + Radio.Sleep(); + + // TODO: Send a "PING" or "PONG" LoRa message + // os_eventq_put(os_eventq_dflt_get(), &loraping_ev_tx); +} + +/////////////////////////////////////////////////////////////////////////////// +// Multitasking Commands + +/// Event Queue containing Events to be processed +////TODO struct ble_npl_eventq event_queue; + +/// Event to be added to the Event Queue +////TODO struct ble_npl_event event; + +static void task_callback(void *arg); +static void handle_event(struct ble_npl_event *ev); + +/// TODO: Create a Background Task to handle LoRa Events +/// This is unused because we don't have a Background Thread to process the Event Queue. +static void create_task(void) { + puts("TODO: create_task"); + +#ifdef TODO + // Init the Event Queue + ble_npl_eventq_init(&event_queue); + + // Init the Event + ble_npl_event_init( + &event, // Event + handle_event, // Event Handler Function + NULL // Argument to be passed to Event Handler + ); +#endif // TODO + + // TODO: Create a Background Thread to process the Event Queue + // nimble_port_freertos_init(task_callback); +} + +/// TODO: Enqueue an Event into the Event Queue. +/// This is unused because we don't have a Background Thread to process the Event Queue. +static void put_event(char *buf, int len, int argc, char **argv) { + puts("TODO: put_event"); + +#ifdef TODO + // Add the Event to the Event Queue + ble_npl_eventq_put(&event_queue, &event); +#endif // TODO +} + +/// TODO: Task Function that dequeues Events from the Event Queue and processes the Events. +/// This is unused because we don't have a Background Thread to process the Event Queue. +static void task_callback(void *arg) { + puts("TODO: task_callback"); + +#ifdef TODO + // Loop forever handling Events from the Event Queue + for (;;) { + // Get the next Event from the Event Queue + struct ble_npl_event *ev = ble_npl_eventq_get( + &event_queue, // Event Queue + 1000 // Timeout in 1,000 ticks + ); + + // If no Event due to timeout, wait for next Event + if (ev == NULL) { continue; } + + // Remove the Event from the Event Queue + ble_npl_eventq_remove(&event_queue, ev); + + // Trigger the Event Handler Function (handle_event) + ble_npl_event_run(ev); + } +#endif // TODO +} + +/// TODO: Handle an Event +/// This is unused because we don't have a Background Thread to process the Event Queue. +static void handle_event(struct ble_npl_event *ev) { + puts("handle_event"); + puts("Handle an event"); +} \ No newline at end of file From af5fa558e5673ef66bd6ffb99925c2bf34086302 Mon Sep 17 00:00:00 2001 From: "i.ostanin" Date: Sun, 16 Feb 2025 18:27:21 +0300 Subject: [PATCH 3/4] spi1 cs fixed. sx1262 works --- examples/sx1262_test/sx1262_test_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sx1262_test/sx1262_test_main.c b/examples/sx1262_test/sx1262_test_main.c index 28d7c1a91d1..a6ea91309db 100644 --- a/examples/sx1262_test/sx1262_test_main.c +++ b/examples/sx1262_test/sx1262_test_main.c @@ -99,10 +99,10 @@ int main(int argc, FAR char *argv[]) { // Uncomment to read SX1262 registers // #define READ_REGISTERS -#ifdef READ_REGISTERS +// #ifdef READ_REGISTERS // Read SX1262 registers 0x00 to 0x0F read_registers(); -#endif // READ_REGISTERS +// #endif // READ_REGISTERS // TODO: Create a Background Thread to handle LoRa Events create_task(); From dae7a4d307fec8685d58939753d0270ca3a087cf Mon Sep 17 00:00:00 2001 From: Iahve Date: Mon, 16 Jun 2025 00:44:32 +0300 Subject: [PATCH 4/4] add simple ping program --- wireless/sx1262/Kconfig | 29 +++ wireless/sx1262/Make.defs | 3 + wireless/sx1262/Makefile | 14 ++ wireless/sx1262/sx1262.c | 478 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 524 insertions(+) create mode 100644 wireless/sx1262/Kconfig create mode 100644 wireless/sx1262/Make.defs create mode 100644 wireless/sx1262/Makefile create mode 100644 wireless/sx1262/sx1262.c diff --git a/wireless/sx1262/Kconfig b/wireless/sx1262/Kconfig new file mode 100644 index 00000000000..ed73fd15356 --- /dev/null +++ b/wireless/sx1262/Kconfig @@ -0,0 +1,29 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig WIRELESS_SX1262 + tristate "Custom sx1262 App" + default n + ---help--- + Enable the Custom sx1262 App + +if WIRELESS_SX1262 + +config WIRELESS_SX1262_PROGNAME + string "Program name" + default "custom_sx1262" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config WIRELESS_SX1262_PRIORITY + int "Custom sx1262 task priority" + default 100 + +config WIRELESS_SX1262_STACKSIZE + int "Custom sx1262 stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/wireless/sx1262/Make.defs b/wireless/sx1262/Make.defs new file mode 100644 index 00000000000..86456d482bc --- /dev/null +++ b/wireless/sx1262/Make.defs @@ -0,0 +1,3 @@ +ifneq ($(CONFIG_WIRELESS_SX1262),) +CONFIGURED_APPS += $(APPDIR)/wireless/sx1262 +endif \ No newline at end of file diff --git a/wireless/sx1262/Makefile b/wireless/sx1262/Makefile new file mode 100644 index 00000000000..a8540cd5849 --- /dev/null +++ b/wireless/sx1262/Makefile @@ -0,0 +1,14 @@ +include $(APPDIR)/Make.defs + +# Custom sx1262 built-in application info + +PROGNAME = $(CONFIG_WIRELESS_SX1262_PROGNAME) +PRIORITY = $(CONFIG_WIRELESS_SX1262_PRIORITY) +STACKSIZE = $(CONFIG_WIRELESS_SX1262_STACKSIZE) +MODULE = $(CONFIG_WIRELESS_SX1262) + +# Custom sx1262 + +MAINSRC = sx1262.c + +include $(APPDIR)/Application.mk \ No newline at end of file diff --git a/wireless/sx1262/sx1262.c b/wireless/sx1262/sx1262.c new file mode 100644 index 00000000000..cecc6185114 --- /dev/null +++ b/wireless/sx1262/sx1262.c @@ -0,0 +1,478 @@ +/****************************************************************************** + * apps/examples/sx126x_demo/sx126x_demo.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * Included Files + ******************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/****************************************************************************** + * Definitions + ******************************************************************************/ + +#define SX126X_DEMO_DEVPATH "/dev/lpw0" +#define SX126X_DEMO_DEF_FREQ 869250000 +#define SX126X_DEMO_DEF_PWR 22 +#define SX126X_DEMO_DEF_SF 10 +#define SX126X_DEMO_DEF_BW 125 + +/****************************************************************************** + * Data types + ******************************************************************************/ + +enum sx126x_demo_mode_e +{ + SX126X_DEMO_TX, + SX126X_DEMO_RX, + SX126X_DEMO_ECHO, + SX126X_DEMO_TXRX +}; + +struct sx126x_demo_config_s +{ + enum sx126x_lora_sf_e sf; + enum sx126x_lora_bw_e bw; + int32_t pwr; + uint32_t frequency_hz; + char *payload; + size_t payload_size; + enum sx126x_demo_mode_e mode; +}; + +/****************************************************************************** + * Globals + ******************************************************************************/ + +/****************************************************************************** + * Public Functions + ******************************************************************************/ + +enum sx126x_lora_bw_e to_nearest_lora_bw(int bw) +{ + static const int16_t possible_bws[] = + { + 7, 10, 15, 20, 31, 41, 62, 125, 250, 500 + }; + + /* Find nearest bandwidth */ + + int16_t record_deviation = INT16_MAX; + size_t record_index = 0; + + for (size_t i = 0; i < sizeof(possible_bws) / sizeof(possible_bws[0]); i++) + { + /* Compare bandwidth */ + + int16_t possible_bw = possible_bws[i]; + int16_t deviation = abs(bw - possible_bw); + + /* Is this a better value? */ + + if (deviation < record_deviation) + { + /* New record deviation */ + + record_deviation = deviation; + record_index = i; + + if (deviation == 0) + { + /* It is perfect */ + + break; + } + } + } + + int16_t nearest_bw = possible_bws[record_index]; + + /* Did not find the perfect match, but got nearest */ + + if (record_deviation != 0) + { + printf("Bandwidth %dkHz is not available. \ + Using nearest available: %dkHz\n", + bw, nearest_bw); + } + + /* Convert to bandwidth code enum */ + + static const enum sx126x_lora_bw_e bw_enum_map[] = + { + SX126X_LORA_BW_7, SX126X_LORA_BW_10, SX126X_LORA_BW_15, + SX126X_LORA_BW_20, SX126X_LORA_BW_31, SX126X_LORA_BW_41, + SX126X_LORA_BW_62, SX126X_LORA_BW_125, SX126X_LORA_BW_250, + SX126X_LORA_BW_500 + }; + + return bw_enum_map[record_index]; +} + +void get_flags(int argc, FAR char *argv[], struct sx126x_demo_config_s *config) +{ + /* For every arg, get flag */ + + for (int i = 0; i < argc; i++) + { + char *arg = argv[i]; + + /* Flag must start with - */ + + if (arg[0] != '-') + { + continue; + } + + /* Read flag */ + + char flag = arg[1]; + switch (flag) + { + /* Is terminator */ + + case '\0': + { + break; + } + + /* Is frequency */ + + case 'f': + { + /* Get value */ + + if (i < argc - 1) + { + uint32_t freq; + freq = strtoul(argv[++i], NULL, 0); + config->frequency_hz = freq; + } + break; + } + + /* Is spreading factor */ + + case 's': + { + /* Get value */ + + if (i < argc - 1) + { + uint32_t sf; + sf = strtoul(argv[++i], NULL, 0); + config->sf = sf; + } + break; + } + + /* Is power */ + + case 'p': + { + /* Get value */ + + if (i < argc - 1) + { + int32_t power; + power = strtol(argv[++i], NULL, 0); + config->pwr = power; + } + break; + } + + /* Is bandwidth */ + + case 'b': + { + /* Get value */ + + if (i < argc - 1) + { + int bw; + bw = strtol(argv[++i], NULL, 0); + config->bw = to_nearest_lora_bw(bw); + } + break; + } + + /* Transmit */ + + case 't': + { + /* Get string */ + + if (i < argc - 1) + { + config->mode = SX126X_DEMO_TX; + config->payload = argv[++i]; + config->payload_size = strlen(config->payload); + } + break; + } + + /* Receive */ + + case 'r': + { + /* Enable */ + + config->mode = SX126X_DEMO_RX; + break; + } + + /* Transmit and Receive */ + + case 'x': + { + /* Get string */ + + if (i < argc - 1) + { + config->mode = SX126X_DEMO_TXRX; + config->payload = argv[++i]; + config->payload_size = strlen(config->payload); + } + break; + } + /* Echo back */ + + case 'e': + { + /* Enable */ + + config->mode = SX126X_DEMO_ECHO; + break; + } + + /* Unknown flag */ + + default: + { + printf("Unknown flag \"%c\"\n", flag); + break; + } + } + } +} + +void set_sx_defaults(struct sx126x_demo_config_s *config) +{ + config->bw = to_nearest_lora_bw(SX126X_DEMO_DEF_BW); + config->sf = SX126X_DEMO_DEF_SF; + config->frequency_hz = SX126X_DEMO_DEF_FREQ; + config->mode = SX126X_DEMO_TX; +} + +void list_config(struct sx126x_demo_config_s *config) +{ + printf("Frequency: %u\n", config->frequency_hz); + printf("Spreading factor: %d\n", config->sf); + printf("Bandwidth 0x%X\n", config->bw); +} + +int open_sx(struct sx126x_demo_config_s *config) +{ + int fd; + + fd = open(SX126X_DEMO_DEVPATH, O_RDWR); + if (fd < 0) + { + int errcode = errno; + printf("ERROR: Failed to open device %s: %d\n", + SX126X_DEMO_DEVPATH, errcode); + return -1; + } + + /* Config */ + + uint32_t freq = config->frequency_hz; + ioctl(fd, WLIOC_SETRADIOFREQ, &freq); + + int pwr = config->pwr; + ioctl(fd, WLIOC_SETTXPOWER, &pwr); + + struct sx126x_lora_config_s deviceconfig = + { + .modulation = + { + .bandwidth = config->bw, + .coding_rate = SX126X_LORA_CR_4_8, + .low_datarate_optimization = false, + .spreading_factor = config->sf + }, + .packet = + { + .crc_enable = true, + .fixed_length_header = false, + .payload_length = 0xff, + .invert_iq = false, + .preambles = 8 + } + }; + + ioctl(fd, SX126XIOC_LORACONFIGSET, &deviceconfig); + + return fd; +} + +void demo_tx(int fd, struct sx126x_demo_config_s *config) +{ + printf("Transmitting..."); + write(fd, config->payload, config->payload_size); + printf("\n\r"); +} + +void demo_rx(int fd, struct sx126x_demo_config_s *config) +{ + struct sx126x_read_header_s r_hdr; + printf("Receiving..."); + int success = read(fd, &r_hdr, sizeof(r_hdr)); + + if (success < 0) + { + printf("RX error\n"); + return; + } + + if (r_hdr.crc_error) + { + printf("CRC error\n"); + return; + } + + printf("Received\n"); + printf("Got %u bytes, RSSI %d, SNR %d\n", r_hdr.payload_length, r_hdr.rssi_db, r_hdr.snr); + + for (size_t i=0;i