/*!
* \file RegionAU915.h
*
* \brief Region definition for AU915
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \author Johannes Bruder ( STACKFORCE )
*
* \defgroup REGIONAU915 Region AU915
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_AU915_H__
#define __REGION_AU915_H__
#include "region/Region.h"
#define AU915_PING_SLOT_CHANNEL_FREQ 923300000
/*!
* LoRaMac maximum number of channels
*/
#define AU915_MAX_NB_CHANNELS 72
/*!
* Minimal datarate that can be used by the node
*/
#define AU915_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define AU915_TX_MAX_DATARATE DR_5
/*!
* Minimal datarate that can be used by the node
*/
#define AU915_RX_MIN_DATARATE DR_8
/*!
* Maximal datarate that can be used by the node
*/
#define AU915_RX_MAX_DATARATE DR_13
/*!
* Default datarate used by the node
*/
#define AU915_DEFAULT_DATARATE DR_0
/*!
* The minimum datarate which is used when the
* dwell time is limited.
*/
#define AU915_DWELL_LIMIT_DATARATE DR_2
/*!
* Minimal Rx1 receive datarate offset
*/
#define AU915_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define AU915_MAX_RX1_DR_OFFSET 3
/*!
* Default Rx1 receive datarate offset
*/
#define AU915_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define AU915_MIN_TX_POWER TX_POWER_10
/*!
* Maximal Tx output power that can be used by the node
*/
#define AU915_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define AU915_DEFAULT_TX_POWER TX_POWER_5
/*!
* Default uplink dwell time configuration
*/
#define AU915_DEFAULT_UPLINK_DWELL_TIME 0
/*!
* Default downlink dwell time configuration
*/
#define AU915_DEFAULT_DOWNLINK_DWELL_TIME 0
/*!
* Default Max EIRP
*/
#define AU915_DEFAULT_MAX_EIRP 30.0f
/*!
* Default antenna gain
*/
#define AU915_DEFAULT_ANTENNA_GAIN 0.0f
/*!
* ADR Ack limit
*/
#define AU915_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define AU915_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define AU915_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define AU915_MAX_RX_WINDOW 1000
/*!
* Receive delay 1
*/
#define AU915_RECEIVE_DELAY1 5000
/*!
* Receive delay 2
*/
#define AU915_RECEIVE_DELAY2 6000
/*!
* Join accept delay 1
*/
#define AU915_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define AU915_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define AU915_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define AU915_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define AU915_ACK_TIMEOUT_RND 1000
/*!
* Second reception window channel frequency definition.
*/
#define AU915_RX_WND_2_FREQ 923300000
/*!
* Second reception window channel datarate definition.
*/
#define AU915_RX_WND_2_DR DR_8
/*
* CLASS B
*/
/*!
* Beacon frequency
*/
#define AU915_BEACON_CHANNEL_FREQ 923300000
/*!
* Beacon frequency channel stepwidth
*/
#define AU915_BEACON_CHANNEL_STEPWIDTH 600000
/*!
* Number of possible beacon channels
*/
#define AU915_BEACON_NB_CHANNELS 8
/*!
* Payload size of a beacon frame
*/
#define AU915_BEACON_SIZE 19
/*!
* Size of RFU 1 field
*/
#define AU915_RFU1_SIZE 3
/*!
* Size of RFU 2 field
*/
#define AU915_RFU2_SIZE 1
/*!
* Datarate of the beacon channel
*/
#define AU915_BEACON_CHANNEL_DR DR_10
/*!
* Bandwith of the beacon channel
*/
#define AU915_BEACON_CHANNEL_BW 2
/*!
* Ping slot channel datarate
*/
#define AU915_PING_SLOT_CHANNEL_DR DR_10
/*!
* LoRaMac maximum number of bands
*/
#define AU915_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
*/
#define AU915_BAND0 { 1, AU915_MAX_TX_POWER, 0, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
*/
#define AU915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 )
/*!
* Defines the last channel for RX window 1 for US band
*/
#define AU915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 )
/*!
* Defines the step width of the channels for RX window 1
*/
#define AU915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 )
/*!
* Data rates table definition
*/
static const uint8_t DataratesAU915[] = { 12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsAU915[] = { 125000, 125000, 125000, 125000, 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 };
/*!
* Up/Down link data rates offset definition
*/
static const int8_t DatarateOffsetsAU915[7][6] =
{
{ DR_8 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_0
{ DR_9 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_1
{ DR_10, DR_9 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_2
{ DR_11, DR_10, DR_9 , DR_8 , DR_8 , DR_8 }, // DR_3
{ DR_12, DR_11, DR_10, DR_9 , DR_8 , DR_8 }, // DR_4
{ DR_13, DR_12, DR_11, DR_10, DR_9 , DR_8 }, // DR_5
{ DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6
};
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
* The table is valid for the dwell time configuration of 0 for uplinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell0AU915[] = { 51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
* The table is valid for the dwell time configuration of 0 for uplinks. The table provides
* repeater support.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
* The table is valid for the dwell time configuration of 1 for uplinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell1AU915[] = { 0, 0, 11, 53, 125, 242, 242, 0, 53, 129, 129, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
* The table is valid for the dwell time configuration of 1 for uplinks. The table provides
* repeater support.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterDwell1AU915[] = { 0, 0, 11, 53, 125, 242, 242, 0, 33, 119, 129, 242, 242, 242, 242 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionAU915InitDefaults( InitDefaultsParams_t* params );
/*!
* \brief Returns a pointer to the internal context and its size.
*
* \param [OUT] params Pointer to the function parameters.
*
* \retval Points to a structure where the module store its non-volatile context.
*/
void* RegionAU915GetNvmCtx( GetPhyParams_t* params );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] currentDr Current datarate.
*
* \retval Datarate to apply.
*/
int8_t RegionAU915AlternateDr( int8_t currentDr, AlternateDrType_t type );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
//void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
//////void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*!
* \brief Sets the radio into beacon reception mode
*
* \param [IN] rxBeaconSetup Pointer to the function parameters
*/
void RegionAU915RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr );
/*! \} defgroup REGIONAU915 */
#endif // __REGION_AU915_H__
/*!
* \file RegionAU915.c
*
* \brief Region implementation for AU915
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013-2017 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*/
/**
******************************************************************************
*
* Portions COPYRIGHT 2020 STMicroelectronics
*
* @file RegionAU915.c
* @author MCD Application Team
* @brief Region implementation for AU915
******************************************************************************
*/
#include "radio.h"
#include "RegionAU915.h"
#include "RegionBaseUS.h"
// Definitions
#define CHANNELS_MASK_SIZE 6
// A mask to select only valid 500KHz channels
#define CHANNELS_MASK_500KHZ_MASK 0x00FF
/* The HYBRID_DEFAULT_MASKx define the enabled channels in Hybrid mode*/
/* Note: they can be redefined in lorawan_conf.h*/
#ifndef HYBRID_DEFAULT_MASK0 /*enabled channels from channel 15 down to channel 0*/
#define HYBRID_DEFAULT_MASK0 0x00FF /*channel 7 down to channel 0 enabled*/
#endif
#ifndef HYBRID_DEFAULT_MASK1 /*enabled channels from channel 31 down to channel 16*/
#define HYBRID_DEFAULT_MASK1 0x0000
#endif
#ifndef HYBRID_DEFAULT_MASK2 /*enabled channels from channel 47 down to channel 32*/
#define HYBRID_DEFAULT_MASK2 0x0000
#endif
#ifndef HYBRID_DEFAULT_MASK3 /*enabled channels from channel 63 down to channel 48*/
#define HYBRID_DEFAULT_MASK3 0x0000
#endif
#ifndef HYBRID_DEFAULT_MASK4 /*enabled channels from channel 71 down to channel 64*/
#define HYBRID_DEFAULT_MASK4 0x0000
#endif
#if defined( REGION_AU915 )
/*
* Non-volatile module context.
*/
static RegionNvmDataGroup1_t* RegionNvmGroup1;
static RegionNvmDataGroup2_t* RegionNvmGroup2;
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
static Band_t* RegionBands;
#endif /* REGION_VERSION */
static bool VerifyRfFreq( uint32_t freq )
{
// Check radio driver support
if( Radio.CheckRfFrequency( freq ) == false )
{
return false;
}
// Rx frequencies
if( ( freq < AU915_FIRST_RX1_CHANNEL ) ||
( freq > AU915_LAST_RX1_CHANNEL ) ||
( ( ( freq - ( uint32_t ) AU915_FIRST_RX1_CHANNEL ) % ( uint32_t ) AU915_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
{
return false;
}
// Tx frequencies for 125kHz
// Also includes the range for 500kHz channels
if( ( freq < 915200000 ) || ( freq > 927800000 ) )
{
return false;
}
return true;
}
static TimerTime_t GetTimeOnAir( int8_t datarate, uint16_t pktLen )
{
int8_t phyDr = DataratesAU915[datarate];
uint32_t bandwidth = RegionCommonGetBandwidth( datarate, BandwidthsAU915 );
return Radio.TimeOnAir( MODEM_LORA, bandwidth, phyDr, 1, 8, false, pktLen, true );
}
#endif /* REGION_AU915 */
PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
{
PhyParam_t phyParam = { 0 };
#if defined( REGION_AU915 )
switch( getPhy->Attribute )
{
case PHY_MIN_RX_DR:
{
if( getPhy->DownlinkDwellTime == 0)
{
phyParam.Value = AU915_RX_MIN_DATARATE;
}
else
{
phyParam.Value = AU915_DWELL_LIMIT_DATARATE;
}
break;
}
case PHY_MIN_TX_DR:
{
if( getPhy->UplinkDwellTime == 0)
{
phyParam.Value = AU915_TX_MIN_DATARATE;
}
else
{
phyParam.Value = AU915_DWELL_LIMIT_DATARATE;
}
break;
}
case PHY_DEF_TX_DR:
{
phyParam.Value = AU915_DEFAULT_DATARATE;
break;
}
case PHY_NEXT_LOWER_TX_DR:
{
RegionCommonGetNextLowerTxDrParams_t nextLowerTxDrParams =
{
.CurrentDr = getPhy->Datarate,
.MaxDr = ( int8_t )AU915_TX_MAX_DATARATE,
.MinDr = ( int8_t )( ( getPhy->UplinkDwellTime == 0 ) ? AU915_TX_MIN_DATARATE : AU915_DWELL_LIMIT_DATARATE ),
.NbChannels = AU915_MAX_NB_CHANNELS,
.ChannelsMask = RegionNvmGroup2->ChannelsMask,
.Channels = RegionNvmGroup2->Channels,
};
phyParam.Value = RegionCommonGetNextLowerTxDr( &nextLowerTxDrParams );
break;
}
case PHY_MAX_TX_POWER:
{
phyParam.Value = AU915_MAX_TX_POWER;
break;
}
case PHY_DEF_TX_POWER:
{
phyParam.Value = AU915_DEFAULT_TX_POWER;
break;
}
case PHY_DEF_ADR_ACK_LIMIT:
{
phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_LIMIT;
break;
}
case PHY_DEF_ADR_ACK_DELAY:
{
phyParam.Value = REGION_COMMON_DEFAULT_ADR_ACK_DELAY;
break;
}
case PHY_MAX_PAYLOAD:
{
if( getPhy->UplinkDwellTime == 0 )
{
phyParam.Value = MaxPayloadOfDatarateDwell0AU915[getPhy->Datarate];
}
else
{
phyParam.Value = MaxPayloadOfDatarateDwell1AU915[getPhy->Datarate];
}
break;
}
/* ST_WORKAROUND_BEGIN: Keep repeater feature */
case PHY_MAX_PAYLOAD_REPEATER:
{
if( getPhy->UplinkDwellTime == 0)
{
phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AU915[getPhy->Datarate];
}
else
{
phyParam.Value = MaxPayloadOfDatarateRepeaterDwell1AU915[getPhy->Datarate];
}
break;
}
/* ST_WORKAROUND_END */
case PHY_DUTY_CYCLE:
{
phyParam.Value = AU915_DUTY_CYCLE_ENABLED;
break;
}
case PHY_MAX_RX_WINDOW:
{
phyParam.Value = AU915_MAX_RX_WINDOW;
break;
}
case PHY_RECEIVE_DELAY1:
{
phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY1;
break;
}
case PHY_RECEIVE_DELAY2:
{
phyParam.Value = REGION_COMMON_DEFAULT_RECEIVE_DELAY2;
break;
}
case PHY_JOIN_ACCEPT_DELAY1:
{
phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY1;
break;
}
case PHY_JOIN_ACCEPT_DELAY2:
{
phyParam.Value = REGION_COMMON_DEFAULT_JOIN_ACCEPT_DELAY2;
break;
}
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
case PHY_MAX_FCNT_GAP:
{
phyParam.Value = REGION_COMMON_DEFAULT_MAX_FCNT_GAP;
break;
}
case PHY_ACK_TIMEOUT:
{
phyParam.Value = ( REGION_COMMON_DEFAULT_ACK_TIMEOUT + randr( -REGION_COMMON_DEFAULT_ACK_TIMEOUT_RND, REGION_COMMON_DEFAULT_ACK_TIMEOUT_RND ) );
break;
}
#elif (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
case PHY_RETRANSMIT_TIMEOUT:
{
phyParam.Value = ( REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT + randr( -REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND, REGION_COMMON_DEFAULT_RETRANSMIT_TIMEOUT_RND ) );
break;
}
#endif /* REGION_VERSION */
case PHY_DEF_DR1_OFFSET:
{
phyParam.Value = REGION_COMMON_DEFAULT_RX1_DR_OFFSET;
break;
}
case PHY_DEF_RX2_FREQUENCY:
{
phyParam.Value = AU915_RX_WND_2_FREQ;
break;
}
case PHY_DEF_RX2_DR:
{
phyParam.Value = AU915_RX_WND_2_DR;
break;
}
case PHY_CHANNELS_MASK:
{
phyParam.ChannelsMask = RegionNvmGroup2->ChannelsMask;
break;
}
case PHY_CHANNELS_DEFAULT_MASK:
{
phyParam.ChannelsMask = RegionNvmGroup2->ChannelsDefaultMask;
break;
}
case PHY_MAX_NB_CHANNELS:
{
phyParam.Value = AU915_MAX_NB_CHANNELS;
break;
}
case PHY_CHANNELS:
{
phyParam.Channels = RegionNvmGroup2->Channels;
break;
}
case PHY_DEF_UPLINK_DWELL_TIME:
{
phyParam.Value = AU915_DEFAULT_UPLINK_DWELL_TIME;
break;
}
case PHY_DEF_DOWNLINK_DWELL_TIME:
{
phyParam.Value = REGION_COMMON_DEFAULT_DOWNLINK_DWELL_TIME;
break;
}
case PHY_DEF_MAX_EIRP:
{
phyParam.fValue = AU915_DEFAULT_MAX_EIRP;
break;
}
case PHY_DEF_ANTENNA_GAIN:
{
phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN;
break;
}
case PHY_BEACON_CHANNEL_FREQ:
{
phyParam.Value = RegionBaseUSCalcDownlinkFrequency( getPhy->Channel,
AU915_BEACON_CHANNEL_FREQ,
AU915_BEACON_CHANNEL_STEPWIDTH );
break;
}
case PHY_BEACON_FORMAT:
{
phyParam.BeaconFormat.BeaconSize = AU915_BEACON_SIZE;
phyParam.BeaconFormat.Rfu1Size = AU915_RFU1_SIZE;
phyParam.BeaconFormat.Rfu2Size = AU915_RFU2_SIZE;
break;
}
case PHY_BEACON_CHANNEL_DR:
{
phyParam.Value = AU915_BEACON_CHANNEL_DR;
break;
}
case PHY_BEACON_NB_CHANNELS:
{
phyParam.Value = AU915_BEACON_NB_CHANNELS;
break;
}
case PHY_PING_SLOT_CHANNEL_FREQ:
{
phyParam.Value = RegionBaseUSCalcDownlinkFrequency( getPhy->Channel,
AU915_PING_SLOT_CHANNEL_FREQ,
AU915_BEACON_CHANNEL_STEPWIDTH );
break;
}
case PHY_PING_SLOT_CHANNEL_DR:
{
phyParam.Value = AU915_PING_SLOT_CHANNEL_DR;
break;
}
case PHY_PING_SLOT_NB_CHANNELS:
{
phyParam.Value = AU915_BEACON_NB_CHANNELS;
break;
}
case PHY_SF_FROM_DR:
{
phyParam.Value = DataratesAU915[getPhy->Datarate];
break;
}
case PHY_BW_FROM_DR:
{
phyParam.Value = RegionCommonGetBandwidth( getPhy->Datarate, BandwidthsAU915 );
break;
}
default:
{
break;
}
}
#endif /* REGION_AU915 */
return phyParam;
}
void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
#if defined( REGION_AU915 )
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
RegionCommonSetBandTxDone( &RegionNvmGroup1->Bands[RegionNvmGroup2->Channels[txDone->Channel].Band],
txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
#elif (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
RegionCommonSetBandTxDone( &RegionBands[RegionNvmGroup2->Channels[txDone->Channel].Band],
txDone->LastTxAirTime, txDone->Joined, txDone->ElapsedTimeSinceStartUp );
#endif /* REGION_VERSION */
#endif /* REGION_AU915 */
}
void RegionAU915InitDefaults( InitDefaultsParams_t* params )
{
#if defined( REGION_AU915 )
Band_t bands[AU915_MAX_NB_BANDS] =
{
AU915_BAND0
};
switch( params->Type )
{
case INIT_TYPE_DEFAULTS:
{
if( ( params->NvmGroup1 == NULL ) || ( params->NvmGroup2 == NULL ) )
{
return;
}
RegionNvmGroup1 = (RegionNvmDataGroup1_t*) params->NvmGroup1;
RegionNvmGroup2 = (RegionNvmDataGroup2_t*) params->NvmGroup2;
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
RegionBands = (Band_t*) params->Bands;
#endif /* REGION_VERSION */
// Initialize 8 bit channel groups index
RegionNvmGroup1->JoinChannelGroupsCurrentIndex = 0;
// Initialize the join trials counter
RegionNvmGroup1->JoinTrialsCounter = 0;
// Default bands
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
memcpy1( ( uint8_t* )RegionNvmGroup1->Bands, ( uint8_t* )bands, sizeof( Band_t ) * AU915_MAX_NB_BANDS );
#elif (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
memcpy1( ( uint8_t* )RegionBands, ( uint8_t* )bands, sizeof( Band_t ) * AU915_MAX_NB_BANDS );
#endif /* REGION_VERSION */
// Channels
for( uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++ )
{
// 125 kHz channels
RegionNvmGroup2->Channels[i].Frequency = 915200000 + i * 200000;
RegionNvmGroup2->Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
RegionNvmGroup2->Channels[i].Band = 0;
}
for( uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++ )
{
// 500 kHz channels
RegionNvmGroup2->Channels[i].Frequency = 915900000 + ( i - ( AU915_MAX_NB_CHANNELS - 8 ) ) * 1600000;
RegionNvmGroup2->Channels[i].DrRange.Value = ( DR_6 << 4 ) | DR_6;
RegionNvmGroup2->Channels[i].Band = 0;
}
// Initialize channels default mask
/* ST_WORKAROUND_BEGIN: Hybrid mode */
#if ( HYBRID_ENABLED == 1 )
RegionNvmGroup2->ChannelsDefaultMask[0] = HYBRID_DEFAULT_MASK0;
RegionNvmGroup2->ChannelsDefaultMask[1] = HYBRID_DEFAULT_MASK1;
RegionNvmGroup2->ChannelsDefaultMask[2] = HYBRID_DEFAULT_MASK2;
RegionNvmGroup2->ChannelsDefaultMask[3] = HYBRID_DEFAULT_MASK3;
RegionNvmGroup2->ChannelsDefaultMask[4] = HYBRID_DEFAULT_MASK4;
RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;
#else
RegionNvmGroup2->ChannelsDefaultMask[0] = 0x00FF;
RegionNvmGroup2->ChannelsDefaultMask[1] = 0x0000;
RegionNvmGroup2->ChannelsDefaultMask[2] = 0x0000;
RegionNvmGroup2->ChannelsDefaultMask[3] = 0x0000;
RegionNvmGroup2->ChannelsDefaultMask[4] = 0x0000;
RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;
#endif /* HYBRID_ENABLED == 1 */
/* ST_WORKAROUND_END */
// Copy channels default mask
RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
// Copy into channels mask remaining
RegionCommonChanMaskCopy( RegionNvmGroup1->ChannelsMaskRemaining, RegionNvmGroup2->ChannelsMask, CHANNELS_MASK_SIZE );
break;
}
case INIT_TYPE_RESET_TO_DEFAULT_CHANNELS:
{
// Intentional fallthrough
}
case INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS:
{
// Copy channels default mask
RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, RegionNvmGroup2->ChannelsDefaultMask, CHANNELS_MASK_SIZE );
for( uint8_t i = 0; i < CHANNELS_MASK_SIZE; i++ )
{ // Copy-And the channels mask
RegionNvmGroup1->ChannelsMaskRemaining[i] &= RegionNvmGroup2->ChannelsMask[i];
}
break;
}
default:
{
break;
}
}
#endif /* REGION_AU915 */
}
bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
#if defined( REGION_AU915 )
switch( phyAttribute )
{
case PHY_FREQUENCY:
{
return VerifyRfFreq( verify->Frequency );
}
case PHY_TX_DR:
case PHY_DEF_TX_DR:
{
if( verify->DatarateParams.UplinkDwellTime == 0 )
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE );
}
else
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_DWELL_LIMIT_DATARATE, AU915_TX_MAX_DATARATE );
}
}
case PHY_RX_DR:
{
if( verify->DatarateParams.UplinkDwellTime == 0 )
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE );
}
else
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_DWELL_LIMIT_DATARATE, AU915_RX_MAX_DATARATE );
}
}
case PHY_DEF_TX_POWER:
case PHY_TX_POWER:
{
// Remark: switched min and max!
return RegionCommonValueInRange( verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER );
}
case PHY_DUTY_CYCLE:
{
return AU915_DUTY_CYCLE_ENABLED;
}
default:
return false;
}
#else
return false;
#endif /* REGION_AU915 */
}
void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList )
{
#if defined( REGION_AU915 )
// Size of the optional CF list must be 16 byte
if( applyCFList->Size != 16 )
{
return;
}
// Last byte CFListType must be 0x01 to indicate the CFList contains a series of ChMask fields
if( applyCFList->Payload[15] != 0x01 )
{
return;
}
// ChMask0 - ChMask4 must be set (every ChMask has 16 bit)
for( uint8_t chMaskItr = 0, cntPayload = 0; chMaskItr <= 4; chMaskItr++, cntPayload+=2 )
{
RegionNvmGroup2->ChannelsMask[chMaskItr] = (uint16_t) (0x00FF & applyCFList->Payload[cntPayload]);
RegionNvmGroup2->ChannelsMask[chMaskItr] |= (uint16_t) (applyCFList->Payload[cntPayload+1] << 8);
if( chMaskItr == 4 )
{
RegionNvmGroup2->ChannelsMask[chMaskItr] = RegionNvmGroup2->ChannelsMask[chMaskItr] & CHANNELS_MASK_500KHZ_MASK;
}
// Set the channel mask to the remaining
RegionNvmGroup1->ChannelsMaskRemaining[chMaskItr] &= RegionNvmGroup2->ChannelsMask[chMaskItr];
}
#endif /* REGION_AU915 */
}
bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
{
#if defined( REGION_AU915 )
switch( chanMaskSet->ChannelsMaskType )
{
case CHANNELS_MASK:
{
RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, chanMaskSet->ChannelsMaskIn, CHANNELS_MASK_SIZE );
RegionNvmGroup2->ChannelsDefaultMask[4] = RegionNvmGroup2->ChannelsDefaultMask[4] & CHANNELS_MASK_500KHZ_MASK;
RegionNvmGroup2->ChannelsDefaultMask[5] = 0x0000;
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
RegionNvmGroup1->ChannelsMaskRemaining[i] &= RegionNvmGroup2->ChannelsMask[i];
}
break;
}
case CHANNELS_DEFAULT_MASK:
{
RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, CHANNELS_MASK_SIZE );
break;
}
default:
return false;
}
return true;
#else
return false;
#endif /* REGION_AU915 */
}
void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
{
#if defined( REGION_AU915 )
uint32_t tSymbolInUs = 0;
// Get the datarate, perform a boundary check
rxConfigParams->Datarate = MIN( datarate, AU915_RX_MAX_DATARATE );
rxConfigParams->Bandwidth = RegionCommonGetBandwidth( rxConfigParams->Datarate, BandwidthsAU915 );
tSymbolInUs = RegionCommonComputeSymbolTimeLoRa( DataratesAU915[rxConfigParams->Datarate], BandwidthsAU915[rxConfigParams->Datarate] );
RegionCommonComputeRxWindowParameters( tSymbolInUs, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
#endif /* REGION_AU915 */
}
bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
#if defined( REGION_AU915 )
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
{
// Apply window 1 frequency
frequency = AU915_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * AU915_STEPWIDTH_RX1_CHANNEL;
}
// Read the physical datarate from the datarates table
phyDr = DataratesAU915[dr];
Radio.SetChannel( frequency );
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
/* ST_WORKAROUND_BEGIN: Keep repeater feature */
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterDwell0AU915[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateDwell0AU915[dr];
}
Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORAMAC_FRAME_PAYLOAD_OVERHEAD_SIZE );
/* ST_WORKAROUND_END */
/* ST_WORKAROUND_BEGIN: Print Rx config */
RegionCommonRxConfigPrint(rxConfig->RxSlot, frequency, dr);
/* ST_WORKAROUND_END */
*datarate = (uint8_t) dr;
return true;
#else
return false;
#endif /* REGION_AU915 */
}
bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
#if defined( REGION_AU915 )
int8_t phyDr = DataratesAU915[txConfig->Datarate];
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
int8_t txPowerLimited = RegionCommonLimitTxPower( txConfig->TxPower, RegionNvmGroup1->Bands[RegionNvmGroup2->Channels[txConfig->Channel].Band].TxMaxPower );
#elif (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
int8_t txPowerLimited = RegionCommonLimitTxPower( txConfig->TxPower, RegionBands[RegionNvmGroup2->Channels[txConfig->Channel].Band].TxMaxPower );
#endif /* REGION_VERSION */
uint32_t bandwidth = RegionCommonGetBandwidth( txConfig->Datarate, BandwidthsAU915 );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
// Setup the radio frequency
Radio.SetChannel( RegionNvmGroup2->Channels[txConfig->Channel].Frequency );
Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
/* ST_WORKAROUND_BEGIN: Print Tx config */
RegionCommonTxConfigPrint(RegionNvmGroup2->Channels[txConfig->Channel].Frequency, txConfig->Datarate);
/* ST_WORKAROUND_END */
// Setup maximum payload length of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
// Update time-on-air
*txTimeOnAir = GetTimeOnAir( txConfig->Datarate, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
#else
return false;
#endif /* REGION_AU915 */
}
uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
{
uint8_t status = 0x07;
#if defined( REGION_AU915 )
RegionCommonLinkAdrParams_t linkAdrParams = { 0 };
uint8_t nextIndex = 0;
uint8_t bytesProcessed = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
GetPhyParams_t getPhy;
PhyParam_t phyParam;
RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
// Initialize local copy of channels mask
RegionCommonChanMaskCopy( channelsMask, RegionNvmGroup2->ChannelsMask, 6 );
while( bytesProcessed < linkAdrReq->PayloadSize )
{
nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
if( nextIndex == 0 )
break; // break loop, since no more request has been found
// Update bytes processed
bytesProcessed += nextIndex;
// Revert status, as we only check the last ADR request for the channel mask KO
status = 0x07;
if( linkAdrParams.ChMaskCtrl == 6 )
{
// Enable all 125 kHz channels
channelsMask[0] = 0xFFFF;
channelsMask[1] = 0xFFFF;
channelsMask[2] = 0xFFFF;
channelsMask[3] = 0xFFFF;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask & CHANNELS_MASK_500KHZ_MASK;
}
else if( linkAdrParams.ChMaskCtrl == 7 )
{
// Disable all 125 kHz channels
channelsMask[0] = 0x0000;
channelsMask[1] = 0x0000;
channelsMask[2] = 0x0000;
channelsMask[3] = 0x0000;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask & CHANNELS_MASK_500KHZ_MASK;
}
else if( linkAdrParams.ChMaskCtrl == 5 )
{
// Start value for comparison
uint8_t bitMask = 1;
// cntChannelMask for channelsMask[0] until channelsMask[3]
uint8_t cntChannelMask = 0;
// i will be 1, 2, 3, ..., 7
for( uint8_t i = 0; i <= 7; i++ )
{
// 8 MSBs of ChMask are RFU
// Checking if the ChMask is set, then true
if( ( ( linkAdrParams.ChMask & 0x00FF ) & ( bitMask << i ) ) != 0 )
{
if( ( i % 2 ) == 0 )
{
// Enable a bank of 8 125kHz channels, 8 LSBs
channelsMask[cntChannelMask] |= 0x00FF;
// Enable the corresponding 500kHz channel
channelsMask[4] |= ( bitMask << i );
}
else
{
// Enable a bank of 8 125kHz channels, 8 MSBs
channelsMask[cntChannelMask] |= 0xFF00;
// Enable the corresponding 500kHz channel
channelsMask[4] |= ( bitMask << i );
// cntChannelMask increment for uneven i
cntChannelMask++;
}
}
// ChMask is not set
else
{
if( ( i % 2 ) == 0 )
{
// Disable a bank of 8 125kHz channels, 8 LSBs
channelsMask[cntChannelMask] &= 0xFF00;
// Disable the corresponding 500kHz channel
channelsMask[4] &= ~( bitMask << i );
}
else
{
// Enable a bank of 8 125kHz channels, 8 MSBs
channelsMask[cntChannelMask] &= 0x00FF;
// Disable the corresponding 500kHz channel
channelsMask[4] &= ~( bitMask << i );
// cntChannelMask increment for uneven i
cntChannelMask++;
}
}
}
}
else
{
channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
}
}
// FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
if( ( linkAdrParams.Datarate < DR_6 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
{
status &= 0xFE; // Channel mask KO
}
// Get the minimum possible datarate
getPhy.Attribute = PHY_MIN_TX_DR;
getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
phyParam = RegionAU915GetPhyParam( &getPhy );
linkAdrVerifyParams.Status = status;
linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
linkAdrVerifyParams.NbChannels = AU915_MAX_NB_CHANNELS;
linkAdrVerifyParams.ChannelsMask = channelsMask;
linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
linkAdrVerifyParams.MaxDatarate = AU915_TX_MAX_DATARATE;
linkAdrVerifyParams.Channels = RegionNvmGroup2->Channels;
linkAdrVerifyParams.MinTxPower = AU915_MIN_TX_POWER;
linkAdrVerifyParams.MaxTxPower = AU915_MAX_TX_POWER;
linkAdrVerifyParams.Version = linkAdrReq->Version;
// Verify the parameters and update, if necessary
status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
// Update channelsMask if everything is correct
if( status == 0x07 )
{
// Copy Mask
RegionCommonChanMaskCopy( RegionNvmGroup2->ChannelsMask, channelsMask, 6 );
RegionNvmGroup1->ChannelsMaskRemaining[0] &= RegionNvmGroup2->ChannelsMask[0];
RegionNvmGroup1->ChannelsMaskRemaining[1] &= RegionNvmGroup2->ChannelsMask[1];
RegionNvmGroup1->ChannelsMaskRemaining[2] &= RegionNvmGroup2->ChannelsMask[2];
RegionNvmGroup1->ChannelsMaskRemaining[3] &= RegionNvmGroup2->ChannelsMask[3];
RegionNvmGroup1->ChannelsMaskRemaining[4] = RegionNvmGroup2->ChannelsMask[4];
RegionNvmGroup1->ChannelsMaskRemaining[5] = RegionNvmGroup2->ChannelsMask[5];
}
// Update status variables
*drOut = linkAdrParams.Datarate;
*txPowOut = linkAdrParams.TxPower;
*nbRepOut = linkAdrParams.NbRep;
*nbBytesParsed = bytesProcessed;
#endif /* REGION_AU915 */
return status;
}
uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
{
uint8_t status = 0x07;
#if defined( REGION_AU915 )
// Verify radio frequency
if( VerifyRfFreq( rxParamSetupReq->Frequency ) == false )
{
status &= 0xFE; // Channel frequency KO
}
// Verify datarate
if( RegionCommonValueInRange( rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
if( ( rxParamSetupReq->Datarate == DR_7 ) ||
( rxParamSetupReq->Datarate > DR_13 ) )
{
status &= 0xFD; // Datarate KO
}
// Verify datarate offset
if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET ) == false )
{
status &= 0xFB; // Rx1DrOffset range KO
}
#endif /* REGION_AU915 */
return status;
}
uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq )
{
// Do not accept the request
return -1;
}
int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
{
// Accept the request
return 0;
}
uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq )
{
// Do not accept the request
return -1;
}
int8_t RegionAU915AlternateDr( int8_t currentDr, AlternateDrType_t type )
{
#if defined( REGION_AU915 )
// Alternates the data rate according to the channel sequence:
// Eight times a 125kHz DR_2 and then one 500kHz DR_6 channel
if( type == ALTERNATE_DR )
{
RegionNvmGroup1->JoinTrialsCounter++;
}
else
{
RegionNvmGroup1->JoinTrialsCounter--;
}
if( RegionNvmGroup1->JoinTrialsCounter % 9 == 0 )
{
// Use DR_6 every 9th times.
currentDr = DR_6;
}
else
{
currentDr = DR_2;
}
return currentDr;
#else
return -1;
#endif /* REGION_AU915 */
}
LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
#if defined( REGION_AU915 )
uint8_t nbEnabledChannels = 0;
uint8_t nbRestrictedChannels = 0;
uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = { 0 };
RegionCommonIdentifyChannelsParam_t identifyChannelsParam;
RegionCommonCountNbOfEnabledChannelsParams_t countChannelsParams;
LoRaMacStatus_t status = LORAMAC_STATUS_NO_CHANNEL_FOUND;
// Count 125kHz channels
if( RegionCommonCountChannels( RegionNvmGroup1->ChannelsMaskRemaining, 0, 4 ) == 0 )
{ // Reactivate default channels
RegionCommonChanMaskCopy( RegionNvmGroup1->ChannelsMaskRemaining, RegionNvmGroup2->ChannelsMask, 4 );
RegionNvmGroup1->JoinChannelGroupsCurrentIndex = 0;
}
// Check other channels
if( nextChanParams->Datarate >= DR_6 )
{
if( ( RegionNvmGroup1->ChannelsMaskRemaining[4] & CHANNELS_MASK_500KHZ_MASK ) == 0 )
{
RegionNvmGroup1->ChannelsMaskRemaining[4] = RegionNvmGroup2->ChannelsMask[4];
}
}
// Search how many channels are enabled
countChannelsParams.Joined = nextChanParams->Joined;
countChannelsParams.Datarate = nextChanParams->Datarate;
countChannelsParams.ChannelsMask = RegionNvmGroup1->ChannelsMaskRemaining;
countChannelsParams.Channels = RegionNvmGroup2->Channels;
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
countChannelsParams.Bands = RegionNvmGroup1->Bands;
#elif (defined( REGION_VERSION ) && ( REGION_VERSION == 0x02010001 ))
countChannelsParams.Bands = RegionBands;
#endif /* REGION_VERSION */
countChannelsParams.MaxNbChannels = AU915_MAX_NB_CHANNELS;
countChannelsParams.JoinChannels = NULL;
identifyChannelsParam.AggrTimeOff = nextChanParams->AggrTimeOff;
identifyChannelsParam.LastAggrTx = nextChanParams->LastAggrTx;
identifyChannelsParam.DutyCycleEnabled = nextChanParams->DutyCycleEnabled;
identifyChannelsParam.MaxBands = AU915_MAX_NB_BANDS;
identifyChannelsParam.ElapsedTimeSinceStartUp = nextChanParams->ElapsedTimeSinceStartUp;
identifyChannelsParam.LastTxIsJoinRequest = nextChanParams->LastTxIsJoinRequest;
identifyChannelsParam.ExpectedTimeOnAir = GetTimeOnAir( nextChanParams->Datarate, nextChanParams->PktLen );
identifyChannelsParam.CountNbOfEnabledChannelsParam = &countChannelsParams;
status = RegionCommonIdentifyChannels( &identifyChannelsParam, aggregatedTimeOff, enabledChannels,
&nbEnabledChannels, &nbRestrictedChannels, time );
if( status == LORAMAC_STATUS_OK )
{
if( nextChanParams->Joined == true )
{
// Choose randomly on of the remaining channels
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
}
else
{
// For rapid network acquisition in mixed gateway channel plan environments, the device
// follow a random channel selection sequence. It probes alternating one out of a
// group of eight 125 kHz channels followed by probing one 500 kHz channel each pass.
// Each time a 125 kHz channel will be selected from another group.
// 125kHz Channels (0 - 63) DR2
if( nextChanParams->Datarate == DR_2 )
{
if( RegionBaseUSComputeNext125kHzJoinChannel( ( uint16_t* ) RegionNvmGroup1->ChannelsMaskRemaining,
&RegionNvmGroup1->JoinChannelGroupsCurrentIndex, channel ) == LORAMAC_STATUS_PARAMETER_INVALID )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
}
// 500kHz Channels (64 - 71) DR6
else
{
// Choose the next available channel
uint8_t i = 0;
while( ( ( RegionNvmGroup1->ChannelsMaskRemaining[4] & CHANNELS_MASK_500KHZ_MASK ) & ( 1 << i ) ) == 0 )
{
i++;
}
*channel = 64 + i;
}
}
// Disable the channel in the mask
RegionCommonChanDisable( RegionNvmGroup1->ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS );
}
return status;
#else
return LORAMAC_STATUS_NO_CHANNEL_FOUND;
#endif /* REGION_AU915 */
}
LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
#if (defined( REGION_VERSION ) && ( REGION_VERSION == 0x01010003 ))
void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave )
{
#if defined( REGION_AU915 )
int8_t txPowerLimited = RegionCommonLimitTxPower( continuousWave->TxPower, RegionNvmGroup1->Bands[RegionNvmGroup2->Channels[continuousWave->Channel].Band].TxMaxPower );
int8_t phyTxPower = 0;
uint32_t frequency = RegionNvmGroup2->Channels[continuousWave->Channel].Frequency;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
#endif /* REGION_AU915 */
}
#endif /* REGION_VERSION */
uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
{
#if defined( REGION_AU915 )
int8_t datarate = DatarateOffsetsAU915[dr][drOffset];
if( datarate < 0 )
{
if( downlinkDwellTime == 0 )
{
datarate = AU915_TX_MIN_DATARATE;
}
else
{
datarate = AU915_DWELL_LIMIT_DATARATE;
}
}
return datarate;
#else
return 0;
#endif /* REGION_AU915 */
}
void RegionAU915RxBeaconSetup( RxBeaconSetup_t* rxBeaconSetup, uint8_t* outDr )
{
#if defined( REGION_AU915 )
RegionCommonRxBeaconSetupParams_t regionCommonRxBeaconSetup;
regionCommonRxBeaconSetup.Datarates = DataratesAU915;
regionCommonRxBeaconSetup.Frequency = rxBeaconSetup->Frequency;
regionCommonRxBeaconSetup.BeaconSize = AU915_BEACON_SIZE;
regionCommonRxBeaconSetup.BeaconDatarate = AU915_BEACON_CHANNEL_DR;
regionCommonRxBeaconSetup.BeaconChannelBW = AU915_BEACON_CHANNEL_BW;
regionCommonRxBeaconSetup.RxTime = rxBeaconSetup->RxTime;
regionCommonRxBeaconSetup.SymbolTimeout = rxBeaconSetup->SymbolTimeout;
RegionCommonRxBeaconSetup( ®ionCommonRxBeaconSetup );
// Store downlink datarate
*outDr = AU915_BEACON_CHANNEL_DR;
#endif /* REGION_AU915 */
}
- Link de download: https://www.st.com/en/development-tools/stm32cubeide.html
- Link do documento:
https://www.st.com/en/development-tools/stm32cubeide.html#documentation
- Import o SDK no menu File
- Selecione "Projects from Folders or Archive" e então Click em Next
- Selecione o Folder do Projeto
- Click em Finish
- Após o projeto ser importado, ele é criado e mostrado no Project Explorer (Tab) no canto superior esquerdo
Enquanto segurando o botão Reset do LSM110A Starter KIT, pressione Connect no STM32 CUBE Programmer e libere o botão de Reset.
C:\LSM1x0A_SDK_LoRaWAN104\Utilities\1_SJITools\1_FW_Merge_Tool\LSM_IAP_V100_220516.hex
- Primeiro selecione LoRaWAN (default após RESET)
- Pegue o DevEUI de seu módulo LSM1x0A
OTAA
1.2 Adicionar um dispositivo EndDevice LoRaWan
Esta seção mostra como adicionar um dispositivo EndDevice LoRaWAN à rede LoRaWAN e ver os dados pelo web site da EveryNet. Usamos o LSM110A como um dispositivo de referência - a configuração para outros dispositivos LoRaWAN será semelhante.
Três códigos são necessários para definir o dispositivo no EveryNet:
Device EUI - código de identificação único para um dispositivo em particular.
Application EUI - código de identificação para um aplicativo definido no Everynet.
Application key - Chave exclusiva para proteger as comunicações com um dispositivo em particular.
Pressione o sinal de + para abrir a tela abaixo e adicionar device!
Mude para Activation para OTAA e Encryption para NS
Nota-se que há uma APP EUI já criado por EveryNet, mas esta não é a definida no dispositivo. Para adicionar o APP EUI do dispositivo LSM110A, utilize comandos AT.
Dados são mostrados no final da página
- Configure agora o módulo LSM1x0A
Dúvidas
Kit de avaliação para módulo LoRa e Sigfox Wisol Seong JI SJI LSM110A
Operação em rede pública e privada LoRaWAN e também ponto a ponto (P2P)
Opera também em Sigfox
Alterne entre LoRa e Sigfox por comando AT, não precisa trocar o Firmware!
Permite embarcar sua aplicação
Módulo LoRa e Sigfox Wisol Seong JI SJI LSM110A
Módulo LoRa e Sigfox compacto
Escolha entre operação LoRa e Sigfox por comando "on the fly", sem precisar trocar firmware !
LoRa: para operação redes públicas e privadas LoRaWAN bem como ponto a ponto (P2P)
Sigfox: zonas RCZ2 e RCZ4 (inclui Brasil)
Caracteristicas:
- Permite embarcar a aplicação
- Dimensão: 14x15x2,8mm
- Frequência: RCZ2 Tx 902,2MHz Rx 905,2MHz
- Potência de saida: configurável até +22dBm
- Sensibilidade: -129dBm@LoRa(BW=500KHz, SF=12)
-124dBm@Sigfox(0.6Kbps)
- Tensão de operação: 1,8 - 3,6Vdc
- Interface UART 9600 8N1
- Baixo consumo
- Na operação P2P não necessita de gateway LoRaWAN
Aplicações:
- Medição individualizada de água, energia, gás
- Automação comercial, industrial residencial;
- Rede de sensores;
- Sistemas de alarme e segurança;
- Estações meteorológicas;
- Automação agrícola.
- utilize o SDK do STM32
- veja como é estruturado a troca de mensagens em (Message Sequence Chart) numa conexão com LoraWAN
- DevNonce is too small error in the device events: If the device is using LoRaWAN MAC version 1.1 or 1.0.4, this error occurs when DevNonce is not being incremented, so the Join Server ignores Join Requests with the same or lower DevNonce value comparing to the previous one. Contact your device’s manufacturer to find out the correct LoRaWAN MAC and PHY versions, and configure the device in The Things Stack accordingly
Nenhum comentário:
Postar um comentário