From d70d248edecca39eee9288fffd0795212f239cb6 Mon Sep 17 00:00:00 2001 From: "Kevin Witteveen (MartiniMarter)" Date: Sun, 16 Feb 2025 16:35:21 +0100 Subject: [PATCH] Initial standalone sx126x driver WIP code style changes and correct file path initial file ops and initialization sx126x board and driver integration Squashed commit of the following: commit 5c27c1e7dd7f83e37dde3249b36c596a67f2375a Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 18 20:57:14 2025 +0100 syncword, crc and wl log commit 30a8f0a9c67615eefba6b7c67e97c1d9e8e43439 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 16:05:51 2025 +0100 style changes commit c95005561ee96a95228a640222190efab1731d77 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 16:05:38 2025 +0100 style changes and board support commit 42b3574dc831686e65ede2cb7cbda352efc8ea72 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 12:40:41 2025 +0100 payload receival commit a116b039a754fe97d2befe7c905134347324e4f4 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 20:07:14 2025 +0100 Receiving test commit 8f250dc7a7be5f78f04617ea4e7af4494127141d Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 15:51:42 2025 +0100 TX semaphore commit 02d325edba9514822bc08e60084ae5ea6bc8de78 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 14:53:19 2025 +0100 irq status commit 4d8a63f9feaf2982003600f2b609cdb6a75fb697 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 13:58:41 2025 +0100 initial interrupt handling commit 4fae8c7b683345e03bd307ecd25248088906aef0 Author: Kevin Witteveen (MartiniMarter) Date: Wed Feb 12 22:39:13 2025 +0100 writing commit 16184f7927456f1d63fee9e7089d4a9be6b3180d Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 21:10:35 2025 +0100 initial nuttx integration for testing commit d404cacca9419dd232538251d6d8704e1eac31bc Merge: 3b38c2007a 3fb5506f9c Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 19:44:41 2025 +0100 Merge branch 'sx126x_lora_driver' of https://github.com/keever50/nuttx into sx126x_testing commit 3b38c2007a2d7b42ec9d2bcf2aa4e7313ac3589b Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 19:18:41 2025 +0100 initial testing commit 3fb5506f9ce509e1aebefd1782a021cc59d6a207 Author: keever50 Date: Sun Feb 9 13:40:20 2025 +0100 Initial standalone sx126x driver WIP code style changes and correct file path initial file ops and initialization commit e51a9ad73ca62bc086beee5ba743d96edc2957f5 Author: keever50 Date: Sun Feb 9 13:38:56 2025 +0100 Initial standlone driver removal of board style Squashed commit of the following: commit ab1a8d0161bc0ea355d9b4a35378ebfc27563d7c Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 22 13:18:43 2025 +0100 typo fix commit 8e2c81ce1bf7aea43c338a42ed00c2d8bf2b7464 Author: Kevin Witteveen (MartiniMarter) Date: Fri Feb 21 20:09:35 2025 +0100 PA power fix commit 5c27c1e7dd7f83e37dde3249b36c596a67f2375a Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 18 20:57:14 2025 +0100 syncword, crc and wl log commit 30a8f0a9c67615eefba6b7c67e97c1d9e8e43439 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 16:05:51 2025 +0100 style changes commit c95005561ee96a95228a640222190efab1731d77 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 16:05:38 2025 +0100 style changes and board support commit 42b3574dc831686e65ede2cb7cbda352efc8ea72 Author: Kevin Witteveen (MartiniMarter) Date: Sun Feb 16 12:40:41 2025 +0100 payload receival commit a116b039a754fe97d2befe7c905134347324e4f4 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 20:07:14 2025 +0100 Receiving test commit 8f250dc7a7be5f78f04617ea4e7af4494127141d Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 15:51:42 2025 +0100 TX semaphore commit 02d325edba9514822bc08e60084ae5ea6bc8de78 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 14:53:19 2025 +0100 irq status commit 4d8a63f9feaf2982003600f2b609cdb6a75fb697 Author: Kevin Witteveen (MartiniMarter) Date: Sat Feb 15 13:58:41 2025 +0100 initial interrupt handling commit 4fae8c7b683345e03bd307ecd25248088906aef0 Author: Kevin Witteveen (MartiniMarter) Date: Wed Feb 12 22:39:13 2025 +0100 writing commit 16184f7927456f1d63fee9e7089d4a9be6b3180d Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 21:10:35 2025 +0100 initial nuttx integration for testing commit d404cacca9419dd232538251d6d8704e1eac31bc Merge: 3b38c2007a 3fb5506f9c Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 19:44:41 2025 +0100 Merge branch 'sx126x_lora_driver' of https://github.com/keever50/nuttx into sx126x_testing commit 3b38c2007a2d7b42ec9d2bcf2aa4e7313ac3589b Author: Kevin Witteveen (MartiniMarter) Date: Tue Feb 11 19:18:41 2025 +0100 initial testing commit 3fb5506f9ce509e1aebefd1782a021cc59d6a207 Author: keever50 Date: Sun Feb 9 13:40:20 2025 +0100 Initial standalone sx126x driver WIP code style changes and correct file path initial file ops and initialization commit e51a9ad73ca62bc086beee5ba743d96edc2957f5 Author: keever50 Date: Sun Feb 9 13:38:56 2025 +0100 Initial standlone driver board removal style --- drivers/wireless/lpwan/Kconfig | 9 + drivers/wireless/lpwan/Make.defs | 1 + drivers/wireless/lpwan/sx126x/CMakeLists.txt | 24 + drivers/wireless/lpwan/sx126x/Kconfig | 28 + drivers/wireless/lpwan/sx126x/Make.defs | 35 + drivers/wireless/lpwan/sx126x/sx126x.c | 1407 ++++++++++++++++++ drivers/wireless/lpwan/sx126x/sx126x.h | 438 ++++++ include/nuttx/wireless/ioctl.h | 5 + include/nuttx/wireless/lpwan/sx126x.h | 414 ++++++ 9 files changed, 2361 insertions(+) create mode 100644 drivers/wireless/lpwan/sx126x/CMakeLists.txt create mode 100644 drivers/wireless/lpwan/sx126x/Kconfig create mode 100644 drivers/wireless/lpwan/sx126x/Make.defs create mode 100644 drivers/wireless/lpwan/sx126x/sx126x.c create mode 100644 drivers/wireless/lpwan/sx126x/sx126x.h create mode 100644 include/nuttx/wireless/lpwan/sx126x.h diff --git a/drivers/wireless/lpwan/Kconfig b/drivers/wireless/lpwan/Kconfig index eb8dae6258d9a..514d6532e5566 100644 --- a/drivers/wireless/lpwan/Kconfig +++ b/drivers/wireless/lpwan/Kconfig @@ -12,6 +12,15 @@ config LPWAN_SX127X ---help--- This options adds driver support for the Samtech SX127X chip. +config LPWAN_SX126X + bool "SX126X Low Power Long Range transceiver support" + default n + select SPI + ---help--- + This options adds driver support for the Samtech SX126X chip. + +source "drivers/wireless/lpwan/sx126x/Kconfig" + if LPWAN_SX127X config LPWAN_SX127X_RFFREQ_DEFAULT diff --git a/drivers/wireless/lpwan/Make.defs b/drivers/wireless/lpwan/Make.defs index 023bff806f2c5..4a12806ac7284 100644 --- a/drivers/wireless/lpwan/Make.defs +++ b/drivers/wireless/lpwan/Make.defs @@ -25,5 +25,6 @@ ifeq ($(CONFIG_DRIVERS_LPWAN),y) include wireless/lpwan/sx127x/Make.defs +include wireless/lpwan/sx126x/Make.defs endif # CONFIG_DRIVERS_LPWAN diff --git a/drivers/wireless/lpwan/sx126x/CMakeLists.txt b/drivers/wireless/lpwan/sx126x/CMakeLists.txt new file mode 100644 index 0000000000000..a69a176feb13d --- /dev/null +++ b/drivers/wireless/lpwan/sx126x/CMakeLists.txt @@ -0,0 +1,24 @@ +# ############################################################################## +# drivers/wireless/lpwan/sx126x/CMakeLists.txt +# +# 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. +# +# ############################################################################## +if(CONFIG_LPWAN_SX126X) + target_sources(drivers PRIVATE sx126x.c) +endif() diff --git a/drivers/wireless/lpwan/sx126x/Kconfig b/drivers/wireless/lpwan/sx126x/Kconfig new file mode 100644 index 0000000000000..6a04e1952c034 --- /dev/null +++ b/drivers/wireless/lpwan/sx126x/Kconfig @@ -0,0 +1,28 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if LPWAN_SX126X + +config LPWAN_SX126X_RFFREQ_DEFAULT + int "SX126X default RF frequency Hz" + default 869252000 + +config LPWAN_SX126X_SF_DEFAULT + int "SX126X default spreading factor" + default 10 + +config LPWAN_SX126X_BW_DEFAULT + int "SX126X default bandwidth kHz" + default 125 + +config LPWAN_SX126X_CR_DEFAULT + int "SX126X default coding rate" + default 8 + +config LPWAN_SX126X_MAX_DEVICES + int "SX126X maximum devices" + default 1 + +endif # DRIVERS_LPWAN diff --git a/drivers/wireless/lpwan/sx126x/Make.defs b/drivers/wireless/lpwan/sx126x/Make.defs new file mode 100644 index 0000000000000..bdf2143d45653 --- /dev/null +++ b/drivers/wireless/lpwan/sx126x/Make.defs @@ -0,0 +1,35 @@ +############################################################################ +# drivers/wireless/lpwan/sx126x/Make.defs +# +# 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. +# +############################################################################ + +# Include SX126X drivers into the build + +ifeq ($(CONFIG_LPWAN_SX126X),y) + +CSRCS += sx126x.c + +# Include SX126X build support + +DEPPATH += --dep-path wireless$(DELIM)lpwan$(DELIM)sx126x +VPATH += :wireless$(DELIM)lpwan$(DELIM)sx126x +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)lpwan$(DELIM)sx126x + +endif # CONFIG_LPWAN_SX126X diff --git a/drivers/wireless/lpwan/sx126x/sx126x.c b/drivers/wireless/lpwan/sx126x/sx126x.c new file mode 100644 index 0000000000000..a6b8f11aea027 --- /dev/null +++ b/drivers/wireless/lpwan/sx126x/sx126x.c @@ -0,0 +1,1407 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx126x/sx126x.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 "sx126x.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Private prototypes for file operations + ****************************************************************************/ + +static int sx126x_open(FAR struct file *filep); + +static int sx126x_close(FAR struct file *filep); + +static ssize_t sx126x_read(FAR struct file *filep, + FAR char *buffer, + size_t buflen); + +static ssize_t sx126x_write(FAR struct file *filep, + FAR const char *buf, + size_t buflen); + +static int sx126x_ioctl(FAR struct file *filep, + int cmd, + unsigned long arg); + +/**************************************************************************** + * Private data types + ****************************************************************************/ + +struct sx126x_dev_s +{ + struct spi_dev_s *spi; + const struct sx126x_lower_s *lower; + uint8_t times_opened; + mutex_t lock; /* Only let one user in at a time */ + sem_t rx_sem; + sem_t tx_sem; + uint16_t irqbits; + + /* Hardware settings */ + + bool invert_iq; + + /* Common settings */ + + uint8_t payload_len; + enum sx126x_packet_type_e packet_type; /* This will decide what modulation to use */ + uint32_t frequency_hz; + uint8_t power; + uint16_t preambles; + + /* LoRa settings */ + + enum sx126x_lora_sf_e lora_sf; + enum sx126x_lora_bw_e lora_bw; + enum sx126x_lora_cr_e lora_cr; + bool lora_crc; + bool lora_fixed_header; + bool low_datarate_optimization; + uint8_t syncword[SX126X_REG_SYNCWORD_LEN]; + + /* Interrupt handling */ + + uint16_t irq_mask; + struct work_s irq0_work; +}; + +enum sx126x_cmd_status +{ + SX126X_STATUS_RESERVED, SX126X_STATUS_RFU, SX126X_STATUS_DATA_AVAILABLE, + SX126X_STATUS_TIMEOUT, SX126X_STATUS_ERROR, SX126X_STATUS_EXECUTE_FAIL, + SX126X_STATUS_TX_DONE +}; + +enum sx126x_chip_mode +{ + SX126X_MODE_UNUSED, SX126X_MODE_RFU, SX126X_MODE_STBY_RC, + SX126X_MODE_STBY_XOSC, SX126X_MODE_FS, SX126X_MODE_RX, SX126X_MODE_TX +}; + +struct sx126x_status_s +{ + enum sx126x_cmd_status cmd; + enum sx126x_chip_mode mode; +}; + +static const struct file_operations sx126x_ops = +{ + sx126x_open, + sx126x_close, + sx126x_read, + sx126x_write, + NULL, + sx126x_ioctl, + NULL, + NULL +}; + +/**************************************************************************** + * Globals + ****************************************************************************/ + +FAR struct sx126x_dev_s g_sx126x_devices[SX126X_MAX_DEVICES]; + +/**************************************************************************** + * Private prototypes + ****************************************************************************/ + +/* SPI and control **********************************************************/ + +static void sx126x_command(FAR struct sx126x_dev_s *dev, + uint8_t cmd, + FAR const uint8_t *params, + size_t paramslen, + FAR uint8_t *returns); + +static void sx126x_reset(FAR struct sx126x_dev_s *dev); + +static void sx126x_get_status(FAR struct sx126x_dev_s *dev, + FAR struct sx126x_status_s *status); + +static void sx126x_spi_lock(FAR struct sx126x_dev_s *dev); + +static void sx126x_spi_unlock(FAR struct sx126x_dev_s *dev); + +static void sx126x_write_register(FAR struct sx126x_dev_s *dev, + uint16_t address, + uint8_t *data, + size_t data_length); + +/* Operational modes functions **********************************************/ + +static void sx126x_set_standby(FAR struct sx126x_dev_s *dev, + enum sx126x_standby_mode_e mode); + +static void sx126x_set_tx(FAR struct sx126x_dev_s *dev, + uint32_t timeout); + +static void sx126x_set_rx(FAR struct sx126x_dev_s *dev, uint32_t timeout); + +static void sx126x_set_cad(struct sx126x_dev_s *dev); + +static void sx126x_set_tx_continuous_wave(FAR struct sx126x_dev_s *dev); + +static void sx126x_set_regulator_mode(FAR struct sx126x_dev_s *dev, + enum sx126x_regulator_mode_e mode); + +static void sx126x_set_pa_config(FAR struct sx126x_dev_s *dev, + enum sx126x_device_e model, + uint8_t hpmax, + uint8_t padutycycle); + +static void sx126x_set_tx_infinite_preamble(FAR struct sx126x_dev_s *dev); + +/* DIO and IRQ control functions ********************************************/ + +static void sx126x_set_dio_irq_params(FAR struct sx126x_dev_s *dev, + uint16_t irq_mask, + uint16_t dio1_mask, + uint16_t dio2_mask, + uint16_t dio3_mask); + +static void sx126x_set_dio2_as_rf_switch(FAR struct sx126x_dev_s *dev, + bool enable); + +static void sx126x_set_dio3_as_tcxo(FAR struct sx126x_dev_s *dev, + enum sx126x_tcxo_voltage_e voltage, + uint32_t delay); + +static void sx126x_get_irq_status(FAR struct sx126x_dev_s *dev, + FAR uint16_t *irqstatus); + +static void sx126x_clear_irq_status(FAR struct sx126x_dev_s *dev, + uint16_t clearbits); + +/* RF Modulation and Packet-Related Functions *******************************/ + +static void sx126x_set_packet_params_lora(FAR struct sx126x_dev_s *dev, + FAR struct + sx126x_packetparams_lora_s * + pktparams); + +static void sx126x_set_modulation_params_lora(FAR struct sx126x_dev_s *dev, + FAR struct + sx126x_modparams_lora_s * + modparams); + +static void sx126x_set_buffer_base_address(FAR struct sx126x_dev_s *dev, + uint8_t tx, + uint8_t rx); + +static void sx126x_set_tx_params(FAR struct sx126x_dev_s *dev, uint8_t power, + enum sx126x_ramp_time_e ramp_time); + +static void sx126x_set_packet_type(FAR struct sx126x_dev_s *dev, + enum sx126x_packet_type_e type); + +static void sx126x_set_rf_frequency(FAR struct sx126x_dev_s *dev, + uint32_t frequency_hz); + +/* Communication status information *****************************************/ + +static void sx126x_get_rssi_inst(FAR struct sx126x_dev_s *dev, + FAR int32_t *dbm); + +static void sx126x_get_rx_buffer_status(FAR struct sx126x_dev_s *dev, + uint8_t *status, + uint8_t *payload_len, + uint8_t *rx_buff_offset); + +/* Registers and buffer *****************************************************/ + +static void sx126x_write_register(FAR struct sx126x_dev_s *dev, + uint16_t address, + uint8_t *data, + size_t data_length); + +static void sx126x_write_buffer(FAR struct sx126x_dev_s *dev, + uint8_t offset, + FAR const uint8_t *payload, + uint8_t len); + +static void sx126x_read_buffer(FAR struct sx126x_dev_s *dev, + uint8_t offset, + FAR uint8_t *payload, + uint8_t len); + +/* Register settings ********************************************************/ + +static void sx126x_set_syncword(FAR struct sx126x_dev_s *dev, + uint8_t *syncword, + uint8_t syncword_length); + +/* Driver specific **********************************************************/ + +static int sx126x_init(FAR struct sx126x_dev_s *dev); + +static int sx126x_deinit(FAR struct sx126x_dev_s *dev); + +static int sx126x_setup_radio(FAR struct sx126x_dev_s *dev); + +static void sx126x_set_defaults(FAR struct sx126x_dev_s *dev); + +/* Interrupt handlers *******************************************************/ + +static int sx126x_irq0handler(int irq, FAR void *context, FAR void *arg); + +static inline int sx126x_attachirq0(FAR struct sx126x_dev_s *dev, xcpt_t isr, + FAR void *arg); + +static void sx126x_isr0_process(FAR void *arg); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* File operations **********************************************************/ + +static int sx126x_open(FAR struct file *filep) +{ + int ret = 0; + + /* Get device */ + + struct sx126x_dev_s *dev; + dev = filep->f_inode->i_private; + wlinfo("Opening SX126x %d", dev->lower->dev_number); + + /* Lock dev */ + + ret = nxmutex_lock(&dev->lock); + if (ret < 0) + { + return ret; + } + + /* Only one can open this dev at a time */ + + if (dev->times_opened > 0) + { + ret = -EBUSY; + goto exit_err; + } + + /* Initialize */ + + ret = sx126x_init(dev); + if (ret != 0) + { + goto exit_err; + } + + /* Success */ + + dev->times_opened++; + ret = OK; + +exit_err: + nxmutex_unlock(&dev->lock); + return ret; +} + +static int sx126x_close(FAR struct file *filep) +{ + int ret = 0; + + /* Get device */ + + struct sx126x_dev_s *dev; + dev = filep->f_inode->i_private; + wlinfo("Closing SX126x %d", dev->lower->dev_number); + + /* Lock */ + + ret = nxmutex_lock(&dev->lock); + if (ret < 0) + { + goto exit_err; + } + + /* De-init */ + + ret = sx126x_deinit(dev); + if (ret != 0) + { + goto exit_err; + } + + /* Success */ + + if (dev->times_opened > 0) + { + dev->times_opened--; /* Do not let this wrap around. */ + ret = OK; + } + +exit_err: + nxmutex_unlock(&dev->lock); + return ret; +} + +static ssize_t sx126x_read(FAR struct file *filep, + FAR char *buf, + size_t buflen) +{ + int ret = 0; + if (buf == NULL || buflen < 1) + { + return -EINVAL; + } + + /* Get device */ + + struct sx126x_dev_s *dev; + dev = filep->f_inode->i_private; + + nxmutex_lock(&dev->lock); + + printf("Reading\n"); + + /* Get header */ + + struct sx126x_read_header_s *header = (struct sx126x_read_header_s *)buf; + + /* Pre-RX setup */ + + sx126x_spi_lock(dev); + dev->irq_mask = SX126X_IRQ_RXDONE_MASK | SX126X_IRQ_CRCERR_MASK; + ret = sx126x_setup_radio(dev); + if (ret != 0) + { + goto sx126x_rx_abort; + } + + /* RX mode */ + + sx126x_set_rx(dev, SX126X_NO_TIMEOUT); + sx126x_spi_unlock(dev); + + /* Wait for a packet */ + + nxsem_wait(&dev->rx_sem); + + /* Get payload */ + + uint8_t status = 0; + uint8_t offset = 0; + + sx126x_spi_lock(dev); + sx126x_get_rx_buffer_status(dev, &status, + &header->payload_length, + &offset); + sx126x_read_buffer(dev, offset, header->payload, + header->payload_length); + sx126x_spi_unlock(dev); + + /* Get CRC check */ + + header->crc_error = dev->irqbits & SX126X_IRQ_CRCERR_MASK; + + /* Exit */ + + sx126x_rx_abort: + + nxmutex_unlock(&dev->lock); + + return 1; +} + +static ssize_t sx126x_write(FAR struct file *filep, + FAR const char *buf, + size_t buflen) +{ + int ret = 0; + + /* Get device */ + + struct sx126x_dev_s *dev; + dev = filep->f_inode->i_private; + + if (buf == NULL || buflen < 1) + { + return -EINVAL; + } + + nxmutex_lock(&dev->lock); + sx126x_spi_lock(dev); + + /* Data */ + + dev->payload_len = buflen; + sx126x_write_buffer(dev, 0, (uint8_t *)buf, buflen); + + /* Pre-TX setup */ + + dev->irq_mask = SX126X_IRQ_TXDONE_MASK; + ret = sx126x_setup_radio(dev); + if (ret != 0) + { + sx126x_spi_unlock(dev); + goto sx126x_tx_abort; + } + + /* TX */ + + sx126x_set_tx(dev, 0); + + sx126x_spi_unlock(dev); + + /* Wait for transmitting operations to be finished */ + + wlinfo("TXing"); + ret = nxsem_wait(&dev->tx_sem); + + sx126x_tx_abort: + + nxmutex_unlock(&dev->lock); + return ret; +} + +static int sx126x_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + int ret = 0; + + /* Get device */ + + struct sx126x_dev_s *dev; + dev = filep->f_inode->i_private; + wlinfo("IOCTL cmd %d arg %u SX126x dev_number %d", + cmd, + *(FAR uint32_t *)((uintptr_t)arg), + dev->lower->dev_number); + + /* Lock */ + + ret = nxmutex_lock(&dev->lock); + if (ret < 0) + { + goto exit_err; + } + + /* Do thing */ + + switch (cmd) + { + /* Set radio freq. Takes uint32_t *frequency in Hz */ + + case WLIOC_SETRADIOFREQ: + { + FAR uint32_t *freq_ptr = (FAR uint32_t *)((uintptr_t)arg); + DEBUGASSERT(freq_ptr != NULL); + + dev->frequency_hz = *freq_ptr; + break; + } + + /* Get radio freq. Sets uint32_t *frequency in Hz */ + + case WLIOC_GETRADIOFREQ: + { + FAR uint32_t *freq_ptr = (FAR uint32_t *)((uintptr_t)arg); + DEBUGASSERT(freq_ptr != NULL); + + *freq_ptr = dev->frequency_hz; + break; + } + + /* Set TX power. arg: Pointer to int8_t power value */ + + case WLIOC_SETTXPOWER: + { + FAR int8_t *ptr = (FAR int8_t *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + + dev->power = *ptr; + break; + } + + /* Get current TX power. arg: Pointer to int8_t power value */ + + case WLIOC_GETTXPOWER: + { + FAR int8_t *ptr = (FAR int8_t *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + + *ptr = dev->power; + break; + } + + /* TODO: Integration with new common IOCTL API */ + + /* Driver specific IOCTL */ + + /* Lora config */ + + case SX126XIOC_LORACONFIGSET: + { + FAR struct sx126x_lora_config_s *ptr = + (FAR struct sx126x_lora_config_s *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + + /* Modulation params */ + + dev->lora_sf = ptr->modulation.spreading_factor; + dev->lora_bw = ptr->modulation.bandwidth; + dev->lora_cr = ptr->modulation.coding_rate; + dev->low_datarate_optimization = + ptr->modulation.low_datarate_optimization; + + /* Packet params */ + + dev->lora_crc = ptr->packet.crc_enable; + dev->lora_fixed_header = + ptr->packet.fixed_length_header; + dev->payload_len = ptr->packet.payload_length; + dev->invert_iq = ptr->packet.invert_iq; + dev->preambles = ptr->packet.preambles; + + break; + } + } + + /* Success */ + + ret = OK; + +exit_err: + nxmutex_unlock(&dev->lock); + return ret; +} + +uint32_t sx126x_convert_freq_in_hz_to_pll_step(uint32_t freq_in_hz) +{ + uint32_t steps_int; + uint32_t steps_frac; + + steps_int = freq_in_hz / SX126X_PLL_STEP_SCALED; + steps_frac = freq_in_hz - (steps_int * SX126X_PLL_STEP_SCALED); + + return (steps_int << + SX126X_PLL_STEP_SHIFT_AMOUNT) + (((steps_frac << + SX126X_PLL_STEP_SHIFT_AMOUNT) + (SX126X_PLL_STEP_SCALED >> + 1)) / SX126X_PLL_STEP_SCALED); +} + +/* Operational modes functions **********************************************/ + +static void sx126x_set_standby(FAR struct sx126x_dev_s *dev, + enum sx126x_standby_mode_e mode) +{ + sx126x_command(dev, SX126X_SETSTANDBY, (uint8_t *)&mode, + SX126X_SETSTANDBY_PARAMS, NULL); +} + +static void sx126x_set_tx(FAR struct sx126x_dev_s *dev, uint32_t timeout) +{ + /* Convert timeout to BE24 */ + + timeout = htobe32(timeout << 8); + + sx126x_command(dev, SX126X_SETTX, (uint8_t *)&timeout, SX126X_SETTX_PARAMS, + NULL); +} + +static void sx126x_set_rx(FAR struct sx126x_dev_s *dev, uint32_t timeout) +{ + /* Convert timeout to BE24 */ + + timeout = htobe32(timeout << 8); + + sx126x_command(dev, SX126X_SETRX, (uint8_t *)&timeout, SX126X_SETRX_PARAMS, + NULL); +} + +static void sx126x_stop_timer_on_preamble(FAR struct sx126x_dev_s *dev, + bool enable) +{ + sx126x_command(dev, SX126X_STOPTIMERONPREAMBLE, (uint8_t *)&enable, + SX126X_STOPTIMERONPREAMBLE_PARAMS, NULL); +} + +static void sx126x_set_rx_duty_cycle(FAR struct sx126x_dev_s *dev, + uint32_t rx_period, + uint32_t sleep_period) +{ + uint8_t params[SX126X_SETRXDUTYCYCLE_PARAMS]; + + rx_period = htobe32(rx_period << 8); + sleep_period = htobe32(sleep_period << 8); + + memcpy(params + SX126X_SETRXDUTYCYCLE_RXPERIOD_PARAM, + (uint8_t *)&rx_period, + SX126X_SETRXDUTYCYCLE_RXPERIOD_PARAMS); + memcpy(params + SX126X_SETRXDUTYCYCLE_SLEEPPERIOD_PARAM, + (uint8_t *)&sleep_period, + SX126X_SETRXDUTYCYCLE_SLEEPPERIOD_PARAMS); + + sx126x_command(dev, SX126X_SETRXDUTYCYCLE, params, + SX126X_SETRXDUTYCYCLE_PARAMS, NULL); +} + +static void sx126x_set_cad(FAR struct sx126x_dev_s *dev) +{ + sx126x_command(dev, SX126X_SETCAD, NULL, 0, NULL); +} + +static void sx126x_set_tx_continuous_wave(FAR struct sx126x_dev_s *dev) +{ + sx126x_command(dev, SX126X_SETTXCONTINUOUSWAVE, NULL, 0, NULL); +} + +static void sx126x_set_regulator_mode(FAR struct sx126x_dev_s *dev, + enum sx126x_regulator_mode_e mode) +{ + sx126x_command(dev, SX126X_SETREGULATORMODE, (uint8_t *)&mode, + SX126X_SETREGULATORMODE_PARAMS, NULL); +} + +/* Caution! Exceeding the limits listed in DS_SX1261/2 V2.1 + * 13.1.14.1 may cause irreversible damage to the device + */ + +static void sx126x_set_pa_config(FAR struct sx126x_dev_s *dev, + enum sx126x_device_e model, uint8_t hpmax, + uint8_t padutycycle) +{ + uint8_t params[SX126X_SETPACONFIG_PARMS]; + + memset(params, 0, SX126X_SETPACONFIG_PARMS); + + params[SX126X_SETPACONFIG_PADUTYCYCLE_PARAM] = padutycycle; + params[SX126X_SETPACONFIG_HPMAX_PARAM] = hpmax; + params[SX126X_SETPACONFIG_DEVICESEL_PARAM] = model; + params[SX126X_SETPACONFIG_PALUT_PARAM] = 0x01; + + sx126x_command(dev, SX126X_SETPACONFIG, params, SX126X_SETPACONFIG_PARMS, + NULL); +} + +static void sx126x_set_tx_infinite_preamble(FAR struct sx126x_dev_s *dev) +{ + sx126x_command(dev, SX126X_SETTXINFINITEPREAMBLE, NULL, 0, NULL); +} + +static void sx126x_set_rx_tx_fallback_mode(FAR struct sx126x_dev_s *dev, + enum sx126x_fallback_mode_e + fallback) +{ + sx126x_command(dev, SX126X_SETRXTXFALLBACKMODE, (uint8_t *)&fallback, + SX126X_SETRXTXFALLBACKMODE_PARAMS, NULL); +} + +/* DIO and IRQ control functions */ + +static void sx126x_set_dio_irq_params(FAR struct sx126x_dev_s *dev, + uint16_t irq_mask, uint16_t dio1_mask, + uint16_t dio2_mask, uint16_t dio3_mask) +{ + irq_mask = htobe16(irq_mask); + dio1_mask = htobe16(dio1_mask); + dio2_mask = htobe16(dio2_mask); + dio3_mask = htobe16(dio3_mask); + + uint8_t params[SX126X_SETDIOIRQPARAMS_PARAMS]; + + memcpy(params + SX126X_SETDIOIRQPARAMS_IRQMASK_PARAM, &irq_mask, + SX126X_SETDIOIRQPARAMS_IRQMASK_PARAMS); + + memcpy(params + SX126X_SETDIOIRQPARAMS_DIO1MASK_PARAM, &dio1_mask, + SX126X_SETDIOIRQPARAMS_DIO1MASK_PARAMS); + + memcpy(params + SX126X_SETDIOIRQPARAMS_DIO2MASK_PARAM, &dio2_mask, + SX126X_SETDIOIRQPARAMS_DIO2MASK_PARAMS); + + memcpy(params + SX126X_SETDIOIRQPARAMS_DIO3MASK_PARAM, &dio3_mask, + SX126X_SETDIOIRQPARAMS_DIO3MASK_PARAMS); + + sx126x_command(dev, SX126X_SETDIOIRQPARAMS, params, + SX126X_SETDIOIRQPARAMS_PARAMS, NULL); +} + +static void sx126x_set_dio2_as_rf_switch(FAR struct sx126x_dev_s *dev, + bool enable) +{ + sx126x_command(dev, SX126X_SETDIO2RFSWCTRL, (uint8_t *)&enable, + SX126X_SETDIO2RFSWCTRL_PARAMS, NULL); +} + +static void sx126x_set_dio3_as_tcxo(FAR struct sx126x_dev_s *dev, + enum sx126x_tcxo_voltage_e voltage, + uint32_t delay) +{ + uint8_t params[SX126X_SETDIO3TCXOCTRL_PARAMS]; + + params[SX126X_SETDIO3TCXOCTRL_TCXO_V_PARAM] = voltage; + + /* Convert delay to 24 bit and convert to BE */ + + delay = htobe32(delay << 8); + memcpy(params + SX126X_SETDIO3TCXOCTRL_DELAY_PARAM, &delay, + SX126X_SETDIO3TCXOCTRL_DELAY_PARAMS); + + sx126x_command(dev, SX126X_SETDIO3TCXOCTRL, params, + SX126X_SETDIO3TCXOCTRL_PARAMS, NULL); +} + +static void sx126x_get_irq_status(FAR struct sx126x_dev_s *dev, + FAR uint16_t *irqstatus) +{ + uint8_t returns[SX126X_GETIRQSTATUS_RETURNS]; + + sx126x_command(dev, SX126X_GETIRQSTATUS, + NULL, SX126X_GETIRQSTATUS_RETURNS, + returns); + + uint16_t bits; + memcpy(&bits, returns + + SX126X_GETIRQSTATUS_IRQSTATUS_RETURN, + SX126X_GETIRQSTATUS_IRQSTATUS_RETURNS); + + *irqstatus = be16toh(bits); +} + +static void sx126x_clear_irq_status(FAR struct sx126x_dev_s *dev, + uint16_t clearbits) +{ + uint8_t params[SX126X_CLEARIRQSTATUS_PARAMS]; + + clearbits = htobe16(clearbits); + memcpy(params + SX126X_CLEARIRQSTATUS_CLEAR_PARAM, + &clearbits, + SX126X_CLEARIRQSTATUS_CLEAR_PARAMS); + + sx126x_command(dev, SX126X_CLEARIRQSTATUS, params, + SX126X_CLEARIRQSTATUS_PARAMS, + NULL); +} + +/* RF Modulation and Packet-Related Functions *******************************/ + +static void sx126x_set_packet_params_lora(FAR struct sx126x_dev_s *dev, + FAR struct + sx126x_packetparams_lora_s * + pktparams) +{ + uint8_t params[SX126X_SETPACKETPARMS_PARAMS]; + + memset(params, 0, SX126X_SETPACKETPARMS_PARAMS); + + uint16_t preambles = htobe16(pktparams->preambles); + memcpy(params + SX126X_PKTPARAM1_LORA_PREAMBLELEN_PARAM, &preambles, + SX126X_PKTPARAM1_LORA_PREAMBLELEN_PARAMS); + + params[SX126X_PKTPARAM3_LORA_HEADERTYPE_PARAM] = + pktparams->fixed_length_header; + params[SX126X_PKTPARAM4_LORA_PAYLOADLEN_PARAM] = + pktparams->payload_length; + params[SX126X_PKTPARAM5_LORA_CRCTYPE_PARAM] = pktparams->crc_enable; + params[SX126X_PKTPARAM6_LORA_INVERTIQ_PARAM] = pktparams->invert_iq; + + sx126x_command(dev, SX126X_SETPACKETPARMS, params, + SX126X_SETPACKETPARMS_PARAMS, NULL); +} + +static void sx126x_set_modulation_params_lora(FAR struct sx126x_dev_s *dev, + FAR struct + sx126x_modparams_lora_s * + modparams) +{ + uint8_t params[SX126X_SETMODULATIONPARAMS_PARAMS]; + + memset(params, 0, SX126X_SETMODULATIONPARAMS_PARAMS); + + params[SX126X_MODPARAM1_LORA_SF_PARAM] = + modparams->spreading_factor; + params[SX126X_MODPARAM2_LORA_BW_PARAM] = + modparams->bandwidth; + params[SX126X_MODPARAM3_LORA_CR_PARAM] = + modparams->coding_rate; + params[SX126X_MODPARAM4_LORA_LOWDATRATE_OPTI_PARAM] = + modparams->low_datarate_optimization; + + sx126x_command(dev, SX126X_SETMODULATIONPARAMS, params, + SX126X_SETMODULATIONPARAMS_PARAMS, NULL); +} + +static void sx126x_set_buffer_base_address(FAR struct sx126x_dev_s *dev, + uint8_t tx, uint8_t rx) +{ + uint8_t params[SX126X_SETBUFFERBASEADDRESS_PARAMS]; + + memset(params, 0, SX126X_SETBUFFERBASEADDRESS_PARAMS); + + params[SX126X_SETBUFFERBASEADDRESS_TX_PARAM] = tx; + params[SX126X_SETBUFFERBASEADDRESS_RX_PARAM] = rx; + + sx126x_command(dev, SX126X_SETBUFFERBASEADDRESS, params, + SX126X_SETBUFFERBASEADDRESS_PARAMS, NULL); +} + +static void sx126x_set_tx_params(FAR struct sx126x_dev_s *dev, uint8_t power, + enum sx126x_ramp_time_e ramp_time) +{ + uint8_t params[SX126X_SETTXPARMS_PARAMS]; + + memset(params, 0, SX126X_SETTXPARMS_PARAMS); + + params[SX126X_SETTXPARMS_RAMPTIME_PARAM] = ramp_time; + params[SX126X_SETTXPARMS_POWER_PARAM] = power; + + sx126x_command(dev, SX126X_SETTXPARMS, params, SX126X_SETTXPARMS_PARAMS, + NULL); +} + +static void sx126x_set_packet_type(FAR struct sx126x_dev_s *dev, + enum sx126x_packet_type_e type) +{ + sx126x_command(dev, SX126X_SETPACKETTYPE, (uint8_t *)&type, + SX126X_SETPACKETTYPE_PARAMS, NULL); +} + +static void sx126x_set_rf_frequency(FAR struct sx126x_dev_s *dev, + uint32_t frequency_hz) +{ + uint32_t corrected_freq = + sx126x_convert_freq_in_hz_to_pll_step(frequency_hz); + + corrected_freq = htobe32(corrected_freq); + + sx126x_command(dev, SX126X_SETRFFREQUENCY, (uint8_t *)&corrected_freq, + SX126X_SETRFFREQUENCY_PARAMS, NULL); +} + +static void sx126x_set_lora_symb_num_timout(FAR struct sx126x_dev_s *dev, + uint8_t symbnum) +{ + sx126x_command(dev, SX126X_SETLORASYMBNUMTIMEOUT, &symbnum, + SX126X_SETLORASYMBNUMTIMEOUT_PARAMS, NULL); +} + +/* Communication status information *****************************************/ + +static void sx126x_get_status(FAR struct sx126x_dev_s *dev, + FAR struct sx126x_status_s *status) +{ + /* NOP param to shift out result */ + + uint8_t parms[1] = { + 0x00 + }; + + uint8_t rets[1]; + + /* Get, mask and shift result into readable mode numbers */ + + sx126x_command(dev, SX126X_CMD_GETSTATUS, parms, sizeof(parms), rets); + status->mode = (rets[0] & SX126X_STATUS_CHIPMODE_MASK) >> + SX126X_STATUS_CHIPMODE_SHIFT; + status->cmd = (rets[0] & SX126X_STATUS_CMD_MASK) >> + SX126X_STATUS_CMD_SHIFT; +} + +static void sx126x_get_rssi_inst(FAR struct sx126x_dev_s *dev, + FAR int32_t *dbm) +{ + uint8_t rets[SX126X_GETRSSIINST_RETURNS]; + + sx126x_command(dev, SX126X_GETRSSIINST, NULL, SX126X_GETRSSIINST_RETURNS, + rets); + + /* Calculate dBm from returns */ + + int32_t rssi = rets[SX126X_GETRSSIINST_RSSI_RETURN]; + (*dbm) = -rssi / 2.0; +} + +static void sx126x_get_rx_buffer_status(FAR struct sx126x_dev_s *dev, + uint8_t *status, + uint8_t *payload_len, + uint8_t *rx_buff_offset) +{ + uint8_t returns[SX126X_GETRXBUFFERSTATUS_RETURNS]; + + sx126x_command(dev, SX126X_GETRXBUFFERSTATUS, + NULL, + SX126X_GETRXBUFFERSTATUS_RETURNS, + returns); + + *status = returns[SX126X_GETRXBUFFERSTATUS_STATUS_RETURN]; + *payload_len = returns[SX126X_GETRXBUFFERSTATUS_PAYLOAD_LEN_RETURN]; + *rx_buff_offset = returns[SX126X_GETRXBUFFERSTATUS_RX_START_PTR_RETURN]; +} + +/* Lower hardware control ***************************************************/ + +static void sx126x_reset(FAR struct sx126x_dev_s *dev) +{ + dev->lower->reset(); +} + +/* SPI Communication ********************************************************/ + +static void sx126x_select(FAR struct sx126x_dev_s *dev) +{ + SPI_SELECT(dev->spi, SPIDEV_LPWAN(dev->lower->dev_number), true); +} + +static void sx126x_deselect(FAR struct sx126x_dev_s *dev) +{ + SPI_SELECT(dev->spi, SPIDEV_LPWAN(dev->lower->dev_number), false); +} + +static void sx126x_spi_lock(FAR struct sx126x_dev_s *dev) +{ + struct spi_dev_s *spi = dev->spi; + + SPI_LOCK(spi, true); + SPI_SETBITS(spi, 8); + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETFREQUENCY(spi, SX126X_SPI_SPEED); +} + +static void sx126x_spi_unlock(FAR struct sx126x_dev_s *dev) +{ + SPI_LOCK(dev->spi, false); +} + +static void sx126x_command(FAR struct sx126x_dev_s *dev, uint8_t cmd, + const FAR uint8_t *params, size_t paramslen, + FAR uint8_t *returns) +{ + sx126x_select(dev); + + /* First send the command. This does not return anything. + * "RFU" according the manual + */ + + SPI_SEND(dev->spi, cmd); + + /* Send all the params and record the returning bytes */ + + for (size_t i = 0; i < paramslen; i++) + { + uint8_t param = SX126X_NOP; + if (params != NULL) + { + param = params[i]; + } + + uint8_t ret = SPI_SEND(dev->spi, param); + + if (returns != NULL) + { + returns[i] = ret; + } + } + + sx126x_deselect(dev); +} + +/* Registers and buffer *****************************************************/ + +static void sx126x_write_register(FAR struct sx126x_dev_s *dev, + uint16_t address, + uint8_t *data, + size_t data_length) +{ + sx126x_select(dev); + + /* Send the opcode and address */ + + SPI_SEND(dev->spi, SX126X_WRITEREGISTER); + SPI_SEND(dev->spi, (uint8_t)(address >> 8)); + SPI_SEND(dev->spi, (uint8_t)address); + + /* Send data */ + + for (size_t i = 0; i < data_length; i++) + { + SPI_SEND(dev->spi, data[i]); + } + + sx126x_deselect(dev); +} + +static void sx126x_read_register(FAR struct sx126x_dev_s *dev, + uint16_t address, + uint8_t *data, + size_t data_length) +{ + sx126x_select(dev); + + /* Send the opcode and address */ + + SPI_SEND(dev->spi, SX126X_WRITEREGISTER); + SPI_SEND(dev->spi, (uint8_t)(address >> 8)); + SPI_SEND(dev->spi, (uint8_t)address); + + /* Send data */ + + for (size_t i = 0; i < data_length; i++) + { + data[i] = SPI_SEND(dev->spi, SX126X_NOP); + } + + sx126x_deselect(dev); +} + +static void sx126x_write_buffer(FAR struct sx126x_dev_s *dev, + uint8_t offset, + FAR const uint8_t *payload, + uint8_t len) +{ + sx126x_select(dev); + + /* Command */ + + SPI_SEND(dev->spi, SX126X_WRITEBUFFER); + + /* Offset */ + + SPI_SEND(dev->spi, offset); + + /* Data */ + + for (size_t i = 0; i < len; i++) + { + SPI_SEND(dev->spi, payload[i]); + } + + sx126x_deselect(dev); +} + +static void sx126x_read_buffer(FAR struct sx126x_dev_s *dev, + uint8_t offset, + FAR uint8_t *payload, + uint8_t len) +{ + sx126x_select(dev); + + /* Command */ + + SPI_SEND(dev->spi, SX126X_READBUFFER); + + /* Offset */ + + SPI_SEND(dev->spi, offset); + + /* NOP */ + + SPI_SEND(dev->spi, SX126X_NOP); + + /* Data */ + + for (size_t i = 0; i < len; i++) + { + payload[i] = SPI_SEND(dev->spi, SX126X_NOP); + } + + sx126x_deselect(dev); +} + +/* Register settings ********************************************************/ + +static void sx126x_set_syncword(FAR struct sx126x_dev_s *dev, + uint8_t *syncword, + uint8_t syncword_length) +{ + if (syncword_length > SX126X_REG_SYNCWORD_LEN) + { + syncword_length = SX126X_REG_SYNCWORD_LEN; + wlerr("Syncword length was limited to the maximum 8 bytes"); + } + + sx126x_write_register(dev, SX126X_REG_SYNCWORD, syncword, syncword_length); +} + +/* Driver specific **********************************************************/ + +static int sx126x_init(FAR struct sx126x_dev_s *dev) +{ + sx126x_reset(dev); + sx126x_set_defaults(dev); + return 0; +} + +static int sx126x_deinit(FAR struct sx126x_dev_s *dev) +{ + return 0; +} + +static void sx126x_set_defaults(FAR struct sx126x_dev_s *dev) +{ + /* Hardware defaults */ + + dev->invert_iq = SX126X_DEFAULT_INVERT_IQ; + + /* Common defaults */ + + dev->packet_type = SX126X_DEFAULT_PACKET_TYPE; + dev->frequency_hz = SX126X_DEFAULT_FREQ; + dev->power = SX126X_DEFAULT_POWER; + dev->preambles = SX126X_DEFAULT_LORA_PREAMBLES; + + /* LoRa defaults */ + + dev->lora_sf = SX126X_DEFAULT_LORA_SF; + dev->lora_bw = SX126X_DEFAULT_LORA_BW; + dev->lora_cr = SX126X_DEFAULT_LORA_CR; + dev->lora_fixed_header = SX126X_DEFAULT_LORA_FIXED_HEADER; + dev->lora_crc = SX126X_DEFAULT_LORA_CRC_EN; + dev->low_datarate_optimization = SX126X_DEFAULT_LORA_LDO; + + uint8_t newsyncword[] = SX126X_DEFAULT_SYNCWORD; + memcpy(dev->syncword, newsyncword, sizeof(dev->syncword)); + + /* GFSK defaults */ +} + +static int sx126x_setup_radio(FAR struct sx126x_dev_s *dev) +{ + /* Clear IRQ status */ + + sx126x_clear_irq_status(dev, 0xffff); + + /* Set regulator */ + + sx126x_set_regulator_mode(dev, dev->lower->regulator_mode); + + /* Set packet type */ + + sx126x_set_packet_type(dev, dev->packet_type); + + /* Set RF frequency */ + + int illegal_freq = dev->lower->check_frequency(dev->frequency_hz); + + if (illegal_freq) + { + wlerr("Board does not support %dHz", dev->frequency_hz); + return -1; + } + + sx126x_set_rf_frequency(dev, dev->frequency_hz); + + /* Set PA settings from lower */ + + uint8_t hp; + uint8_t dc; + enum sx126x_device_e model; + dev->lower->get_pa_values(&model, &hp, &dc); + sx126x_set_pa_config(dev, model, hp, dc); + + /* Set TX params */ + + dev->lower->limit_tx_power(&dev->power); /* Limited by board */ + sx126x_set_tx_params(dev, dev->power, dev->lower->tx_ramp_time); + + /* Set base */ + + sx126x_set_buffer_base_address(dev, 0, 0); + + /* Set params depending on packet type */ + + switch (dev->packet_type) + { + case (SX126X_PACKETTYPE_LORA): + { + /* Mod params */ + + struct sx126x_modparams_lora_s modparams = { + .spreading_factor = dev->lora_sf, + .bandwidth = dev->lora_bw, + .coding_rate = dev->lora_cr, + .low_datarate_optimization = dev->low_datarate_optimization + }; + + sx126x_set_modulation_params_lora(dev, &modparams); + + /* Packet params */ + + struct sx126x_packetparams_lora_s pktparams = { + .crc_enable = dev->lora_crc, + .fixed_length_header = dev->lora_fixed_header, + .payload_length = dev->payload_len, + .invert_iq = dev->invert_iq, + .preambles = dev->preambles + }; + + sx126x_set_packet_params_lora(dev, &pktparams); + break; + } + + default: + break; + } + + /* Sync word */ + + sx126x_set_syncword(dev, dev->syncword, sizeof(dev->syncword)); + + /* IRQ MASK */ + + sx126x_set_dio_irq_params(dev, dev->irq_mask, + dev->lower->masks.dio1_mask, + dev->lower->masks.dio2_mask, + dev->lower->masks.dio3_mask); + + /* DIO 2 */ + + sx126x_set_dio2_as_rf_switch(dev, dev->lower->use_dio2_as_rf_sw); + + /* DIO 3 */ + + sx126x_set_dio3_as_tcxo(dev, dev->lower->dio3_voltage, + dev->lower->dio3_delay); + return 0; +} + +/* Interrupt handling *******************************************************/ + +static int sx126x_irq0handler(int irq, FAR void *context, FAR void *arg) +{ + FAR struct sx126x_dev_s *dev = (FAR struct sx126x_dev_s *)arg; + + DEBUGASSERT(dev != NULL); + + DEBUGASSERT(work_available(&dev->irq0_work)); + + return work_queue(HPWORK, &dev->irq0_work, sx126x_isr0_process, arg, 0); +} + +static inline int sx126x_attachirq0(FAR struct sx126x_dev_s *dev, xcpt_t isr, + FAR void *arg) +{ + DEBUGASSERT(dev->lower->irq0attach != NULL); + + return dev->lower->irq0attach(isr, arg); +} + +static void sx126x_isr0_process(FAR void *arg) +{ + DEBUGASSERT(arg); + + FAR struct sx126x_dev_s *dev = (FAR struct sx126x_dev_s *)arg; + + wlinfo("SX126x ISR0 process triggered"); + + /* Get and clear IRQ bits */ + + sx126x_spi_lock(dev); + sx126x_get_irq_status(dev, &dev->irqbits); + sx126x_spi_unlock(dev); + + wlinfo("IRQ status 0x%X", dev->irqbits); + + /* On TX done */ + + if (dev->irqbits & SX126X_IRQ_TXDONE_MASK) + { + wlinfo("TX done"); + + /* Release writing threads */ + + nxsem_post(&dev->tx_sem); + } + + /* On RX done */ + + if (dev->irqbits & SX126X_IRQ_RXDONE_MASK) + { + wlinfo("RX done"); + + nxsem_post(&dev->rx_sem); + } + + /* On CAD done */ + + if (dev->irqbits & SX126X_IRQ_CADDONE_MASK) + { + wlinfo("CAD done"); + } + + /* On CAD detect */ + + if (dev->irqbits & SX126X_IRQ_CADDETECTED_MASK) + { + wlinfo("CAD detect"); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void sx126x_register(FAR struct spi_dev_s *spi, + FAR const struct sx126x_lower_s *lower, + const char *path) +{ + /* Register the dev using an unique dev_number, + * so multiple radios can be registered at once + */ + + if (lower->dev_number >= SX126X_MAX_DEVICES) + { + wlerr("SX126x dev_number %d is greater than \ + allowed amount of SX126x devices", + lower->dev_number); + return; + } + + struct sx126x_dev_s *dev; + dev = &g_sx126x_devices[lower->dev_number]; + dev->lower = lower; + dev->spi = spi; + + /* Initialize locks and semaphores */ + + nxmutex_init(&dev->lock); + nxsem_init(&dev->rx_sem, 0, 0); + nxsem_init(&dev->tx_sem, 0, 0); + + sx126x_attachirq0(dev, sx126x_irq0handler, dev); + + (void)register_driver(path, &sx126x_ops, 0666, + dev); +} diff --git a/drivers/wireless/lpwan/sx126x/sx126x.h b/drivers/wireless/lpwan/sx126x/sx126x.h new file mode 100644 index 0000000000000..173c0a99bf412 --- /dev/null +++ b/drivers/wireless/lpwan/sx126x/sx126x.h @@ -0,0 +1,438 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx126x/sx126x.h + * + * 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. + * + ****************************************************************************/ + +/* All functions and definitions are accurately recreated + * from the official datasheet "DS_SX1261-2_V2_1" + */ + +#ifndef __DRIVERS_WIRELESS_LPWAN_SX126X_SX126X_H +#define __DRIVERS_WIRELESS_LPWAN_SX126X_SX126X_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Settings + ****************************************************************************/ + +/* Driver settings */ + +#define SX126X_MAX_DEVICES 2 +#define SX126X_SPI_SPEED 500000 + +/* LoRa defaults */ + +#define SX126X_DEFAULT_LORA_SF SX126X_LORA_SF10 +#define SX126X_DEFAULT_LORA_BW SX126X_LORA_BW_125 +#define SX126X_DEFAULT_LORA_CR SX126X_LORA_CR_4_8 +#define SX126X_DEFAULT_LORA_CRC_EN true +#define SX126X_DEFAULT_LORA_FIXED_HEADER false +#define SX126X_DEFAULT_LORA_PREAMBLES 12 +#define SX126X_DEFAULT_LORA_LDO false + +/* Common defaults */ + +#define SX126X_DEFAULT_FREQ 869525000 +#define SX126X_DEFAULT_POWER 0x0e +#define SX126X_DEFAULT_PACKET_TYPE SX126X_PACKETTYPE_LORA +#define SX126X_DEFAULT_SYNCWORD {0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + +/* Hardware defaults */ + +#define SX126X_DEFAULT_INVERT_IQ false + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register addresses *******************************************************/ + +#define SX126X_REG_SYNCWORD 0x06C0 /* Start of Byte 0 - Byte 7 */ +#define SX126X_REG_SYNCWORD_LEN 8 /* Bytes */ +#define SX126X_REG_NODEADDR 0x06CD /* Node address to filter. Default 0x00 */ +#define SX126X_REG_BRDCASTADDR 0x06CE /* Broadcast address to filter. Default 0x00 */ +#define SX126X_REG_CRC_INIT_MSB 0x06BC /* Default 0x1D */ +#define SX126X_REG_CRC_INIT_LSB 0x06BD /* Default 0x0F */ +#define SX126X_REG_CRC_POLY_MSB 0x06BE /* Default 0x10 */ +#define SX126X_REG_CRC_POLY_LSB 0x06BF /* Default 0x21 */ +#define SX126X_REG_WHITENING_MSB 0x06B8 /* Default 0x01 */ +#define SX126X_REG_WHITENING_LSB 0x06B9 /* Default 0x00 */ + +/* Enum and constant definitions ********************************************/ + +/* Packet parameters *****************************************************/ + +#define SX126X_PKTPARAM1_GFSK_PREAMBLELEN_PARAM 0 /* Takes 0x0001 to 0xFFFF preamble bits */ +#define SX126X_PKTPARAM1_GFSK_PREAMBLELEN_PARAMS 2 +#define SX126X_PKTPARAM3_GFSK_PREAMBLEDETECTORLEN_PARAM 2 /* Takes SX126X_GFSK_PREABMLE_DETECT_x */ +#define SX126X_PKTPARAM4_GFSK_SYNCWORDLEN_PARAM 3 /* 0x00 to 0x40, 0 to 8 bytes from SX126X_SYNCWORD register */ +#define SX126X_PKTPARAM5_GFSK_ADDRCOMP_PARAM 4 /* Takes SX126X_ADDR_FILT_x */ +#define SX126X_PKTPARAM6_GFSK_PKTTYPE_PARAM 5 /* Packet length unknown? false/true */ +#define SX126X_PKTPARAM7_GFSK_PAYLOADLEN_PARAM 6 /* 0x00 to 0xFF size of tx&rx payload in bytes */ +#define SX126X_PKTPARAM8_GFSK_CRCTYPE_PARAM 7 /* Takes SX126X_GFSK_CRCTYPE_x */ +#define SX126X_PKTPARAM9_GFSK_WHITENING_PARAM 8 /* Enable false/true */ + +#define SX126X_PKTPARAM1_LORA_PREAMBLELEN_PARAM 0 /* 0x0001 to 0xFFFF preamble symbols */ +#define SX126X_PKTPARAM1_LORA_PREAMBLELEN_PARAMS 2 +#define SX126X_PKTPARAM3_LORA_HEADERTYPE_PARAM 2 /* Variable/Fixed length false/true */ +#define SX126X_PKTPARAM4_LORA_PAYLOADLEN_PARAM 3 /* 0x00 to 0xFF number of tx and rx bytes */ +#define SX126X_PKTPARAM5_LORA_CRCTYPE_PARAM 4 /* CRC OFF/ON false/true */ +#define SX126X_PKTPARAM6_LORA_INVERTIQ_PARAM 5 /* Standard/Inverted false/true */ + +/* Modulation parameters ****************************************************/ + +/* GFSK */ + +#define SX126X_MODPARAM1_GFSK_BR_PARAM 0 /* Takes br = 32 * Fxtal / bit_rate */ +#define SX126X_MODPARAM1_GFSK_BR_PARAMS 3 +#define SX126X_MODPARAM4_GFSK_PULSESHAPE_PARAM 3 /* Takes SX126X_GFSK_PULSESHAPE_x */ +#define SX126X_MODPARAM5_GFSK_BANDWIDTH_PARAM 4 /* Takes SX126X_GFSK_BANDWIDTH_xHZ */ +#define SX126X_MODPARAM6_GFSK_FDEV_PARAM 5 /* Takes Fdev = (frequency_deviation * 2^25) / Fxtal */ +#define SX126X_MODPARAM6_GFSK_FDEV_PARAMS 3 + +/* LoRa */ + +#define SX126X_MODPARAM1_LORA_SF_PARAM 0 /* Takes SF between SX126X_LORA_SF_MIN and MAX */ +#define SX126X_MODPARAM2_LORA_BW_PARAM 1 /* Takes SX126X_LORA_BW_x */ +#define SX126X_MODPARAM3_LORA_CR_PARAM 2 /* Takes SX126X_LORA_CR_x */ +#define SX126X_MODPARAM4_LORA_LOWDATRATE_OPTI_PARAM 3 /* Takes true/false*/ + +/* Operational modes functions **********************************************/ + +/* SetSleep */ + +#define SX126X_SETSLEEP 0x84 /* Opcode */ +#define SX126X_SETSLEEP_PARAMS 1 +#define SX126X_SETSLEEP_CONF_PARAM 0 +#define SX126X_SETSLEEP_CONF_RTC_SHIFT 0 +# define SX126X_SETSLEEP_CONF_RTC_DISABLE (0< +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Defintions + ****************************************************************************/ + +#define SX126X_RX_PAYLOAD_SIZE 0xff + +/* IOCTL commands ***********************************************************/ + +/* arg: sx126x_packet_type_e */ + +#define SX126XIOC_PACKETTYPESET _WLCIOC(SX126X_FIRST+0)// + +/* Sets lora parameters. arg: sx126x_lora_config_s *config */ + +#define SX126XIOC_LORACONFIGSET _WLCIOC(SX126X_FIRST+1) + +/* IRQ Register bits ********************************************************/ + +#define SX126X_IRQ_TXDONE_MASK (1<<0) +#define SX126X_IRQ_RXDONE_MASK (1<<1) +#define SX126X_IRQ_PREAMBLEDETECTED_MASK (1<<2) +#define SX126X_IRQ_SYNCWORDVALID_MASK (1<<3) +#define SX126X_IRQ_HEADERVALID_MASK (1<<4) +#define SX126X_IRQ_HEADERERR_MASK (1<<5) +#define SX126X_IRQ_CRCERR_MASK (1<<6) +#define SX126X_IRQ_CADDONE_MASK (1<<7) +#define SX126X_IRQ_CADDETECTED_MASK (1<<8) +#define SX126X_IRQ_TIMEOUT_MASK (1<<9) +#define SX126X_IRQ_LRFHSSHOP_MASK (1<<14) + +/* Others */ + +#define SX126X_NOP 0 +#define SX126X_NO_TIMEOUT 0 +#define SX126X_NO_DELAY 0 + +/* Oscillators and PLLs */ + +#define SX126X_OSC_MAIN_HZ (32000000) +#define SX126X_FXTAL SX126X_OSC_MAIN_HZ +#define SX126X_PLL_STEP_SHIFT_AMOUNT (14) +#define SX126X_PLL_STEP_SCALED (SX126X_FXTAL>>(25-SX126X_PLL_STEP_SHIFT_AMOUNT)) + +/**************************************************************************** + * Public Data Types + ****************************************************************************/ + +/* Standby config */ + +enum sx126x_standby_mode_e +{ + SX126X_STDBY_RC = 0x00, + SX126X_STDBY_XOSC = 0x01 +}; + +/* Packet Types */ + +enum sx126x_packet_type_e +{ + SX126X_PACKETTYPE_GFSK = 0x00, + SX126X_PACKETTYPE_LORA = 0x01, + SX126X_PACKETTYPE_LR_FHSS = 0x13 +}; + +/* Ramp times */ + +enum sx126x_ramp_time_e +{ + SX126X_SET_RAMP_10U = 0x00, + SX126X_SET_RAMP_20U = 0x01, + SX126X_SET_RAMP_40U = 0x02, + SX126X_SET_RAMP_80U = 0x03, + SX126X_SET_RAMP_200U = 0x04, + SX126X_SET_RAMP_800U = 0x05, + SX126X_SET_RAMP_1700U = 0x06, + SX126X_SET_RAMP_3400U = 0x07 +}; + +/* GFSK Pulse shapes */ + +enum sx126x_gfsk_pulseshape_e +{ + SX126X_GFSK_PULSESHAPE_NONE = 0x00, + SX126X_GFSK_PULSESHAPE_GAUSSIAN_BT_0_3 = 0x08, + SX126X_GFSK_PULSESHAPE_GAUSSIAN_BT_0_5 = 0x09, + SX126X_GFSK_PULSESHAPE_GAUSSIAN_BT_0_7 = 0x0a, + SX126X_GFSK_PULSESHAPE_GAUSSIAN_BT_1 = 0x0b +}; + +/* GFSK Bandwidths in Hz */ + +enum sx126x_gfsk_bandwidth_e +{ + SX126X_GFSK_BANDWIDTH_4800HZ = 0x1f, + SX126X_GFSK_BANDWIDTH_5800HZ = 0x17, + SX126X_GFSK_BANDWIDTH_7300HZ = 0x0f, + SX126X_GFSK_BANDWIDTH_9700HZ = 0x1e, + SX126X_GFSK_BANDWIDTH_11700HZ = 0x16, + SX126X_GFSK_BANDWIDTH_14600HZ = 0x0e, + SX126X_GFSK_BANDWIDTH_19500HZ = 0x1d, + SX126X_GFSK_BANDWIDTH_23400HZ = 0x15, + SX126X_GFSK_BANDWIDTH_29300HZ = 0x0d, + SX126X_GFSK_BANDWIDTH_39000HZ = 0x1c, + SX126X_GFSK_BANDWIDTH_46900HZ = 0x14, + SX126X_GFSK_BANDWIDTH_58600HZ = 0x0c, + SX126X_GFSK_BANDWIDTH_78200HZ = 0x1b, + SX126X_GFSK_BANDWIDTH_93800HZ = 0x13, + SX126X_GFSK_BANDWIDTH_117300HZ = 0x0b, + SX126X_GFSK_BANDWIDTH_156200HZ = 0x1a, + SX126X_GFSK_BANDWIDTH_187200HZ = 0x12, + SX126X_GFSK_BANDWIDTH_234300HZ = 0x0a, + SX126X_GFSK_BANDWIDTH_312000HZ = 0x19, + SX126X_GFSK_BANDWIDTH_373600HZ = 0x11, + SX126X_GFSK_BANDWIDTH_467000HZ = 0x09 +}; + +/* LoRa Spreading Factors */ + +enum sx126x_lora_sf_e +{ + SX126X_LORA_SF5 = 0x05, + SX126X_LORA_SF6 = 0x06, + SX126X_LORA_SF7 = 0x07, + SX126X_LORA_SF8 = 0x08, + SX126X_LORA_SF9 = 0x09, + SX126X_LORA_SF10 = 0x0a, + SX126X_LORA_SF11 = 0x0b, + SX126X_LORA_SF12 = 0x0c +}; + +/* LoRa Bandwidths */ + +enum sx126x_lora_bw_e +{ + SX126X_LORA_BW_7 = 0x00, + SX126X_LORA_BW_10 = 0x08, + SX126X_LORA_BW_15 = 0x01, + SX126X_LORA_BW_20 = 0x09, + SX126X_LORA_BW_31 = 0x02, + SX126X_LORA_BW_41 = 0x0a, + SX126X_LORA_BW_62 = 0x03, + SX126X_LORA_BW_125 = 0x04, + SX126X_LORA_BW_250 = 0x05, + SX126X_LORA_BW_500 = 0x06 +}; + +/* LoRa Coding Rates */ + +enum sx126x_lora_cr_e +{ + SX126X_LORA_CR_4_5 = 0x01, + SX126X_LORA_CR_4_6 = 0x02, + SX126X_LORA_CR_4_7 = 0x03, + SX126X_LORA_CR_4_8 = 0x04 +}; + +/* CAD Exit modes */ + +enum sx126x_cad_exit_mode_e +{ + SX126X_CAD_ONLY = 0x00, + SX126X_CAD_RX = 0x01 +}; + +/* TCXO voltages */ + +enum sx126x_tcxo_voltage_e +{ + SX126X_TCXO_1_6V = 0x00, + SX126X_TCXO_1_7V = 0x01, + SX126X_TCXO_1_8V = 0x02, + SX126X_TCXO_2_2V = 0x03, + SX126X_TCXO_2_4V = 0x04, + SX126X_TCXO_2_7V = 0x05, + SX126X_TCXO_3_0V = 0x06, + SX126X_TCXO_3_3V = 0x07 +}; + +/* Fallback modes */ + +enum sx126x_fallback_mode_e +{ + SX126X_FALLBACK_FS = 0x40, + SX126X_FALLBACK_STDBY_XOSC = 0x30, + SX126X_FALLBACK_STDBY_RC = 0x20 +}; + +/* Regulator modes */ + +enum sx126x_regulator_mode_e +{ + SX126X_LDO = 0x00, + SX126X_DC_DC_LDO = 0x01 +}; + +/* Device */ + +enum sx126x_device_e +{ + SX1261 = 0x01, + SX1262 = 0x00 +}; + +enum sx126x_gfsk_preamble_detect_e +{ + SX126X_GFSK_PREAMBLE_DETECT_OFF, + SX126X_GFSK_PREAMBLE_DETECT_8B, + SX126X_GFSK_PREAMBLE_DETECT_16B, + SX126X_GFSK_PREAMBLE_DETECT_24B, + SX126X_GFSK_PREAMBLE_DETECT_32B +}; + +/* Addr comp */ + +enum sx126x_address_filtering_e +{ + SX126X_ADDR_FILT_DISABLED, + SX126X_ADDR_FILT_NODE, + SX126X_ADDR_FILT_NODE_BROADCAST +}; + +/* GFSK CRC types */ + +enum sx126x_gfsk_crc_type_e +{ + SX126X_GFSK_CRCTYPE_OFF = 0x01, + SX126X_GFSK_CRCTYPE_1_BYTE = 0x00, + SX126X_GFSK_CRCTYPE_2_BYTE = 0x02, + SX126X_GFSK_CRCTYPE_1_BYTE_INV = 0x04, + SX126X_GFSK_CRCTYPE_2_BYTE_INV = 0x06 +}; + +/* LoRa mod params */ + +struct sx126x_modparams_lora_s +{ + enum sx126x_lora_sf_e spreading_factor; + enum sx126x_lora_bw_e bandwidth; + enum sx126x_lora_cr_e coding_rate; + bool low_datarate_optimization; +}; + +/* GFSK mod params */ + +struct sx126x_modparams_gfsk_s +{ + uint32_t bitrate; + enum sx126x_gfsk_pulseshape_e pulseshape; + enum sx126x_gfsk_bandwidth_e bandwidth; + uint32_t frequency_deviation; +}; + +/* LoRa packet params */ + +struct sx126x_packetparams_lora_s +{ + uint16_t preambles; + bool fixed_length_header; + uint8_t payload_length; + bool crc_enable; + bool invert_iq; +}; + +/* GFSK packet params */ + +struct sx126x_packetparams_gfsk_s +{ + uint16_t preambles; + enum sx126x_gfsk_preamble_detect_e preamble_detect; + uint8_t syncword_length; + enum sx126x_address_filtering_e address_filtering; + bool include_packet_size; + uint8_t packet_length; + enum sx126x_gfsk_crc_type_e crc_type; + bool whitening_enable; +}; + +/* Config */ + +struct sx126x_lora_config_s +{ + struct sx126x_modparams_lora_s modulation; + struct sx126x_packetparams_lora_s packet; +}; + +/* Lower driver *************************************************************/ + +struct sx126x_irq_masks +{ + uint16_t dio1_mask; + uint16_t dio2_mask; + uint16_t dio3_mask; +}; + +struct sx126x_lower_s +{ + /* Index of radio to register. + * ex: 0 is the primary radio, 1 is the secondary. + * Must be within the maximum configured radios. + */ + + unsigned int dev_number; + CODE void (*reset)(void); + + /* This controls which DIO reacts to interrupts + * Depended on the pinout of the board / module. + * Note that DIO 2 and DIO 3 can be already in use + * by the module and setting them might intefere + * with the operation or even damage them. + */ + + struct sx126x_irq_masks masks; + enum sx126x_tcxo_voltage_e dio3_voltage; + uint32_t dio3_delay; + uint8_t use_dio2_as_rf_sw; + + /* Interrupt attachments. These should be + * connected to one of the DIOx pins + */ + + CODE int (*irq0attach)(xcpt_t handler, FAR void *arg); + + /* The regulator mode is board / module depended */ + + enum sx126x_regulator_mode_e regulator_mode; + + /* Power amplifier control. DO NOT exceeds the + * limits listed in SX1261-2 V2 datasheet. + * 13.1.14 SetPaConfig + * This can cause damage to the device. + */ + + CODE int (*get_pa_values)(enum sx126x_device_e *model, + uint8_t *hpmax, uint8_t *padutycycle); + + /* TX power control. Depending on the local RF regulations, + * power might have to be limited. + * Also depending on board or module, + * power values have different charactersitics. + * More info in sx1261-2 V2 datasheet 13.4.4 SetTxParams. + * uint8_t *power is set and this function may limit it. + */ + + CODE int (*limit_tx_power)(uint8_t *current_power); + + enum sx126x_ramp_time_e tx_ramp_time; + + /* Frequency control + * Typically boards have a limited range of frequencies. + * Exceeding these can damage the radio. + * Also depending on regulations, some frequencies are restricted. + * This must return non zero in case a frequency is denied. + */ + + CODE int (*check_frequency)(uint32_t frequency); +}; + +/* Upper ********************************************************************/ + +struct sx126x_read_header_s +{ + uint8_t payload_length; + int32_t snr; + int16_t rssi_db; + uint8_t payload[SX126X_RX_PAYLOAD_SIZE]; + uint8_t crc_error; +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +void sx126x_register(FAR struct spi_dev_s *spi, + FAR const struct sx126x_lower_s *lower, + const char *path); + +#endif /* __INCLUDE_NUTTX_WIRELESS_LPWAN_SX126X_H */ \ No newline at end of file