mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16177 from aabadie/driver_llcc68
drivers: add support for sx1261/2 and llcc68 radio devices
This commit is contained in:
commit
18a0889bc4
@ -16,6 +16,7 @@ rsource "ncv7356/Kconfig"
|
||||
rsource "pn532/Kconfig"
|
||||
rsource "rn2xx3/Kconfig"
|
||||
rsource "slipdev/Kconfig"
|
||||
rsource "sx126x/Kconfig"
|
||||
rsource "sx127x/Kconfig"
|
||||
rsource "tja1042/Kconfig"
|
||||
source "$(RIOTCPU)/nrf52/radio/nrf802154/Kconfig"
|
||||
|
@ -68,6 +68,10 @@ ifneq (,$(filter lis2dh12%,$(USEMODULE)))
|
||||
USEMODULE += lis2dh12
|
||||
endif
|
||||
|
||||
ifneq (,$(filter llcc68,$(USEMODULE)))
|
||||
USEMODULE += sx126x
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lps331ap lps2%hb,$(USEMODULE)))
|
||||
USEMODULE += lpsxxx
|
||||
endif
|
||||
@ -147,6 +151,10 @@ ifneq (,$(filter slipdev_%,$(USEMODULE)))
|
||||
USEMODULE += slipdev
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sx126%,$(USEMODULE)))
|
||||
USEMODULE += sx126x
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sx127%,$(USEMODULE)))
|
||||
USEMODULE += sx127x
|
||||
endif
|
||||
|
@ -318,6 +318,7 @@ typedef enum {
|
||||
NETDEV_ESP_NOW,
|
||||
NETDEV_NRF24L01P_NG,
|
||||
NETDEV_SOCKET_ZEP,
|
||||
NETDEV_SX126X,
|
||||
/* add more if needed */
|
||||
} netdev_type_t;
|
||||
/** @} */
|
||||
|
236
drivers/include/sx126x.h
Normal file
236
drivers/include/sx126x.h
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_sx126x SX1261/2/8 and LLCC68 LoRa radio driver
|
||||
* @ingroup drivers_netdev
|
||||
* @brief Driver for the SX1261/2/8 and LLCC68 LoRa radio device
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX126X_H
|
||||
#define SX126X_H
|
||||
|
||||
#include "sx126x_driver.h"
|
||||
|
||||
#include "net/netdev.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Device initialization parameters
|
||||
*/
|
||||
typedef struct {
|
||||
spi_t spi; /**< SPI device */
|
||||
gpio_t nss_pin; /**< SPI NSS pin */
|
||||
gpio_t reset_pin; /**< Reset pin */
|
||||
gpio_t busy_pin; /**< Busy pin */
|
||||
gpio_t dio1_pin; /**< Dio1 pin */
|
||||
sx126x_reg_mod_t regulator; /**< Power regulator mode */
|
||||
} sx126x_params_t;
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for the driver
|
||||
*/
|
||||
typedef struct {
|
||||
netdev_t netdev; /**< Netdev parent struct */
|
||||
sx126x_params_t *params; /**< Initialization parameters */
|
||||
sx126x_pkt_params_lora_t pkt_params; /**< Lora packet parameters */
|
||||
sx126x_mod_params_lora_t mod_params; /**< Lora modulation parameters */
|
||||
uint32_t channel; /**< Current channel frequency (in Hz) */
|
||||
uint32_t rx_timeout; /**< RX timeout in ms */
|
||||
} sx126x_t;
|
||||
|
||||
/**
|
||||
* @brief Setup the radio device
|
||||
*
|
||||
* @param[in] dev Device descriptor
|
||||
* @param[in] params Parameters for device initialization
|
||||
* @param[in] index Index of @p params in a global parameter struct array.
|
||||
* If initialized manually, pass a unique identifier instead.
|
||||
*/
|
||||
void sx126x_setup(sx126x_t *dev, const sx126x_params_t *params, uint8_t index);
|
||||
|
||||
/**
|
||||
* @brief Initialize the given device
|
||||
*
|
||||
* @param[inout] dev Device descriptor of the driver
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int sx126x_init(sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Gets the channel RF frequency.
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return The channel frequency
|
||||
*/
|
||||
uint32_t sx126x_get_channel(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the channel RF frequency.
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] freq Channel RF frequency
|
||||
*/
|
||||
void sx126x_set_channel(sx126x_t *dev, uint32_t freq);
|
||||
|
||||
/**
|
||||
* @brief Gets the LoRa bandwidth
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the bandwidth
|
||||
*/
|
||||
uint8_t sx126x_get_bandwidth(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the LoRa bandwidth
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] bandwidth The new bandwidth
|
||||
*/
|
||||
void sx126x_set_bandwidth(sx126x_t *dev, uint8_t bandwidth);
|
||||
|
||||
/**
|
||||
* @brief Gets the LoRa spreading factor
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the spreading factor
|
||||
*/
|
||||
uint8_t sx126x_get_spreading_factor(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the LoRa spreading factor
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] sf The spreading factor
|
||||
*/
|
||||
void sx126x_set_spreading_factor(sx126x_t *dev, uint8_t sf);
|
||||
|
||||
/**
|
||||
* @brief Gets the LoRa coding rate
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the current LoRa coding rate
|
||||
*/
|
||||
uint8_t sx126x_get_coding_rate(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the LoRa coding rate
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] cr The LoRa coding rate
|
||||
*/
|
||||
void sx126x_set_coding_rate(sx126x_t *dev, uint8_t cr);
|
||||
|
||||
/**
|
||||
* @brief Gets the payload length
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the payload length
|
||||
*/
|
||||
uint8_t sx126x_get_lora_payload_length(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the payload length
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] len The payload len
|
||||
*/
|
||||
void sx126x_set_lora_payload_length(sx126x_t *dev, uint8_t len);
|
||||
|
||||
/**
|
||||
* @brief Checks if CRC verification mode is enabled
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the LoRa single mode
|
||||
*/
|
||||
bool sx126x_get_lora_crc(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable CRC verification mode
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] crc The CRC check mode
|
||||
*/
|
||||
void sx126x_set_lora_crc(sx126x_t *dev, bool crc);
|
||||
|
||||
/**
|
||||
* @brief Gets the LoRa implicit header mode
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the LoRa implicit mode
|
||||
*/
|
||||
bool sx126x_get_lora_implicit_header(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets LoRa implicit header mode
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] mode The header mode
|
||||
*/
|
||||
void sx126x_set_lora_implicit_header(sx126x_t *dev, bool mode);
|
||||
|
||||
/**
|
||||
* @brief Gets the LoRa preamble length
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the preamble length
|
||||
*/
|
||||
uint16_t sx126x_get_lora_preamble_length(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the LoRa preamble length
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] preamble The LoRa preamble length
|
||||
*/
|
||||
void sx126x_set_lora_preamble_length(sx126x_t *dev, uint16_t preamble);
|
||||
|
||||
/**
|
||||
* @brief Checks if the LoRa inverted IQ mode is enabled/disabled
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
*
|
||||
* @return the LoRa IQ inverted mode
|
||||
*/
|
||||
bool sx126x_get_lora_iq_invert(const sx126x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable the LoRa IQ inverted mode
|
||||
*
|
||||
* @param[in] dev Device descriptor of the driver
|
||||
* @param[in] iq_invert The LoRa IQ inverted mode
|
||||
*/
|
||||
void sx126x_set_lora_iq_invert(sx126x_t *dev, bool iq_invert);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX126X_H */
|
||||
/** @} */
|
14
drivers/sx126x/Kconfig
Normal file
14
drivers/sx126x/Kconfig
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2021 Inria
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
config MODULE_SX126X
|
||||
bool "SX126X LoRa Sub-GHz radio"
|
||||
depends on HAS_PERIPH_GPIO_IRQ
|
||||
depends on PACKAGE_DRIVER_SX126X
|
||||
depends on TEST_KCONFIG
|
||||
select MODULE_PERIPH_GPIO_IRQ
|
||||
select MODULE_IOLIST
|
1
drivers/sx126x/Makefile
Normal file
1
drivers/sx126x/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
3
drivers/sx126x/Makefile.dep
Normal file
3
drivers/sx126x/Makefile.dep
Normal file
@ -0,0 +1,3 @@
|
||||
USEMODULE += iolist
|
||||
USEPKG += driver_sx126x
|
||||
FEATURES_REQUIRED += periph_gpio_irq
|
2
drivers/sx126x/Makefile.include
Normal file
2
drivers/sx126x/Makefile.include
Normal file
@ -0,0 +1,2 @@
|
||||
USEMODULE_INCLUDES_sx126x := $(LAST_MAKEFILEDIR)/include
|
||||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_sx126x)
|
37
drivers/sx126x/include/sx126x_netdev.h
Normal file
37
drivers/sx126x/include/sx126x_netdev.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_sx126x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Netdev driver definitions for SX1261/2/8 and LLCC68 driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX126X_NETDEV_H
|
||||
#define SX126X_NETDEV_H
|
||||
|
||||
#include "net/netdev.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference to the netdev device driver struct
|
||||
*/
|
||||
extern const netdev_driver_t sx126x_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX126X_NETDEV_H */
|
||||
/** @} */
|
81
drivers/sx126x/include/sx126x_params.h
Normal file
81
drivers/sx126x/include/sx126x_params.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_sx126x
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief Default configuration
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX126X_PARAMS_H
|
||||
#define SX126X_PARAMS_H
|
||||
|
||||
#include "board.h"
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_driver.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Set default configuration parameters
|
||||
*
|
||||
* Default values are adapted for mbed shield used with to nucleo64 boards
|
||||
* @{
|
||||
*/
|
||||
#ifndef SX126X_PARAM_SPI
|
||||
#define SX126X_PARAM_SPI SPI_DEV(0)
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_SPI_NSS
|
||||
#define SX126X_PARAM_SPI_NSS GPIO_PIN(0, 8) /* D7 */
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_RESET
|
||||
#define SX126X_PARAM_RESET GPIO_PIN(0, 0) /* A0 */
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_BUSY
|
||||
#define SX126X_PARAM_BUSY GPIO_PIN(1, 3) /* D3 */
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_DIO1
|
||||
#define SX126X_PARAM_DIO1 GPIO_PIN(1, 4) /* D5 */
|
||||
#endif
|
||||
|
||||
#ifndef SX126X_PARAM_REGULATOR
|
||||
#define SX126X_PARAM_REGULATOR SX126X_REG_MODE_DCDC
|
||||
#endif
|
||||
|
||||
#define SX126X_PARAMS { .spi = SX126X_PARAM_SPI, \
|
||||
.nss_pin = SX126X_PARAM_SPI_NSS, \
|
||||
.reset_pin = SX126X_PARAM_RESET, \
|
||||
.busy_pin = SX126X_PARAM_BUSY, \
|
||||
.dio1_pin = SX126X_PARAM_DIO1, \
|
||||
.regulator = SX126X_PARAM_REGULATOR }
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @brief Configuration struct
|
||||
*/
|
||||
static const sx126x_params_t sx126x_params[] =
|
||||
{
|
||||
SX126X_PARAMS
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX126X_PARAMS_H */
|
||||
/** @} */
|
307
drivers/sx126x/sx126x.c
Normal file
307
drivers/sx126x/sx126x.c
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_sx126x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Device driver implementation for the SX1261/2/8 and LLCC68 LoRa radio driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "sx126x_netdev.h"
|
||||
|
||||
#include "net/lora.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "sx126x_driver.h"
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_params.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef CONFIG_SX126X_PKT_TYPE_DEFAULT
|
||||
#define CONFIG_SX126X_PKT_TYPE_DEFAULT (SX126X_PKT_TYPE_LORA)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SX126X_CHANNEL_DEFAULT
|
||||
#define CONFIG_SX126X_CHANNEL_DEFAULT (868300000UL) /* in Hz */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SX126X_TX_POWER_DEFAULT
|
||||
#define CONFIG_SX126X_TX_POWER_DEFAULT (14U) /* in dBm */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SX126X_RAMP_TIME_DEFAULT
|
||||
#define CONFIG_SX126X_RAMP_TIME_DEFAULT (SX126X_RAMP_10_US)
|
||||
#endif
|
||||
|
||||
void sx126x_setup(sx126x_t *dev, const sx126x_params_t *params, uint8_t index)
|
||||
{
|
||||
netdev_t *netdev = (netdev_t *)dev;
|
||||
|
||||
netdev->driver = &sx126x_driver;
|
||||
dev->params = (sx126x_params_t *)params;
|
||||
netdev_register(&dev->netdev, NETDEV_SX126X, index);
|
||||
}
|
||||
|
||||
static const uint16_t _bw_khz[3] = {
|
||||
[LORA_BW_125_KHZ] = 125,
|
||||
[LORA_BW_250_KHZ] = 250,
|
||||
[LORA_BW_500_KHZ] = 500,
|
||||
};
|
||||
|
||||
static uint8_t _compute_ldro(sx126x_t *dev)
|
||||
{
|
||||
uint32_t symbol_len = (uint32_t)(1 << dev->mod_params.sf) / _bw_khz[dev->mod_params.bw - SX126X_LORA_BW_125];
|
||||
if (symbol_len >= 16) {
|
||||
return 0x01;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static void sx126x_init_default_config(sx126x_t *dev)
|
||||
{
|
||||
/* packet type must be set first */
|
||||
sx126x_set_pkt_type(dev, SX126X_PKT_TYPE_LORA);
|
||||
sx126x_set_channel(dev, CONFIG_SX126X_CHANNEL_DEFAULT);
|
||||
|
||||
/* Configure PA optimal settings for maximum output power
|
||||
* Values used here comes from the datasheet, section 13.1.14 SetPaConfig
|
||||
* and are optimal for a TX output power of 14dBm.
|
||||
*/
|
||||
if (IS_USED(MODULE_LLCC68) || IS_USED(MODULE_SX1262)) {
|
||||
sx126x_pa_cfg_params_t pa_cfg = {
|
||||
.pa_duty_cycle = 0x02,
|
||||
.hp_max = 0x02,
|
||||
.device_sel = 0x00,
|
||||
.pa_lut = 0x01
|
||||
};
|
||||
sx126x_set_pa_cfg(dev, &pa_cfg);
|
||||
}
|
||||
else if (IS_USED(MODULE_SX1268)) {
|
||||
sx126x_pa_cfg_params_t pa_cfg = {
|
||||
.pa_duty_cycle = 0x04,
|
||||
.hp_max = 0x06,
|
||||
.device_sel = 0x00,
|
||||
.pa_lut = 0x01
|
||||
};
|
||||
sx126x_set_pa_cfg(dev, &pa_cfg);
|
||||
}
|
||||
else { /* IS_USED(MODULE_SX1261) */
|
||||
sx126x_pa_cfg_params_t pa_cfg = {
|
||||
.pa_duty_cycle = 0x04,
|
||||
.hp_max = 0x00,
|
||||
.device_sel = 0x01,
|
||||
.pa_lut = 0x01
|
||||
};
|
||||
sx126x_set_pa_cfg(dev, &pa_cfg);
|
||||
}
|
||||
sx126x_set_tx_params(dev, CONFIG_SX126X_TX_POWER_DEFAULT, CONFIG_SX126X_RAMP_TIME_DEFAULT);
|
||||
|
||||
dev->mod_params.bw = (sx126x_lora_bw_t)(CONFIG_LORA_BW_DEFAULT + SX126X_LORA_BW_125);
|
||||
dev->mod_params.sf = (sx126x_lora_sf_t)CONFIG_LORA_SF_DEFAULT;
|
||||
dev->mod_params.cr = (sx126x_lora_cr_t)CONFIG_LORA_CR_DEFAULT;
|
||||
dev->mod_params.ldro = _compute_ldro(dev);
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
|
||||
dev->pkt_params.pld_len_in_bytes = 0;
|
||||
dev->pkt_params.crc_is_on = LORA_PAYLOAD_CRC_ON_DEFAULT;
|
||||
dev->pkt_params.header_type = (
|
||||
IS_ACTIVE(CONFIG_LORA_FIXED_HEADER_LEN_MODE_DEFAULT) ? true : false
|
||||
);
|
||||
dev->pkt_params.preamble_len_in_symb = CONFIG_LORA_PREAMBLE_LENGTH_DEFAULT;
|
||||
dev->pkt_params.invert_iq_is_on = (
|
||||
IS_ACTIVE(CONFIG_LORA_IQ_INVERTED_DEFAULT) ? true : false
|
||||
);
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
static void _dio1_isr(void *arg)
|
||||
{
|
||||
netdev_trigger_event_isr((netdev_t *)arg);
|
||||
}
|
||||
|
||||
int sx126x_init(sx126x_t *dev)
|
||||
{
|
||||
/* Setup SPI for SX126X */
|
||||
int res = spi_init_cs(dev->params->spi, dev->params->nss_pin);
|
||||
|
||||
if (res != SPI_OK) {
|
||||
DEBUG("[sx126x] error: failed to initialize SPI_%i device (code %i)\n",
|
||||
dev->params->spi, res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("[sx126x] init: SPI_%i initialized with success\n", dev->params->spi);
|
||||
|
||||
gpio_init(dev->params->reset_pin, GPIO_OUT);
|
||||
gpio_init(dev->params->busy_pin, GPIO_IN_PD);
|
||||
|
||||
/* Initialize DIOs */
|
||||
if (gpio_is_valid(dev->params->dio1_pin)) {
|
||||
res = gpio_init_int(dev->params->dio1_pin, GPIO_IN, GPIO_RISING, _dio1_isr, dev);
|
||||
if (res < 0) {
|
||||
DEBUG("[sx126x] error: failed to initialize DIO1 pin\n");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("[sx126x] error: no DIO1 pin defined\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Reset the device */
|
||||
sx126x_reset(dev);
|
||||
|
||||
/* Configure the power regulator mode */
|
||||
sx126x_set_reg_mode(dev, dev->params->regulator);
|
||||
|
||||
/* Initialize radio with the default parameters */
|
||||
sx126x_init_default_config(dev);
|
||||
|
||||
/* Configure available IRQs */
|
||||
const uint16_t irq_mask = (
|
||||
SX126X_IRQ_TX_DONE |
|
||||
SX126X_IRQ_RX_DONE |
|
||||
SX126X_IRQ_PREAMBLE_DETECTED |
|
||||
SX126X_IRQ_HEADER_VALID |
|
||||
SX126X_IRQ_HEADER_ERROR |
|
||||
SX126X_IRQ_CRC_ERROR |
|
||||
SX126X_IRQ_CAD_DONE |
|
||||
SX126X_IRQ_CAD_DETECTED |
|
||||
SX126X_IRQ_TIMEOUT
|
||||
);
|
||||
|
||||
sx126x_set_dio_irq_params(dev, irq_mask, irq_mask, 0, 0);
|
||||
|
||||
if (IS_ACTIVE(ENABLE_DEBUG)) {
|
||||
sx126x_pkt_type_t pkt_type;
|
||||
sx126x_get_pkt_type(dev, &pkt_type);
|
||||
DEBUG("[sx126x] init radio: pkt type: %d\n", pkt_type);
|
||||
|
||||
sx126x_chip_status_t radio_status;
|
||||
sx126x_get_status(dev, &radio_status);
|
||||
DEBUG("[sx126x] init: chip mode %d\n", radio_status.chip_mode);
|
||||
DEBUG("[sx126x] init: cmd status %d\n", radio_status.cmd_status);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t sx126x_get_channel(const sx126x_t *dev)
|
||||
{
|
||||
return dev->channel;
|
||||
}
|
||||
|
||||
void sx126x_set_channel(sx126x_t *dev, uint32_t freq)
|
||||
{
|
||||
dev->channel = freq;
|
||||
sx126x_set_rf_freq(dev, dev->channel);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_bandwidth(const sx126x_t *dev)
|
||||
{
|
||||
return dev->mod_params.bw - SX126X_LORA_BW_125;
|
||||
}
|
||||
|
||||
void sx126x_set_bandwidth(sx126x_t *dev, uint8_t bandwidth)
|
||||
{
|
||||
dev->mod_params.bw = bandwidth + SX126X_LORA_BW_125;
|
||||
dev->mod_params.ldro = _compute_ldro(dev);
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_spreading_factor(const sx126x_t *dev)
|
||||
{
|
||||
return dev->mod_params.sf;
|
||||
}
|
||||
|
||||
void sx126x_set_spreading_factor(sx126x_t *dev, uint8_t sf)
|
||||
{
|
||||
dev->mod_params.sf = (sx126x_lora_sf_t)sf;
|
||||
dev->mod_params.ldro = _compute_ldro(dev);
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_coding_rate(const sx126x_t *dev)
|
||||
{
|
||||
return dev->mod_params.cr;
|
||||
}
|
||||
|
||||
void sx126x_set_coding_rate(sx126x_t *dev, uint8_t cr)
|
||||
{
|
||||
dev->mod_params.cr = (sx126x_lora_cr_t)cr;
|
||||
sx126x_set_lora_mod_params(dev, &dev->mod_params);
|
||||
}
|
||||
|
||||
uint8_t sx126x_get_lora_payload_length(const sx126x_t *dev)
|
||||
{
|
||||
sx126x_rx_buffer_status_t rx_buffer_status;
|
||||
|
||||
sx126x_get_rx_buffer_status(dev, &rx_buffer_status);
|
||||
return rx_buffer_status.pld_len_in_bytes;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_payload_length(sx126x_t *dev, uint8_t len)
|
||||
{
|
||||
dev->pkt_params.pld_len_in_bytes = len;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_crc(const sx126x_t *dev)
|
||||
{
|
||||
return dev->pkt_params.crc_is_on;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_crc(sx126x_t *dev, bool crc)
|
||||
{
|
||||
dev->pkt_params.crc_is_on = crc;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_implicit_header(const sx126x_t *dev)
|
||||
{
|
||||
return dev->pkt_params.header_type == SX126X_LORA_PKT_IMPLICIT;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_implicit_header(sx126x_t *dev, bool mode)
|
||||
{
|
||||
dev->pkt_params.header_type = (mode ? SX126X_LORA_PKT_IMPLICIT : SX126X_LORA_PKT_EXPLICIT);
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
uint16_t sx126x_get_lora_preamble_length(const sx126x_t *dev)
|
||||
{
|
||||
return dev->pkt_params.preamble_len_in_symb;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_preamble_length(sx126x_t *dev, uint16_t preamble)
|
||||
{
|
||||
dev->pkt_params.preamble_len_in_symb = preamble;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
||||
|
||||
bool sx126x_get_lora_iq_invert(const sx126x_t *dev)
|
||||
{
|
||||
return dev->pkt_params.invert_iq_is_on;
|
||||
}
|
||||
|
||||
void sx126x_set_lora_iq_invert(sx126x_t *dev, bool iq_invert)
|
||||
{
|
||||
dev->pkt_params.invert_iq_is_on = iq_invert;
|
||||
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
|
||||
}
|
436
drivers/sx126x/sx126x_netdev.c
Normal file
436
drivers/sx126x/sx126x_netdev.c
Normal file
@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_sx126x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Netdev adaptation for the SX1261/2/8 and LLCC68 driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "iolist.h"
|
||||
#include "net/netopt.h"
|
||||
#include "net/netdev.h"
|
||||
#include "net/netdev/lora.h"
|
||||
#include "net/lora.h"
|
||||
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_netdev.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#if IS_USED(MODULE_LLCC68)
|
||||
#define SX126X_MAX_SF LORA_SF11
|
||||
#else
|
||||
#define SX126X_MAX_SF LORA_SF12
|
||||
#endif
|
||||
|
||||
static int _send(netdev_t *netdev, const iolist_t *iolist)
|
||||
{
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
|
||||
netopt_state_t state;
|
||||
|
||||
netdev->driver->get(netdev, NETOPT_STATE, &state, sizeof(uint8_t));
|
||||
if (state == NETOPT_STATE_TX) {
|
||||
DEBUG("[sx126x] netdev: cannot send packet, radio is already transmitting.\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
uint8_t size = iolist_size(iolist);
|
||||
|
||||
/* Ignore send if packet size is 0 */
|
||||
if (!size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG("[sx126x] netdev: sending packet now (size: %d).\n", size);
|
||||
/* Write payload buffer */
|
||||
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
|
||||
if (iol->iol_len > 0) {
|
||||
sx126x_set_lora_payload_length(dev, iol->iol_len);
|
||||
sx126x_write_buffer(dev, 0, iol->iol_base, iol->iol_len);
|
||||
DEBUG("[sx126x] netdev: send: wrote data to payload buffer.\n");
|
||||
}
|
||||
}
|
||||
|
||||
state = NETOPT_STATE_TX;
|
||||
netdev->driver->set(netdev, NETOPT_STATE, &state, sizeof(uint8_t));
|
||||
DEBUG("[sx126x] netdev: send: transmission in progress.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
||||
{
|
||||
DEBUG("[sx126x] netdev: read received data.\n");
|
||||
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
uint8_t size = 0;
|
||||
|
||||
netdev_lora_rx_info_t *packet_info = (netdev_lora_rx_info_t *)info;
|
||||
|
||||
if (packet_info) {
|
||||
sx126x_pkt_status_lora_t pkt_status;
|
||||
sx126x_get_lora_pkt_status(dev, &pkt_status);
|
||||
packet_info->snr = pkt_status.snr_pkt_in_db;
|
||||
packet_info->rssi = pkt_status.rssi_pkt_in_dbm;
|
||||
}
|
||||
|
||||
sx126x_rx_buffer_status_t rx_buffer_status;
|
||||
|
||||
sx126x_get_rx_buffer_status(dev, &rx_buffer_status);
|
||||
|
||||
size = rx_buffer_status.pld_len_in_bytes;
|
||||
|
||||
if (buf == NULL) {
|
||||
return size;
|
||||
}
|
||||
|
||||
if (size > len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
sx126x_read_buffer(dev, rx_buffer_status.buffer_start_pointer, buf, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _init(netdev_t *netdev)
|
||||
{
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
|
||||
/* Launch initialization of driver and device */
|
||||
DEBUG("[sx126x] netdev: initializing driver...\n");
|
||||
if (sx126x_init(dev) != 0) {
|
||||
DEBUG("[sx126x] netdev: initialization failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("[sx126x] netdev: initialization successful\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _isr(netdev_t *netdev)
|
||||
{
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
|
||||
sx126x_irq_mask_t irq_mask;
|
||||
|
||||
sx126x_get_and_clear_irq_status(dev, &irq_mask);
|
||||
|
||||
if (irq_mask & SX126X_IRQ_TX_DONE) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_TX_DONE\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_RX_DONE) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_RX_DONE\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_PREAMBLE_DETECTED) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_PREAMBLE_DETECTED\n");
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_SYNC_WORD_VALID) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_SYNC_WORD_VALID\n");
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_HEADER_VALID) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_HEADER_VALID\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_STARTED);
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_HEADER_ERROR) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_HEADER_ERROR\n");
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_CRC_ERROR) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_CRC_ERROR\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_CRC_ERROR);
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_CAD_DONE) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_CAD_DONE\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_CAD_DONE);
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_CAD_DETECTED) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_CAD_DETECTED\n");
|
||||
}
|
||||
else if (irq_mask & SX126X_IRQ_TIMEOUT) {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_TIMEOUT\n");
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_TIMEOUT);
|
||||
}
|
||||
else {
|
||||
DEBUG("[sx126x] netdev: SX126X_IRQ_NONE\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int _get_state(sx126x_t *dev, void *val)
|
||||
{
|
||||
sx126x_chip_status_t radio_status;
|
||||
|
||||
sx126x_get_status(dev, &radio_status);
|
||||
netopt_state_t state = NETOPT_STATE_OFF;
|
||||
|
||||
switch (radio_status.chip_mode) {
|
||||
case SX126X_CHIP_MODE_RFU:
|
||||
case SX126X_CHIP_MODE_STBY_RC:
|
||||
case SX126X_CHIP_MODE_STBY_XOSC:
|
||||
state = NETOPT_STATE_STANDBY;
|
||||
break;
|
||||
|
||||
case SX126X_CHIP_MODE_TX:
|
||||
state = NETOPT_STATE_TX;
|
||||
break;
|
||||
|
||||
case SX126X_CHIP_MODE_RX:
|
||||
state = NETOPT_STATE_RX;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
memcpy(val, &state, sizeof(netopt_state_t));
|
||||
return sizeof(netopt_state_t);
|
||||
}
|
||||
|
||||
static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
|
||||
{
|
||||
(void)max_len; /* unused when compiled without debug, assert empty */
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
|
||||
if (dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_STATE:
|
||||
assert(max_len >= sizeof(netopt_state_t));
|
||||
return _get_state(dev, val);
|
||||
|
||||
case NETOPT_DEVICE_TYPE:
|
||||
assert(max_len >= sizeof(uint16_t));
|
||||
sx126x_pkt_type_t pkt_type;
|
||||
sx126x_get_pkt_type(dev, &pkt_type);
|
||||
*((uint16_t *)val) =
|
||||
(pkt_type == SX126X_PKT_TYPE_LORA) ? NETDEV_TYPE_LORA : NETDEV_TYPE_UNKNOWN;
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_CHANNEL_FREQUENCY:
|
||||
assert(max_len >= sizeof(uint32_t));
|
||||
*((uint32_t *)val) = sx126x_get_channel(dev);
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_BANDWIDTH:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t *)val) = sx126x_get_bandwidth(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SPREADING_FACTOR:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t *)val) = sx126x_get_spreading_factor(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_CODING_RATE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t *)val) = sx126x_get_coding_rate(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_PDU_SIZE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t *)val) = sx126x_get_lora_payload_length(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_INTEGRITY_CHECK:
|
||||
assert(max_len >= sizeof(netopt_enable_t));
|
||||
*((netopt_enable_t *)val) = sx126x_get_lora_crc(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RANDOM:
|
||||
assert(max_len >= sizeof(uint32_t));
|
||||
sx126x_get_random_numbers(dev, val, 1);
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_IQ_INVERT:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((netopt_enable_t *)val) = sx126x_get_lora_iq_invert(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RSSI:
|
||||
assert(max_len >= sizeof(int8_t));
|
||||
sx126x_get_rssi_inst(dev, ((int16_t *)val));
|
||||
return sizeof(int8_t);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int _set_state(sx126x_t *dev, netopt_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case NETOPT_STATE_STANDBY:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_STANDBY state\n");
|
||||
sx126x_set_standby(dev, SX126X_CHIP_MODE_STBY_XOSC);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_IDLE:
|
||||
case NETOPT_STATE_RX:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_RX state\n");
|
||||
sx126x_cfg_rx_boosted(dev, true);
|
||||
if (dev->rx_timeout != 0) {
|
||||
sx126x_set_rx(dev, dev->rx_timeout);
|
||||
}
|
||||
else {
|
||||
sx126x_set_rx(dev, SX126X_RX_SINGLE_MODE);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_TX:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_TX state\n");
|
||||
sx126x_set_tx(dev, 0);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_RESET:
|
||||
DEBUG("[sx126x] netdev: set NETOPT_STATE_RESET state\n");
|
||||
sx126x_reset(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return sizeof(netopt_state_t);
|
||||
}
|
||||
|
||||
static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
|
||||
{
|
||||
(void)len; /* unused when compiled without debug, assert empty */
|
||||
sx126x_t *dev = (sx126x_t *)netdev;
|
||||
int res = -ENOTSUP;
|
||||
|
||||
if (dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (opt) {
|
||||
case NETOPT_STATE:
|
||||
assert(len == sizeof(netopt_state_t));
|
||||
return _set_state(dev, *((const netopt_state_t *)val));
|
||||
|
||||
case NETOPT_DEVICE_TYPE:
|
||||
assert(len <= sizeof(uint16_t));
|
||||
/* Only LoRa modem is supported for the moment */
|
||||
if (*(const uint16_t *)val == NETDEV_TYPE_LORA) {
|
||||
sx126x_set_pkt_type(dev, SX126X_PKT_TYPE_LORA);
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
case NETOPT_CHANNEL_FREQUENCY:
|
||||
assert(len <= sizeof(uint32_t));
|
||||
sx126x_set_channel(dev, *((const uint32_t *)val));
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_BANDWIDTH:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t bw = *((const uint8_t *)val);
|
||||
if (bw > LORA_BW_500_KHZ) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx126x_set_bandwidth(dev, bw);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SPREADING_FACTOR:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t sf = *((const uint8_t *)val);
|
||||
if ((sf < LORA_SF6) || (sf > SX126X_MAX_SF)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx126x_set_spreading_factor(dev, sf);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_CODING_RATE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t cr = *((const uint8_t *)val);
|
||||
if ((cr < LORA_CR_4_5) || (cr > LORA_CR_4_8)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx126x_set_coding_rate(dev, cr);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_PDU_SIZE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx126x_set_lora_payload_length(dev, *((const uint8_t *)val));
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_INTEGRITY_CHECK:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx126x_set_lora_crc(dev, *((const netopt_enable_t *)val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RX_TIMEOUT:
|
||||
assert(len <= sizeof(uint32_t));
|
||||
dev->rx_timeout = *(const uint32_t *)val;
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_TX_POWER:
|
||||
assert(len <= sizeof(int16_t));
|
||||
int16_t power = *((const int16_t *)val);
|
||||
if ((power < INT8_MIN) || (power > INT8_MAX)) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx126x_set_tx_params(dev, power, SX126X_RAMP_10_US);
|
||||
return sizeof(int16_t);
|
||||
|
||||
case NETOPT_FIXED_HEADER:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx126x_set_lora_implicit_header(dev, *((const netopt_enable_t *)val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_PREAMBLE_LENGTH:
|
||||
assert(len <= sizeof(uint16_t));
|
||||
sx126x_set_lora_preamble_length(dev, *((const uint16_t *)val));
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_SYNCWORD:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx126x_set_lora_sync_word(dev, *((uint8_t *)val));
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_IQ_INVERT:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx126x_set_lora_iq_invert(dev, *((const netopt_enable_t *)val) ? true : false);
|
||||
return sizeof(bool);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
const netdev_driver_t sx126x_driver = {
|
||||
.send = _send,
|
||||
.recv = _recv,
|
||||
.init = _init,
|
||||
.isr = _isr,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
};
|
@ -234,6 +234,12 @@ PSEUDOMODULES += pn532_spi
|
||||
# include variants of sdp3x drivers as pseudo modules
|
||||
PSEUDOMODULES += sdp3x_irq
|
||||
|
||||
# include variants of SX126X drivers and LLCC68 driver as pseudo modules
|
||||
PSEUDOMODULES += sx1261
|
||||
PSEUDOMODULES += sx1262
|
||||
PSEUDOMODULES += sx1268
|
||||
PSEUDOMODULES += llcc68
|
||||
|
||||
# include variants of SX127X drivers as pseudo modules
|
||||
PSEUDOMODULES += sx1272
|
||||
PSEUDOMODULES += sx1276
|
||||
|
@ -7,6 +7,7 @@
|
||||
menu "Packages"
|
||||
|
||||
rsource "driver_bme680/Kconfig"
|
||||
rsource "driver_sx126x/Kconfig"
|
||||
rsource "semtech-loramac/Kconfig"
|
||||
rsource "tinydtls/Kconfig"
|
||||
rsource "umorse/Kconfig"
|
||||
|
20
pkg/driver_sx126x/Kconfig
Normal file
20
pkg/driver_sx126x/Kconfig
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2021 Inria
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
config PACKAGE_DRIVER_SX126X
|
||||
bool "LLCC68 driver package"
|
||||
depends on TEST_KCONFIG
|
||||
depends on HAS_PERIPH_SPI
|
||||
select MODULE_PERIPH_SPI
|
||||
select MODULE_ZTIMER
|
||||
select MODULE_ZTIMER_USEC
|
||||
select MODULE_DRIVER_SX126X_HAL
|
||||
|
||||
config MODULE_DRIVER_SX126X_HAL
|
||||
bool
|
||||
help
|
||||
HAL implementation for the SX126X LoRa radio driver.
|
9
pkg/driver_sx126x/Makefile
Normal file
9
pkg/driver_sx126x/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
PKG_NAME=driver_sx126x
|
||||
PKG_URL=https://github.com/Lora-net/sx126x_driver
|
||||
PKG_VERSION=ba61312213450ae94a4293d75285c1d8f30c04b3
|
||||
PKG_LICENSE=BSD
|
||||
|
||||
include $(RIOTBASE)/pkg/pkg.mk
|
||||
|
||||
all:
|
||||
$(QQ)"$(MAKE)" -C $(PKG_SOURCE_DIR)/src -f $(CURDIR)/$(PKG_NAME).mk
|
7
pkg/driver_sx126x/Makefile.dep
Normal file
7
pkg/driver_sx126x/Makefile.dep
Normal file
@ -0,0 +1,7 @@
|
||||
# module dependencies
|
||||
USEMODULE += driver_sx126x_hal
|
||||
USEMODULE += ztimer
|
||||
USEMODULE += ztimer_usec
|
||||
|
||||
# required features
|
||||
FEATURES_REQUIRED += periph_spi
|
3
pkg/driver_sx126x/Makefile.include
Normal file
3
pkg/driver_sx126x/Makefile.include
Normal file
@ -0,0 +1,3 @@
|
||||
INCLUDES += -I$(PKGDIRBASE)/driver_sx126x/src
|
||||
|
||||
DIRS += $(RIOTBASE)/pkg/driver_sx126x/contrib
|
3
pkg/driver_sx126x/contrib/Makefile
Normal file
3
pkg/driver_sx126x/contrib/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = driver_sx126x_hal
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
98
pkg/driver_sx126x/contrib/driver_sx126x_hal.c
Normal file
98
pkg/driver_sx126x/contrib/driver_sx126x_hal.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup pkg_driver_sx126x
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief HAL implementation for the SX1261/2 LoRa radio driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "ztimer.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_hal.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#define SX126X_SPI_SPEED (SPI_CLK_1MHZ)
|
||||
#define SX126X_SPI_MODE (SPI_MODE_0)
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_write(const void *context,
|
||||
const uint8_t *command, const uint16_t command_length,
|
||||
const uint8_t *data, const uint16_t data_length)
|
||||
{
|
||||
(void)data;
|
||||
(void)data_length;
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, data_length != 0, command, NULL,
|
||||
command_length);
|
||||
if (data_length) {
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, data, NULL, data_length);
|
||||
}
|
||||
spi_release(dev->params->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_read(const void *context,
|
||||
const uint8_t *command, const uint16_t command_length,
|
||||
uint8_t *data, const uint16_t data_length)
|
||||
{
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
/* wait for the device to not be busy anymore */
|
||||
while (gpio_read(dev->params->busy_pin)) {}
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, true, command, NULL, command_length);
|
||||
spi_transfer_bytes(dev->params->spi, dev->params->nss_pin, false, NULL, data, data_length);
|
||||
spi_release(dev->params->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_reset(const void *context)
|
||||
{
|
||||
DEBUG("[sx126x_hal] reset\n");
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
gpio_set(dev->params->reset_pin);
|
||||
gpio_clear(dev->params->reset_pin);
|
||||
/* it takes 100us for the radio to be ready after reset */
|
||||
ztimer_sleep(ZTIMER_USEC, 100);
|
||||
gpio_set(dev->params->reset_pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sx126x_hal_status_t sx126x_hal_wakeup(const void *context)
|
||||
{
|
||||
DEBUG("[sx126x_hal] wakeup\n");
|
||||
sx126x_t *dev = (sx126x_t *)context;
|
||||
|
||||
spi_acquire(dev->params->spi, SPI_CS_UNDEF, SX126X_SPI_MODE, SX126X_SPI_SPEED);
|
||||
gpio_clear(dev->params->nss_pin);
|
||||
gpio_set(dev->params->nss_pin);
|
||||
spi_release(dev->params->spi);
|
||||
|
||||
/* it takes 500us for the radio device to be ready after waking up */
|
||||
ztimer_sleep(ZTIMER_USEC, 500);
|
||||
return 0;
|
||||
}
|
7
pkg/driver_sx126x/doc.txt
Normal file
7
pkg/driver_sx126x/doc.txt
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @defgroup pkg_driver_sx126x SX1261/2 LoRa radio driver
|
||||
* @ingroup pkg
|
||||
* @brief This package is an implementation of the SX1261/2 LoRa radio driver.
|
||||
*
|
||||
* @see https://github.com/Lora-net/sx126x_driver
|
||||
*/
|
3
pkg/driver_sx126x/driver_sx126x.mk
Normal file
3
pkg/driver_sx126x/driver_sx126x.mk
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = driver_sx126x
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
BIN
pkg/driver_sx126x/patches/0001-adapt-to-RIOT.patch
Normal file
BIN
pkg/driver_sx126x/patches/0001-adapt-to-RIOT.patch
Normal file
Binary file not shown.
71
sys/net/gnrc/netif/init_devs/auto_init_sx126x.c
Normal file
71
sys/net/gnrc/netif/init_devs/auto_init_sx126x.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup sys_auto_init_gnrc_netif
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Auto initialization for SX1261/2 LoRa interfaces
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "board.h"
|
||||
#include "net/gnrc/netif/lorawan_base.h"
|
||||
#include "net/gnrc/netif/raw.h"
|
||||
#include "net/gnrc.h"
|
||||
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_params.h"
|
||||
|
||||
/**
|
||||
* @brief Calculate the number of configured SX126X devices
|
||||
*/
|
||||
#define SX126X_NUMOF ARRAY_SIZE(sx126x_params)
|
||||
|
||||
/**
|
||||
* @brief Define stack parameters for the MAC layer thread
|
||||
*/
|
||||
#define SX126X_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
#ifndef SX126X_PRIO
|
||||
#define SX126X_PRIO (GNRC_NETIF_PRIO)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for device descriptors, stacks, and GNRC adaption
|
||||
*/
|
||||
static sx126x_t sx126x_devs[SX126X_NUMOF];
|
||||
static char sx126x_stacks[SX126X_NUMOF][SX126X_STACKSIZE];
|
||||
static gnrc_netif_t _netif[SX126X_NUMOF];
|
||||
|
||||
void auto_init_sx126x(void)
|
||||
{
|
||||
for (unsigned i = 0; i < SX126X_NUMOF; ++i) {
|
||||
LOG_DEBUG("[auto_init_netif] initializing sx126x #%u\n", i);
|
||||
sx126x_setup(&sx126x_devs[i], &sx126x_params[i], i);
|
||||
if (IS_USED(MODULE_GNRC_NETIF_LORAWAN)) {
|
||||
/* Currently only one lora device is supported */
|
||||
assert(SX126X_NUMOF == 1);
|
||||
|
||||
gnrc_netif_lorawan_create(&_netif[i], sx126x_stacks[i],
|
||||
SX126X_STACKSIZE, SX126X_PRIO,
|
||||
"sx126x", (netdev_t *)&sx126x_devs[i]);
|
||||
}
|
||||
else {
|
||||
gnrc_netif_raw_create(&_netif[i], sx126x_stacks[i],
|
||||
SX126X_STACKSIZE, SX126X_PRIO,
|
||||
"sx126x", (netdev_t *)&sx126x_devs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @} */
|
@ -166,4 +166,9 @@ void gnrc_netif_init_devs(void)
|
||||
extern void auto_init_nrf802154(void);
|
||||
auto_init_nrf802154();
|
||||
}
|
||||
|
||||
if (IS_USED(MODULE_SX126X)) {
|
||||
extern void auto_init_sx126x(void);
|
||||
auto_init_sx126x();
|
||||
}
|
||||
}
|
||||
|
10
tests/driver_sx126x/Makefile
Normal file
10
tests/driver_sx126x/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
# other values supported are sx1262, sx1268 and llcc68
|
||||
LORA_DRIVER ?= sx1261
|
||||
USEMODULE += $(LORA_DRIVER)
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
11
tests/driver_sx126x/Makefile.ci
Normal file
11
tests/driver_sx126x/Makefile.ci
Normal file
@ -0,0 +1,11 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-leonardo \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
nucleo-l011k4 \
|
||||
stm32f030f4-demo \
|
||||
samd10-xmini \
|
||||
waspmote-pro \
|
||||
#
|
45
tests/driver_sx126x/README.md
Normal file
45
tests/driver_sx126x/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
sx126x/llcc68 LoRa driver
|
||||
==================
|
||||
|
||||
This is a manual test application for the SX1261/2/8 and LLCC68 LoRa radio driver.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
This application adds a shell command to control basic features radio device:
|
||||
|
||||
```
|
||||
main(): This is RIOT! (Version: 2021.04-devel)
|
||||
Initialization successful - starting the shell now
|
||||
> help
|
||||
help
|
||||
Command Description
|
||||
---------------------------------------
|
||||
sx126x Control the SX126X radio
|
||||
reboot Reboot the node
|
||||
version Prints current RIOT_VERSION
|
||||
pm interact with layered PM subsystem
|
||||
> sx126x
|
||||
sx126x
|
||||
Usage: sx126x <get|set|rx|tx>
|
||||
```
|
||||
|
||||
The `get` and `set` subcommands allows for getting/setting the current
|
||||
frequency channel (freq) and lora modulation parameters (bw, sf, cr).
|
||||
|
||||
To put the device in listen mode, use the `rx` subcommand:
|
||||
|
||||
```
|
||||
> sx126x rx start
|
||||
sx126x rx start
|
||||
Listen mode started
|
||||
```
|
||||
|
||||
To send a message, use the `tx` subcommand:
|
||||
|
||||
```
|
||||
> sx126x tx "This is RIOT!"
|
||||
sx126x tx "This is RIOT!"
|
||||
sending "This is RIOT!" payload (14 bytes)
|
||||
> Transmission completed
|
||||
```
|
7
tests/driver_sx126x/app.config.test
Normal file
7
tests/driver_sx126x/app.config.test
Normal file
@ -0,0 +1,7 @@
|
||||
# this file enables modules defined in Kconfig. Do not use this file for
|
||||
# application configuration. This is only needed during migration.
|
||||
CONFIG_MODULE_SX126X=y
|
||||
CONFIG_PACKAGE_DRIVER_SX126X=y
|
||||
|
||||
CONFIG_MODULE_SHELL=y
|
||||
CONFIG_MODULE_SHELL_COMMANDS=y
|
350
tests/driver_sx126x/main.c
Normal file
350
tests/driver_sx126x/main.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Inria
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for the sx126x/llcc68 radio driver
|
||||
*
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "msg.h"
|
||||
#include "thread.h"
|
||||
#include "shell.h"
|
||||
|
||||
#include "net/lora.h"
|
||||
#include "net/netdev.h"
|
||||
#include "net/netdev/lora.h"
|
||||
|
||||
#include "sx126x.h"
|
||||
#include "sx126x_params.h"
|
||||
#include "sx126x_netdev.h"
|
||||
|
||||
#define SX126X_MSG_QUEUE (8U)
|
||||
#define SX126X_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
#define SX126X_MSG_TYPE_ISR (0x3456)
|
||||
#define SX126X_MAX_PAYLOAD_LEN (128U)
|
||||
|
||||
static char stack[SX126X_STACKSIZE];
|
||||
static kernel_pid_t _recv_pid;
|
||||
|
||||
static char message[SX126X_MAX_PAYLOAD_LEN];
|
||||
|
||||
static sx126x_t sx126x;
|
||||
|
||||
static void _event_cb(netdev_t *dev, netdev_event_t event)
|
||||
{
|
||||
if (event == NETDEV_EVENT_ISR) {
|
||||
msg_t msg;
|
||||
msg.type = SX126X_MSG_TYPE_ISR;
|
||||
if (msg_send(&msg, _recv_pid) <= 0) {
|
||||
puts("sx126x_netdev: possibly lost interrupt.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (event) {
|
||||
case NETDEV_EVENT_RX_STARTED:
|
||||
puts("Data reception started");
|
||||
break;
|
||||
|
||||
case NETDEV_EVENT_RX_COMPLETE:
|
||||
{
|
||||
size_t len = dev->driver->recv(dev, NULL, 0, 0);
|
||||
netdev_lora_rx_info_t packet_info;
|
||||
dev->driver->recv(dev, message, len, &packet_info);
|
||||
printf(
|
||||
"Received: \"%s\" (%d bytes) - [RSSI: %i, SNR: %i, TOA: %" PRIu32 "ms]\n",
|
||||
message, (int)len,
|
||||
packet_info.rssi, (int)packet_info.snr,
|
||||
sx126x_get_lora_time_on_air_in_ms(&sx126x.pkt_params, &sx126x.mod_params)
|
||||
);
|
||||
netopt_state_t state = NETOPT_STATE_RX;
|
||||
dev->driver->set(dev, NETOPT_STATE, &state, sizeof(state));
|
||||
}
|
||||
break;
|
||||
|
||||
case NETDEV_EVENT_TX_COMPLETE:
|
||||
puts("Transmission completed");
|
||||
break;
|
||||
|
||||
case NETDEV_EVENT_TX_TIMEOUT:
|
||||
puts("Transmission timeout");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unexpected netdev event received: %d\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *_recv_thread(void *arg)
|
||||
{
|
||||
netdev_t *netdev = (netdev_t *)arg;
|
||||
|
||||
static msg_t _msg_queue[SX126X_MSG_QUEUE];
|
||||
|
||||
msg_init_queue(_msg_queue, SX126X_MSG_QUEUE);
|
||||
|
||||
while (1) {
|
||||
msg_t msg;
|
||||
msg_receive(&msg);
|
||||
if (msg.type == SX126X_MSG_TYPE_ISR) {
|
||||
netdev->driver->isr(netdev);
|
||||
}
|
||||
else {
|
||||
puts("Unexpected msg type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _get_usage(const char *cmd)
|
||||
{
|
||||
printf("Usage: %s get <type|freq|bw|sf|cr|random>\n", cmd);
|
||||
}
|
||||
|
||||
static int sx126x_get_cmd(netdev_t *netdev, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
_get_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp("type", argv[2])) {
|
||||
uint16_t type;
|
||||
netdev->driver->get(netdev, NETOPT_DEVICE_TYPE, &type, sizeof(uint16_t));
|
||||
printf("Device type: %s\n", (type == NETDEV_TYPE_LORA) ? "lora" : "fsk");
|
||||
}
|
||||
else if (!strcmp("freq", argv[2])) {
|
||||
uint32_t freq;
|
||||
netdev->driver->get(netdev, NETOPT_CHANNEL_FREQUENCY, &freq, sizeof(uint32_t));
|
||||
printf("Frequency: %" PRIu32 "Hz\n", freq);
|
||||
}
|
||||
else if (!strcmp("bw", argv[2])) {
|
||||
uint8_t bw;
|
||||
netdev->driver->get(netdev, NETOPT_BANDWIDTH, &bw, sizeof(uint8_t));
|
||||
uint16_t bw_val = 0;
|
||||
switch (bw) {
|
||||
case LORA_BW_125_KHZ:
|
||||
bw_val = 125;
|
||||
break;
|
||||
case LORA_BW_250_KHZ:
|
||||
bw_val = 250;
|
||||
break;
|
||||
case LORA_BW_500_KHZ:
|
||||
bw_val = 500;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("Bandwidth: %ukHz\n", bw_val);
|
||||
}
|
||||
else if (!strcmp("sf", argv[2])) {
|
||||
uint8_t sf;
|
||||
netdev->driver->get(netdev, NETOPT_SPREADING_FACTOR, &sf, sizeof(uint8_t));
|
||||
printf("Spreading factor: %d\n", sf);
|
||||
}
|
||||
else if (!strcmp("cr", argv[2])) {
|
||||
uint8_t cr;
|
||||
netdev->driver->get(netdev, NETOPT_CODING_RATE, &cr, sizeof(uint8_t));
|
||||
printf("Coding rate: %d\n", cr);
|
||||
}
|
||||
else if (!strcmp("random", argv[2])) {
|
||||
uint32_t rand;
|
||||
netdev->driver->get(netdev, NETOPT_RANDOM, &rand, sizeof(uint32_t));
|
||||
printf("random number: %" PRIu32 "\n", rand);
|
||||
}
|
||||
else {
|
||||
_get_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _set_usage(const char *cmd)
|
||||
{
|
||||
printf("Usage: %s set <freq|bw|sf|cr> <value>\n", cmd);
|
||||
}
|
||||
|
||||
static int sx126x_set_cmd(netdev_t *netdev, int argc, char **argv)
|
||||
{
|
||||
if (argc != 4) {
|
||||
_set_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (!strcmp("freq", argv[2])) {
|
||||
uint32_t freq = atoi(argv[3]);
|
||||
ret = netdev->driver->set(netdev, NETOPT_CHANNEL_FREQUENCY, &freq, sizeof(uint32_t));
|
||||
}
|
||||
else if (!strcmp("bw", argv[2])) {
|
||||
uint8_t bw;
|
||||
if (!strcmp("125", argv[3])) {
|
||||
bw = LORA_BW_125_KHZ;
|
||||
}
|
||||
else if (!strcmp("250", argv[3])) {
|
||||
bw = LORA_BW_250_KHZ;
|
||||
}
|
||||
else if (!strcmp("500", argv[3])) {
|
||||
bw = LORA_BW_500_KHZ;
|
||||
}
|
||||
else {
|
||||
puts("invalid bandwidth, use 125, 250 or 500");
|
||||
return -1;
|
||||
}
|
||||
ret = netdev->driver->set(netdev, NETOPT_BANDWIDTH, &bw, sizeof(uint8_t));
|
||||
}
|
||||
else if (!strcmp("sf", argv[2])) {
|
||||
uint8_t sf = atoi(argv[3]);
|
||||
ret = netdev->driver->set(netdev, NETOPT_SPREADING_FACTOR, &sf, sizeof(uint8_t));
|
||||
}
|
||||
else if (!strcmp("cr", argv[2])) {
|
||||
uint8_t cr = atoi(argv[3]);
|
||||
ret = netdev->driver->set(netdev, NETOPT_CODING_RATE, &cr, sizeof(uint8_t));
|
||||
}
|
||||
else {
|
||||
_set_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
printf("cannot set %s\n", argv[2]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("%s set\n", argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _rx_usage(const char *cmd)
|
||||
{
|
||||
printf("Usage: %s rx <start|stop>\n", cmd);
|
||||
}
|
||||
|
||||
static int sx126x_rx_cmd(netdev_t *netdev, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
_rx_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp("start", argv[2])) {
|
||||
/* Switch to RX state */
|
||||
netopt_state_t state = NETOPT_STATE_IDLE;
|
||||
netdev->driver->set(netdev, NETOPT_STATE, &state, sizeof(state));
|
||||
printf("Listen mode started\n");
|
||||
}
|
||||
else if (!strcmp("stop", argv[2])) {
|
||||
/* Switch to RX state */
|
||||
netopt_state_t state = NETOPT_STATE_STANDBY;
|
||||
netdev->driver->set(netdev, NETOPT_STATE, &state, sizeof(state));
|
||||
printf("Listen mode stopped\n");
|
||||
}
|
||||
else {
|
||||
_rx_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sx126x_tx_cmd(netdev_t *netdev, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
printf("Usage: %s tx <payload>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("sending \"%s\" payload (%u bytes)\n",
|
||||
argv[2], (unsigned)strlen(argv[2]) + 1);
|
||||
iolist_t iolist = {
|
||||
.iol_base = argv[2],
|
||||
.iol_len = (strlen(argv[2]) + 1)
|
||||
};
|
||||
|
||||
if (netdev->driver->send(netdev, &iolist) == -ENOTSUP) {
|
||||
puts("Cannot send: radio is still transmitting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sx126x_cmd(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <get|set|rx|tx>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
netdev_t *netdev = (netdev_t *)&sx126x;
|
||||
|
||||
if (!strcmp("get", argv[1])) {
|
||||
return sx126x_get_cmd(netdev, argc, argv);
|
||||
}
|
||||
else if (!strcmp("set", argv[1])) {
|
||||
return sx126x_set_cmd(netdev, argc, argv);
|
||||
}
|
||||
else if (!strcmp("rx", argv[1])) {
|
||||
return sx126x_rx_cmd(netdev, argc, argv);
|
||||
}
|
||||
else if (!strcmp("tx", argv[1])) {
|
||||
return sx126x_tx_cmd(netdev, argc, argv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "sx126x", "Control the SX126X radio", sx126x_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sx126x_setup(&sx126x, &sx126x_params[0], 0);
|
||||
netdev_t *netdev = (netdev_t *)&sx126x;
|
||||
|
||||
netdev->driver = &sx126x_driver;
|
||||
|
||||
if (netdev->driver->init(netdev) < 0) {
|
||||
puts("Failed to initialize SX126X device, exiting");
|
||||
return 1;
|
||||
}
|
||||
|
||||
netdev->event_callback = _event_cb;
|
||||
|
||||
_recv_pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST, _recv_thread, netdev,
|
||||
"recv_thread");
|
||||
|
||||
if (_recv_pid <= KERNEL_PID_UNDEF) {
|
||||
puts("Creation of receiver thread failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start the shell */
|
||||
puts("Initialization successful - starting the shell now");
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user