Skip to content

Commit f76bdca

Browse files
author
Daniel Jaeckle
committedJun 2, 2020
Update LinkAdr algorithm to LoRaWAN Specification v1.0.4
1 parent 03e7ff5 commit f76bdca

File tree

4 files changed

+162
-95
lines changed

4 files changed

+162
-95
lines changed
 

‎src/mac/LoRaMac.c

+96-29
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
*/
8585
#define BACKOFF_DC_24_HOURS 10000
8686

87+
/*!
88+
* Maximum value for the ADR ack counter
89+
*/
90+
#define ADR_ACK_COUNTER_MAX 0xFFFFFFFF
91+
8792
/*!
8893
* LoRaMac internal states
8994
*/
@@ -664,6 +669,16 @@ static bool CheckRetransUnconfirmedUplink( void );
664669
*/
665670
static bool CheckRetransConfirmedUplink( void );
666671

672+
/*!
673+
* \brief Increases the ADR ack counter. Takes the maximum
674+
* value into account.
675+
*
676+
* \param [IN] counter Current counter value.
677+
*
678+
* \retval Returns the next counter value.
679+
*/
680+
static uint32_t IncreaseAdrAckCounter( uint32_t counter );
681+
667682
/*!
668683
* \brief Stops the uplink retransmission
669684
*
@@ -1971,38 +1986,79 @@ static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t comm
19711986
uint8_t linkAdrNbRep = 0;
19721987
uint8_t linkAdrNbBytesParsed = 0;
19731988

1989+
// The end node is allowed to process one block of LinkAdrRequests.
1990+
// It must ignore subsequent blocks
19741991
if( adrBlockFound == false )
19751992
{
19761993
adrBlockFound = true;
19771994

1978-
// Fill parameter structure
1979-
linkAdrReq.Payload = &payload[macIndex - 1];
1980-
linkAdrReq.PayloadSize = commandsSize - ( macIndex - 1 );
1981-
linkAdrReq.AdrEnabled = MacCtx.NvmCtx->AdrCtrlOn;
1982-
linkAdrReq.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
1983-
linkAdrReq.CurrentDatarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
1984-
linkAdrReq.CurrentTxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
1985-
linkAdrReq.CurrentNbRep = MacCtx.NvmCtx->MacParams.ChannelsNbTrans;
1986-
linkAdrReq.Version = MacCtx.NvmCtx->Version;
1987-
1988-
// Process the ADR requests
1989-
status = RegionLinkAdrReq( MacCtx.NvmCtx->Region, &linkAdrReq, &linkAdrDatarate,
1990-
&linkAdrTxPower, &linkAdrNbRep, &linkAdrNbBytesParsed );
1991-
1992-
if( ( status & 0x07 ) == 0x07 )
1995+
do
19931996
{
1994-
MacCtx.NvmCtx->MacParams.ChannelsDatarate = linkAdrDatarate;
1995-
MacCtx.NvmCtx->MacParams.ChannelsTxPower = linkAdrTxPower;
1996-
MacCtx.NvmCtx->MacParams.ChannelsNbTrans = linkAdrNbRep;
1997-
}
1998-
1999-
// Add the answers to the buffer
2000-
for( uint8_t i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++ )
1997+
// Fill parameter structure
1998+
linkAdrReq.Payload = &payload[macIndex - 1];
1999+
linkAdrReq.AdrEnabled = MacCtx.NvmCtx->AdrCtrlOn;
2000+
linkAdrReq.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
2001+
linkAdrReq.CurrentDatarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
2002+
linkAdrReq.CurrentTxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
2003+
linkAdrReq.CurrentNbRep = MacCtx.NvmCtx->MacParams.ChannelsNbTrans;
2004+
linkAdrReq.Version = MacCtx.NvmCtx->Version;
2005+
2006+
// There is a fundamental difference in reporting the status
2007+
// of the LinkAdrRequests when ADR is on or off. When ADR is on, every
2008+
// LinkAdrAns contains the same value. This does not hold when ADR is off,
2009+
// where every LinkAdrAns requires an individual status.
2010+
if( MacCtx.NvmCtx->AdrCtrlOn == true )
2011+
{
2012+
// When ADR is on, the function RegionLinkAdrReq will take care
2013+
// about the parsing and interpretation of the LinkAdrRequest block and
2014+
// it provides one status which shall be applied to every LinkAdrAns
2015+
linkAdrReq.PayloadSize = commandsSize - ( macIndex - 1 );
2016+
}
2017+
else
2018+
{
2019+
// When ADR is off, this function will loop over the individual LinkAdrRequests
2020+
// and will call RegionLinkAdrReq for each individually, as every request
2021+
// requires an individual answer.
2022+
// When ADR is off, the function RegionLinkAdrReq ignores the new values for
2023+
// ChannelsDatarate, ChannelsTxPower and ChannelsNbTrans.
2024+
linkAdrReq.PayloadSize = 5;
2025+
}
2026+
2027+
// Process the ADR requests
2028+
status = RegionLinkAdrReq( MacCtx.NvmCtx->Region, &linkAdrReq, &linkAdrDatarate,
2029+
&linkAdrTxPower, &linkAdrNbRep, &linkAdrNbBytesParsed );
2030+
2031+
if( ( status & 0x07 ) == 0x07 )
2032+
{
2033+
MacCtx.NvmCtx->MacParams.ChannelsDatarate = linkAdrDatarate;
2034+
MacCtx.NvmCtx->MacParams.ChannelsTxPower = linkAdrTxPower;
2035+
MacCtx.NvmCtx->MacParams.ChannelsNbTrans = linkAdrNbRep;
2036+
}
2037+
2038+
// Add the answers to the buffer
2039+
for( uint8_t i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++ )
2040+
{
2041+
LoRaMacCommandsAddCmd( MOTE_MAC_LINK_ADR_ANS, &status, 1 );
2042+
}
2043+
// Update MAC index
2044+
macIndex += linkAdrNbBytesParsed - 1;
2045+
2046+
// Check to prevent invalid access
2047+
if( macIndex >= commandsSize )
2048+
break;
2049+
2050+
} while( payload[macIndex++] == SRV_MAC_LINK_ADR_REQ );
2051+
2052+
if( macIndex < commandsSize )
20012053
{
2002-
LoRaMacCommandsAddCmd( MOTE_MAC_LINK_ADR_ANS, &status, 1 );
2054+
// Decrease the index such that it points to the next MAC command
2055+
macIndex--;
20032056
}
2004-
// Update MAC index
2005-
macIndex += linkAdrNbBytesParsed - 1;
2057+
}
2058+
else
2059+
{
2060+
// Increase the index by the MAC command size (without command)
2061+
macIndex += 4;
20062062
}
20072063
break;
20082064
}
@@ -2298,19 +2354,20 @@ LoRaMacStatus_t Send( LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uin
22982354
}
22992355

23002356
// ADR next request
2301-
adrNext.Version = MacCtx.NvmCtx->Version;
23022357
adrNext.UpdateChanMask = true;
23032358
adrNext.AdrEnabled = fCtrl.Bits.Adr;
23042359
adrNext.AdrAckCounter = MacCtx.NvmCtx->AdrAckCounter;
23052360
adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
23062361
adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
23072362
adrNext.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
23082363
adrNext.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
2364+
adrNext.NbTrans = MacCtx.ChannelsNbTransCounter;
23092365
adrNext.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
23102366
adrNext.Region = MacCtx.NvmCtx->Region;
23112367

23122368
fCtrl.Bits.AdrAckReq = LoRaMacAdrCalcNext( &adrNext, &MacCtx.NvmCtx->MacParams.ChannelsDatarate,
2313-
&MacCtx.NvmCtx->MacParams.ChannelsTxPower, &adrAckCounter );
2369+
&MacCtx.NvmCtx->MacParams.ChannelsTxPower,
2370+
&MacCtx.ChannelsNbTransCounter, &adrAckCounter );
23142371

23152372
// Prepare the frame
23162373
status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
@@ -3087,6 +3144,15 @@ static bool CheckRetransConfirmedUplink( void )
30873144
return false;
30883145
}
30893146

3147+
static uint32_t IncreaseAdrAckCounter( uint32_t counter )
3148+
{
3149+
if( counter < ADR_ACK_COUNTER_MAX )
3150+
{
3151+
counter++;
3152+
}
3153+
return counter;
3154+
}
3155+
30903156
static bool StopRetransmission( void )
30913157
{
30923158
if( ( MacCtx.MacFlags.Bits.McpsInd == 0 ) ||
@@ -3442,6 +3508,7 @@ LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
34423508
uint32_t adrAckCounter = MacCtx.NvmCtx->AdrAckCounter;
34433509
int8_t datarate = MacCtx.NvmCtx->MacParamsDefaults.ChannelsDatarate;
34443510
int8_t txPower = MacCtx.NvmCtx->MacParamsDefaults.ChannelsTxPower;
3511+
uint8_t nbTrans = MacCtx.ChannelsNbTransCounter;
34453512
size_t macCmdsSize = 0;
34463513

34473514
if( txInfo == NULL )
@@ -3450,20 +3517,20 @@ LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
34503517
}
34513518

34523519
// Setup ADR request
3453-
adrNext.Version = MacCtx.NvmCtx->Version;
34543520
adrNext.UpdateChanMask = false;
34553521
adrNext.AdrEnabled = MacCtx.NvmCtx->AdrCtrlOn;
34563522
adrNext.AdrAckCounter = MacCtx.NvmCtx->AdrAckCounter;
34573523
adrNext.AdrAckLimit = MacCtx.AdrAckLimit;
34583524
adrNext.AdrAckDelay = MacCtx.AdrAckDelay;
34593525
adrNext.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
34603526
adrNext.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
3527+
adrNext.NbTrans = MacCtx.ChannelsNbTransCounter;
34613528
adrNext.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
34623529
adrNext.Region = MacCtx.NvmCtx->Region;
34633530

34643531
// We call the function for information purposes only. We don't want to
34653532
// apply the datarate, the tx power and the ADR ack counter.
3466-
LoRaMacAdrCalcNext( &adrNext, &datarate, &txPower, &adrAckCounter );
3533+
LoRaMacAdrCalcNext( &adrNext, &datarate, &txPower, &nbTrans, &adrAckCounter );
34673534

34683535
txInfo->CurrentPossiblePayloadSize = GetMaxAppPayloadWithoutFOptsLength( datarate );
34693536

‎src/mac/LoRaMacAdr.c

+37-58
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434
#include "region/Region.h"
3535
#include "LoRaMacAdr.h"
3636

37-
static bool CalcNextV10X( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
37+
bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut,
38+
uint8_t* nbTransOut, uint32_t* adrAckCounter )
3839
{
3940
bool adrAckReq = false;
4041
int8_t datarate = adrNext->Datarate;
4142
int8_t txPower = adrNext->TxPower;
43+
uint8_t nbTrans = adrNext->NbTrans;
4244
int8_t minTxDatarate;
4345
GetPhyParams_t getPhy;
4446
PhyParam_t phyParam;
@@ -55,76 +57,53 @@ static bool CalcNextV10X( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* t
5557
minTxDatarate = phyParam.Value;
5658
datarate = MAX( datarate, minTxDatarate );
5759

58-
if( datarate == minTxDatarate )
60+
// Verify if ADR ack req bit needs to be set.
61+
if( adrNext->AdrAckCounter >= adrNext->AdrAckLimit )
5962
{
60-
*adrAckCounter = 0;
61-
adrAckReq = false;
63+
adrAckReq = true;
6264
}
63-
else
65+
66+
// Verify, if we need to set the TX power to default
67+
if( adrNext->AdrAckCounter >= ( adrNext->AdrAckLimit + adrNext->AdrAckDelay ) )
6468
{
65-
if( adrNext->AdrAckCounter >= adrNext->AdrAckLimit )
66-
{
67-
adrAckReq = true;
68-
}
69-
else
70-
{
71-
adrAckReq = false;
72-
}
73-
if( adrNext->AdrAckCounter >= ( adrNext->AdrAckLimit + adrNext->AdrAckDelay ) )
74-
{
75-
// Set TX Power to maximum
76-
getPhy.Attribute = PHY_MAX_TX_POWER;
77-
phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
78-
txPower = phyParam.Value;
69+
// Set TX Power to default
70+
getPhy.Attribute = PHY_DEF_TX_POWER;
71+
phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
72+
txPower = phyParam.Value;
73+
}
7974

80-
if( ( adrNext->AdrAckCounter % adrNext->AdrAckDelay ) == 1 )
75+
// Verify, if we need to decrease the data rate
76+
if( adrNext->AdrAckCounter >= ( uint32_t )( adrNext->AdrAckLimit + ( adrNext->AdrAckDelay << 1 ) ) )
77+
{
78+
// Perform actions with every adrNext->AdrAckDelay only
79+
if( ( ( adrNext->AdrAckCounter - adrNext->AdrAckLimit ) % adrNext->AdrAckDelay ) == 0 )
80+
{
81+
if( datarate == minTxDatarate )
8182
{
82-
// Decrease the datarate
83-
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
84-
getPhy.Datarate = datarate;
85-
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
86-
phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
87-
datarate = phyParam.Value;
88-
89-
if( datarate == minTxDatarate )
83+
// Restore the channel mask
84+
if( adrNext->UpdateChanMask == true )
9085
{
91-
// We must set adrAckReq to false as soon as we reach the lowest datarate
92-
adrAckReq = false;
93-
if( adrNext->UpdateChanMask == true )
94-
{
95-
InitDefaultsParams_t params;
96-
params.Type = INIT_TYPE_RESTORE_DEFAULT_CHANNELS;
97-
RegionInitDefaults( adrNext->Region, &params );
98-
}
86+
InitDefaultsParams_t params;
87+
params.Type = INIT_TYPE_RESTORE_DEFAULT_CHANNELS;
88+
RegionInitDefaults( adrNext->Region, &params );
9989
}
90+
91+
// Restore NbTrans
92+
nbTrans = 1;
10093
}
94+
95+
// Decrease the datarate
96+
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
97+
getPhy.Datarate = datarate;
98+
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
99+
phyParam = RegionGetPhyParam( adrNext->Region, &getPhy );
100+
datarate = phyParam.Value;
101101
}
102102
}
103103
}
104104

105105
*drOut = datarate;
106106
*txPowOut = txPower;
107+
*nbTransOut = nbTrans;
107108
return adrAckReq;
108109
}
109-
110-
/*!
111-
* \brief Calculates the next datarate to set, when ADR is on or off.
112-
*
113-
* \param [IN] adrNext Pointer to the function parameters.
114-
*
115-
* \param [OUT] drOut The calculated datarate for the next TX.
116-
*
117-
* \param [OUT] txPowOut The TX power for the next TX.
118-
*
119-
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
120-
*
121-
* \retval Returns true, if an ADR request should be performed.
122-
*/
123-
bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
124-
{
125-
if( adrNext->Version.Fields.Minor == 0 )
126-
{
127-
return CalcNextV10X( adrNext, drOut, txPowOut, adrAckCounter );
128-
}
129-
return false;
130-
}

‎src/mac/LoRaMacAdr.h

+18-5
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ extern "C"
4949
*/
5050
typedef struct sCalcNextAdrParams
5151
{
52-
/*!
53-
* LoRaWAN Minor Version 1.X
54-
*/
55-
Version_t Version;
5652
/*!
5753
* Set to true, if the function should update the channels mask.
5854
*/
@@ -81,6 +77,10 @@ typedef struct sCalcNextAdrParams
8177
* TX power used currently.
8278
*/
8379
int8_t TxPower;
80+
/*!
81+
* NbTrans counter used currently.
82+
*/
83+
uint8_t NbTrans;
8484
/*!
8585
* UplinkDwellTime
8686
*/
@@ -94,17 +94,30 @@ typedef struct sCalcNextAdrParams
9494
/*!
9595
* \brief Calculates the next datarate to set, when ADR is on or off.
9696
*
97+
* \details Here is a summary of the actions:
98+
*
99+
* | ADR_ACK_CNT | Action |
100+
* | ----------- | --------------------------------------------------------- |
101+
* | 0... 63 | Do nothing |
102+
* | 64...95 | Set ADR ack bit |
103+
* | 96...127 | Set TX power to default (if already default, do nothing) |
104+
* | 128...159 | Set data rate to default (if already default, do nothing) |
105+
* | >=160 | Set NbTrans to 1, re-enable default channels |
106+
*
97107
* \param [IN] adrNext Pointer to the function parameters.
98108
*
99109
* \param [OUT] drOut The calculated datarate for the next TX.
100110
*
101111
* \param [OUT] txPowOut The TX power for the next TX.
102112
*
113+
* \param [OUT] nbTransOut The NbTrans counter.
114+
*
103115
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
104116
*
105117
* \retval Returns true, if an ADR request should be performed.
106118
*/
107-
bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
119+
bool LoRaMacAdrCalcNext( CalcNextAdrParams_t* adrNext, int8_t* drOut, int8_t* txPowOut,
120+
uint8_t* nbTransOut, uint32_t* adrAckCounter );
108121

109122
#ifdef __cplusplus
110123
}

‎src/mac/region/RegionCommon.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,22 @@ uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t
372372
if( status != 0 )
373373
{
374374
// Verify datarate. The variable phyParam. Value contains the minimum allowed datarate.
375-
if( RegionCommonChanVerifyDr( verifyParams->NbChannels, verifyParams->ChannelsMask, datarate,
375+
if( datarate == 0x0F )
376+
{ // 0xF means that the device MUST ignore that field, and keep the current parameter value.
377+
datarate = verifyParams->CurrentDatarate;
378+
}
379+
else if( RegionCommonChanVerifyDr( verifyParams->NbChannels, verifyParams->ChannelsMask, datarate,
376380
verifyParams->MinDatarate, verifyParams->MaxDatarate, verifyParams->Channels ) == false )
377381
{
378382
status &= 0xFD; // Datarate KO
379383
}
380384

381385
// Verify tx power
382-
if( RegionCommonValueInRange( txPower, verifyParams->MaxTxPower, verifyParams->MinTxPower ) == 0 )
386+
if( txPower == 0x0F )
387+
{ // 0xF means that the device MUST ignore that field, and keep the current parameter value.
388+
txPower = verifyParams->CurrentTxPower;
389+
}
390+
else if( RegionCommonValueInRange( txPower, verifyParams->MaxTxPower, verifyParams->MinTxPower ) == 0 )
383391
{
384392
// Verify if the maximum TX power is exceeded
385393
if( verifyParams->MaxTxPower > txPower )
@@ -397,7 +405,7 @@ uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t
397405
if( status == 0x07 )
398406
{
399407
if( nbRepetitions == 0 )
400-
{ // Restore the default value according to the LoRaWAN specification
408+
{ // Set nbRep to the default value of 1.
401409
nbRepetitions = 1;
402410
}
403411
}

0 commit comments

Comments
 (0)
Please sign in to comment.