/*! * \file LoRaMacAdr.c * * \brief LoRa MAC ADR implementation * * \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 ) */ #include "Region.h" #include "LoRaMacAdr.h" #include "LoRaMacVersion.h" #if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01000300 )) static bool CalcNextV10X( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ) { bool adrAckReq = false; int8_t datarate = adrNext->Datarate; int8_t txPower = adrNext->TxPower; int8_t minTxDatarate; GetPhyParams_t getPhy; PhyParam_t phyParam; // Report back the adr ack counter *adrAckCounter = adrNext->AdrAckCounter; if( adrNext->AdrEnabled == true ) { // Query minimum TX Datarate getPhy.Attribute = PHY_MIN_TX_DR; getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); minTxDatarate = phyParam.Value; datarate = MAX( datarate, minTxDatarate ); if( datarate == minTxDatarate ) { *adrAckCounter = 0; adrAckReq = false; } else { if( adrNext->AdrAckCounter >= adrNext->AdrAckLimit ) { adrAckReq = true; } else { adrAckReq = false; } if( adrNext->AdrAckCounter >= ( adrNext->AdrAckLimit + adrNext->AdrAckDelay ) ) { // Set TX Power to maximum getPhy.Attribute = PHY_MAX_TX_POWER; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); txPower = phyParam.Value; if( ( adrNext->AdrAckCounter % adrNext->AdrAckDelay ) == 1 ) { // Decrease the datarate getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; getPhy.Datarate = datarate; getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); datarate = phyParam.Value; if( datarate == minTxDatarate ) { // We must set adrAckReq to false as soon as we reach the lowest datarate adrAckReq = false; if( adrNext->UpdateChanMask == true ) { InitDefaultsParams_t params; params.Type = INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS; RegionInitDefaults( adrNext->Region, ¶ms ); } } } } } } *drOut = datarate; *txPowOut = txPower; return adrAckReq; } /*! * \brief Calculates the next datarate to set, when ADR is on or off. * * \param [IN] adrNext Pointer to the function parameters. * * \param [OUT] drOut The calculated datarate for the next TX. * * \param [OUT] txPowOut The TX power for the next TX. * * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter. * * \retval Returns true, if an ADR request should be performed. */ bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter ) { if( adrNext->Version.Fields.Minor == 0 ) { return CalcNextV10X( adrNext, drOut, txPowOut, adrAckCounter ); } return false; } #elif (defined( LORAMAC_VERSION ) && (( LORAMAC_VERSION == 0x01000400 ) || ( LORAMAC_VERSION == 0x01010100 ))) bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint8_t* nbTransOut, uint32_t* adrAckCounter ) { bool adrAckReq = false; int8_t datarate = adrNext->Datarate; int8_t txPower = adrNext->TxPower; uint8_t nbTrans = adrNext->NbTrans; int8_t minTxDatarate; GetPhyParams_t getPhy; PhyParam_t phyParam; // Report back the adr ack counter *adrAckCounter = adrNext->AdrAckCounter; if( adrNext->AdrEnabled == true ) { // Query minimum TX Datarate getPhy.Attribute = PHY_MIN_TX_DR; getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); minTxDatarate = phyParam.Value; datarate = MAX( datarate, minTxDatarate ); // Verify if ADR ack req bit needs to be set. if( adrNext->AdrAckCounter >= adrNext->AdrAckLimit ) { adrAckReq = true; } // Verify, if we need to set the TX power to default if( adrNext->AdrAckCounter >= ( adrNext->AdrAckLimit + adrNext->AdrAckDelay ) ) { // Set TX Power to default getPhy.Attribute = PHY_DEF_TX_POWER; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); txPower = phyParam.Value; } // Verify, if we need to decrease the data rate if( adrNext->AdrAckCounter >= ( uint32_t )( adrNext->AdrAckLimit + ( adrNext->AdrAckDelay << 1 ) ) ) { // Perform actions with every adrNext->AdrAckDelay only if( ( ( adrNext->AdrAckCounter - adrNext->AdrAckLimit ) % adrNext->AdrAckDelay ) == 0 ) { if( datarate == minTxDatarate ) { // Restore the channel mask if( adrNext->UpdateChanMask == true ) { InitDefaultsParams_t params; params.Type = INIT_TYPE_ACTIVATE_DEFAULT_CHANNELS; RegionInitDefaults( adrNext->Region, ¶ms ); } // Restore NbTrans nbTrans = 1; } // Decrease the datarate getPhy.Attribute = PHY_NEXT_LOWER_TX_DR; getPhy.Datarate = datarate; getPhy.UplinkDwellTime = adrNext->UplinkDwellTime; phyParam = RegionGetPhyParam( adrNext->Region, &getPhy ); datarate = phyParam.Value; } } } *drOut = datarate; *txPowOut = txPower; *nbTransOut = nbTrans; return adrAckReq; } #endif /* LORAMAC_VERSION */