1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #18033 from thingsat/pr/sx1280_v2

drivers/sx1280: add driver for SX1280 transceiver v2
This commit is contained in:
Francisco 2022-05-18 22:10:38 +02:00 committed by GitHub
commit 37da85f047
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2233 additions and 3 deletions

View File

@ -21,5 +21,6 @@ rsource "slipdev/Kconfig"
rsource "$(RIOTCPU)/native/socket_zep/Kconfig"
rsource "sx126x/Kconfig"
rsource "sx127x/Kconfig"
rsource "sx1280/Kconfig"
rsource "tja1042/Kconfig"
endmenu # Network Device Drivers

View File

@ -320,6 +320,7 @@ typedef enum {
NETDEV_NRF24L01P_NG,
NETDEV_SOCKET_ZEP,
NETDEV_SX126X,
NETDEV_SX1280,
NETDEV_CC2420,
NETDEV_ETHOS,
NETDEV_SLIPDEV,

267
drivers/include/sx1280.h Normal file
View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280 LoRa radio driver
* @ingroup drivers_netdev
* @brief Driver for the sx1280 LoRa radio device
*
* @{
*
* @file
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
*/
#ifndef SX1280_H
#define SX1280_H
#include <assert.h>
#include "sx1280_driver/src/sx1280_hal.h"
#include "sx1280_driver/src/sx1280.h"
#include "smtc_ral/src/ral.h"
#include "smtc_ral/src/ral_defs.h"
#include "net/netdev.h"
#include "periph/gpio.h"
#include "periph/spi.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name SX1280 device default configuration
* @{
*/
#define SX1280_CHANNEL_DEFAULT (2403000000UL) /**< Default channel frequency, 2403MHz */
#define SX1280_RADIO_TX_POWER (SX1280_PWR_MAX) /**< Radio power in dBm */
/** @} */
/**
* * @note Forward declaration of the sx1280 device descriptor
*/
typedef struct sx1280 sx1280_t;
/**
* @brief Device initialization parameters
*/
typedef struct {
spi_t spi; /**< SPI device */
spi_mode_t spi_mode; /**< SPI mode */
spi_clk_t spi_clk; /**< SPI clk */
gpio_t nss_pin; /**< SPI NSS pin */
gpio_t reset_pin; /**< Reset pin */
gpio_t busy_pin; /**< Busy pin */
gpio_t dio0_pin; /**< Dio0 pin */
gpio_t dio1_pin; /**< Dio1 pin */
sx1280_reg_mod_t regulator; /**< Power regulator mode */
} sx1280_params_t;
/**
* @brief Device descriptor for the driver
*/
struct sx1280 {
netdev_t netdev; /**< Netdev parent struct */
ral_t ral; /**< Radio abstraction */
ral_params_lora_t ral_params_lora; /**< LoRa modulation parameters */
sx1280_params_t *params; /**< Initialization parameters */
sx1280_hal_operating_mode_t mode; /**< Operating Mode */
};
/**
* @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 sx1280_setup(sx1280_t *dev, const sx1280_params_t *params, uint8_t index);
/**
* @brief Initialize the given device
*
* @param[inout] dev Device descriptor of the driver
*
* @return 0 on success
*/
int sx1280_init(sx1280_t *dev);
/**
* @brief Gets the channel RF frequency.
*
* @param[in] dev Device descriptor of the driver
*
* @return The channel frequency
*/
uint32_t sx1280_get_channel(const sx1280_t *dev);
/**
* @brief Gets a random number
*
* @param[in] dev Device descriptor of the driver
*
* @return a random number
*/
uint32_t sx1280_random(const sx1280_t *dev);
/**
* @brief Sets the channel RF frequency.
*
* @param[in] dev Device descriptor of the driver
* @param[in] freq Channel RF frequency
*/
void sx1280_set_channel(sx1280_t *dev, uint32_t freq);
/**
* @brief Gets the LoRa bandwidth
*
* @param[in] dev Device descriptor of the driver
*
* @return the bandwidth
*/
uint32_t sx1280_get_bandwidth(const sx1280_t *dev);
/**
* @brief Sets the LoRa bandwidth
*
* @param[in] dev Device descriptor of the driver
* @param[in] bandwidth The new bandwidth
*/
void sx1280_set_bandwidth(sx1280_t *dev, uint16_t bandwidth);
/**
* @brief Gets the LoRa spreading factor
*
* @param[in] dev Device descriptor of the driver
*
* @return the spreading factor
*/
uint8_t sx1280_get_spreading_factor(const sx1280_t *dev);
/**
* @brief Sets the LoRa spreading factor
*
* @param[in] dev Device descriptor of the driver
* @param[in] sf The spreading factor
*/
void sx1280_set_spreading_factor(sx1280_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 sx1280_get_coding_rate(const sx1280_t *dev);
/**
* @brief Sets the LoRa coding rate
*
* @param[in] dev Device descriptor of the driver
* @param[in] cr The LoRa coding rate
*/
void sx1280_set_coding_rate(sx1280_t *dev, uint8_t cr);
/**
* @brief Gets the payload length
*
* @param[in] dev Device descriptor of the driver
*
* @return the payload length
*/
uint8_t sx1280_get_lora_payload_length(const sx1280_t *dev);
/**
* @brief Sets the payload length
*
* @param[in] dev Device descriptor of the driver
* @param[in] len The payload len
*/
void sx1280_set_lora_payload_length(sx1280_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 sx1280_get_lora_crc(const sx1280_t *dev);
/**
* @brief Enable/Disable CRC verification mode
*
* @param[in] dev Device descriptor of the driver
* @param[in] crc The CRC check mode
*/
void sx1280_set_lora_crc(sx1280_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 sx1280_get_lora_implicit_header(const sx1280_t *dev);
/**
* @brief Sets LoRa implicit header mode
*
* @param[in] dev Device descriptor of the driver
* @param[in] mode The header mode
*/
void sx1280_set_lora_implicit_header(sx1280_t *dev, bool mode);
/**
* @brief Gets the LoRa preamble length
*
* @param[in] dev Device descriptor of the driver
*
* @return the preamble length
*/
uint16_t sx1280_get_lora_preamble_length(const sx1280_t *dev);
/**
* @brief Sets the LoRa preamble length
*
* @param[in] dev Device descriptor of the driver
* @param[in] preamble The LoRa preamble length
*/
void sx1280_set_lora_preamble_length(sx1280_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 sx1280_get_lora_iq_invert(const sx1280_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 sx1280_set_lora_iq_invert(sx1280_t *dev, bool iq_invert);
#ifdef __cplusplus
}
#endif
#endif /* SX1280_H */
/** @} */

17
drivers/sx1280/Kconfig Normal file
View File

@ -0,0 +1,17 @@
# Copyright (c) 2022 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_SX1280
bool "LoRa 2.4Ghz SX1280 Driver" if !(HAVE_SX1280 && MODULE_NETDEV_DEFAULT)
default y if (HAVE_SX1280 && MODULE_NETDEV_DEFAULT)
depends on TEST_KCONFIG
select PACKAGE_LORABASICS
select MODULE_LORABASICS_SX1280_DRIVER
config HAVE_SX1280
bool
help
Indicates that an sx1280 2.4Ghz transceiver is present.

1
drivers/sx1280/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,2 @@
USEPKG += lorabasics
USEMODULE += lorabasics_sx1280_driver

View File

@ -0,0 +1,7 @@
USEMODULE_INCLUDES_sx1280 := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_sx1280)
# Overide defaults see See https://lora-developers.semtech.com/documentation/tech-papers-and-guides/physical-layer-proposal-2.4ghz/
CFLAGS += -DCONFIG_LORA_BW_DEFAULT_800=1
CFLAGS += -DCONFIG_LORA_SF_DEFAULT_SF12=1
CFLAGS += -DCONFIG_LORA_CR_DEFAULT_CR_LI_4_8=1

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280
* @{
*
* @file
* @brief Internal addresses, registers and constants
*
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
*/
#ifndef SX1280_CONSTANTS_H
#define SX1280_CONSTANTS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SX1280 Single RX mode.
*
* sx1280_set_rx constant to be in single mode
*
* There is a known issue about this in some circonstances described in section 16.1 of the datasheet:
* https://manualzz.com/doc/55353537/semtech-sx1280-2.4-ghz-transceiver-datasheet
*
* When subjected to a high co-channel traffic conditions
* (for example in BLE mode when the SX1280 receives more than 220 packets per second)
* and only when configured in continuous receiver
* The SX1280 busy line will remain high and the radio unresponsive.
*
* If the radio may be subject to high levels of BLE traffic, to allow the radio to remain in operation RX single mode must be used
*/
#define SX1280_RX_SINGLE_MODE 0x0000
/**
* @brief SX1280 Continuous RX mode.
*
* @note This addresses a known issue detailed in section 16.1 of the datasheet, see
* @ref SX1280_RX_SINGLE_MODE for more details.
*
* sx1280_set_rx require this constant to be in continuous mode
*
*/
#define SX1280_RX_CONTINUOUS_MODE 0xFFFF
/**
* @brief SX1280 wakeup time in ms
* @note From the datasheet wakeup time is usually 1200us but rounded up to 2 to only use the ZTIMER_MSEC
*
*/
#define SX1280_WAKEUP_TIME_MS 2
/**
* @brief SX1280 reset time in ms
* hold NRST pin low for 1ms, nothing is specified in the datasheet, 1ms worked fine
*
*/
#define SX1280_RESET_MS 1
#ifdef __cplusplus
}
#endif
#endif /* SX1280_CONSTANTS_H */
/** @} */

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280
* @{
* @file
* @brief Netdev driver definitions for LoRa SX1280 Driver driver
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
*/
#ifndef SX1280_NETDEV_H
#define SX1280_NETDEV_H
#include "net/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t sx1280_driver;
#ifdef __cplusplus
}
#endif
#endif /* SX1280_NETDEV_H */
/** @} */

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280
* @{
* @file
* @brief Default configuration
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
*/
#ifndef SX1280_PARAMS_H
#define SX1280_PARAMS_H
#include "board.h"
#include "sx1280.h"
#include "sx1280_constants.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters
*
* Default values are adapted for mbed shield used with to nucleo64 boards
* @see https://github.com/donsez/RIOT/blob/pr/sx1280/drivers/sx1280/include/sx1280_hal.h
* @see 'board/commun/nucleo64/include/arduino_pinmap.h'
*
* ARDUINO_PIN_10 -> GPIO_PIN(PORT_B, 6) -> GPIO_PIN(1, 6)
* ARDUINO_PIN_7 -> GPIO_PIN(PORT_A, 8) -> GPIO_PIN(0, 8)
* ARDUINO_PIN_6 -> GPIO_PIN(PORT_B, 10) -> GPIO_PIN(1, 10)
* ARDUINO_PIN_9 -> GPIO_PIN(PORT_C, 7) -> GPIO_PIN(2, 7)
*
* @{
*/
#ifndef USE_RX_CONTINUOUS_MODE
#define USE_RX_CONTINUOUS_MODE /**< default RX MODE */
#endif
#ifdef USE_RX_CONTINUOUS_MODE
#define SX1280_RX_MODE SX1280_RX_CONTINUOUS_MODE /**< continuous RX MODE */
#else
#define SX1280_RX_MODE SX1280_RX_SINGLE_MODE /**< single RX MODE */
#endif
#ifndef SX1280_PARAM_SPI
#define SX1280_PARAM_SPI SPI_DEV(0) /**< default SPI device */
#endif
#ifndef SX1280_PARAM_SPI_CLK
#define SX1280_PARAM_SPI_CLK SPI_CLK_5MHZ /**< default SPI speed */
#endif
#ifndef SX1280_PARAM_SPI_MODE
#define SX1280_PARAM_SPI_MODE SPI_MODE_0 /**< default SPI mode for sx1280 */
#endif
#ifndef SX1280_PARAM_SPI_NSS
#define SX1280_PARAM_SPI_NSS GPIO_PIN(1, 6) /**< SPI NSS pin */
#endif
#ifndef SX1280_PARAM_RESET
#define SX1280_PARAM_RESET GPIO_PIN(0, 8) /**< Reset pin */
#endif
#ifndef SX1280_PARAM_DIO0
#define SX1280_PARAM_DIO0 GPIO_PIN(1, 10) /**< DIO0 */
#endif
#ifndef SX1280_PARAM_DIO1
#define SX1280_PARAM_DIO1 GPIO_PIN(2, 7) /**< DIO1 */
#endif
/**
* @brief Default sx1280 parameters
*/
#define SX1280_PARAMS { .spi = SX1280_PARAM_SPI, \
.spi_mode = SX1280_PARAM_SPI_MODE, \
.spi_clk = SX1280_PARAM_SPI_CLK, \
.nss_pin = SX1280_PARAM_SPI_NSS, \
.reset_pin = SX1280_PARAM_RESET, \
.dio0_pin = SX1280_PARAM_DIO0, \
.dio1_pin = SX1280_PARAM_DIO1, \
}
/**@}*/
/**
* @brief Configuration struct
*/
static const sx1280_params_t sx1280_params[] =
{
SX1280_PARAMS
};
#ifdef __cplusplus
}
#endif
#endif /* SX1280_PARAMS_H */
/** @} */

406
drivers/sx1280/sx1280.c Normal file
View File

@ -0,0 +1,406 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280
* @{
* @file
* @brief Device driver implementation for the LoRa SX1280 Driver
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
* @}
*/
#include <string.h>
#include "ztimer.h"
#include "sx1280_driver/src/sx1280.h"
#include "sx1280_driver/src/sx1280_regs.h"
#include "smtc_ral/src/ral_sx1280.h"
#include "sx1280.h"
#include "sx1280_constants.h"
#include "sx1280_params.h"
#include "sx1280_netdev.h"
#include "net/lora.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static ral_lora_bw_t _lora_bw_to_ral_bw(int bw)
{
switch (bw) {
case LORA_BW_125_KHZ:
return RAL_LORA_BW_125_KHZ;
case LORA_BW_200_KHZ:
return RAL_LORA_BW_200_KHZ;
case LORA_BW_250_KHZ:
return RAL_LORA_BW_250_KHZ;
case LORA_BW_400_KHZ:
return RAL_LORA_BW_400_KHZ;
case LORA_BW_500_KHZ:
return RAL_LORA_BW_500_KHZ;
case LORA_BW_800_KHZ:
return RAL_LORA_BW_800_KHZ;
case LORA_BW_1600_KHZ:
return RAL_LORA_BW_1600_KHZ;
default:
return -1;
}
}
static ral_lora_sf_t _lora_sf_to_ral_sf(int sf)
{
return (ral_lora_sf_t)sf;
}
static ral_lora_cr_t _lora_cr_to_ral_cr(int cr)
{
switch (cr) {
case LORA_CR_4_5:
return RAL_LORA_CR_4_5;
case LORA_CR_4_6:
return RAL_LORA_CR_4_6;
case LORA_CR_4_7:
return RAL_LORA_CR_4_7;
case LORA_CR_4_8:
return RAL_LORA_CR_4_8;
case LORA_CR_LI_4_5:
return RAL_LORA_CR_LI_4_5;
case LORA_CR_LI_4_6:
return RAL_LORA_CR_LI_4_6;
case LORA_CR_LI_4_8:
return RAL_LORA_CR_LI_4_8;
default:
return -1;
}
}
static int _ral_lora_cr_to_lora_cr(int cr)
{
switch (cr) {
case RAL_LORA_CR_4_5:
return LORA_CR_4_5;
case RAL_LORA_CR_4_6:
return LORA_CR_4_6;
case RAL_LORA_CR_4_7:
return LORA_CR_4_7;
case RAL_LORA_CR_4_8:
return LORA_CR_4_8;
case RAL_LORA_CR_LI_4_5:
return LORA_CR_LI_4_5;
case RAL_LORA_CR_LI_4_6:
return LORA_CR_LI_4_6;
case RAL_LORA_CR_LI_4_8:
return LORA_CR_LI_4_8;
default:
return -1;
}
}
static uint32_t _get_bw(ral_lora_bw_t lora_bw)
{
switch (lora_bw) {
case RAL_LORA_BW_007_KHZ:
return (uint32_t)7000;
case RAL_LORA_BW_010_KHZ:
return (uint32_t)10000;
case RAL_LORA_BW_015_KHZ:
return (uint32_t)15000;
case RAL_LORA_BW_020_KHZ:
return (uint32_t)20000;
case RAL_LORA_BW_031_KHZ:
return (uint32_t)31000;
case RAL_LORA_BW_041_KHZ:
return (uint32_t)41000;
case RAL_LORA_BW_062_KHZ:
return (uint32_t)62000;
case RAL_LORA_BW_125_KHZ:
return (uint32_t)125000;
case RAL_LORA_BW_200_KHZ:
return (uint32_t)200000;
case RAL_LORA_BW_250_KHZ:
return (uint32_t)250000;
case RAL_LORA_BW_400_KHZ:
return (uint32_t)400000;
case RAL_LORA_BW_500_KHZ:
return (uint32_t)500000;
case RAL_LORA_BW_800_KHZ:
return (uint32_t)800000;
case RAL_LORA_BW_1600_KHZ:
return (uint32_t)1600000;
default:
return 0;
}
}
static void _dio1_isr(void *arg)
{
netdev_trigger_event_isr(arg);
}
static int enable_irq(const sx1280_t *dev)
{
const uint16_t irq_mask = (
SX1280_IRQ_TX_DONE |
SX1280_IRQ_RX_DONE |
SX1280_IRQ_PBL_DET |
SX1280_IRQ_HEADER_VALID |
SX1280_IRQ_HEADER_ERROR |
SX1280_IRQ_CAD_DONE |
SX1280_IRQ_CAD_DET |
SX1280_IRQ_TIMEOUT
);
int res = sx1280_set_dio_irq_params(dev, irq_mask, irq_mask, SX1280_IRQ_NONE, SX1280_IRQ_NONE);
return res;
}
void sx1280_setup(sx1280_t *dev, const sx1280_params_t *params, uint8_t index)
{
dev->ral.context = dev;
dev->ral.radio_type = RAL_RADIO_SX1280;
dev->ral.tcxo_cfg.tcxo_ctrl_mode = RAL_TCXO_NONE;
netdev_t *netdev = &dev->netdev;
netdev->driver = &sx1280_driver;
dev->params = (sx1280_params_t *)params;
netdev_register(&dev->netdev, NETDEV_SX1280, index);
}
static uint32_t sx1280_init_default_config(sx1280_t *dev)
{
/* default parameters */
const ral_params_lora_t params_default = {
.freq_in_hz = SX1280_CHANNEL_DEFAULT,
.sf = _lora_sf_to_ral_sf(CONFIG_LORA_SF_DEFAULT),
.bw = _lora_bw_to_ral_bw(CONFIG_LORA_BW_DEFAULT),
.cr = _lora_cr_to_ral_cr(CONFIG_LORA_CR_DEFAULT),
.pbl_len_in_symb = CONFIG_LORA_PREAMBLE_LENGTH_DEFAULT,
.sync_word = LORA_SYNCWORD_ISM2400_PUBLIC,
.pld_is_fix = false,
.crc_is_on = true,
.invert_iq_is_on = false,
.symb_nb_timeout = 0,
.pwr_in_dbm = SX1280_RADIO_TX_POWER,
};
/* set current ral_params */
dev->ral_params_lora = params_default;
ral_status_t res = ral_sx1280_setup_lora(&dev->ral, &params_default);
if (res != RAL_STATUS_OK) {
DEBUG("[sx1280] init: ERROR failed LoRa setup, %d\n", res);
return -EIO;
}
return 0;
}
int sx1280_init(sx1280_t *dev)
{
/* Setup SPI for SX1280 */
int res = spi_init_cs(dev->params->spi, dev->params->nss_pin);
if (res != SPI_OK) {
DEBUG("[sx1280] error: failed to initialize SPI_%i device (code %i)\n",
dev->params->spi, res);
return -1;
}
DEBUG("[sx1280] init: SPI_%i initialized with success\n", dev->params->spi);
/* Initialize Reset */
if (gpio_init(dev->params->reset_pin, GPIO_OUT) < 0) {
DEBUG("[sx1280] error: failed to initialize RESET pin\n");
return -EIO;
}
/* Initialize DIO0s */
if (gpio_init(dev->params->dio0_pin, GPIO_IN) < 0) {
DEBUG("[sx1280] error: failed to initialize DIO1 pin\n");
return -EIO;
}
/* Initialize DI01s */
if (gpio_init_int(dev->params->dio1_pin, GPIO_IN, GPIO_RISING, _dio1_isr, dev)) {
DEBUG("[sx1280] error: failed to initialize DIO1 pin\n");
return -EIO;
}
/* sx1280_reset() and sx1280_set_reg_mode() set in ral_sx1280_init */
res = ral_sx1280_init(&dev->ral);
if (res == RAL_STATUS_OK) {
uint16_t fwid;
ral_sx1280_read_register(&dev->ral, SX1280_REG_FW_VERSION, (uint8_t *)&fwid, 2);
if (fwid == 0x5853) {
DEBUG("[sx1280]: firmware version = %x\n", fwid);
}
else {
DEBUG("[sx1280] error: firmware version = %x\n", fwid);
return -EIO;
}
}
sx1280_init_default_config(dev);
res = enable_irq(dev);
if (res != SX1280_STATUS_OK) {
DEBUG("[sx1280] init: ERROR failed irq setup, %d\n", res);
return -EIO;
}
sx1280_set_lna_settings(dev, SX1280_LNA_HIGH_SENSITIVITY_MODE);
return 0;
}
uint32_t sx1280_get_channel(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_channel\n");
return dev->ral_params_lora.freq_in_hz;
}
void sx1280_set_channel(sx1280_t *dev, uint32_t freq)
{
DEBUG("[sx1280]: sx1280_set_channel %" PRIu32 "Hz\n", freq);
dev->ral_params_lora.freq_in_hz = freq;
sx1280_set_rf_freq(dev, dev->ral_params_lora.freq_in_hz);
}
uint32_t sx1280_get_bandwidth(const sx1280_t *dev)
{
return _get_bw(dev->ral_params_lora.bw);
}
void sx1280_set_bandwidth(sx1280_t *dev, uint16_t bandwidth)
{
DEBUG("[sx1280]: sx1280_set_bandwidth (KHz)\n");
switch (bandwidth) {
case 200:
puts("setup: setting 200KHz bandwidth");
dev->ral_params_lora.bw = RAL_LORA_BW_200_KHZ;
break;
case 400:
puts("setup: setting 400KHz bandwidth");
dev->ral_params_lora.bw = RAL_LORA_BW_400_KHZ;
break;
case 800:
puts("setup: setting 800KHz bandwidth");
dev->ral_params_lora.bw = RAL_LORA_BW_800_KHZ;
break;
case 1600:
puts("setup: setting 1600KHz bandwidth");
dev->ral_params_lora.bw = RAL_LORA_BW_1600_KHZ;
break;
/* assume caller function check the validity of the value so should never go here */
default:
puts("[Error] setup: invalid bandwidth value given, "
"only 200, 400, 800 or 1600 allowed.");
return;
}
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
uint8_t sx1280_get_spreading_factor(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_spreading_factor\n");
/* no conversion needed */
return dev->ral_params_lora.sf;
}
void sx1280_set_spreading_factor(sx1280_t *dev, uint8_t sf)
{
DEBUG("[sx1280]: sx1280_set_spreading_factor\n");
dev->ral_params_lora.sf = sf;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
uint8_t sx1280_get_coding_rate(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_coding_rate\n");
return _ral_lora_cr_to_lora_cr(dev->ral_params_lora.cr);
}
void sx1280_set_coding_rate(sx1280_t *dev, uint8_t cr)
{
DEBUG("[sx1280]: sx1280_set_coding_rate\n");
dev->ral_params_lora.cr = cr;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
uint8_t sx1280_get_lora_payload_length(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_lora_payload_length\n");
sx1280_rx_buffer_status_t rx_buffer_status;
sx1280_get_rx_buffer_status(dev, &rx_buffer_status);
return rx_buffer_status.pld_len_in_bytes;
}
void sx1280_set_lora_payload_length(sx1280_t *dev, uint8_t len)
{
DEBUG("[sx1280]: sx1280_set_lora_payload_length\n");
dev->ral_params_lora.pld_len_in_bytes = len;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
bool sx1280_get_lora_crc(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_lora_crc\n");
return dev->ral_params_lora.crc_is_on;
}
void sx1280_set_lora_crc(sx1280_t *dev, bool crc)
{
DEBUG("[sx1280]: sx1280_set_lora_crc\n");
dev->ral_params_lora.crc_is_on = crc;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
bool sx1280_get_lora_implicit_header(const sx1280_t *dev)
{
(void)dev;
DEBUG("[sx1280]: sx1280_get_lora_implicit_header not implemented \n");
return false;
}
void sx1280_set_lora_implicit_header(sx1280_t *dev, bool mode)
{
(void)dev;
DEBUG("[sx1280]: sx1280_set_lora_implicit_header not implemented %d\n", mode);
}
uint16_t sx1280_get_lora_preamble_length(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_lora_preamble_length\n");
return dev->ral_params_lora.pbl_len_in_symb;
}
void sx1280_set_lora_preamble_length(sx1280_t *dev, uint16_t preamble)
{
DEBUG("[sx1280]: sx1280_set_lora_preamble_length\n");
dev->ral_params_lora.pbl_len_in_symb = preamble;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}
bool sx1280_get_lora_iq_invert(const sx1280_t *dev)
{
DEBUG("[sx1280]: sx1280_get_lora_iq_invert\n");
return dev->ral_params_lora.invert_iq_is_on;
}
void sx1280_set_lora_iq_invert(sx1280_t *dev, bool iq_invert)
{
DEBUG("[sx1280]: sx1280_set_lora_iq_invert\n");
dev->ral_params_lora.invert_iq_is_on = iq_invert;
ral_sx1280_setup_lora(&dev->ral, &dev->ral_params_lora);
}

View File

@ -0,0 +1,458 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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_sx1280
* @{
* @file
* @brief Netdev adaptation for the LoRa SX1280 Driver driver
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.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 "sx1280.h"
#include "sx1280_params.h"
#include "sx1280_netdev.h"
#include "sx1280_driver/src/sx1280.h"
#include "smtc_ral/src/ral_defs.h"
#include "smtc_ral/src/ral_sx1280.h"
#define ENABLE_DEBUG 0
#include "debug.h"
static int _send(netdev_t *netdev, const iolist_t *iolist)
{
sx1280_t *dev = (sx1280_t *)netdev;
netopt_state_t state;
netdev->driver->get(netdev, NETOPT_STATE, &state, sizeof(netopt_state_t));
if (state == NETOPT_STATE_TX) {
DEBUG("[sx1280] netdev: cannot send packet, radio is already transmitting.\n");
return -ENOTSUP;
}
else {
DEBUG("[sx1280] netdev: can send packet\n");
}
size_t pos = 0;
/* Write payload buffer */
for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (iol->iol_len > 0) {
/* write data to payload buffer */
sx1280_write_buffer(dev, pos, iol->iol_base, iol->iol_len);
DEBUG("[sx1280] netdev: send: wrote data to payload buffer.\n");
pos += iol->iol_len;
}
}
/* Ignore send if packet size is 0 */
if (!pos) {
return 0;
}
DEBUG("[sx1280] netdev: sending packet now (size: %d).\n", pos);
sx1280_set_lora_payload_length(dev, pos);
state = NETOPT_STATE_TX;
netdev->driver->set(netdev, NETOPT_STATE, &state, sizeof(state));
DEBUG("[sx1280] netdev: send: transmission in progress.\n");
return 0;
}
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
{
DEBUG("[sx1280] netdev: read received data.\n");
sx1280_t *dev = (sx1280_t *)netdev;
uint8_t size = 0;
/* Get received packet info and size here */
netdev_lora_rx_info_t *packet_info = info;
if (packet_info) {
sx1280_pkt_status_lora_t pkt_status;
sx1280_get_lora_pkt_status(dev, &pkt_status);
packet_info->snr = pkt_status.snr;
packet_info->rssi = pkt_status.rssi;
}
sx1280_rx_buffer_status_t rx_buffer_status;
sx1280_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;
}
/* Read the received packet content here and write it to buf */
sx1280_read_buffer(dev, rx_buffer_status.buffer_start_pointer, buf, size);
/* RX SINGLE MODE */
if (sx1280_hal_get_operating_mode(&dev) == SX1280_HAL_OP_MODE_RX) {
DEBUG("[sx1280] netdev stop RX single mode" );
netopt_state_t state = NETOPT_STATE_IDLE;
dev->netdev.driver->set(&dev->netdev, NETOPT_STATE, &state, sizeof(state));
return 0;
/* RX CONTINUOUS MODE */
}
else if (sx1280_hal_get_operating_mode(&dev) == SX1280_HAL_OP_MODE_RX_C) {
DEBUG("[sx1280] netdev keep RX continuous mode" );
netopt_state_t state = NETOPT_STATE_RX;
dev->netdev.driver->set(&dev->netdev, NETOPT_STATE, &state, sizeof(state));
return size;
}
else {
DEBUG("[sx1280] netdev NOT IMPLEMENTED");
return 0;
}
}
static int _init(netdev_t *netdev)
{
sx1280_t *dev = (sx1280_t *)netdev;
/* Launch initialization of driver and device */
DEBUG("[sx1280] netdev: initializing driver...\n");
if (sx1280_init(dev) != 0) {
DEBUG("[sx1280] netdev: initialization failed\n");
return -1;
}
DEBUG("[sx1280] netdev: initialization successful\n");
return 0;
}
static void _isr(netdev_t *netdev)
{
sx1280_t *dev = (sx1280_t *)netdev;
sx1280_irq_mask_t irq_mask;
ral_sx1280_get_and_clear_irq_status(&dev->ral, &irq_mask);
if (irq_mask & RAL_IRQ_RX_DONE) {
if (irq_mask & RAL_IRQ_RX_CRC_ERROR) {
DEBUG("[sx1280] netdev: SX1280_IRQ_CRC_ERROR\n");
netdev->event_callback(netdev, NETDEV_EVENT_CRC_ERROR);
}
else {
DEBUG("[sx1280] netdev: SX1280_IRQ_RX_DONE\n");
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
}
}
else if (irq_mask & RAL_IRQ_TX_DONE) {
DEBUG("[sx1280] netdev: SX1280_IRQ_TX_DONE\n");
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
}
else if (irq_mask & RAL_IRQ_RX_HDR_OK) {
DEBUG("[sx1280] netdev: SX1280_IRQ_HEADER_VALID\n");
netdev->event_callback(netdev, NETDEV_EVENT_RX_STARTED);
}
else if (irq_mask & RAL_IRQ_RX_HDR_ERROR) {
DEBUG("[sx1280] netdev: SX1280_IRQ_HEADER_ERROR\n");
}
else if (irq_mask & RAL_IRQ_RX_TIMEOUT) {
DEBUG("[sx1280x] netdev: SX1280_IRQ_RX_TIMEOUT\n");
netdev->event_callback(netdev, NETDEV_EVENT_RX_TIMEOUT);
}
}
static int _get_state(sx1280_t *dev, void *val)
{
(void)dev;
netopt_state_t state = NETOPT_STATE_OFF;
sx1280_chip_status_t radio_status;
sx1280_get_status(dev, &radio_status);
switch (radio_status.chip_mode) {
case SX1280_CHIP_MODE_STBY_RC:
/* Intentional fall-through */
case SX1280_CHIP_MODE_STBY_XOSC:
state = NETOPT_STATE_STANDBY;
DEBUG("NETOPT_STATE_STANDBY ");
break;
case SX1280_CHIP_MODE_RX:
state = NETOPT_STATE_RX;
DEBUG("NETOPT_STATE_RX ");
break;
case SX1280_CHIP_MODE_TX:
state = NETOPT_STATE_TX;
DEBUG("NETOPT_STATE_TX ");
break;
case SX1280_CHIP_MODE_FS:
DEBUG("SX1280_CHIP_MODE_FS");
/* Intentional fall-through */
default:
DEBUG("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 */
sx1280_t *dev = (sx1280_t *)netdev;
if (dev == NULL) {
return -ENODEV;
}
switch (opt) {
case NETOPT_DEVICE_TYPE:
assert(max_len == sizeof(uint16_t));
*((uint16_t *)val) = NETDEV_TYPE_LORA;
return sizeof(uint16_t);
case NETOPT_STATE:
assert(max_len >= sizeof(netopt_state_t));
return _get_state(dev, val);
case NETOPT_CHANNEL_FREQUENCY:
assert(max_len >= sizeof(uint32_t));
*((uint32_t *)val) = sx1280_get_channel(dev);
return sizeof(uint32_t);
case NETOPT_BANDWIDTH:
assert(max_len >= sizeof(uint32_t));
*((uint32_t *)val) = sx1280_get_bandwidth(dev);
return sizeof(uint32_t);
case NETOPT_SPREADING_FACTOR:
assert(max_len >= sizeof(uint8_t));
*((uint8_t *)val) = sx1280_get_spreading_factor(dev);
return sizeof(uint8_t);
case NETOPT_CODING_RATE:
assert(max_len >= sizeof(uint8_t));
*((uint8_t *)val) = sx1280_get_coding_rate(dev);
return sizeof(uint8_t);
case NETOPT_PDU_SIZE:
assert(max_len >= sizeof(uint8_t));
*((uint8_t *)val) = sx1280_get_lora_payload_length(dev);
return sizeof(uint8_t);
case NETOPT_INTEGRITY_CHECK:
assert(max_len >= sizeof(netopt_enable_t));
*((netopt_enable_t *)val) = sx1280_get_lora_crc(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
return sizeof(netopt_enable_t);
case NETOPT_IQ_INVERT:
assert(max_len >= sizeof(uint8_t));
*((netopt_enable_t *)val) = sx1280_get_lora_iq_invert(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
return sizeof(netopt_enable_t);
case NETOPT_RSSI:
assert(max_len >= sizeof(int16_t));
sx1280_get_rssi_inst(dev, ((int16_t *)val));
return sizeof(int16_t);
default:
break;
}
return -ENOTSUP;
}
static int _set_state(sx1280_t *dev, netopt_state_t state)
{
(void)dev;
switch (state) {
case NETOPT_STATE_STANDBY:
DEBUG("[sx1280] netdev: set NETOPT_STATE_STANDBY state\n");
sx1280_set_standby(dev, SX1280_STANDBY_CFG_RC);
break;
case NETOPT_STATE_IDLE:
/* intentional fall-throught */
case NETOPT_STATE_RX:
DEBUG("[sx1280] netdev: set NETOPT_STATE_RX state\n");
sx1280_set_rx(dev->ral.context, SX1280_TICK_SIZE_1000_US, SX1280_RX_MODE );
break;
case NETOPT_STATE_TX:
DEBUG("[sx1280] netdev: set NETOPT_STATE_TX state\n");
sx1280_set_tx(dev->ral.context, SX1280_TICK_SIZE_1000_US, 0 );
break;
case NETOPT_STATE_RESET:
DEBUG("[sx1280] netdev: set NETOPT_STATE_RESET state\n");
sx1280_reset(dev);
sx1280_init(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 */
sx1280_t *dev = (sx1280_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_CHANNEL_FREQUENCY:
assert(len <= sizeof(uint32_t));
uint32_t params_lora_bw = sx1280_get_bandwidth(dev);
uint32_t freq = *((const uint32_t *)val);
uint32_t min_freq = (uint32_t)LORA_ISM2400_FREQUENCY_LOW + (params_lora_bw / 2);
uint32_t max_freq = (uint32_t)LORA_ISM2400_FREQUENCY_HIGH - (params_lora_bw / 2);
if (freq < min_freq || freq > max_freq) {
res = -EINVAL;
break;
}
sx1280_set_channel(dev, *((const uint32_t *)val));
return sizeof(uint32_t);
case NETOPT_BANDWIDTH:
assert(len <= sizeof(uint16_t));
uint16_t bw = *((const uint16_t *)val);
switch (bw) {
case 200: /* fall-through */
case 400: /* fall-through */
case 800: /* fall-through */
case 1600:
sx1280_set_bandwidth(dev, bw);
return sizeof(uint16_t);
default:
res = -EINVAL;
puts("invalid bandwidth, use 200, 400 , 800, 1600");
break;
}
break; /* outer switch*/
case NETOPT_SPREADING_FACTOR:
assert(len <= sizeof(uint8_t));
uint8_t sf = *((const uint8_t *)val);
if ((sf < RAL_LORA_SF5) || (sf > RAL_LORA_SF12)) {
res = -EINVAL;
break;
}
sx1280_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);
switch (cr) {
case LORA_CR_4_5:
cr = RAL_LORA_CR_4_5;
break;
case LORA_CR_4_6:
cr = RAL_LORA_CR_4_6;
break;
case LORA_CR_4_7:
cr = RAL_LORA_CR_4_7;
break;
case LORA_CR_4_8:
cr = RAL_LORA_CR_4_8;
break;
case LORA_CR_LI_4_5:
cr = RAL_LORA_CR_LI_4_5;
break;
case LORA_CR_LI_4_6:
cr = RAL_LORA_CR_LI_4_6;
break;
case LORA_CR_LI_4_8:
cr = RAL_LORA_CR_LI_4_8;
break;
default:
res = -EINVAL;
puts(
"invalid cr, use\n \
LORA_CR_4_5 = 1\n \
LORA_CR_4_6 = 2\n \
LORA_CR_4_7 = 3\n \
LORA_CR_4_8 = 4\n \
LORA_CR_LI_4_5 = 5\n \
LORA_CR_LI_4_6 = 6\n \
LORA_CR_LI_4_8 = 7\n");
return res;
}
sx1280_set_coding_rate(dev, cr);
return sizeof(uint8_t);
case NETOPT_PDU_SIZE:
assert(len <= sizeof(uint8_t));
sx1280_set_lora_payload_length(dev, *((const uint8_t *)val));
return sizeof(uint8_t);
case NETOPT_INTEGRITY_CHECK:
assert(len <= sizeof(netopt_enable_t));
sx1280_set_lora_crc(dev, *((const netopt_enable_t *)val) ? true : false);
return sizeof(netopt_enable_t);
case NETOPT_PREAMBLE_LENGTH:
assert(len <= sizeof(uint16_t));
sx1280_set_lora_preamble_length(dev, *((const uint16_t *)val));
return sizeof(uint16_t);
case NETOPT_IQ_INVERT:
assert(len <= sizeof(netopt_enable_t));
sx1280_set_lora_iq_invert(dev, *((const netopt_enable_t *)val) ? true : false);
return sizeof(bool);
default:
DEBUG(" OPT unrecognised (missing case) %i", opt);
break;
}
return res;
}
const netdev_driver_t sx1280_driver = {
.send = _send,
.recv = _recv,
.init = _init,
.isr = _isr,
.get = _get,
.set = _set,
};

View File

@ -38,6 +38,7 @@ rsource "libcose/Kconfig"
rsource "libfixmath/Kconfig"
rsource "libhydrogen/Kconfig"
rsource "littlefs2/Kconfig"
rsource "lorabasics/Kconfig"
rsource "lora-serialization/Kconfig"
rsource "lua/Kconfig"
rsource "lv_drivers/Kconfig"

33
pkg/lorabasics/Kconfig Normal file
View File

@ -0,0 +1,33 @@
# Copyright (c) 2022 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_LORABASICS
bool "LoRa Basics"
depends on TEST_KCONFIG
# depends on HAS_ARCH_32_BIT
select MODULE_LORABASICS_SMTC_RAL
if PACKAGE_LORABASICS
config MODULE_LORABASICS_SX1280_DRIVER
bool "LoRaBasics SX1280 driver code"
depends on HAS_PERIPH_SPI
depends on HAS_PERIPH_GPIO
depends on HAS_PERIPH_GPIO_IRQ
select MODULE_PERIPH_SPI
select MODULE_PERIPH_GPIO
select MODULE_PERIPH_GPIO_IRQ
select MODULE_ZTIMER
select MODULE_ZTIMER_MSEC
select MODULE_LORABASICS_DRIVER_SX1280_HAL
config MODULE_LORABASICS_DRIVER_SX1280_HAL
bool "LoRaBasicsModem SX1280 driver hal"
config MODULE_LORABASICS_SMTC_RAL
bool "LoRaBasicsModem Radio Abstraction Layer (RAL)"
endif # PACKAGE_LORABASICS

23
pkg/lorabasics/Makefile Normal file
View File

@ -0,0 +1,23 @@
PKG_NAME=lorabasicsmodem
PKG_URL=https://github.com/lorabasics/lorabasicsmodem.git
PKG_VERSION=04e415bcfbdc7f1f4bff918a4867fab53bc8bb8a
PKG_LICENSE=BSD
include $(RIOTBASE)/pkg/pkg.mk
CFLAGS += -Wno-error=unused-parameter
CFLAGS += -Wno-error=unused-function
IGNORE_MODULES := lorabasics_driver_sx1280_hal
#
LORABASICS_MODULES := $(filter-out $(IGNORE_MODULES),$(filter lorabasics%,$(USEMODULE)))
all: $(LORABASICS_MODULES)
@true
lorabasics_smtc_ral:
$(QQ)"$(MAKE)" -C $(PKG_SOURCE_DIR)/smtc_ral/src -f $(RIOTBASE)/Makefile.base MODULE=$@ SRC="ral.c ral_sx1280.c"
lorabasics_sx1280_driver:
$(QQ)"$(MAKE)" -C $(PKG_SOURCE_DIR)/sx1280_driver/src -f $(RIOTBASE)/Makefile.base MODULE=$@

View File

@ -0,0 +1,11 @@
ifneq (,$(filter lorabasics_sx1280_driver,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio_irq
FEATURES_REQUIRED += periph_spi
USEMODULE += ztimer_msec
USEMODULE += lorabasics_driver_sx1280_hal
endif
# This package has assumptions that only work for 32-bit architectures
FEATURES_REQUIRED += arch_32bit
USEMODULE += lorabasics_smtc_ral

View File

@ -0,0 +1,11 @@
INCLUDES += -I$(PKGDIRBASE)/lorabasicsmodem \
#
ifneq (,$(filter lorabasics_driver_sx1280_hal,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lorabasics/driver_sx1280_hal
# In the lorabasics package setting this define includes RAL code for the sx1280 radio
CFLAGS += -DSX1280
endif
PSEUDOMODULES += lorabasics

13
pkg/lorabasics/doc.txt Normal file
View File

@ -0,0 +1,13 @@
/**
* @defgroup pkg_lorabasicsmodem LoRa Basics
* @ingroup pkg
* @brief LoRa Basics Modem
*
* # HAL implementation for the SX1280 LoRa radio driver and vendor code for SX1280
*
* # License
*
* Licensed under BSD.
*
* @see git@github.com:lorabasics/lorabasicsmodem.git
*/

View File

@ -0,0 +1,3 @@
MODULE = lorabasics_driver_sx1280_hal
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2022 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_lorabasicsmodem
* @{
*
* @file
* @brief HAL implementation for the SX1280 LoRa radio driver
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Nicolas Albarel <nicolas.albarel@univ-grenoble-alpes.fr>
* @author Didier Donsez <didier.donsez@univ-grenoble-alpes.fr>
* @author Olivier Alphand <olivier.alphand@univ-grenoble-alpes.fr>
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.fr>
*
* @}
*/
#include <stdint.h>
#include <stdbool.h>
#include "irq.h"
#include "periph/spi.h"
#include "ztimer.h"
#include "sx1280.h"
#include "sx1280_constants.h"
#include "sx1280_driver/src/sx1280_hal.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief Wait until radio busy pin is reset to 0
*/
static void sx1280_hal_wait_on_busy(const void *context)
{
sx1280_t *dev = (sx1280_t *)context;
while (gpio_read(dev->params->dio0_pin)) {}
}
sx1280_hal_status_t sx1280_hal_write(const void *context, const uint8_t *command,
const uint16_t command_length,
const uint8_t *data, const uint16_t data_length)
{
sx1280_t *dev = (sx1280_t *)context;
sx1280_hal_wakeup(context);
DEBUG("[sx1280_hal_write]: command_length=%d data_length=%d\n", command_length, data_length);
spi_acquire(dev->params->spi, SPI_CS_UNDEF, dev->params->spi_mode, dev->params->spi_clk);
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);
/* 0x84 - SX1280_SET_SLEEP opcode. In sleep mode the radio dio is stuck
to 1 => do not test it */
if (command[0] != 0x84) {
sx1280_hal_wait_on_busy(context);
}
return SX1280_HAL_STATUS_OK;
}
sx1280_hal_status_t sx1280_hal_read(const void *context, const uint8_t *command,
const uint16_t command_length,
uint8_t *data, const uint16_t data_length)
{
sx1280_t *dev = (sx1280_t *)context;
sx1280_hal_wakeup(context);
spi_acquire(dev->params->spi, SPI_CS_UNDEF, dev->params->spi_mode, dev->params->spi_clk);
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 SX1280_HAL_STATUS_OK;
}
void sx1280_hal_reset( const void *context )
{
sx1280_t *dev = (sx1280_t *)context;
gpio_clear(dev->params->reset_pin);
ztimer_sleep(ZTIMER_MSEC, SX1280_RESET_MS);
gpio_set(dev->params->reset_pin);
ztimer_sleep(ZTIMER_MSEC, SX1280_WAKEUP_TIME_MS);
}
sx1280_hal_status_t sx1280_hal_wakeup(const void *context)
{
sx1280_t *dev = (sx1280_t *)context;
if (dev->mode == SX1280_HAL_OP_MODE_SLEEP) {
/* Busy is HIGH in sleep mode, wake-up the device */
gpio_clear(dev->params->nss_pin);
sx1280_hal_wait_on_busy(context);
gpio_set(dev->params->nss_pin);
/* Radio is awake in STDBY_RC mode */
dev->mode = SX1280_HAL_OP_MODE_STDBY_RC;
}
else {
/* if the radio is awake, just wait until busy pin get low */
sx1280_hal_wait_on_busy(context);
}
return SX1280_HAL_STATUS_OK;
}
sx1280_hal_operating_mode_t sx1280_hal_get_operating_mode(const void *context)
{
sx1280_t *dev = (sx1280_t *)context;
return dev->mode;
}
void sx1280_hal_set_operating_mode(const void *context, const sx1280_hal_operating_mode_t op_mode)
{
sx1280_t *dev = (sx1280_t *)context;
dev->mode = op_mode;
}

View File

@ -75,6 +75,14 @@ extern "C" {
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_250_KHZ)
#elif IS_ACTIVE(CONFIG_LORA_BW_DEFAULT_500)
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_500_KHZ)
#elif IS_ACTIVE(CONFIG_LORA_BW_DEFAULT_200)
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_200_KHZ)
#elif IS_ACTIVE(CONFIG_LORA_BW_DEFAULT_400)
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_400_KHZ)
#elif IS_ACTIVE(CONFIG_LORA_BW_DEFAULT_800)
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_800_KHZ)
#elif IS_ACTIVE(CONFIG_LORA_BW_DEFAULT_1600)
#define CONFIG_LORA_BW_DEFAULT (LORA_BW_1600_KHZ)
#endif
#ifndef CONFIG_LORA_BW_DEFAULT
@ -131,6 +139,12 @@ extern "C" {
#define CONFIG_LORA_CR_DEFAULT (LORA_CR_4_7)
#elif IS_ACTIVE(CONFIG_LORA_CR_DEFAULT_CR_4_8)
#define CONFIG_LORA_CR_DEFAULT (LORA_CR_4_8)
#elif IS_ACTIVE(CONFIG_LORA_CR_DEFAULT_CR_LI_4_5)
#define CONFIG_LORA_CR_DEFAULT (LORA_CR_LI_4_5)
#elif IS_ACTIVE(CONFIG_LORA_CR_DEFAULT_CR_LI_4_6)
#define CONFIG_LORA_CR_DEFAULT (LORA_CR_LI_4_6)
#elif IS_ACTIVE(CONFIG_LORA_CR_DEFAULT_CR_LI_4_8)
#define CONFIG_LORA_CR_DEFAULT (LORA_CR_LI_4_8)
#endif
#ifndef CONFIG_LORA_CR_DEFAULT
@ -201,6 +215,18 @@ extern "C" {
*/
#define LORA_SYNCWORD_PUBLIC (0x34) /**< Syncword used for public networks */
#define LORA_SYNCWORD_PRIVATE (0x12) /**< Syncword used for private networks */
/* see https://lora-developers.semtech.com/documentation/tech-papers-and-guides/physical-layer-proposal-2.4ghz */
#define LORA_SYNCWORD_ISM2400_PUBLIC (0x21) /**< Syncword used for public networks on ISM2400 */
/** @} */
/**
* @name LoRa 2.4Ghz band frequency definitions
*
* See https://lora-developers.semtech.com/documentation/tech-papers-and-guides/physical-layer-proposal-2.4ghz/
* @{
*/
#define LORA_ISM2400_FREQUENCY_LOW 2400000000 /**< lowest frequency ISM24000 band */
#define LORA_ISM2400_FREQUENCY_HIGH 2500000000 /**< highest frequency ISM24000 band */
/** @} */
/**
@ -213,14 +239,19 @@ extern "C" {
enum {
LORA_BW_125_KHZ = 0, /**< 125 kHz bandwidth */
LORA_BW_250_KHZ, /**< 250 kHz bandwidth */
LORA_BW_500_KHZ /**< 500 kHz bandwidth */
LORA_BW_500_KHZ, /**< 500 kHz bandwidth */
LORA_BW_200_KHZ, /**< 200 kHz bandwidth, only 2.4Ghz */
LORA_BW_400_KHZ, /**< 400 kHz bandwidth, only 2.4Ghz */
LORA_BW_800_KHZ, /**< 800 kHz bandwidth, only 2.4Ghz */
LORA_BW_1600_KHZ, /**< 1600 kHz bandwidth, only 2.4Ghz */
};
/**
* @brief LoRa modulation spreading factor rate
*/
enum {
LORA_SF6 = 6, /**< spreading factor 6 */
LORA_SF5 = 5, /**< spreading factor 5, sx126x and sx1280 */
LORA_SF6, /**< spreading factor 6 */
LORA_SF7, /**< spreading factor 7 */
LORA_SF8, /**< spreading factor 8 */
LORA_SF9, /**< spreading factor 9 */
@ -236,7 +267,10 @@ enum {
LORA_CR_4_5 = 1, /**< coding rate 4/5 */
LORA_CR_4_6, /**< coding rate 4/6 */
LORA_CR_4_7, /**< coding rate 4/7 */
LORA_CR_4_8 /**< coding rate 4/8 */
LORA_CR_4_8, /**< coding rate 4/8 */
LORA_CR_LI_4_5, /**< coding rate long interleaving 4/5 */
LORA_CR_LI_4_6, /**< coding rate long interleaving 4/6 */
LORA_CR_LI_4_8 /**< coding rate long interleaving 4/8 */
};
/** @} */

View File

@ -0,0 +1,13 @@
BOARD ?= nucleo-f103rb
include ../Makefile.tests_common
# required modules
USEMODULE += sx1280
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += iolist
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,5 @@
BOARD_INSUFFICIENT_MEMORY := \
nucleo-l011k4 \
stm32f030f4-demo \
samd10-xmini \
#

View File

@ -0,0 +1,172 @@
## About
This is a manual test application for the SX1280 radio driver.
This manual test application was also tested with a custom board (esp32-wroom-32 + lambda80C-24S on Mikrobus_0) :
see https://github.com/thingsat/tinygs_2g4station
If you have other hardware (boards, Semtech based LoRa module), you can adapt
the configuration to your needs by copying an adapted version of
`drivers/sx1280/include/sx1280_params.h` file to your application directory.
## Build and Flash
```shell
cd tests/driver_sx1280
make flash term
```
## Usage
This test application provides low level shell commands to interact with the
SX1280 module.
Once the board is flashed and you are connected via serial to the shell, use the `help`
command to display the available commands:
```
> help
2022-05-09 10:27:13,724 # help
2022-05-09 10:27:13,731 # Command Description
2022-05-09 10:27:13,731 # ---------------------------------------
2022-05-09 10:27:13,735 # sx1280 Control the SX1280 radio
2022-05-09 10:27:13,738 # reboot Reboot the node
2022-05-09 10:27:13,742 # version Prints current RIOT_VERSION
2022-05-09 10:27:13,747 # pm interact with layered PM subsystem
```
### Getter
```
2022-04-28 15:00:32,795 # main(): This is RIOT! (Version: 2021.10-devel-3491-g23b57-pr/sx1280_v2)
2022-04-28 15:00:32,806 # Initialization successful - starting the shell now
> sx1280
2022-04-28 15:00:39,408 # sx1280
2022-04-28 15:00:39,409 # Usage: sx1280 <get|set|rx|tx|reset>
> sx1280 get
2022-04-28 15:00:44,808 # sx1280 get
2022-04-28 15:00:44,809 # Usage: sx1280 get <type|freq|bw|sf|cr>
> sx1280 get type
2022-04-28 15:00:48,064 # sx1280 get type
2022-04-28 15:00:48,065 # Device type: lora
> sx1280 get freq
2022-04-28 15:00:52,639 # sx1280 get freq
2022-04-28 15:00:52,639 # Frequency: 2403000000 Hz
> sx1280 get bw
2022-04-28 15:00:57,130 # sx1280 get bw
2022-04-28 15:00:57,131 # Bandwidth: 800 kHz
> sx1280 get sf
2022-04-28 15:01:01,476 # sx1280 get sf
2022-04-28 15:01:01,477 # Spreading factor: 12
2022-04-28 15:01:10,159 # sx1280 get cr
2022-04-28 15:01:10,165 # Coding rate: 6
2022-04-28 15:01:10,165 # Usage: use
2022-04-28 15:01:10,166 # LORA_CR_4_5 = 1
2022-04-28 15:01:10,166 # LORA_CR_4_6 = 2
2022-04-28 15:01:10,167 # LORA_CR_4_7 = 3
2022-04-28 15:01:10,167 # LORA_CR_4_8 = 4
2022-04-28 15:01:10,169 # LORA_CR_LI_4_5 = 5
2022-04-28 15:01:10,170 # LORA_CR_LI_4_6 = 6
2022-04-28 15:01:10,171 # LORA_CR_LI_4_8 = 7
```
### Setter
```
2022-04-28 16:30:53,635 # sx1280
2022-04-28 16:30:53,642 # Usage: sx1280 <get|set|rx|tx>
> sx1280 set
2022-04-28 16:30:56,504 # sx1280 set
2022-04-28 16:30:56,505 # Usage: sx1280 set <freq|bw|sf|cr|> <value>
> sx1280 freq
2022-04-28 16:31:02,802 # sx1280 freq
> sx1280 set freq
2022-04-28 16:31:12,282 # sx1280 set freq
2022-04-28 16:31:12,287 # Usage: use freq between 2400000000 + (bw/2) and 2500000000 - (bw/2) (Hz) !
2022-04-28 16:31:12,290 # Usage: sx1280 set <freq|bw|sf|cr|> <value>
> sx1280 set bw
2022-04-28 16:31:18,924 # sx1280 set bw
2022-04-28 16:31:18,925 # Usage: use 200, 400, 800, 1600 (kHz)
2022-04-28 16:31:18,929 # Usage: sx1280 set <freq|bw|sf|cr|> <value>
> sx1280 set sf
2022-04-28 16:31:23,232 # sx1280 set sf
2022-04-28 16:31:23,233 # Usage: use SF between 5 and 12
2022-04-28 16:31:23,236 # Usage: sx1280 set <freq|bw|sf|cr|> <value>
> sx1280 set cr
2022-04-28 15:01:10,159 # sx1280 set cr
2022-04-28 15:01:10,165 # Usage: use
2022-04-28 15:01:10,166 # LORA_CR_4_5 = 1
2022-04-28 15:01:10,166 # LORA_CR_4_6 = 2
2022-04-28 15:01:10,167 # LORA_CR_4_7 = 3
2022-04-28 15:01:10,167 # LORA_CR_4_8 = 4
2022-04-28 15:01:10,169 # LORA_CR_LI_4_5 = 5
2022-04-28 15:01:10,170 # LORA_CR_LI_4_6 = 6
2022-04-28 15:01:10,171 # LORA_CR_LI_4_8 = 7
> sx1280 set cr 6
2022-04-28 15:01:12,359 # sx1280 set cr 6
2022-04-28 15:01:12,362 # cr set
2022-04-28 16:31:27,001 # Usage: sx1280 set <freq|bw|sf|cr|> <value>
> sx1280 set freq 2455555555
2022-04-28 16:32:20,235 # sx1280 set freq 2455555555
2022-04-28 16:32:20,236 # freq set
> sx1280 set bw 200
2022-04-28 16:32:29,468 # sx1280 set bw 200
2022-04-28 16:32:29,468 # setup: setting 200KHz bandwidth
2022-04-28 16:32:29,469 # bw set
> sx1280 set sf 5
2022-04-28 16:32:35,138 # sx1280 set sf 5
2022-04-28 16:32:35,141 # sf set
> sx1280 set cr 4
2022-04-28 16:32:40,970 # sx1280 set cr 4
2022-04-28 16:32:40,973 # cr set
sx1280 reset
2022-05-17 13:36:54,836 # sx1280 reset
2022-05-17 13:36:54,836 # resetting sx1280...
```
### TX/RX
Once we have a shell on both card we can use the shell cmd :
```
2022-04-28 16:26:48,034 # main(): This is RIOT! (Version: 2021.10-devel-3491-g23b57-pr/sx1280_v2)
2022-04-28 16:26:48,046 # Initialization successful - starting the shell now
help
2022-04-28 16:27:23,060 # help
2022-04-28 16:27:23,061 # Command Description
2022-04-28 16:27:23,066 # ---------------------------------------
2022-04-28 16:27:23,067 # sx1280 Control the SX1280 radio
2022-04-28 16:27:23,072 # reboot Reboot the node
2022-04-28 16:27:23,077 # version Prints current RIOT_VERSION
2022-04-28 16:27:23,082 # pm interact with layered PM subsystem
2022-04-28 16:27:23,085 # ps Prints information about running threads.
> sx1280
2022-04-28 16:27:27,574 # sx1280
2022-04-28 16:27:27,575 # Usage: sx1280 <get|set|rx|tx>
> sx1280 tx
2022-04-28 16:27:30,710 # sx1280 tx
2022-04-28 16:27:30,711 # Usage: sx1280 tx <payload>
> sx1280 tx test_default_params
2022-04-28 16:28:00,452 # sx1280 tx test_default_params
2022-04-28 16:28:00,455 # sending "test_default_params" payload (20 bytes)
> 2022-04-28 16:28:00,718 # Transmission completed
```
```
2022-04-28 16:26:43,538 # Connect to serial port /dev/tty.usbserial-14620
Welcome to pyterm!
Type '/exit' to exit.
sx1280
2022-04-28 16:27:49,686 # sx1280
2022-04-28 16:27:49,687 # Usage: sx1280 <get|set|rx|tx>
> sx1280 rx
2022-04-28 16:27:53,657 # sx1280 rx
2022-04-28 16:27:53,657 # Usage: sx1280 rx <start|stop>
> sx1280 rx start
2022-04-28 16:27:56,596 # sx1280 rx start
2022-04-28 16:27:56,600 # Listen mode started
> 2022-04-28 16:28:00,562 # Data reception started
2022-04-28 16:28:00,726 # Received: "test_default_params" (20 bytes) - [RSSI: -43, SNR: 8]
```

View File

@ -0,0 +1,8 @@
# this file enables modules defined in Kconfig. Do not use this file for
# application configuration. This is only needed during migration.
CONFIG_MODULE_SX1280=y
CONFIG_MODULE_IOLIST=y
CONFIG_MODULE_SHELL=y
CONFIG_MODULE_SHELL_COMMANDS=y

379
tests/driver_sx1280/main.c Normal file
View File

@ -0,0 +1,379 @@
/*
* Copyright (C) 2022 Inria
* Copyright (C) 2020-2022 Université Grenoble Alpes
*
* 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 SX1280 Driver
*
* @author Aymeric Brochier <aymeric.brochier@univ-grenoble-alpes.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 "sx1280.h"
#include "sx1280_params.h"
#include "sx1280_netdev.h"
#define SX1280_MSG_QUEUE (8U)
#define SX1280_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#define SX1280_MSG_TYPE_ISR (0x3456)
#define SX1280_MAX_PAYLOAD_LEN (128U)
static char stack[SX1280_STACKSIZE];
static kernel_pid_t _recv_pid;
static char message[SX1280_MAX_PAYLOAD_LEN];
static sx1280_t sx1280;
static void _event_cb(netdev_t *dev, netdev_event_t event)
{
if (event == NETDEV_EVENT_ISR) {
msg_t msg;
msg.type = SX1280_MSG_TYPE_ISR;
if (msg_send(&msg, _recv_pid) <= 0) {
puts("sx1280_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]\n",
message, (int)len, packet_info.rssi, (int)packet_info.snr);
}
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 = arg;
static msg_t _msg_queue[SX1280_MSG_QUEUE];
msg_init_queue(_msg_queue, SX1280_MSG_QUEUE);
while (1) {
msg_t msg;
msg_receive(&msg);
if (msg.type == SX1280_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>\n", cmd);
}
static void _usage_freq(void)
{
printf("Usage: use freq between 2400000000 + (bw/2) and 2500000000 - (bw/2) (Hz) !\n");
}
static void _usage_bw(void)
{
printf("Usage: use 200, 400, 800, 1600 (kHz)\n");
}
static void _usage_sf(void)
{
printf("Usage: use SF between 5 and 12\n");
}
static void _usage_cr(void)
{
printf(
"Usage: use\n \
LORA_CR_4_5 = 1\n \
LORA_CR_4_6 = 2\n \
LORA_CR_4_7 = 3\n \
LORA_CR_4_8 = 4\n \
LORA_CR_LI_4_5 = 5\n \
LORA_CR_LI_4_6 = 6\n \
LORA_CR_LI_4_8 = 7\n");
}
static int sx1280_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])) {
uint32_t bw_val = 0;
netdev->driver->get(netdev, NETOPT_BANDWIDTH, &bw_val, sizeof(uint32_t));
printf("Bandwidth: %" PRIu32 " kHz\n", bw_val / 1000);
}
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);
_usage_cr();
}
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 sx1280_set_cmd(netdev_t *netdev, int argc, char **argv)
{
if (argc == 3) {
if (!strcmp("freq", argv[2])) {
_usage_freq();
}
if (!strcmp("bw", argv[2])) {
_usage_bw();
}
if (!strcmp("sf", argv[2])) {
_usage_sf();
}
if (!strcmp("cr", argv[2])) {
_usage_cr();
}
}
if (argc != 4) {
_set_usage(argv[0]);
return -1;
}
int ret = 0;
if (!strcmp("freq", argv[2])) {
uint32_t freq = strtoul(argv[3], NULL, 10);
ret = netdev->driver->set(netdev, NETOPT_CHANNEL_FREQUENCY, &freq, sizeof(uint32_t));
}
else if (!strcmp("bw", argv[2])) {
uint16_t bw = atoi(argv[3]);
ret = netdev->driver->set(netdev, NETOPT_BANDWIDTH, &bw, sizeof(uint16_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 sx1280_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 (IDLE) 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 STANDBY 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 sx1280_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;
}
static int sx1280_reset_cmd(netdev_t *netdev, int argc, char **argv)
{
(void)argc;
(void)argv;
puts("resetting sx1280...");
netopt_state_t state = NETOPT_STATE_RESET;
netdev->driver->set(netdev, NETOPT_STATE, &state, sizeof(netopt_state_t));
return 0;
}
int sx1280_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <get|set|rx|tx|reset>\n", argv[0]);
return -1;
}
netdev_t *netdev = &sx1280.netdev;
if (!strcmp("get", argv[1])) {
return sx1280_get_cmd(netdev, argc, argv);
}
else if (!strcmp("set", argv[1])) {
return sx1280_set_cmd(netdev, argc, argv);
}
else if (!strcmp("rx", argv[1])) {
return sx1280_rx_cmd(netdev, argc, argv);
}
else if (!strcmp("tx", argv[1])) {
return sx1280_tx_cmd(netdev, argc, argv);
}
else if (!strcmp("reset", argv[1])) {
return sx1280_reset_cmd(netdev, argc, argv);
}
else {
printf("Unknown cmd %s\n", argv[1]);
printf("Usage: %s <get|set|rx|tx|reset>\n", argv[0]);
return -1;
}
return 0;
}
static const shell_command_t shell_commands[] = {
{ "sx1280", "Control the SX1280 radio", sx1280_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
sx1280_setup(&sx1280, &sx1280_params[0], 0);
netdev_t *netdev = &sx1280.netdev;
netdev->driver = &sx1280_driver;
if (netdev->driver->init(netdev) < 0) {
puts("Failed to initialize SX1280 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;
}
puts("Initialization successful - starting the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}