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

347 lines
9.8 KiB
C

/*
* 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"
#include "sx126x_internal.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
const sx126x_pa_cfg_params_t sx1268_pa_cfg = {
.pa_duty_cycle = 0x04,
.hp_max = 0x06,
.device_sel = 0x00,
.pa_lut = 0x01
};
const sx126x_pa_cfg_params_t lpa_cfg = {
.pa_duty_cycle = 0x04,
.hp_max = 0x00,
.device_sel = 0x01,
.pa_lut = 0x01
};
const sx126x_pa_cfg_params_t hpa_cfg = {
.pa_duty_cycle = 0x02,
.hp_max = 0x02,
.device_sel = 0x00,
.pa_lut = 0x01
};
void sx126x_setup(sx126x_t *dev, const sx126x_params_t *params, uint8_t index)
{
netdev_t *netdev = &dev->netdev;
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 (sx126x_is_llcc68(dev) || sx126x_is_sx1262(dev)) {
sx126x_set_pa_cfg(dev, &hpa_cfg);
}
else if (sx126x_is_sx1268(dev)) {
sx126x_set_pa_cfg(dev, &sx1268_pa_cfg);
}
else if (sx126x_is_sx1261(dev)) {
sx126x_set_pa_cfg(dev, &lpa_cfg);
}
#if IS_USED(MODULE_SX126X_RF_SWITCH)
if (dev->params->tx_pa_mode == SX126X_RF_MODE_TX_LPA){
sx126x_set_pa_cfg(dev, &lpa_cfg);
} else {
sx126x_set_pa_cfg(dev, &hpa_cfg);
}
#endif
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 = !IS_ACTIVE(CONFIG_LORA_PAYLOAD_CRC_OFF_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);
}
#if IS_ACTIVE(SX126X_SPI)
static void _dio1_isr(void *arg)
{
netdev_trigger_event_isr(arg);
}
#endif
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);
#if IS_ACTIVE(SX126X_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;
}
#endif
/* 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_SYNC_WORD_VALID |
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);
}
/* Radio Rx timeout timer stopped on preamble detection */
sx126x_stop_timer_on_preamble(dev, true);
return res;
}
uint32_t sx126x_get_channel(const sx126x_t *dev)
{
DEBUG("[sx126x]: sx126x_get_radio_status \n");
return dev->channel;
}
void sx126x_set_channel(sx126x_t *dev, uint32_t freq)
{
DEBUG("[sx126x]: sx126x_set_channel %" PRIu32 "Hz \n", freq);
dev->channel = freq;
sx126x_set_rf_freq(dev, dev->channel);
}
uint8_t sx126x_get_bandwidth(const sx126x_t *dev)
{
DEBUG("[sx126x]: sx126x_get_bandwidth \n");
return dev->mod_params.bw - SX126X_LORA_BW_125;
}
void sx126x_set_bandwidth(sx126x_t *dev, uint8_t bandwidth)
{
DEBUG("[sx126x]: sx126x_set_bandwidth %02x\n", 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)
{
DEBUG("[sx126x]: sx126x_get_spreading_factor \n");
return dev->mod_params.sf;
}
void sx126x_set_spreading_factor(sx126x_t *dev, uint8_t sf)
{
DEBUG("[sx126x]: sx126x_set_spreading_factor : %02x\n", 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)
{
DEBUG("[sx126x]: sx126x_get_coding_rate \n");
return dev->mod_params.cr;
}
void sx126x_set_coding_rate(sx126x_t *dev, uint8_t cr)
{
DEBUG("[sx126x]: sx126x_set_coding_rate %01x\n", 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)
{
DEBUG("[sx126x]: sx126x_get_lora_payload_length \n");
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)
{
DEBUG("[sx126x]: sx126x_set_lora_payload_length %d\n", 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)
{
DEBUG("[sx126x]: sx126x_get_lora_crc \n");
return dev->pkt_params.crc_is_on;
}
void sx126x_set_lora_crc(sx126x_t *dev, bool crc)
{
DEBUG("[sx126x]: sx126x_set_lora_crc %d\n", 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)
{
DEBUG("[sx126x]: sx126x_get_lora_implicit_header \n");
return dev->pkt_params.header_type == SX126X_LORA_PKT_IMPLICIT;
}
void sx126x_set_lora_implicit_header(sx126x_t *dev, bool mode)
{
DEBUG("[sx126x]: sx126x_set_lora_implicit_header %d\n", 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)
{
DEBUG("[sx126x]: sx126x_get_lora_preamble_length \n");
return dev->pkt_params.preamble_len_in_symb;
}
void sx126x_set_lora_preamble_length(sx126x_t *dev, uint16_t preamble)
{
DEBUG("[sx126x]: sx126x_set_lora_preamble_length %" PRIu16 "\n", 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)
{
DEBUG("[sx126x]: sx126x_get_lora_iq_invert \n");
return dev->pkt_params.invert_iq_is_on;
}
void sx126x_set_lora_iq_invert(sx126x_t *dev, bool iq_invert)
{
DEBUG("[sx126x]: sx126x_set_lora_iq_invert %d\n", iq_invert);
dev->pkt_params.invert_iq_is_on = iq_invert;
sx126x_set_lora_pkt_params(dev, &dev->pkt_params);
}