1981 lines
69 KiB
C
1981 lines
69 KiB
C
/*!
|
||
* \file radio.c
|
||
*
|
||
* \brief Radio driver API definition
|
||
*
|
||
* \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 API definition
|
||
******************************************************************************
|
||
*/
|
||
/* Includes ------------------------------------------------------------------*/
|
||
#include <math.h>
|
||
#include "timer.h"
|
||
#include "radio.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;
|
||
} SubgRf_t;
|
||
|
||
/*!
|
||
* FSK bandwidth definition
|
||
*/
|
||
typedef struct
|
||
{
|
||
uint32_t bandwidth;
|
||
uint8_t RegValue;
|
||
} FskBandwidth_t;
|
||
|
||
/* Private define ------------------------------------------------------------*/
|
||
/* Private macro -------------------------------------------------------------*/
|
||
#define RADIO_BIT_MASK(__n) (~(1<<__n))
|
||
|
||
/**
|
||
* \brief Calculates ceiling( X / N )
|
||
*
|
||
* \param [IN] X numerator
|
||
* \param [IN] N denominator
|
||
*
|
||
*/
|
||
#ifndef DIVC
|
||
#define DIVC( X, N ) ( ( ( X ) + ( N ) - 1 ) / ( N ) )
|
||
#endif
|
||
/* Private function prototypes -----------------------------------------------*/
|
||
/*!
|
||
* \brief Returns the known FSK bandwidth registers value
|
||
*
|
||
* \param [IN] bandwidth Bandwidth value in Hz
|
||
* \retval regValue Bandwidth register value.
|
||
*/
|
||
static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth );
|
||
|
||
/*!
|
||
* \brief Initializes the radio
|
||
*
|
||
* \param [IN] events Structure containing the driver callback functions
|
||
*/
|
||
static void RadioInit( RadioEvents_t *events );
|
||
|
||
/*!
|
||
* Return current radio status
|
||
*
|
||
* \param 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 Convert the bandwitdh 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 GSFK 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 );
|
||
|
||
/*!
|
||
* \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
|
||
*/
|
||
static void 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 DIO 0 IRQ callback
|
||
*/
|
||
static void RadioOnDioIrq( RadioIrqMasks_t radioIrq );
|
||
|
||
/*!
|
||
* \brief Tx timeout timer callback
|
||
*/
|
||
static void RadioOnTxTimeoutIrq( void * context );
|
||
|
||
/*!
|
||
* \brief Rx timeout timer callback
|
||
*/
|
||
static void RadioOnRxTimeoutIrq( void * context );
|
||
|
||
/*!
|
||
* @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);
|
||
|
||
/*!
|
||
* \brief Set Tx PRBS modulated wave
|
||
* \retval none
|
||
*/
|
||
static void RadioTxPrbs( void );
|
||
|
||
/*!
|
||
* \brief Set Tx continuous wave
|
||
* \retval none
|
||
*/
|
||
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);
|
||
|
||
/* 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,
|
||
};
|
||
|
||
|
||
/*!
|
||
* Precomputed FSK bandwidth registers values
|
||
*/
|
||
const FskBandwidth_t FskBandwidths[] =
|
||
{
|
||
{ 4800 , 0x1F },
|
||
{ 5800 , 0x17 },
|
||
{ 7300 , 0x0F },
|
||
{ 9700 , 0x1E },
|
||
{ 11700 , 0x16 },
|
||
{ 14600 , 0x0E },
|
||
{ 19500 , 0x1D },
|
||
{ 23400 , 0x15 },
|
||
{ 29300 , 0x0D },
|
||
{ 39000 , 0x1C },
|
||
{ 46900 , 0x14 },
|
||
{ 58600 , 0x0C },
|
||
{ 78200 , 0x1B },
|
||
{ 93800 , 0x13 },
|
||
{ 117300, 0x0B },
|
||
{ 156200, 0x1A },
|
||
{ 187200, 0x12 },
|
||
{ 234300, 0x0A },
|
||
{ 312000, 0x19 },
|
||
{ 373600, 0x11 },
|
||
{ 467000, 0x09 },
|
||
{ 500000, 0x00 }, // Invalid Bandwidth
|
||
};
|
||
|
||
const RadioLoRaBandwidths_t Bandwidths[] = { LORA_BW_125, LORA_BW_250, LORA_BW_500 };
|
||
|
||
static uint8_t MaxPayloadLength = RADIO_RX_BUF_SIZE;
|
||
|
||
static uint8_t RadioRxPayload[RADIO_RX_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;
|
||
/* Exported functions ---------------------------------------------------------*/
|
||
static int32_t RadioSetRxGenericConfig( GenericModems_t modem, RxConfigGeneric_t* config, uint32_t rxContinuous, uint32_t symbTimeout)
|
||
{
|
||
int32_t status=0;
|
||
uint8_t syncword[8]={0};
|
||
uint8_t MaxPayloadLength;
|
||
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
|
||
{
|
||
for(int i =0; i<config->fsk.SyncWordLength; i++)
|
||
{
|
||
syncword[i]=config->fsk.SyncWord[i];
|
||
}
|
||
}
|
||
if( config->fsk.LengthMode == RADIO_FSK_PACKET_FIXED_LENGTH )
|
||
{
|
||
MaxPayloadLength = config->fsk.MaxPayloadLength;
|
||
}
|
||
else
|
||
{
|
||
MaxPayloadLength = 0xFF;
|
||
}
|
||
|
||
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 = RadioGetFskBandwidthRegValue(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;
|
||
SubgRf.PacketParams.Params.Gfsk.HeaderType = (RadioPacketLengthModes_t) config->fsk.LengthMode;
|
||
SubgRf.PacketParams.Params.Gfsk.PayloadLength = MaxPayloadLength;
|
||
SubgRf.PacketParams.Params.Gfsk.CrcLength = (RadioCrcTypes_t) config->fsk.CrcLength;
|
||
SubgRf.PacketParams.Params.Gfsk.DcFree = (RadioDcFree_t) config->fsk.Whitening;
|
||
|
||
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*/
|
||
|
||
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 DS_SX1261-2_V1.2 datasheet chapter 15.4
|
||
if( SubgRf.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
|
||
{
|
||
// RegIqPolaritySetup = @address 0x0736
|
||
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) & ~( 1 << 2 ) );
|
||
}
|
||
else
|
||
{
|
||
// RegIqPolaritySetup @address 0x0736
|
||
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) | ( 1 << 2 ) );
|
||
}
|
||
// WORKAROUND END
|
||
|
||
// Timeout Max, Timeout handled directly in SetRx function
|
||
SubgRf.RxTimeout = 0xFFFF;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
static int32_t RadioSetTxGenericConfig( GenericModems_t modem, TxConfigGeneric_t* config, int8_t power, uint32_t timeout )
|
||
{
|
||
uint8_t syncword[8]={0};
|
||
switch( modem )
|
||
{
|
||
case GENERIC_FSK:
|
||
if ((config->fsk.BitRate== 0) || (config->fsk.PreambleLen== 0))
|
||
{
|
||
return -1;
|
||
}
|
||
if ( config->fsk.SyncWordLength>8)
|
||
{
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
for(int i =0; i<config->fsk.SyncWordLength; i++)
|
||
{
|
||
syncword[i]=config->fsk.SyncWord[i];
|
||
}
|
||
}
|
||
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 = RadioGetFskBandwidthRegValue( config->fsk.Bandwidth );
|
||
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*/
|
||
SubgRf.PacketParams.Params.Gfsk.HeaderType = (RadioPacketLengthModes_t) config->fsk.HeaderType;
|
||
SubgRf.PacketParams.Params.Gfsk.CrcLength = (RadioCrcTypes_t) config->fsk.CrcLength;
|
||
SubgRf.PacketParams.Params.Gfsk.DcFree = (RadioDcFree_t) config->fsk.Whitening;
|
||
|
||
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.ModulationParams.Params.LoRa.LowDatarateOptimize = (config->lora.LowDatarateOptimize==0)?0:1;
|
||
|
||
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<52> Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1
|
||
if( SubgRf.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 )
|
||
{
|
||
// RegTxModulation = @address 0x0889
|
||
SUBGRF_WriteRegister( 0x0889, SUBGRF_ReadRegister( 0x0889 ) & ~( 1 << 2 ) );
|
||
}
|
||
else
|
||
{
|
||
// RegTxModulation = @address 0x0889
|
||
SUBGRF_WriteRegister( 0x0889, SUBGRF_ReadRegister( 0x0889 ) | ( 1 << 2 ) );
|
||
}
|
||
// WORKAROUND END
|
||
break;
|
||
case GENERIC_BPSK:
|
||
if ((config->fsk.BitRate== 0) || (config->fsk.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 );
|
||
SubgRf.TxTimeout = timeout;
|
||
return 0;
|
||
}
|
||
|
||
/* Private functions ---------------------------------------------------------*/
|
||
static uint8_t RadioGetFskBandwidthRegValue( uint32_t bandwidth )
|
||
{
|
||
uint8_t i;
|
||
|
||
if( bandwidth == 0 )
|
||
{
|
||
return( 0x1F );
|
||
}
|
||
|
||
/* ST_WORKAROUND_BEGIN: Simplified loop */
|
||
for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ); i++ )
|
||
{
|
||
if ( bandwidth < FskBandwidths[i].bandwidth )
|
||
{
|
||
return FskBandwidths[i].RegValue;
|
||
}
|
||
}
|
||
/* ST_WORKAROUND_END */
|
||
// ERROR: Value not found
|
||
while( 1 );
|
||
}
|
||
|
||
static void RadioInit( RadioEvents_t *events )
|
||
{
|
||
RadioEvents = events;
|
||
|
||
SubgRf.RxContinuous = false;
|
||
SubgRf.TxTimeout = 0;
|
||
SubgRf.RxTimeout = 0;
|
||
|
||
SUBGRF_Init( RadioOnDioIrq );
|
||
/*SubgRf.publicNetwork set to false*/
|
||
RadioSetPublicNetwork( false );
|
||
|
||
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 );
|
||
|
||
/* ST_WORKAROUND_BEGIN: Sleep radio */
|
||
RadioSleep();
|
||
/* ST_WORKAROUND_END */
|
||
// 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;
|
||
switch( modem )
|
||
{
|
||
default:
|
||
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_SIGFOX_TX:
|
||
SUBGRF_SetPacketType( PACKET_TYPE_BPSK );
|
||
break;
|
||
case MODEM_SIGFOX_RX:
|
||
SUBGRF_SetPacketType( PACKET_TYPE_GFSK );
|
||
break;
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
/* ST_WORKAROUND_BEGIN: Prevent multiple sleeps with TXCO delay */
|
||
RadioStandby( );
|
||
/* ST_WORKAROUND_END */
|
||
|
||
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;
|
||
}
|
||
}
|
||
/* ST_WORKAROUND_BEGIN: Prevent multiple sleeps with TXCO delay */
|
||
RadioStandby( );
|
||
/* ST_WORKAROUND_END */
|
||
return status;
|
||
}
|
||
|
||
static uint32_t RadioRandom( void )
|
||
{
|
||
uint32_t rnd = 0;
|
||
|
||
/*
|
||
* Radio setup for random number generation
|
||
*/
|
||
/* Set LoRa modem ON */
|
||
RadioSetModem( MODEM_LORA );
|
||
|
||
/* Disable LoRa 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 )
|
||
{
|
||
|
||
uint8_t modReg;
|
||
SubgRf.RxContinuous = rxContinuous;
|
||
if( rxContinuous == true )
|
||
{
|
||
symbTimeout = 0;
|
||
}
|
||
if( fixLen == true )
|
||
{
|
||
MaxPayloadLength = payloadLen;
|
||
}
|
||
else
|
||
{
|
||
MaxPayloadLength = 0xFF;
|
||
}
|
||
|
||
switch( modem )
|
||
{
|
||
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 = RadioGetFskBandwidthRegValue( 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(0x8b8);
|
||
modReg&=RADIO_BIT_MASK(4);
|
||
RadioWrite(0x8b8, modReg);
|
||
/* Lower the threshold of cfo_reset */
|
||
RadioWrite(0x8b9, 0x4 );
|
||
|
||
/* Bigger rssi_len (stability AGC). Reg 0x89b, bits[2 :4] = 0x1 */
|
||
modReg= RadioRead(0x89b);
|
||
modReg&=( RADIO_BIT_MASK(2) & RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
|
||
RadioWrite(0x89b, (modReg| (0x1<<3) ) );
|
||
|
||
/* Biger afc_pbl_len (better frequency correction). Reg 0x6d1, bits[3 :4] = 0x3 */
|
||
modReg= RadioRead(0x6d1);
|
||
modReg&=( RADIO_BIT_MASK(3) & RADIO_BIT_MASK(4) );
|
||
RadioWrite(0x6d1, (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(0x6ac);
|
||
modReg&=( RADIO_BIT_MASK(4) & RADIO_BIT_MASK(5) & RADIO_BIT_MASK(6) );
|
||
RadioWrite(0x6ac, (modReg| (0x5<<4) ));
|
||
|
||
SubgRf.RxTimeout = ( uint32_t )(( symbTimeout * 8 * 1000 ) /datarate);
|
||
break;
|
||
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 = RadioGetFskBandwidthRegValue( 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( ( SubgRf.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
|
||
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
|
||
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
|
||
SUBGRF_SetSyncWord( ( uint8_t[] ){ 0xC1, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00 } );
|
||
SUBGRF_SetWhiteningSeed( 0x01FF );
|
||
|
||
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( ( SubgRf.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
|
||
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
|
||
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
|
||
SUBGRF_SetLoRaSymbNumTimeout( symbTimeout );
|
||
|
||
/* WORKAROUND - Optimizing the Inverted IQ Operation, see DS_SX1261-2_V1.2 datasheet chapter 15.4 */
|
||
if( SubgRf.PacketParams.Params.LoRa.InvertIQ == LORA_IQ_INVERTED )
|
||
{
|
||
/* RegIqPolaritySetup = @address 0x0736 */
|
||
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) & ~( 1 << 2 ) );
|
||
}
|
||
else
|
||
{
|
||
/* RegIqPolaritySetup @address 0x0736 */
|
||
SUBGRF_WriteRegister( 0x0736, SUBGRF_ReadRegister( 0x0736 ) | ( 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 )
|
||
{
|
||
|
||
switch( modem )
|
||
{
|
||
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;
|
||
|
||
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 = RadioGetFskBandwidthRegValue( 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( ( SubgRf.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
|
||
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( ( SubgRf.ModulationParams.PacketType == PACKET_TYPE_GFSK ) ? MODEM_FSK : MODEM_LORA );
|
||
SUBGRF_SetModulationParams( &SubgRf.ModulationParams );
|
||
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
|
||
default:
|
||
break;
|
||
}
|
||
|
||
/* WORKAROUND - Modulation Quality with 500 kHz LoRa<52> Bandwidth, see DS_SX1261-2_V1.2 datasheet chapter 15.1 */
|
||
if( ( modem == MODEM_LORA ) && ( SubgRf.ModulationParams.Params.LoRa.Bandwidth == LORA_BW_500 ) )
|
||
{
|
||
/* RegTxModulation = @address 0x0889 */
|
||
SUBGRF_WriteRegister( 0x0889, SUBGRF_ReadRegister( 0x0889 ) & ~( 1 << 2 ) );
|
||
}
|
||
else
|
||
{
|
||
/* RegTxModulation = @address 0x0889 */
|
||
SUBGRF_WriteRegister( 0x0889, SUBGRF_ReadRegister( 0x0889 ) | ( 1 << 2 ) );
|
||
}
|
||
/* WORKAROUND END */
|
||
|
||
SubgRf.AntSwitchPaSelect = SUBGRF_SetRfTxPower( power );
|
||
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 )
|
||
{
|
||
/*
|
||
const RadioAddressComp_t addrComp = RADIO_ADDRESSCOMP_FILT_OFF;
|
||
const uint8_t syncWordLength = 3;
|
||
|
||
return ( preambleLen << 3 ) +
|
||
( ( fixLen == false ) ? 8 : 0 ) +
|
||
( syncWordLength << 3 ) +
|
||
( ( payloadLen +
|
||
( addrComp == RADIO_ADDRESSCOMP_FILT_OFF ? 0 : 1 ) +
|
||
( ( crcOn == true ) ? 2 : 0 )
|
||
) << 3
|
||
);
|
||
*/
|
||
/* ST_WORKAROUND_BEGIN: Simplified calculation without const values */
|
||
return ( preambleLen << 3 ) +
|
||
( ( fixLen == false ) ? 8 : 0 ) + 24 +
|
||
( ( payloadLen + ( ( crcOn == true ) ? 2 : 0 ) ) << 3 );
|
||
/* ST_WORKAROUND_END */
|
||
}
|
||
|
||
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 void RadioSend( uint8_t *buffer, uint8_t size )
|
||
{
|
||
/* Radio IRQ is set to DIO1 by default */
|
||
SUBGRF_SetDioIrqParams( IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_TX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_RADIO_NONE,
|
||
IRQ_RADIO_NONE );
|
||
|
||
/* ST_WORKAROUND_BEGIN : Set the debug pin and update the radio switch */
|
||
/* Set DBG pin */
|
||
DBG_GPIO_RADIO_TX(SET);
|
||
|
||
/* Set RF switch */
|
||
SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_TX);
|
||
/* ST_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_FSK:
|
||
{
|
||
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;
|
||
}
|
||
case MODEM_SIGFOX_TX:
|
||
{
|
||
uint8_t outBuffer[35] = {0};
|
||
/*from bpsk to dbpsk*/
|
||
/*first 1 bit duplicated*/
|
||
payload_integration( outBuffer, buffer, size );
|
||
|
||
SubgRf.PacketParams.PacketType = PACKET_TYPE_BPSK;
|
||
SubgRf.PacketParams.Params.Bpsk.PayloadLength = size + 1;
|
||
SUBGRF_SetPacketParams( &SubgRf.PacketParams );
|
||
|
||
if( SubgRf.ModulationParams.Params.Bpsk.BitRate == 100 )
|
||
{
|
||
RadioWrite( 0x00F1, 0 ); // clean start-up LSB
|
||
RadioWrite( 0x00F0, 0 ); // clean start-up MSB
|
||
RadioWrite( 0x00F3, 0x70 ); // clean end of frame LSB
|
||
RadioWrite( 0x00F2, 0x1D ); // clean end of frame MSB
|
||
}
|
||
else // 600 bps
|
||
{
|
||
RadioWrite( 0x00F1, 0 ); // clean start-up LSB
|
||
RadioWrite( 0x00F0, 0 ); // clean start-up MSB
|
||
RadioWrite( 0x00F3, 0xE1 ); // clean end of frame LSB
|
||
RadioWrite( 0x00F2, 0x04 ); // clean end of frame MSB
|
||
}
|
||
|
||
uint16_t bitNum = (size*8)+2;
|
||
RadioWrite( 0x00F4, ( bitNum >> 8 ) & 0x00FF ); // limit frame
|
||
RadioWrite( 0x00F5, bitNum & 0x00FF ); // limit frame
|
||
//
|
||
SUBGRF_SendPayload( outBuffer, size+1 , 0xFFFFFF );
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
TimerSetValue( &TxTimeoutTimer, SubgRf.TxTimeout );
|
||
TimerStart( &TxTimeoutTimer );
|
||
}
|
||
|
||
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 )
|
||
{
|
||
/* Radio IRQ is set to DIO1 by default */
|
||
SUBGRF_SetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_RADIO_NONE,
|
||
IRQ_RADIO_NONE );
|
||
|
||
if( timeout != 0 )
|
||
{
|
||
TimerSetValue( &RxTimeoutTimer, timeout );
|
||
TimerStart( &RxTimeoutTimer );
|
||
}
|
||
|
||
/* ST_WORKAROUND_BEGIN : Set the debug pin and update the radio switch */
|
||
/* Set DBG pin */
|
||
DBG_GPIO_RADIO_RX(SET);
|
||
|
||
/* RF switch configuration */
|
||
SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_RX);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
if( SubgRf.RxContinuous == true )
|
||
{
|
||
SUBGRF_SetRx( 0xFFFFFF ); // Rx Continuous
|
||
}
|
||
else
|
||
{
|
||
SUBGRF_SetRx( SubgRf.RxTimeout << 6 );
|
||
}
|
||
}
|
||
|
||
static void RadioRxBoosted( uint32_t timeout )
|
||
{
|
||
SUBGRF_SetDioIrqParams( IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_RADIO_ALL, //IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT,
|
||
IRQ_RADIO_NONE,
|
||
IRQ_RADIO_NONE );
|
||
|
||
if( timeout != 0 )
|
||
{
|
||
TimerSetValue( &RxTimeoutTimer, timeout );
|
||
TimerStart( &RxTimeoutTimer );
|
||
}
|
||
|
||
/* 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 )
|
||
{
|
||
/* RF switch configuration */
|
||
SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_RX);
|
||
SUBGRF_SetRxDutyCycle( rxTime, sleepTime );
|
||
}
|
||
|
||
static void RadioStartCad( void )
|
||
{
|
||
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 )
|
||
{
|
||
uint32_t timeout = (uint32_t)time * 1000;
|
||
uint8_t antswitchpow;
|
||
|
||
SUBGRF_SetRfFrequency( freq );
|
||
|
||
antswitchpow = SUBGRF_SetRfTxPower( power );
|
||
|
||
/* 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 )
|
||
{
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_TX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
if( ( RadioEvents != NULL ) && ( RadioEvents->TxTimeout != NULL ) )
|
||
{
|
||
RadioEvents->TxTimeout( );
|
||
}
|
||
}
|
||
|
||
static void RadioOnRxTimeoutIrq( void* context )
|
||
{
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_RX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
if( ( RadioEvents != NULL ) && ( RadioEvents->RxTimeout != NULL ) )
|
||
{
|
||
RadioEvents->RxTimeout( );
|
||
}
|
||
}
|
||
|
||
static void RadioOnDioIrq( RadioIrqMasks_t radioIrq )
|
||
{
|
||
SubgRf.RadioIrq = radioIrq;
|
||
|
||
RadioIrqProcess();
|
||
}
|
||
|
||
static void RadioIrqProcess( void )
|
||
{
|
||
uint8_t size;
|
||
|
||
switch (SubgRf.RadioIrq)
|
||
{
|
||
case IRQ_TX_DONE:
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_TX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
TimerStop( &TxTimeoutTimer );
|
||
SUBGRF_SetStandby( STDBY_RC );
|
||
if( ( RadioEvents != NULL ) && ( RadioEvents->TxDone != NULL ) )
|
||
{
|
||
RadioEvents->TxDone( );
|
||
}
|
||
break;
|
||
|
||
case IRQ_RX_DONE:
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_RX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
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 DS_SX1261-2_V1.2 datasheet chapter 15.3
|
||
// RegRtcControl = @address 0x0902
|
||
SUBGRF_WriteRegister( 0x0902, 0x00 );
|
||
// RegEventMask = @address 0x0944
|
||
SUBGRF_WriteRegister( 0x0944, SUBGRF_ReadRegister( 0x0944 ) | ( 1 << 1 ) );
|
||
// WORKAROUND END
|
||
}
|
||
SUBGRF_GetPayload( RadioRxPayload, &size , 255 );
|
||
SUBGRF_GetPacketStatus( &(SubgRf.PacketStatus) );
|
||
if( ( RadioEvents != NULL ) && ( RadioEvents->RxDone != NULL ) )
|
||
{
|
||
switch (SubgRf.PacketStatus.packetType)
|
||
{
|
||
case PACKET_TYPE_LORA:
|
||
RadioEvents->RxDone( RadioRxPayload, size, SubgRf.PacketStatus.Params.LoRa.RssiPkt, SubgRf.PacketStatus.Params.LoRa.SnrPkt );
|
||
break;
|
||
default:
|
||
RadioEvents->RxDone( RadioRxPayload, size, SubgRf.PacketStatus.Params.Gfsk.RssiAvg, (int8_t)(SubgRf.PacketStatus.Params.Gfsk.FreqError) );
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case IRQ_CRC_ERROR:
|
||
|
||
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;
|
||
|
||
|
||
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:
|
||
if( SUBGRF_GetOperatingMode( ) == MODE_TX )
|
||
{
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_TX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
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 )
|
||
{
|
||
/* ST_WORKAROUND_BEGIN: Reset DBG pin */
|
||
DBG_GPIO_RADIO_RX(RST);
|
||
/* ST_WORKAROUND_END */
|
||
|
||
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" );
|
||
break;
|
||
|
||
case IRQ_SYNCWORD_VALID:
|
||
|
||
MW_LOG( TS_ON, VLEVEL_M, "SYNC OK\r\n" );
|
||
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;
|
||
|
||
default:
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
static void RadioTxPrbs(void )
|
||
{
|
||
SUBGRF_SetSwitch(SubgRf.AntSwitchPaSelect, RFSWITCH_TX);
|
||
Radio.Write(0x6B8, 0x2d); // sel mode prbs9 instead of preamble
|
||
SUBGRF_SetTxInfinitePreamble();
|
||
SUBGRF_SetTx(0x0fffff);
|
||
}
|
||
|
||
static void RadioTxCw( int8_t power )
|
||
{
|
||
uint8_t paselect = SUBGRF_SetRfTxPower( power );
|
||
SUBGRF_SetSwitch( paselect, RFSWITCH_TX);
|
||
SUBGRF_SetTxContinuousWave();
|
||
}
|
||
|
||
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;
|
||
int 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 rigth*/
|
||
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) ;
|
||
}
|
||
|
||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|