STM32CubeWL/Middlewares/Third_Party/SubGHz_Phy/stm32_radio_driver/radio.c

2416 lines
88 KiB
C

/*!
* \file radio.c
*
* \brief Radio driver API implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file radio.c
* @author MCD Application Team
* @brief Radio driver API definition
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include "radio.h"
#include "wl_lr_fhss.h"
#include "timer.h"
#include "radio_fw.h"
#include "radio_driver.h"
#include "radio_conf.h"
#include "mw_log_conf.h"
/* Private typedef -----------------------------------------------------------*/
/*!
* Radio hardware and global parameters
*/
typedef struct SubgRf_s
{
RadioModems_t Modem;
bool RxContinuous;
uint32_t TxTimeout;
uint32_t RxTimeout;
struct
{
bool Previous;
bool Current;
} PublicNetwork;
PacketParams_t PacketParams;
PacketStatus_t PacketStatus;
ModulationParams_t ModulationParams;
RadioIrqMasks_t RadioIrq;
uint8_t AntSwitchPaSelect;
uint32_t RxDcPreambleDetectTimeout; /* 0:RxDutyCycle is off, otherwise on with 2*rxTime + sleepTime (See STM32WL Errata: RadioSetRxDutyCycle)*/
#if( RADIO_LR_FHSS_IS_ON == 1 )
struct
{
uint32_t rf_freq_in_hz;
int8_t tx_rf_pwr_in_dbm;
bool is_lr_fhss_on;
uint16_t hop_sequence_id;
wl_lr_fhss_params_t lr_fhss_params;
wl_lr_fhss_state_t lr_fhss_state;
} lr_fhss;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
} SubgRf_t;
/* Private macro -------------------------------------------------------------*/
#define RADIO_BIT_MASK(__n) (~(1<<__n))
/**
* \brief Calculates ceiling division of ( X / N )
*
* \param [in] X numerator
* \param [in] N denominator
*
*/
#ifndef DIVC
#define DIVC( X, N ) ( ( ( X ) + ( N ) - 1 ) / ( N ) )
#endif
/**
* \brief Calculates rounding division of ( X / N )
*
* \param [in] X numerator
* \param [in] N denominator
*
*/
#ifndef DIVR
#define DIVR( X, N ) ( ( ( X ) + ( ((X)>0?(N):(N))>>1 ) ) / ( N ) )
#endif
/* Private define ------------------------------------------------------------*/
/* */
/*can be overridden in radio_conf.h*/
#ifndef RADIO_LR_FHSS_IS_ON
#define RADIO_LR_FHSS_IS_ON 0
#endif /* !RADIO_LR_FHSS_IS_ON */
/*can be overridden in radio_conf.h*/
#ifndef XTAL_FREQ
#define XTAL_FREQ 32000000UL
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_IRQ_PROCESS_INIT
#define RADIO_IRQ_PROCESS_INIT()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_IRQ_PROCESS
#define RADIO_IRQ_PROCESS() RadioIrqProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_RX_TIMEOUT_PROCESS
#define RADIO_RX_TIMEOUT_PROCESS() RadioOnRxTimeoutProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_TX_TIMEOUT_PROCESS
#define RADIO_TX_TIMEOUT_PROCESS() RadioOnTxTimeoutProcess()
#endif
/*can be overridden in radio_conf.h*/
#ifndef IRQ_TX_DBG
#define IRQ_TX_DBG ((uint16_t) 0)
#endif
/*can be overridden in radio_conf.h*/
#ifndef IRQ_RX_DBG
#define IRQ_RX_DBG ((uint16_t) 0)
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_SIGFOX_ENABLE
#define RADIO_SIGFOX_ENABLE 1
#endif
/*can be overridden in radio_conf.h*/
#ifndef RADIO_GENERIC_CONFIG_ENABLE
#define RADIO_GENERIC_CONFIG_ENABLE 1
#endif
/*can be overridden in radio_conf.h*/
#ifndef DBG_GPIO_RADIO_RX
#define DBG_GPIO_RADIO_RX(set_rst)
#endif
/*can be overridden in radio_conf.h*/
#ifndef DBG_GPIO_RADIO_TX
#define DBG_GPIO_RADIO_TX(set_rst)
#endif
#define RADIO_BUF_SIZE 255
/* Private function prototypes -----------------------------------------------*/
/*!
* \brief Initializes the radio
*
* \param [in] events Structure containing the driver callback functions
*/
static void RadioInit( RadioEvents_t *events );
/*!
* Return current radio status
*
* \return status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
static RadioState_t RadioGetStatus( void );
/*!
* \brief Configures the radio with the given modem
*
* \param [in] modem Modem to be used [0: FSK, 1: LoRa]
*/
static void RadioSetModem( RadioModems_t modem );
/*!
* \brief Sets the channel frequency
*
* \param [in] freq Channel RF frequency
*/
static void RadioSetChannel( uint32_t freq );
/*!
* \brief Checks if the channel is free for the given time
*
* \remark The FSK modem is always used for this task as we can select the Rx bandwidth at will.
*
* \param [in] freq Channel RF frequency in Hertz
* \param [in] rxBandwidth Rx bandwidth in Hertz
* \param [in] rssiThresh RSSI threshold in dBm
* \param [in] maxCarrierSenseTime Max time in milliseconds while the RSSI is measured
*
* \retval isFree [true: Channel is free, false: Channel is not free]
*/
static bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \brief Generates a 32 bits random value based on the RSSI readings
*
* \remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \retval randomValue 32 bits random value
*/
static uint32_t RadioRandom( void );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \param [in] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
static void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool FreqHopOn, uint8_t HopPeriod,
bool iqInverted, bool rxContinuous );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] power Sets the output power [dBm]
* \param [in] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \param [in] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \param [in] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [in] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [in] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [in] timeout Transmission timeout [ms]
*/
static void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool FreqHopOn,
uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
/*!
* \brief Checks if the given RF frequency is supported by the hardware
*
* \param [in] frequency RF frequency to be checked
* \retval isSupported [true: supported, false: unsupported]
*/
static bool RadioCheckRfFrequency( uint32_t frequency );
/*!
* \brief Computes the packet time on air in ms for the given payload
*
* \remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
static uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \param [in] buffer Buffer pointer
* \param [in] size Buffer size
*
* \retval status (OK, ERROR, ...)
*/
static radio_status_t RadioSend( uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the radio in sleep mode
*/
static void RadioSleep( void );
/*!
* \brief Sets the radio in standby mode
*/
static void RadioStandby( void );
/*!
* \brief Sets the radio in reception mode for the given time
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
static void RadioRx( uint32_t timeout );
/*!
* \brief Start a Channel Activity Detection
*/
static void RadioStartCad( void );
/*!
* \brief Sets the radio in continuous wave transmission mode
*
* \param [in] freq Channel RF frequency
* \param [in] power Sets the output power [dBm]
* \param [in] time Transmission mode timeout [s]
*/
static void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time );
/*!
* \brief Reads the current RSSI value
*
* \retval rssiValue Current RSSI value in [dBm]
*/
static int16_t RadioRssi( RadioModems_t modem );
/*!
* \brief Writes the radio register at the specified address
*
* \param [in] addr Register address
* \param [in] data New register value
*/
static void RadioWrite( uint16_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [in] addr Register address
* \retval data Register value
*/
static uint8_t RadioRead( uint16_t addr );
/*!
* \brief Writes multiple radio registers starting at address
*
* \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
*/
static void RadioWriteRegisters( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
* \param [in] addr First Radio register address
* \param [out] buffer Buffer where to copy the registers data
* \param [in] size Number of registers to be read
*/
static void RadioReadRegisters( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the maximum payload length.
*
* \param [in] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [in] max Maximum payload length in bytes
*/
static void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max );
/*!
* \brief Sets the network to public or private. Updates the sync byte.
*
* \remark Applies to LoRa modem only
*
* \param [in] enable if true, it enables a public network
*/
static void RadioSetPublicNetwork( bool enable );
/*!
* \brief Gets the time required for the board plus radio to get out of sleep.[ms]
*
* \retval time Radio plus board wakeup time in ms.
*/
static uint32_t RadioGetWakeupTime( void );
/*!
* \brief Process radio irq
*/
static void RadioIrqProcess( void );
/*!
* \brief Sets the radio in reception mode with Max LNA gain for the given time
* \param [in] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
static void RadioRxBoosted( uint32_t timeout );
/*!
* \brief Sets the Rx duty cycle management parameters
*
* \param [in] rxTime Structure describing reception timeout value
* \param [in] sleepTime Structure describing sleep timeout value
*/
static void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime );
/*!
* \brief radio IRQ callback
*
* \param [in] radioIrq mask of radio irq
*/
static void RadioOnDioIrq( RadioIrqMasks_t radioIrq );
/*!
* \brief Tx timeout timer callback
*
* \param [in] context context of the interrupt
*/
static void RadioOnTxTimeoutIrq( void *context );
/*!
* \brief Rx timeout timer callback
*
* \param [in] context context of the interrupt
*/
static void RadioOnRxTimeoutIrq( void *context );
/*!
* \brief Rx timeout timer process
*/
static void RadioOnRxTimeoutProcess( void );
/*!
* \brief Tx timeout timer process
*/
static void RadioOnTxTimeoutProcess( void );
#if( RADIO_LR_FHSS_IS_ON == 1 )
static uint32_t prbs31_val = 0xAA;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
#if (RADIO_SIGFOX_ENABLE == 1)
/*!
* @brief D-BPSK to BPSK
*
* @param [out] outBuffer buffer with frame encoded
* @param [in] inBuffer buffer with frame to encode
* @param [in] size size of the payload to encode
*/
static void payload_integration( uint8_t *outBuffer, uint8_t *inBuffer, uint8_t size );
#endif /*RADIO_SIGFOX_ENABLE == 1*/
/*!
* \brief Sets the Transmitter in continuous PRBS mode
*/
static void RadioTxPrbs( void );
/*!
* \brief Sets the Transmitter in continuous un-modulated Carrier mode at power dBm
*
* \param [in] power Tx power in dBm
*/
static void RadioTxCw( int8_t power );
/*!
* \brief Sets the reception parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
* \param [in] rxContinuous Sets the reception in continuous mode
* [0: single mode, otherwise continuous mode]
* \param [in] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \return 0 when no parameters error, -1 otherwise
*/
static int32_t RadioSetRxGenericConfig( GenericModems_t modem, RxConfigGeneric_t *config,
uint32_t rxContinuous, uint32_t symbTimeout );
/*!
* \brief Sets the transmission parameters
*
* \param [in] modem Radio modem to be used [GENERIC_FSK or GENERIC_FSK or GENERIC_BPSK]
* \param [in] config configuration of receiver
* fsk field to be used if modem =GENERIC_FSK
* lora field to be used if modem =GENERIC_LORA
bpsk field to be used if modem =GENERIC_BPSK
* \param [in] power Sets the output power [dBm]
* \param [in] timeout Transmission timeout [ms]
* \return 0 when no parameters error, -1 otherwise
*/
static int32_t RadioSetTxGenericConfig( GenericModems_t modem, TxConfigGeneric_t *config,
int8_t power, uint32_t timeout );
/*!
* \brief Configure the radio LR-FHSS modem parameters
*
* \param [in] cfg_params LR-FHSS modem configuration parameters
*
* \returns Operation status
*/
static radio_status_t RadioLrFhssSetCfg( const radio_lr_fhss_cfg_params_t *cfg_params );
/*!
* \brief Get the time on air in millisecond for LR-FHSS packet
*
* \param [in] params Pointer to LR-FHSS time on air parameters
* \param [out] time_on_air_in_ms time on air parameters results in ms
*
* \returns Time-on-air value in ms for LR-FHSS packet
*/
static radio_status_t RadioLrFhssGetTimeOnAirInMs( const radio_lr_fhss_time_on_air_params_t *params, uint32_t *time_on_air_in_ms );
/*!
* \brief Convert the bandwidth enum to Hz value
*
* \param [in] bw RF frequency to be checked
* \retval bandwidthInHz bandwidth value in Hertz
*/
static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw );
/*!
* \brief Computes the time on air GFSK numerator
*
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \retval numerator time on air GFSK numerator
*/
static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
/*!
* \brief Computes the time on air LoRa numerator
*
* \param [in] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [in] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [in] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [in] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [in] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [in] payloadLen Sets payload length when fixed length is used
* \param [in] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \retval numerator time on air LoRa numerator
*/
static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn );
#if( RADIO_LR_FHSS_IS_ON == 1 )
static uint32_t GetNextFreqIdx( uint32_t max );
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
/* Private variables ---------------------------------------------------------*/
/*!
* Radio driver structure initialization
*/
const struct Radio_s Radio =
{
RadioInit,
RadioGetStatus,
RadioSetModem,
RadioSetChannel,
RadioIsChannelFree,
RadioRandom,
RadioSetRxConfig,
RadioSetTxConfig,
RadioCheckRfFrequency,
RadioTimeOnAir,
RadioSend,
RadioSleep,
RadioStandby,
RadioRx,
RadioStartCad,
RadioSetTxContinuousWave,
RadioRssi,
RadioWrite,
RadioRead,
RadioWriteRegisters,
RadioReadRegisters,
RadioSetMaxPayloadLength,
RadioSetPublicNetwork,
RadioGetWakeupTime,
RadioIrqProcess,
RadioRxBoosted,
RadioSetRxDutyCycle,
RadioTxPrbs,
RadioTxCw,
RadioSetRxGenericConfig,
RadioSetTxGenericConfig,
RFW_TransmitLongPacket,
RFW_ReceiveLongPacket,
/* LrFhss extended radio functions */
RadioLrFhssSetCfg,
RadioLrFhssGetTimeOnAirInMs
};
const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
static uint8_t MaxPayloadLength = RADIO_BUF_SIZE;
static uint8_t RadioBuffer[RADIO_BUF_SIZE];
/*
* Radio callbacks variable
*/
static RadioEvents_t *RadioEvents;
/*!
* Radio hardware and global parameters
*/
SubgRf_t SubgRf;
/*!
* Tx and Rx timers
*/
TimerEvent_t TxTimeoutTimer;
TimerEvent_t RxTimeoutTimer;
/* Private functions ---------------------------------------------------------*/
static void RadioInit( RadioEvents_t *events )
{
RadioEvents = events;
SubgRf.RxContinuous = false;
SubgRf.TxTimeout = 0;
SubgRf.RxTimeout = 0;
/*See STM32WL Errata: RadioSetRxDutyCycle*/
SubgRf.RxDcPreambleDetectTimeout = 0;
#if( RADIO_LR_FHSS_IS_ON == 1 )
SubgRf.lr_fhss.is_lr_fhss_on = false;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
SUBGRF_Init( RadioOnDioIrq );
/*SubgRf.publicNetwork set to false*/
SubgRf.PublicNetwork.Current = false;
SubgRf.PublicNetwork.Previous = false;
RADIO_IRQ_PROCESS_INIT();
SUBGRF_SetRegulatorMode( );
SUBGRF_SetBufferBaseAddress( 0x00, 0x00 );
SUBGRF_SetTxParams( RFO_LP, 0, RADIO_RAMP_200_US );
SUBGRF_SetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
RadioSleep();
// Initialize driver timeout timers
TimerInit( &TxTimeoutTimer, RadioOnTxTimeoutIrq );
TimerInit( &RxTimeoutTimer, RadioOnRxTimeoutIrq );
TimerStop( &TxTimeoutTimer );
TimerStop( &RxTimeoutTimer );
}
static RadioState_t RadioGetStatus( void )
{
switch( SUBGRF_GetOperatingMode( ) )
{
case MODE_TX:
return RF_TX_RUNNING;
case MODE_RX:
return RF_RX_RUNNING;
case MODE_CAD:
return RF_CAD;
default:
return RF_IDLE;
}
}
static void RadioSetModem( RadioModems_t modem )
{
SubgRf.Modem = modem;
RFW_SetRadioModem( modem );
switch( modem )
{
default:
case MODEM_MSK:
SUBGRF_SetPacketType( PACKET_TYPE_GMSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_FSK:
SUBGRF_SetPacketType( PACKET_TYPE_GFSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_LORA:
SUBGRF_SetPacketType( PACKET_TYPE_LORA );
// Public/Private network register is reset when switching modems
if( SubgRf.PublicNetwork.Current != SubgRf.PublicNetwork.Previous )
{
SubgRf.PublicNetwork.Current = SubgRf.PublicNetwork.Previous;
RadioSetPublicNetwork( SubgRf.PublicNetwork.Current );
}
break;
case MODEM_BPSK:
SUBGRF_SetPacketType( PACKET_TYPE_BPSK );
// When switching to BPSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_TX:
SUBGRF_SetPacketType( PACKET_TYPE_BPSK );
// When switching to BPSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
case MODEM_SIGFOX_RX:
SUBGRF_SetPacketType( PACKET_TYPE_GFSK );
// When switching to GFSK mode the LoRa SyncWord register value is reset
// Thus, we also reset the RadioPublicNetwork variable
SubgRf.PublicNetwork.Current = false;
break;
#endif /*RADIO_SIGFOX_ENABLE == 1*/
}
}
static void RadioSetChannel( uint32_t freq )
{
SUBGRF_SetRfFrequency( freq );
}
static bool RadioIsChannelFree( uint32_t freq, uint32_t rxBandwidth, int16_t rssiThresh, uint32_t maxCarrierSenseTime )
{
bool status = true;
int16_t rssi = 0;
uint32_t carrierSenseTime = 0;
RadioStandby( );
RadioSetModem( MODEM_FSK );
RadioSetChannel( freq );
// Set Rx bandwidth. Other parameters are not used.
RadioSetRxConfig( MODEM_FSK, rxBandwidth, 600, 0, rxBandwidth, 3, 0, false,
0, false, 0, 0, false, true );
RadioRx( 0 );
RADIO_DELAY_MS( RadioGetWakeupTime( ) );
carrierSenseTime = TimerGetCurrentTime( );
// Perform carrier sense for maxCarrierSenseTime
while( TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime )
{
rssi = RadioRssi( MODEM_FSK );
if( rssi > rssiThresh )
{
status = false;
break;
}
}
RadioStandby( );
return status;
}
static uint32_t RadioRandom( void )
{
uint32_t rnd = 0;
/*
* Radio setup for random number generation
*/
// Disable modem interrupts
SUBGRF_SetDioIrqParams( IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
rnd = SUBGRF_GetRandom();
return rnd;
}
static void RadioSetRxConfig( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool freqHopOn, uint8_t hopPeriod,
bool iqInverted, bool rxContinuous )
{
#if (RADIO_SIGFOX_ENABLE == 1)
uint8_t modReg;
#endif
//Disabled, too much influence on RX timing
/*
MW_LOG( TS_ON, VLEVEL_M,
"Setting RX Config: modem=%s, bandwidth=%u, datarate=%u, coderate=%u bandwithAfc=%u, preambleLen=%u, symbTimeout=%u, fixLen=%u, payloadLen=%u, crcOn=%u, freqHopOn=%u, hopPeriod=%u, iqInverted=%u, rxContinuous=%u\r\n",
modem == MODEM_FSK ? "MODEM_FSK" : (modem == MODEM_LORA ? "MODEM_LORA" : "?"),
(unsigned)bandwidth, (unsigned)datarate, (unsigned)coderate,
(unsigned)bandwidthAfc, (unsigned)preambleLen,
(unsigned)symbTimeout, (unsigned)fixLen, (unsigned)payloadLen,
(unsigned)crcOn, (unsigned)freqHopOn, (unsigned)hopPeriod,
(unsigned)iqInverted, (unsigned)rxContinuous
);
*/
SubgRf.RxContinuous = rxContinuous;
RFW_DeInit();
if( rxContinuous == true )
{
symbTimeout = 0;
}
if( fixLen == true )
{
MaxPayloadLength = payloadLen;
}
else
{
MaxPayloadLength = 0xFF;
}
switch( modem )
{
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_RX:
SUBGRF_SetStopRxTimerOnPreambleDetect( true );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_05;
SubgRf.ModulationParams.Params.Gfsk.Fdev = 800;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( bandwidth );
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_OFF;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = 2 << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
SubgRf.PacketParams.Params.Gfsk.HeaderType = RADIO_PACKET_FIXED_LENGTH;
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
SubgRf.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREE_OFF;
RadioSetModem( MODEM_SIGFOX_RX );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( ( uint8_t[] ){0xB2, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } );
SUBGRF_SetWhiteningSeed( 0x01FF );
/* NO gfo reset (better sensitivity). Reg 0x8b8, bit4 = 0 */
modReg= RadioRead(SUBGHZ_AGCGFORSTCFGR);
modReg&=RADIO_BIT_MASK(4);
RadioWrite(SUBGHZ_AGCGFORSTCFGR, modReg);
/* Lower the threshold of cfo_reset */
RadioWrite(SUBGHZ_AGCGFORSTPOWTHR, 0x4 );
/* Bigger rssi_len (stability AGC). Reg 0x89b, bits[2 :4] = 0x1 */
modReg= RadioRead(SUBGHZ_AGCRSSICTL0R);
modReg&=( RADIO_BIT_MASK(2) & RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
RadioWrite(SUBGHZ_AGCRSSICTL0R, (modReg| (0x1<<3) ) );
/* Bigger afc_pbl_len (better frequency correction). Reg 0x6d1, bits[3 :4] = 0x3 */
modReg= RadioRead(SUBGHZ_GAFCR);
modReg&=( RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
RadioWrite(SUBGHZ_GAFCR, (modReg| (0x3<<3) ));
/* Use of new bit synchronizer (to avoid CRC errors during PER for payloads with a small amount of transitions). Reg 0x6ac, bits[4 :6] = 0x5 */
modReg= RadioRead(SUBGHZ_GBSYNCR);
modReg&=( RADIO_BIT_MASK(4) & RADIO_BIT_MASK(5) & RADIO_BIT_MASK(6) );
RadioWrite(SUBGHZ_GBSYNCR, (modReg| (0x5<<4) ));
/*timeout unused when SubgRf.RxContinuous*/
SubgRf.RxTimeout = ( uint32_t )(( symbTimeout * 8 * 1000 ) /datarate);
break;
#endif /*RADIO_SIGFOX_ENABLE == 1*/
case MODEM_FSK:
SUBGRF_SetStopRxTimerOnPreambleDetect( false );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( bandwidth );
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
if( crcOn == true )
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
}
SubgRf.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING;
RadioStandby( );
RadioSetModem( MODEM_FSK );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
SUBGRF_SetWhiteningSeed( 0x01FF );
/*timeout unused when SubgRf.RxContinuous*/
SubgRf.RxTimeout = ( uint32_t )(( symbTimeout * 8 * 1000 ) /datarate);
break;
case MODEM_LORA:
SUBGRF_SetStopRxTimerOnPreambleDetect( false );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_LORA;
SubgRf.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t )datarate;
SubgRf.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth];
SubgRf.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t )coderate;
if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01;
}
else
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
}
SubgRf.PacketParams.PacketType = PACKET_TYPE_LORA;
if( ( SubgRf.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) ||
( SubgRf.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) )
{
if( preambleLen < 12 )
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = 12;
}
else
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = preambleLen;
}
}
else
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = preambleLen;
}
SubgRf.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen;
SubgRf.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength;
SubgRf.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn;
SubgRf.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted;
RadioStandby( );
RadioSetModem( MODEM_LORA );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetLoRaSymbNumTimeout( symbTimeout );
/* WORKAROUND - Set the step threshold value to 1 to avoid to miss low power signal after an interferer jam the chip in LoRa modulaltion */
SUBGRF_WriteRegister(SUBGHZ_AGCCFG,SUBGRF_ReadRegister(SUBGHZ_AGCCFG)&0x1);
/* WORKAROUND - Optimizing the Inverted IQ Operation, see STM32WL Erratasheet */
if( SubgRf.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
{
// RegIqPolaritySetup = @address 0x0736
SUBGRF_WriteRegister( SUBGHZ_LIQPOLR, SUBGRF_ReadRegister( SUBGHZ_LIQPOLR ) & ~( 1 << 2 ) );
}
else
{
// RegIqPolaritySetup @address 0x0736
SUBGRF_WriteRegister( SUBGHZ_LIQPOLR, SUBGRF_ReadRegister( SUBGHZ_LIQPOLR ) | ( 1 << 2 ) );
}
/* WORKAROUND END */
// Timeout Max, Timeout handled directly in SetRx function
SubgRf.RxTimeout = 0xFFFF;
break;
default:
break;
}
}
static void RadioSetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool freqHopOn,
uint8_t hopPeriod, bool iqInverted, uint32_t timeout )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
/*disable LrFhss*/
SubgRf.lr_fhss.is_lr_fhss_on = false;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
RFW_DeInit();
MW_LOG( TS_ON, VLEVEL_M,
"Setting TX Config: modem=%s, power=%u, fdev=%u, bandwidth=%u, datarate=%u, coderate=%u preambleLen=%u, fixLen=%u, crcOn=%u, freqHopOn=%u, hopPeriod=%u, iqInverted=%u, timeout=%u\r\n",
modem == MODEM_FSK ? "MODEM_FSK" : (modem == MODEM_LORA ? "MODEM_LORA" : "?"),
(int)power, (unsigned)fdev, (unsigned)bandwidth,
(unsigned)datarate, (unsigned)coderate, (unsigned)preambleLen,
(unsigned)fixLen, (unsigned)crcOn, (unsigned)freqHopOn,
(unsigned)hopPeriod, (unsigned)iqInverted, (unsigned)timeout
);
switch( modem )
{
case MODEM_FSK:
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( bandwidth );
SubgRf.ModulationParams.Params.Gfsk.Fdev = fdev;
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( preambleLen << 3 ); // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = 3 << 3 ; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( fixLen == true ) ? RADIO_PACKET_FIXED_LENGTH : RADIO_PACKET_VARIABLE_LENGTH;
if( crcOn == true )
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_2_BYTES_CCIT;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
}
SubgRf.PacketParams.Params.Gfsk.DcFree = RADIO_DC_FREEWHITENING;
RadioStandby( );
RadioSetModem( MODEM_FSK );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
SUBGRF_SetWhiteningSeed( 0x01FF );
break;
case MODEM_LORA:
SubgRf.ModulationParams.PacketType = PACKET_TYPE_LORA;
SubgRf.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) datarate;
SubgRf.ModulationParams.Params.LoRa.Bandwidth = Bandwidths[bandwidth];
SubgRf.ModulationParams.Params.LoRa.CodingRate= ( RadioLoRaCodingRates_t )coderate;
if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x01;
}
else
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0x00;
}
SubgRf.PacketParams.PacketType = PACKET_TYPE_LORA;
if( ( SubgRf.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF5 ) ||
( SubgRf.ModulationParams.Params.LoRa.SpreadingFactor == LORA_SF6 ) )
{
if( preambleLen < 12 )
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = 12;
}
else
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = preambleLen;
}
}
else
{
SubgRf.PacketParams.Params.LoRa.PreambleLength = preambleLen;
}
SubgRf.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t )fixLen;
SubgRf.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength;
SubgRf.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t )crcOn;
SubgRf.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t )iqInverted;
RadioStandby( );
RadioSetModem( MODEM_LORA );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
break;
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_TX:
RadioSetModem(MODEM_SIGFOX_TX);
SubgRf.ModulationParams.PacketType = PACKET_TYPE_BPSK;
SubgRf.ModulationParams.Params.Bpsk.BitRate = datarate;
SubgRf.ModulationParams.Params.Bpsk.ModulationShaping = MOD_SHAPING_DBPSK;
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
break;
#endif /*RADIO_SIGFOX_ENABLE == 1*/
default:
break;
}
SubgRf.AntSwitchPaSelect = SUBGRF_SetRfTxPower( power );
/* WORKAROUND - Trimming the output voltage power_ldo to 3.3V */
SUBGRF_WriteRegister(REG_DRV_CTRL, 0x7 << 1);
RFW_SetAntSwitch( SubgRf.AntSwitchPaSelect );
SubgRf.TxTimeout = timeout;
}
static bool RadioCheckRfFrequency( uint32_t frequency )
{
return true;
}
static uint32_t RadioGetLoRaBandwidthInHz( RadioLoRaBandwidths_t bw )
{
uint32_t bandwidthInHz = 0;
switch( bw )
{
case LORA_BW_007:
bandwidthInHz = 7812UL;
break;
case LORA_BW_010:
bandwidthInHz = 10417UL;
break;
case LORA_BW_015:
bandwidthInHz = 15625UL;
break;
case LORA_BW_020:
bandwidthInHz = 20833UL;
break;
case LORA_BW_031:
bandwidthInHz = 31250UL;
break;
case LORA_BW_041:
bandwidthInHz = 41667UL;
break;
case LORA_BW_062:
bandwidthInHz = 62500UL;
break;
case LORA_BW_125:
bandwidthInHz = 125000UL;
break;
case LORA_BW_250:
bandwidthInHz = 250000UL;
break;
case LORA_BW_500:
bandwidthInHz = 500000UL;
break;
}
return bandwidthInHz;
}
static uint32_t RadioGetGfskTimeOnAirNumerator( uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn )
{
return ( preambleLen << 3 ) +
( ( fixLen == false ) ? 8 : 0 ) + 24 +
( ( payloadLen + ( ( crcOn == true ) ? 2 : 0 ) ) << 3 );
}
static uint32_t RadioGetLoRaTimeOnAirNumerator( uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn )
{
int32_t crDenom = coderate + 4;
bool lowDatareOptimize = false;
// Ensure that the preamble length is at least 12 symbols when using SF5 or SF6
if( ( datarate == 5 ) || ( datarate == 6 ) )
{
if( preambleLen < 12 )
{
preambleLen = 12;
}
}
if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
{
lowDatareOptimize = true;
}
int32_t ceilDenominator;
int32_t ceilNumerator = ( payloadLen << 3 ) +
( crcOn ? 16 : 0 ) -
( 4 * datarate ) +
( fixLen ? 0 : 20 );
if( datarate <= 6 )
{
ceilDenominator = 4 * datarate;
}
else
{
ceilNumerator += 8;
if( lowDatareOptimize == true )
{
ceilDenominator = 4 * ( datarate - 2 );
}
else
{
ceilDenominator = 4 * datarate;
}
}
if( ceilNumerator < 0 )
{
ceilNumerator = 0;
}
// Perform integral ceil()
int32_t intermediate =
( ( ceilNumerator + ceilDenominator - 1 ) / ceilDenominator ) * crDenom + preambleLen + 12;
if( datarate <= 6 )
{
intermediate += 2;
}
return ( uint32_t )( ( 4 * intermediate + 1 ) * ( 1 << ( datarate - 2 ) ) );
}
static uint32_t RadioTimeOnAir( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint16_t preambleLen, bool fixLen, uint8_t payloadLen,
bool crcOn )
{
uint32_t numerator = 0;
uint32_t denominator = 1;
switch( modem )
{
case MODEM_FSK:
{
numerator = 1000U * RadioGetGfskTimeOnAirNumerator( datarate, coderate,
preambleLen, fixLen,
payloadLen, crcOn );
denominator = datarate;
}
break;
case MODEM_LORA:
{
numerator = 1000U * RadioGetLoRaTimeOnAirNumerator( bandwidth, datarate,
coderate, preambleLen,
fixLen, payloadLen, crcOn );
denominator = RadioGetLoRaBandwidthInHz( Bandwidths[bandwidth] );
}
break;
default:
break;
}
// Perform integral ceil()
return DIVC( numerator, denominator );
}
static radio_status_t RadioSend( uint8_t *buffer, uint8_t size )
{
SUBGRF_SetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_TX_DBG,
IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_TX_DBG,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
MW_LOG( TS_ON, VLEVEL_M, "TX:");
for (size_t i = 0; i < size; ++i)
MW_LOG( TS_ON, VLEVEL_M, " %02x", buffer[i]);
MW_LOG( TS_ON, VLEVEL_M, "\r\n");
/* Set DBG pin */
DBG_GPIO_RADIO_TX( SET );
/* Set RF switch */
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_TX );
/* WORKAROUND - Modulation Quality with 500 kHz LoRaTM Bandwidth*/
/* RegTxModulation = @address 0x0889 */
if( ( SubgRf.Modem == MODEM_LORA ) && ( SubgRf.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 ) )
{
SUBGRF_WriteRegister( SUBGHZ_SDCFG0R, SUBGRF_ReadRegister( SUBGHZ_SDCFG0R ) & ~( 1 << 2 ) );
}
else
{
SUBGRF_WriteRegister( SUBGHZ_SDCFG0R, SUBGRF_ReadRegister( SUBGHZ_SDCFG0R ) | ( 1 << 2 ) );
}
#if( RADIO_LR_FHSS_IS_ON == 1 )
//ral_lr_fhss_memory_state_t lr_fhss_state = radio_board_get_lr_fhss_state_reference( );
if( SubgRf.lr_fhss.is_lr_fhss_on == true )
{
uint32_t hop_sequence_count = lr_fhss_get_hop_sequence_count( &SubgRf.lr_fhss.lr_fhss_params.lr_fhss_params );
SubgRf.lr_fhss.hop_sequence_id = GetNextFreqIdx( hop_sequence_count );
MW_LOG( TS_ON, VLEVEL_M, "LRFHSS HOPSEQ %d\r\n", SubgRf.lr_fhss.hop_sequence_id );
if( RADIO_STATUS_OK != wl_lr_fhss_build_frame( &SubgRf.lr_fhss.lr_fhss_params, &SubgRf.lr_fhss.lr_fhss_state,
SubgRf.lr_fhss.hop_sequence_id, buffer, size, NULL ) )
{
return RADIO_STATUS_ERROR;
}
SUBGRF_SetDioIrqParams( IRQ_TX_DONE | IRQ_LR_FHSS_HOP | IRQ_RX_TX_TIMEOUT | IRQ_TX_DBG,
IRQ_TX_DONE | IRQ_LR_FHSS_HOP | IRQ_RX_TX_TIMEOUT | IRQ_TX_DBG,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
SUBGRF_SetTx( SubgRf.TxTimeout << 6 );
}
else
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
{
/* WORKAROUND END */
switch( SubgRf.Modem )
{
case MODEM_LORA:
{
SubgRf.PacketParams.Params.LoRa.PayloadLength = size;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SendPayload( buffer, size, 0 );
break;
}
case MODEM_MSK:
case MODEM_FSK:
{
if ( 1UL == RFW_Is_Init( ) )
{
uint8_t outsize;
if ( 0UL == RFW_TransmitInit( buffer,size, &outsize ) )
{
SubgRf.PacketParams.Params.Gfsk.PayloadLength = outsize;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SendPayload( buffer, outsize, 0 );
}
else
{
MW_LOG( TS_ON, VLEVEL_M, "RadioSend Oversize\r\n" );
return RADIO_STATUS_ERROR;
}
}
else
{
SubgRf.PacketParams.Params.Gfsk.PayloadLength = size;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SendPayload( buffer, size, 0 );
}
break;
}
case MODEM_BPSK:
{
SubgRf.PacketParams.PacketType = PACKET_TYPE_BPSK;
SubgRf.PacketParams.Params.Bpsk.PayloadLength = size;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SendPayload( buffer, size, 0 );
break;
}
#if (RADIO_SIGFOX_ENABLE == 1)
case MODEM_SIGFOX_TX:
{
/* from bpsk to dbpsk */
/* first 1 bit duplicated */
/* RadioBuffer is 1 bytes more */
payload_integration( RadioBuffer, buffer, size );
SubgRf.PacketParams.PacketType = PACKET_TYPE_BPSK;
SubgRf.PacketParams.Params.Bpsk.PayloadLength = size + 1;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
RadioWrite( SUBGHZ_RAM_RAMPUPL, 0 ); // clean start-up LSB
RadioWrite( SUBGHZ_RAM_RAMPUPH, 0 ); // clean start-up MSB
if( SubgRf.ModulationParams.Params.Bpsk.BitRate == 100 )
{
RadioWrite( SUBGHZ_RAM_RAMPDNL, 0x70 ); // clean end of frame LSB
RadioWrite( SUBGHZ_RAM_RAMPDNH, 0x1D ); // clean end of frame MSB
}
else // 600 bps
{
RadioWrite( SUBGHZ_RAM_RAMPDNL, 0xE1 ); // clean end of frame LSB
RadioWrite( SUBGHZ_RAM_RAMPDNH, 0x04 ); // clean end of frame MSB
}
uint16_t bitNum = ( size * 8 ) + 2;
RadioWrite( SUBGHZ_RAM_FRAMELIMH, ( bitNum >> 8 ) & 0x00FF ); // limit frame
RadioWrite( SUBGHZ_RAM_FRAMELIML, bitNum & 0x00FF ); // limit frame
SUBGRF_SendPayload( RadioBuffer, size + 1, 0xFFFFFF );
break;
}
#endif /*RADIO_SIGFOX_ENABLE == 1*/
default:
break;
}
TimerSetValue( &TxTimeoutTimer, SubgRf.TxTimeout );
TimerStart( &TxTimeoutTimer );
}
return RADIO_STATUS_OK;
}
static void RadioSleep( void )
{
SleepParams_t params = { 0 };
params.Fields.WarmStart = 1;
SUBGRF_SetSleep( params );
RADIO_DELAY_MS( 2 );
}
static void RadioStandby( void )
{
SUBGRF_SetStandby( STDBY_RC );
}
static void RadioRx( uint32_t timeout )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
if( SubgRf.lr_fhss.is_lr_fhss_on == true )
{
//return LORAMAC_RADIO_STATUS_ERROR;
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
if( 1UL == RFW_Is_Init( ) )
{
RFW_ReceiveInit( );
}
else
{
SUBGRF_SetDioIrqParams( IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
}
if( timeout != 0 )
{
TimerSetValue( &RxTimeoutTimer, timeout );
TimerStart( &RxTimeoutTimer );
}
/* switch off RxDcPreambleDetect See STM32WL Errata: RadioSetRxDutyCycle*/
SubgRf.RxDcPreambleDetectTimeout = 0;
/* Set DBG pin */
DBG_GPIO_RADIO_RX( SET );
/* RF switch configuration */
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_RX );
if( SubgRf.RxContinuous == true )
{
SUBGRF_SetRx( 0xFFFFFF ); // Rx Continuous
}
else
{
SUBGRF_SetRx( SubgRf.RxTimeout << 6 );
}
}
static void RadioRxBoosted( uint32_t timeout )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
if( SubgRf.lr_fhss.is_lr_fhss_on == true )
{
//return LORAMAC_RADIO_STATUS_ERROR;
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
if( 1UL == RFW_Is_Init() )
{
RFW_ReceiveInit();
}
else
{
SUBGRF_SetDioIrqParams( IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
}
if( timeout != 0 )
{
TimerSetValue( &RxTimeoutTimer, timeout );
TimerStart( &RxTimeoutTimer );
}
/* switch off RxDcPreambleDetect See STM32WL Errata: RadioSetRxDutyCycle*/
SubgRf.RxDcPreambleDetectTimeout = 0;
/* Set DBG pin */
DBG_GPIO_RADIO_RX( SET );
/* RF switch configuration */
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_RX );
if( SubgRf.RxContinuous == true )
{
SUBGRF_SetRxBoosted( 0xFFFFFF ); // Rx Continuous
}
else
{
SUBGRF_SetRxBoosted( SubgRf.RxTimeout << 6 );
}
}
static void RadioSetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime )
{
/*See STM32WL Errata: RadioSetRxDutyCycle*/
SubgRf.RxDcPreambleDetectTimeout = 2 * rxTime + sleepTime;
/*Enable also the IRQ_PREAMBLE_DETECTED*/
SUBGRF_SetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
/* RF switch configuration */
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_RX );
/* Start Rx DutyCycle*/
SUBGRF_SetRxDutyCycle( rxTime, sleepTime );
}
static void RadioStartCad( void )
{
/* RF switch configuration */
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_RX );
SUBGRF_SetDioIrqParams( IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
IRQ_CAD_CLEAR | IRQ_CAD_DETECTED,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
SUBGRF_SetCad( );
}
static void RadioSetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
if( SubgRf.lr_fhss.is_lr_fhss_on == true )
{
//return LORAMAC_RADIO_STATUS_ERROR;
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
uint32_t timeout = ( uint32_t )time * 1000;
uint8_t antswitchpow;
SUBGRF_SetRfFrequency( freq );
antswitchpow = SUBGRF_SetRfTxPower( power );
/* WORKAROUND - Trimming the output voltage power_ldo to 3.3V */
SUBGRF_WriteRegister(REG_DRV_CTRL, 0x7 << 1);
/* Set RF switch */
SUBGRF_SetSwitch( antswitchpow, RFSWITCH_TX );
SUBGRF_SetTxContinuousWave( );
TimerSetValue( &TxTimeoutTimer, timeout );
TimerStart( &TxTimeoutTimer );
}
static int16_t RadioRssi( RadioModems_t modem )
{
return SUBGRF_GetRssiInst( );
}
static void RadioWrite( uint16_t addr, uint8_t data )
{
SUBGRF_WriteRegister( addr, data );
}
static uint8_t RadioRead( uint16_t addr )
{
return SUBGRF_ReadRegister( addr );
}
static void RadioWriteRegisters( uint16_t addr, uint8_t *buffer, uint8_t size )
{
SUBGRF_WriteRegisters( addr, buffer, size );
}
static void RadioReadRegisters( uint16_t addr, uint8_t *buffer, uint8_t size )
{
SUBGRF_ReadRegisters( addr, buffer, size );
}
static void RadioSetMaxPayloadLength( RadioModems_t modem, uint8_t max )
{
if( modem == MODEM_LORA )
{
SubgRf.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength = max;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
}
else
{
if( SubgRf.PacketParams.Params.Gfsk.HeaderType == RADIO_PACKET_VARIABLE_LENGTH )
{
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength = max;
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
}
}
}
static void RadioSetPublicNetwork( bool enable )
{
SubgRf.PublicNetwork.Current = SubgRf.PublicNetwork.Previous = enable;
RadioSetModem( MODEM_LORA );
if( enable == true )
{
// Change LoRa modem SyncWord
SUBGRF_WriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PUBLIC_SYNCWORD >> 8 ) & 0xFF );
SUBGRF_WriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PUBLIC_SYNCWORD & 0xFF );
}
else
{
// Change LoRa modem SyncWord
SUBGRF_WriteRegister( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF );
SUBGRF_WriteRegister( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF );
}
}
static uint32_t RadioGetWakeupTime( void )
{
return SUBGRF_GetRadioWakeUpTime() + RADIO_WAKEUP_TIME;
}
static void RadioOnTxTimeoutIrq( void *context )
{
RADIO_TX_TIMEOUT_PROCESS();
}
static void RadioOnRxTimeoutIrq( void *context )
{
RADIO_RX_TIMEOUT_PROCESS();
}
static void RadioOnTxTimeoutProcess( void )
{
DBG_GPIO_RADIO_TX( RST );
if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
{
RadioEvents->TxTimeout( );
}
}
static void RadioOnRxTimeoutProcess( void )
{
DBG_GPIO_RADIO_RX( RST );
if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
{
RadioEvents->RxTimeout( );
}
}
static void RadioOnDioIrq( RadioIrqMasks_t radioIrq )
{
SubgRf.RadioIrq = radioIrq;
RADIO_IRQ_PROCESS();
}
static void RadioIrqProcess( void )
{
uint8_t size = 0;
int32_t cfo = 0;
switch( SubgRf.RadioIrq )
{
case IRQ_TX_DONE:
DBG_GPIO_RADIO_TX( RST );
TimerStop( &TxTimeoutTimer );
#if( RADIO_LR_FHSS_IS_ON == 1 )
if( SubgRf.lr_fhss.is_lr_fhss_on == true )
{
wl_lr_fhss_handle_tx_done( &SubgRf.lr_fhss.lr_fhss_params,
&SubgRf.lr_fhss.lr_fhss_state );
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
if( RFW_Is_LongPacketModeEnabled() == 1 )
{
RFW_DeInit_TxLongPacket( );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) )
{
RadioEvents->TxDone( );
}
break;
case IRQ_RX_DONE:
DBG_GPIO_RADIO_RX( RST );
TimerStop( &RxTimeoutTimer );
if( SubgRf.RxContinuous == false )
{
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
/* WORKAROUND - Implicit Header Mode Timeout Behavior, see STM32WL Erratasheet */
SUBGRF_WriteRegister( SUBGHZ_RTCCTLR, 0x00 );
SUBGRF_WriteRegister( SUBGHZ_EVENTMASKR, SUBGRF_ReadRegister( SUBGHZ_EVENTMASKR ) | ( 1 << 1 ) );
/* WORKAROUND END */
}
SUBGRF_GetPayload( RadioBuffer, &size, 255 );
SUBGRF_GetPacketStatus( &( SubgRf.PacketStatus ) );
if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
{
switch( SubgRf.PacketStatus.packetType )
{
case PACKET_TYPE_LORA:
RadioEvents->RxDone( RadioBuffer, size, SubgRf.PacketStatus.Params.LoRa.RssiPkt,
SubgRf.PacketStatus.Params.LoRa.SnrPkt );
break;
default:
SUBGRF_GetCFO( SubgRf.ModulationParams.Params.Gfsk.BitRate, &cfo );
RadioEvents->RxDone( RadioBuffer, size, SubgRf.PacketStatus.Params.Gfsk.RssiAvg, ( int8_t ) DIVR( cfo, 1000 ) );
break;
}
}
break;
case IRQ_CAD_CLEAR:
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
{
RadioEvents->CadDone( false );
}
break;
case IRQ_CAD_DETECTED:
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
if( ( RadioEvents != NULL ) && ( RadioEvents->CadDone != NULL ) )
{
RadioEvents->CadDone( true );
}
break;
case IRQ_RX_TX_TIMEOUT:
MW_LOG( TS_ON, VLEVEL_M, "IRQ_RX_TX_TIMEOUT\r\n" );
if( SUBGRF_GetOperatingMode( ) == MODE_TX )
{
DBG_GPIO_RADIO_TX( RST );
TimerStop( &TxTimeoutTimer );
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
{
RadioEvents->TxTimeout( );
}
}
else if( SUBGRF_GetOperatingMode( ) == MODE_RX )
{
DBG_GPIO_RADIO_RX( RST );
TimerStop( &RxTimeoutTimer );
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
{
RadioEvents->RxTimeout( );
}
}
break;
case IRQ_PREAMBLE_DETECTED:
MW_LOG( TS_ON, VLEVEL_M, "PRE OK\r\n" );
/*See STM32WL Errata: RadioSetRxDutyCycle*/
if( SubgRf.RxDcPreambleDetectTimeout != 0 )
{
/* Update Radio RTC period */
Radio.Write( SUBGHZ_RTCPRDR2, ( SubgRf.RxDcPreambleDetectTimeout >> 16 ) & 0xFF ); /*Update Radio RTC Period MSB*/
Radio.Write( SUBGHZ_RTCPRDR1, ( SubgRf.RxDcPreambleDetectTimeout >> 8 ) & 0xFF ); /*Update Radio RTC Period MidByte*/
Radio.Write( SUBGHZ_RTCPRDR0, ( SubgRf.RxDcPreambleDetectTimeout ) & 0xFF ); /*Update Radio RTC Period lsb*/
Radio.Write( SUBGHZ_RTCCTLR, Radio.Read( SUBGHZ_RTCCTLR ) | 0x1 ); /*restart Radio RTC*/
SubgRf.RxDcPreambleDetectTimeout = 0;
/*Clear IRQ_PREAMBLE_DETECTED mask*/
SUBGRF_SetDioIrqParams( IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT | IRQ_CRC_ERROR | IRQ_HEADER_ERROR | IRQ_RX_DBG,
IRQ_RADIO_NONE,
IRQ_RADIO_NONE );
}
break;
case IRQ_SYNCWORD_VALID:
MW_LOG( TS_ON, VLEVEL_M, "SYNC OK\r\n" );
if( 1UL == RFW_Is_Init( ) )
{
RFW_ReceivePayload( );
}
break;
case IRQ_HEADER_VALID:
MW_LOG( TS_ON, VLEVEL_M, "HDR OK\r\n" );
break;
case IRQ_HEADER_ERROR:
TimerStop( &RxTimeoutTimer );
if( SubgRf.RxContinuous == false )
{
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
{
RadioEvents->RxTimeout( );
MW_LOG( TS_ON, VLEVEL_M, "HDR KO\r\n" );
}
break;
case IRQ_CRC_ERROR:
MW_LOG( TS_ON, VLEVEL_M, "IRQ_CRC_ERROR\r\n" );
if( SubgRf.RxContinuous == false )
{
//!< Update operating mode state to a value lower than \ref MODE_STDBY_XOSC
SUBGRF_SetStandby( STDBY_RC );
}
if( ( RadioEvents != NULL ) && ( RadioEvents->RxError ) )
{
RadioEvents->RxError( );
}
break;
#if( RADIO_LR_FHSS_IS_ON == 1 )
case IRQ_LR_FHSS_HOP:
{
( void ) wl_lr_fhss_handle_hop( &SubgRf.lr_fhss.lr_fhss_params, &SubgRf.lr_fhss.lr_fhss_state );
MW_LOG( TS_ON, VLEVEL_M, "HOP\r\n" );
break;
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
default:
break;
}
}
static void RadioTxPrbs( void )
{
SUBGRF_SetSwitch( SubgRf.AntSwitchPaSelect, RFSWITCH_TX );
Radio.Write( SUBGHZ_GPKTCTL1AR, 0x2d ); // sel mode prbs9 instead of preamble
SUBGRF_SetTxInfinitePreamble( );
SUBGRF_SetTx( 0x0fffff );
}
static void RadioTxCw( int8_t power )
{
uint8_t paselect = SUBGRF_SetRfTxPower( power );
/* WORKAROUND - Trimming the output voltage power_ldo to 3.3V */
SUBGRF_WriteRegister(REG_DRV_CTRL, 0x7 << 1);
SUBGRF_SetSwitch( paselect, RFSWITCH_TX );
SUBGRF_SetTxContinuousWave( );
}
#if (RADIO_SIGFOX_ENABLE == 1)
static void payload_integration( uint8_t *outBuffer, uint8_t *inBuffer, uint8_t size )
{
uint8_t prevInt = 0;
uint8_t currBit;
uint8_t index_bit;
uint8_t index_byte;
uint8_t index_bit_out;
uint8_t index_byte_out;
int32_t i = 0;
for( i = 0; i < size; i++ )
{
/* reverse all inputs */
inBuffer[i] = ~inBuffer[i];
/* init outBuffer */
outBuffer[i] = 0;
}
for( i = 0; i < ( size * 8 ); i++ )
{
/* index to take bit in inBuffer */
index_bit = 7 - ( i % 8 );
index_byte = i / 8;
/* index to place bit in outBuffer is shifted 1 bit right */
index_bit_out = 7 - ( ( i + 1 ) % 8 );
index_byte_out = ( i + 1 ) / 8;
/* extract current bit from input */
currBit = ( inBuffer[index_byte] >> index_bit ) & 0x01;
/* integration */
prevInt ^= currBit;
/* write result integration in output */
outBuffer[index_byte_out] |= ( prevInt << index_bit_out );
}
outBuffer[size] = ( prevInt << 7 ) | ( prevInt << 6 ) | ( ( ( !prevInt ) & 0x01 ) << 5 ) ;
}
#endif /*RADIO_SIGFOX_ENABLE == 1*/
static int32_t RadioSetRxGenericConfig( GenericModems_t modem, RxConfigGeneric_t *config, uint32_t rxContinuous,
uint32_t symbTimeout )
{
#if (RADIO_GENERIC_CONFIG_ENABLE == 1)
int32_t status = 0;
uint8_t syncword[8] = {0};
uint8_t MaxPayloadLength;
RFW_DeInit( ); /* switch Off FwPacketDecoding by default */
if( rxContinuous != 0 )
{
symbTimeout = 0;
}
SubgRf.RxContinuous = ( rxContinuous == 0 ) ? false : true;
switch( modem )
{
case GENERIC_FSK:
if( ( config->fsk.BitRate == 0 ) || ( config->fsk.PreambleLen == 0 ) )
{
return -1;
}
if( config->fsk.SyncWordLength > 8 )
{
return -1;
}
else
{
RADIO_MEMCPY8( syncword, config->fsk.SyncWord, config->fsk.SyncWordLength );
}
SUBGRF_SetStopRxTimerOnPreambleDetect( ( config->fsk.StopTimerOnPreambleDetect == 0 ) ? false : true );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = config->fsk.BitRate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = ( RadioModShapings_t ) config->fsk.ModulationShaping;
SubgRf.ModulationParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue( config->fsk.Bandwidth );
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( config->fsk.PreambleLen ) << 3 ; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = ( RadioPreambleDetection_t ) config->fsk.PreambleMinDetect;
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = ( config->fsk.SyncWordLength ) << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = ( RadioAddressComp_t ) config->fsk.AddrComp;
if( config->fsk.LengthMode == RADIO_FSK_PACKET_FIXED_LENGTH )
{
SubgRf.PacketParams.Params.Gfsk.PayloadLength = config->fsk.MaxPayloadLength;
}
else if( config->fsk.LengthMode == RADIO_FSK_PACKET_2BYTES_LENGTH )
{
/* Set max in the radio, in long packet mode will be tuned based dynamically on received chunk */
SubgRf.PacketParams.Params.Gfsk.PayloadLength = 0xFF;
}
else
{
/* Set max in the radio */
SubgRf.PacketParams.Params.Gfsk.PayloadLength = 0xFF;
}
if( ( config->fsk.Whitening == RADIO_FSK_DC_IBM_WHITENING )
|| ( config->fsk.LengthMode == RADIO_FSK_PACKET_2BYTES_LENGTH ) )
{
/* Supports only RADIO_FSK_CRC_2_BYTES_IBM or RADIO_FSK_CRC_2_BYTES_CCIT*/
if( ( config->fsk.CrcLength != RADIO_FSK_CRC_2_BYTES_IBM ) && ( config->fsk.CrcLength != RADIO_FSK_CRC_2_BYTES_CCIT )
&& ( config->fsk.CrcLength != RADIO_FSK_CRC_OFF ) )
{
return -1;
}
ConfigGeneric_t ConfigGeneric;
ConfigGeneric.rtx = CONFIG_RX;
ConfigGeneric.RxConfig = config;
if( 0UL != RFW_Init( &ConfigGeneric, RadioEvents, &RxTimeoutTimer ) )
{
return -1;
}
/* Whitening off, will be processed by FW, switch off built-in radio whitening*/
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) RADIO_FSK_DC_FREE_OFF;
/* Crc off, Crc processed by FW, switch off built-in radio Crc*/
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) RADIO_CRC_OFF;
/* Length contained in Tx, but will be processed by FW after de-whitening*/
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) RADIO_PACKET_FIXED_LENGTH;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) config->fsk.CrcLength;
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) config->fsk.Whitening;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) config->fsk.LengthMode;
}
RadioStandby( );
RadioSetModem( MODEM_FSK );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( syncword );
SUBGRF_SetWhiteningSeed( config->fsk.whiteSeed );
SUBGRF_SetCrcPolynomial( config->fsk.CrcPolynomial );
/* timeout unused when SubgRf.RxContinuous */
SubgRf.RxTimeout = ( uint32_t )( ( symbTimeout * 1000 * 8 ) / config->fsk.BitRate );
break;
case GENERIC_LORA:
if( config->lora.PreambleLen == 0 )
{
return -1;
}
if( config->lora.LengthMode == RADIO_LORA_PACKET_FIXED_LENGTH )
{
MaxPayloadLength = config->fsk.MaxPayloadLength;
}
else
{
MaxPayloadLength = 0xFF;
}
SUBGRF_SetStopRxTimerOnPreambleDetect( ( config->lora.StopTimerOnPreambleDetect == 0 ) ? false : true );
SUBGRF_SetLoRaSymbNumTimeout( symbTimeout );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_LORA;
SubgRf.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) config->lora.SpreadingFactor;
SubgRf.ModulationParams.Params.LoRa.Bandwidth = ( RadioLoRaBandwidths_t ) config->lora.Bandwidth;
SubgRf.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t ) config->lora.Coderate;
switch( config->lora.LowDatarateOptimize )
{
case RADIO_LORA_LOWDR_OPT_OFF:
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0;
break;
case RADIO_LORA_LOWDR_OPT_ON:
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 1;
break;
case RADIO_LORA_LOWDR_OPT_AUTO:
if( ( config->lora.SpreadingFactor == RADIO_LORA_SF11 ) || ( config->lora.SpreadingFactor == RADIO_LORA_SF12 ) )
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 1;
}
else
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0;
}
break;
default:
break;
}
SubgRf.PacketParams.PacketType = PACKET_TYPE_LORA;
SubgRf.PacketParams.Params.LoRa.PreambleLength = config->lora.PreambleLen;
SubgRf.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t ) config->lora.LengthMode;
SubgRf.PacketParams.Params.LoRa.PayloadLength = MaxPayloadLength;
SubgRf.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t ) config->lora.CrcMode;
SubgRf.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t ) config->lora.IqInverted;
RadioStandby( );
RadioSetModem( MODEM_LORA );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
/* WORKAROUND - Optimizing the Inverted IQ Operation, see STM32WL Erratasheet */
if( SubgRf.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
{
SUBGRF_WriteRegister( SUBGHZ_LIQPOLR, SUBGRF_ReadRegister( SUBGHZ_LIQPOLR ) & ~( 1 << 2 ) );
}
else
{
SUBGRF_WriteRegister( SUBGHZ_LIQPOLR, SUBGRF_ReadRegister( SUBGHZ_LIQPOLR ) | ( 1 << 2 ) );
}
/* WORKAROUND END */
// Timeout Max, Timeout handled directly in SetRx function
SubgRf.RxTimeout = 0xFFFF;
break;
default:
break;
}
return status;
#else /* RADIO_GENERIC_CONFIG_ENABLE == 1*/
return -1;
#endif /* RADIO_GENERIC_CONFIG_ENABLE == 0*/
}
static int32_t RadioSetTxGenericConfig( GenericModems_t modem, TxConfigGeneric_t *config, int8_t power,
uint32_t timeout )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
/*disable LrFhss*/
SubgRf.lr_fhss.is_lr_fhss_on = false;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
#if (RADIO_GENERIC_CONFIG_ENABLE == 1)
uint8_t syncword[8] = {0};
RadioModems_t radio_modem;
RFW_DeInit( ); /* switch Off FwPacketDecoding by default */
switch( modem )
{
case GENERIC_MSK:
if( config->msk.SyncWordLength > 8 )
{
return -1;
}
else
{
RADIO_MEMCPY8( syncword, config->msk.SyncWord, config->msk.SyncWordLength );
}
if( ( config->msk.BitRate == 0 ) )
{
return -1;
}
else if( config->msk.BitRate <= 10000 )
{
/*max msk modulator datarate is 10kbps*/
radio_modem = MODEM_MSK;
SubgRf.PacketParams.PacketType = PACKET_TYPE_GMSK;
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GMSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = config->msk.BitRate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = ( RadioModShapings_t ) config->msk.ModulationShaping;
}
else
{
radio_modem = MODEM_FSK;
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = config->msk.BitRate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = ( RadioModShapings_t ) config->msk.ModulationShaping;
/*do msk with gfsk modulator*/
SubgRf.ModulationParams.Params.Gfsk.Fdev = config->msk.BitRate / 4;
}
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( config->msk.PreambleLen ) << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; // don't care in tx
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = ( config->msk.SyncWordLength ) << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; // don't care in tx
if( ( config->msk.Whitening == RADIO_FSK_DC_IBM_WHITENING )
|| ( config->msk.HeaderType == RADIO_FSK_PACKET_2BYTES_LENGTH ) )
{
/* Supports only RADIO_FSK_CRC_2_BYTES_IBM or RADIO_FSK_CRC_2_BYTES_CCIT */
if( ( config->msk.CrcLength != RADIO_FSK_CRC_2_BYTES_IBM ) && ( config->msk.CrcLength != RADIO_FSK_CRC_2_BYTES_CCIT )
&& ( config->msk.CrcLength != RADIO_FSK_CRC_OFF ) )
{
return -1;
}
ConfigGeneric_t ConfigGeneric;
/*msk and fsk are union, no need for copy as fsk/msk struct are on same address*/
ConfigGeneric.TxConfig = config;
ConfigGeneric.rtx = CONFIG_TX;
if( 0UL != RFW_Init( &ConfigGeneric, RadioEvents, &TxTimeoutTimer ) )
{
return -1;
}
/* whitening off, will be processed by FW, switch off built-in radio whitening */
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) RADIO_FSK_DC_FREE_OFF;
/* Crc processed by FW, switch off built-in radio Crc */
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) RADIO_CRC_OFF;
/* length contained in Tx, but will be processed by FW after de-whitening */
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) RADIO_PACKET_FIXED_LENGTH;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) config->msk.CrcLength;
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) config->msk.Whitening;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) config->msk.HeaderType;
}
RadioStandby( );
RadioSetModem( radio_modem );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( syncword );
SUBGRF_SetWhiteningSeed( config->msk.whiteSeed );
SUBGRF_SetCrcPolynomial( config->msk.CrcPolynomial );
break;
case GENERIC_FSK:
if( config->fsk.BitRate == 0 )
{
return -1;
}
if( config->fsk.SyncWordLength > 8 )
{
return -1;
}
else
{
RADIO_MEMCPY8( syncword, config->fsk.SyncWord, config->fsk.SyncWordLength );
}
SubgRf.ModulationParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.ModulationParams.Params.Gfsk.BitRate = config->fsk.BitRate;
SubgRf.ModulationParams.Params.Gfsk.ModulationShaping = ( RadioModShapings_t ) config->fsk.ModulationShaping;
SubgRf.ModulationParams.Params.Gfsk.Fdev = config->fsk.FrequencyDeviation;
SubgRf.PacketParams.PacketType = PACKET_TYPE_GFSK;
SubgRf.PacketParams.Params.Gfsk.PreambleLength = ( config->fsk.PreambleLen ) << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_08_BITS; // don't care in tx
SubgRf.PacketParams.Params.Gfsk.SyncWordLength = ( config->fsk.SyncWordLength ) << 3; // convert byte into bit
SubgRf.PacketParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF; // don't care in tx
if( ( config->fsk.Whitening == RADIO_FSK_DC_IBM_WHITENING )
|| ( config->fsk.HeaderType == RADIO_FSK_PACKET_2BYTES_LENGTH ) )
{
/* Supports only RADIO_FSK_CRC_2_BYTES_IBM or RADIO_FSK_CRC_2_BYTES_CCIT */
if( ( config->fsk.CrcLength != RADIO_FSK_CRC_2_BYTES_IBM ) && ( config->fsk.CrcLength != RADIO_FSK_CRC_2_BYTES_CCIT )
&& ( config->fsk.CrcLength != RADIO_FSK_CRC_OFF ) )
{
return -1;
}
ConfigGeneric_t ConfigGeneric;
ConfigGeneric.rtx = CONFIG_TX;
ConfigGeneric.TxConfig = config;
if( 0UL != RFW_Init( &ConfigGeneric, RadioEvents, &TxTimeoutTimer ) )
{
return -1;
}
/* whitening off, will be processed by FW, switch off built-in radio whitening */
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) RADIO_FSK_DC_FREE_OFF;
/* Crc processed by FW, switch off built-in radio Crc */
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) RADIO_CRC_OFF;
/* length contained in Tx, but will be processed by FW after de-whitening */
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) RADIO_PACKET_FIXED_LENGTH;
}
else
{
SubgRf.PacketParams.Params.Gfsk.CrcLength = ( RadioCrcTypes_t ) config->fsk.CrcLength;
SubgRf.PacketParams.Params.Gfsk.DcFree = ( RadioDcFree_t ) config->fsk.Whitening;
SubgRf.PacketParams.Params.Gfsk.HeaderType = ( RadioPacketLengthModes_t ) config->fsk.HeaderType;
}
RadioStandby( );
RadioSetModem( MODEM_FSK );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
SUBGRF_SetSyncWord( syncword );
SUBGRF_SetWhiteningSeed( config->fsk.whiteSeed );
SUBGRF_SetCrcPolynomial( config->fsk.CrcPolynomial );
break;
case GENERIC_LORA:
SubgRf.ModulationParams.PacketType = PACKET_TYPE_LORA;
SubgRf.ModulationParams.Params.LoRa.SpreadingFactor = ( RadioLoRaSpreadingFactors_t ) config->lora.SpreadingFactor;
SubgRf.ModulationParams.Params.LoRa.Bandwidth = ( RadioLoRaBandwidths_t ) config->lora.Bandwidth;
SubgRf.ModulationParams.Params.LoRa.CodingRate = ( RadioLoRaCodingRates_t ) config->lora.Coderate;
switch( config->lora.LowDatarateOptimize )
{
case RADIO_LORA_LOWDR_OPT_OFF:
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0;
break;
case RADIO_LORA_LOWDR_OPT_ON:
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 1;
break;
case RADIO_LORA_LOWDR_OPT_AUTO:
if( ( config->lora.SpreadingFactor == RADIO_LORA_SF11 ) || ( config->lora.SpreadingFactor == RADIO_LORA_SF12 ) )
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 1;
}
else
{
SubgRf.ModulationParams.Params.LoRa.LowDatarateOptimize = 0;
}
break;
default:
break;
}
SubgRf.PacketParams.PacketType = PACKET_TYPE_LORA;
SubgRf.PacketParams.Params.LoRa.PreambleLength = config->lora.PreambleLen;
SubgRf.PacketParams.Params.LoRa.HeaderType = ( RadioLoRaPacketLengthsMode_t ) config->lora.LengthMode;
SubgRf.PacketParams.Params.LoRa.CrcMode = ( RadioLoRaCrcModes_t ) config->lora.CrcMode;
SubgRf.PacketParams.Params.LoRa.InvertIQ = ( RadioLoRaIQModes_t ) config->lora.IqInverted;
RadioStandby( );
RadioSetModem( MODEM_LORA );
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
/* WORKAROUND - Modulation Quality with 500 kHz LoRa Bandwidth, see STM32WL Erratasheet */
if( SubgRf.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 )
{
// RegTxModulation = @address 0x0889
SUBGRF_WriteRegister( SUBGHZ_SDCFG0R, SUBGRF_ReadRegister( SUBGHZ_SDCFG0R ) & ~( 1 << 2 ) );
}
else
{
// RegTxModulation = @address 0x0889
SUBGRF_WriteRegister( SUBGHZ_SDCFG0R, SUBGRF_ReadRegister( SUBGHZ_SDCFG0R ) | ( 1 << 2 ) );
}
/* WORKAROUND END */
break;
case GENERIC_BPSK:
if( ( config->bpsk.BitRate == 0 ) || ( config->bpsk.BitRate > 1000 ) )
{
return -1;
}
RadioSetModem( MODEM_BPSK );
SubgRf.ModulationParams.PacketType = PACKET_TYPE_BPSK;
SubgRf.ModulationParams.Params.Bpsk.BitRate = config->bpsk.BitRate;
SubgRf.ModulationParams.Params.Bpsk.ModulationShaping = MOD_SHAPING_DBPSK;
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
break;
default:
break;
}
SubgRf.AntSwitchPaSelect = SUBGRF_SetRfTxPower( power );
RFW_SetAntSwitch( SubgRf.AntSwitchPaSelect );
SubgRf.TxTimeout = timeout;
return 0;
#else /* RADIO_GENERIC_CONFIG_ENABLE == 1*/
return -1;
#endif /* RADIO_GENERIC_CONFIG_ENABLE == 0*/
}
/* Lora Fhss Radio interface definitions*/
#if( RADIO_LR_FHSS_IS_ON == 1 )
static uint32_t GetNextFreqIdx( uint32_t max )
{
int32_t newbit = ( ( ( prbs31_val >> 30 ) ^ ( prbs31_val >> 27 ) ) & 1 );
prbs31_val = ( ( prbs31_val << 1 ) | newbit );
return ( prbs31_val - 1 ) % ( max );
}
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
static radio_status_t RadioLrFhssSetCfg( const radio_lr_fhss_cfg_params_t *cfg_params )
{
radio_status_t status = RADIO_STATUS_UNSUPPORTED_FEATURE;
#if( RADIO_LR_FHSS_IS_ON == 1 )
/* record config parameters in Subg structure*/
SubgRf.lr_fhss.lr_fhss_params.lr_fhss_params = cfg_params->radio_lr_fhss_params.lr_fhss_params;
/* record tx timeout*/
SubgRf.lr_fhss.tx_rf_pwr_in_dbm = cfg_params->tx_rf_pwr_in_dbm;
/* Convert Hz to pll steps*/
SX_FREQ_TO_CHANNEL( SubgRf.lr_fhss.lr_fhss_params.center_freq_in_pll_steps,
cfg_params->radio_lr_fhss_params.center_frequency_in_hz );
/**/
SubgRf.lr_fhss.lr_fhss_params.device_offset = cfg_params->radio_lr_fhss_params.device_offset;
SubgRf.TxTimeout = cfg_params->tx_timeout_in_ms;
/* set power and record RF switch config*/
SubgRf.AntSwitchPaSelect = SUBGRF_SetRfTxPower( SubgRf.lr_fhss.tx_rf_pwr_in_dbm );
RadioStandby();
status = ( radio_status_t ) wl_lr_fhss_init( &SubgRf.lr_fhss.lr_fhss_params );
if( status != RADIO_STATUS_OK )
{
return status;
}
SubgRf.lr_fhss.is_lr_fhss_on = true;
#endif /* RADIO_LR_FHSS_IS_ON == 1 */
return status;
}
static radio_status_t RadioLrFhssGetTimeOnAirInMs( const radio_lr_fhss_time_on_air_params_t *params,
uint32_t *time_on_air_in_ms )
{
#if( RADIO_LR_FHSS_IS_ON == 1 )
*time_on_air_in_ms = lr_fhss_get_time_on_air_in_ms( &params->radio_lr_fhss_params.lr_fhss_params,
params->pld_len_in_bytes );
return RADIO_STATUS_OK;
#else
return RADIO_STATUS_UNSUPPORTED_FEATURE;
#endif /* RADIO_LR_FHSS_IS_ON */
}