Update LoRaWAN MAC

Dependents:   LoRaWAN-SX1272-Application-crash LoRaWAN-SX1272-Application-24-31-9sec Canada-SX1272-LoRaWAN-EEPROM Training-Aug2018-SX1272-X-NUCLEO-IKS01A2_Natalia

Fork of LoRaWAN-lib by Semtech

Revision:
4:37c12dbc8dc7
Parent:
3:b9d87593a8ae
Child:
5:2477c924494a
--- a/LoRaMac.cpp	Mon Mar 14 09:09:54 2016 +0000
+++ b/LoRaMac.cpp	Fri May 13 14:51:50 2016 +0000
@@ -34,6 +34,13 @@
 #define LORA_MAC_COMMAND_MAX_LENGTH                 15
 
 /*!
+ * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
+ * in RxWindowSetup function.
+ * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD
+ */
+#define LORA_MAC_FRMPAYLOAD_OVERHEAD                13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
+
+/*!
  * Device IEEE EUI
  */
 static uint8_t *LoRaMacDevEui;
@@ -362,7 +369,6 @@
  * Contains the channels which remain to be applied.
  */
 static uint16_t ChannelsMaskRemaining[6];
-
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
@@ -430,6 +436,8 @@
  */
 static uint8_t Channel;
 
+static uint8_t LastTxChannel;
+
 /*!
  * LoRaMac internal states
  */
@@ -442,6 +450,7 @@
     MAC_ACK_RETRY     = 0x00000008,
     MAC_TX_DELAYED    = 0x00000010,
     MAC_TX_CONFIG     = 0x00000020,
+    MAC_RX_ABORT      = 0x00000040,
 };
 
 /*!
@@ -672,16 +681,46 @@
  */
 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
 
+/*!
+ * \brief Counts the number of bits in a mask.
+ *
+ * \param [IN] mask A mask from which the function counts the active bits.
+ * \param [IN] nbBits The number of bits to check.
+ *
+ * \retval Number of enabled bits in the mask.
+ */
+static uint8_t CountBits( uint16_t mask, uint8_t nbBits );
+
 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
 /*!
  * \brief Counts the number of enabled 125 kHz channels in the channel mask.
  *        This function can only be applied to US915 band.
  *
- * \param channelsMask Pointer to the first element of the channel mask
+ * \param [IN] channelsMask Pointer to the first element of the channel mask
  *
  * \retval Number of enabled channels in the channel mask
  */
 static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask );
+
+#if defined( USE_BAND_915_HYBRID )
+/*!
+ * \brief Validates the correctness of the channel mask for US915, hybrid mode.
+ *
+ * \param [IN] mask Block definition to set.
+ * \param [OUT] channelsMask Pointer to the first element of the channel mask
+ */
+static void ReenableChannels( uint16_t mask, uint16_t* channelMask );
+
+/*!
+ * \brief Validates the correctness of the channel mask for US915, hybrid mode.
+ *
+ * \param [IN] channelsMask Pointer to the first element of the channel mask
+ *
+ * \retval [true: channel mask correct, false: channel mask not correct]
+ */
+static bool ValidateChannelMask( uint16_t* channelMask );
+#endif
+
 #endif
 
 /*!
@@ -764,6 +803,13 @@
  */
 static LoRaMacStatus_t ScheduleTx( void );
 
+/*
+ * \brief Calculates the back-off time for the band of a channel.
+ *
+ * \param [IN] channel     The last Tx channel index
+ */
+static void CalculateBackOff( uint8_t channel );
+
 /*!
  * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
  *
@@ -789,19 +835,12 @@
         OnRxWindow2TimerEvent( );
     }
 
-    // Update Band Time OFF
-    Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
-    if( DutyCycleOn == true )
-    {
-        Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
-    }
-    else
-    {
-        Bands[Channels[Channel].Band].TimeOff = 0;
-    }
-    // Update Aggregated Time OFF
+    // Store last Tx channel
+    LastTxChannel = Channel;
+    // Update last tx done time for the current channel
+    Bands[Channels[LastTxChannel].Band].LastTxDoneTime = curTime;
+    // Update Aggregated last tx done time
     AggregatedLastTxDoneTime = curTime;
-    AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
 
     if( IsRxWindowsEnabled == true )
     {
@@ -840,7 +879,7 @@
 
 static void PrepareRxDoneAbort( void )
 {
-    LoRaMacState &= ~MAC_TX_RUNNING;
+    LoRaMacState |= MAC_RX_ABORT;
 
     if( NodeAckRequested )
     {
@@ -864,6 +903,7 @@
 {
     LoRaMacHeader_t macHdr;
     LoRaMacFrameCtrl_t fCtrl;
+    bool skipIndication = false;
 
     uint8_t pktHeaderLen = 0;
     uint32_t address = 0;
@@ -1061,6 +1101,15 @@
                     }
                 }
 
+                // Check for a the maximum allowed counter difference
+                if( sequenceCounterDiff >= MAX_FCNT_GAP )
+                {
+                    McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
+                    McpsIndication.DownLinkCounter = downLinkCounter;
+                    PrepareRxDoneAbort( );
+                    return;
+                }
+
                 if( isMicOk == true )
                 {
                     McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
@@ -1095,19 +1144,27 @@
                         {
                             SrvAckRequested = true;
                             McpsIndication.McpsIndication = MCPS_CONFIRMED;
+
+                            if( ( DownLinkCounter == downLinkCounter ) &&
+                                ( DownLinkCounter != 0 ) )
+                            {
+                                // Duplicated confirmed downlink. Skip indication.
+                                skipIndication = true;
+                            }
                         }
                         else
                         {
                             SrvAckRequested = false;
                             McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
-                        }
-                        if( ( DownLinkCounter == downLinkCounter ) &&
-                            ( DownLinkCounter != 0 ) )
-                        {
-                            McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
-                            McpsIndication.DownLinkCounter = downLinkCounter;
-                            PrepareRxDoneAbort( );
-                            return;
+
+                            if( ( DownLinkCounter == downLinkCounter ) &&
+                                ( DownLinkCounter != 0 ) )
+                            {
+                                McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
+                                McpsIndication.DownLinkCounter = downLinkCounter;
+                                PrepareRxDoneAbort( );
+                                return;
+                            }
                         }
                         DownLinkCounter = downLinkCounter;
                     }
@@ -1169,12 +1226,18 @@
                                                    downLinkCounter,
                                                    LoRaMacRxPayload );
 
-                            McpsIndication.Buffer = LoRaMacRxPayload;
-                            McpsIndication.BufferSize = frameLen;
-                            McpsIndication.RxData = true;
+                            if( skipIndication == false )
+                            {
+                                McpsIndication.Buffer = LoRaMacRxPayload;
+                                McpsIndication.BufferSize = frameLen;
+                                McpsIndication.RxData = true;
+                            }
                         }
                     }
-                    LoRaMacFlags.Bits.McpsInd = 1;
+                    if( skipIndication == false )
+                    {
+                        LoRaMacFlags.Bits.McpsInd = 1;
+                    }
                 }
                 else
                 {
@@ -1281,6 +1344,12 @@
 
     if( LoRaMacFlags.Bits.MacDone == 1 )
     {
+        if( ( LoRaMacState & MAC_RX_ABORT ) == MAC_RX_ABORT )
+        {
+            LoRaMacState &= ~MAC_RX_ABORT;
+            LoRaMacState &= ~MAC_TX_RUNNING;
+        }
+
         if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) )
         {
             if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ||
@@ -1357,7 +1426,7 @@
 
                 if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
                 {
-                    ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
+                    ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE );
                 }
                 LoRaMacFlags.Bits.MacDone = 0;
                 // Sends the same frame again
@@ -1378,12 +1447,7 @@
                 ChannelsMask[5] = 0x0000;
 #elif defined( USE_BAND_915_HYBRID )
                 // Re-enable default channels
-                ChannelsMask[0] = 0x00FF;
-                ChannelsMask[1] = 0x0000;
-                ChannelsMask[2] = 0x0000;
-                ChannelsMask[3] = 0x0000;
-                ChannelsMask[4] = 0x0001;
-                ChannelsMask[5] = 0x0000;
+                ReenableChannels( ChannelsMask[4], ChannelsMask );
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
@@ -1464,13 +1528,18 @@
     }
 
     // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( datarate >= DR_3 )
-    { // DR_6, DR_5, DR_4, DR_3
+    if( ( datarate == DR_3 ) || ( datarate == DR_4 ) )
+    { // DR_4, DR_3
         symbTimeout = 8;
     }
-    if( datarate == DR_6 )
+    else if( datarate == DR_5 )
+    {
+        symbTimeout = 10;
+    }
+    else if( datarate == DR_6 )
     {// LoRa 250 kHz
         bandwidth  = 1;
+        symbTimeout = 14;
     }
     RxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
 #elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
@@ -1480,9 +1549,35 @@
         datarate = DR_0;
     }
     // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( datarate > DR_0 )
-    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
-        symbTimeout = 8;
+    switch( datarate )
+    {
+        case DR_0:       // SF10 - BW125
+            symbTimeout = 5;
+            break;
+
+        case DR_1:       // SF9  - BW125
+        case DR_2:       // SF8  - BW125
+        case DR_8:       // SF12 - BW500
+        case DR_9:       // SF11 - BW500
+        case DR_10:      // SF10 - BW500
+            symbTimeout = 8;
+            break;
+
+        case DR_3:       // SF7  - BW125
+        case DR_11:      // SF9  - BW500
+            symbTimeout = 10;
+            break;
+
+        case DR_4:       // SF8  - BW500
+        case DR_12:      // SF8  - BW500
+            symbTimeout = 14;
+            break;
+
+        case DR_13:      // SF7  - BW500
+            symbTimeout = 16;
+            break;
+        default:
+            break;
     }
     if( datarate >= DR_4 )
     {// LoRa 500 kHz
@@ -1504,19 +1599,50 @@
 
 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
     // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( Rx2Channel.Datarate >= DR_3 )
-    { // DR_6, DR_5, DR_4, DR_3
+    if( ( Rx2Channel.Datarate == DR_3 ) || ( Rx2Channel.Datarate == DR_4 ) )
+    { // DR_4, DR_3
         symbTimeout = 8;
     }
-    if( Rx2Channel.Datarate == DR_6 )
+    else if( Rx2Channel.Datarate == DR_5 )
+    {
+        symbTimeout = 10;
+    }
+    else if( Rx2Channel.Datarate == DR_6 )
     {// LoRa 250 kHz
         bandwidth  = 1;
+        symbTimeout = 14;
     }
 #elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
     // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( Rx2Channel.Datarate > DR_0 )
-    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
-        symbTimeout = 8;
+    switch( Rx2Channel.Datarate )
+    {
+        case DR_0:       // SF10 - BW125
+            symbTimeout = 5;
+            break;
+
+        case DR_1:       // SF9  - BW125
+        case DR_2:       // SF8  - BW125
+        case DR_8:       // SF12 - BW500
+        case DR_9:       // SF11 - BW500
+        case DR_10:      // SF10 - BW500
+            symbTimeout = 8;
+            break;
+
+        case DR_3:       // SF7  - BW125
+        case DR_11:      // SF9  - BW500
+            symbTimeout = 10;
+            break;
+
+        case DR_4:       // SF8  - BW500
+        case DR_12:      // SF8  - BW500
+            symbTimeout = 14;
+            break;
+
+        case DR_13:      // SF7  - BW500
+            symbTimeout = 16;
+            break;
+        default:
+            break;
     }
     if( Rx2Channel.Datarate >= DR_4 )
     {// LoRa 500 kHz
@@ -1555,7 +1681,6 @@
     uint8_t nbEnabledChannels = 0;
     uint8_t delayTx = 0;
     uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
-    TimerTime_t curTime = TimerGetCurrentTime( );
     TimerTime_t nextTxDelay = ( TimerTime_t )( -1 );
 
     memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
@@ -1570,16 +1695,7 @@
         ChannelsMaskRemaining[4] = ChannelsMask[4];
     }
 #else
-    uint8_t chanCnt = 0;
-    for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
-    {
-        if( ChannelsMask[k] != 0 )
-        {
-            chanCnt++;
-            break;
-        }
-    }
-    if( chanCnt == 0 )
+    if( CountBits( ChannelsMask[0], 16 ) == 0 )
     {
         // Re-enable default channels, if no channel is enabled
         ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
@@ -1587,7 +1703,7 @@
 #endif
 
     // Update Aggregated duty cycle
-    if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) )
+    if( AggregatedTimeOff <= TimerGetElapsedTime( AggregatedLastTxDoneTime ) )
     {
         AggregatedTimeOff = 0;
 
@@ -1596,14 +1712,14 @@
         {
             if( DutyCycleOn == true )
             {
-                if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) )
+                if( Bands[i].TimeOff <= TimerGetElapsedTime( Bands[i].LastTxDoneTime ) )
                 {
                     Bands[i].TimeOff = 0;
                 }
                 if( Bands[i].TimeOff != 0 )
                 {
                     nextTxDelay = MIN( Bands[i].TimeOff -
-                                       ( curTime - Bands[i].LastTxDoneTime ),
+                                       TimerGetElapsedTime( Bands[i].LastTxDoneTime ),
                                        nextTxDelay );
                 }
             }
@@ -1629,6 +1745,15 @@
                     { // Check if the channel is enabled
                         continue;
                     }
+#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 )
+                    if( IsLoRaMacNetworkJoined == false )
+                    {
+                        if( ( JOIN_CHANNELS & ( 1 << j ) ) == 0 )
+                        {
+                            continue;
+                        }
+                    }
+#endif
                     if( ( ( Channels[i + j].DrRange.Fields.Min <= ChannelsDatarate ) &&
                           ( ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
                     { // Check if the current channel selection supports the given datarate
@@ -1647,7 +1772,7 @@
     else
     {
         delayTx++;
-        nextTxDelay = AggregatedTimeOff - ( curTime - AggregatedLastTxDoneTime );
+        nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime( AggregatedLastTxDoneTime );
     }
 
     if( nbEnabledChannels > 0 )
@@ -1722,11 +1847,11 @@
 
         if( RepeaterSupport == true )
         {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] );
+            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
         }
         else
         {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] );
+            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
         }
 
         if( rxContinuous == false )
@@ -1766,6 +1891,20 @@
     return false;
 }
 
+static uint8_t CountBits( uint16_t mask, uint8_t nbBits )
+{
+    uint8_t nbActiveBits = 0;
+
+    for( uint8_t j = 0; j < nbBits; j++ )
+    {
+        if( ( mask & ( 1 << j ) ) == ( 1 << j ) )
+        {
+            nbActiveBits++;
+        }
+    }
+    return nbActiveBits;
+}
+
 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
 static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask )
 {
@@ -1773,17 +1912,75 @@
 
     for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ )
     {
-        for( uint8_t j = 0; j < 16; j++ )
-        {// Verify if the channel is active
-            if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) )
-            {
-                nb125kHzChannels++;
-            }
-        }
+        nb125kHzChannels += CountBits( channelsMask[k], 16 );
     }
 
     return nb125kHzChannels;
 }
+
+#if defined( USE_BAND_915_HYBRID )
+static void ReenableChannels( uint16_t mask, uint16_t* channelMask )
+{
+    uint16_t blockMask = mask;
+
+    for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 )
+    {
+        channelMask[i] = 0;
+        if( ( blockMask & ( 1 << j ) ) != 0 )
+        {
+            channelMask[i] |= 0x00FF;
+        }
+        if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 )
+        {
+            channelMask[i] |= 0xFF00;
+        }
+    }
+    channelMask[4] = blockMask;
+    channelMask[5] = 0x0000;
+}
+
+static bool ValidateChannelMask( uint16_t* channelMask )
+{
+    bool chanMaskState = false;
+    uint16_t block1 = 0;
+    uint16_t block2 = 0;
+    uint8_t index = 0;
+
+    for( uint8_t i = 0; i < 4; i++ )
+    {
+        block1 = channelMask[i] & 0x00FF;
+        block2 = channelMask[i] & 0xFF00;
+
+        if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) )
+        {
+            channelMask[i] &= block1;
+            channelMask[4] = 1 << ( i * 2 );
+            chanMaskState = true;
+            index = i;
+        }
+        else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) )
+        {
+            channelMask[i] &= block2;
+            channelMask[4] = 1 << ( i * 2 + 1 );
+            chanMaskState = true;
+            index = i;
+        }
+    }
+
+    // Do only change the channel mask, if we have found a valid block.
+    if( chanMaskState == true )
+    {
+        for( uint8_t i = 0; i < 4; i++ )
+        {
+            if( i != index )
+            {
+                channelMask[i] = 0;
+            }
+        }
+    }
+    return chanMaskState;
+}
+#endif
 #endif
 
 static int8_t LimitTxPower( int8_t txPower )
@@ -1838,7 +2035,7 @@
 
     if( adrEnabled == true )
     {
-        if( datarate == LORAMAC_MIN_DATARATE )
+        if( datarate == LORAMAC_TX_MIN_DATARATE )
         {
             AdrAckCounter = 0;
             adrAckReq = false;
@@ -1858,11 +2055,11 @@
                 if( ( ( AdrAckCounter - ADR_ACK_DELAY ) % ADR_ACK_LIMIT ) == 0 )
                 {
 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                    if( datarate > LORAMAC_MIN_DATARATE )
+                    if( datarate > LORAMAC_TX_MIN_DATARATE )
                     {
                         datarate--;
                     }
-                    if( datarate == LORAMAC_MIN_DATARATE )
+                    if( datarate == LORAMAC_TX_MIN_DATARATE )
                     {
                         if( updateChannelMask == true )
                         {
@@ -1872,15 +2069,15 @@
                         }
                     }
 #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                    if( ( datarate > LORAMAC_MIN_DATARATE ) && ( datarate == DR_8 ) )
+                    if( ( datarate > LORAMAC_TX_MIN_DATARATE ) && ( datarate == DR_8 ) )
                     {
                         datarate = DR_4;
                     }
-                    else if( datarate > LORAMAC_MIN_DATARATE )
+                    else if( datarate > LORAMAC_TX_MIN_DATARATE )
                     {
                         datarate--;
                     }
-                    if( datarate == LORAMAC_MIN_DATARATE )
+                    if( datarate == LORAMAC_TX_MIN_DATARATE )
                     {
                         if( updateChannelMask == true )
                         {
@@ -1894,12 +2091,7 @@
                             ChannelsMask[5] = 0x0000;
 #else // defined( USE_BAND_915_HYBRID )
                             // Re-enable default channels
-                            ChannelsMask[0] = 0x00FF;
-                            ChannelsMask[1] = 0x0000;
-                            ChannelsMask[2] = 0x0000;
-                            ChannelsMask[3] = 0x0000;
-                            ChannelsMask[4] = 0x0001;
-                            ChannelsMask[5] = 0x0000;
+                            ReenableChannels( ChannelsMask[4], ChannelsMask );
 #endif
                         }
                     }
@@ -2124,11 +2316,18 @@
                         {
                             status &= 0xFE; // Channel mask KO
                         }
+
+#if defined( USE_BAND_915_HYBRID )
+                        if( ValidateChannelMask( channelsMask ) == false )
+                        {
+                            status &= 0xFE; // Channel mask KO
+                        }
+#endif
                     }
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
-                    if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
+                    if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
                     {
                         status &= 0xFD; // Datarate KO
                     }
@@ -2144,21 +2343,14 @@
                     {
                         ChannelsDatarate = datarate;
                         ChannelsTxPower = txPower;
-#if defined( USE_BAND_915_HYBRID )
-                        ChannelsMask[0] = channelsMask[0] & 0x00FF;
-                        ChannelsMask[1] = channelsMask[1] & 0x0000;
-                        ChannelsMask[2] = channelsMask[2] & 0x0000;
-                        ChannelsMask[3] = channelsMask[3] & 0x0000;
-                        ChannelsMask[4] = channelsMask[4] & 0x0001;
-                        ChannelsMask[5] = channelsMask[5] & 0x0000;
-#else
+
                         ChannelsMask[0] = channelsMask[0];
                         ChannelsMask[1] = channelsMask[1];
                         ChannelsMask[2] = channelsMask[2];
                         ChannelsMask[3] = channelsMask[3];
                         ChannelsMask[4] = channelsMask[4];
                         ChannelsMask[5] = channelsMask[5];
-#endif
+
                         ChannelsNbRep = nbRep;
                     }
                     AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
@@ -2190,7 +2382,7 @@
                         status &= 0xFE; // Channel frequency KO
                     }
 
-                    if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
+                    if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false )
                     {
                         status &= 0xFD; // Datarate KO
                     }
@@ -2358,6 +2550,8 @@
         AggregatedTimeOff = 0;
     }
 
+    CalculateBackOff( LastTxChannel );
+
     // Select channel
     while( SetNextChannel( &dutyCycleTimeOff ) == false )
     {
@@ -2387,6 +2581,30 @@
     }
 }
 
+static void CalculateBackOff( uint8_t channel )
+{
+    uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle;
+
+    if( IsLoRaMacNetworkJoined == false )
+    {
+#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 )
+        dutyCycle = JOIN_DC;
+#endif
+    }
+
+    // Update Band Time OFF
+    if( DutyCycleOn == true )
+    {
+        Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir;
+    }
+    else
+    {
+        Bands[Channels[channel].Band].TimeOff = 0;
+    }
+    // Update Aggregated Time OFF
+    AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
+}
+
 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
 {
     uint16_t i;
@@ -2537,15 +2755,16 @@
 LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel )
 {
     int8_t datarate = Datarates[ChannelsDatarate];
+    int8_t txPowerIndex = 0;
     int8_t txPower = 0;
 
-    ChannelsTxPower = LimitTxPower( ChannelsTxPower );
-    txPower = TxPowers[ChannelsTxPower];
+    txPowerIndex = LimitTxPower( ChannelsTxPower );
+    txPower = TxPowers[txPowerIndex];
 
     MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
     McpsConfirm.Datarate = ChannelsDatarate;
-    McpsConfirm.TxPower = ChannelsTxPower;
+    McpsConfirm.TxPower = txPowerIndex;
 
     Radio.SetChannel( channel.Frequency );
 
@@ -2876,6 +3095,11 @@
             mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2;
             break;
         }
+        case MIB_CHANNELS_DEFAULT_DATARATE:
+        {
+            mibGet->Param.ChannelsDefaultDatarate = ChannelsDefaultDatarate;
+            break;
+        }
         case MIB_CHANNELS_DATARATE:
         {
             mibGet->Param.ChannelsDatarate = ChannelsDatarate;
@@ -3015,19 +3239,32 @@
             if( mibSet->Param.ChannelsMask )
             {
 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) &&
-                    ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
+                bool chanMaskState = true;
+
+#if defined( USE_BAND_915_HYBRID )
+                chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask );
+#endif
+                if( chanMaskState == true )
                 {
-                    status = LORAMAC_STATUS_PARAMETER_INVALID;
+                    if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) &&
+                        ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
+                    {
+                        status = LORAMAC_STATUS_PARAMETER_INVALID;
+                    }
+                    else
+                    {
+                        memcpy1( ( uint8_t* ) ChannelsMask,
+                                 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) );
+                        for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ )
+                        {
+                            // Disable channels which are no longer available
+                            ChannelsMaskRemaining[i] &= ChannelsMask[i];
+                        }
+                    }
                 }
                 else
                 {
-                    memcpy1( ( uint8_t* ) ChannelsMask,
-                             ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) );
-                    for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ )
-                    {
-                        ChannelsMaskRemaining[i] &= ChannelsMask[i];
-                    }
+                    status = LORAMAC_STATUS_PARAMETER_INVALID;
                 }
 #else
                 memcpy1( ( uint8_t* ) ChannelsMask,
@@ -3078,10 +3315,23 @@
             JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
             break;
         }
+        case MIB_CHANNELS_DEFAULT_DATARATE:
+        {
+            if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate,
+                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
+            {
+                ChannelsDefaultDatarate = mibSet->Param.ChannelsDefaultDatarate;
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
         case MIB_CHANNELS_DATARATE:
         {
             if( ValueInRange( mibSet->Param.ChannelsDatarate,
-                              LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) )
+                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
             {
                 ChannelsDatarate = mibSet->Param.ChannelsDatarate;
             }
@@ -3116,6 +3366,16 @@
             }
             break;
         }
+        case MIB_UPLINK_COUNTER:
+        {
+            UpLinkCounter = mibSet->Param.UpLinkCounter;
+            break;
+        }
+        case MIB_DOWNLINK_COUNTER:
+        {
+            DownLinkCounter = mibSet->Param.DownLinkCounter;
+            break;
+        }
         default:
             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
             break;
@@ -3148,10 +3408,10 @@
     }
     // Validate the datarate
     if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) ||
-        ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_MIN_DATARATE,
-                        LORAMAC_MAX_DATARATE ) == false ) ||
-        ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_MIN_DATARATE,
-                        LORAMAC_MAX_DATARATE ) == false ) )
+        ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_TX_MIN_DATARATE,
+                        LORAMAC_TX_MAX_DATARATE ) == false ) ||
+        ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_TX_MIN_DATARATE,
+                        LORAMAC_TX_MAX_DATARATE ) == false ) )
     {
         datarateInvalid = true;
     }
@@ -3164,11 +3424,11 @@
             frequencyInvalid = true;
         }
 
-        if( params.DrRange.Fields.Min > LORAMAC_DEFAULT_DATARATE )
+        if( params.DrRange.Fields.Min > ChannelsDefaultDatarate )
         {
             datarateInvalid = true;
         }
-        if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_MAX_DATARATE ) == false )
+        if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE ) == false )
         {
             datarateInvalid = true;
         }
@@ -3243,7 +3503,7 @@
         }
     }
 
-    if( id < 3 )
+    if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
     {
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
@@ -3251,7 +3511,7 @@
     {
         // Remove the channel from the list of channels
         Channels[id] = ( ChannelParams_t ){ 0, { 0 }, 0 };
-        
+
         // Disable the channel as it doesn't exist anymore
         if( DisableChannelInMask( id, ChannelsMask ) == false )
         {
@@ -3501,7 +3761,7 @@
     {
         if( AdrCtrlOn == false )
         {
-            if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == true )
+            if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true )
             {
                 ChannelsDatarate = datarate;
             }