Merge pull request #6797 from aabadie/driver_sx127x
drivers/sx127x: rework of implementations from #6645 and #6002
This commit is contained in:
commit
d61be01596
@ -230,6 +230,8 @@ void cc2538_set_state(cc2538_rf_t *dev, netopt_state_t state)
|
||||
RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE > FSM_STATE_RX_CALIBRATION);
|
||||
dev->state = NETOPT_STATE_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -201,6 +201,13 @@ ifneq (,$(filter srf08,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter sx127%,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
FEATURES_REQUIRED += periph_spi
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += sx127x
|
||||
endif
|
||||
|
||||
ifneq (,$(filter veml6070,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_i2c
|
||||
endif
|
||||
|
||||
@ -130,3 +130,6 @@ endif
|
||||
ifneq (,$(filter adcxx1c,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/adcxx1c/include
|
||||
endif
|
||||
ifneq (,$(filter sx127%,$(USEMODULE)))
|
||||
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include
|
||||
endif
|
||||
|
||||
@ -212,6 +212,7 @@ enum {
|
||||
NETDEV_TYPE_ETHERNET,
|
||||
NETDEV_TYPE_IEEE802154,
|
||||
NETDEV_TYPE_CC110X,
|
||||
NETDEV_TYPE_LORA,
|
||||
NETDEV_TYPE_NRFMIN
|
||||
};
|
||||
|
||||
@ -230,6 +231,11 @@ typedef enum {
|
||||
NETDEV_EVENT_TX_MEDIUM_BUSY, /**< couldn't transfer packet */
|
||||
NETDEV_EVENT_LINK_UP, /**< link established */
|
||||
NETDEV_EVENT_LINK_DOWN, /**< link gone */
|
||||
NETDEV_EVENT_TX_TIMEOUT, /**< timeout when sending */
|
||||
NETDEV_EVENT_RX_TIMEOUT, /**< timeout when receiving */
|
||||
NETDEV_EVENT_CRC_ERROR, /**< wrong CRC */
|
||||
NETDEV_EVENT_FHSS_CHANGE_CHANNEL, /**< channel changed */
|
||||
NETDEV_EVENT_CAD_DONE, /**< channel activity detection done */
|
||||
/* expand this list if needed */
|
||||
} netdev_event_t;
|
||||
|
||||
|
||||
711
drivers/include/sx127x.h
Normal file
711
drivers/include/sx127x.h
Normal file
@ -0,0 +1,711 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 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_sx127x SX127X
|
||||
* @ingroup drivers_netdev
|
||||
* @brief Semtech SX127X driver (SX1272 and SX1276)
|
||||
*
|
||||
* This module contains the driver for radio devices of the Semtech SX127x
|
||||
* series (SX1272 and SX1276).
|
||||
* Only LoRa long range modem is supported at the moment.
|
||||
*
|
||||
* SX127x modules are designed to be used in the ISM RF band. This RF band
|
||||
* depends on different regional regulatory worldwide.
|
||||
* Be careful to configure the device to use a RF frequency allowed in your
|
||||
* region.
|
||||
* sHere is the list of allowed frequencies for your region (see
|
||||
* [LoRaWAN regional parameters document available online]
|
||||
* (https://www.lora-alliance.org/Contact/RequestSpecificationForm.aspx))
|
||||
* - Europe has 2 allowed bands (ETSI):
|
||||
* - EU863-870
|
||||
* - EU433 (from 433.175MHZ to 434.665MHZ exactly)
|
||||
* - US is US902-928
|
||||
* - China has 2 allowed bands:
|
||||
* - CN779-787 (from 779.5MHz to 786.5MHz exactly)
|
||||
* - CN470-510 (from 470.3MHz to 509.7MHz exactly)
|
||||
* - Australia is AU915-928
|
||||
* - South asia, AS923:
|
||||
* - Bruneï [923-925 MHz]
|
||||
* - Cambodia [923-925 MHz]
|
||||
* - Hong Kong [920-925 MHz]
|
||||
* - Indonesia [923-925 MHz]
|
||||
* - Japan [920-928 MHz]
|
||||
* - Laos [923-925 MHz]
|
||||
* - New Zealand [915-928 MHz]
|
||||
* - Singapore [920-925 MHz]
|
||||
* - Taiwan [922-928 MHz]
|
||||
* - Thailand [920-925 MHz]
|
||||
* - Vietnam [920-925 MHz]
|
||||
* - South Korea: KR920-923 (from 920.9MHz to 923.3MHz exactly)
|
||||
*
|
||||
* For more information on Semtech SX1272 and SX1276 modules see:
|
||||
* - [SX1272/73 datasheet](http://www.semtech.com/images/datasheet/sx1272.pdf)
|
||||
* - [SX1276/77/78/79 datasheet](http://www.semtech.com/images/datasheet/sx1276_77_78_79.pdf)
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Public interface for SX127X driver
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX127X_H
|
||||
#define SX127X_H
|
||||
|
||||
#include "xtimer.h"
|
||||
#include "net/netdev.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name SX127X device default configuration
|
||||
* @{
|
||||
*/
|
||||
#define SX127X_MODEM_DEFAULT (SX127X_MODEM_LORA) /**< Use LoRa as default modem */
|
||||
#define SX127X_CHANNEL_DEFAULT (868300000UL) /**< Default channel frequency, 868.3MHz (Europe) */
|
||||
#define SX127X_HF_CHANNEL_DEFAULT (868000000UL) /**< Use to calibrate RX chain for LF and HF bands */
|
||||
#define SX127X_RF_MID_BAND_THRESH (525000000UL) /**< Mid-band threshold */
|
||||
#define SX127X_FREQUENCY_RESOLUTION (61.03515625) /**< Frequency resolution in Hz */
|
||||
#define SX127X_XTAL_FREQ (32000000UL) /**< Internal oscillator frequency, 32MHz */
|
||||
#define SX127X_RADIO_WAKEUP_TIME (1000U) /**< In microseconds [us] */
|
||||
|
||||
#define SX127X_PREAMBLE_LENGTH (8U) /**< Preamble length, same for Tx and Rx */
|
||||
#define SX127X_SYMBOL_TIMEOUT (10U) /**< Symbols timeout (s) */
|
||||
|
||||
#define SX127X_BW_DEFAULT (SX127X_BW_125_KHZ) /**< Set default bandwidth to 125kHz */
|
||||
#define SX127X_SF_DEFAULT (SX127X_SF12) /**< Set default spreading factor to 12 */
|
||||
#define SX127X_CR_DEFAULT (SX127X_CR_4_8) /**< Set default coding rate to 8 */
|
||||
#define SX127X_FIX_LENGTH_PAYLOAD_ON (false) /**< Set fixed payload length on */
|
||||
#define SX127X_IQ_INVERSION (false) /**< Set inverted IQ on */
|
||||
#define SX127X_FREQUENCY_HOPPING (false) /**< Frequency hopping on */
|
||||
#define SX127X_FREQUENCY_HOPPING_PERIOD (0U) /**< Frequency hopping period */
|
||||
#define SX127X_FIXED_HEADER_LEN_MODE (false) /**< Set fixed header length mode (implicit header) */
|
||||
#define SX127X_PAYLOAD_CRC_ON (true) /**< Enable payload CRC, optional */
|
||||
#define SX127X_PAYLOAD_LENGTH (0U) /**< Set payload length, unused with implicit header */
|
||||
|
||||
#define SX127X_TX_TIMEOUT_DEFAULT (1000U * 1000U * 30UL) /**< TX timeout, 30s */
|
||||
#define SX127X_RX_SINGLE (false) /**< Single byte receive mode => continuous by default */
|
||||
#define SX127X_RX_BUFFER_SIZE (256) /**< RX buffer size */
|
||||
|
||||
#define SX127X_RADIO_TX_POWER (14U) /**< Radio power in dBm */
|
||||
|
||||
#ifndef SX1272_DEFAULT_PASELECT
|
||||
/** @brief Default PA selection config (1: RFO, 0: PABOOST)
|
||||
*
|
||||
* This depends on the module configuration.
|
||||
*/
|
||||
#define SX1272_DEFAULT_PASELECT (1U)
|
||||
#endif
|
||||
|
||||
#define SX127X_EVENT_HANDLER_STACK_SIZE (2048U) /**< Stack size event handler */
|
||||
#define SX127X_IRQ_DIO0 (1<<0) /**< DIO0 IRQ */
|
||||
#define SX127X_IRQ_DIO1 (1<<1) /**< DIO1 IRQ */
|
||||
#define SX127X_IRQ_DIO2 (1<<2) /**< DIO2 IRQ */
|
||||
#define SX127X_IRQ_DIO3 (1<<3) /**< DIO3 IRQ */
|
||||
#define SX127X_IRQ_DIO4 (1<<4) /**< DIO4 IRQ */
|
||||
#define SX127X_IRQ_DIO5 (1<<5) /**< DIO5 IRQ */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief SX127X initialization result.
|
||||
*/
|
||||
enum {
|
||||
SX127X_INIT_OK = 0, /**< Initialization was successful */
|
||||
SX127X_ERR_SPI, /**< Failed to initialize SPI bus or CS line */
|
||||
SX127X_ERR_TEST_FAILED, /**< SX127X testing failed during initialization (check chip) */
|
||||
SX127X_ERR_THREAD /**< Unable to create DIO handling thread (check amount of free memory) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Radio driver supported modems.
|
||||
*/
|
||||
enum {
|
||||
SX127X_MODEM_FSK = 0, /**< FSK modem driver */
|
||||
SX127X_MODEM_LORA, /**< LoRa modem driver */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LoRa signal bandwidth.
|
||||
*/
|
||||
enum {
|
||||
SX127X_BW_125_KHZ = 0, /**< 125 kHz bandwidth */
|
||||
SX127X_BW_250_KHZ, /**< 250 kHz bandwidth */
|
||||
SX127X_BW_500_KHZ /**< 500 kHz bandwidth */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LoRa spreading factor rate
|
||||
*/
|
||||
enum {
|
||||
SX127X_SF6 = 6, /**< spreading factor 6 */
|
||||
SX127X_SF7, /**< spreading factor 7 */
|
||||
SX127X_SF8, /**< spreading factor 8 */
|
||||
SX127X_SF9, /**< spreading factor 9 */
|
||||
SX127X_SF10, /**< spreading factor 10 */
|
||||
SX127X_SF11, /**< spreading factor 11 */
|
||||
SX127X_SF12 /**< spreading factor 12 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief LoRa error coding rate.
|
||||
*/
|
||||
enum {
|
||||
SX127X_CR_4_5 = 1, /**< coding rate 4/5 */
|
||||
SX127X_CR_4_6, /**< coding rate 4/6 */
|
||||
SX127X_CR_4_7, /**< coding rate 4/7 */
|
||||
SX127X_CR_4_8 /**< coding rate 4/8 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Radio driver internal state machine states definition.
|
||||
*/
|
||||
enum {
|
||||
SX127X_RF_IDLE = 0, /**< Idle state */
|
||||
SX127X_RF_RX_RUNNING, /**< Sending state */
|
||||
SX127X_RF_TX_RUNNING, /**< Receiving state */
|
||||
SX127X_RF_CAD, /**< Channel activity detection state */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event types.
|
||||
*/
|
||||
enum {
|
||||
SX127X_RX_DONE = 0, /**< Receiving complete */
|
||||
SX127X_TX_DONE, /**< Sending complete*/
|
||||
SX127X_RX_TIMEOUT, /**< Receiving timeout */
|
||||
SX127X_TX_TIMEOUT, /**< Sending timeout */
|
||||
SX127X_RX_ERROR_CRC, /**< Receiving CRC error */
|
||||
SX127X_FHSS_CHANGE_CHANNEL, /**< Channel change */
|
||||
SX127X_CAD_DONE, /**< Channel activity detection complete */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name SX127X device descriptor boolean flags
|
||||
* @{
|
||||
*/
|
||||
#define SX127X_LOW_DATARATE_OPTIMIZE_FLAG (1 << 0)
|
||||
#define SX127X_ENABLE_FIXED_HEADER_LENGTH_FLAG (1 << 1)
|
||||
#define SX127X_ENABLE_CRC_FLAG (1 << 2)
|
||||
#define SX127X_CHANNEL_HOPPING_FLAG (1 << 3)
|
||||
#define SX127X_IQ_INVERTED_FLAG (1 << 4)
|
||||
#define SX127X_RX_CONTINUOUS_FLAG (1 << 5)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief LoRa configuration structure.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t preamble_len; /**< Length of preamble header */
|
||||
uint8_t power; /**< Signal power */
|
||||
uint8_t bandwidth; /**< Signal bandwidth */
|
||||
uint8_t datarate; /**< Spreading factor rate, e.g datarate */
|
||||
uint8_t coderate; /**< Error coding rate */
|
||||
uint8_t freq_hop_period; /**< Frequency hop period */
|
||||
uint8_t flags; /**< Boolean flags */
|
||||
uint32_t rx_timeout; /**< RX timeout in symbols */
|
||||
uint32_t tx_timeout; /**< TX timeout in symbols */
|
||||
} sx127x_lora_settings_t;
|
||||
|
||||
/**
|
||||
* @brief Radio settings.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t channel; /**< Radio channel */
|
||||
uint32_t window_timeout; /**< Timeout window */
|
||||
uint8_t state; /**< Radio state */
|
||||
uint8_t modem; /**< Driver model (FSK or LoRa) */
|
||||
sx127x_lora_settings_t lora; /**< LoRa settings */
|
||||
} sx127x_radio_settings_t;
|
||||
|
||||
/**
|
||||
* @brief SX127X internal data.
|
||||
*/
|
||||
typedef struct {
|
||||
/* Data that will be passed to events handler in application */
|
||||
xtimer_t tx_timeout_timer; /**< TX operation timeout timer */
|
||||
xtimer_t rx_timeout_timer; /**< RX operation timeout timer */
|
||||
uint32_t last_channel; /**< Last channel in frequency hopping sequence */
|
||||
bool is_last_cad_success; /**< Sign of success of last CAD operation (activity detected) */
|
||||
} sx127x_internal_t;
|
||||
|
||||
/**
|
||||
* @brief SX127X hardware and global parameters.
|
||||
*/
|
||||
typedef struct {
|
||||
spi_t spi; /**< SPI device */
|
||||
gpio_t nss_pin; /**< SPI NSS pin */
|
||||
gpio_t reset_pin; /**< Reset pin */
|
||||
gpio_t dio0_pin; /**< Interrupt line DIO0 (Tx done) */
|
||||
gpio_t dio1_pin; /**< Interrupt line DIO1 (Rx timeout) */
|
||||
gpio_t dio2_pin; /**< Interrupt line DIO2 (FHSS channel change) */
|
||||
gpio_t dio3_pin; /**< Interrupt line DIO3 (CAD done) */
|
||||
gpio_t dio4_pin; /**< Interrupt line DIO4 (not used) */
|
||||
gpio_t dio5_pin; /**< Interrupt line DIO5 (not used) */
|
||||
} sx127x_params_t;
|
||||
|
||||
/**
|
||||
* @brief SX127X IRQ flags.
|
||||
*/
|
||||
typedef uint8_t sx127x_flags_t;
|
||||
|
||||
/**
|
||||
* @brief SX127X device.
|
||||
* @extends netdev_t
|
||||
*/
|
||||
typedef struct sx127x_s {
|
||||
netdev_t netdev; /**< Netdev parent struct */
|
||||
sx127x_radio_settings_t settings; /**< Radio settings */
|
||||
sx127x_params_t params; /**< Device driver parameters */
|
||||
sx127x_internal_t _internal; /**< Internal sx127x data used within the driver */
|
||||
sx127x_flags_t irq; /**< Device IRQ flags */
|
||||
} sx127x_t;
|
||||
|
||||
/**
|
||||
* @brief Hardware IO IRQ callback function definition.
|
||||
*/
|
||||
typedef void (sx127x_dio_irq_handler_t)(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Setup the SX127X
|
||||
*
|
||||
* @param[in] dev Device descriptor
|
||||
* @param[in] params Parameters for device initialization
|
||||
*/
|
||||
void sx127x_setup(sx127x_t *dev, const sx127x_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Resets the SX127X
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_reset(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initializes the transceiver.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return result of initialization
|
||||
*/
|
||||
int sx127x_init(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initialize radio settings with default values
|
||||
*
|
||||
* @param[in] dev The sx127x device pointer
|
||||
*/
|
||||
void sx127x_init_radio_settings(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Generates 32 bits random value based on the RSSI readings
|
||||
*
|
||||
* @attention This function sets the radio in LoRa mode and disables all
|
||||
* interrupts from it. After calling this function either
|
||||
* sx127x_set_rx_config or sx127x_set_tx_config functions must
|
||||
* be called.
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
*
|
||||
* @return random 32 bits value
|
||||
*/
|
||||
uint32_t sx127x_random(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief sx127x DIO0 IRQ handler.
|
||||
*
|
||||
* @param[in] arg An sx127x device instance
|
||||
*/
|
||||
void sx127x_on_dio0(void *arg);
|
||||
|
||||
/**
|
||||
* @brief sx127x DIO1 IRQ handler.
|
||||
*
|
||||
* @param[in] arg An sx127x device instance
|
||||
*/
|
||||
void sx127x_on_dio1(void *arg);
|
||||
|
||||
/**
|
||||
* @brief sx127x DIO2 IRQ handler.
|
||||
*
|
||||
* @param[in] arg An sx127x device instance
|
||||
*/
|
||||
void sx127x_on_dio2(void *arg);
|
||||
|
||||
/**
|
||||
* @brief sx127x DIO3 IRQ handler.
|
||||
*
|
||||
* @param[in] arg An sx127x device instance
|
||||
*/
|
||||
void sx127x_on_dio3(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Start a channel activity detection.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_start_cad(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Gets current state of transceiver.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return radio state [RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
|
||||
*/
|
||||
uint8_t sx127x_get_state(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets current state of transceiver.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] state The new radio state
|
||||
*
|
||||
* @return radio state [RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
|
||||
*/
|
||||
void sx127x_set_state(sx127x_t *dev, uint8_t state);
|
||||
|
||||
/**
|
||||
* @brief Configures the radio with the given modem.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] modem Modem to be used [0: FSK, 1: LoRa]
|
||||
*/
|
||||
void sx127x_set_modem(sx127x_t *dev, uint8_t modem);
|
||||
|
||||
/**
|
||||
* @brief Gets the synchronization word.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return The synchronization word
|
||||
*/
|
||||
uint8_t sx127x_get_syncword(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the synchronization word.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] syncword The synchronization word
|
||||
*/
|
||||
void sx127x_set_syncword(sx127x_t *dev, uint8_t syncword);
|
||||
|
||||
/**
|
||||
* @brief Gets the channel RF frequency.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return The channel frequency
|
||||
*/
|
||||
uint32_t sx127x_get_channel(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the channel RF frequency.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] freq Channel RF frequency
|
||||
*/
|
||||
void sx127x_set_channel(sx127x_t *dev, uint32_t freq);
|
||||
|
||||
/**
|
||||
* @brief Computes the packet time on air in milliseconds.
|
||||
*
|
||||
* @pre Can only be called once sx127x_init_radio_settings have already
|
||||
* been called.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] pkt_len The received packet payload length
|
||||
*
|
||||
* @return computed air time (ms) for the given packet payload length
|
||||
*/
|
||||
uint32_t sx127x_get_time_on_air(const sx127x_t *dev, uint8_t pkt_len);
|
||||
|
||||
/**
|
||||
* @brief Sets the radio in sleep mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_set_sleep(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the radio in stand-by mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_set_standby(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the radio in reception mode.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_set_rx(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the radio in transmission mode.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*/
|
||||
void sx127x_set_tx(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum payload length.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return The maximum payload length
|
||||
*/
|
||||
uint8_t sx127x_get_max_payload_len(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the maximum payload length.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] maxlen Maximum payload length in bytes
|
||||
*/
|
||||
void sx127x_set_max_payload_len(const sx127x_t *dev, uint8_t maxlen);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X operating mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return The actual operating mode
|
||||
*/
|
||||
uint8_t sx127x_get_op_mode(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X operating mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] op_mode The new operating mode
|
||||
*/
|
||||
void sx127x_set_op_mode(const sx127x_t *dev, uint8_t op_mode);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X bandwidth
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the bandwidth
|
||||
*/
|
||||
uint8_t sx127x_get_bandwidth(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X bandwidth
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] bandwidth The new bandwidth
|
||||
*/
|
||||
void sx127x_set_bandwidth(sx127x_t *dev, uint8_t bandwidth);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X LoRa spreading factor
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the spreading factor
|
||||
*/
|
||||
uint8_t sx127x_get_spreading_factor(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa spreading factor
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] sf The spreading factor
|
||||
*/
|
||||
void sx127x_set_spreading_factor(sx127x_t *dev, uint8_t sf);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X LoRa coding rate
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the current LoRa coding rate
|
||||
*/
|
||||
uint8_t sx127x_get_coding_rate(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa coding rate
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] coderate The LoRa coding rate
|
||||
*/
|
||||
void sx127x_set_coding_rate(sx127x_t *dev, uint8_t coderate);
|
||||
|
||||
/**
|
||||
* @brief Checks if the SX127X LoRa RX single mode is enabled/disabled
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the LoRa single mode
|
||||
*/
|
||||
bool sx127x_get_rx_single(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable the SX127X LoRa RX single mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] single The LoRa RX single mode
|
||||
*/
|
||||
void sx127x_set_rx_single(sx127x_t *dev, bool single);
|
||||
|
||||
/**
|
||||
* @brief Checks if the SX127X CRC verification mode is enabled
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the LoRa single mode
|
||||
*/
|
||||
bool sx127x_get_crc(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the SX127X CRC verification mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] crc The CRC check mode
|
||||
*/
|
||||
void sx127x_set_crc(sx127x_t *dev, bool crc);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X frequency hopping period
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the frequency hopping period
|
||||
*/
|
||||
uint8_t sx127x_get_hop_period(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X frequency hopping period
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] hop_period The frequency hopping period
|
||||
*/
|
||||
void sx127x_set_hop_period(sx127x_t *dev, uint8_t hop_period);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X LoRa fixed header length mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the LoRa implicit mode
|
||||
*/
|
||||
bool sx127x_get_fixed_header_len_mode(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X to fixed header length mode (explicit mode)
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] mode The header mode
|
||||
*/
|
||||
void sx127x_set_fixed_header_len_mode(sx127x_t *dev, bool mode);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X payload length
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the payload length
|
||||
*/
|
||||
uint8_t sx127x_get_payload_length(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X payload length
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] len The payload len
|
||||
*/
|
||||
void sx127x_set_payload_length(sx127x_t *dev, uint8_t len);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X TX radio power
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the radio power
|
||||
*/
|
||||
uint8_t sx127x_get_tx_power(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X transmission power
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] power The TX power
|
||||
*/
|
||||
void sx127x_set_tx_power(sx127x_t *dev, uint8_t power);
|
||||
|
||||
/**
|
||||
* @brief Gets the SX127X preamble length
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return the preamble length
|
||||
*/
|
||||
uint16_t sx127x_get_preamble_length(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa preamble length
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] preamble The LoRa preamble length
|
||||
*/
|
||||
void sx127x_set_preamble_length(sx127x_t *dev, uint16_t preamble);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa symbol timeout
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] timeout The LoRa symbol timeout
|
||||
*/
|
||||
void sx127x_set_symbol_timeout(sx127x_t *dev, uint16_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X RX timeout
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] timeout The RX timeout
|
||||
*/
|
||||
void sx127x_set_rx_timeout(sx127x_t *dev, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X TX timeout
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] timeout The TX timeout
|
||||
*/
|
||||
void sx127x_set_tx_timeout(sx127x_t *dev, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa IQ inverted mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] iq_invert The LoRa IQ inverted mode
|
||||
*/
|
||||
void sx127x_set_iq_invert(sx127x_t *dev, bool iq_invert);
|
||||
|
||||
/**
|
||||
* @brief Sets the SX127X LoRa frequency hopping mode
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @param[in] freq_hop_on The LoRa frequency hopping mode
|
||||
*/
|
||||
void sx127x_set_freq_hop(sx127x_t *dev, bool freq_hop_on);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX127X_H */
|
||||
/** @} */
|
||||
1
drivers/sx127x/Makefile
Normal file
1
drivers/sx127x/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
134
drivers/sx127x/include/sx127x_internal.h
Normal file
134
drivers/sx127x/include/sx127x_internal.h
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 Inria Chile
|
||||
* 2017 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Semtech SX127X internal functions
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX127X_INTERNAL_H
|
||||
#define SX127X_INTERNAL_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "sx127x.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Constant values used to compute RSSI
|
||||
* @{
|
||||
*/
|
||||
#if defined(MODULE_SX1272)
|
||||
#define SX127X_RSSI_OFFSET (-139)
|
||||
#else /* MODULE_SX1276 */
|
||||
#define SX127X_RSSI_OFFSET_LF (-164)
|
||||
#define SX127X_RSSI_OFFSET_HF (-157)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Tests the transceiver version type.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
* @return true if test passed, false otherwise
|
||||
*/
|
||||
bool sx127x_test(const sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Writes the radio register at specified address.
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] addr Register address
|
||||
* @param[in] data New register value
|
||||
*/
|
||||
void sx127x_reg_write(const sx127x_t *dev, uint8_t addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Reads the radio register at specified address.
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] addr Register address
|
||||
*
|
||||
* @return Register value
|
||||
*/
|
||||
uint8_t sx127x_reg_read(const sx127x_t *dev, uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Writes multiple radio registers starting at address (burst-mode).
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] addr First radio register address
|
||||
* @param[in] buffer Buffer containing the new register's values
|
||||
* @param[in] size Number of registers to be written
|
||||
*/
|
||||
void sx127x_reg_write_burst(const sx127x_t *dev, uint8_t addr, uint8_t *buffer,
|
||||
uint8_t size);
|
||||
|
||||
/**
|
||||
* @brief Reads multiple radio registers starting at address.
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] addr First radio register address
|
||||
* @param[in] size Number of registers to be read
|
||||
* @param[out] buffer Buffer where to copy registers data
|
||||
*/
|
||||
void sx127x_reg_read_burst(const sx127x_t *dev, uint8_t addr, uint8_t *buffer,
|
||||
uint8_t size);
|
||||
|
||||
/**
|
||||
* @brief Writes the buffer contents to the SX1276 FIFO
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] buffer Buffer Buffer containing data to be put on the FIFO.
|
||||
* @param[in] size Size Number of bytes to be written to the FIFO
|
||||
*/
|
||||
void sx127x_write_fifo(const sx127x_t *dev, uint8_t *buffer, uint8_t size);
|
||||
|
||||
/**
|
||||
* @brief Reads the contents of the SX1276 FIFO
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
* @param[in] size Size Number of bytes to be read from the FIFO
|
||||
* @param[out] buffer Buffer Buffer where to copy the FIFO read data.
|
||||
*/
|
||||
void sx127x_read_fifo(const sx127x_t *dev, uint8_t *buffer, uint8_t size);
|
||||
|
||||
/**
|
||||
* @brief Performs the Rx chain calibration for LF and HF bands
|
||||
*
|
||||
* Must be called just after the reset so all registers are at their
|
||||
* default values
|
||||
*
|
||||
* @param[in] dev The sx127x device structure pointer
|
||||
*/
|
||||
void sx127x_rx_chain_calibration(sx127x_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Reads the current RSSI value.
|
||||
*
|
||||
* @param[in] dev The sx127x device descriptor
|
||||
*
|
||||
* @return current value of RSSI in [dBm]
|
||||
*/
|
||||
int16_t sx127x_read_rssi(const sx127x_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX127X_INTERNAL_H */
|
||||
48
drivers/sx127x/include/sx127x_netdev.h
Normal file
48
drivers/sx127x/include/sx127x_netdev.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
* 2017 Inria Chile
|
||||
*
|
||||
* 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Netdev driver definitions for SX127X driver
|
||||
*
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX127X_NETDEV_H
|
||||
#define SX127X_NETDEV_H
|
||||
|
||||
#include "net/netdev.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference to the netdev device driver struct
|
||||
*/
|
||||
extern const netdev_driver_t sx127x_driver;
|
||||
|
||||
/**
|
||||
* @brief Received LoRa packet status information
|
||||
*/
|
||||
typedef struct netdev_radio_lora_packet_info {
|
||||
uint8_t rssi; /**< RSSI of a received packet */
|
||||
uint8_t lqi; /**< LQI of a received packet */
|
||||
int8_t snr; /**< S/N ratio */
|
||||
uint32_t time_on_air; /**< Time on air of a received packet (ms) */
|
||||
} netdev_sx127x_lora_packet_info_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX127X_NETDEV_H */
|
||||
97
drivers/sx127x/include/sx127x_params.h
Normal file
97
drivers/sx127x/include/sx127x_params.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Inria
|
||||
* 2017 Inria Chile
|
||||
*
|
||||
* 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Default configuration for SX127X driver
|
||||
*
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
*/
|
||||
|
||||
#ifndef SX127X_PARAMS_H
|
||||
#define SX127X_PARAMS_H
|
||||
|
||||
#include "board.h"
|
||||
#include "sx127x.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Set default configuration parameters for the SX127X driver
|
||||
* Pins are adapted to ST Nucleo boards.
|
||||
* @{
|
||||
*/
|
||||
#ifndef SX127X_PARAM_SPI
|
||||
#define SX127X_PARAM_SPI (SPI_DEV(0))
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_SPI_SPEED
|
||||
#define SX127X_PARAM_SPI_SPEED (SPI_CLK_1MHZ)
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_SPI_MODE
|
||||
#define SX127X_PARAM_SPI_MODE (SPI_MODE_0)
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_SPI_NSS
|
||||
#define SX127X_PARAM_SPI_NSS GPIO_PIN(1, 6) /* D10 */
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_RESET
|
||||
#define SX127X_PARAM_RESET GPIO_PIN(0, 0) /* A0 */
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_DIO0
|
||||
#define SX127X_PARAM_DIO0 GPIO_PIN(0, 10) /* D2 */
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_DIO1
|
||||
#define SX127X_PARAM_DIO1 GPIO_PIN(1, 3) /* D3 */
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_DIO2
|
||||
#define SX127X_PARAM_DIO2 GPIO_PIN(1, 5) /* D4 */
|
||||
#endif
|
||||
|
||||
#ifndef SX127X_PARAM_DIO3
|
||||
#define SX127X_PARAM_DIO3 GPIO_PIN(1, 4) /* D5 */
|
||||
#endif
|
||||
|
||||
#define SX127X_PARAMS_DEFAULT { .spi = SX127X_PARAM_SPI, \
|
||||
.nss_pin = SX127X_PARAM_SPI_NSS, \
|
||||
.reset_pin = SX127X_PARAM_RESET, \
|
||||
.dio0_pin = SX127X_PARAM_DIO0, \
|
||||
.dio1_pin = SX127X_PARAM_DIO1, \
|
||||
.dio2_pin = SX127X_PARAM_DIO2, \
|
||||
.dio3_pin = SX127X_PARAM_DIO3 }
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
* @brief SX127X configuration
|
||||
*/
|
||||
static const sx127x_params_t sx127x_params[] =
|
||||
{
|
||||
#ifdef SX127X_PARAMS_BOARD
|
||||
SX127X_PARAMS_BOARD,
|
||||
#else
|
||||
SX127X_PARAMS_DEFAULT,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SX127X_PARAMS_H */
|
||||
/** @} */
|
||||
1426
drivers/sx127x/include/sx127x_registers.h
Normal file
1426
drivers/sx127x/include/sx127x_registers.h
Normal file
File diff suppressed because it is too large
Load Diff
422
drivers/sx127x/sx127x.c
Normal file
422
drivers/sx127x/sx127x.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 Inria Chile
|
||||
* 2017 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Basic functionality of sx127x driver
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xtimer.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "sx127x.h"
|
||||
#include "sx127x_internal.h"
|
||||
#include "sx127x_registers.h"
|
||||
#include "sx127x_netdev.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* Internal functions */
|
||||
static void _init_isrs(sx127x_t *dev);
|
||||
static void _init_timers(sx127x_t *dev);
|
||||
static int _init_peripherals(sx127x_t *dev);
|
||||
static void _on_tx_timeout(void *arg);
|
||||
static void _on_rx_timeout(void *arg);
|
||||
|
||||
/* SX127X DIO interrupt handlers initialization */
|
||||
static void sx127x_on_dio0_isr(void *arg);
|
||||
static void sx127x_on_dio1_isr(void *arg);
|
||||
static void sx127x_on_dio2_isr(void *arg);
|
||||
static void sx127x_on_dio3_isr(void *arg);
|
||||
|
||||
|
||||
void sx127x_setup(sx127x_t *dev, const sx127x_params_t *params)
|
||||
{
|
||||
netdev_t *netdev = (netdev_t*) dev;
|
||||
netdev->driver = &sx127x_driver;
|
||||
memcpy(&dev->params, params, sizeof(sx127x_params_t));
|
||||
}
|
||||
|
||||
void sx127x_reset(const sx127x_t *dev)
|
||||
{
|
||||
/*
|
||||
* This reset scheme complies with 7.2 chapter of the SX1272/1276 datasheet
|
||||
* See http://www.semtech.com/images/datasheet/sx1276.pdf for SX1276
|
||||
* See http://www.semtech.com/images/datasheet/sx1272.pdf for SX1272
|
||||
*
|
||||
* 1. Set NReset pin to LOW for at least 100 us
|
||||
* 2. Set NReset in Hi-Z state
|
||||
* 3. Wait at least 5 milliseconds
|
||||
*/
|
||||
gpio_init(dev->params.reset_pin, GPIO_OUT);
|
||||
|
||||
/* Set reset pin to 0 */
|
||||
gpio_clear(dev->params.reset_pin);
|
||||
|
||||
/* Wait 1 ms */
|
||||
xtimer_usleep(1000);
|
||||
|
||||
/* Put reset pin in High-Z */
|
||||
gpio_init(dev->params.reset_pin, GPIO_IN);
|
||||
|
||||
/* Wait 10 ms */
|
||||
xtimer_usleep(1000 * 10);
|
||||
}
|
||||
|
||||
int sx127x_init(sx127x_t *dev)
|
||||
{
|
||||
/* Do internal initialization routines */
|
||||
if (!_init_peripherals(dev)) {
|
||||
return -SX127X_ERR_SPI;
|
||||
}
|
||||
|
||||
/* Check presence of SX127X */
|
||||
if (!sx127x_test(dev)) {
|
||||
DEBUG("[Error] init : sx127x test failed\n");
|
||||
return -SX127X_ERR_TEST_FAILED;
|
||||
}
|
||||
|
||||
_init_timers(dev);
|
||||
xtimer_usleep(1000); /* wait 1 millisecond */
|
||||
|
||||
sx127x_reset(dev);
|
||||
|
||||
sx127x_rx_chain_calibration(dev);
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_SLEEP);
|
||||
|
||||
_init_isrs(dev);
|
||||
|
||||
return SX127X_INIT_OK;
|
||||
}
|
||||
|
||||
void sx127x_init_radio_settings(sx127x_t *dev)
|
||||
{
|
||||
sx127x_set_freq_hop(dev, SX127X_FREQUENCY_HOPPING);
|
||||
sx127x_set_iq_invert(dev, SX127X_IQ_INVERSION);
|
||||
sx127x_set_rx_single(dev, SX127X_RX_SINGLE);
|
||||
sx127x_set_tx_timeout(dev, SX127X_TX_TIMEOUT_DEFAULT);
|
||||
sx127x_set_modem(dev, SX127X_MODEM_DEFAULT);
|
||||
sx127x_set_channel(dev, SX127X_CHANNEL_DEFAULT);
|
||||
sx127x_set_bandwidth(dev, SX127X_BW_DEFAULT);
|
||||
sx127x_set_spreading_factor(dev, SX127X_SF_DEFAULT);
|
||||
sx127x_set_coding_rate(dev, SX127X_CR_DEFAULT);
|
||||
|
||||
sx127x_set_fixed_header_len_mode(dev, SX127X_FIXED_HEADER_LEN_MODE);
|
||||
sx127x_set_crc(dev, SX127X_PAYLOAD_CRC_ON);
|
||||
sx127x_set_symbol_timeout(dev, SX127X_SYMBOL_TIMEOUT);
|
||||
sx127x_set_preamble_length(dev, SX127X_PREAMBLE_LENGTH);
|
||||
sx127x_set_payload_length(dev, SX127X_PAYLOAD_LENGTH);
|
||||
sx127x_set_hop_period(dev, SX127X_FREQUENCY_HOPPING_PERIOD);
|
||||
|
||||
sx127x_set_tx_power(dev, SX127X_RADIO_TX_POWER);
|
||||
}
|
||||
|
||||
uint32_t sx127x_random(sx127x_t *dev)
|
||||
{
|
||||
uint32_t rnd = 0;
|
||||
|
||||
sx127x_set_modem(dev, SX127X_MODEM_LORA); /* Set LoRa modem ON */
|
||||
|
||||
/* Disable LoRa modem interrupts */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK, SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR |
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
SX127X_RF_LORA_IRQFLAGS_TXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* Set radio in continuous reception */
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_RECEIVER);
|
||||
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
xtimer_usleep(1000); /* wait for the chaos */
|
||||
|
||||
/* Non-filtered RSSI value reading. Only takes the LSB value */
|
||||
rnd |= ((uint32_t) sx127x_reg_read(dev, SX127X_REG_LR_RSSIWIDEBAND) & 0x01) << i;
|
||||
}
|
||||
|
||||
sx127x_set_sleep(dev);
|
||||
|
||||
return rnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* IRQ handlers
|
||||
*/
|
||||
void sx127x_isr(netdev_t *dev)
|
||||
{
|
||||
if (dev->event_callback) {
|
||||
dev->event_callback(dev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
}
|
||||
|
||||
static void sx127x_on_dio_isr(sx127x_t *dev, sx127x_flags_t flag)
|
||||
{
|
||||
dev->irq |= flag;
|
||||
sx127x_isr((netdev_t *)dev);
|
||||
}
|
||||
|
||||
static void sx127x_on_dio0_isr(void *arg)
|
||||
{
|
||||
sx127x_on_dio_isr((sx127x_t*) arg, SX127X_IRQ_DIO0);
|
||||
}
|
||||
|
||||
static void sx127x_on_dio1_isr(void *arg)
|
||||
{
|
||||
sx127x_on_dio_isr((sx127x_t*) arg, SX127X_IRQ_DIO1);
|
||||
}
|
||||
|
||||
static void sx127x_on_dio2_isr(void *arg)
|
||||
{
|
||||
sx127x_on_dio_isr((sx127x_t*) arg, SX127X_IRQ_DIO2);
|
||||
}
|
||||
|
||||
static void sx127x_on_dio3_isr(void *arg)
|
||||
{
|
||||
sx127x_on_dio_isr((sx127x_t*) arg, SX127X_IRQ_DIO3);
|
||||
}
|
||||
|
||||
/* Internal event handlers */
|
||||
void sx127x_on_dio0(void *arg)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_t *) arg;
|
||||
netdev_t *netdev = (netdev_t*) &dev->netdev;
|
||||
|
||||
switch (dev->settings.state) {
|
||||
case SX127X_RF_RX_RUNNING:
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
|
||||
break;
|
||||
case SX127X_RF_TX_RUNNING:
|
||||
xtimer_remove(&dev->_internal.tx_timeout_timer);
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_LORA:
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS,
|
||||
SX127X_RF_LORA_IRQFLAGS_TXDONE);
|
||||
/* Intentional fall-through */
|
||||
case SX127X_MODEM_FSK:
|
||||
default:
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SX127X_RF_IDLE:
|
||||
printf("sx127x_on_dio0: IDLE state\n");
|
||||
break;
|
||||
default:
|
||||
printf("sx127x_on_dio0: Unknown state [%d]\n", dev->settings.state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x_on_dio1(void *arg)
|
||||
{
|
||||
/* Get interrupt context */
|
||||
sx127x_t *dev = (sx127x_t *) arg;
|
||||
netdev_t *netdev = (netdev_t*) &dev->netdev;
|
||||
|
||||
switch (dev->settings.state) {
|
||||
case SX127X_RF_RX_RUNNING:
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
xtimer_remove(&dev->_internal.rx_timeout_timer);
|
||||
/* Clear Irq */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS, SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT);
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_RX_TIMEOUT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SX127X_RF_TX_RUNNING:
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
puts("sx127x_on_dio1: Unknown state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x_on_dio2(void *arg)
|
||||
{
|
||||
/* Get interrupt context */
|
||||
sx127x_t *dev = (sx127x_t *) arg;
|
||||
netdev_t *netdev = (netdev_t*) dev;
|
||||
|
||||
switch (dev->settings.state) {
|
||||
case SX127X_RF_RX_RUNNING:
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
if (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) {
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS,
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL);
|
||||
|
||||
dev->_internal.last_channel = (sx127x_reg_read(dev, SX127X_REG_LR_HOPCHANNEL) &
|
||||
SX127X_RF_LORA_HOPCHANNEL_CHANNEL_MASK);
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_FHSS_CHANGE_CHANNEL);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SX127X_RF_TX_RUNNING:
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
if (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) {
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS,
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL);
|
||||
|
||||
dev->_internal.last_channel = (sx127x_reg_read(dev, SX127X_REG_LR_HOPCHANNEL) &
|
||||
SX127X_RF_LORA_HOPCHANNEL_CHANNEL_MASK);
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_FHSS_CHANGE_CHANNEL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
puts("sx127x_on_dio2: Unknown state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x_on_dio3(void *arg)
|
||||
{
|
||||
/* Get interrupt context */
|
||||
sx127x_t *dev = (sx127x_t *) arg;
|
||||
netdev_t *netdev = (netdev_t *) dev;
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS,
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE);
|
||||
|
||||
/* Send event message */
|
||||
dev->_internal.is_last_cad_success = (sx127x_reg_read(dev, SX127X_REG_LR_IRQFLAGS) &
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED) == SX127X_RF_LORA_IRQFLAGS_CADDETECTED;
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_CAD_DONE);
|
||||
break;
|
||||
default:
|
||||
puts("sx127x_on_dio3: Unknown modem");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _init_isrs(sx127x_t *dev)
|
||||
{
|
||||
if (gpio_init_int(dev->params.dio0_pin, GPIO_IN, GPIO_RISING, sx127x_on_dio0_isr, dev) < 0) {
|
||||
DEBUG("Error: cannot initialize DIO0 pin\n");
|
||||
}
|
||||
|
||||
if (gpio_init_int(dev->params.dio1_pin, GPIO_IN, GPIO_RISING, sx127x_on_dio1_isr, dev) < 0) {
|
||||
DEBUG("Error: cannot initialize DIO1 pin\n");
|
||||
}
|
||||
|
||||
if (gpio_init_int(dev->params.dio2_pin, GPIO_IN, GPIO_RISING, sx127x_on_dio2_isr, dev) < 0) {
|
||||
DEBUG("Error: cannot initialize DIO2 pin\n");
|
||||
}
|
||||
|
||||
if (gpio_init_int(dev->params.dio3_pin, GPIO_IN, GPIO_RISING, sx127x_on_dio3_isr, dev) < 0) {
|
||||
DEBUG("Error: cannot initialize DIO3 pin\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _on_tx_timeout(void *arg)
|
||||
{
|
||||
netdev_t *dev = (netdev_t *) arg;
|
||||
|
||||
dev->event_callback(dev, NETDEV_EVENT_TX_TIMEOUT);
|
||||
}
|
||||
|
||||
static void _on_rx_timeout(void *arg)
|
||||
{
|
||||
netdev_t *dev = (netdev_t *) arg;
|
||||
|
||||
dev->event_callback(dev, NETDEV_EVENT_RX_TIMEOUT);
|
||||
}
|
||||
|
||||
static void _init_timers(sx127x_t *dev)
|
||||
{
|
||||
dev->_internal.tx_timeout_timer.arg = dev;
|
||||
dev->_internal.tx_timeout_timer.callback = _on_tx_timeout;
|
||||
|
||||
dev->_internal.rx_timeout_timer.arg = dev;
|
||||
dev->_internal.rx_timeout_timer.callback = _on_rx_timeout;
|
||||
}
|
||||
|
||||
static int _init_peripherals(sx127x_t *dev)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Setup SPI for SX127X */
|
||||
res = spi_init_cs(dev->params.spi, dev->params.nss_pin);
|
||||
|
||||
if (res != SPI_OK) {
|
||||
DEBUG("sx127x: error initializing SPI_%i device (code %i)\n",
|
||||
dev->params.spi, res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = gpio_init(dev->params.nss_pin, GPIO_OUT);
|
||||
if (res < 0) {
|
||||
DEBUG("sx127x: error initializing GPIO_%ld as CS line (code %i)\n",
|
||||
(long)dev->params.nss_pin, res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gpio_set(dev->params.nss_pin);
|
||||
|
||||
DEBUG("sx127x: peripherals initialized with success\n");
|
||||
return 1;
|
||||
}
|
||||
850
drivers/sx127x/sx127x_getset.c
Normal file
850
drivers/sx127x/sx127x_getset.c
Normal file
@ -0,0 +1,850 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 Inria Chile
|
||||
* 2017 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Implementation of get and set functions for SX127X
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "sx127x.h"
|
||||
#include "sx127x_registers.h"
|
||||
#include "sx127x_internal.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
uint8_t sx127x_get_state(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.state;
|
||||
}
|
||||
|
||||
void sx127x_set_state(sx127x_t *dev, uint8_t state)
|
||||
{
|
||||
#if ENABLE_DEBUG
|
||||
switch (state) {
|
||||
case SX127X_RF_IDLE:
|
||||
DEBUG("[DEBUG] Change state: IDLE\n");
|
||||
break;
|
||||
case SX127X_RF_RX_RUNNING:
|
||||
DEBUG("[DEBUG] Change state: RX\n");
|
||||
break;
|
||||
case SX127X_RF_TX_RUNNING:
|
||||
DEBUG("[DEBUG] Change state: TX\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG("[DEBUG] Change state: UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
dev->settings.state = state;
|
||||
}
|
||||
|
||||
void sx127x_set_modem(sx127x_t *dev, uint8_t modem)
|
||||
{
|
||||
DEBUG("[DEBUG] set modem: %d\n", modem);
|
||||
|
||||
dev->settings.modem = modem;
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* Todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_SLEEP);
|
||||
sx127x_reg_write(dev, SX127X_REG_OPMODE,
|
||||
(sx127x_reg_read(dev, SX127X_REG_OPMODE) &
|
||||
SX127X_RF_LORA_OPMODE_LONGRANGEMODE_MASK) |
|
||||
SX127X_RF_LORA_OPMODE_LONGRANGEMODE_ON);
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1, 0x00);
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING2, 0x00);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_syncword(const sx127x_t *dev)
|
||||
{
|
||||
return sx127x_reg_read(dev, SX127X_REG_LR_SYNCWORD);
|
||||
}
|
||||
|
||||
void sx127x_set_syncword(sx127x_t *dev, uint8_t syncword)
|
||||
{
|
||||
DEBUG("[DEBUG] Set syncword: %d\n", syncword);
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_SYNCWORD, syncword);
|
||||
}
|
||||
|
||||
uint32_t sx127x_get_channel(const sx127x_t *dev)
|
||||
{
|
||||
return (((uint32_t)sx127x_reg_read(dev, SX127X_REG_FRFMSB) << 16) |
|
||||
(sx127x_reg_read(dev, SX127X_REG_FRFMID) << 8) |
|
||||
(sx127x_reg_read(dev, SX127X_REG_FRFLSB))) * SX127X_FREQUENCY_RESOLUTION;
|
||||
}
|
||||
|
||||
void sx127x_set_channel(sx127x_t *dev, uint32_t channel)
|
||||
{
|
||||
DEBUG("[DEBUG] Set channel: %lu\n", channel);
|
||||
|
||||
/* Save current operating mode */
|
||||
dev->settings.channel = channel;
|
||||
|
||||
channel = (uint32_t)((double) channel / (double) SX127X_FREQUENCY_RESOLUTION);
|
||||
|
||||
/* Write frequency settings into chip */
|
||||
sx127x_reg_write(dev, SX127X_REG_FRFMSB, (uint8_t)((channel >> 16) & 0xFF));
|
||||
sx127x_reg_write(dev, SX127X_REG_FRFMID, (uint8_t)((channel >> 8) & 0xFF));
|
||||
sx127x_reg_write(dev, SX127X_REG_FRFLSB, (uint8_t)(channel & 0xFF));
|
||||
}
|
||||
|
||||
uint32_t sx127x_get_time_on_air(const sx127x_t *dev, uint8_t pkt_len)
|
||||
{
|
||||
uint32_t air_time = 0;
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
{
|
||||
double bw = 0.0;
|
||||
|
||||
/* Note: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported. */
|
||||
switch (dev->settings.lora.bandwidth) {
|
||||
case SX127X_BW_125_KHZ:
|
||||
bw = 125e3;
|
||||
break;
|
||||
case SX127X_BW_250_KHZ:
|
||||
bw = 250e3;
|
||||
break;
|
||||
case SX127X_BW_500_KHZ:
|
||||
bw = 500e3;
|
||||
break;
|
||||
default:
|
||||
DEBUG("Invalid bandwith: %d\n", dev->settings.lora.bandwidth);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Symbol rate : time for one symbol [secs] */
|
||||
double rs = bw / (1 << dev->settings.lora.datarate);
|
||||
double ts = 1 / rs;
|
||||
|
||||
/* time of preamble */
|
||||
double t_preamble = (dev->settings.lora.preamble_len + 4.25) * ts;
|
||||
|
||||
/* Symbol length of payload and time */
|
||||
double tmp =
|
||||
ceil(
|
||||
(8 * pkt_len - 4 * dev->settings.lora.datarate + 28
|
||||
+ 16 * (dev->settings.lora.flags & SX127X_ENABLE_CRC_FLAG)
|
||||
- (!(dev->settings.lora.flags & SX127X_ENABLE_FIXED_HEADER_LENGTH_FLAG) ? 20 : 0))
|
||||
/ (double) (4 * dev->settings.lora.datarate
|
||||
- (((dev->settings.lora.flags & SX127X_LOW_DATARATE_OPTIMIZE_FLAG)
|
||||
> 0) ? 2 : 0)))
|
||||
* (dev->settings.lora.coderate + 4);
|
||||
double n_payload = 8 + ((tmp > 0) ? tmp : 0);
|
||||
double t_payload = n_payload * ts;
|
||||
|
||||
/* Time on air */
|
||||
double t_on_air = t_preamble + t_payload;
|
||||
|
||||
/* return milli seconds */
|
||||
air_time = floor(t_on_air * 1e3 + 0.999);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return air_time;
|
||||
}
|
||||
|
||||
void sx127x_set_sleep(sx127x_t *dev)
|
||||
{
|
||||
DEBUG("[DEBUG] Set sleep\n");
|
||||
|
||||
/* Disable running timers */
|
||||
xtimer_remove(&dev->_internal.tx_timeout_timer);
|
||||
xtimer_remove(&dev->_internal.rx_timeout_timer);
|
||||
|
||||
/* Put chip into sleep */
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_SLEEP);
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
}
|
||||
|
||||
void sx127x_set_standby(sx127x_t *dev)
|
||||
{
|
||||
DEBUG("[DEBUG] Set standby\n");
|
||||
|
||||
/* Disable running timers */
|
||||
xtimer_remove(&dev->_internal.tx_timeout_timer);
|
||||
xtimer_remove(&dev->_internal.rx_timeout_timer);
|
||||
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_STANDBY);
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
}
|
||||
|
||||
void sx127x_set_rx(sx127x_t *dev)
|
||||
{
|
||||
DEBUG("[DEBUG] Set RX\n");
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
{
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_INVERTIQ2,
|
||||
((dev->settings.lora.flags & SX127X_IQ_INVERTED_FLAG) ? SX127X_RF_LORA_INVERTIQ2_ON : SX127X_RF_LORA_INVERTIQ2_OFF));
|
||||
|
||||
#if defined(MODULE_SX1276)
|
||||
/* ERRATA 2.3 - Receiver Spurious Reception of a LoRa Signal */
|
||||
if (dev->settings.lora.bandwidth < 9) {
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTOPTIMIZE,
|
||||
sx127x_reg_read(dev, SX127X_REG_LR_DETECTOPTIMIZE) & 0x7F);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST30, 0x00);
|
||||
switch (dev->settings.lora.bandwidth) {
|
||||
case SX127X_BW_125_KHZ: /* 125 kHz */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST2F, 0x40);
|
||||
break;
|
||||
case SX127X_BW_250_KHZ: /* 250 kHz */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST2F, 0x40);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTOPTIMIZE,
|
||||
sx127x_reg_read(dev, SX127X_REG_LR_DETECTOPTIMIZE) | 0x80);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup interrupts */
|
||||
if (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) {
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
/* SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR | */
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
SX127X_RF_LORA_IRQFLAGS_TXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
/* SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL | */
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* DIO0=RxDone, DIO2=FhssChangeChannel */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_MASK &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO2_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_00 |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO2_00);
|
||||
}
|
||||
else {
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
/* SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR | */
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
SX127X_RF_LORA_IRQFLAGS_TXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* DIO0=RxDone */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_00);
|
||||
}
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_FIFORXBASEADDR, 0);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_FIFOADDRPTR, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sx127x_set_state(dev, SX127X_RF_RX_RUNNING);
|
||||
if (dev->settings.window_timeout != 0) {
|
||||
xtimer_set(&(dev->_internal.rx_timeout_timer),
|
||||
dev->settings.window_timeout);
|
||||
}
|
||||
|
||||
if (dev->settings.lora.flags & SX127X_RX_CONTINUOUS_FLAG) {
|
||||
sx127x_set_op_mode(dev, SX127X_RF_LORA_OPMODE_RECEIVER);
|
||||
}
|
||||
else {
|
||||
sx127x_set_op_mode(dev, SX127X_RF_LORA_OPMODE_RECEIVER_SINGLE);
|
||||
}
|
||||
}
|
||||
|
||||
void sx127x_set_tx(sx127x_t *dev)
|
||||
{
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
{
|
||||
if (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) {
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR |
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
/* RFLR_IRQFLAGS_TXDONE | */
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
/* RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | */
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* DIO0=TxDone, DIO2=FhssChangeChannel */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1 ) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_MASK &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO2_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_01 |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO2_00);
|
||||
}
|
||||
else
|
||||
{
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR |
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
/* RFLR_IRQFLAGS_TXDONE | */
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* DIO0=TxDone */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_01);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
sx127x_set_state(dev, SX127X_RF_RX_RUNNING);
|
||||
if (dev->settings.window_timeout != 0) {
|
||||
xtimer_set(&(dev->_internal.tx_timeout_timer),
|
||||
dev->settings.window_timeout);
|
||||
}
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_TRANSMITTER );
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_max_payload_len(const sx127x_t *dev)
|
||||
{
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
return sx127x_reg_read(dev, SX127X_REG_PAYLOADLENGTH);
|
||||
|
||||
case SX127X_MODEM_LORA:
|
||||
return sx127x_reg_read(dev, SX127X_REG_LR_PAYLOADMAXLENGTH);
|
||||
}
|
||||
|
||||
/* should never be reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sx127x_set_max_payload_len(const sx127x_t *dev, uint8_t maxlen)
|
||||
{
|
||||
DEBUG("[DEBUG] Set max payload len: %d\n", maxlen);
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
sx127x_reg_write(dev, SX127X_REG_PAYLOADLENGTH, maxlen);
|
||||
break;
|
||||
|
||||
case SX127X_MODEM_LORA:
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_PAYLOADMAXLENGTH, maxlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_op_mode(const sx127x_t *dev)
|
||||
{
|
||||
return sx127x_reg_read(dev, SX127X_REG_OPMODE) & ~SX127X_RF_OPMODE_MASK;
|
||||
}
|
||||
|
||||
void sx127x_set_op_mode(const sx127x_t *dev, uint8_t op_mode)
|
||||
{
|
||||
#if ENABLE_DEBUG
|
||||
switch(op_mode) {
|
||||
case SX127X_RF_OPMODE_SLEEP:
|
||||
DEBUG("[DEBUG] Set op mode: SLEEP\n");
|
||||
break;
|
||||
case SX127X_RF_OPMODE_STANDBY:
|
||||
DEBUG("[DEBUG] Set op mode: STANDBY\n");
|
||||
break;
|
||||
case SX127X_RF_OPMODE_RECEIVER:
|
||||
DEBUG("[DEBUG] Set op mode: RECEIVER\n");
|
||||
break;
|
||||
case SX127X_RF_OPMODE_TRANSMITTER:
|
||||
DEBUG("[DEBUG] Set op mode: TRANSMITTER\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG("[DEBUG] Set op mode: UNKNOWN\n");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Replace previous mode value and setup new mode value */
|
||||
sx127x_reg_write(dev, SX127X_REG_OPMODE,
|
||||
(sx127x_reg_read(dev, SX127X_REG_OPMODE) & SX127X_RF_OPMODE_MASK) | op_mode);
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_bandwidth(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.bandwidth;
|
||||
}
|
||||
|
||||
inline void _low_datarate_optimize(sx127x_t *dev)
|
||||
{
|
||||
if ( ((dev->settings.lora.bandwidth == SX127X_BW_125_KHZ) &&
|
||||
((dev->settings.lora.datarate == SX127X_SF11) ||
|
||||
(dev->settings.lora.datarate == SX127X_SF12))) ||
|
||||
((dev->settings.lora.bandwidth == SX127X_BW_250_KHZ) &&
|
||||
(dev->settings.lora.datarate == SX127X_SF12))) {
|
||||
dev->settings.lora.flags |= SX127X_LOW_DATARATE_OPTIMIZE_FLAG;
|
||||
} else {
|
||||
dev->settings.lora.flags &= ~SX127X_LOW_DATARATE_OPTIMIZE_FLAG;
|
||||
}
|
||||
|
||||
#if defined(MODULE_SX1272)
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1) &
|
||||
SX127X_RF_LORA_MODEMCONFIG1_LOWDATARATEOPTIMIZE_MASK) |
|
||||
((dev->settings.lora.flags & SX127X_LOW_DATARATE_OPTIMIZE_FLAG)));
|
||||
#else /* MODULE_SX1276 */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG3,
|
||||
(sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG3) &
|
||||
SX127X_RF_LORA_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK) |
|
||||
((dev->settings.lora.flags & SX127X_LOW_DATARATE_OPTIMIZE_FLAG) << 3));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void _update_bandwidth(const sx127x_t *dev)
|
||||
{
|
||||
uint8_t config1_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1);
|
||||
#if defined(MODULE_SX1272)
|
||||
config1_reg &= SX1272_RF_LORA_MODEMCONFIG1_BW_MASK;
|
||||
switch (dev->settings.lora.bandwidth) {
|
||||
case SX127X_BW_125_KHZ:
|
||||
config1_reg |= SX1272_RF_LORA_MODEMCONFIG1_BW_125_KHZ;
|
||||
break;
|
||||
case SX127X_BW_250_KHZ:
|
||||
config1_reg |= SX1272_RF_LORA_MODEMCONFIG1_BW_250_KHZ;
|
||||
break;
|
||||
case SX127X_BW_500_KHZ:
|
||||
config1_reg |= SX1272_RF_LORA_MODEMCONFIG1_BW_500_KHZ;
|
||||
break;
|
||||
default:
|
||||
DEBUG("Unsupported bandwidth, %d", dev->settings.lora.bandwidth);
|
||||
break;
|
||||
}
|
||||
#else /* MODULE_SX1276 */
|
||||
config1_reg &= SX1276_RF_LORA_MODEMCONFIG1_BW_MASK;
|
||||
switch (dev->settings.lora.bandwidth) {
|
||||
case SX127X_BW_125_KHZ:
|
||||
config1_reg |= SX1276_RF_LORA_MODEMCONFIG1_BW_125_KHZ;
|
||||
break;
|
||||
case SX127X_BW_250_KHZ:
|
||||
config1_reg |= SX1276_RF_LORA_MODEMCONFIG1_BW_250_KHZ;
|
||||
break;
|
||||
case SX127X_BW_500_KHZ:
|
||||
config1_reg |= SX1276_RF_LORA_MODEMCONFIG1_BW_500_KHZ;
|
||||
break;
|
||||
default:
|
||||
DEBUG("Unsupported bandwidth, %d", dev->settings.lora.bandwidth);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG1, config1_reg);
|
||||
}
|
||||
|
||||
void sx127x_set_bandwidth(sx127x_t *dev, uint8_t bandwidth)
|
||||
{
|
||||
DEBUG("[DEBUG] Set bandwidth: %d\n", bandwidth);
|
||||
|
||||
dev->settings.lora.bandwidth = bandwidth;
|
||||
|
||||
_update_bandwidth((const sx127x_t *)dev);
|
||||
|
||||
_low_datarate_optimize(dev);
|
||||
|
||||
/* ERRATA sensitivity tweaks */
|
||||
if ((dev->settings.lora.bandwidth == SX127X_BW_500_KHZ) &&
|
||||
(dev->settings.channel > SX127X_RF_MID_BAND_THRESH)) {
|
||||
/* ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST36, 0x02);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST3A, 0x64);
|
||||
}
|
||||
else if (dev->settings.lora.bandwidth == SX127X_BW_500_KHZ) {
|
||||
/* ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST36, 0x02);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST3A, 0x7F);
|
||||
}
|
||||
else {
|
||||
/* ERRATA 2.1 - Sensitivity Optimization with another Bandwidth */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_TEST36, 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_spreading_factor(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.datarate;
|
||||
}
|
||||
|
||||
void sx127x_set_spreading_factor(sx127x_t *dev, uint8_t datarate)
|
||||
{
|
||||
DEBUG("[DEBUG] Set spreading factor: %d\n", datarate);
|
||||
|
||||
if (datarate == SX127X_SF6 &&
|
||||
!(dev->settings.lora.flags & SX127X_ENABLE_FIXED_HEADER_LENGTH_FLAG)) {
|
||||
/* SF 6 is only valid when using explicit header mode */
|
||||
DEBUG("Spreading Factor 6 can only be used when explicit header "
|
||||
"mode is set, this mode is not supported by this driver."
|
||||
"Ignoring.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->settings.lora.datarate = datarate;
|
||||
|
||||
uint8_t config2_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG2);
|
||||
config2_reg &= SX127X_RF_LORA_MODEMCONFIG2_SF_MASK;
|
||||
config2_reg |= datarate << 4;
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG2, config2_reg);
|
||||
|
||||
_low_datarate_optimize(dev);
|
||||
|
||||
switch(dev->settings.lora.datarate) {
|
||||
case SX127X_SF6:
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTOPTIMIZE,
|
||||
SX127X_RF_LORA_DETECTIONOPTIMIZE_SF6);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTIONTHRESHOLD,
|
||||
SX127X_RF_LORA_DETECTIONTHRESH_SF6);
|
||||
break;
|
||||
default:
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTOPTIMIZE,
|
||||
SX127X_RF_LORA_DETECTIONOPTIMIZE_SF7_TO_SF12);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_DETECTIONTHRESHOLD,
|
||||
SX127X_RF_LORA_DETECTIONTHRESH_SF7_TO_SF12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_coding_rate(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.coderate;
|
||||
}
|
||||
|
||||
void sx127x_set_coding_rate(sx127x_t *dev, uint8_t coderate)
|
||||
{
|
||||
DEBUG("[DEBUG] Set coding rate: %d\n", coderate);
|
||||
|
||||
dev->settings.lora.coderate = coderate;
|
||||
uint8_t config1_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1);
|
||||
|
||||
#if defined(MODULE_SX1272)
|
||||
config1_reg &= SX1272_RF_LORA_MODEMCONFIG1_CODINGRATE_MASK;
|
||||
config1_reg |= coderate << 3;
|
||||
#else /* MODULE_SX1276 */
|
||||
config1_reg &= SX1276_RF_LORA_MODEMCONFIG1_CODINGRATE_MASK;
|
||||
config1_reg |= coderate << 1;
|
||||
#endif
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG1, config1_reg);
|
||||
}
|
||||
|
||||
static inline void _set_flag(sx127x_t *dev, uint8_t flag, bool value)
|
||||
{
|
||||
if (value) {
|
||||
dev->settings.lora.flags |= flag;
|
||||
}
|
||||
else {
|
||||
dev->settings.lora.flags &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
bool sx127x_get_rx_single(const sx127x_t *dev)
|
||||
{
|
||||
return !(dev->settings.lora.flags & SX127X_RX_CONTINUOUS_FLAG);
|
||||
}
|
||||
|
||||
void sx127x_set_rx_single(sx127x_t *dev, bool single)
|
||||
{
|
||||
DEBUG("[DEBUG] Set RX single: %d\n", single);
|
||||
_set_flag(dev, SX127X_RX_CONTINUOUS_FLAG, !single);
|
||||
}
|
||||
|
||||
bool sx127x_get_crc(const sx127x_t *dev)
|
||||
{
|
||||
#if defined(MODULE_SX1272)
|
||||
return (sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1) &
|
||||
SX1272_RF_LORA_MODEMCONFIG1_RXPAYLOADCRC_MASK);
|
||||
#else /* MODULE_SX1276 */
|
||||
return (sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG2) &
|
||||
SX1276_RF_LORA_MODEMCONFIG2_RXPAYLOADCRC_MASK);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sx127x_set_crc(sx127x_t *dev, bool crc)
|
||||
{
|
||||
DEBUG("[DEBUG] Set CRC: %d\n", crc);
|
||||
_set_flag(dev, SX127X_ENABLE_CRC_FLAG, crc);
|
||||
|
||||
#if defined(MODULE_SX1272)
|
||||
uint8_t config2_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1);
|
||||
config2_reg &= SX1272_RF_LORA_MODEMCONFIG1_RXPAYLOADCRC_MASK;
|
||||
config2_reg |= crc << 1;
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG1, config2_reg);
|
||||
#else /* MODULE_SX1276 */
|
||||
uint8_t config2_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG2);
|
||||
config2_reg &= SX1276_RF_LORA_MODEMCONFIG2_RXPAYLOADCRC_MASK;
|
||||
config2_reg |= crc << 2;
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG2, config2_reg);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_hop_period(const sx127x_t *dev)
|
||||
{
|
||||
return sx127x_reg_read(dev, SX127X_REG_LR_HOPPERIOD);
|
||||
}
|
||||
|
||||
void sx127x_set_hop_period(sx127x_t *dev, uint8_t hop_period)
|
||||
{
|
||||
DEBUG("[DEBUG] Set Hop period: %d\n", hop_period);
|
||||
|
||||
dev->settings.lora.freq_hop_period = hop_period;
|
||||
|
||||
uint8_t tmp = sx127x_reg_read(dev, SX127X_REG_LR_PLLHOP);
|
||||
if (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) {
|
||||
tmp |= SX127X_RF_LORA_PLLHOP_FASTHOP_ON;
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_PLLHOP, tmp);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_HOPPERIOD, hop_period);
|
||||
}
|
||||
}
|
||||
|
||||
bool sx127x_get_fixed_header_len_mode(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.flags & SX127X_ENABLE_FIXED_HEADER_LENGTH_FLAG;
|
||||
}
|
||||
|
||||
void sx127x_set_fixed_header_len_mode(sx127x_t *dev, bool fixed_len)
|
||||
{
|
||||
DEBUG("[DEBUG] Set fixed header length: %d\n", fixed_len);
|
||||
|
||||
_set_flag(dev, SX127X_ENABLE_FIXED_HEADER_LENGTH_FLAG, fixed_len);
|
||||
|
||||
uint8_t config1_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG1);
|
||||
#if defined(MODULE_SX1272)
|
||||
config1_reg &= SX1272_RF_LORA_MODEMCONFIG1_IMPLICITHEADER_MASK;
|
||||
config1_reg |= fixed_len << 2;
|
||||
#else /* MODULE_SX1276 */
|
||||
config1_reg &= SX1276_RF_LORA_MODEMCONFIG1_IMPLICITHEADER_MASK;
|
||||
config1_reg |= fixed_len;
|
||||
#endif
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG1, config1_reg);
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_payload_length(const sx127x_t *dev)
|
||||
{
|
||||
return sx127x_reg_read(dev, SX127X_REG_LR_PAYLOADLENGTH);;
|
||||
}
|
||||
|
||||
void sx127x_set_payload_length(sx127x_t *dev, uint8_t len)
|
||||
{
|
||||
DEBUG("[DEBUG] Set payload len: %d\n", len);
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_PAYLOADLENGTH, len);
|
||||
}
|
||||
|
||||
static inline uint8_t sx127x_get_pa_select(uint32_t channel)
|
||||
{
|
||||
#if defined(MODULE_SX1272)
|
||||
(void) channel;
|
||||
#if SX1272_DEFAULT_PASELECT
|
||||
return SX127X_RF_PACONFIG_PASELECT_RFO;
|
||||
#else
|
||||
return SX127X_RF_PACONFIG_PASELECT_PABOOST;
|
||||
#endif
|
||||
#else /* MODULE_SX1276 */
|
||||
if (channel < SX127X_RF_MID_BAND_THRESH) {
|
||||
return SX127X_RF_PACONFIG_PASELECT_PABOOST;
|
||||
}
|
||||
else {
|
||||
return SX127X_RF_PACONFIG_PASELECT_RFO;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t sx127x_get_tx_power(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.power;
|
||||
}
|
||||
|
||||
void sx127x_set_tx_power(sx127x_t *dev, uint8_t power)
|
||||
{
|
||||
DEBUG("[DEBUG] Set power: %d\n", power);
|
||||
|
||||
dev->settings.lora.power = power;
|
||||
|
||||
uint8_t pa_config = sx127x_reg_read(dev, SX127X_REG_PACONFIG);
|
||||
#if defined(MODULE_SX1272)
|
||||
uint8_t pa_dac = sx127x_reg_read(dev, SX1272_REG_PADAC);
|
||||
#else /* MODULE_SX1276 */
|
||||
uint8_t pa_dac = sx127x_reg_read(dev, SX1276_REG_PADAC);
|
||||
#endif
|
||||
|
||||
pa_config = ((pa_config & SX127X_RF_PACONFIG_PASELECT_MASK) |
|
||||
sx127x_get_pa_select(dev->settings.channel));
|
||||
|
||||
#if defined(MODULE_SX1276)
|
||||
/* max power is 14dBm */
|
||||
pa_config = (pa_config & SX127X_RF_PACONFIG_MAX_POWER_MASK) | 0x70;
|
||||
#endif
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_PARAMP, SX127X_RF_PARAMP_0050_US);
|
||||
|
||||
if ((pa_config & SX127X_RF_PACONFIG_PASELECT_PABOOST)
|
||||
== SX127X_RF_PACONFIG_PASELECT_PABOOST) {
|
||||
if (power > 17) {
|
||||
pa_dac = ((pa_dac & SX127X_RF_PADAC_20DBM_MASK) |
|
||||
SX127X_RF_PADAC_20DBM_ON);
|
||||
} else {
|
||||
pa_dac = ((pa_dac & SX127X_RF_PADAC_20DBM_MASK) |
|
||||
SX127X_RF_PADAC_20DBM_OFF);
|
||||
}
|
||||
if ((pa_dac & SX127X_RF_PADAC_20DBM_ON) == SX127X_RF_PADAC_20DBM_ON) {
|
||||
if (power < 5) {
|
||||
power = 5;
|
||||
}
|
||||
if (power > 20) {
|
||||
power = 20;
|
||||
}
|
||||
|
||||
pa_config = ((pa_config & SX127X_RF_PACONFIG_OUTPUTPOWER_MASK) |
|
||||
(uint8_t)((uint16_t)(power - 5) & 0x0F));
|
||||
} else {
|
||||
if (power < 2) {
|
||||
power = 2;
|
||||
}
|
||||
if (power > 17) {
|
||||
power = 17;
|
||||
}
|
||||
|
||||
pa_config = ((pa_config & SX127X_RF_PACONFIG_OUTPUTPOWER_MASK) |
|
||||
(uint8_t)((uint16_t)(power - 2) & 0x0F));
|
||||
}
|
||||
} else {
|
||||
if (power < -1) {
|
||||
power = -1;
|
||||
}
|
||||
if (power > 14) {
|
||||
power = 14;
|
||||
}
|
||||
|
||||
pa_config = ((pa_config & SX127X_RF_PACONFIG_OUTPUTPOWER_MASK) |
|
||||
(uint8_t)((uint16_t)(power + 1) & 0x0F));
|
||||
}
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_PACONFIG, pa_config);
|
||||
#if defined(MODULE_SX1272)
|
||||
sx127x_reg_write(dev, SX1272_REG_PADAC, pa_dac);
|
||||
#else /* MODULE_SX1276 */
|
||||
sx127x_reg_write(dev, SX1276_REG_PADAC, pa_dac);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t sx127x_get_preamble_length(const sx127x_t *dev)
|
||||
{
|
||||
return dev->settings.lora.preamble_len;
|
||||
}
|
||||
|
||||
void sx127x_set_preamble_length(sx127x_t *dev, uint16_t preamble)
|
||||
{
|
||||
DEBUG("[DEBUG] Set preamble length: %d\n", preamble);
|
||||
|
||||
dev->settings.lora.preamble_len = preamble;
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_PREAMBLEMSB,
|
||||
(preamble >> 8) & 0xFF);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_PREAMBLELSB,
|
||||
preamble & 0xFF);
|
||||
}
|
||||
|
||||
void sx127x_set_rx_timeout(sx127x_t *dev, uint32_t timeout)
|
||||
{
|
||||
DEBUG("[DEBUG] Set RX timeout: %lu\n", timeout);
|
||||
|
||||
dev->settings.lora.rx_timeout = timeout;
|
||||
}
|
||||
|
||||
void sx127x_set_tx_timeout(sx127x_t *dev, uint32_t timeout)
|
||||
{
|
||||
DEBUG("[DEBUG] Set TX timeout: %lu\n", timeout);
|
||||
|
||||
dev->settings.lora.tx_timeout = timeout;
|
||||
}
|
||||
|
||||
void sx127x_set_symbol_timeout(sx127x_t *dev, uint16_t timeout)
|
||||
{
|
||||
DEBUG("[DEBUG] Set symbol timeout: %d\n", timeout);
|
||||
|
||||
dev->settings.lora.rx_timeout = timeout;
|
||||
|
||||
uint8_t config2_reg = sx127x_reg_read(dev, SX127X_REG_LR_MODEMCONFIG2);
|
||||
config2_reg &= SX127X_RF_LORA_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK;
|
||||
config2_reg |= (timeout >> 8) & ~SX127X_RF_LORA_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK;
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_MODEMCONFIG2, config2_reg);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_SYMBTIMEOUTLSB,timeout & 0xFF);
|
||||
}
|
||||
|
||||
void sx127x_set_iq_invert(sx127x_t *dev, bool iq_invert)
|
||||
{
|
||||
DEBUG("[DEBUG] Set IQ invert: %d\n", iq_invert);
|
||||
|
||||
_set_flag(dev, SX127X_IQ_INVERTED_FLAG, iq_invert);
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_INVERTIQ,
|
||||
(sx127x_reg_read(dev, SX127X_REG_LR_INVERTIQ) &
|
||||
SX127X_RF_LORA_INVERTIQ_RX_MASK &
|
||||
SX127X_RF_LORA_INVERTIQ_TX_MASK) |
|
||||
SX127X_RF_LORA_INVERTIQ_RX_OFF |
|
||||
(iq_invert ? SX127X_RF_LORA_INVERTIQ_TX_ON : SX127X_RF_LORA_INVERTIQ_TX_OFF));
|
||||
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_INVERTIQ2,
|
||||
(iq_invert ? SX127X_RF_LORA_INVERTIQ2_ON : SX127X_RF_LORA_INVERTIQ2_OFF));
|
||||
}
|
||||
|
||||
void sx127x_set_freq_hop(sx127x_t *dev, bool freq_hop_on)
|
||||
{
|
||||
DEBUG("[DEBUG] Set freq hop: %d\n", freq_hop_on);
|
||||
|
||||
_set_flag(dev, SX127X_CHANNEL_HOPPING_FLAG, freq_hop_on);
|
||||
}
|
||||
220
drivers/sx127x/sx127x_internal.c
Normal file
220
drivers/sx127x/sx127x_internal.c
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 Inria Chile
|
||||
* 2017 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief implementation of internal functions for sx127x
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "irq.h"
|
||||
|
||||
#include "sx127x.h"
|
||||
#include "sx127x_registers.h"
|
||||
#include "sx127x_internal.h"
|
||||
#include "sx127x_params.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
bool sx127x_test(const sx127x_t *dev)
|
||||
{
|
||||
/* Read version number and compare with sx127x assigned revision */
|
||||
uint8_t version = sx127x_reg_read(dev, SX127X_REG_VERSION);
|
||||
|
||||
#if defined(MODULE_SX1272)
|
||||
if (version != VERSION_SX1272) {
|
||||
DEBUG("[Error] sx1272 test failed, invalid version number: %d\n",
|
||||
version);
|
||||
return false;
|
||||
}
|
||||
DEBUG("SX1272 transceiver detected.\n");
|
||||
#else /* MODULE_SX1276) */
|
||||
if (version != VERSION_SX1276) {
|
||||
DEBUG("[Error] sx1276 test failed, invalid version number: %d\n",
|
||||
version);
|
||||
return false;
|
||||
}
|
||||
DEBUG("SX1276 transceiver detected.\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sx127x_reg_write(const sx127x_t *dev, uint8_t addr, uint8_t data)
|
||||
{
|
||||
sx127x_reg_write_burst(dev, addr, &data, 1);
|
||||
}
|
||||
|
||||
uint8_t sx127x_reg_read(const sx127x_t *dev, uint8_t addr)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
sx127x_reg_read_burst(dev, addr, &data, 1);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void sx127x_reg_write_burst(const sx127x_t *dev, uint8_t addr, uint8_t *buffer,
|
||||
uint8_t size)
|
||||
{
|
||||
unsigned int cpsr;
|
||||
|
||||
spi_acquire(dev->params.spi, SPI_CS_UNDEF, SX127X_PARAM_SPI_MODE, SX127X_PARAM_SPI_SPEED);
|
||||
cpsr = irq_disable();
|
||||
|
||||
gpio_clear(dev->params.nss_pin);
|
||||
spi_transfer_regs(dev->params.spi, SPI_CS_UNDEF, addr | 0x80, (char *) buffer, NULL, size);
|
||||
gpio_set(dev->params.nss_pin);
|
||||
|
||||
irq_restore(cpsr);
|
||||
spi_release(dev->params.spi);
|
||||
}
|
||||
|
||||
void sx127x_reg_read_burst(const sx127x_t *dev, uint8_t addr, uint8_t *buffer,
|
||||
uint8_t size)
|
||||
{
|
||||
unsigned int cpsr;
|
||||
|
||||
cpsr = irq_disable();
|
||||
|
||||
spi_acquire(dev->params.spi, SPI_CS_UNDEF, SX127X_PARAM_SPI_MODE, SX127X_PARAM_SPI_SPEED);
|
||||
|
||||
gpio_clear(dev->params.nss_pin);
|
||||
spi_transfer_regs(dev->params.spi, SPI_CS_UNDEF, addr & 0x7F, NULL, (char *) buffer, size);
|
||||
gpio_set(dev->params.nss_pin);
|
||||
|
||||
spi_release(dev->params.spi);
|
||||
|
||||
irq_restore(cpsr);
|
||||
}
|
||||
|
||||
void sx127x_write_fifo(const sx127x_t *dev, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
sx127x_reg_write_burst(dev, 0, buffer, size);
|
||||
}
|
||||
|
||||
void sx127x_read_fifo(const sx127x_t *dev, uint8_t *buffer, uint8_t size)
|
||||
{
|
||||
sx127x_reg_read_burst(dev, 0, buffer, size);
|
||||
}
|
||||
|
||||
void sx127x_rx_chain_calibration(sx127x_t *dev)
|
||||
{
|
||||
uint8_t reg_pa_config_init_val;
|
||||
uint32_t initial_freq;
|
||||
|
||||
/* Save context */
|
||||
reg_pa_config_init_val = sx127x_reg_read(dev, SX127X_REG_PACONFIG);
|
||||
initial_freq = (double) (((uint32_t) sx127x_reg_read(dev, SX127X_REG_FRFMSB) << 16)
|
||||
| ((uint32_t) sx127x_reg_read(dev, SX127X_REG_FRFMID) << 8)
|
||||
| ((uint32_t) sx127x_reg_read(dev, SX127X_REG_FRFLSB))) * (double) SX127X_FREQUENCY_RESOLUTION;
|
||||
|
||||
/* Cut the PA just in case, RFO output, power = -1 dBm */
|
||||
sx127x_reg_write(dev, SX127X_REG_PACONFIG, 0x00);
|
||||
|
||||
/* Launch Rx chain calibration for LF band */
|
||||
sx127x_reg_write(dev,
|
||||
SX127X_REG_IMAGECAL,
|
||||
(sx127x_reg_read(dev, SX127X_REG_IMAGECAL) & SX127X_RF_IMAGECAL_IMAGECAL_MASK)
|
||||
| SX127X_RF_IMAGECAL_IMAGECAL_START);
|
||||
|
||||
while ((sx127x_reg_read(dev, SX127X_REG_IMAGECAL) & SX127X_RF_IMAGECAL_IMAGECAL_RUNNING)
|
||||
== SX127X_RF_IMAGECAL_IMAGECAL_RUNNING) {
|
||||
}
|
||||
|
||||
/* Set a frequency in HF band */
|
||||
sx127x_set_channel(dev, SX127X_HF_CHANNEL_DEFAULT);
|
||||
|
||||
/* Launch Rx chain calibration for HF band */
|
||||
sx127x_reg_write(dev,
|
||||
SX127X_REG_IMAGECAL,
|
||||
(sx127x_reg_read(dev, SX127X_REG_IMAGECAL) & SX127X_RF_IMAGECAL_IMAGECAL_MASK)
|
||||
| SX127X_RF_IMAGECAL_IMAGECAL_START);
|
||||
while ((sx127x_reg_read(dev, SX127X_REG_IMAGECAL) & SX127X_RF_IMAGECAL_IMAGECAL_RUNNING)
|
||||
== SX127X_RF_IMAGECAL_IMAGECAL_RUNNING) {
|
||||
}
|
||||
|
||||
/* Restore context */
|
||||
sx127x_reg_write(dev, SX127X_REG_PACONFIG, reg_pa_config_init_val);
|
||||
sx127x_set_channel(dev, initial_freq);
|
||||
}
|
||||
|
||||
int16_t sx127x_read_rssi(const sx127x_t *dev)
|
||||
{
|
||||
int16_t rssi = 0;
|
||||
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
rssi = -(sx127x_reg_read(dev, SX127X_REG_RSSIVALUE) >> 1);
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
#if defined(MODULE_SX1272)
|
||||
rssi = SX127X_RSSI_OFFSET + sx127x_reg_read(dev, SX127X_REG_LR_RSSIVALUE);
|
||||
#else /* MODULE_SX1276 */
|
||||
if (dev->settings.channel > SX127X_RF_MID_BAND_THRESH) {
|
||||
rssi = SX127X_RSSI_OFFSET_HF + sx127x_reg_read(dev, SX127X_REG_LR_RSSIVALUE);
|
||||
}
|
||||
else {
|
||||
rssi = SX127X_RSSI_OFFSET_LF + sx127x_reg_read(dev, SX127X_REG_LR_RSSIVALUE);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
rssi = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
void sx127x_start_cad(sx127x_t *dev)
|
||||
{
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
/* Disable all interrupts except CAD-related */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR |
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
SX127X_RF_LORA_IRQFLAGS_TXDONE |
|
||||
/*SX127X_RF_LORA_IRQFLAGS_CADDONE |*/
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL
|
||||
/* | SX127X_RF_LORA_IRQFLAGS_CADDETECTED*/
|
||||
);
|
||||
|
||||
/* DIO3 = CADDone */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO3_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO3_00);
|
||||
|
||||
sx127x_set_state(dev, SX127X_RF_CAD);
|
||||
sx127x_set_op_mode(dev, SX127X_RF_LORA_OPMODE_CAD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
540
drivers/sx127x/sx127x_netdev.c
Normal file
540
drivers/sx127x/sx127x_netdev.c
Normal file
@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Fundación Inria Chile
|
||||
*
|
||||
* 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_sx127x
|
||||
* @{
|
||||
* @file
|
||||
* @brief Netdev adaptation for the sx127x driver
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "net/netopt.h"
|
||||
#include "net/netdev.h"
|
||||
#include "sx127x_registers.h"
|
||||
#include "sx127x_internal.h"
|
||||
#include "sx127x_netdev.h"
|
||||
#include "sx127x.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* Internal helper functions */
|
||||
static uint8_t _get_tx_len(const struct iovec *vector, unsigned count);
|
||||
static int _set_state(sx127x_t *dev, netopt_state_t state);
|
||||
static int _get_state(sx127x_t *dev, void *val);
|
||||
|
||||
/* Netdev driver api functions */
|
||||
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count);
|
||||
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info);
|
||||
static int _init(netdev_t *netdev);
|
||||
static void _isr(netdev_t *netdev);
|
||||
static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len);
|
||||
static int _set(netdev_t *netdev, netopt_t opt, void *val, size_t len);
|
||||
|
||||
const netdev_driver_t sx127x_driver = {
|
||||
.send = _send,
|
||||
.recv = _recv,
|
||||
.init = _init,
|
||||
.isr = _isr,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
};
|
||||
|
||||
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_t*) netdev;
|
||||
|
||||
if (sx127x_get_state(dev) == SX127X_RF_TX_RUNNING) {
|
||||
DEBUG("[WARNING] Cannot send packet: radio alredy in transmitting "
|
||||
"state.\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
uint8_t size;
|
||||
size = _get_tx_len(vector, count);
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
/* Initializes the payload size */
|
||||
sx127x_set_payload_length(dev, size);
|
||||
|
||||
/* Full buffer used for Tx */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_FIFOTXBASEADDR, 0x00);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_FIFOADDRPTR, 0x00);
|
||||
|
||||
/* FIFO operations can not take place in Sleep mode
|
||||
* So wake up the chip */
|
||||
if (sx127x_get_op_mode(dev) == SX127X_RF_OPMODE_SLEEP) {
|
||||
sx127x_set_standby(dev);
|
||||
xtimer_usleep(SX127X_RADIO_WAKEUP_TIME); /* wait for chip wake up */
|
||||
}
|
||||
|
||||
/* Write payload buffer */
|
||||
for (size_t i = 0;i < count ; i++) {
|
||||
sx127x_write_fifo(dev, vector[i].iov_base, vector[i].iov_len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
puts("sx127x_netdev, Unsupported modem");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable TXDONE interrupt */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGSMASK,
|
||||
SX127X_RF_LORA_IRQFLAGS_RXTIMEOUT |
|
||||
SX127X_RF_LORA_IRQFLAGS_RXDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR |
|
||||
SX127X_RF_LORA_IRQFLAGS_VALIDHEADER |
|
||||
/* SX127X_RF_LORA_IRQFLAGS_TXDONE | */
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDONE |
|
||||
SX127X_RF_LORA_IRQFLAGS_FHSSCHANGEDCHANNEL |
|
||||
SX127X_RF_LORA_IRQFLAGS_CADDETECTED);
|
||||
|
||||
/* Set TXDONE interrupt to the DIO0 line */
|
||||
sx127x_reg_write(dev, SX127X_REG_DIOMAPPING1,
|
||||
(sx127x_reg_read(dev, SX127X_REG_DIOMAPPING1) &
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_MASK) |
|
||||
SX127X_RF_LORA_DIOMAPPING1_DIO0_01);
|
||||
|
||||
/* Start TX timeout timer */
|
||||
xtimer_set(&dev->_internal.tx_timeout_timer, dev->settings.lora.tx_timeout);
|
||||
|
||||
/* Put chip into transfer mode */
|
||||
sx127x_set_state(dev, SX127X_RF_TX_RUNNING);
|
||||
sx127x_set_op_mode(dev, SX127X_RF_OPMODE_TRANSMITTER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_t*) netdev;
|
||||
volatile uint8_t irq_flags = 0;
|
||||
uint8_t size = 0;
|
||||
switch (dev->settings.modem) {
|
||||
case SX127X_MODEM_FSK:
|
||||
/* todo */
|
||||
break;
|
||||
case SX127X_MODEM_LORA:
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS, SX127X_RF_LORA_IRQFLAGS_RXDONE);
|
||||
|
||||
irq_flags = sx127x_reg_read(dev, SX127X_REG_LR_IRQFLAGS);
|
||||
if ( (irq_flags & SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR_MASK) ==
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR) {
|
||||
/* Clear IRQ */
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_IRQFLAGS,
|
||||
SX127X_RF_LORA_IRQFLAGS_PAYLOADCRCERROR);
|
||||
|
||||
if (!(dev->settings.lora.flags & SX127X_RX_CONTINUOUS_FLAG)) {
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
}
|
||||
|
||||
xtimer_remove(&dev->_internal.rx_timeout_timer);
|
||||
netdev->event_callback(netdev, NETDEV_EVENT_CRC_ERROR);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
netdev_sx127x_lora_packet_info_t *packet_info = info;
|
||||
if (packet_info) {
|
||||
/* there is no LQI for LoRa */
|
||||
packet_info->lqi = 0;
|
||||
uint8_t snr_value = sx127x_reg_read(dev, SX127X_REG_LR_PKTSNRVALUE);
|
||||
if (snr_value & 0x80) { /* The SNR is negative */
|
||||
/* Invert and divide by 4 */
|
||||
packet_info->snr = -1 * ((~snr_value + 1) & 0xFF) >> 2;
|
||||
}
|
||||
else {
|
||||
/* Divide by 4 */
|
||||
packet_info->snr = (snr_value & 0xFF) >> 2;
|
||||
}
|
||||
|
||||
int16_t rssi = sx127x_reg_read(dev, SX127X_REG_LR_PKTRSSIVALUE);
|
||||
|
||||
if (packet_info->snr < 0) {
|
||||
#if defined(MODULE_SX1272)
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET + rssi + (rssi >> 4) + packet_info->snr;
|
||||
#else /* MODULE_SX1276 */
|
||||
if (dev->settings.channel > SX127X_RF_MID_BAND_THRESH) {
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET_HF + rssi + (rssi >> 4) + packet_info->snr;
|
||||
}
|
||||
else {
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET_LF + rssi + (rssi >> 4) + packet_info->snr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if defined(MODULE_SX1272)
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET + rssi + (rssi >> 4);
|
||||
#else /* MODULE_SX1276 */
|
||||
if (dev->settings.channel > SX127X_RF_MID_BAND_THRESH) {
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET_HF + rssi + (rssi >> 4);
|
||||
}
|
||||
else {
|
||||
packet_info->rssi = SX127X_RSSI_OFFSET_LF + rssi + (rssi >> 4);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
packet_info->time_on_air = sx127x_get_time_on_air(dev, len);
|
||||
}
|
||||
|
||||
size = sx127x_reg_read(dev, SX127X_REG_LR_RXNBBYTES);
|
||||
if (buf == NULL) {
|
||||
return size;
|
||||
}
|
||||
|
||||
if (size > len) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (!(dev->settings.lora.flags & SX127X_RX_CONTINUOUS_FLAG)) {
|
||||
sx127x_set_state(dev, SX127X_RF_IDLE);
|
||||
}
|
||||
|
||||
xtimer_remove(&dev->_internal.rx_timeout_timer);
|
||||
|
||||
/* Read the last packet from FIFO */
|
||||
uint8_t last_rx_addr = sx127x_reg_read(dev, SX127X_REG_LR_FIFORXCURRENTADDR);
|
||||
sx127x_reg_write(dev, SX127X_REG_LR_FIFOADDRPTR, last_rx_addr);
|
||||
sx127x_read_fifo(dev, (uint8_t*)buf, size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int _init(netdev_t *netdev)
|
||||
{
|
||||
sx127x_t *sx127x = (sx127x_t*) netdev;
|
||||
|
||||
sx127x->irq = 0;
|
||||
sx127x_radio_settings_t settings;
|
||||
settings.channel = SX127X_CHANNEL_DEFAULT;
|
||||
settings.modem = SX127X_MODEM_DEFAULT;
|
||||
settings.state = SX127X_RF_IDLE;
|
||||
|
||||
sx127x->settings = settings;
|
||||
|
||||
/* Launch initialization of driver and device */
|
||||
DEBUG("init_radio: initializing driver...\n");
|
||||
sx127x_init(sx127x);
|
||||
|
||||
sx127x_init_radio_settings(sx127x);
|
||||
/* Put chip into sleep */
|
||||
sx127x_set_sleep(sx127x);
|
||||
|
||||
DEBUG("init_radio: sx127x initialization done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _isr(netdev_t *netdev)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_t *) netdev;
|
||||
|
||||
uint8_t irq = dev->irq;
|
||||
dev->irq = 0;
|
||||
|
||||
switch (irq) {
|
||||
case SX127X_IRQ_DIO0:
|
||||
sx127x_on_dio0(dev);
|
||||
break;
|
||||
|
||||
case SX127X_IRQ_DIO1:
|
||||
sx127x_on_dio1(dev);
|
||||
break;
|
||||
|
||||
case SX127X_IRQ_DIO2:
|
||||
sx127x_on_dio2(dev);
|
||||
break;
|
||||
|
||||
case SX127X_IRQ_DIO3:
|
||||
sx127x_on_dio3(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_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_MODE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = dev->settings.modem;
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_CHANNEL:
|
||||
assert(max_len >= sizeof(uint32_t));
|
||||
*((uint32_t*) val) = sx127x_get_channel(dev);
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_BANDWIDTH:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = sx127x_get_bandwidth(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SPREADING_FACTOR:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = sx127x_get_spreading_factor(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_CODING_RATE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = sx127x_get_coding_rate(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_MAX_PACKET_SIZE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = sx127x_get_max_payload_len(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_INTEGRITY_CHECK:
|
||||
assert(max_len >= sizeof(netopt_enable_t));
|
||||
*((netopt_enable_t*) val) = sx127x_get_crc(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
break;
|
||||
|
||||
case NETOPT_CHANNEL_HOP:
|
||||
assert(max_len >= sizeof(netopt_enable_t));
|
||||
*((netopt_enable_t*) val) = (dev->settings.lora.flags & SX127X_CHANNEL_HOPPING_FLAG) ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
break;
|
||||
|
||||
case NETOPT_CHANNEL_HOP_PERIOD:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((uint8_t*) val) = sx127x_get_hop_period(dev);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SINGLE_RECEIVE:
|
||||
assert(max_len >= sizeof(uint8_t));
|
||||
*((netopt_enable_t*) val) = sx127x_get_rx_single(dev) ? NETOPT_ENABLE : NETOPT_DISABLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set(netdev_t *netdev, netopt_t opt, void *val, size_t len)
|
||||
{
|
||||
sx127x_t *dev = (sx127x_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, *((netopt_state_t*) val));
|
||||
|
||||
case NETOPT_DEVICE_MODE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx127x_set_modem(dev, *((uint8_t*) val));
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_CHANNEL:
|
||||
assert(len <= sizeof(uint32_t));
|
||||
sx127x_set_channel(dev, *((uint32_t*) val));
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_BANDWIDTH:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t bw = *((uint8_t *)val);
|
||||
if (bw < SX127X_BW_125_KHZ ||
|
||||
bw > SX127X_BW_500_KHZ) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx127x_set_bandwidth(dev, bw);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SPREADING_FACTOR:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t sf = *((uint8_t *)val);
|
||||
if (sf < SX127X_SF6 ||
|
||||
sf > SX127X_SF12) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx127x_set_spreading_factor(dev, sf);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_CODING_RATE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
uint8_t cr = *((uint8_t *)val);
|
||||
if (cr < SX127X_CR_4_5 ||
|
||||
cr > SX127X_CR_4_8) {
|
||||
res = -EINVAL;
|
||||
break;
|
||||
}
|
||||
sx127x_set_coding_rate(dev, cr);
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_MAX_PACKET_SIZE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx127x_set_max_payload_len(dev, *((uint8_t*) val));
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_INTEGRITY_CHECK:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx127x_set_crc(dev, *((netopt_enable_t*) val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_CHANNEL_HOP:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx127x_set_freq_hop(dev, *((netopt_enable_t*) val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_CHANNEL_HOP_PERIOD:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx127x_set_hop_period(dev, *((uint8_t*) val));
|
||||
return sizeof(uint8_t);
|
||||
|
||||
case NETOPT_SINGLE_RECEIVE:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx127x_set_rx_single(dev, *((netopt_enable_t*) val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RX_TIMEOUT:
|
||||
assert(len <= sizeof(uint32_t));
|
||||
sx127x_set_rx_timeout(dev, *((uint32_t*) val));
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_TX_TIMEOUT:
|
||||
assert(len <= sizeof(uint32_t));
|
||||
sx127x_set_tx_timeout(dev, *((uint32_t*) val));
|
||||
return sizeof(uint32_t);
|
||||
|
||||
case NETOPT_TX_POWER:
|
||||
assert(len <= sizeof(uint8_t));
|
||||
sx127x_set_tx_power(dev, *((uint8_t*) val));
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_FIXED_HEADER:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx127x_set_fixed_header_len_mode(dev, *((netopt_enable_t*) val) ? true : false);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_PREAMBLE_LENGTH:
|
||||
assert(len <= sizeof(uint16_t));
|
||||
sx127x_set_preamble_length(dev, *((uint16_t*) val));
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_IQ_INVERT:
|
||||
assert(len <= sizeof(netopt_enable_t));
|
||||
sx127x_set_iq_invert(dev, *((netopt_enable_t*) val) ? true : false);
|
||||
return sizeof(bool);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint8_t _get_tx_len(const struct iovec *vector, unsigned count)
|
||||
{
|
||||
uint8_t len = 0;
|
||||
|
||||
for (int i=0 ; i < count ; i++) {
|
||||
len += vector[i].iov_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _set_state(sx127x_t *dev, netopt_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case NETOPT_STATE_SLEEP:
|
||||
sx127x_set_sleep(dev);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_STANDBY:
|
||||
sx127x_set_standby(dev);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_IDLE:
|
||||
dev->settings.window_timeout = 0;
|
||||
/* set permanent listening */
|
||||
sx127x_set_rx(dev);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_RX:
|
||||
sx127x_set_rx(dev);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_TX:
|
||||
sx127x_set_tx(dev);
|
||||
break;
|
||||
|
||||
case NETOPT_STATE_RESET:
|
||||
sx127x_reset(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return sizeof(netopt_state_t);
|
||||
}
|
||||
|
||||
static int _get_state(sx127x_t *dev, void *val)
|
||||
{
|
||||
uint8_t op_mode;
|
||||
op_mode = sx127x_get_op_mode(dev);
|
||||
netopt_state_t state;
|
||||
switch(op_mode) {
|
||||
case SX127X_RF_OPMODE_SLEEP:
|
||||
state = NETOPT_STATE_SLEEP;
|
||||
break;
|
||||
|
||||
case SX127X_RF_OPMODE_STANDBY:
|
||||
state = NETOPT_STATE_STANDBY;
|
||||
break;
|
||||
|
||||
case SX127X_RF_OPMODE_TRANSMITTER:
|
||||
state = NETOPT_STATE_TX;
|
||||
break;
|
||||
|
||||
case SX127X_RF_OPMODE_RECEIVER:
|
||||
case SX127X_RF_LORA_OPMODE_RECEIVER_SINGLE:
|
||||
state = NETOPT_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
memcpy(val, &state, sizeof(netopt_state_t));
|
||||
return sizeof(netopt_state_t);
|
||||
}
|
||||
@ -76,5 +76,9 @@ PSEUDOMODULES += adc081c
|
||||
PSEUDOMODULES += adc101c
|
||||
PSEUDOMODULES += adc121c
|
||||
|
||||
# include variants of SX127X drivers as pseudo modules
|
||||
PSEUDOMODULES += sx1272
|
||||
PSEUDOMODULES += sx1276
|
||||
|
||||
# add all pseudo random number generator variants as pseudomodules
|
||||
PSEUDOMODULES += prng_%
|
||||
|
||||
@ -269,10 +269,81 @@ typedef enum {
|
||||
*/
|
||||
NETOPT_LAST_ED_LEVEL,
|
||||
|
||||
/**
|
||||
* @brief Get/Set preamble length as uint16_t in host byte order.
|
||||
*/
|
||||
NETOPT_PREAMBLE_LENGTH,
|
||||
|
||||
/**
|
||||
* @brief Enable/disable integrity check (e.g CRC).
|
||||
*/
|
||||
NETOPT_INTEGRITY_CHECK,
|
||||
|
||||
/**
|
||||
* @brief Enable/disable channel hopping.
|
||||
*/
|
||||
NETOPT_CHANNEL_HOP,
|
||||
|
||||
/**
|
||||
* @brief Get/Set channel hopping period as uint8_t.
|
||||
*/
|
||||
NETOPT_CHANNEL_HOP_PERIOD,
|
||||
|
||||
/**
|
||||
* @brief Enable/disable single packet reception.
|
||||
*
|
||||
* If enabled, RX is turned off upon reception of a packet
|
||||
*/
|
||||
NETOPT_SINGLE_RECEIVE,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the reception timeout of a packet.
|
||||
*
|
||||
* Values are retrieved/passed as uint32_t in host byte order.
|
||||
*/
|
||||
NETOPT_RX_TIMEOUT,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the transmission timeout of a packet.
|
||||
*
|
||||
* Values are retrieved/passed as uint32_t in host byte order.
|
||||
*/
|
||||
NETOPT_TX_TIMEOUT,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the radio modem type as uint8_t.
|
||||
*/
|
||||
NETOPT_DEVICE_MODE,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the radio modulation bandwidth as uint8_t.
|
||||
*/
|
||||
NETOPT_BANDWIDTH,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the radio spreading factor as uint8_t.
|
||||
*/
|
||||
NETOPT_SPREADING_FACTOR,
|
||||
|
||||
/**
|
||||
* @brief Get/Set the radio coding rate as uint8_t.
|
||||
*/
|
||||
NETOPT_CODING_RATE,
|
||||
|
||||
/**
|
||||
* @brief Enable/disable fixed header mode.
|
||||
*/
|
||||
NETOPT_FIXED_HEADER,
|
||||
|
||||
/**
|
||||
* @brief Enable/disable IQ inverted.
|
||||
*/
|
||||
NETOPT_IQ_INVERT,
|
||||
|
||||
/* add more options if needed */
|
||||
|
||||
/**
|
||||
* @brief maximum number of options defined here
|
||||
* @brief maximum number of options defined here.
|
||||
*
|
||||
* @note Interfaces are not meant to respond to that.
|
||||
*/
|
||||
@ -306,6 +377,8 @@ typedef enum {
|
||||
* transmitting a packet */
|
||||
NETOPT_STATE_RESET, /**< triggers a hardware reset. The resulting
|
||||
* state of the network device is @ref NETOPT_STATE_IDLE */
|
||||
NETOPT_STATE_STANDBY, /**< standby mode. The devices is awake but
|
||||
* not listening to packets. */
|
||||
/* add other states if needed */
|
||||
} netopt_state_t;
|
||||
|
||||
|
||||
@ -24,44 +24,57 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
static const char *_netopt_strmap[] = {
|
||||
[NETOPT_CHANNEL] = "NETOPT_CHANNEL",
|
||||
[NETOPT_IS_CHANNEL_CLR] = "NETOPT_IS_CHANNEL_CLR",
|
||||
[NETOPT_ADDRESS] = "NETOPT_ADDRESS",
|
||||
[NETOPT_ADDRESS_LONG] = "NETOPT_ADDRESS_LONG",
|
||||
[NETOPT_ADDR_LEN] = "NETOPT_ADDR_LEN",
|
||||
[NETOPT_SRC_LEN] = "NETOPT_SRC_LEN",
|
||||
[NETOPT_NID] = "NETOPT_NID",
|
||||
[NETOPT_IPV6_IID] = "NETOPT_IPV6_IID",
|
||||
[NETOPT_TX_POWER] = "NETOPT_TX_POWER",
|
||||
[NETOPT_MAX_PACKET_SIZE] = "NETOPT_MAX_PACKET_SIZE",
|
||||
[NETOPT_PRELOADING] = "NETOPT_PRELOADING",
|
||||
[NETOPT_PROMISCUOUSMODE] = "NETOPT_PROMISCUOUSMODE",
|
||||
[NETOPT_AUTOACK] = "NETOPT_AUTOACK",
|
||||
[NETOPT_ACK_REQ] = "NETOPT_ACK_REQ",
|
||||
[NETOPT_RETRANS] = "NETOPT_RETRANS",
|
||||
[NETOPT_PROTO] = "NETOPT_PROTO",
|
||||
[NETOPT_STATE] = "NETOPT_STATE",
|
||||
[NETOPT_RAWMODE] = "NETOPT_RAWMODE",
|
||||
[NETOPT_RX_START_IRQ] = "NETOPT_RX_START_IRQ",
|
||||
[NETOPT_RX_END_IRQ] = "NETOPT_RX_END_IRQ",
|
||||
[NETOPT_TX_START_IRQ] = "NETOPT_TX_START_IRQ",
|
||||
[NETOPT_TX_END_IRQ] = "NETOPT_TX_END_IRQ",
|
||||
[NETOPT_AUTOCCA] = "NETOPT_AUTOCCA",
|
||||
[NETOPT_CSMA] = "NETOPT_CSMA",
|
||||
[NETOPT_CSMA_RETRIES] = "NETOPT_CSMA_RETRIES",
|
||||
[NETOPT_IS_WIRED] = "NETOPT_IS_WIRED",
|
||||
[NETOPT_DEVICE_TYPE] = "NETOPT_DEVICE_TYPE",
|
||||
[NETOPT_CHANNEL_PAGE] = "NETOPT_CHANNEL_PAGE",
|
||||
[NETOPT_CCA_THRESHOLD] = "NETOPT_CCA_THRESHOLD",
|
||||
[NETOPT_CCA_MODE] = "NETOPT_CCA_MODE",
|
||||
[NETOPT_STATS] = "NETOPT_STATS",
|
||||
[NETOPT_ENCRYPTION] = "NETOPT_ENCRYPTION",
|
||||
[NETOPT_ENCRYPTION_KEY] = "NETOPT_ENCRYPTION_KEY",
|
||||
[NETOPT_RF_TESTMODE] = "NETOPT_RF_TESTMODE",
|
||||
[NETOPT_L2FILTER] = "NETOPT_L2FILTER",
|
||||
[NETOPT_L2FILTER_RM] = "NETOPT_L2FILTER_RM",
|
||||
[NETOPT_LAST_ED_LEVEL] = "NETOPT_LAST_ED_LEVEL",
|
||||
[NETOPT_NUMOF] = "NETOPT_NUMOF",
|
||||
[NETOPT_CHANNEL] = "NETOPT_CHANNEL",
|
||||
[NETOPT_IS_CHANNEL_CLR] = "NETOPT_IS_CHANNEL_CLR",
|
||||
[NETOPT_ADDRESS] = "NETOPT_ADDRESS",
|
||||
[NETOPT_ADDRESS_LONG] = "NETOPT_ADDRESS_LONG",
|
||||
[NETOPT_ADDR_LEN] = "NETOPT_ADDR_LEN",
|
||||
[NETOPT_SRC_LEN] = "NETOPT_SRC_LEN",
|
||||
[NETOPT_NID] = "NETOPT_NID",
|
||||
[NETOPT_IPV6_IID] = "NETOPT_IPV6_IID",
|
||||
[NETOPT_TX_POWER] = "NETOPT_TX_POWER",
|
||||
[NETOPT_MAX_PACKET_SIZE] = "NETOPT_MAX_PACKET_SIZE",
|
||||
[NETOPT_PRELOADING] = "NETOPT_PRELOADING",
|
||||
[NETOPT_PROMISCUOUSMODE] = "NETOPT_PROMISCUOUSMODE",
|
||||
[NETOPT_AUTOACK] = "NETOPT_AUTOACK",
|
||||
[NETOPT_ACK_REQ] = "NETOPT_ACK_REQ",
|
||||
[NETOPT_RETRANS] = "NETOPT_RETRANS",
|
||||
[NETOPT_PROTO] = "NETOPT_PROTO",
|
||||
[NETOPT_STATE] = "NETOPT_STATE",
|
||||
[NETOPT_RAWMODE] = "NETOPT_RAWMODE",
|
||||
[NETOPT_RX_START_IRQ] = "NETOPT_RX_START_IRQ",
|
||||
[NETOPT_RX_END_IRQ] = "NETOPT_RX_END_IRQ",
|
||||
[NETOPT_TX_START_IRQ] = "NETOPT_TX_START_IRQ",
|
||||
[NETOPT_TX_END_IRQ] = "NETOPT_TX_END_IRQ",
|
||||
[NETOPT_AUTOCCA] = "NETOPT_AUTOCCA",
|
||||
[NETOPT_CSMA] = "NETOPT_CSMA",
|
||||
[NETOPT_CSMA_RETRIES] = "NETOPT_CSMA_RETRIES",
|
||||
[NETOPT_IS_WIRED] = "NETOPT_IS_WIRED",
|
||||
[NETOPT_DEVICE_TYPE] = "NETOPT_DEVICE_TYPE",
|
||||
[NETOPT_CHANNEL_PAGE] = "NETOPT_CHANNEL_PAGE",
|
||||
[NETOPT_CCA_THRESHOLD] = "NETOPT_CCA_THRESHOLD",
|
||||
[NETOPT_CCA_MODE] = "NETOPT_CCA_MODE",
|
||||
[NETOPT_STATS] = "NETOPT_STATS",
|
||||
[NETOPT_ENCRYPTION] = "NETOPT_ENCRYPTION",
|
||||
[NETOPT_ENCRYPTION_KEY] = "NETOPT_ENCRYPTION_KEY",
|
||||
[NETOPT_RF_TESTMODE] = "NETOPT_RF_TESTMODE",
|
||||
[NETOPT_L2FILTER] = "NETOPT_L2FILTER",
|
||||
[NETOPT_L2FILTER_RM] = "NETOPT_L2FILTER_RM",
|
||||
[NETOPT_LAST_ED_LEVEL] = "NETOPT_LAST_ED_LEVEL",
|
||||
[NETOPT_DEVICE_MODE] = "NETOPT_DEVICE_MODE",
|
||||
[NETOPT_BANDWIDTH] = "NETOPT_BANDWIDTH",
|
||||
[NETOPT_SPREADING_FACTOR] = "NETOPT_SPREADING_FACTOR",
|
||||
[NETOPT_CODING_RATE] = "NETOPT_CODING_RATE",
|
||||
[NETOPT_SINGLE_RECEIVE] = "NETOPT_SINGLE_RECEIVE",
|
||||
[NETOPT_RX_TIMEOUT] = "NETOPT_RX_TIMEOUT",
|
||||
[NETOPT_TX_TIMEOUT] = "NETOPT_TX_TIMEOUT",
|
||||
[NETOPT_PREAMBLE_LENGTH] = "NETOPT_PREAMBLE_LENGTH",
|
||||
[NETOPT_INTEGRITY_CHECK] = "NETOPT_INTEGRITY_CHECK",
|
||||
[NETOPT_CHANNEL_HOP] = "NETOPT_CHANNEL_HOP",
|
||||
[NETOPT_CHANNEL_HOP_PERIOD] = "NETOPT_CHANNEL_HOP_PERIOD",
|
||||
[NETOPT_FIXED_HEADER] = "NETOPT_FIXED_HEADER",
|
||||
[NETOPT_IQ_INVERT] = "NETOPT_IQ_INVERT",
|
||||
[NETOPT_NUMOF] = "NETOPT_NUMOF",
|
||||
};
|
||||
|
||||
const char *netopt2str(netopt_t opt)
|
||||
|
||||
24
tests/driver_sx127x/Makefile
Normal file
24
tests/driver_sx127x/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
APPLICATION = driver_sx127x
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := nucleo32-f031
|
||||
|
||||
BOARD ?= nucleo-l1
|
||||
|
||||
USEMODULE += od
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
USEMODULE += xtimer
|
||||
|
||||
DRIVER ?= sx1276
|
||||
|
||||
# use SX1276 by default
|
||||
USEMODULE += ${DRIVER}
|
||||
|
||||
FEATURES_REQUIRED ?= periph_spi
|
||||
FEATURES_REQUIRED ?= periph_gpio
|
||||
|
||||
CFLAGS += -DDEVELHELP
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
134
tests/driver_sx127x/README.md
Normal file
134
tests/driver_sx127x/README.md
Normal file
@ -0,0 +1,134 @@
|
||||
## About
|
||||
|
||||
This is a manual test application for the SX127X radio driver.
|
||||
|
||||
This test application uses the default pin configuration provided by the
|
||||
driver implementation and that matches the ST Nucleo 64 pins layout.
|
||||
It is best to use [SX1272](https://developer.mbed.org/components/SX1272MB2xAS/)
|
||||
or [SX1276](https://developer.mbed.org/components/SX1276MB1xAS/) mbed modules
|
||||
with nucleo boards or the all-in-one
|
||||
[ST P-NUCLEO-LRWAN1 LoRa kit](http://www.st.com/en/evaluation-tools/p-nucleo-lrwan1.html).
|
||||
|
||||
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/sx127x/include/sx127x_params.h` file to your application directory.
|
||||
|
||||
By default the application builds the SX1276 version of the driver. If you
|
||||
want to use this application with a SX1272 module, set the variable `DRIVER` in
|
||||
the application [Makefile](Makefile):
|
||||
```
|
||||
DRIVER = sx1272
|
||||
```
|
||||
instead of
|
||||
```
|
||||
DRIVER = sx1276
|
||||
```
|
||||
You can also pass `DRIVER` when building the application:
|
||||
```
|
||||
$ make BOARD=nucleo-l073 DRIVER=sx1272 -C tests/drivers_sx127x flash term
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
This test application provides low level shell commands to interact with the
|
||||
SX1272/SX1276 modules.
|
||||
|
||||
Once the board is flashed and you are connected via serial to the shell, use the `help`
|
||||
command to display the available commands:
|
||||
```
|
||||
> help
|
||||
help
|
||||
Command Description
|
||||
---------------------------------------
|
||||
setup Initialize LoRa modulation settings
|
||||
random Get random number from sx127x
|
||||
channel Get/Set channel frequency (in Hz)
|
||||
register Get/Set value(s) of registers of sx127x
|
||||
send Send raw payload string
|
||||
listen Start raw payload listener
|
||||
reboot Reboot the node
|
||||
ps Prints information about running threads.
|
||||
```
|
||||
|
||||
Once the board is booted, use `setup` to configure the basic LoRa settings:
|
||||
* Bandwidth: 125kHz, 250kHz or 500kHz
|
||||
* Spreading factor: between 7 and 12
|
||||
* Code rate: between 5 and 8
|
||||
|
||||
Example:
|
||||
```
|
||||
> setup 125 12 5
|
||||
setup: setting 125KHz bandwidth
|
||||
[Info] setup: configuration set with success
|
||||
```
|
||||
|
||||
All values are supported by both SX1272 and SX1276.
|
||||
|
||||
The `random ` command use the Semtech to generate a random integer value.
|
||||
|
||||
Example:
|
||||
```
|
||||
> random
|
||||
random: number from sx127x: 2339536315
|
||||
> random
|
||||
random: number from sx127x: 863363442
|
||||
```
|
||||
|
||||
The `channel` command allows to change/query the RF frequency channel.
|
||||
The default is 868MHz for Europe, change to 915MHz for America. The frequency
|
||||
is given/returned in Hz.
|
||||
|
||||
Example:
|
||||
```
|
||||
> channel set 868000000
|
||||
New channel set
|
||||
> channel get
|
||||
Channel: 868000000
|
||||
```
|
||||
|
||||
The `register` command allows to get/set the content of the module registers.
|
||||
Example:
|
||||
```
|
||||
> register get all
|
||||
- listing all registers -
|
||||
Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x00 00 80 1A 0B 00 52 D9 00 00 0F 08 2B 00 4D 80 00
|
||||
0x10 00 FF 00 00 00 00 00 00 00 00 00 00 00 72 C4 0A
|
||||
0x20 00 08 01 FF 00 00 08 00 00 00 00 00 00 50 14 40
|
||||
0x30 00 03 05 67 1C 0A 00 0A 42 12 64 19 01 A1 00 00
|
||||
0x40 00 10 22 13 0E 5B DB 24 0E 81 3A 2E 00 03 00 00
|
||||
0x50 00 00 04 23 01 24 3F B0 09 05 84 0B D0 0B D0 32
|
||||
0x60 2B 14 00 00 10 00 00 00 0F E0 00 0C F6 10 1D 07
|
||||
0x70 00 5C 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
- done -
|
||||
```
|
||||
|
||||
Use the `send` and `receive` commands in order to exchange messages between several modules.
|
||||
You need first to ensure that all modules are configured the same: use `setup` and
|
||||
`channel` commands to configure them correctly.
|
||||
|
||||
Assuming you have 2 modules, one listening and one sending messages, do the following:
|
||||
* On listening module:
|
||||
```
|
||||
> setup 125 12 5
|
||||
setup: setting 125KHz bandwidth
|
||||
[Info] setup: configuration set with success
|
||||
> channel set 868000000
|
||||
New channel set
|
||||
> listen
|
||||
Listen mode set
|
||||
```
|
||||
* On sending module:
|
||||
```
|
||||
> setup 125 12 5
|
||||
setup: setting 125KHz bandwidth
|
||||
[Info] setup: configuration set with success
|
||||
> channel set 868000000
|
||||
New channel set
|
||||
> send This\ is\ RIOT!
|
||||
```
|
||||
|
||||
On the listening module, the message is captured:
|
||||
```
|
||||
{Payload: "This is RIOT!" (13 bytes), RSSI: 103, SNR: 240}
|
||||
```
|
||||
365
tests/driver_sx127x/main.c
Normal file
365
tests/driver_sx127x/main.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Unwired Devices <info@unwds.com>
|
||||
* 2017 Inria Chile
|
||||
* 2017 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 SX127X modem driver
|
||||
*
|
||||
* @author Eugene P. <ep@unwds.com>
|
||||
* @author José Ignacio Alamos <jose.alamos@inria.cl>
|
||||
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "thread.h"
|
||||
#include "xtimer.h"
|
||||
#include "shell.h"
|
||||
#include "shell_commands.h"
|
||||
|
||||
#include "net/gnrc/netdev.h"
|
||||
#include "net/netdev.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "periph/rtc.h"
|
||||
|
||||
#include "sx127x_internal.h"
|
||||
#include "sx127x_params.h"
|
||||
#include "sx127x_netdev.h"
|
||||
|
||||
#define SX127X_LORA_MSG_QUEUE (16U)
|
||||
#define SX127X_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
|
||||
#define MSG_TYPE_ISR (0x3456)
|
||||
|
||||
static char stack[SX127X_STACKSIZE];
|
||||
static kernel_pid_t _recv_pid;
|
||||
|
||||
static char message[32];
|
||||
static sx127x_t sx127x;
|
||||
static netdev_t *netdev;
|
||||
|
||||
int lora_setup_cmd(int argc, char **argv) {
|
||||
|
||||
if (argc < 4) {
|
||||
puts("usage: setup "
|
||||
"<bandwidth (125, 250, 500)> "
|
||||
"<spreading factor (7..12)> "
|
||||
"<code rate (5..8)>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check bandwidth value */
|
||||
int bw = atoi(argv[1]);
|
||||
uint8_t lora_bw;
|
||||
switch (bw) {
|
||||
case 125:
|
||||
puts("setup: setting 125KHz bandwidth");
|
||||
lora_bw = SX127X_BW_125_KHZ;
|
||||
break;
|
||||
|
||||
case 250:
|
||||
puts("setup: setting 250KHz bandwidth");
|
||||
lora_bw = SX127X_BW_250_KHZ;
|
||||
break;
|
||||
|
||||
case 500:
|
||||
puts("setup: setting 500KHz bandwidth");
|
||||
lora_bw = SX127X_BW_500_KHZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("[Error] setup: invalid bandwidth value given, "
|
||||
"only 125, 250 or 500 allowed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check spreading factor value */
|
||||
uint8_t lora_sf = atoi(argv[2]);
|
||||
if (lora_sf < 7 || lora_sf > 12) {
|
||||
puts("[Error] setup: invalid spreading factor value given");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check coding rate value */
|
||||
int cr = atoi(argv[3]);;
|
||||
if (cr < 5 || cr > 8) {
|
||||
puts("[Error ]setup: invalid coding rate value given");
|
||||
return -1;
|
||||
}
|
||||
uint8_t lora_cr = (uint8_t)(cr - 4);
|
||||
|
||||
/* Configure radio device */
|
||||
netdev_t *netdev = (netdev_t*) &sx127x;
|
||||
netdev->driver->set(netdev, NETOPT_BANDWIDTH,
|
||||
&lora_bw, sizeof(uint8_t));
|
||||
netdev->driver->set(netdev, NETOPT_SPREADING_FACTOR,
|
||||
&lora_sf, 1);
|
||||
netdev->driver->set(netdev, NETOPT_CODING_RATE,
|
||||
&lora_cr, sizeof(uint8_t));
|
||||
|
||||
puts("[Info] setup: configuration set with success");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int random_cmd(int argc, char **argv)
|
||||
{
|
||||
printf("random: number from sx127x: %u\n",
|
||||
(unsigned int) sx127x_random((sx127x_t*) netdev));
|
||||
|
||||
/* reinit the transceiver to default values */
|
||||
sx127x_init_radio_settings((sx127x_t*) netdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_cmd(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
puts("usage: register <get | set>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "get") != NULL) {
|
||||
if (argc < 3) {
|
||||
puts("usage: register get <all | allinline | regnum>");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(argv[2], "all") == 0) {
|
||||
puts("- listing all registers -");
|
||||
uint8_t reg = 0, data = 0;
|
||||
/* Listing registers map */
|
||||
puts("Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F");
|
||||
for (unsigned i = 0; i <= 7; i++) {
|
||||
printf("0x%02X ", i << 4);
|
||||
|
||||
for (unsigned j = 0; j <= 15; j++, reg++) {
|
||||
data = sx127x_reg_read(&sx127x, reg);
|
||||
printf("%02X ", data);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
puts("-done-");
|
||||
return 0;
|
||||
} else if (strcmp(argv[2], "allinline") == 0) {
|
||||
puts("- listing all registers in one line -");
|
||||
/* Listing registers map */
|
||||
for (uint16_t reg = 0; reg < 256; reg++) {
|
||||
printf("%02X ", sx127x_reg_read(&sx127x, (uint8_t) reg));
|
||||
}
|
||||
puts("- done -");
|
||||
return 0;
|
||||
} else {
|
||||
long int num = 0;
|
||||
/* Register number in hex */
|
||||
if (strstr(argv[2], "0x") != NULL) {
|
||||
num = strtol(argv[2], NULL, 16);
|
||||
} else {
|
||||
num = atoi(argv[2]);
|
||||
}
|
||||
if (num >= 0 && num <= 255) {
|
||||
printf("[regs] 0x%02X = 0x%02X\n",
|
||||
(uint8_t) num,
|
||||
sx127x_reg_read(&sx127x, (uint8_t) num));
|
||||
} else {
|
||||
puts("regs: invalid register number specified");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (strstr(argv[1], "set") != NULL) {
|
||||
if (argc < 4) {
|
||||
puts("usage: register set <regnum> <value>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long num, val;
|
||||
|
||||
/* Register number in hex */
|
||||
if (strstr(argv[2], "0x") != NULL) {
|
||||
num = strtol(argv[2], NULL, 16);
|
||||
} else {
|
||||
num = atoi(argv[2]);
|
||||
}
|
||||
|
||||
/* Register value in hex */
|
||||
if (strstr(argv[3], "0x") != NULL) {
|
||||
val = strtol(argv[3], NULL, 16);
|
||||
} else {
|
||||
val = atoi(argv[3]);
|
||||
}
|
||||
|
||||
sx127x_reg_write(&sx127x, (uint8_t) num, (uint8_t) val);
|
||||
}
|
||||
else {
|
||||
puts("usage: register get <all | allinline | regnum>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_cmd(int argc, char **argv)
|
||||
{
|
||||
if (argc <= 1) {
|
||||
puts("usage: send <payload>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("sending \"%s\" payload (%d bytes)\n",
|
||||
argv[1], strlen(argv[1]) + 1);
|
||||
|
||||
struct iovec vec[1];
|
||||
vec[0].iov_base = argv[1];
|
||||
vec[0].iov_len = strlen(argv[1]) + 1;
|
||||
if (netdev->driver->send(netdev, vec, 1) == -ENOTSUP) {
|
||||
puts("Cannot send: radio is still transmitting");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int listen_cmd(int argc, char **argv)
|
||||
{
|
||||
/* Switch to continuous listen mode */
|
||||
netdev->driver->set(netdev, NETOPT_SINGLE_RECEIVE, false, sizeof(uint8_t));
|
||||
sx127x_set_rx(&sx127x);
|
||||
|
||||
printf("Listen mode set\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int channel_cmd(int argc, char **argv)
|
||||
{
|
||||
if(argc < 2) {
|
||||
puts("usage: channel <get|set>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t chan;
|
||||
if (strstr(argv[1], "get") != NULL) {
|
||||
netdev->driver->get(netdev, NETOPT_CHANNEL, &chan, sizeof(uint32_t));
|
||||
printf("Channel: %i\n", (int) chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "set") != NULL) {
|
||||
if(argc < 3) {
|
||||
puts("usage: channel set <channel>");
|
||||
return -1;
|
||||
}
|
||||
chan = atoi(argv[2]);
|
||||
netdev->driver->set(netdev, NETOPT_CHANNEL, &chan, sizeof(uint32_t));
|
||||
printf("New channel set\n");
|
||||
}
|
||||
else {
|
||||
puts("usage: channel <get|set>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "setup", "Initialize LoRa modulation settings", lora_setup_cmd},
|
||||
{ "random", "Get random number from sx127x", random_cmd },
|
||||
{ "channel", "Get/Set channel frequency (in Hz)", channel_cmd },
|
||||
{ "register", "Get/Set value(s) of registers of sx127x", register_cmd },
|
||||
{ "send", "Send raw payload string", send_cmd },
|
||||
{ "listen", "Start raw payload listener", listen_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void _event_cb(netdev_t *dev, netdev_event_t event)
|
||||
{
|
||||
if (event == NETDEV_EVENT_ISR) {
|
||||
msg_t msg;
|
||||
|
||||
msg.type = MSG_TYPE_ISR;
|
||||
msg.content.ptr = dev;
|
||||
|
||||
if (msg_send(&msg, _recv_pid) <= 0) {
|
||||
puts("gnrc_netdev: possibly lost interrupt.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t len;
|
||||
netdev_sx127x_lora_packet_info_t packet_info;
|
||||
switch (event) {
|
||||
case NETDEV_EVENT_RX_COMPLETE:
|
||||
len = dev->driver->recv(dev, NULL, 0, 0);
|
||||
dev->driver->recv(dev, message, len, &packet_info);
|
||||
printf("{Payload: \"%s\" (%d bytes), RSSI: %i, SNR: %i, TOA: %i}\n",
|
||||
message, (int)len,
|
||||
packet_info.rssi, (int)packet_info.snr,
|
||||
(int)packet_info.time_on_air);
|
||||
break;
|
||||
case NETDEV_EVENT_TX_COMPLETE:
|
||||
puts("Transmission completed");
|
||||
break;
|
||||
case NETDEV_EVENT_CAD_DONE:
|
||||
break;
|
||||
case NETDEV_EVENT_TX_TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
printf("Unexpected netdev event received: %d\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *_recv_thread(void *arg)
|
||||
{
|
||||
static msg_t _msg_q[SX127X_LORA_MSG_QUEUE];
|
||||
msg_init_queue(_msg_q, SX127X_LORA_MSG_QUEUE);
|
||||
|
||||
while (1) {
|
||||
msg_t msg;
|
||||
msg_receive(&msg);
|
||||
if (msg.type == MSG_TYPE_ISR) {
|
||||
netdev_t *dev = msg.content.ptr;
|
||||
dev->driver->isr(dev);
|
||||
}
|
||||
else {
|
||||
puts("Unexpected msg type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
memcpy(&sx127x.params, sx127x_params, sizeof(sx127x_params));
|
||||
netdev = (netdev_t*) &sx127x;
|
||||
netdev->driver = &sx127x_driver;
|
||||
netdev->driver->init(netdev);
|
||||
netdev->event_callback = _event_cb;
|
||||
|
||||
_recv_pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST, _recv_thread, NULL,
|
||||
"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…
x
Reference in New Issue
Block a user