Fork of Semtech LoRaWAN stack

Fork of LoRaWAN-lib by canuck lehead

Branch:
class_b
Revision:
38:182ba91524e4
Parent:
34:1ac668ce2b15
Child:
39:ca51084123b8
diff -r a592e8eeaa1e -r 182ba91524e4 LoRaMac.cpp
--- a/LoRaMac.cpp	Tue Aug 08 19:27:17 2017 -0400
+++ b/LoRaMac.cpp	Wed Aug 09 16:20:21 2017 -0400
@@ -15,15 +15,18 @@
 
 License: Revised BSD License, see LICENSE.TXT file include in the project
 
-Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
+Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
 */
-#include <math.h>
 #include "board.h"
 
+#include "LoRaMac.h"
+#include "LoRaMacClassB.h"
+#include "region/Region.h"
 #include "LoRaMacCrypto.h"
-#include "LoRaMac.h"
 #include "LoRaMacTest.h"
 
+
+
 /*!
  * Maximum PHY layer payload size
  */
@@ -32,14 +35,12 @@
 /*!
  * Maximum MAC commands buffer size
  */
-#define LORA_MAC_COMMAND_MAX_LENGTH                 15
+#define LORA_MAC_COMMAND_MAX_LENGTH                 128
 
 /*!
- * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
- * in RxWindowSetup function.
- * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD
+ * Maximum length of the fOpts field
  */
-#define LORA_MAC_FRMPAYLOAD_OVERHEAD                13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
+#define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH           15
 
 /*!
  * LoRaMac duty cycle for the back-off procedure during the first hour.
@@ -57,6 +58,11 @@
 #define BACKOFF_DC_24_HOURS                         10000
 
 /*!
+ * LoRaMac region.
+ */
+static LoRaMacRegion_t LoRaMacRegion;
+
+/*!
  * Device IEEE EUI
  */
 static uint8_t *LoRaMacDevEui;
@@ -121,11 +127,6 @@
 static bool PublicNetwork;
 
 /*!
- * Indicates if the node supports repeaters
- */
-static bool RepeaterSupport;
-
-/*!
  * Buffer containing the data to be sent or received.
  */
 static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD];
@@ -220,269 +221,6 @@
  */
 static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
 
-#if defined( USE_BAND_433 )
-/*!
- * Data rates table definition
- */
-const uint8_t Datarates[]  = { 12, 11, 10,  9,  8,  7,  7, 50 };
-
-/*!
- * Bandwidths table definition in Hz
- */
-const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 };
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
-/*!
- * Tx output powers table definition
- */
-const int8_t TxPowers[]    = { 10, 7, 4, 1, -2, -5 };
-
-/*!
- * LoRaMac bands
- */
-static Band_t Bands[LORA_MAX_NB_BANDS] =
-{
-    BAND0,
-};
-
-/*!
- * LoRaMAC channels
- */
-static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
-{
-    LC1,
-    LC2,
-    LC3,
-};
-#elif defined( USE_BAND_470 )
-
-/*!
- * Data rates table definition
- */
-const uint8_t Datarates[]  = { 12, 11, 10,  9,  8,  7 };
-
-/*!
- * Bandwidths table definition in Hz
- */
-const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3 };
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 222, 222 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222 };
-
-/*!
- * Tx output powers table definition
- */
-const int8_t TxPowers[]    = { 17, 16, 14, 12, 10, 7, 5, 2 };
-
-/*!
- * LoRaMac bands
- */
-static Band_t Bands[LORA_MAX_NB_BANDS] =
-{
-    BAND0,
-};
-
-/*!
- * LoRaMAC channels
- */
-static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
-
-/*!
- * Defines the first channel for RX window 1 for CN470 band
- */
-#define LORAMAC_FIRST_RX1_CHANNEL           ( (uint32_t) 500.3e6 )
-
-/*!
- * Defines the last channel for RX window 1 for CN470 band
- */
-#define LORAMAC_LAST_RX1_CHANNEL            ( (uint32_t) 509.7e6 )
-
-/*!
- * Defines the step width of the channels for RX window 1
- */
-#define LORAMAC_STEPWIDTH_RX1_CHANNEL       ( (uint32_t) 200e3 )
-
-#elif defined( USE_BAND_780 )
-/*!
- * Data rates table definition
- */
-const uint8_t Datarates[]  = { 12, 11, 10,  9,  8,  7,  7, 50 };
-
-/*!
- * Bandwidths table definition in Hz
- */
-const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 };
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
-/*!
- * Tx output powers table definition
- */
-const int8_t TxPowers[]    = { 10, 7, 4, 1, -2, -5 };
-
-/*!
- * LoRaMac bands
- */
-static Band_t Bands[LORA_MAX_NB_BANDS] =
-{
-    BAND0,
-};
-
-/*!
- * LoRaMAC channels
- */
-static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
-{
-    LC1,
-    LC2,
-    LC3,
-};
-#elif defined( USE_BAND_868 )
-/*!
- * Data rates table definition
- */
-const uint8_t Datarates[]  = { 12, 11, 10,  9,  8,  7,  7, 50 };
-
-/*!
- * Bandwidths table definition in Hz
- */
-const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 };
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
-
-/*!
- * Tx output powers table definition
- */
-const int8_t TxPowers[]    = { 20, 14, 11,  8,  5,  2 };
-
-/*!
- * LoRaMac bands
- */
-static Band_t Bands[LORA_MAX_NB_BANDS] =
-{
-    BAND0,
-    BAND1,
-    BAND2,
-    BAND3,
-    BAND4,
-};
-
-/*!
- * LoRaMAC channels
- */
-static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
-{
-    LC1,
-    LC2,
-    LC3,
-};
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-/*!
- * Data rates table definition
- */
-const uint8_t Datarates[]  = { 10, 9, 8,  7,  8,  0,  0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
-
-/*!
- * Bandwidths table definition in Hz
- */
-const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 500e3, 0, 0, 0, 500e3, 500e3, 500e3, 500e3, 500e3, 500e3, 0, 0 };
-
-/*!
- * Up/Down link data rates offset definition
- */
-const int8_t DatarateOffsets[5][4] =
-{
-    { DR_10, DR_9 , DR_8 , DR_8  }, // DR_0
-    { DR_11, DR_10, DR_9 , DR_8  }, // DR_1
-    { DR_12, DR_11, DR_10, DR_9  }, // DR_2
-    { DR_13, DR_12, DR_11, DR_10 }, // DR_3
-    { DR_13, DR_13, DR_12, DR_11 }, // DR_4
-};
-
-/*!
- * Maximum payload with respect to the datarate index. Cannot operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarate[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
-
-/*!
- * Maximum payload with respect to the datarate index. Can operate with repeater.
- */
-const uint8_t MaxPayloadOfDatarateRepeater[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
-
-/*!
- * Tx output powers table definition
- */
-const int8_t TxPowers[]    = { 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10 };
-
-/*!
- * LoRaMac bands
- */
-static Band_t Bands[LORA_MAX_NB_BANDS] =
-{
-    BAND0,
-};
-
-/*!
- * LoRaMAC channels
- */
-static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
-
-/*!
- * Contains the channels which remain to be applied.
- */
-static uint16_t ChannelsMaskRemaining[6];
-
-/*!
- * Defines the first channel for RX window 1 for US band
- */
-#define LORAMAC_FIRST_RX1_CHANNEL           ( (uint32_t) 923.3e6 )
-
-/*!
- * Defines the last channel for RX window 1 for US band
- */
-#define LORAMAC_LAST_RX1_CHANNEL            ( (uint32_t) 927.5e6 )
-
-/*!
- * Defines the step width of the channels for RX window 1
- */
-#define LORAMAC_STEPWIDTH_RX1_CHANNEL       ( (uint32_t) 600e3 )
-
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
 /*!
  * LoRaMac parameters
  */
@@ -522,6 +260,16 @@
 static uint8_t Channel;
 
 /*!
+ * Current channel index
+ */
+static uint8_t LastTxChannel;
+
+/*!
+ * Set to true, if the last uplink was a join request
+ */
+static bool LastTxIsJoinRequest;
+
+/*!
  * Stores the time at LoRaMac initialization.
  *
  * \remark Used for the BACKOFF_DC computation.
@@ -588,20 +336,10 @@
 static uint32_t RxWindow2Delay;
 
 /*!
- * Rx window parameters
+ * LoRaMac Rx windows configuration
  */
-typedef struct
-{
-    int8_t Datarate;
-    uint8_t Bandwidth;
-    uint32_t RxWindowTimeout;
-    int32_t RxOffset;
-}RxConfigParams_t;
-
-/*!
- * Rx windows params
- */
-static RxConfigParams_t RxWindowsParams[2];
+static RxConfigParams_t RxWindow1Config;
+static RxConfigParams_t RxWindow2Config;
 
 /*!
  * Acknowledge timeout timer. Used for packet retransmissions.
@@ -649,11 +387,26 @@
 static McpsConfirm_t McpsConfirm;
 
 /*!
+ * Structure to hold MLME indication data.
+ */
+static MlmeIndication_t MlmeIndication;
+
+/*!
  * Structure to hold MLME confirm data.
  */
 static MlmeConfirm_t MlmeConfirm;
 
 /*!
+ * MlmeConfirm queue data structure
+ */
+static MlmeConfirmQueue_t MlmeConfirmQueue[LORA_MAC_MLME_CONFIRM_QUEUE_LEN];
+
+/*!
+ * Counts the number of MlmeConfirms to process
+ */
+static uint8_t MlmeConfirmQueueCnt;
+
+/*!
  * Holds the current rx window slot
  */
 static uint8_t RxSlot = 0;
@@ -720,36 +473,19 @@
 static void OnAckTimeoutTimerEvent( void );
 
 /*!
- * \brief Searches and set the next random available channel
- *
- * \param [OUT] Time to wait for the next transmission according to the duty
- *              cycle.
- *
- * \retval status  Function status [1: OK, 0: Unable to find a channel on the
- *                                  current datarate]
- */
-static bool SetNextChannel( TimerTime_t* time );
-
-/*!
  * \brief Initializes and opens the reception window
  *
- * \param [IN] freq window channel frequency
- * \param [IN] datarate window channel datarate
- * \param [IN] bandwidth window channel bandwidth
- * \param [IN] timeout window channel timeout
- *
- * \retval status Operation status [true: Success, false: Fail]
+ * \param [IN] rxContinuous Set to true, if the RX is in continuous mode
+ * \param [IN] maxRxWindow Maximum RX window timeout
  */
-static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous );
+static void RxWindowSetup( bool rxContinuous, uint32_t maxRxWindow );
 
 /*!
- * \brief Verifies if the RX window 2 frequency is in range
- *
- * \param [IN] freq window channel frequency
+ * \brief Switches the device class
  *
- * \retval status  Function status [1: OK, 0: Frequency not applicable]
+ * \param [IN] deviceClass Device class to switch to
  */
-static bool Rx2FreqInRange( uint32_t freq );
+static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass );
 
 /*!
  * \brief Adds a new MAC command to be sent.
@@ -803,105 +539,6 @@
 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 [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* channelsMask );
-
-/*!
- * \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* channelsMask );
-#endif
-
-#endif
-
-/*!
- * \brief Validates the correctness of the datarate against the enable channels.
- *
- * \param [IN] datarate Datarate to be check
- * \param [IN] channelsMask Pointer to the first element of the channel mask
- *
- * \retval [true: datarate can be used, false: datarate can not be used]
- */
-static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask );
-
-/*!
- * \brief Limits the Tx power according to the number of enabled channels
- *
- * \param [IN] txPower txPower to limit
- * \param [IN] maxBandTxPower Maximum band allowed TxPower
- *
- * \retval Returns the maximum valid tx power
- */
-static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower );
-
-/*!
- * \brief Verifies, if a value is in a given range.
- *
- * \param value Value to verify, if it is in range
- *
- * \param min Minimum possible value
- *
- * \param max Maximum possible value
- *
- * \retval Returns the maximum valid tx power
- */
-static bool ValueInRange( int8_t value, int8_t min, int8_t max );
-
-/*!
- * \brief Calculates the next datarate to set, when ADR is on or off
- *
- * \param [IN] adrEnabled Specify whether ADR is on or off
- *
- * \param [IN] updateChannelMask Set to true, if the channel masks shall be updated
- *
- * \param [OUT] datarateOut Reports the datarate which will be used next
- *
- * \retval Returns the state of ADR ack request
- */
-static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut );
-
-/*!
- * \brief Disables channel in a specified channel mask
- *
- * \param [IN] id - Id of the channel
- *
- * \param [IN] mask - Pointer to the channel mask to edit
- *
- * \retval [true, if disable was successful, false if not]
- */
-static bool DisableChannelInMask( uint8_t id, uint16_t* mask );
-
-/*!
  * \brief Decodes MAC commands in the fOpts field and in the payload
  */
 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
@@ -938,13 +575,6 @@
 static LoRaMacStatus_t ScheduleTx( void );
 
 /*
- * \brief Sets the duty cycle for the join procedure.
- *
- * \retval Duty cycle
- */
-static uint16_t JoinDutyCycle( void );
-
-/*
  * \brief Calculates the back-off time for the band of a channel.
  *
  * \param [IN] channel     The last Tx channel index
@@ -952,12 +582,21 @@
 static void CalculateBackOff( uint8_t channel );
 
 /*
- * \brief Alternates the datarate of the channel for the join request.
+ * \brief Gets the index of the confirm queue of a specific MLME-request
  *
- * \param [IN] nbTrials    Number of performed join requests.
- * \retval Datarate to apply
+ * \param [IN] queue        MLME-Confirm queue pointer
+ * \param [IN] req          MLME-Request to validate
+ * \retval Index of the MLME-Confirm. 0xFF is no entry found.
  */
-static int8_t AlternateDatarate( uint16_t nbTrials );
+static uint8_t GetMlmeConfirmIndex( MlmeConfirmQueue_t* queue, Mlme_t req );
+
+/*
+ * \brief Sets the status of all MLME requests in the queue to the provided status
+ *
+ * \param [IN] queue        MLME-Confirm queue pointer
+ * \param [IN] status       MLME-Status to set
+ */
+static void SetEveryMlmeConfirmStatus( MlmeConfirmQueue_t* queue, LoRaMacEventInfoStatus_t status );
 
 /*!
  * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
@@ -965,10 +604,10 @@
  * \remark PrepareFrame must be called at least once before calling this
  *         function.
  *
- * \param [IN] channel     Channel parameters
- * \retval status          Status of the operation.
+ * \param [IN] channel     Channel to transmit on
+ * \retval Time delay      Returns a time which shall delay the next TX.
  */
-LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
+TimerTime_t SendFrameOnChannel( uint8_t channel );
 
 /*!
  * \brief Sets the radio in continuous transmission mode
@@ -987,7 +626,7 @@
  *
  * \param [IN] timeout     Time in seconds while the radio is kept in continuous wave mode
  * \param [IN] frequency   RF frequency to be set.
- * \param [IN] power       RF ouptput power to be set.
+ * \param [IN] power       RF output power to be set.
  * \retval status          Status of the operation.
  */
 LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power );
@@ -997,58 +636,11 @@
  */
 static void ResetMacParameters( void );
 
-/*
- * Rx window precise timing
- *
- * For more details please consult the following document, chapter 3.1.2.
- * http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf
- * or
- * http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf
- *
- *                 Downlink start: T = Tx + 1s (+/- 20 us)
- *                            |
- *             TRxEarly       |        TRxLate
- *                |           |           |
- *                |           |           +---+---+---+---+---+---+---+---+
- *                |           |           |       Latest Rx window        |
- *                |           |           +---+---+---+---+---+---+---+---+
- *                |           |           |
- *                +---+---+---+---+---+---+---+---+
- *                |       Earliest Rx window      |
- *                +---+---+---+---+---+---+---+---+
- *                            |
- *                            +---+---+---+---+---+---+---+---+
- *Downlink preamble 8 symbols |   |   |   |   |   |   |   |   |
- *                            +---+---+---+---+---+---+---+---+
- *
- *                     Worst case Rx window timings
- *
- * TRxLate  = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME
- * TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME
- *
- * TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
- *
- * RxOffset = ( TRxLate + TRxEarly ) / 2
- *
- * RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR
- * RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME
- *
- * Minimal value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol
- */
-/*!
- * Computes the Rx window parameters.
- *
- * \param [IN] datarate     Rx window datarate to be used
- * \param [IN] rxError      Maximum timing error of the receiver. in milliseconds
- *                          The receiver will turn on in a [-rxError : +rxError] ms
- *                          interval around RxOffset
- *
- * \retval rxConfigParams   Returns a RxConfigParams_t structure.
- */
-static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError );
-
 static void OnRadioTxDone( void )
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    SetBandTxDoneParams_t txDone;
     TimerTime_t curTime = TimerGetCurrentTime( );
 
     if( LoRaMacDeviceClass != CLASS_C )
@@ -1072,15 +664,16 @@
         }
         if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
         {
-            TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT +
-                                             randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
+            getPhy.Attribute = PHY_ACK_TIMEOUT;
+            phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+            TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + phyParam.Value );
             TimerStart( &AckTimeoutTimer );
         }
     }
     else
     {
         McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+        SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT );
 
         if( LoRaMacFlags.Value == 0 )
         {
@@ -1089,12 +682,25 @@
         LoRaMacFlags.Bits.MacDone = 1;
     }
 
+    // Verify if the last uplink was a join request
+    if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) )
+    {
+        LastTxIsJoinRequest = true;
+    }
+    else
+    {
+        LastTxIsJoinRequest = false;
+    }
+
+    // Store last Tx channel
+    LastTxChannel = Channel;
     // Update last tx done time for the current channel
-    Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
+    txDone.Channel = Channel;
+    txDone.Joined = IsLoRaMacNetworkJoined;
+    txDone.LastTxDoneTime = curTime;
+    RegionSetBandTxDone( LoRaMacRegion, &txDone );
     // Update Aggregated last tx done time
     AggregatedLastTxDoneTime = curTime;
-    // Update Backoff
-    CalculateBackOff( Channel );
 
     if( NodeAckRequested == false )
     {
@@ -1124,8 +730,13 @@
 {
     LoRaMacHeader_t macHdr;
     LoRaMacFrameCtrl_t fCtrl;
+    ApplyCFListParams_t applyCFList;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     bool skipIndication = false;
 
+    uint8_t index = 0;
+
     uint8_t pktHeaderLen = 0;
     uint32_t address = 0;
     uint8_t appPayloadStartIndex = 0;
@@ -1164,6 +775,21 @@
     Radio.Sleep( );
     TimerStop( &RxWindowTimer2 );
 
+    // This function must be called even if we are not in class b mode yet.
+    if( LoRaMacClassBRxBeacon( payload, size ) == true )
+    {
+        return;
+    }
+    // Check if we expect a ping slot.
+    if( LoRaMacDeviceClass == CLASS_B )
+    {
+        if( LoRaMacClassBIsPingExpected( ) == true )
+        {
+            LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_SET_TIMER );
+            LoRaMacClassBPingSlotTimerEvent( );
+        }
+    }
+
     macHdr.Value = payload[pktHeaderLen++];
 
     switch( macHdr.Bits.MType )
@@ -1186,72 +812,80 @@
             micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
             micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
 
-            if( micRx == mic )
+            index = GetMlmeConfirmIndex( MlmeConfirmQueue, MLME_JOIN );
+            if( index < LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
             {
-                LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
-
-                LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4];
-                LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
-                LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 );
-
-                LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7];
-                LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 );
-                LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 );
-                LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 );
-
-                // DLSettings
-                LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
-                LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
-
-                // RxDelay
-                LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
-                if( LoRaMacParams.ReceiveDelay1 == 0 )
+                if( micRx == mic )
                 {
-                    LoRaMacParams.ReceiveDelay1 = 1;
+                    LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
+
+                    LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4];
+                    LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
+                    LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 );
+
+                    LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7];
+                    LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 );
+                    LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 );
+                    LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 );
+
+                    // DLSettings
+                    LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
+                    LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
+
+                    // RxDelay
+                    LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
+                    if( LoRaMacParams.ReceiveDelay1 == 0 )
+                    {
+                        LoRaMacParams.ReceiveDelay1 = 1;
+                    }
+                    LoRaMacParams.ReceiveDelay1 *= 1000;
+                    LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1000;
+
+                    // Apply CF list
+                    applyCFList.Payload = &LoRaMacRxPayload[13];
+                    // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
+                    applyCFList.Size = size - 17;
+
+                    RegionApplyCFList( LoRaMacRegion, &applyCFList );
+
+                    MlmeConfirmQueue[index].Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                    IsLoRaMacNetworkJoined = true;
+                    LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
                 }
-                LoRaMacParams.ReceiveDelay1 *= 1e3;
-                LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3;
-
-#if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-                //CFList
-                if( ( size - 1 ) > 16 )
+                else
                 {
-                    ChannelParams_t param;
-                    param.DrRange.Value = ( DR_5 << 4 ) | DR_0;
-
-                    LoRaMacState |= LORAMAC_TX_CONFIG;
-                    for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
-                    {
-                        param.Frequency = ( ( uint32_t )LoRaMacRxPayload[13 + j] | ( ( uint32_t )LoRaMacRxPayload[14 + j] << 8 ) | ( ( uint32_t )LoRaMacRxPayload[15 + j] << 16 ) ) * 100;
-                        if( param.Frequency != 0 )
-                        {
-                            LoRaMacChannelAdd( i, param );
-                        }
-                        else
-                        {
-                            LoRaMacChannelRemove( i );
-                        }
-                    }
-                    LoRaMacState &= ~LORAMAC_TX_CONFIG;
+                    MlmeConfirmQueue[index].Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
                 }
-#endif
-                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-                IsLoRaMacNetworkJoined = true;
-                LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
-            }
-            else
-            {
-                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
             }
             break;
         case FRAME_TYPE_DATA_CONFIRMED_DOWN:
         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
             {
+                // Check if the received payload size is valid
+                getPhy.UplinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+                getPhy.Datarate = McpsIndication.RxDatarate;
+                getPhy.Attribute = PHY_MAX_PAYLOAD;
+
+                // Get the maximum payload length
+                if( LoRaMacParams.RepeaterSupport == true )
+                {
+                    getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
+                }
+                phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+                if( (uint32_t)MAX( (int16_t)0, ( int16_t )( ( int16_t )size - ( int16_t )LORA_MAC_FRMPAYLOAD_OVERHEAD ) ) > phyParam.Value )
+                {
+                    McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+                    PrepareRxDoneAbort( );
+                    return;
+                }
+
                 address = payload[pktHeaderLen++];
                 address |= ( (uint32_t)payload[pktHeaderLen++] << 8 );
                 address |= ( (uint32_t)payload[pktHeaderLen++] << 16 );
                 address |= ( (uint32_t)payload[pktHeaderLen++] << 24 );
 
+                fCtrl.Value = payload[pktHeaderLen++];
+
                 if( address != LoRaMacDevAddr )
                 {
                     curMulticastParams = MulticastChannels;
@@ -1274,6 +908,15 @@
                         PrepareRxDoneAbort( );
                         return;
                     }
+                    if( ( macHdr.Bits.MType != FRAME_TYPE_DATA_UNCONFIRMED_DOWN ) ||
+                        ( fCtrl.Bits.Ack == 1 ) ||
+                        ( fCtrl.Bits.AdrAckReq == 1 ) )
+                    {
+                        // Wrong multicast message format. Refer to chapter 11.2.2 of the specification
+                        McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL;
+                        PrepareRxDoneAbort( );
+                        return;
+                    }
                 }
                 else
                 {
@@ -1283,8 +926,6 @@
                     downLinkCounter = DownLinkCounter;
                 }
 
-                fCtrl.Value = payload[pktHeaderLen++];
-
                 sequenceCounter = ( uint16_t )payload[pktHeaderLen++];
                 sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8;
 
@@ -1320,7 +961,9 @@
                 }
 
                 // Check for a the maximum allowed counter difference
-                if( sequenceCounterDiff >= MAX_FCNT_GAP )
+                getPhy.Attribute = PHY_MAX_FCNT_GAP;
+                phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+                if( sequenceCounterDiff >= phyParam.Value )
                 {
                     McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
                     McpsIndication.DownLinkCounter = downLinkCounter;
@@ -1394,7 +1037,7 @@
 
                     // This must be done before parsing the payload and the MAC commands.
                     // We need to reset the MacCommandsBufferIndex here, since we need
-                    // to take retransmissions and repititions into account. Error cases
+                    // to take retransmissions and repetitions into account. Error cases
                     // will be handled in function OnMacStateCheckTimerEvent.
                     if( McpsConfirm.McpsRequest == MCPS_CONFIRMED )
                     {
@@ -1418,8 +1061,7 @@
 
                         if( port == 0 )
                         {
-                            // Only allow frames which do not have fOpts
-                            if( fCtrl.Bits.FOptsLen == 0 )
+                            if( ( fCtrl.Bits.FOptsLen == 0 ) && ( multicast == 0 ) )
                             {
                                 LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
                                                        frameLen,
@@ -1439,7 +1081,7 @@
                         }
                         else
                         {
-                            if( fCtrl.Bits.FOptsLen > 0 )
+                            if( ( fCtrl.Bits.FOptsLen > 0 ) && ( multicast == 0 ) )
                             {
                                 // Decode Options field MAC commands. Omit the fPort.
                                 ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr );
@@ -1544,12 +1186,14 @@
     }
 
     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
-    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
+    SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT );
     LoRaMacFlags.Bits.MacDone = 1;
 }
 
 static void OnRadioRxError( void )
 {
+    bool classBRx = false;
+
     if( LoRaMacDeviceClass != CLASS_C )
     {
         Radio.Sleep( );
@@ -1559,32 +1203,52 @@
         OnRxWindow2TimerEvent( );
     }
 
-    if( RxSlot == 0 )
+    if( LoRaMacDeviceClass == CLASS_B )
     {
-        if( NodeAckRequested == true )
+        if( LoRaMacClassBIsBeaconExpected( ) == true )
+        {
+            LoRaMacClassBSetBeaconState( BEACON_STATE_TIMEOUT );
+            LoRaMacClassBBeaconTimerEvent( );
+            classBRx = true;
+        }
+        if( LoRaMacClassBIsPingExpected( ) == true )
         {
-            McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
+            LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_SET_TIMER );
+            LoRaMacClassBPingSlotTimerEvent( );
+            classBRx = true;
         }
-        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
-
-        if( TimerGetElapsedTime( AggregatedLastTxDoneTime ) >= RxWindow2Delay )
+    }
+
+    if( classBRx == false )
+    {
+        if( RxSlot == 0 )
         {
+            if( NodeAckRequested == true )
+            {
+                McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR;
+            }
+            SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_RX1_ERROR );
+            if( TimerGetElapsedTime( AggregatedLastTxDoneTime ) >= RxWindow2Delay )
+            {
+                LoRaMacFlags.Bits.MacDone = 1;
+            }
+        }
+        else
+        {
+            if( NodeAckRequested == true )
+            {
+                McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
+            }
+            SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_RX2_ERROR );
             LoRaMacFlags.Bits.MacDone = 1;
         }
     }
-    else
-    {
-        if( NodeAckRequested == true )
-        {
-            McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
-        }
-        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
-        LoRaMacFlags.Bits.MacDone = 1;
-    }
 }
 
 static void OnRadioRxTimeout( void )
 {
+    bool classBRx = false;
+
     if( LoRaMacDeviceClass != CLASS_C )
     {
         Radio.Sleep( );
@@ -1594,21 +1258,64 @@
         OnRxWindow2TimerEvent( );
     }
 
-    if( RxSlot == 1 )
+    if( LoRaMacDeviceClass == CLASS_B )
     {
-        if( NodeAckRequested == true )
+        if( LoRaMacClassBIsBeaconExpected( ) == true )
+        {
+            LoRaMacClassBSetBeaconState( BEACON_STATE_TIMEOUT );
+            LoRaMacClassBBeaconTimerEvent( );
+            classBRx = true;
+        }
+
+        if( LoRaMacClassBIsPingExpected( ) == true )
+        {
+            LoRaMacClassBSetPingSlotState( PINGSLOT_STATE_SET_TIMER );
+            LoRaMacClassBPingSlotTimerEvent( );
+            classBRx = true;
+        }
+    }
+
+    if( classBRx == false )
+    {
+        if( RxSlot == 0 )
         {
-            McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+            if( NodeAckRequested == true )
+            {
+                McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT;
+            }
+            SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT );
+
+            if( TimerGetElapsedTime( AggregatedLastTxDoneTime ) >= RxWindow2Delay )
+            {
+                LoRaMacFlags.Bits.MacDone = 1;
+            }
         }
-        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
-        LoRaMacFlags.Bits.MacDone = 1;
+        else
+        {
+            if( NodeAckRequested == true )
+            {
+                McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+            }
+            SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT );
+
+            if( LoRaMacDeviceClass != CLASS_C )
+            {
+                LoRaMacFlags.Bits.MacDone = 1;
+            }
+        }
     }
 }
 
 static void OnMacStateCheckTimerEvent( void )
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    uint8_t index = 0;
+    bool noTx = false;
+    uint8_t i, j = 0;
+
+
     TimerStop( &MacStateCheckTimer );
-    bool txTimeout = false;
 
     if( LoRaMacFlags.Bits.MacDone == 1 )
     {
@@ -1620,6 +1327,9 @@
 
         if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) )
         {
+            // Get a status of any request and check if we have a TX timeout
+            MlmeConfirm.Status = MlmeConfirmQueue[0].Status;
+
             if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ||
                 ( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) )
             {
@@ -1629,19 +1339,30 @@
                 McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
                 McpsConfirm.AckReceived = false;
                 McpsConfirm.TxTimeOnAir = 0;
-                txTimeout = true;
+                noTx = true;
+            }
+
+            index = GetMlmeConfirmIndex( MlmeConfirmQueue, MLME_BEACON_ACQUISITION );
+            if( ( index < LORA_MAC_MLME_CONFIRM_QUEUE_LEN ) && ( LoRaMacFlags.Bits.McpsReq == 0 ) )
+            {
+                if( LoRaMacFlags.Bits.MlmeReq == 1 )
+                {
+                    noTx = true;
+                    LoRaMacState &= ~LORAMAC_TX_RUNNING;
+                }
             }
         }
 
-        if( ( NodeAckRequested == false ) && ( txTimeout == false ) )
+        if( ( NodeAckRequested == false ) && ( noTx == false ) )
         {
             if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) )
             {
-                if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) )
+                index = GetMlmeConfirmIndex( MlmeConfirmQueue, MLME_JOIN );
+                if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( index < LORA_MAC_MLME_CONFIRM_QUEUE_LEN ) )
                 {// Procedure for the join request
                     MlmeConfirm.NbRetries = JoinRequestTrials;
 
-                    if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK )
+                    if( MlmeConfirmQueue[index].Status == LORAMAC_EVENT_INFO_STATUS_OK )
                     {// Node joined successfully
                         UpLinkCounter = 0;
                         ChannelsNbRepCounter = 0;
@@ -1666,7 +1387,7 @@
                     if( ( ChannelsNbRepCounter >= LoRaMacParams.ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) )
                     {
                         if( LoRaMacFlags.Bits.McpsInd == 0 )
-                        {   // Maximum repititions without downlink. Reset MacCommandsBufferIndex. Increase ADR Ack counter.
+                        {   // Maximum repetitions without downlink. Reset MacCommandsBufferIndex. Increase ADR Ack counter.
                             // Only process the case when the MAC did not receive a downlink.
                             MacCommandsBufferIndex = 0;
                             AdrAckCounter++;
@@ -1716,7 +1437,11 @@
 
                 if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
                 {
-                    LoRaMacParams.ChannelsDatarate = MAX( LoRaMacParams.ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE );
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+                    getPhy.Datarate = LoRaMacParams.ChannelsDatarate;
+                    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+                    LoRaMacParams.ChannelsDatarate = phyParam.Value;
                 }
                 // Try to send the frame again
                 if( ScheduleTx( ) == LORAMAC_STATUS_OK )
@@ -1742,21 +1467,8 @@
             }
             else
             {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                // Re-enable default channels LC1, LC2, LC3
-                LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-#elif defined( USE_BAND_470 )
-                // Re-enable default channels
-                memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#elif defined( USE_BAND_915 )
-                // Re-enable default channels
-                memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#elif defined( USE_BAND_915_HYBRID )
-                // Re-enable default channels
-                ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask );
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
+                RegionInitDefaults( LoRaMacRegion, INIT_TYPE_RESTORE );
+
                 LoRaMacState &= ~LORAMAC_TX_RUNNING;
 
                 MacCommandsBufferIndex = 0;
@@ -1785,12 +1497,44 @@
 
         if( LoRaMacFlags.Bits.MlmeReq == 1 )
         {
-            LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
-            LoRaMacFlags.Bits.MlmeReq = 0;
+            j = MlmeConfirmQueueCnt;
+            for( i = 0; i < MlmeConfirmQueueCnt; i++ )
+            {
+                if( MlmeConfirmQueue[i].MlmeRequest == MLME_BEACON_ACQUISITION )
+                {
+                    if( LoRaMacClassBIsAcquisitionPending( ) == true )
+                    {
+                        MlmeConfirmQueue[0].MlmeRequest = MLME_BEACON_ACQUISITION;
+                        MlmeConfirmQueue[0].Status = MlmeConfirmQueue[i].Status;
+                        continue;
+                    }
+                }
+                j--;
+                MlmeConfirm.Status = MlmeConfirmQueue[i].Status;
+                MlmeConfirm.MlmeRequest = MlmeConfirmQueue[i].MlmeRequest;
+                LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
+            }
+            MlmeConfirmQueueCnt = j;
+
+            if( MlmeConfirmQueueCnt == 0 )
+            {
+                LoRaMacFlags.Bits.MlmeReq = 0;
+            }
+        }
+
+        if( LoRaMacFlags.Bits.MlmeInd == 1 )
+        {
+            LoRaMacPrimitives->MacMlmeIndication( &MlmeIndication );
+            LoRaMacFlags.Bits.MlmeInd = 0;
         }
 
         // Procedure done. Reset variables.
         LoRaMacFlags.Bits.MacDone = 0;
+
+        if( LoRaMacDeviceClass == CLASS_B )
+        {
+            LoRaMacClassBResumeBeaconing( );
+        }
     }
     else
     {
@@ -1818,15 +1562,20 @@
 {
     LoRaMacHeader_t macHdr;
     LoRaMacFrameCtrl_t fCtrl;
+    AlternateDrParams_t altDr;
+    uint8_t index = 0;
 
     TimerStop( &TxDelayedTimer );
     LoRaMacState &= ~LORAMAC_TX_DELAYED;
 
-    if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) )
+    index = GetMlmeConfirmIndex( MlmeConfirmQueue, MLME_JOIN );
+
+    if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( index < LORA_MAC_MLME_CONFIRM_QUEUE_LEN ) )
     {
         ResetMacParameters( );
-        // Add a +1, since we start to count from 0
-        LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 );
+
+        altDr.NbTrials = JoinRequestTrials + 1;
+        LoRaMacParams.ChannelsDatarate = RegionAlternateDr( LoRaMacRegion, &altDr );
 
         macHdr.Value = 0;
         macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
@@ -1848,35 +1597,45 @@
     TimerStop( &RxWindowTimer1 );
     RxSlot = 0;
 
+    RxWindow1Config.Channel = Channel;
+    RxWindow1Config.DrOffset = LoRaMacParams.Rx1DrOffset;
+    RxWindow1Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+    RxWindow1Config.RepeaterSupport = LoRaMacParams.RepeaterSupport;
+    RxWindow1Config.RxContinuous = false;
+    RxWindow1Config.Window = RxSlot;
+
     if( LoRaMacDeviceClass == CLASS_C )
     {
         Radio.Standby( );
     }
 
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    RxWindowSetup( Channels[Channel].Frequency, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false );
-#elif defined( USE_BAND_470 )
-    RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false );
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 8 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false );
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
+    RegionRxConfig( LoRaMacRegion, &RxWindow1Config, ( int8_t* )&McpsIndication.RxDatarate );
+    RxWindowSetup( RxWindow1Config.RxContinuous, LoRaMacParams.MaxRxWindow );
 }
 
 static void OnRxWindow2TimerEvent( void )
 {
-    bool rxContinuousMode = false;
-
     TimerStop( &RxWindowTimer2 );
 
-    if( LoRaMacDeviceClass == CLASS_C )
+    RxWindow2Config.Channel = Channel;
+    RxWindow2Config.Frequency = LoRaMacParams.Rx2Channel.Frequency;
+    RxWindow2Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+    RxWindow2Config.RepeaterSupport = LoRaMacParams.RepeaterSupport;
+    RxWindow2Config.Window = 1;
+
+    if( LoRaMacDeviceClass != CLASS_C )
     {
-        rxContinuousMode = true;
+        RxWindow2Config.RxContinuous = false;
+    }
+    else
+    {
+        RxWindow2Config.RxContinuous = true;
     }
-    if( RxWindowSetup( LoRaMacParams.Rx2Channel.Frequency, RxWindowsParams[1].Datarate, RxWindowsParams[1].Bandwidth, RxWindowsParams[1].RxWindowTimeout, rxContinuousMode ) == true )
+
+    if( RegionRxConfig( LoRaMacRegion, &RxWindow2Config, ( int8_t* )&McpsIndication.RxDatarate ) == true )
     {
-        RxSlot = 1;
+        RxWindowSetup( RxWindow2Config.RxContinuous, LoRaMacParams.MaxRxWindow );
+        RxSlot = RxWindow2Config.Window;
     }
 }
 
@@ -1895,221 +1654,93 @@
     }
 }
 
-static bool SetNextChannel( TimerTime_t* time )
+static void RxWindowSetup( bool rxContinuous, uint32_t maxRxWindow )
 {
-    uint8_t nbEnabledChannels = 0;
-    uint8_t delayTx = 0;
-    uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
-    TimerTime_t nextTxDelay = ( TimerTime_t )( -1 );
-
-    memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( CountNbEnabled125kHzChannels( ChannelsMaskRemaining ) == 0 )
-    { // Restore default channels
-        memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParams.ChannelsMask, 8 );
-    }
-    if( ( LoRaMacParams.ChannelsDatarate >= DR_4 ) && ( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 ) )
-    { // Make sure, that the channels are activated
-        ChannelsMaskRemaining[4] = LoRaMacParams.ChannelsMask[4];
-    }
-#elif defined( USE_BAND_470 )
-    if( ( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 ) &&
-        ( CountBits( LoRaMacParams.ChannelsMask[1], 16 ) == 0 ) &&
-        ( CountBits( LoRaMacParams.ChannelsMask[2], 16 ) == 0 ) &&
-        ( CountBits( LoRaMacParams.ChannelsMask[3], 16 ) == 0 ) &&
-        ( CountBits( LoRaMacParams.ChannelsMask[4], 16 ) == 0 ) &&
-        ( CountBits( LoRaMacParams.ChannelsMask[5], 16 ) == 0 ) )
-    {
-        memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-    }
-#else
-    if( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 )
-    {
-        // Re-enable default channels, if no channel is enabled
-        LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-    }
-#endif
-
-    // Update Aggregated duty cycle
-    if( AggregatedTimeOff <= TimerGetElapsedTime( AggregatedLastTxDoneTime ) )
+    if( rxContinuous == false )
     {
-        AggregatedTimeOff = 0;
-
-        // Update bands Time OFF
-        for( uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++ )
-        {
-            if( ( IsLoRaMacNetworkJoined == false ) || ( DutyCycleOn == true ) )
-            {
-                if( Bands[i].TimeOff <= TimerGetElapsedTime( Bands[i].LastTxDoneTime ) )
-                {
-                    Bands[i].TimeOff = 0;
-                }
-                if( Bands[i].TimeOff != 0 )
-                {
-                    nextTxDelay = MIN( Bands[i].TimeOff - TimerGetElapsedTime( Bands[i].LastTxDoneTime ), nextTxDelay );
-                }
-            }
-            else
-            {
-                if( DutyCycleOn == false )
-                {
-                    Bands[i].TimeOff = 0;
-                }
-            }
-        }
-
-        // Search how many channels are enabled
-        for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
-        {
-            for( uint8_t j = 0; j < 16; j++ )
-            {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                if( ( ChannelsMaskRemaining[k] & ( 1 << j ) ) != 0 )
-#else
-                if( ( LoRaMacParams.ChannelsMask[k] & ( 1 << j ) ) != 0 )
-#endif
-                {
-                    if( Channels[i + j].Frequency == 0 )
-                    { // 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 <= LoRaMacParams.ChannelsDatarate ) &&
-                          ( LoRaMacParams.ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
-                    { // Check if the current channel selection supports the given datarate
-                        continue;
-                    }
-                    if( Bands[Channels[i + j].Band].TimeOff > 0 )
-                    { // Check if the band is available for transmission
-                        delayTx++;
-                        continue;
-                    }
-                    enabledChannels[nbEnabledChannels++] = i + j;
-                }
-            }
-        }
+        Radio.Rx( maxRxWindow );
     }
     else
     {
-        delayTx++;
-        nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime( AggregatedLastTxDoneTime );
-    }
-
-    if( nbEnabledChannels > 0 )
-    {
-        Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-        if( Channel < ( LORA_MAX_NB_CHANNELS - 8 ) )
-        {
-            DisableChannelInMask( Channel, ChannelsMaskRemaining );
-        }
-#endif
-        *time = 0;
-        return true;
-    }
-    else
-    {
-        if( delayTx > 0 )
-        {
-            // Delay transmission due to AggregatedTimeOff or to a band time off
-            *time = nextTxDelay;
-            return true;
-        }
-        // Datarate not supported by any channel
-        *time = 0;
-        return false;
+        Radio.Rx( 0 ); // Continuous mode
     }
 }
 
-static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
+static LoRaMacStatus_t SwitchClass( DeviceClass_t deviceClass )
 {
-    uint8_t downlinkDatarate = Datarates[datarate];
-    RadioModems_t modem;
-
-    if( Radio.GetStatus( ) == RF_IDLE )
+    LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
+
+    switch( LoRaMacDeviceClass )
     {
-        Radio.SetChannel( freq );
-
-        // Store downlink datarate
-        McpsIndication.RxDatarate = ( uint8_t ) datarate;
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-        if( datarate == DR_7 )
+        case CLASS_A:
         {
-            modem = MODEM_FSK;
-            Radio.SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, timeout, false, 0, true, 0, 0, false, rxContinuous );
-        }
-        else
-        {
-            modem = MODEM_LORA;
-            Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
-        }
-#elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-        modem = MODEM_LORA;
-        Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
-#endif
-
-        if( RepeaterSupport == true )
-        {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+            if( deviceClass == CLASS_B )
+            {
+                status = LoRaMacClassBSwitchClass( deviceClass );
+                if( status == LORAMAC_STATUS_OK )
+                {
+                    LoRaMacDeviceClass = deviceClass;
+                }
+            }
+
+            if( deviceClass == CLASS_C )
+            {
+                LoRaMacDeviceClass = deviceClass;
+
+                // Set the NodeAckRequested indicator to default
+                NodeAckRequested = false;
+                OnRxWindow2TimerEvent( );
+
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
         }
-        else
+        case CLASS_B:
         {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+            status = LoRaMacClassBSwitchClass( deviceClass );
+            if( status == LORAMAC_STATUS_OK )
+            {
+                LoRaMacDeviceClass = deviceClass;
+            }
+            break;
         }
-
-        if( rxContinuous == false )
+        case CLASS_C:
         {
-            Radio.Rx( LoRaMacParams.MaxRxWindow );
+            if( deviceClass == CLASS_A )
+            {
+                LoRaMacDeviceClass = deviceClass;
+
+                // Set the radio into sleep to setup a defined state
+                Radio.Sleep( );
+
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
         }
-        else
-        {
-            Radio.Rx( 0 ); // Continuous mode
-        }
-        return true;
     }
-    return false;
-}
-
-static bool Rx2FreqInRange( uint32_t freq )
-{
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( Radio.CheckRfFrequency( freq ) == true )
-#elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( ( Radio.CheckRfFrequency( freq ) == true ) &&
-        ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) &&
-        ( freq <= LORAMAC_LAST_RX1_CHANNEL ) &&
-        ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) )
-#endif
-    {
-        return true;
-    }
-    return false;
+
+    return status;
 }
 
 static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     uint16_t maxN = 0;
     uint16_t payloadSize = 0;
 
+    // Setup PHY request
+    getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+    getPhy.Datarate = datarate;
+    getPhy.Attribute = PHY_MAX_PAYLOAD;
+
     // Get the maximum payload length
-    if( RepeaterSupport == true )
+    if( LoRaMacParams.RepeaterSupport == true )
     {
-        maxN = MaxPayloadOfDatarateRepeater[datarate];
+        getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
     }
-    else
-    {
-        maxN = MaxPayloadOfDatarate[datarate];
-    }
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    maxN = phyParam.Value;
 
     // Calculate the resulting payload size
     payloadSize = ( lenN + fOptsLen );
@@ -2122,258 +1753,6 @@
     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 )
-{
-    uint8_t nb125kHzChannels = 0;
-
-    for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ )
-    {
-        nb125kHzChannels += CountBits( channelsMask[k], 16 );
-    }
-
-    return nb125kHzChannels;
-}
-
-#if defined( USE_BAND_915_HYBRID )
-static void ReenableChannels( uint16_t mask, uint16_t* channelsMask )
-{
-    uint16_t blockMask = mask;
-
-    for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 )
-    {
-        channelsMask[i] = 0;
-        if( ( blockMask & ( 1 << j ) ) != 0 )
-        {
-            channelsMask[i] |= 0x00FF;
-        }
-        if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 )
-        {
-            channelsMask[i] |= 0xFF00;
-        }
-    }
-    channelsMask[4] = blockMask;
-    channelsMask[5] = 0x0000;
-}
-
-static bool ValidateChannelMask( uint16_t* channelsMask )
-{
-    bool chanMaskState = false;
-    uint16_t block1 = 0;
-    uint16_t block2 = 0;
-    uint8_t index = 0;
-
-    for( uint8_t i = 0; i < 4; i++ )
-    {
-        block1 = channelsMask[i] & 0x00FF;
-        block2 = channelsMask[i] & 0xFF00;
-
-        if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) )
-        {
-            channelsMask[i] &= block1;
-            channelsMask[4] = 1 << ( i * 2 );
-            chanMaskState = true;
-            index = i;
-        }
-        else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) )
-        {
-            channelsMask[i] &= block2;
-            channelsMask[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 )
-            {
-                channelsMask[i] = 0;
-            }
-        }
-    }
-    return chanMaskState;
-}
-#endif
-#endif
-
-static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask )
-{
-    if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
-    {
-        return false;
-    }
-    for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
-    {
-        for( uint8_t j = 0; j < 16; j++ )
-        {
-            if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) )
-            {// Check datarate validity for enabled channels
-                if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true )
-                {
-                    // At least 1 channel has been found we can return OK.
-                    return true;
-                }
-            }
-        }
-    }
-    return false;
-}
-
-static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower )
-{
-    int8_t resultTxPower = txPower;
-
-    // Limit tx power to the band max
-    resultTxPower =  MAX( txPower, maxBandTxPower );
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( ( LoRaMacParams.ChannelsDatarate == DR_4 ) ||
-        ( ( LoRaMacParams.ChannelsDatarate >= DR_8 ) && ( LoRaMacParams.ChannelsDatarate <= DR_13 ) ) )
-    {// Limit tx power to max 26dBm
-        resultTxPower =  MAX( txPower, TX_POWER_26_DBM );
-    }
-    else
-    {
-        if( CountNbEnabled125kHzChannels( LoRaMacParams.ChannelsMask ) < 50 )
-        {// Limit tx power to max 21dBm
-            resultTxPower = MAX( txPower, TX_POWER_20_DBM );
-        }
-    }
-#endif
-    return resultTxPower;
-}
-
-static bool ValueInRange( int8_t value, int8_t min, int8_t max )
-{
-    if( ( value >= min ) && ( value <= max ) )
-    {
-        return true;
-    }
-    return false;
-}
-
-static bool DisableChannelInMask( uint8_t id, uint16_t* mask )
-{
-    uint8_t index = 0;
-    index = id / 16;
-
-    if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
-    {
-        return false;
-    }
-
-    // Deactivate channel
-    mask[index] &= ~( 1 << ( id % 16 ) );
-
-    return true;
-}
-
-static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut )
-{
-    bool adrAckReq = false;
-    int8_t datarate = LoRaMacParams.ChannelsDatarate;
-
-    if( adrEnabled == true )
-    {
-        if( datarate == LORAMAC_TX_MIN_DATARATE )
-        {
-            AdrAckCounter = 0;
-            adrAckReq = false;
-        }
-        else
-        {
-            if( AdrAckCounter >= ADR_ACK_LIMIT )
-            {
-                adrAckReq = true;
-                LoRaMacParams.ChannelsTxPower = LORAMAC_MAX_TX_POWER;
-            }
-            else
-            {
-                adrAckReq = false;
-            }
-            if( AdrAckCounter >= ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
-            {
-                if( ( AdrAckCounter % ADR_ACK_DELAY ) == 1 )
-                {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                    if( datarate > LORAMAC_TX_MIN_DATARATE )
-                    {
-                        datarate--;
-                    }
-                    if( datarate == LORAMAC_TX_MIN_DATARATE )
-                    {
-                        if( updateChannelMask == true )
-                        {
-                            // Re-enable default channels LC1, LC2, LC3
-                            LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-                        }
-                    }
-#elif defined( USE_BAND_470 )
-                    if( datarate > LORAMAC_TX_MIN_DATARATE )
-                    {
-                        datarate--;
-                    }
-                    if( datarate == LORAMAC_TX_MIN_DATARATE )
-                    {
-                        if( updateChannelMask == true )
-                        {
-                            // Re-enable default channels
-                            memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-                        }
-                    }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                    if( ( datarate > LORAMAC_TX_MIN_DATARATE ) && ( datarate == DR_8 ) )
-                    {
-                        datarate = DR_4;
-                    }
-                    else if( datarate > LORAMAC_TX_MIN_DATARATE )
-                    {
-                        datarate--;
-                    }
-                    if( datarate == LORAMAC_TX_MIN_DATARATE )
-                    {
-                        if( updateChannelMask == true )
-                        {
-#if defined( USE_BAND_915 )
-                            // Re-enable default channels
-                            memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#else // defined( USE_BAND_915_HYBRID )
-                            // Re-enable default channels
-                            ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask );
-#endif
-                        }
-                    }
-#else
-#error "Please define a frequency band in the compiler options."
-#endif
-                }
-            }
-        }
-    }
-
-    *datarateOut = datarate;
-
-    return adrAckReq;
-}
-
 static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
@@ -2444,6 +1823,57 @@
                 status = LORAMAC_STATUS_OK;
             }
             break;
+        case MOTE_MAC_TX_PARAM_SETUP_ANS:
+            if( MacCommandsBufferIndex < bufLen )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // No payload for this answer
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
+        case MOTE_MAC_DL_CHANNEL_ANS:
+            if( MacCommandsBufferIndex < bufLen )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // Status: Uplink frequency exists, Channel frequency OK
+                MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
+        case MOTE_MAC_PING_SLOT_INFO_REQ:
+            if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 1 ) )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // Status: Periodicity and Datarate
+                MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
+        case MOTE_MAC_PING_SLOT_FREQ_ANS:
+            if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // Status: Datarate range OK, Channel frequency OK
+                MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
+        case MOTE_MAC_BEACON_TIMING_REQ:
+            if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // No payload for this answer
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
+        case MOTE_MAC_BEACON_FREQ_ANS:
+            if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+            {
+                MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+                // No payload for this answer
+                status = LORAMAC_STATUS_OK;
+            }
+            break;
         default:
             return LORAMAC_STATUS_SERVICE_UNKNOWN;
     }
@@ -2469,14 +1899,15 @@
         switch( cmdBufIn[i] )
         {
             // STICKY
+            case MOTE_MAC_DL_CHANNEL_ANS:
             case MOTE_MAC_RX_PARAM_SETUP_ANS:
-            {
+            { // 1 byte payload
                 cmdBufOut[cmdCount++] = cmdBufIn[i++];
                 cmdBufOut[cmdCount++] = cmdBufIn[i];
                 break;
             }
             case MOTE_MAC_RX_TIMING_SETUP_ANS:
-            {
+            { // 0 byte payload
                 cmdBufOut[cmdCount++] = cmdBufIn[i];
                 break;
             }
@@ -2492,6 +1923,7 @@
                 i++;
                 break;
             }
+            case MOTE_MAC_TX_PARAM_SETUP_ANS:
             case MOTE_MAC_DUTY_CYCLE_ANS:
             case MOTE_MAC_LINK_CHECK_REQ:
             { // 0 byte payload
@@ -2507,198 +1939,58 @@
 
 static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
 {
+    uint8_t status = 0;
+    uint8_t index = 0;
+
     while( macIndex < commandsSize )
     {
         // Decode Frame MAC commands
         switch( payload[macIndex++] )
         {
             case SRV_MAC_LINK_CHECK_ANS:
-                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-                MlmeConfirm.DemodMargin = payload[macIndex++];
-                MlmeConfirm.NbGateways = payload[macIndex++];
+                index = GetMlmeConfirmIndex( MlmeConfirmQueue, MLME_LINK_CHECK );
+                if( index < LORA_MAC_MLME_CONFIRM_QUEUE_LEN )
+                {
+                    MlmeConfirmQueue[index].Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                    MlmeConfirm.DemodMargin = payload[macIndex++];
+                    MlmeConfirm.NbGateways = payload[macIndex++];
+                }
                 break;
             case SRV_MAC_LINK_ADR_REQ:
                 {
-                    uint8_t i;
-                    uint8_t status = 0x07;
-                    uint16_t chMask;
-                    int8_t txPower = 0;
-                    int8_t datarate = 0;
-                    uint8_t nbRep = 0;
-                    uint8_t chMaskCntl = 0;
-                    uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
-
-                    // Initialize local copy of the channels mask array
-                    for( i = 0; i < 6; i++ )
-                    {
-                        channelsMask[i] = LoRaMacParams.ChannelsMask[i];
-                    }
-                    datarate = payload[macIndex++];
-                    txPower = datarate & 0x0F;
-                    datarate = ( datarate >> 4 ) & 0x0F;
-
-                    if( ( AdrCtrlOn == false ) &&
-                        ( ( LoRaMacParams.ChannelsDatarate != datarate ) || ( LoRaMacParams.ChannelsTxPower != txPower ) ) )
-                    { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
-                        // Answer the server with fail status
-                        // Power ACK     = 0
-                        // Data rate ACK = 0
-                        // Channel mask  = 0
-                        AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
-                        macIndex += 3;  // Skip over the remaining bytes of the request
-                        break;
-                    }
-                    chMask = ( uint16_t )payload[macIndex++];
-                    chMask |= ( uint16_t )payload[macIndex++] << 8;
-
-                    nbRep = payload[macIndex++];
-                    chMaskCntl = ( nbRep >> 4 ) & 0x07;
-                    nbRep &= 0x0F;
-                    if( nbRep == 0 )
-                    {
-                        nbRep = 1;
-                    }
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                    if( ( chMaskCntl == 0 ) && ( chMask == 0 ) )
-                    {
-                        status &= 0xFE; // Channel mask KO
-                    }
-                    else if( ( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 )) ||
-                             ( chMaskCntl >= 7 ) )
-                    {
-                        // RFU
-                        status &= 0xFE; // Channel mask KO
-                    }
-                    else
-                    {
-                        for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
-                        {
-                            if( chMaskCntl == 6 )
-                            {
-                                if( Channels[i].Frequency != 0 )
-                                {
-                                    chMask |= 1 << i;
-                                }
-                            }
-                            else
-                            {
-                                if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
-                                    ( Channels[i].Frequency == 0 ) )
-                                {// Trying to enable an undefined channel
-                                    status &= 0xFE; // Channel mask KO
-                                }
-                            }
-                        }
-                        channelsMask[0] = chMask;
-                    }
-#elif defined( USE_BAND_470 )
-                    if( chMaskCntl == 6 )
-                    {
-                        // Enable all 125 kHz channels
-                        for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
-                        {
-                            for( uint8_t j = 0; j < 16; j++ )
-                            {
-                                if( Channels[i + j].Frequency != 0 )
-                                {
-                                    channelsMask[k] |= 1 << j;
-                                }
-                            }
-                        }
-                    }
-                    else if( chMaskCntl == 7 )
-                    {
-                        status &= 0xFE; // Channel mask KO
-                    }
-                    else
-                    {
-                        for( uint8_t i = 0; i < 16; i++ )
-                        {
-                            if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
-                                ( Channels[chMaskCntl * 16 + i].Frequency == 0 ) )
-                            {// Trying to enable an undefined channel
-                                status &= 0xFE; // Channel mask KO
-                            }
-                        }
-                        channelsMask[chMaskCntl] = chMask;
-                    }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                    if( chMaskCntl == 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] = chMask;
-                    }
-                    else if( chMaskCntl == 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] = chMask;
-                    }
-                    else if( chMaskCntl == 5 )
-                    {
-                        // RFU
-                        status &= 0xFE; // Channel mask KO
-                    }
-                    else
-                    {
-                        channelsMask[chMaskCntl] = chMask;
-
-                        // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
-                        if( ( datarate < DR_4 ) && ( CountNbEnabled125kHzChannels( channelsMask ) < 2 ) )
-                        {
-                            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( ValidateDatarate( datarate, channelsMask ) == false )
-                    {
-                        status &= 0xFD; // Datarate KO
-                    }
-
-                    //
-                    // Remark MaxTxPower = 0 and MinTxPower = 5
-                    //
-                    if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
-                    {
-                        status &= 0xFB; // TxPower KO
-                    }
+                    LinkAdrReqParams_t linkAdrReq;
+                    int8_t linkAdrDatarate = DR_0;
+                    int8_t linkAdrTxPower = TX_POWER_0;
+                    uint8_t linkAdrNbRep = 0;
+                    uint8_t linkAdrNbBytesParsed = 0;
+
+                    // Fill parameter structure
+                    linkAdrReq.Payload = &payload[macIndex - 1];
+                    linkAdrReq.PayloadSize = commandsSize - ( macIndex - 1 );
+                    linkAdrReq.AdrEnabled = AdrCtrlOn;
+                    linkAdrReq.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+                    linkAdrReq.CurrentDatarate = LoRaMacParams.ChannelsDatarate;
+                    linkAdrReq.CurrentTxPower = LoRaMacParams.ChannelsTxPower;
+                    linkAdrReq.CurrentNbRep = LoRaMacParams.ChannelsNbRep;
+
+                    // Process the ADR requests
+                    status = RegionLinkAdrReq( LoRaMacRegion, &linkAdrReq, &linkAdrDatarate,
+                                               &linkAdrTxPower, &linkAdrNbRep, &linkAdrNbBytesParsed );
+
                     if( ( status & 0x07 ) == 0x07 )
                     {
-                        LoRaMacParams.ChannelsDatarate = datarate;
-                        LoRaMacParams.ChannelsTxPower = txPower;
-
-                        memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )channelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-
-                        LoRaMacParams.ChannelsNbRep = nbRep;
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                        // Reset ChannelsMaskRemaining to the new ChannelsMask
-                        ChannelsMaskRemaining[0] &= channelsMask[0];
-                        ChannelsMaskRemaining[1] &= channelsMask[1];
-                        ChannelsMaskRemaining[2] &= channelsMask[2];
-                        ChannelsMaskRemaining[3] &= channelsMask[3];
-                        ChannelsMaskRemaining[4] = channelsMask[4];
-                        ChannelsMaskRemaining[5] = channelsMask[5];
-#endif
+                        LoRaMacParams.ChannelsDatarate = linkAdrDatarate;
+                        LoRaMacParams.ChannelsTxPower = linkAdrTxPower;
+                        LoRaMacParams.ChannelsNbRep = linkAdrNbRep;
                     }
-                    AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
+
+                    // Add the answers to the buffer
+                    for( uint8_t i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++ )
+                    {
+                        AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
+                    }
+                    // Update MAC index
+                    macIndex += linkAdrNbBytesParsed - 1;
                 }
                 break;
             case SRV_MAC_DUTY_CYCLE_REQ:
@@ -2708,46 +2000,26 @@
                 break;
             case SRV_MAC_RX_PARAM_SETUP_REQ:
                 {
-                    uint8_t status = 0x07;
-                    int8_t datarate = 0;
-                    int8_t drOffset = 0;
-                    uint32_t freq = 0;
-
-                    drOffset = ( payload[macIndex] >> 4 ) & 0x07;
-                    datarate = payload[macIndex] & 0x0F;
+                    RxParamSetupReqParams_t rxParamSetupReq;
+                    status = 0x07;
+
+                    rxParamSetupReq.DrOffset = ( payload[macIndex] >> 4 ) & 0x07;
+                    rxParamSetupReq.Datarate = payload[macIndex] & 0x0F;
                     macIndex++;
 
-                    freq =  ( uint32_t )payload[macIndex++];
-                    freq |= ( uint32_t )payload[macIndex++] << 8;
-                    freq |= ( uint32_t )payload[macIndex++] << 16;
-                    freq *= 100;
-
-                    if( Rx2FreqInRange( freq ) == false )
-                    {
-                        status &= 0xFE; // Channel frequency KO
-                    }
-
-                    if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false )
-                    {
-                        status &= 0xFD; // Datarate KO
-                    }
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-                    if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) ||
-                        ( datarate > DR_13 ) )
-                    {
-                        status &= 0xFD; // Datarate KO
-                    }
-#endif
-                    if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false )
-                    {
-                        status &= 0xFB; // Rx1DrOffset range KO
-                    }
+                    rxParamSetupReq.Frequency =  ( uint32_t )payload[macIndex++];
+                    rxParamSetupReq.Frequency |= ( uint32_t )payload[macIndex++] << 8;
+                    rxParamSetupReq.Frequency |= ( uint32_t )payload[macIndex++] << 16;
+                    rxParamSetupReq.Frequency *= 100;
+
+                    // Perform request on region
+                    status = RegionRxParamSetupReq( LoRaMacRegion, &rxParamSetupReq );
 
                     if( ( status & 0x07 ) == 0x07 )
                     {
-                        LoRaMacParams.Rx2Channel.Datarate = datarate;
-                        LoRaMacParams.Rx2Channel.Frequency = freq;
-                        LoRaMacParams.Rx1DrOffset = drOffset;
+                        LoRaMacParams.Rx2Channel.Datarate = rxParamSetupReq.Datarate;
+                        LoRaMacParams.Rx2Channel.Frequency = rxParamSetupReq.Frequency;
+                        LoRaMacParams.Rx1DrOffset = rxParamSetupReq.DrOffset;
                     }
                     AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
                 }
@@ -2764,69 +2036,22 @@
                 }
             case SRV_MAC_NEW_CHANNEL_REQ:
                 {
-                    uint8_t status = 0x03;
-
-#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                    status &= 0xFC; // Channel frequency and datarate KO
-                    macIndex += 5;
-#else
-                    int8_t channelIndex = 0;
+                    NewChannelReqParams_t newChannelReq;
                     ChannelParams_t chParam;
-
-                    channelIndex = payload[macIndex++];
+                    status = 0x03;
+
+                    newChannelReq.ChannelId = payload[macIndex++];
+                    newChannelReq.NewChannel = &chParam;
+
                     chParam.Frequency = ( uint32_t )payload[macIndex++];
                     chParam.Frequency |= ( uint32_t )payload[macIndex++] << 8;
                     chParam.Frequency |= ( uint32_t )payload[macIndex++] << 16;
                     chParam.Frequency *= 100;
+                    chParam.Rx1Frequency = 0;
                     chParam.DrRange.Value = payload[macIndex++];
 
-                    LoRaMacState |= LORAMAC_TX_CONFIG;
-                    if( chParam.Frequency == 0 )
-                    {
-                        if( channelIndex < 3 )
-                        {
-                            status &= 0xFC;
-                        }
-                        else
-                        {
-                            if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK )
-                            {
-                                status &= 0xFC;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        switch( LoRaMacChannelAdd( channelIndex, chParam ) )
-                        {
-                            case LORAMAC_STATUS_OK:
-                            {
-                                break;
-                            }
-                            case LORAMAC_STATUS_FREQUENCY_INVALID:
-                            {
-                                status &= 0xFE;
-                                break;
-                            }
-                            case LORAMAC_STATUS_DATARATE_INVALID:
-                            {
-                                status &= 0xFD;
-                                break;
-                            }
-                            case LORAMAC_STATUS_FREQ_AND_DR_INVALID:
-                            {
-                                status &= 0xFC;
-                                break;
-                            }
-                            default:
-                            {
-                                status &= 0xFC;
-                                break;
-                            }
-                        }
-                    }
-                    LoRaMacState &= ~LORAMAC_TX_CONFIG;
-#endif
+                    status = RegionNewChannelReq( LoRaMacRegion, &newChannelReq );
+
                     AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
                 }
                 break;
@@ -2838,11 +2063,109 @@
                     {
                         delay++;
                     }
-                    LoRaMacParams.ReceiveDelay1 = delay * 1e3;
-                    LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3;
+                    LoRaMacParams.ReceiveDelay1 = delay * 1000;
+                    LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1000;
                     AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
                 }
                 break;
+            case SRV_MAC_TX_PARAM_SETUP_REQ:
+                {
+                    TxParamSetupReqParams_t txParamSetupReq;
+                    uint8_t eirpDwellTime = payload[macIndex++];
+
+                    txParamSetupReq.UplinkDwellTime = 0;
+                    txParamSetupReq.DownlinkDwellTime = 0;
+
+                    if( ( eirpDwellTime & 0x20 ) == 0x20 )
+                    {
+                        txParamSetupReq.DownlinkDwellTime = 1;
+                    }
+                    if( ( eirpDwellTime & 0x10 ) == 0x10 )
+                    {
+                        txParamSetupReq.UplinkDwellTime = 1;
+                    }
+                    txParamSetupReq.MaxEirp = eirpDwellTime & 0x0F;
+
+                    // Check the status for correctness
+                    if( RegionTxParamSetupReq( LoRaMacRegion, &txParamSetupReq ) != -1 )
+                    {
+                        // Accept command
+                        LoRaMacParams.UplinkDwellTime = txParamSetupReq.UplinkDwellTime;
+                        LoRaMacParams.DownlinkDwellTime = txParamSetupReq.DownlinkDwellTime;
+                        LoRaMacParams.MaxEirp = LoRaMacMaxEirpTable[txParamSetupReq.MaxEirp];
+                        // Add command response
+                        AddMacCommand( MOTE_MAC_TX_PARAM_SETUP_ANS, 0, 0 );
+                    }
+                }
+                break;
+            case SRV_MAC_DL_CHANNEL_REQ:
+                {
+                    DlChannelReqParams_t dlChannelReq;
+                    status = 0x03;
+
+                    dlChannelReq.ChannelId = payload[macIndex++];
+                    dlChannelReq.Rx1Frequency = ( uint32_t )payload[macIndex++];
+                    dlChannelReq.Rx1Frequency |= ( uint32_t )payload[macIndex++] << 8;
+                    dlChannelReq.Rx1Frequency |= ( uint32_t )payload[macIndex++] << 16;
+                    dlChannelReq.Rx1Frequency *= 100;
+
+                    status = RegionDlChannelReq( LoRaMacRegion, &dlChannelReq );
+
+                    AddMacCommand( MOTE_MAC_DL_CHANNEL_ANS, status, 0 );
+                }
+                break;
+            case SRV_MAC_PING_SLOT_INFO_ANS:
+                {
+                    LoRaMacClassBPingSlotInfoAns( );
+                }
+                break;
+            case SRV_MAC_PING_SLOT_CHANNEL_REQ:
+                {
+                    uint8_t status = 0x03;
+                    uint32_t frequency = 0;
+                    uint8_t datarate;
+
+                    frequency = ( uint32_t )payload[macIndex++];
+                    frequency |= ( uint32_t )payload[macIndex++] << 8;
+                    frequency |= ( uint32_t )payload[macIndex++] << 16;
+                    frequency *= 100;
+                    datarate = payload[macIndex++] & 0x0F;
+
+                    status = LoRaMacClassBPingSlotChannelReq( datarate, frequency );
+                    AddMacCommand( MOTE_MAC_PING_SLOT_FREQ_ANS, status, 0 );
+                }
+                break;
+            case SRV_MAC_BEACON_TIMING_ANS:
+                {
+                    uint16_t beaconTimingDelay = 0;
+                    uint8_t beaconTimingChannel = 0;
+
+                    beaconTimingDelay = ( uint16_t )payload[macIndex++];
+                    beaconTimingDelay |= ( uint16_t )payload[macIndex++] << 8;
+                    beaconTimingChannel = payload[macIndex++];
+
+                    LoRaMacClassBBeaconTimingAns( beaconTimingDelay, beaconTimingChannel );
+                }
+                break;
+            case SRV_MAC_BEACON_FREQ_REQ:
+                {
+                    uint32_t frequency = 0;
+
+                    frequency = ( uint32_t )payload[macIndex++];
+                    frequency |= ( uint32_t )payload[macIndex++] << 8;
+                    frequency |= ( uint32_t )payload[macIndex++] << 16;
+                    frequency *= 100;
+
+                    if( LoRaMacClassBBeaconFreqReq( frequency ) == true )
+                    {
+                        AddMacCommand( MOTE_MAC_BEACON_FREQ_ANS, 1, 0 );
+                    }
+                    else
+                    {
+                        AddMacCommand( MOTE_MAC_BEACON_FREQ_ANS, 0, 0 );
+                    }
+                }
+                break;
             default:
                 // Unknown command. ABORT MAC commands processing
                 return;
@@ -2857,7 +2180,14 @@
 
     fCtrl.Value = 0;
     fCtrl.Bits.FOptsLen      = 0;
-    fCtrl.Bits.FPending      = 0;
+    if( LoRaMacDeviceClass == CLASS_B )
+    {
+        fCtrl.Bits.FPending      = 1;
+    }
+    else
+    {
+        fCtrl.Bits.FPending      = 0;
+    }
     fCtrl.Bits.Ack           = false;
     fCtrl.Bits.AdrAckReq     = false;
     fCtrl.Bits.Adr           = AdrCtrlOn;
@@ -2884,6 +2214,9 @@
 static LoRaMacStatus_t ScheduleTx( void )
 {
     TimerTime_t dutyCycleTimeOff = 0;
+    TimerTime_t mutexTimeLock = 0;
+    TimerTime_t timeOff = 0;
+    NextChanParams_t nextChan;
 
     // Check if the device is off
     if( MaxDCycle == 255 )
@@ -2895,31 +2228,41 @@
         AggregatedTimeOff = 0;
     }
 
+    // Update Backoff
+    CalculateBackOff( LastTxChannel );
+
+    nextChan.AggrTimeOff = AggregatedTimeOff;
+    nextChan.Datarate = LoRaMacParams.ChannelsDatarate;
+    nextChan.DutyCycleEnabled = DutyCycleOn;
+    nextChan.Joined = IsLoRaMacNetworkJoined;
+    nextChan.LastAggrTx = AggregatedLastTxDoneTime;
+
     // Select channel
-    while( SetNextChannel( &dutyCycleTimeOff ) == false )
+    while( RegionNextChannel( LoRaMacRegion, &nextChan, &Channel, &dutyCycleTimeOff, &AggregatedTimeOff ) == false )
     {
         // Set the default datarate
         LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-        // Re-enable default channels LC1, LC2, LC3
-        LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-#endif
+        // Update datarate in the function parameters
+        nextChan.Datarate = LoRaMacParams.ChannelsDatarate;
     }
 
     // Compute Rx1 windows parameters
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    RxWindowsParams[0] = ComputeRxWindowParameters( DatarateOffsets[LoRaMacParams.ChannelsDatarate][LoRaMacParams.Rx1DrOffset], LoRaMacParams.SystemMaxRxError );
-#else
-    RxWindowsParams[0] = ComputeRxWindowParameters( MAX( DR_0, LoRaMacParams.ChannelsDatarate - LoRaMacParams.Rx1DrOffset ), LoRaMacParams.SystemMaxRxError );
-#endif
+    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                     RegionApplyDrOffset( LoRaMacRegion, LoRaMacParams.DownlinkDwellTime, LoRaMacParams.ChannelsDatarate, LoRaMacParams.Rx1DrOffset ),
+                                     LoRaMacParams.MinRxSymbols,
+                                     LoRaMacParams.SystemMaxRxError,
+                                     &RxWindow1Config );
     // Compute Rx2 windows parameters
-    RxWindowsParams[1] = ComputeRxWindowParameters( LoRaMacParams.Rx2Channel.Datarate, LoRaMacParams.SystemMaxRxError );
+    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                     LoRaMacParams.Rx2Channel.Datarate,
+                                     LoRaMacParams.MinRxSymbols,
+                                     LoRaMacParams.SystemMaxRxError,
+                                     &RxWindow2Config );
 
     if( IsLoRaMacNetworkJoined == false )
     {
-        RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 + RxWindowsParams[0].RxOffset;
-        RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 + RxWindowsParams[1].RxOffset;
+        RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 + RxWindow1Config.WindowOffset;
+        RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 + RxWindow2Config.WindowOffset;
     }
     else
     {
@@ -2927,123 +2270,68 @@
         {
             return LORAMAC_STATUS_LENGTH_ERROR;
         }
-        RxWindow1Delay = LoRaMacParams.ReceiveDelay1 + RxWindowsParams[0].RxOffset;
-        RxWindow2Delay = LoRaMacParams.ReceiveDelay2 + RxWindowsParams[1].RxOffset;
+        RxWindow1Delay = LoRaMacParams.ReceiveDelay1 + RxWindow1Config.WindowOffset;
+        RxWindow2Delay = LoRaMacParams.ReceiveDelay2 + RxWindow2Config.WindowOffset;
     }
 
     // Schedule transmission of frame
     if( dutyCycleTimeOff == 0 )
     {
         // Try to send now
-        return SendFrameOnChannel( Channels[Channel] );
+        mutexTimeLock =  SendFrameOnChannel( Channel );
     }
-    else
+
+    timeOff = MAX( dutyCycleTimeOff, mutexTimeLock );
+
+    if( timeOff > 0 )
     {
         // Send later - prepare timer
         LoRaMacState |= LORAMAC_TX_DELAYED;
-        TimerSetValue( &TxDelayedTimer, dutyCycleTimeOff );
+        TimerSetValue( &TxDelayedTimer, timeOff );
         TimerStart( &TxDelayedTimer );
-
-        return LORAMAC_STATUS_OK;
     }
-}
-
-static uint16_t JoinDutyCycle( void )
-{
-    uint16_t dutyCycle = 0;
-    TimerTime_t timeElapsed = TimerGetElapsedTime( LoRaMacInitializationTime );
-
-    if( timeElapsed < 3600e3 )
-    {
-        dutyCycle = BACKOFF_DC_1_HOUR;
-    }
-    else if( timeElapsed < ( 3600e3 + 36000e3 ) )
-    {
-        dutyCycle = BACKOFF_DC_10_HOURS;
-    }
-    else
-    {
-        dutyCycle = BACKOFF_DC_24_HOURS;
-    }
-    return dutyCycle;
+    return LORAMAC_STATUS_OK;
 }
 
 static void CalculateBackOff( uint8_t channel )
 {
-    uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle;
-    uint16_t joinDutyCycle = 0;
-
-    // Reset time-off to initial value.
-    Bands[Channels[channel].Band].TimeOff = 0;
-
-    if( IsLoRaMacNetworkJoined == false )
-    {
-        // The node has not joined yet. Apply join duty cycle to all regions.
-        joinDutyCycle = JoinDutyCycle( );
-        dutyCycle = MAX( dutyCycle, joinDutyCycle );
-
-        // Update Band time-off.
-        Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir;
-    }
-    else
-    {
-        if( DutyCycleOn == true )
-        {
-            Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir;
-        }
-    }
-
-    // Update Aggregated Time OFF
+    CalcBackOffParams_t calcBackOff;
+
+    calcBackOff.Joined = IsLoRaMacNetworkJoined;
+    calcBackOff.DutyCycleEnabled = DutyCycleOn;
+    calcBackOff.Channel = channel;
+    calcBackOff.ElapsedTime = TimerGetElapsedTime( LoRaMacInitializationTime );
+    calcBackOff.TxTimeOnAir = TxTimeOnAir;
+    calcBackOff.LastTxIsJoinRequest = LastTxIsJoinRequest;
+
+    // Update regional back-off
+    RegionCalcBackOff( LoRaMacRegion, &calcBackOff );
+
+    // Update aggregated time-off
     AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
 }
 
-static int8_t AlternateDatarate( uint16_t nbTrials )
+static uint8_t GetMlmeConfirmIndex( MlmeConfirmQueue_t* queue, Mlme_t req )
 {
-    int8_t datarate = LORAMAC_TX_MIN_DATARATE;
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-#if defined( USE_BAND_915 )
-    // Re-enable 500 kHz default channels
-    LoRaMacParams.ChannelsMask[4] = 0x00FF;
-#else // defined( USE_BAND_915_HYBRID )
-    // Re-enable 500 kHz default channels
-    ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask );
-#endif
-
-    if( ( nbTrials & 0x01 ) == 0x01 )
-    {
-        datarate = DR_4;
-    }
-    else
-    {
-        datarate = DR_0;
-    }
-#else
-    if( ( nbTrials % 48 ) == 0 )
+    for( uint8_t i = 0; i < MlmeConfirmQueueCnt; i++ )
     {
-        datarate = DR_0;
-    }
-    else if( ( nbTrials % 32 ) == 0 )
-    {
-        datarate = DR_1;
+        if( queue->MlmeRequest == req )
+        {
+            return i;
+        }
+        queue++;
     }
-    else if( ( nbTrials % 24 ) == 0 )
-    {
-        datarate = DR_2;
-    }
-    else if( ( nbTrials % 16 ) == 0 )
+
+    // Out of band
+    return LORA_MAC_MLME_CONFIRM_QUEUE_LEN;
+}
+
+static void SetEveryMlmeConfirmStatus( MlmeConfirmQueue_t* queue, LoRaMacEventInfoStatus_t status )
+{
+    for( uint8_t i = 0; i < MlmeConfirmQueueCnt; i++ )
     {
-        datarate = DR_3;
-    }
-    else if( ( nbTrials % 8 ) == 0 )
-    {
-        datarate = DR_4;
+        queue[i].Status = status;
     }
-    else
-    {
-        datarate = DR_5;
-    }
-#endif
-    return datarate;
 }
 
 static void ResetMacParameters( void )
@@ -3071,16 +2359,12 @@
 
     LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
     LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
-
     LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset;
     LoRaMacParams.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel;
-
-    memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#endif
-
+    LoRaMacParams.UplinkDwellTime = LoRaMacParamsDefaults.UplinkDwellTime;
+    LoRaMacParams.DownlinkDwellTime = LoRaMacParamsDefaults.DownlinkDwellTime;
+    LoRaMacParams.MaxEirp = LoRaMacParamsDefaults.MaxEirp;
+    LoRaMacParams.AntennaGain = LoRaMacParamsDefaults.AntennaGain;
 
     NodeAckRequested = false;
     SrvAckRequested = false;
@@ -3095,11 +2379,13 @@
     }
 
     // Initialize channel index.
-    Channel = LORA_MAX_NB_CHANNELS;
+    Channel = 0;
+    LastTxChannel = Channel;
 }
 
 LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
 {
+    AdrNextParams_t adrNext;
     uint16_t i;
     uint8_t pktHeaderLen = 0;
     uint32_t mic = 0;
@@ -3151,8 +2437,17 @@
                 return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
             }
 
-            fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &LoRaMacParams.ChannelsDatarate );
-            
+            // Adr next request
+            adrNext.UpdateChanMask = true;
+            adrNext.AdrEnabled = fCtrl->Bits.Adr;
+            adrNext.AdrAckCounter = AdrAckCounter;
+            adrNext.Datarate = LoRaMacParams.ChannelsDatarate;
+            adrNext.TxPower = LoRaMacParams.ChannelsTxPower;
+            adrNext.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+            fCtrl->Bits.AdrAckReq = RegionAdrNext( LoRaMacRegion, &adrNext,
+                                                   &LoRaMacParams.ChannelsDatarate, &LoRaMacParams.ChannelsTxPower, &AdrAckCounter );
+
             if( SrvAckRequested == true )
             {
                 SrvAckRequested = false;
@@ -3175,21 +2470,30 @@
 
             if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
             {
-                if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
+                if( MacCommandsInNextTx == true )
                 {
-                    fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
-
-                    // Update FCtrl field with new value of OptionsLength
-                    LoRaMacBuffer[0x05] = fCtrl->Value;
-                    for( i = 0; i < MacCommandsBufferIndex; i++ )
+                    if( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH )
                     {
-                        LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
+                        fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
+
+                        // Update FCtrl field with new value of OptionsLength
+                        LoRaMacBuffer[0x05] = fCtrl->Value;
+                        for( i = 0; i < MacCommandsBufferIndex; i++ )
+                        {
+                            LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
+                        }
+                    }
+                    else
+                    {
+                        LoRaMacTxPayloadLen = MacCommandsBufferIndex;
+                        payload = MacCommandsBuffer;
+                        framePort = 0;
                     }
                 }
             }
             else
             {
-                if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
+                if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx == true ) )
                 {
                     LoRaMacTxPayloadLen = MacCommandsBufferIndex;
                     payload = MacCommandsBuffer;
@@ -3210,6 +2514,8 @@
 
                 if( framePort == 0 )
                 {
+                    // Reset buffer index as the mac commands are being sent on port 0
+                    MacCommandsBufferIndex = 0;
                     LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] );
                 }
                 else
@@ -3243,67 +2549,55 @@
     return LORAMAC_STATUS_OK;
 }
 
-LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel )
+TimerTime_t SendFrameOnChannel( uint8_t channel )
 {
-    int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate];
-    int8_t txPowerIndex = 0;
+    TxConfigParams_t txConfig;
     int8_t txPower = 0;
 
-    txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[channel.Band].TxMaxPower );
-    txPower = TxPowers[txPowerIndex];
-
-    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+    txConfig.Channel = channel;
+    txConfig.Datarate = LoRaMacParams.ChannelsDatarate;
+    txConfig.TxPower = LoRaMacParams.ChannelsTxPower;
+    txConfig.MaxEirp = LoRaMacParams.MaxEirp;
+    txConfig.AntennaGain = LoRaMacParams.AntennaGain;
+    txConfig.PktLen = LoRaMacBufferPktLen;
+
+    if( LoRaMacDeviceClass == CLASS_B )
+    {
+        if( LoRaMacClassBIsBeaconExpected( ) == true )
+        {
+            return LoRaMacClassBGetBeaconReservedTime( );
+        }
+        if( LoRaMacClassBIsPingExpected( ) == true )
+        {
+            return LoRaMacClassBGetPingSlotWinTime( );
+        }
+    }
+    RegionTxConfig( LoRaMacRegion, &txConfig, &txPower, &TxTimeOnAir );
+
+    SetEveryMlmeConfirmStatus( MlmeConfirmQueue, LORAMAC_EVENT_INFO_STATUS_ERROR );
     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
     McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate;
-    McpsConfirm.TxPower = txPowerIndex;
-    McpsConfirm.UpLinkFrequency = channel.Frequency;
-
-    Radio.SetChannel( channel.Frequency );
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( LoRaMacParams.ChannelsDatarate == DR_7 )
-    { // High Speed FSK channel
-        Radio.SetMaxPayloadLength( MODEM_FSK, LoRaMacBufferPktLen );
-        Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e3 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
-
-    }
-    else if( LoRaMacParams.ChannelsDatarate == DR_6 )
-    { // High speed LoRa channel
-        Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e3 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-    else
-    { // Normal LoRa channel
-        Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-    if( LoRaMacParams.ChannelsDatarate >= DR_4 )
-    { // High speed LoRa channel BW500 kHz
-        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e3 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-    else
-    { // Normal LoRa channel
-        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-#elif defined( USE_BAND_470 )
-    Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-    Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 );
-    TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
+    McpsConfirm.TxPower = txPower;
 
     // Store the time on air
     McpsConfirm.TxTimeOnAir = TxTimeOnAir;
     MlmeConfirm.TxTimeOnAir = TxTimeOnAir;
 
+    if( ( LoRaMacDeviceClass == CLASS_B ) || ( LoRaMacClassBIsBeaconModeActive( ) == true ) )
+    {
+        TimerTime_t collisionTime = LoRaMacClassBIsUplinkCollision( TxTimeOnAir );
+
+        if( collisionTime > 0 )
+        {
+            return collisionTime;
+        }
+    }
+
+    if( LoRaMacDeviceClass == CLASS_B )
+    {
+        LoRaMacClassBHaltBeaconing( );
+    }
+
     // Starts the MAC layer status check timer
     TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT );
     TimerStart( &MacStateCheckTimer );
@@ -3313,28 +2607,33 @@
         JoinRequestTrials++;
     }
 
+    LoRaMacState |= LORAMAC_TX_RUNNING;
+
     // Send now
     Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
 
     LoRaMacState |= LORAMAC_TX_RUNNING;
 
-    return LORAMAC_STATUS_OK;
+    return 0;
 }
 
 LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
 {
-    int8_t txPowerIndex = 0;
-    int8_t txPower = 0;
-
-    txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[Channels[Channel].Band].TxMaxPower );
-    txPower = TxPowers[txPowerIndex];
+    ContinuousWaveParams_t continuousWave;
+
+    continuousWave.Channel = Channel;
+    continuousWave.Datarate = LoRaMacParams.ChannelsDatarate;
+    continuousWave.TxPower = LoRaMacParams.ChannelsTxPower;
+    continuousWave.MaxEirp = LoRaMacParams.MaxEirp;
+    continuousWave.AntennaGain = LoRaMacParams.AntennaGain;
+    continuousWave.Timeout = timeout;
+
+    RegionSetContinuousWave( LoRaMacRegion, &continuousWave );
 
     // Starts the MAC layer status check timer
     TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT );
     TimerStart( &MacStateCheckTimer );
 
-    Radio.SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout );
-
     LoRaMacState |= LORAMAC_TX_RUNNING;
 
     return LORAMAC_STATUS_OK;
@@ -3353,8 +2652,13 @@
     return LORAMAC_STATUS_OK;
 }
 
-LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks )
+LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaMacRegion_t region )
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    LoRaMacClassBCallback_t classBCallbacks;
+    LoRaMacClassBParams_t classBParams;
+
     if( primitives == NULL )
     {
         return LORAMAC_STATUS_PARAMETER_INVALID;
@@ -3362,13 +2666,20 @@
 
     if( ( primitives->MacMcpsConfirm == NULL ) ||
         ( primitives->MacMcpsIndication == NULL ) ||
-        ( primitives->MacMlmeConfirm == NULL ) )
+        ( primitives->MacMlmeConfirm == NULL ) ||
+        ( primitives->MacMlmeIndication == NULL ) )
     {
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
+    // Verify if the region is supported
+    if( RegionIsActive( region ) == false )
+    {
+        return LORAMAC_STATUS_REGION_NOT_SUPPORTED;
+    }
 
     LoRaMacPrimitives = primitives;
     LoRaMacCallbacks = callbacks;
+    LoRaMacRegion = region;
 
     LoRaMacFlags.Value = 0;
 
@@ -3377,102 +2688,80 @@
 
     JoinRequestTrials = 0;
     MaxJoinRequestTrials = 1;
-    RepeaterSupport = false;
 
     // Reset duty cycle times
     AggregatedLastTxDoneTime = 0;
     AggregatedTimeOff = 0;
 
-    // Duty cycle
-#if defined( USE_BAND_433 )
-    DutyCycleOn = true;
-#elif defined( USE_BAND_470 )
-    DutyCycleOn = false;
-#elif defined( USE_BAND_780 )
-    DutyCycleOn = true;
-#elif defined( USE_BAND_868 )
-    DutyCycleOn = true;
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    DutyCycleOn = false;
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
     // Reset to defaults
-    LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
-    LoRaMacParamsDefaults.ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
-
+    getPhy.Attribute = PHY_DUTY_CYCLE;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    DutyCycleOn = ( bool ) phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_TX_POWER;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.ChannelsTxPower = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_TX_DR;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.ChannelsDatarate = phyParam.Value;
+
+    getPhy.Attribute = PHY_MAX_RX_WINDOW;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.MaxRxWindow = phyParam.Value;
+
+    getPhy.Attribute = PHY_RECEIVE_DELAY1;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.ReceiveDelay1 = phyParam.Value;
+
+    getPhy.Attribute = PHY_RECEIVE_DELAY2;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.ReceiveDelay2 = phyParam.Value;
+
+    getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY1;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.JoinAcceptDelay1 = phyParam.Value;
+
+    getPhy.Attribute = PHY_JOIN_ACCEPT_DELAY2;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.JoinAcceptDelay2 = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_DR1_OFFSET;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.Rx1DrOffset = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_RX2_FREQUENCY;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.Rx2Channel.Frequency = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_RX2_DR;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.Rx2Channel.Datarate = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_UPLINK_DWELL_TIME;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.UplinkDwellTime = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_DOWNLINK_DWELL_TIME;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.DownlinkDwellTime = phyParam.Value;
+
+    getPhy.Attribute = PHY_DEF_MAX_EIRP;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.MaxEirp = phyParam.fValue;
+
+    getPhy.Attribute = PHY_DEF_ANTENNA_GAIN;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    LoRaMacParamsDefaults.AntennaGain = phyParam.fValue;
+
+    RegionInitDefaults( LoRaMacRegion, INIT_TYPE_INIT );
+
+    // Init parameters which are not set in function ResetMacParameters
+    LoRaMacParams.RepeaterSupport = false;
+    LoRaMacParamsDefaults.ChannelsNbRep = 1;
     LoRaMacParamsDefaults.SystemMaxRxError = 10;
     LoRaMacParamsDefaults.MinRxSymbols = 6;
-    LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW;
-    LoRaMacParamsDefaults.ReceiveDelay1 = RECEIVE_DELAY1;
-    LoRaMacParamsDefaults.ReceiveDelay2 = RECEIVE_DELAY2;
-    LoRaMacParamsDefaults.JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
-    LoRaMacParamsDefaults.JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
-
-    LoRaMacParamsDefaults.ChannelsNbRep = 1;
-    LoRaMacParamsDefaults.Rx1DrOffset = 0;
-
-    LoRaMacParamsDefaults.Rx2Channel = ( Rx2ChannelParams_t )RX_WND_2_CHANNEL;
-
-    // Channel mask
-#if defined( USE_BAND_433 )
-    LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined ( USE_BAND_470 )
-    LoRaMacParamsDefaults.ChannelsMask[0] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[1] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[2] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[3] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[4] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[5] = 0xFFFF;
-#elif defined( USE_BAND_780 )
-    LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined( USE_BAND_868 )
-    LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined( USE_BAND_915 )
-    LoRaMacParamsDefaults.ChannelsMask[0] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[1] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[2] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[3] = 0xFFFF;
-    LoRaMacParamsDefaults.ChannelsMask[4] = 0x00FF;
-    LoRaMacParamsDefaults.ChannelsMask[5] = 0x0000;
-#elif defined( USE_BAND_915_HYBRID )
-    LoRaMacParamsDefaults.ChannelsMask[0] = 0x00FF;
-    LoRaMacParamsDefaults.ChannelsMask[1] = 0x0000;
-    LoRaMacParamsDefaults.ChannelsMask[2] = 0x0000;
-    LoRaMacParamsDefaults.ChannelsMask[3] = 0x0000;
-    LoRaMacParamsDefaults.ChannelsMask[4] = 0x0001;
-    LoRaMacParamsDefaults.ChannelsMask[5] = 0x0000;
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    // 125 kHz channels
-    for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ )
-    {
-        Channels[i].Frequency = 902.3e6 + i * 200e3;
-        Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
-        Channels[i].Band = 0;
-    }
-    // 500 kHz channels
-    for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ )
-    {
-        Channels[i].Frequency = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6;
-        Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
-        Channels[i].Band = 0;
-    }
-#elif defined( USE_BAND_470 )
-    // 125 kHz channels
-    for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
-    {
-        Channels[i].Frequency = 470.3e6 + i * 200e3;
-        Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
-        Channels[i].Band = 0;
-    }
-#endif
-
-    // Init parameters which are not set in function ResetMacParameters
+
     LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError;
     LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols;
     LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow;
@@ -3511,12 +2800,39 @@
     Radio.SetPublicNetwork( PublicNetwork );
     Radio.Sleep( );
 
+    // Initialize class b
+    // Apply callback
+    classBCallbacks.GetTemperatureLevel = NULL;
+    if( callbacks != NULL )
+    {
+        classBCallbacks.GetTemperatureLevel = callbacks->GetTemperatureLevel;
+    }
+    classBCallbacks.GetMlmeConfrimIndex = GetMlmeConfirmIndex;
+
+    // Must all be static. Don't use local references.
+    classBParams.MlmeIndication = &MlmeIndication;
+    classBParams.McpsIndication = &McpsIndication;
+    classBParams.MlmeConfirm = &MlmeConfirm;
+    classBParams.LoRaMacFlags = &LoRaMacFlags;
+    classBParams.LoRaMacDevAddr = &LoRaMacDevAddr;
+    classBParams.MlmeConfirmQueue = MlmeConfirmQueue;
+    classBParams.LoRaMacRegion = &LoRaMacRegion;
+    classBParams.MacStateCheckTimer = &MacStateCheckTimer;
+    classBParams.LoRaMacParams = &LoRaMacParams;
+    classBParams.MulticastChannels = MulticastChannels;
+
+    LoRaMacClassBInit( &classBParams, &classBCallbacks );
+
     return LORAMAC_STATUS_OK;
 }
 
 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
 {
+    AdrNextParams_t adrNext;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     int8_t datarate = LoRaMacParamsDefaults.ChannelsDatarate;
+    int8_t txPower = LoRaMacParamsDefaults.ChannelsTxPower;
     uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
 
     if( txInfo == NULL )
@@ -3524,42 +2840,59 @@
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
 
-    AdrNextDr( AdrCtrlOn, false, &datarate );
-
-    if( RepeaterSupport == true )
+    // Setup ADR request
+    adrNext.UpdateChanMask = false;
+    adrNext.AdrEnabled = AdrCtrlOn;
+    adrNext.AdrAckCounter = AdrAckCounter;
+    adrNext.Datarate = LoRaMacParams.ChannelsDatarate;
+    adrNext.TxPower = LoRaMacParams.ChannelsTxPower;
+    adrNext.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+    // We call the function for information purposes only. We don't want to
+    // apply the datarate, the tx power and the ADR ack counter.
+    RegionAdrNext( LoRaMacRegion, &adrNext, &datarate, &txPower, &AdrAckCounter );
+
+    // Setup PHY request
+    getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+    getPhy.Datarate = datarate;
+    getPhy.Attribute = PHY_MAX_PAYLOAD;
+
+    // Change request in case repeater is supported
+    if( LoRaMacParams.RepeaterSupport == true )
     {
-        txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate];
+        getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
     }
-    else
-    {
-        txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
-    }
-
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    txInfo->CurrentPayloadSize = phyParam.Value;
+
+    // Verify if the fOpts fit into the maximum payload
     if( txInfo->CurrentPayloadSize >= fOptLen )
     {
         txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
     }
     else
     {
-        return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
+        txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize;
+        // The fOpts don't fit into the maximum payload. Omit the MAC commands to
+        // ensure that another uplink is possible.
+        fOptLen = 0;
+        MacCommandsBufferIndex = 0;
+        MacCommandsBufferToRepeatIndex = 0;
     }
 
-    if( ValidatePayloadLength( size, datarate, 0 ) == false )
+    // Verify if the fOpts and the payload fit into the maximum payload
+    if( ValidatePayloadLength( size, datarate, fOptLen ) == false )
     {
         return LORAMAC_STATUS_LENGTH_ERROR;
     }
-
-    if( ValidatePayloadLength( size, datarate, fOptLen ) == false )
-    {
-        return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
-    }
-
     return LORAMAC_STATUS_OK;
 }
 
 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
 
     if( mibGet == NULL )
     {
@@ -3610,12 +2943,15 @@
         }
         case MIB_REPEATER_SUPPORT:
         {
-            mibGet->Param.EnableRepeaterSupport = RepeaterSupport;
+            mibGet->Param.EnableRepeaterSupport = LoRaMacParams.RepeaterSupport;
             break;
         }
         case MIB_CHANNELS:
         {
-            mibGet->Param.ChannelList = Channels;
+            getPhy.Attribute = PHY_CHANNELS;
+            phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+
+            mibGet->Param.ChannelList = phyParam.Channels;
             break;
         }
         case MIB_RX2_CHANNEL:
@@ -3630,12 +2966,18 @@
         }
         case MIB_CHANNELS_DEFAULT_MASK:
         {
-            mibGet->Param.ChannelsDefaultMask = LoRaMacParamsDefaults.ChannelsMask;
+            getPhy.Attribute = PHY_CHANNELS_DEFAULT_MASK;
+            phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+
+            mibGet->Param.ChannelsDefaultMask = phyParam.ChannelsMask;
             break;
         }
         case MIB_CHANNELS_MASK:
         {
-            mibGet->Param.ChannelsMask = LoRaMacParams.ChannelsMask;
+            getPhy.Attribute = PHY_CHANNELS_MASK;
+            phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+
+            mibGet->Param.ChannelsMask = phyParam.ChannelsMask;
             break;
         }
         case MIB_CHANNELS_NB_REP:
@@ -3713,17 +3055,32 @@
             mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols;
             break;
         }
-        default:
-            status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+        case MIB_ANTENNA_GAIN:
+        {
+            mibGet->Param.AntennaGain = LoRaMacParams.AntennaGain;
             break;
+        }
+        default:
+        {
+            if( LoRaMacDeviceClass == CLASS_B )
+            {
+                status = LoRaMacClassBMibGetRequestConfirm( mibGet );
+            }
+            else
+            {
+                status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+            }
+            break;
+        }
     }
-
     return status;
 }
 
 LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+    ChanMaskSetParams_t chanMaskSet;
+    VerifyParams_t verify;
 
     if( mibSet == NULL )
     {
@@ -3738,27 +3095,7 @@
     {
         case MIB_DEVICE_CLASS:
         {
-            LoRaMacDeviceClass = mibSet->Param.Class;
-            switch( LoRaMacDeviceClass )
-            {
-                case CLASS_A:
-                {
-                    // Set the radio into sleep to setup a defined state
-                    Radio.Sleep( );
-                    break;
-                }
-                case CLASS_B:
-                {
-                    break;
-                }
-                case CLASS_C:
-                {
-                    // Set the NodeAckRequested indicator to default
-                    NodeAckRequested = false;
-                    OnRxWindow2TimerEvent( );
-                    break;
-                }
-            }
+            status = SwitchClass( mibSet->Param.Class );
             break;
         }
         case MIB_NETWORK_JOINED:
@@ -3815,58 +3152,44 @@
         }
         case MIB_REPEATER_SUPPORT:
         {
-             RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
+             LoRaMacParams.RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
             break;
         }
         case MIB_RX2_CHANNEL:
         {
-            LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel;
-            break;
-        }
-        case MIB_RX2_DEFAULT_CHANNEL:
-        {
-            LoRaMacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel;
-            break;
-        }
-        case MIB_CHANNELS_DEFAULT_MASK:
-        {
-            if( mibSet->Param.ChannelsDefaultMask )
+            verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
+            verify.DatarateParams.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_RX_DR ) == true )
             {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                bool chanMaskState = true;
-
-#if defined( USE_BAND_915_HYBRID )
-                chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsDefaultMask );
-#endif
-                if( chanMaskState == true )
+                LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel;
+
+                if( ( LoRaMacDeviceClass == CLASS_C ) && ( IsLoRaMacNetworkJoined == true ) )
                 {
-                    if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
-                        ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
+                    // Compute Rx2 windows parameters
+                    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                                     LoRaMacParams.Rx2Channel.Datarate,
+                                                     LoRaMacParams.MinRxSymbols,
+                                                     LoRaMacParams.SystemMaxRxError,
+                                                     &RxWindow2Config );
+
+                    RxWindow2Config.Channel = Channel;
+                    RxWindow2Config.Frequency = LoRaMacParams.Rx2Channel.Frequency;
+                    RxWindow2Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+                    RxWindow2Config.RepeaterSupport = LoRaMacParams.RepeaterSupport;
+                    RxWindow2Config.Window = 1;
+                    RxWindow2Config.RxContinuous = true;
+
+                    if( RegionRxConfig( LoRaMacRegion, &RxWindow2Config, ( int8_t* )&McpsIndication.RxDatarate ) == true )
+                    {
+                        RxWindowSetup( RxWindow2Config.RxContinuous, LoRaMacParams.MaxRxWindow );
+                        RxSlot = RxWindow2Config.Window;
+                    }
+                    else
                     {
                         status = LORAMAC_STATUS_PARAMETER_INVALID;
                     }
-                    else
-                    {
-                        memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask,
-                                 ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) );
-                        for ( uint8_t i = 0; i < sizeof( LoRaMacParamsDefaults.ChannelsMask ) / 2; i++ )
-                        {
-                            // Disable channels which are no longer available
-                            ChannelsMaskRemaining[i] &= LoRaMacParamsDefaults.ChannelsMask[i];
-                        }
-                    }
                 }
-                else
-                {
-                    status = LORAMAC_STATUS_PARAMETER_INVALID;
-                }
-#elif defined( USE_BAND_470 )
-                memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) );
-#else
-                memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, 2 );
-#endif
             }
             else
             {
@@ -3874,47 +3197,38 @@
             }
             break;
         }
+        case MIB_RX2_DEFAULT_CHANNEL:
+        {
+            verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
+            verify.DatarateParams.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_RX_DR ) == true )
+            {
+                LoRaMacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel;
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        case MIB_CHANNELS_DEFAULT_MASK:
+        {
+            chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
+            chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
+
+            if( RegionChanMaskSet( LoRaMacRegion, &chanMaskSet ) == false )
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
         case MIB_CHANNELS_MASK:
         {
-            if( mibSet->Param.ChannelsMask )
-            {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                bool chanMaskState = true;
-
-#if defined( USE_BAND_915_HYBRID )
-                chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask );
-#endif
-                if( chanMaskState == true )
-                {
-                    if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
-                        ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
-                    {
-                        status = LORAMAC_STATUS_PARAMETER_INVALID;
-                    }
-                    else
-                    {
-                        memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask,
-                                 ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-                        for ( uint8_t i = 0; i < sizeof( LoRaMacParams.ChannelsMask ) / 2; i++ )
-                        {
-                            // Disable channels which are no longer available
-                            ChannelsMaskRemaining[i] &= LoRaMacParams.ChannelsMask[i];
-                        }
-                    }
-                }
-                else
-                {
-                    status = LORAMAC_STATUS_PARAMETER_INVALID;
-                }
-#elif defined( USE_BAND_470 )
-                memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#else
-                memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
-#endif
-            }
-            else
+            chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
+            chanMaskSet.ChannelsMaskType = CHANNELS_MASK;
+
+            if( RegionChanMaskSet( LoRaMacRegion, &chanMaskSet ) == false )
             {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
@@ -3960,19 +3274,12 @@
         }
         case MIB_CHANNELS_DEFAULT_DATARATE:
         {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-            if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate,
-                              DR_0, DR_5 ) )
+            verify.DatarateParams.Datarate = mibSet->Param.ChannelsDefaultDatarate;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_DEF_TX_DR ) == true )
             {
-                LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate;
+                LoRaMacParamsDefaults.ChannelsDatarate = verify.DatarateParams.Datarate;
             }
-#else
-            if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate,
-                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
-            {
-                LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate;
-            }
-#endif
             else
             {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
@@ -3981,10 +3288,11 @@
         }
         case MIB_CHANNELS_DATARATE:
         {
-            if( ValueInRange( mibSet->Param.ChannelsDatarate,
-                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
+            verify.DatarateParams.Datarate = mibSet->Param.ChannelsDatarate;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_TX_DR ) == true )
             {
-                LoRaMacParams.ChannelsDatarate = mibSet->Param.ChannelsDatarate;
+                LoRaMacParams.ChannelsDatarate = verify.DatarateParams.Datarate;
             }
             else
             {
@@ -3994,10 +3302,11 @@
         }
         case MIB_CHANNELS_DEFAULT_TX_POWER:
         {
-            if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower,
-                              LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
+            verify.TxPower = mibSet->Param.ChannelsDefaultTxPower;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_DEF_TX_POWER ) == true )
             {
-                LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower;
+                LoRaMacParamsDefaults.ChannelsTxPower = verify.TxPower;
             }
             else
             {
@@ -4007,10 +3316,11 @@
         }
         case MIB_CHANNELS_TX_POWER:
         {
-            if( ValueInRange( mibSet->Param.ChannelsTxPower,
-                              LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
+            verify.TxPower = mibSet->Param.ChannelsTxPower;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_TX_POWER ) == true )
             {
-                LoRaMacParams.ChannelsTxPower = mibSet->Param.ChannelsTxPower;
+                LoRaMacParams.ChannelsTxPower = verify.TxPower;
             }
             else
             {
@@ -4038,9 +3348,23 @@
             LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
             break;
         }
+        case MIB_ANTENNA_GAIN:
+        {
+            LoRaMacParams.AntennaGain = mibSet->Param.AntennaGain;
+            break;
+        }
         default:
-            status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+        {
+            if( LoRaMacDeviceClass == CLASS_B )
+            {
+                status = LoRaMacMibClassBSetRequestConfirm( mibSet );
+            }
+            else
+            {
+                status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+            }
             break;
+        }
     }
 
     return status;
@@ -4048,18 +3372,8 @@
 
 LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
 {
-#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    return LORAMAC_STATUS_PARAMETER_INVALID;
-#else
-    bool datarateInvalid = false;
-    bool frequencyInvalid = false;
-    uint8_t band = 0;
-
-    // The id must not exceed LORA_MAX_NB_CHANNELS
-    if( id >= LORA_MAX_NB_CHANNELS )
-    {
-        return LORAMAC_STATUS_PARAMETER_INVALID;
-    }
+    ChannelAddParams_t channelAdd;
+
     // Validate if the MAC is in a correct state
     if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
     {
@@ -4068,99 +3382,17 @@
             return LORAMAC_STATUS_BUSY;
         }
     }
-    // Validate the datarate
-    if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) ||
-        ( 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;
-    }
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( id < 3 )
-    {
-        if( params.Frequency != Channels[id].Frequency )
-        {
-            frequencyInvalid = true;
-        }
-
-        if( params.DrRange.Fields.Min > DR_0 )
-        {
-            datarateInvalid = true;
-        }
-        if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE ) == false )
-        {
-            datarateInvalid = true;
-        }
-    }
-#endif
-
-    // Validate the frequency
-    if( ( Radio.CheckRfFrequency( params.Frequency ) == true ) && ( params.Frequency > 0 ) && ( frequencyInvalid == false ) )
-    {
-#if defined( USE_BAND_868 )
-        if( ( params.Frequency >= 863000000 ) && ( params.Frequency < 865000000 ) )
-        {
-            band = BAND_G1_2;
-        }
-        else if( ( params.Frequency >= 865000000 ) && ( params.Frequency <= 868000000 ) )
-        {
-            band = BAND_G1_0;
-        }
-        else if( ( params.Frequency > 868000000 ) && ( params.Frequency <= 868600000 ) )
-        {
-            band = BAND_G1_1;
-        }
-        else if( ( params.Frequency >= 868700000 ) && ( params.Frequency <= 869200000 ) )
-        {
-            band = BAND_G1_2;
-        }
-        else if( ( params.Frequency >= 869400000 ) && ( params.Frequency <= 869650000 ) )
-        {
-            band = BAND_G1_3;
-        }
-        else if( ( params.Frequency >= 869700000 ) && ( params.Frequency <= 870000000 ) )
-        {
-            band = BAND_G1_4;
-        }
-        else
-        {
-            frequencyInvalid = true;
-        }
-#endif
-    }
-    else
-    {
-        frequencyInvalid = true;
-    }
-
-    if( ( datarateInvalid == true ) && ( frequencyInvalid == true ) )
-    {
-        return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
-    }
-    if( datarateInvalid == true )
-    {
-        return LORAMAC_STATUS_DATARATE_INVALID;
-    }
-    if( frequencyInvalid == true )
-    {
-        return LORAMAC_STATUS_FREQUENCY_INVALID;
-    }
-
-    // Every parameter is valid, activate the channel
-    Channels[id] = params;
-    Channels[id].Band = band;
-    LoRaMacParams.ChannelsMask[0] |= ( 1 << id );
-
-    return LORAMAC_STATUS_OK;
-#endif
+
+    channelAdd.NewChannel = &params;
+    channelAdd.ChannelId = id;
+
+    return RegionChannelAdd( LoRaMacRegion, &channelAdd );
 }
 
 LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
 {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+    ChannelRemoveParams_t channelRemove;
+
     if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
     {
         if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
@@ -4169,25 +3401,13 @@
         }
     }
 
-    if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
+    channelRemove.ChannelId = id;
+
+    if( RegionChannelsRemove( LoRaMacRegion, &channelRemove ) == false )
     {
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-    else
-    {
-        // 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, LoRaMacParams.ChannelsMask ) == false )
-        {
-            return LORAMAC_STATUS_PARAMETER_INVALID;
-        }
-    }
     return LORAMAC_STATUS_OK;
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) || defined( USE_BAND_470 ) )
-    return LORAMAC_STATUS_PARAMETER_INVALID;
-#endif
 }
 
 LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam )
@@ -4203,6 +3423,7 @@
 
     // Reset downlink counter
     channelParam->DownLinkCounter = 0;
+    channelParam->Next = NULL;
 
     if( MulticastChannels == NULL )
     {
@@ -4268,6 +3489,10 @@
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
     LoRaMacHeader_t macHdr;
+    AlternateDrParams_t altDr;
+    VerifyParams_t verify;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
 
     if( mlmeRequest == NULL )
     {
@@ -4277,11 +3502,18 @@
     {
         return LORAMAC_STATUS_BUSY;
     }
-
-    memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
-
-    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
-
+    if( LORA_MAC_MLME_CONFIRM_QUEUE_LEN <= MlmeConfirmQueueCnt )
+    {
+        return LORAMAC_STATUS_BUSY;
+    }
+
+    // Reset the confirm queue if it is empty
+    if( MlmeConfirmQueueCnt == 0 )
+    {
+        memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
+    }
+
+    // Switch requests
     switch( mlmeRequest->Type )
     {
         case MLME_JOIN:
@@ -4299,22 +3531,21 @@
                 return LORAMAC_STATUS_PARAMETER_INVALID;
             }
 
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-            // Enables at least the usage of the 2 datarates.
-            if( mlmeRequest->Req.Join.NbTrials < 2 )
+            // Apply the request
+            LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+
+            // Verify the parameter NbTrials for the join procedure
+            verify.NbJoinTrials = mlmeRequest->Req.Join.NbTrials;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_NB_JOIN_TRIALS ) == false )
             {
-                mlmeRequest->Req.Join.NbTrials = 2;
+                // Value not supported, get default
+                getPhy.Attribute = PHY_DEF_NB_JOIN_TRIALS;
+                phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+                mlmeRequest->Req.Join.NbTrials = ( uint8_t ) phyParam.Value;
             }
-#else
-            // Enables at least the usage of all datarates.
-            if( mlmeRequest->Req.Join.NbTrials < 48 )
-            {
-                mlmeRequest->Req.Join.NbTrials = 48;
-            }
-#endif
-
-            LoRaMacFlags.Bits.MlmeReq = 1;
-            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
 
             LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
             LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
@@ -4330,33 +3561,85 @@
 
             ResetMacParameters( );
 
-            // Add a +1, since we start to count from 0
-            LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 );
+            altDr.NbTrials = JoinRequestTrials + 1;
+
+            LoRaMacParams.ChannelsDatarate = RegionAlternateDr( LoRaMacRegion, &altDr );
 
             status = Send( &macHdr, 0, NULL, 0 );
             break;
         }
         case MLME_LINK_CHECK:
         {
+            // Apply the request
             LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+
             // LoRaMac will send this command piggy-pack
-            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
-
             status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
             break;
         }
         case MLME_TXCW:
         {
-            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
+            // Apply the request
             LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
             status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
             break;
         }
         case MLME_TXCW_1:
         {
-            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
+            // Apply the request
+            LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+            status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
+            break;
+        }
+        case MLME_PING_SLOT_INFO:
+        {
+            uint8_t value = mlmeRequest->Req.PingSlotInfo.PingSlot.Value;
+
+            // Apply the request
+            LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+            // LoRaMac will send this command piggy-pack
+            LoRaMacClassBSetPingSlotInfo( mlmeRequest->Req.PingSlotInfo.PingSlot.Fields.Periodicity );
+
+            status = AddMacCommand( MOTE_MAC_PING_SLOT_INFO_REQ, value, 0 );
+            break;
+        }
+        case MLME_BEACON_TIMING:
+        {
+            // Apply the request
             LoRaMacFlags.Bits.MlmeReq = 1;
-            status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power );
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+            // LoRaMac will send this command piggy-pack
+            status = AddMacCommand( MOTE_MAC_BEACON_TIMING_REQ, 0, 0 );
+            break;
+        }
+        case MLME_BEACON_ACQUISITION:
+        {
+            // Apply the request
+            LoRaMacFlags.Bits.MlmeReq = 1;
+            MlmeConfirmQueue[MlmeConfirmQueueCnt].MlmeRequest = mlmeRequest->Type;
+            MlmeConfirmQueueCnt++;
+
+            if( ( LoRaMacClassBIsAcquisitionPending( ) == false ) && ( LoRaMacClassBIsAcquisitionTimerSet( ) == false ) )
+            {
+                // Start class B algorithm
+                LoRaMacClassBSetBeaconState( BEACON_STATE_ACQUISITION );
+                LoRaMacClassBBeaconTimerEvent( );
+
+                status = LORAMAC_STATUS_OK;
+            }
+            else
+            {
+                status = LORAMAC_STATUS_BUSY;
+            }
             break;
         }
         default:
@@ -4366,7 +3649,11 @@
     if( status != LORAMAC_STATUS_OK )
     {
         NodeAckRequested = false;
-        LoRaMacFlags.Bits.MlmeReq = 0;
+        MlmeConfirmQueueCnt--;
+        if( MlmeConfirmQueueCnt == 0 )
+        {
+            LoRaMacFlags.Bits.MlmeReq = 0;
+        }
     }
 
     return status;
@@ -4374,8 +3661,11 @@
 
 LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
     LoRaMacHeader_t macHdr;
+    VerifyParams_t verify;
     uint8_t fPort = 0;
     void *fBuffer;
     uint16_t fBufferSize;
@@ -4396,6 +3686,9 @@
     memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
     McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
 
+    // AckTimeoutRetriesCounter must be reset every time a new request (unconfirmed or confirmed) is performed.
+    AckTimeoutRetriesCounter = 1;
+
     switch( mcpsRequest->Type )
     {
         case MCPS_UNCONFIRMED:
@@ -4413,7 +3706,6 @@
         case MCPS_CONFIRMED:
         {
             readyToSend = true;
-            AckTimeoutRetriesCounter = 1;
             AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials;
 
             macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
@@ -4438,13 +3730,24 @@
             break;
     }
 
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    // Apply the minimum possible datarate.
+    // Some regions have limitations for the minimum datarate.
+    datarate = MAX( datarate, phyParam.Value );
+
     if( readyToSend == true )
     {
         if( AdrCtrlOn == false )
         {
-            if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true )
+            verify.DatarateParams.Datarate = datarate;
+            verify.DatarateParams.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+            if( RegionVerify( LoRaMacRegion, &verify, PHY_TX_DR ) == true )
             {
-                LoRaMacParams.ChannelsDatarate = datarate;
+                LoRaMacParams.ChannelsDatarate = verify.DatarateParams.Datarate;
             }
             else
             {
@@ -4480,52 +3783,17 @@
 
 void LoRaMacTestSetDutyCycleOn( bool enable )
 {
-#if ( defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) )
-    DutyCycleOn = enable;
-#else
-    DutyCycleOn = false;
-#endif
+    VerifyParams_t verify;
+
+    verify.DutyCycle = enable;
+
+    if( RegionVerify( LoRaMacRegion, &verify, PHY_DUTY_CYCLE ) == true )
+    {
+        DutyCycleOn = enable;
+    }
 }
 
 void LoRaMacTestSetChannel( uint8_t channel )
 {
     Channel = channel;
 }
-
-static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError )
-{
-    RxConfigParams_t rxConfigParams = { 0, 0, 0, 0 };
-    double tSymbol = 0.0;
-
-    rxConfigParams.Datarate = datarate;
-    switch( Bandwidths[datarate] )
-    {
-        default:
-        case 125000:
-            rxConfigParams.Bandwidth = 0;
-            break;
-        case 250000:
-            rxConfigParams.Bandwidth = 1;
-            break;
-        case 500000:
-            rxConfigParams.Bandwidth = 2;
-            break;
-    }
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( datarate == DR_7 )
-    { // FSK
-        tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte
-    }
-    else
-#endif
-    { // LoRa
-        tSymbol = ( ( double )( 1 << Datarates[datarate] ) / ( double )Bandwidths[datarate] ) * 1e3;
-    }
-
-    rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols
-
-    rxConfigParams.RxOffset = ( int32_t )ceil( ( 4.0 * tSymbol ) - ( ( rxConfigParams.RxWindowTimeout * tSymbol ) / 2.0 ) - RADIO_WAKEUP_TIME );
-
-    return rxConfigParams;
-}