You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2018/05/02 20:41:15 UTC

[GitHub] wes3 closed pull request #1059: Add region support to lora code

wes3 closed pull request #1059: Add region support to lora code
URL: https://github.com/apache/mynewt-core/pull/1059
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/apps/lora_app_shell/src/las_cmd.c b/apps/lora_app_shell/src/las_cmd.c
index 9153172ad..289071b15 100644
--- a/apps/lora_app_shell/src/las_cmd.c
+++ b/apps/lora_app_shell/src/las_cmd.c
@@ -94,7 +94,6 @@ static int las_cmd_app_port(int argc, char **argv);
 static int las_cmd_app_tx(int argc, char **argv);
 static int las_cmd_join(int argc, char **argv);
 static int las_cmd_link_chk(int argc, char **argv);
-static int las_cmd_ln_log(int argc, char **argv);
 
 static struct shell_cmd las_cmds[] = {
     {
@@ -145,10 +144,6 @@ static struct shell_cmd las_cmds[] = {
         .sc_cmd = "las_link_chk",
         .sc_cmd_func = las_cmd_link_chk,
     },
-    {
-        .sc_cmd = "las_ln_log",
-        .sc_cmd_func = las_cmd_ln_log,
-    },
     {
         NULL, NULL,
 #if MYNEWT_VAL(SHELL_CMD_HELP)
@@ -175,15 +170,22 @@ las_cmd_disp_byte_str(uint8_t *bytes, int len)
 static void
 las_cmd_disp_chan_mask(uint16_t *mask)
 {
-    int i;
-    int len;
+    uint16_t i;
+    uint16_t len;
+    uint16_t max_chans;
+    PhyParam_t phy_param;
+    GetPhyParams_t getPhy;
 
     if (!mask) {
         return;
     }
 
-    len = LORA_MAX_NB_CHANNELS / 16;
-    if ((len * 16) != LORA_MAX_NB_CHANNELS) {
+    getPhy.Attribute = PHY_MAX_NB_CHANNELS;
+    phy_param = RegionGetPhyParam(LORA_NODE_REGION, &getPhy);
+    max_chans = phy_param.Value;
+
+    len = max_chans / 16;
+    if ((len * 16) != max_chans) {
         len += 1;
     }
 
@@ -249,106 +251,18 @@ las_parse_bool(char *str)
     return rc;
 }
 
-static int
-las_cmd_ln_log(int argc, char **argv)
-{
-    uint16_t i;
-    uint16_t lines_logged;
-
-#ifdef LORA_NODE_DEBUG_LOG
-    console_printf("Lora node log\n");
-    i = g_lnd_log_index;
-    lines_logged = 0;
-    while (lines_logged != LORA_NODE_DEBUG_LOG_ENTRIES) {
-        /* Do not display empty log lines */
-        if (g_lnd_log[i].lnd_id == 0) {
-            goto next_entry;
-        }
-
-        console_printf("index=%u ", i);
-        switch (g_lnd_log[i].lnd_id) {
-        case LORA_NODE_LOG_TX_DONE:
-            console_printf("TX_DONE chan=%u done_time=%lu",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_RX_WIN_SETUP:
-            console_printf("RX_WIN_SETUP dr=%u timeout=%u freq=%lu",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
-                           g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_RX_TIMEOUT:
-            console_printf("RX_TIMEOUT chan=%u rxslot=%u",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16);
-            break;
-        case LORA_NODE_LOG_RX_DONE:
-            console_printf("RX_DONE chan=%u size=%u slot=%lu",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
-                           g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_RX_SYNC_TIMEOUT:
-            break;
-        case LORA_NODE_LOG_RADIO_TIMEOUT_IRQ:
-            break;
-        case LORA_NODE_LOG_RX_PORT:
-            console_printf("RX_PORT port=%u len=%u",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16);
-            break;
-        case LORA_NODE_LOG_RX_WIN2:
-            console_printf("RX_WIN2 rxslot=%u continuous=%lu",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_RX_WIN_SETUP_FAIL:
-            break;
-        case LORA_NODE_LOG_APP_TX:
-            console_printf("APP_TX pktlen=%u om=%lx",
-                           g_lnd_log[i].lnd_p16, g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_RX_ADR_REQ:
-            console_printf("RX_ADR_REQ dr=%u txpwr=%u chmassk=%u nbrep=%u",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
-                           (uint16_t)(g_lnd_log[i].lnd_p32 >> 16),
-                           (uint16_t)g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_PROC_MAC_CMD:
-            console_printf("PROC_MAC_CMD index=%u snr=%u cmd_size=%lu",
-                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
-                           g_lnd_log[i].lnd_p32);
-            break;
-        case LORA_NODE_LOG_LINK_CHK:
-            console_printf("LINK_CHK status=%lu", g_lnd_log[i].lnd_p32);
-            break;
-        default:
-            console_printf("id=%u p8=%u p16=%u p32=%lu",
-                           g_lnd_log[i].lnd_id, g_lnd_log[i].lnd_p8,
-                           g_lnd_log[i].lnd_p16, g_lnd_log[i].lnd_p32);
-            break;
-        }
-
-        console_printf(" cputime=%lu\n", g_lnd_log[i].lnd_cputime);
-
-next_entry:
-        ++i;
-        if (i == LORA_NODE_DEBUG_LOG_ENTRIES) {
-            i = 0;
-        }
-        ++lines_logged;
-    }
-#else
-    console_printf("No Lora node log available\n");
-#endif
-    return 0;
-}
-
 static int
 las_cmd_wr_mib(int argc, char **argv)
 {
     int rc;
     int plen;
     uint8_t key[LORA_KEY_LEN];
-    uint16_t mask[6];
+    uint16_t mask[16];
     int mask_len;
     struct mib_pair *mp;
     MibRequestConfirm_t mib;
+    GetPhyParams_t getPhy;
+    PhyParam_t phy_param;
 
     if (argc < 3) {
         console_printf("Invalid # of arguments\n");
@@ -467,8 +381,11 @@ las_cmd_wr_mib(int argc, char **argv)
             /* NOTE: fall-through intentional */
         case MIB_CHANNELS_MASK:
             memset(mask, 0, sizeof(mask));
-            mask_len = LORA_MAX_NB_CHANNELS / 8;
-            if ((mask_len * 8) != LORA_MAX_NB_CHANNELS) {
+
+            getPhy.Attribute = PHY_MAX_NB_CHANNELS;
+            phy_param = RegionGetPhyParam(LORA_NODE_REGION, &getPhy);
+            mask_len = phy_param.Value / 8;
+            if ((mask_len * 8) != phy_param.Value) {
                 mask_len += 1;
             }
 
diff --git a/apps/lora_app_shell/src/main.c b/apps/lora_app_shell/src/main.c
index 1afd2e98d..13bb578af 100644
--- a/apps/lora_app_shell/src/main.c
+++ b/apps/lora_app_shell/src/main.c
@@ -54,7 +54,7 @@ lora_app_shell_txd_func(uint8_t port, LoRaMacEventInfoStatus_t status,
     console_printf("\tack_rxd:%u\n", lpkt->txdinfo.ack_rxd);
     console_printf("\ttx_time_on_air:%lu\n", lpkt->txdinfo.tx_time_on_air);
     console_printf("\tuplink_cntr:%lu\n", lpkt->txdinfo.uplink_cntr);
-    console_printf("\tuplink_freq:%lu\n", lpkt->txdinfo.uplink_freq);
+    console_printf("\tuplink_chan:%lu\n", lpkt->txdinfo.uplink_chan);
 
     os_mbuf_free_chain(om);
 }
diff --git a/hw/drivers/lora/sx1272/include/radio/radio.h b/hw/drivers/lora/sx1272/include/radio/radio.h
index ccc0ffc98..2ede13183 100644
--- a/hw/drivers/lora/sx1272/include/radio/radio.h
+++ b/hw/drivers/lora/sx1272/include/radio/radio.h
@@ -1,21 +1,29 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
-
-Description: Generic radio driver definition
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis and Gregory Cristian
-*/
+/*!
+ * \file      radio.h
+ *
+ * \brief     Radio driver API definition
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ */
 #ifndef __RADIO_H__
 #define __RADIO_H__
 
-#include <inttypes.h>
+#include <stdint.h>
 #include <stdbool.h>
 
 /*!
@@ -32,10 +40,10 @@ typedef enum
  */
 typedef enum
 {
-    RF_IDLE = 0,
-    RF_RX_RUNNING,
-    RF_TX_RUNNING,
-    RF_CAD,
+    RF_IDLE = 0,   //!< The radio is idle
+    RF_RX_RUNNING, //!< The radio is in reception state
+    RF_TX_RUNNING, //!< The radio is in transmission state
+    RF_CAD,        //!< The radio is doing channel activity detection
 }RadioState_t;
 
 /*!
@@ -105,7 +113,7 @@ struct Radio_s
     /*!
      * \brief Configures the radio with the given modem
      *
-     * \param [IN] modem Modem to be used [0: FSK, 1: LoRa] 
+     * \param [IN] modem Modem to be used [0: FSK, 1: LoRa]
      */
     void    ( *SetModem )( RadioModems_t modem );
     /*!
@@ -115,19 +123,20 @@ struct Radio_s
      */
     void    ( *SetChannel )( uint32_t freq );
     /*!
-     * \brief Sets the channels configuration
+     * \brief Checks if the channel is free for the given time
      *
      * \param [IN] modem      Radio modem to be used [0: FSK, 1: LoRa]
      * \param [IN] freq       Channel RF frequency
      * \param [IN] rssiThresh RSSI threshold
+     * \param [IN] maxCarrierSenseTime Max time while the RSSI is measured
      *
      * \retval isFree         [true: Channel is free, false: Channel is not free]
      */
-    bool    ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh );
+    bool    ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
     /*!
      * \brief Generates a 32 bits random value based on the RSSI readings
      *
-     * \remark This function sets the radio in LoRa modem mode and disables 
+     * \remark This function sets the radio in LoRa modem mode and disables
      *         all interrupts.
      *         After calling this function either Radio.SetRxConfig or
      *         Radio.SetTxConfig functions must be called.
@@ -142,30 +151,30 @@ struct Radio_s
      * \param [IN] bandwidth    Sets the bandwidth
      *                          FSK : >= 2600 and <= 250000 Hz
      *                          LoRa: [0: 125 kHz, 1: 250 kHz,
-     *                                 2: 500 kHz, 3: Reserved] 
+     *                                 2: 500 kHz, 3: Reserved]
      * \param [IN] datarate     Sets the Datarate
      *                          FSK : 600..300000 bits/s
      *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
      *                                10: 1024, 11: 2048, 12: 4096  chips]
      * \param [IN] coderate     Sets the coding rate (LoRa only)
      *                          FSK : N/A ( set to 0 )
-     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] 
-     * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only) 
+     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+     * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
      *                          FSK : >= 2600 and <= 250000 Hz
-     *                          LoRa: N/A ( set to 0 ) 
+     *                          LoRa: N/A ( set to 0 )
      * \param [IN] preambleLen  Sets the Preamble length
-     *                          FSK : Number of bytes 
+     *                          FSK : Number of bytes
      *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
-     * \param [IN] symbTimeout  Sets the RxSingle timeout value (LoRa only) 
-     *                          FSK : N/A ( set to 0 ) 
+     * \param [IN] symbTimeout  Sets the RxSingle timeout value
+     *                          FSK : timeout in number of bytes
      *                          LoRa: timeout in symbols
      * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
      * \param [IN] payloadLen   Sets payload length when fixed length is used
      * \param [IN] crcOn        Enables/Disables the CRC [0: OFF, 1: ON]
-     * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
+     * \param [IN] freqHopOn    Enables disables the intra-packet frequency hopping
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: [0: OFF, 1: ON]
-     * \param [IN] HopPeriod    Number of symbols between each hop
+     * \param [IN] hopPeriod    Number of symbols between each hop
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: Number of symbols
      * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
@@ -179,12 +188,12 @@ struct Radio_s
                               uint32_t bandwidthAfc, uint16_t preambleLen,
                               uint16_t symbTimeout, bool fixLen,
                               uint8_t payloadLen,
-                              bool crcOn, bool FreqHopOn, uint8_t HopPeriod,
+                              bool crcOn, bool freqHopOn, uint8_t hopPeriod,
                               bool iqInverted, bool rxContinuous );
     /*!
      * \brief Sets the transmission parameters
      *
-     * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa] 
+     * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa]
      * \param [IN] power        Sets the output power [dBm]
      * \param [IN] fdev         Sets the frequency deviation (FSK only)
      *                          FSK : [Hz]
@@ -192,23 +201,23 @@ struct Radio_s
      * \param [IN] bandwidth    Sets the bandwidth (LoRa only)
      *                          FSK : 0
      *                          LoRa: [0: 125 kHz, 1: 250 kHz,
-     *                                 2: 500 kHz, 3: Reserved] 
+     *                                 2: 500 kHz, 3: Reserved]
      * \param [IN] datarate     Sets the Datarate
      *                          FSK : 600..300000 bits/s
      *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
      *                                10: 1024, 11: 2048, 12: 4096  chips]
      * \param [IN] coderate     Sets the coding rate (LoRa only)
      *                          FSK : N/A ( set to 0 )
-     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] 
+     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
      * \param [IN] preambleLen  Sets the preamble length
-     *                          FSK : Number of bytes 
+     *                          FSK : Number of bytes
      *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
      * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
      * \param [IN] crcOn        Enables disables the CRC [0: OFF, 1: ON]
-     * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
+     * \param [IN] freqHopOn    Enables disables the intra-packet frequency hopping
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: [0: OFF, 1: ON]
-     * \param [IN] HopPeriod    Number of symbols between each hop
+     * \param [IN] hopPeriod    Number of symbols between each hop
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: Number of symbols
      * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
@@ -216,11 +225,11 @@ struct Radio_s
      *                          LoRa: [0: not inverted, 1: inverted]
      * \param [IN] timeout      Transmission timeout [ms]
      */
-    void    ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev, 
+    void    ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev,
                               uint32_t bandwidth, uint32_t datarate,
                               uint8_t coderate, uint16_t preambleLen,
-                              bool fixLen, bool crcOn, bool FreqHopOn,
-                              uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
+                              bool fixLen, bool crcOn, bool freqHopOn,
+                              uint8_t hopPeriod, bool iqInverted, uint32_t timeout );
     /*!
      * \brief Checks if the given RF frequency is supported by the hardware
      *
@@ -285,14 +294,14 @@ struct Radio_s
      * \param [IN]: addr Register address
      * \param [IN]: data New register value
      */
-    void    ( *Write )( uint8_t addr, uint8_t data );
+    void    ( *Write )( uint16_t addr, uint8_t data );
     /*!
      * \brief Reads the radio register at the specified address
      *
      * \param [IN]: addr Register address
      * \retval data Register value
      */
-    uint8_t ( *Read )( uint8_t addr );
+    uint8_t ( *Read )( uint16_t addr );
     /*!
      * \brief Writes multiple radio registers starting at address
      *
@@ -300,7 +309,7 @@ struct Radio_s
      * \param [IN] buffer Buffer containing the new register's values
      * \param [IN] size   Number of registers to be written
      */
-    void    ( *WriteBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
+    void    ( *WriteBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
     /*!
      * \brief Reads multiple radio registers starting at address
      *
@@ -308,7 +317,7 @@ struct Radio_s
      * \param [OUT] buffer Buffer where to copy the registers data
      * \param [IN] size Number of registers to be read
      */
-    void    ( *ReadBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
+    void    ( *ReadBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
     /*!
      * \brief Sets the maximum payload length.
      *
@@ -324,6 +333,37 @@ struct Radio_s
      * \param [IN] enable if true, it enables a public network
      */
     void    ( *SetPublicNetwork )( bool enable );
+    /*!
+     * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
+     *
+     * \retval time Radio plus board wakeup time in ms.
+     */
+    uint32_t  ( *GetWakeupTime )( void );
+    /*!
+     * \brief Process radio irq
+     */
+    void ( *IrqProcess )( void );
+    /*
+     * The next functions are available only on SX126x radios.
+     */
+    /*!
+     * \brief Sets the radio in reception mode with Max LNA gain for the given time
+     *
+     * \remark Available on SX126x radios only.
+     *
+     * \param [IN] timeout Reception timeout [ms]
+     *                     [0: continuous, others timeout]
+     */
+    void    ( *RxBoosted )( uint32_t timeout );
+    /*!
+     * \brief Sets the Rx duty cycle management parameters
+     *
+     * \remark Available on SX126x radios only.
+     *
+     * \param [in]  rxTime        Structure describing reception timeout value
+     * \param [in]  sleepTime     Structure describing sleep timeout value
+     */
+    void ( *SetRxDutyCycle ) ( uint32_t rxTime, uint32_t sleepTime );
 };
 
 /*!
diff --git a/hw/drivers/lora/sx1272/src/sx1272-board.c b/hw/drivers/lora/sx1272/src/sx1272-board.c
index 5edd53141..9e587663b 100644
--- a/hw/drivers/lora/sx1272/src/sx1272-board.c
+++ b/hw/drivers/lora/sx1272/src/sx1272-board.c
@@ -62,7 +62,8 @@ const struct Radio_s Radio =
     SX1272WriteBuffer,
     SX1272ReadBuffer,
     SX1272SetMaxPayloadLength,
-    SX1272SetPublicNetwork
+    SX1272SetPublicNetwork,
+    SX1272GetWakeupTime
 };
 
 void
@@ -341,3 +342,10 @@ SX1272CheckRfFrequency(uint32_t frequency)
     // Implement check. Currently all frequencies are supported
     return true;
 }
+
+uint32_t
+SX1272GetBoardTcxoWakeupTime(void)
+{
+    return 0;
+}
+
diff --git a/hw/drivers/lora/sx1272/src/sx1272-board.h b/hw/drivers/lora/sx1272/src/sx1272-board.h
index 98de9cadf..b20d86f34 100644
--- a/hw/drivers/lora/sx1272/src/sx1272-board.h
+++ b/hw/drivers/lora/sx1272/src/sx1272-board.h
@@ -144,6 +144,13 @@ void SX1272SetAntSw(uint8_t opMode);
  */
 bool SX1272CheckRfFrequency(uint32_t frequency);
 
+/*!
+ * \brief Gets the Defines the time required for the TCXO to wakeup [ms].
+ *
+ * \retval time Board TCXO wakeup time in ms.
+ */
+uint32_t SX1272GetBoardTcxoWakeupTime( void );
+
 /*!
  * Radio hardware and global parameters
  */
diff --git a/hw/drivers/lora/sx1272/src/sx1272.c b/hw/drivers/lora/sx1272/src/sx1272.c
index 7f3fe844f..4a0f746f9 100644
--- a/hw/drivers/lora/sx1272/src/sx1272.c
+++ b/hw/drivers/lora/sx1272/src/sx1272.c
@@ -23,6 +23,7 @@ Maintainer: Miguel Luis and Gregory Cristian
 #include "radio/radio.h"
 #include "sx1272.h"
 #include "sx1272-board.h"
+#include "node/utilities.h"
 
 #if MYNEWT_VAL(LORA_MAC_TIMER_NUM) == -1
 #error "Must define a Lora MAC timer number"
@@ -300,9 +301,12 @@ SX1272SetChannel(uint32_t freq)
 }
 
 bool
-SX1272IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh)
+SX1272IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
+                    uint32_t maxCarrierSenseTime)
 {
+    bool status = true;
     int16_t rssi;
+    uint32_t carrierSenseTime;
 
     SX1272SetModem(modem);
 
@@ -313,14 +317,18 @@ SX1272IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh)
     /* Delay for 1 msec */
     hal_timer_delay(SX1272_TIMER_NUM, 1000);
 
-    rssi = SX1272ReadRssi(modem);
+    carrierSenseTime = TimerGetCurrentTime( );
 
-    SX1272SetSleep();
-
-    if (rssi > rssiThresh) {
-        return false;
+    // Perform carrier sense for maxCarrierSenseTime
+    while (TimerGetElapsedTime( carrierSenseTime ) < maxCarrierSenseTime) {
+        rssi = SX1272ReadRssi(modem);
+        if (rssi > rssiThresh) {
+            status = false;
+            break;
+        }
     }
-    return true;
+    SX1272SetSleep();
+    return status;
 }
 
 uint32_t
@@ -1046,13 +1054,13 @@ SX1272SetModem(RadioModems_t modem)
 }
 
 void
-SX1272Write(uint8_t addr, uint8_t data)
+SX1272Write(uint16_t addr, uint8_t data)
 {
     SX1272WriteBuffer(addr, &data, 1);
 }
 
 uint8_t
-SX1272Read(uint8_t addr)
+SX1272Read(uint16_t addr)
 {
     uint8_t data;
     SX1272ReadBuffer(addr, &data, 1);
@@ -1060,7 +1068,7 @@ SX1272Read(uint8_t addr)
 }
 
 void
-SX1272WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
+SX1272WriteBuffer(uint16_t addr, uint8_t *buffer, uint8_t size)
 {
 #if MYNEWT_VAL(BSP_USE_HAL_SPI) == 1
     hal_gpio_write(RADIO_NSS, 0);
@@ -1079,7 +1087,7 @@ SX1272WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
 }
 
 void
-SX1272ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
+SX1272ReadBuffer(uint16_t addr, uint8_t *buffer, uint8_t size)
 {
 #if MYNEWT_VAL(BSP_USE_HAL_SPI) == 1
     hal_gpio_write(RADIO_NSS, 0);
@@ -1140,6 +1148,11 @@ SX1272SetPublicNetwork(bool enable)
     }
 }
 
+uint32_t SX1272GetWakeupTime( void )
+{
+    return SX1272GetBoardTcxoWakeupTime( ) + RADIO_WAKEUP_TIME;
+}
+
 void
 SX1272OnTimeoutIrq(void *unused)
 {
diff --git a/hw/drivers/lora/sx1272/src/sx1272.h b/hw/drivers/lora/sx1272/src/sx1272.h
index 2d59020eb..af4fd5df5 100644
--- a/hw/drivers/lora/sx1272/src/sx1272.h
+++ b/hw/drivers/lora/sx1272/src/sx1272.h
@@ -179,7 +179,8 @@ void SX1272SetChannel(uint32_t freq);
  *
  * \retval isFree         [true: Channel is free, false: Channel is not free]
  */
-bool SX1272IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh);
+bool SX1272IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
+                         uint32_t maxCarrierSenseTime);
 
 /*!
  * \brief Generates a 32 bits random value based on the RSSI readings
@@ -345,7 +346,7 @@ int16_t SX1272ReadRssi(RadioModems_t modem);
  * \param [IN]: addr Register address
  * \param [IN]: data New register value
  */
-void SX1272Write(uint8_t addr, uint8_t data);
+void SX1272Write(uint16_t addr, uint8_t data);
 
 /*!
  * \brief Reads the radio register at the specified address
@@ -353,7 +354,7 @@ void SX1272Write(uint8_t addr, uint8_t data);
  * \param [IN]: addr Register address
  * \retval data Register value
  */
-uint8_t SX1272Read(uint8_t addr);
+uint8_t SX1272Read(uint16_t addr);
 
 /*!
  * \brief Writes multiple radio registers starting at address
@@ -362,7 +363,7 @@ uint8_t SX1272Read(uint8_t addr);
  * \param [IN] buffer Buffer containing the new register's values
  * \param [IN] size   Number of registers to be written
  */
-void SX1272WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
+void SX1272WriteBuffer(uint16_t addr, uint8_t *buffer, uint8_t size);
 
 /*!
  * \brief Reads multiple radio registers starting at address
@@ -371,7 +372,7 @@ void SX1272WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
  * \param [OUT] buffer Buffer where to copy the registers data
  * \param [IN] size Number of registers to be read
  */
-void SX1272ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
+void SX1272ReadBuffer(uint16_t addr, uint8_t *buffer, uint8_t size);
 
 /*!
  * \brief Sets the maximum payload length.
@@ -390,4 +391,11 @@ void SX1272SetMaxPayloadLength(RadioModems_t modem, uint8_t max);
  */
 void SX1272SetPublicNetwork(bool enable);
 
+/*!
+ * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
+ *
+ * \retval time Radio plus board wakeup time in ms.
+ */
+uint32_t SX1272GetWakeupTime(void);
+
 #endif // __SX1272_H__
diff --git a/hw/drivers/lora/sx1276/include/radio/radio.h b/hw/drivers/lora/sx1276/include/radio/radio.h
index ccc0ffc98..2ede13183 100644
--- a/hw/drivers/lora/sx1276/include/radio/radio.h
+++ b/hw/drivers/lora/sx1276/include/radio/radio.h
@@ -1,21 +1,29 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
-
-Description: Generic radio driver definition
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis and Gregory Cristian
-*/
+/*!
+ * \file      radio.h
+ *
+ * \brief     Radio driver API definition
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ */
 #ifndef __RADIO_H__
 #define __RADIO_H__
 
-#include <inttypes.h>
+#include <stdint.h>
 #include <stdbool.h>
 
 /*!
@@ -32,10 +40,10 @@ typedef enum
  */
 typedef enum
 {
-    RF_IDLE = 0,
-    RF_RX_RUNNING,
-    RF_TX_RUNNING,
-    RF_CAD,
+    RF_IDLE = 0,   //!< The radio is idle
+    RF_RX_RUNNING, //!< The radio is in reception state
+    RF_TX_RUNNING, //!< The radio is in transmission state
+    RF_CAD,        //!< The radio is doing channel activity detection
 }RadioState_t;
 
 /*!
@@ -105,7 +113,7 @@ struct Radio_s
     /*!
      * \brief Configures the radio with the given modem
      *
-     * \param [IN] modem Modem to be used [0: FSK, 1: LoRa] 
+     * \param [IN] modem Modem to be used [0: FSK, 1: LoRa]
      */
     void    ( *SetModem )( RadioModems_t modem );
     /*!
@@ -115,19 +123,20 @@ struct Radio_s
      */
     void    ( *SetChannel )( uint32_t freq );
     /*!
-     * \brief Sets the channels configuration
+     * \brief Checks if the channel is free for the given time
      *
      * \param [IN] modem      Radio modem to be used [0: FSK, 1: LoRa]
      * \param [IN] freq       Channel RF frequency
      * \param [IN] rssiThresh RSSI threshold
+     * \param [IN] maxCarrierSenseTime Max time while the RSSI is measured
      *
      * \retval isFree         [true: Channel is free, false: Channel is not free]
      */
-    bool    ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh );
+    bool    ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
     /*!
      * \brief Generates a 32 bits random value based on the RSSI readings
      *
-     * \remark This function sets the radio in LoRa modem mode and disables 
+     * \remark This function sets the radio in LoRa modem mode and disables
      *         all interrupts.
      *         After calling this function either Radio.SetRxConfig or
      *         Radio.SetTxConfig functions must be called.
@@ -142,30 +151,30 @@ struct Radio_s
      * \param [IN] bandwidth    Sets the bandwidth
      *                          FSK : >= 2600 and <= 250000 Hz
      *                          LoRa: [0: 125 kHz, 1: 250 kHz,
-     *                                 2: 500 kHz, 3: Reserved] 
+     *                                 2: 500 kHz, 3: Reserved]
      * \param [IN] datarate     Sets the Datarate
      *                          FSK : 600..300000 bits/s
      *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
      *                                10: 1024, 11: 2048, 12: 4096  chips]
      * \param [IN] coderate     Sets the coding rate (LoRa only)
      *                          FSK : N/A ( set to 0 )
-     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] 
-     * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only) 
+     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
+     * \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
      *                          FSK : >= 2600 and <= 250000 Hz
-     *                          LoRa: N/A ( set to 0 ) 
+     *                          LoRa: N/A ( set to 0 )
      * \param [IN] preambleLen  Sets the Preamble length
-     *                          FSK : Number of bytes 
+     *                          FSK : Number of bytes
      *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
-     * \param [IN] symbTimeout  Sets the RxSingle timeout value (LoRa only) 
-     *                          FSK : N/A ( set to 0 ) 
+     * \param [IN] symbTimeout  Sets the RxSingle timeout value
+     *                          FSK : timeout in number of bytes
      *                          LoRa: timeout in symbols
      * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
      * \param [IN] payloadLen   Sets payload length when fixed length is used
      * \param [IN] crcOn        Enables/Disables the CRC [0: OFF, 1: ON]
-     * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
+     * \param [IN] freqHopOn    Enables disables the intra-packet frequency hopping
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: [0: OFF, 1: ON]
-     * \param [IN] HopPeriod    Number of symbols between each hop
+     * \param [IN] hopPeriod    Number of symbols between each hop
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: Number of symbols
      * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
@@ -179,12 +188,12 @@ struct Radio_s
                               uint32_t bandwidthAfc, uint16_t preambleLen,
                               uint16_t symbTimeout, bool fixLen,
                               uint8_t payloadLen,
-                              bool crcOn, bool FreqHopOn, uint8_t HopPeriod,
+                              bool crcOn, bool freqHopOn, uint8_t hopPeriod,
                               bool iqInverted, bool rxContinuous );
     /*!
      * \brief Sets the transmission parameters
      *
-     * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa] 
+     * \param [IN] modem        Radio modem to be used [0: FSK, 1: LoRa]
      * \param [IN] power        Sets the output power [dBm]
      * \param [IN] fdev         Sets the frequency deviation (FSK only)
      *                          FSK : [Hz]
@@ -192,23 +201,23 @@ struct Radio_s
      * \param [IN] bandwidth    Sets the bandwidth (LoRa only)
      *                          FSK : 0
      *                          LoRa: [0: 125 kHz, 1: 250 kHz,
-     *                                 2: 500 kHz, 3: Reserved] 
+     *                                 2: 500 kHz, 3: Reserved]
      * \param [IN] datarate     Sets the Datarate
      *                          FSK : 600..300000 bits/s
      *                          LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
      *                                10: 1024, 11: 2048, 12: 4096  chips]
      * \param [IN] coderate     Sets the coding rate (LoRa only)
      *                          FSK : N/A ( set to 0 )
-     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] 
+     *                          LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
      * \param [IN] preambleLen  Sets the preamble length
-     *                          FSK : Number of bytes 
+     *                          FSK : Number of bytes
      *                          LoRa: Length in symbols (the hardware adds 4 more symbols)
      * \param [IN] fixLen       Fixed length packets [0: variable, 1: fixed]
      * \param [IN] crcOn        Enables disables the CRC [0: OFF, 1: ON]
-     * \param [IN] FreqHopOn    Enables disables the intra-packet frequency hopping
+     * \param [IN] freqHopOn    Enables disables the intra-packet frequency hopping
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: [0: OFF, 1: ON]
-     * \param [IN] HopPeriod    Number of symbols between each hop
+     * \param [IN] hopPeriod    Number of symbols between each hop
      *                          FSK : N/A ( set to 0 )
      *                          LoRa: Number of symbols
      * \param [IN] iqInverted   Inverts IQ signals (LoRa only)
@@ -216,11 +225,11 @@ struct Radio_s
      *                          LoRa: [0: not inverted, 1: inverted]
      * \param [IN] timeout      Transmission timeout [ms]
      */
-    void    ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev, 
+    void    ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev,
                               uint32_t bandwidth, uint32_t datarate,
                               uint8_t coderate, uint16_t preambleLen,
-                              bool fixLen, bool crcOn, bool FreqHopOn,
-                              uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
+                              bool fixLen, bool crcOn, bool freqHopOn,
+                              uint8_t hopPeriod, bool iqInverted, uint32_t timeout );
     /*!
      * \brief Checks if the given RF frequency is supported by the hardware
      *
@@ -285,14 +294,14 @@ struct Radio_s
      * \param [IN]: addr Register address
      * \param [IN]: data New register value
      */
-    void    ( *Write )( uint8_t addr, uint8_t data );
+    void    ( *Write )( uint16_t addr, uint8_t data );
     /*!
      * \brief Reads the radio register at the specified address
      *
      * \param [IN]: addr Register address
      * \retval data Register value
      */
-    uint8_t ( *Read )( uint8_t addr );
+    uint8_t ( *Read )( uint16_t addr );
     /*!
      * \brief Writes multiple radio registers starting at address
      *
@@ -300,7 +309,7 @@ struct Radio_s
      * \param [IN] buffer Buffer containing the new register's values
      * \param [IN] size   Number of registers to be written
      */
-    void    ( *WriteBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
+    void    ( *WriteBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
     /*!
      * \brief Reads multiple radio registers starting at address
      *
@@ -308,7 +317,7 @@ struct Radio_s
      * \param [OUT] buffer Buffer where to copy the registers data
      * \param [IN] size Number of registers to be read
      */
-    void    ( *ReadBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
+    void    ( *ReadBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
     /*!
      * \brief Sets the maximum payload length.
      *
@@ -324,6 +333,37 @@ struct Radio_s
      * \param [IN] enable if true, it enables a public network
      */
     void    ( *SetPublicNetwork )( bool enable );
+    /*!
+     * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
+     *
+     * \retval time Radio plus board wakeup time in ms.
+     */
+    uint32_t  ( *GetWakeupTime )( void );
+    /*!
+     * \brief Process radio irq
+     */
+    void ( *IrqProcess )( void );
+    /*
+     * The next functions are available only on SX126x radios.
+     */
+    /*!
+     * \brief Sets the radio in reception mode with Max LNA gain for the given time
+     *
+     * \remark Available on SX126x radios only.
+     *
+     * \param [IN] timeout Reception timeout [ms]
+     *                     [0: continuous, others timeout]
+     */
+    void    ( *RxBoosted )( uint32_t timeout );
+    /*!
+     * \brief Sets the Rx duty cycle management parameters
+     *
+     * \remark Available on SX126x radios only.
+     *
+     * \param [in]  rxTime        Structure describing reception timeout value
+     * \param [in]  sleepTime     Structure describing sleep timeout value
+     */
+    void ( *SetRxDutyCycle ) ( uint32_t rxTime, uint32_t sleepTime );
 };
 
 /*!
diff --git a/hw/drivers/lora/sx1276/src/sx1276-board.c b/hw/drivers/lora/sx1276/src/sx1276-board.c
index 3e5d922f1..7430c69e8 100644
--- a/hw/drivers/lora/sx1276/src/sx1276-board.c
+++ b/hw/drivers/lora/sx1276/src/sx1276-board.c
@@ -54,7 +54,8 @@ const struct Radio_s Radio =
     .WriteBuffer = SX1276WriteBuffer,
     .ReadBuffer = SX1276ReadBuffer,
     .SetMaxPayloadLength = SX1276SetMaxPayloadLength,
-    .SetPublicNetwork = SX1276SetPublicNetwork
+    .SetPublicNetwork = SX1276SetPublicNetwork,
+    .GetWakeupTime = SX1276GetWakeupTime
 };
 
 void
@@ -223,3 +224,10 @@ SX1276CheckRfFrequency(uint32_t frequency)
     // Implement check. Currently all frequencies are supported
     return true;
 }
+
+uint32_t
+SX1276GetBoardTcxoWakeupTime(void)
+{
+    return 0;
+}
+
diff --git a/hw/drivers/lora/sx1276/src/sx1276-board.h b/hw/drivers/lora/sx1276/src/sx1276-board.h
index 65701f69e..173f1d944 100644
--- a/hw/drivers/lora/sx1276/src/sx1276-board.h
+++ b/hw/drivers/lora/sx1276/src/sx1276-board.h
@@ -121,7 +121,7 @@ bool SX1276CheckRfFrequency(uint32_t frequency);
 
 void SX1276SetPublicNetwork(bool enable);
 
-void hal_pin_rxtx (int val);
+uint32_t SX1276GetBoardTcxoWakeupTime(void);
 
 /*!
  * Radio hardware and global parameters
diff --git a/hw/drivers/lora/sx1276/src/sx1276.c b/hw/drivers/lora/sx1276/src/sx1276.c
index 7ac9628b9..d728ce13f 100644
--- a/hw/drivers/lora/sx1276/src/sx1276.c
+++ b/hw/drivers/lora/sx1276/src/sx1276.c
@@ -23,6 +23,7 @@ Maintainer: Miguel Luis, Gregory Cristian and Wael Guibene
 #include "radio/radio.h"
 #include "sx1276.h"
 #include "sx1276-board.h"
+#include "node/utilities.h"
 
 #if MYNEWT_VAL(LORA_MAC_TIMER_NUM) == -1
 #error "Must define a Lora MAC timer number"
@@ -338,9 +339,12 @@ SX1276SetChannel(uint32_t freq)
 }
 
 bool
-SX1276IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh)
+SX1276IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
+                    uint32_t maxCarrierSenseTime)
 {
+    bool status = true;
     int16_t rssi;
+    uint32_t carrierSenseTime;
 
     SX1276SetModem(modem);
 
@@ -351,14 +355,18 @@ SX1276IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh)
     /* Delay for 1 msec */
     hal_timer_delay(SX1276_TIMER_NUM, 1000);
 
-    rssi = SX1276ReadRssi(modem);
+    carrierSenseTime = TimerGetCurrentTime();
 
-    SX1276SetSleep();
-
-    if (rssi > rssiThresh) {
-        return false;
+    // Perform carrier sense for maxCarrierSenseTime
+    while (TimerGetElapsedTime(carrierSenseTime) < maxCarrierSenseTime) {
+        rssi = SX1276ReadRssi(modem);
+        if (rssi > rssiThresh) {
+            status = false;
+            break;
+        }
     }
-    return true;
+    SX1276SetSleep();
+    return status;
 }
 
 uint32_t
@@ -1241,13 +1249,13 @@ SX1276SetModem(RadioModems_t modem)
 }
 
 void
-SX1276Write(uint8_t addr, uint8_t data)
+SX1276Write(uint16_t addr, uint8_t data)
 {
     SX1276WriteBuffer(addr, &data, 1);
 }
 
 uint8_t
-SX1276Read(uint8_t addr)
+SX1276Read(uint16_t addr)
 {
     uint8_t data;
     SX1276ReadBuffer(addr, &data, 1);
@@ -1255,7 +1263,7 @@ SX1276Read(uint8_t addr)
 }
 
 void
-SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
+SX1276WriteBuffer(uint16_t addr, uint8_t *buffer, uint8_t size)
 {
     uint8_t i;
 
@@ -1270,7 +1278,7 @@ SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
 }
 
 void
-SX1276ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size)
+SX1276ReadBuffer(uint16_t addr, uint8_t *buffer, uint8_t size)
 {
     uint8_t i;
 
@@ -1327,6 +1335,12 @@ SX1276SetPublicNetwork(bool enable)
     }
 }
 
+uint32_t
+SX1276GetWakeupTime(void)
+{
+    return SX1276GetBoardTcxoWakeupTime( ) + RADIO_WAKEUP_TIME;
+}
+
 void
 SX1276OnTimeoutIrq(void *unused)
 {
diff --git a/hw/drivers/lora/sx1276/src/sx1276.h b/hw/drivers/lora/sx1276/src/sx1276.h
index 2e2bb50c2..bfbb082a6 100644
--- a/hw/drivers/lora/sx1276/src/sx1276.h
+++ b/hw/drivers/lora/sx1276/src/sx1276.h
@@ -20,6 +20,11 @@ Maintainer: Miguel Luis and Gregory Cristian
 #include "sx1276Regs-Fsk.h"
 #include "sx1276Regs-LoRa.h"
 
+/*!
+ * Radio complete Wake-up Time with margin for temperature compensation
+ */
+#define RADIO_WAKEUP_TIME                           1 // [ms]
+
 /*!
  * Sync word for Private LoRa networks
  */
@@ -30,21 +35,6 @@ Maintainer: Miguel Luis and Gregory Cristian
  */
 #define LORA_MAC_PUBLIC_SYNCWORD                    0x34
 
-/*!
- * Radio wakeup time from SLEEP mode
- */
-#define RADIO_OSC_STARTUP                           1 // [ms]
-
-/*!
- * Radio PLL lock and Mode Ready delay which can vary with the temperature
- */
-#define RADIO_SLEEP_TO_RX                           2 // [ms]
-
-/*!
- * Radio complete Wake-up Time with margin for temperature compensation
- */
-#define RADIO_WAKEUP_TIME   (RADIO_OSC_STARTUP + RADIO_SLEEP_TO_RX)
-
 /*!
  * Radio FSK modem parameters
  */
@@ -190,7 +180,8 @@ void SX1276SetChannel(uint32_t freq);
  *
  * \retval isFree         [true: Channel is free, false: Channel is not free]
  */
-bool SX1276IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh);
+bool SX1276IsChannelFree(RadioModems_t modem, uint32_t freq, int16_t rssiThresh,
+                         uint32_t maxCarrierSenseTime);
 
 /*!
  * \brief Generates a 32 bits random value based on the RSSI readings
@@ -351,7 +342,7 @@ int16_t SX1276ReadRssi(RadioModems_t modem);
  * \param [IN]: addr Register address
  * \param [IN]: data New register value
  */
-void SX1276Write(uint8_t addr, uint8_t data);
+void SX1276Write(uint16_t addr, uint8_t data);
 
 /*!
  * \brief Reads the radio register at the specified address
@@ -359,7 +350,7 @@ void SX1276Write(uint8_t addr, uint8_t data);
  * \param [IN]: addr Register address
  * \retval data Register value
  */
-uint8_t SX1276Read(uint8_t addr);
+uint8_t SX1276Read(uint16_t addr);
 
 /*!
  * \brief Writes multiple radio registers starting at address
@@ -368,7 +359,7 @@ uint8_t SX1276Read(uint8_t addr);
  * \param [IN] buffer Buffer containing the new register's values
  * \param [IN] size   Number of registers to be written
  */
-void SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
+void SX1276WriteBuffer(uint16_t addr, uint8_t *buffer, uint8_t size);
 
 /*!
  * \brief Reads multiple radio registers starting at address
@@ -377,7 +368,7 @@ void SX1276WriteBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
  * \param [OUT] buffer Buffer where to copy the registers data
  * \param [IN] size Number of registers to be read
  */
-void SX1276ReadBuffer(uint8_t addr, uint8_t *buffer, uint8_t size);
+void SX1276ReadBuffer(uint16_t addr, uint8_t *buffer, uint8_t size);
 
 /*!
  * \brief Sets the maximum payload length.
@@ -396,4 +387,11 @@ void SX1276SetMaxPayloadLength(RadioModems_t modem, uint8_t max);
  */
 void SX1276SetPublicNetwork(bool enable);
 
+/*!
+ * \brief Gets the time required for the board plus radio to get out of sleep.[ms]
+ *
+ * \retval time Radio plus board wakeup time in ms.
+ */
+uint32_t SX1276GetWakeupTime(void);
+
 #endif // __SX1276_H__
diff --git a/net/lora/node/include/node/lora.h b/net/lora/node/include/node/lora.h
index 546ffe347..f12f8c381 100644
--- a/net/lora/node/include/node/lora.h
+++ b/net/lora/node/include/node/lora.h
@@ -41,6 +41,10 @@ STATS_SECT_START(lora_mac_stats)
     STATS_SECT_ENTRY(rx_mic_failures)
     STATS_SECT_ENTRY(rx_mlme)
     STATS_SECT_ENTRY(rx_mcps)
+    STATS_SECT_ENTRY(rx_dups)
+    STATS_SECT_ENTRY(rx_invalid)
+    STATS_SECT_ENTRY(no_bufs)
+    STATS_SECT_ENTRY(already_joined)
 STATS_SECT_END
 extern STATS_SECT_DECL(lora_mac_stats) lora_mac_stats;
 
@@ -156,7 +160,7 @@ struct lora_txd_info
     uint8_t ack_rxd: 1;
 
     /*!
-     * The transmission time on air of the frame
+     * The transmission time on air of the frame (in msecs)
      */
     uint32_t tx_time_on_air;
 
@@ -166,9 +170,9 @@ struct lora_txd_info
     uint32_t uplink_cntr;
 
     /*!
-     * The uplink frequency related to the frame
+     * The uplink channel related to the frame
      */
-    uint32_t uplink_freq;
+    uint32_t uplink_chan;
 };
 
 /*
diff --git a/net/lora/node/include/node/lora_band.h b/net/lora/node/include/node/lora_band.h
index 3dd4c33e0..4085c41ce 100644
--- a/net/lora/node/include/node/lora_band.h
+++ b/net/lora/node/include/node/lora_band.h
@@ -22,24 +22,51 @@
 
 #include "os/mynewt.h"
 
-#if   MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 433
-#define USE_BAND_433
-
-#elif MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 470
-#define USE_BAND_470
-
-#elif MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 780
-#define USE_BAND_780
-
-#elif MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 868
-#define USE_BAND_868
-
-#elif MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 915
-#define USE_BAND_915
-
-#elif MYNEWT_VAL(LORA_NODE_FREQ_BAND) == 916
-#define USE_BAND_915_HYBRID
+/* These definitions are required to include the code for a given region */
+#undef REGION_AS923
+#undef REGION_AU915
+#undef REGION_CN470
+#undef REGION_CN779
+#undef REGION_EU433
+#undef REGION_EU868
+#undef REGION_KR920
+#undef REGION_IN865
+#undef REGION_US915
+#undef REGION_US915_HYBRID
 
+/* This defines the currently active region */
+#if   MYNEWT_VAL(LORA_NODE_REGION) == 1
+#define LORA_NODE_REGION    LORAMAC_REGION_AS923
+#define REGION_AS923
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 2
+#define LORA_NODE_REGION    LORAMAC_REGION_AU915
+#define REGION_AU915
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 3
+#define LORA_NODE_REGION LORAMAC_REGION_CN470
+#define REGION_CN470
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 4
+#define LORA_NODE_REGION LORAMAC_REGION_CN779
+#define REGION_CN779
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 5
+#define LORA_NODE_REGION LORAMAC_REGION_EU433
+#define REGION_EU433
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 6
+#define LORA_NODE_REGION LORAMAC_REGION_EU868
+#define REGION_EU868
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 7
+#define LORA_NODE_REGION LORAMAC_REGION_KR920
+#define REGION_KR920
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 8
+#define LORA_NODE_REGION LORAMAC_REGION_IN865
+#define REGION_IN865
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 9
+#define LORA_NODE_REGION LORAMAC_REGION_US915
+#define REGION_US915
+#elif MYNEWT_VAL(LORA_NODE_REGION) == 10
+#define LORA_NODE_REGION LORAMAC_REGION_US915_HYBRID
+#define REGION_US915_HYBRID
+#else
+#error "Unknown region specified!"
 #endif
 
 #endif
diff --git a/net/lora/node/include/node/lora_priv.h b/net/lora/node/include/node/lora_priv.h
index 3460d51ee..d817123aa 100644
--- a/net/lora/node/include/node/lora_priv.h
+++ b/net/lora/node/include/node/lora_priv.h
@@ -23,12 +23,108 @@
 #include "node/mac/LoRaMac.h"
 #include "os/mynewt.h"
 #include "node/lora.h"
+#include "node/lora_band.h"
+
+/* Connection state machine flags. */
+union lora_mac_flags {
+    struct {
+        uint8_t gw_ack_req: 1;
+        uint8_t node_ack_req: 1;
+        uint8_t last_tx_join: 1;
+        uint8_t is_joined: 1;
+        uint8_t is_joining: 1;
+        uint8_t is_public_nwk: 1;
+        uint8_t is_mcps_req: 1;
+        uint8_t repeater_supp: 1;
+    } lmfbit;
+    uint8_t lmf_all;
+} __attribute__((packed));
 
 /*
  * Lora MAC data object
  */
 struct lora_mac_obj
 {
+    /* To limit # of join attempts */
+    uint8_t cur_join_attempt;
+    uint8_t max_join_attempt;
+
+    /* Current tx payload (N) */
+    uint8_t cur_tx_pyld;
+
+    /* current and last transmit channel used */
+    uint8_t cur_chan;
+    uint8_t last_tx_chan;
+
+    /*!
+     * Maximum duty cycle
+     * \remark Possibility to shutdown the device.
+     */
+    uint8_t max_dc;
+
+    /*!
+     * Number of trials to get a frame acknowledged
+     */
+    uint8_t ack_timeout_retries;
+
+    /*!
+     * Number of trials to get a frame acknowledged
+     */
+    uint8_t ack_timeout_retries_cntr;
+
+    /*!
+     * Uplink messages repetitions counter
+     */
+    uint8_t nb_rep_cntr;
+
+    /*!
+     * Device nonce is a random value extracted by issuing a sequence of RSSI
+     * measurements
+     */
+    uint16_t dev_nonce;
+
+    /*!
+     * Aggregated duty cycle management
+     */
+    uint16_t aggr_dc;
+    uint32_t aggr_last_tx_done_time;
+    uint32_t aggr_time_off;
+
+    /*!
+     * LoRaMac reception windows delay
+     * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
+     *         join frame  : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
+     */
+    uint32_t rx_win1_delay;
+    uint32_t rx_win2_delay;
+
+    /* uplink and downlink counters */
+    uint32_t uplink_cntr;
+    uint32_t downlink_cntr;
+
+    /*!
+     * Last transmission time on air (in msecs)
+     */
+    uint32_t tx_time_on_air;
+
+    /* Counts the number of missed ADR acknowledgements */
+    uint32_t adr_ack_cntr;
+
+    /*!
+     * Network ID ( 3 bytes )
+     */
+    uint32_t netid;
+
+    /*!
+     * Mote Address
+     */
+    uint32_t dev_addr;
+
+    /*!
+     * Holds the current rx window slot
+     */
+    LoRaMacRxSlot_t rx_slot;
+
     /* Task event queue */
     struct os_eventq lm_evq;
 
@@ -66,6 +162,14 @@ struct lora_mac_obj
     /* Pointer to current transmit mbuf. Can be NULL and still txing */
     struct os_mbuf *cur_tx_mbuf;
 
+    /*!
+     * Retransmission timer. This is used for confirmed frames on both class
+     * A and C devices and for unconfirmed transmissions on class C devices
+     * (so that a class C device will not transmit before listening on the
+     * second receive window).
+     */
+    struct hal_timer rtx_timer;
+
     /*
      * Global lora rx packet info structure. Used when receiving and prior to
      * obtaining a mbuf.
@@ -73,10 +177,32 @@ struct lora_mac_obj
     uint16_t rxbufsize;
     uint8_t *rxbuf;
     struct lora_pkt_info rxpkt;
+
+    /* Flags */
+    union lora_mac_flags lmflags;
+
+    /*!
+     * Stores the time at LoRaMac initialization.
+     *
+     * NOTE: units of this variable are in os time ticks
+     *
+     * \remark Used for the BACKOFF_DC computation.
+     */
+    os_time_t init_time;
 };
 
 extern struct lora_mac_obj g_lora_mac_data;
 
+/* Flag macros */
+#define LM_F_GW_ACK_REQ()       (g_lora_mac_data.lmflags.lmfbit.gw_ack_req)
+#define LM_F_NODE_ACK_REQ()     (g_lora_mac_data.lmflags.lmfbit.node_ack_req)
+#define LM_F_IS_JOINED()        (g_lora_mac_data.lmflags.lmfbit.is_joined)
+#define LM_F_IS_JOINING()       (g_lora_mac_data.lmflags.lmfbit.is_joining)
+#define LM_F_IS_PUBLIC_NWK()    (g_lora_mac_data.lmflags.lmfbit.is_public_nwk)
+#define LM_F_IS_MCPS_REQ()      (g_lora_mac_data.lmflags.lmfbit.is_mcps_req)
+#define LM_F_REPEATER_SUPP()    (g_lora_mac_data.lmflags.lmfbit.repeater_supp)
+#define LM_F_LAST_TX_IS_JOIN_REQ() (g_lora_mac_data.lmflags.lmfbit.last_tx_join)
+
 void lora_cli_init(void);
 void lora_app_init(void);
 
@@ -121,15 +247,19 @@ extern uint16_t g_lnd_log_index;
 /* IDs */
 #define LORA_NODE_LOG_UNUSED            (0)
 #define LORA_NODE_LOG_TX_DONE           (10)
-#define LORA_NODE_LOG_RX_WIN_SETUP      (20)
+#define LORA_NODE_LOG_TX_SETUP          (11)
+#define LORA_NODE_LOG_TX_START          (12)
+#define LORA_NODE_LOG_TX_DELAY          (15)
+#define LORA_NODE_LOG_TX_PREP_FRAME     (16)
+#define LORA_NODE_LOG_RX_WIN1_SETUP     (20)
 #define LORA_NODE_LOG_RX_TIMEOUT        (21)
 #define LORA_NODE_LOG_RX_DONE           (22)
-#define LORA_NODE_LOG_RX_SYNC_TIMEOUT   (23)
 #define LORA_NODE_LOG_RADIO_TIMEOUT_IRQ (24)
 #define LORA_NODE_LOG_RX_PORT           (25)
 #define LORA_NODE_LOG_RX_WIN2           (26)
-#define LORA_NODE_LOG_RX_WIN_SETUP_FAIL (27)
+#define LORA_NODE_LOG_RX_CFG            (27)
 #define LORA_NODE_LOG_APP_TX            (40)
+#define LORA_NODE_LOG_RTX_TIMEOUT       (50)
 #define LORA_NODE_LOG_RX_ADR_REQ        (80)
 #define LORA_NODE_LOG_PROC_MAC_CMD      (85)
 #define LORA_NODE_LOG_LINK_CHK          (90)
diff --git a/net/lora/node/include/node/mac/LoRaMac-definitions.h b/net/lora/node/include/node/mac/LoRaMac-definitions.h
deleted file mode 100644
index c6f903aef..000000000
--- a/net/lora/node/include/node/mac/LoRaMac-definitions.h
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
-
-Description: LoRa MAC layer global definitions
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis and Gregory Cristian
-*/
-#ifndef __LORAMAC_BOARD_H__
-#define __LORAMAC_BOARD_H__
-
-#include "node/lora_band.h"
-
-/*!
- * Returns individual channel mask
- *
- * \param[IN] channelIndex Channel index 1 based
- * \retval channelMask
- */
-#define LC( channelIndex )            ( uint16_t )( 1 << ( channelIndex - 1 ) )
-
-#if defined( USE_BAND_433 )
-
-/*!
- * LoRaMac maximum number of channels
- */
-#define LORA_MAX_NB_CHANNELS                        16
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_TX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_TX_MAX_DATARATE                     DR_7
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_RX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_RX_MAX_DATARATE                     DR_7
-
-/*!
- * Default datarate used by the node
- */
-#define LORAMAC_DEFAULT_DATARATE                    DR_0
-
-/*!
- * Minimal Rx1 receive datarate offset
- */
-#define LORAMAC_MIN_RX1_DR_OFFSET                   0
-
-/*!
- * Maximal Rx1 receive datarate offset
- */
-#define LORAMAC_MAX_RX1_DR_OFFSET                   5
-
-/*!
- * Minimal Tx output power that can be used by the node
- */
-#define LORAMAC_MIN_TX_POWER                        TX_POWER_M5_DBM
-
-/*!
- * Maximal Tx output power that can be used by the node
- */
-#define LORAMAC_MAX_TX_POWER                        TX_POWER_10_DBM
-
-/*!
- * Default Tx output power used by the node
- */
-#define LORAMAC_DEFAULT_TX_POWER                    TX_POWER_10_DBM
-
-/*!
- * LoRaMac TxPower definition
- */
-#define TX_POWER_10_DBM                             0
-#define TX_POWER_07_DBM                             1
-#define TX_POWER_04_DBM                             2
-#define TX_POWER_01_DBM                             3
-#define TX_POWER_M2_DBM                             4
-#define TX_POWER_M5_DBM                             5
-
-/*!
- * LoRaMac datarates definition
- */
-#define DR_0                                        0  // SF12 - BW125
-#define DR_1                                        1  // SF11 - BW125
-#define DR_2                                        2  // SF10 - BW125
-#define DR_3                                        3  // SF9  - BW125
-#define DR_4                                        4  // SF8  - BW125
-#define DR_5                                        5  // SF7  - BW125
-#define DR_6                                        6  // SF7  - BW250
-#define DR_7                                        7  // FSK
-
-/*!
- * Verification of default datarate
- */
-#if ( LORAMAC_DEFAULT_DATARATE > DR_5 )
-#error "A default DR higher than DR_5 may lead to connectivity loss."
-#endif
-
-/*!
- * Second reception window channel definition.
- */
-// Channel = { Frequency [Hz], Datarate }
-#define RX_WND_2_CHANNEL                                  { 434665000, DR_0 }
-
-/*!
- * LoRaMac maximum number of bands
- */
-#define LORA_MAX_NB_BANDS                           1
-
-// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
-#define BAND0              { 100, TX_POWER_10_DBM, 0,  0 } //  1.0 %
-
-/*!
- * LoRaMac default channels
- */
-// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
-#define LC1                { 433175000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-#define LC2                { 433375000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-#define LC3                { 433575000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-
-/*!
- * LoRaMac channels which are allowed for the join procedure
- */
-#define JOIN_CHANNELS      ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
-
-#elif defined( USE_BAND_470 )
-
-/*!
- * LoRaMac maximum number of channels
- */
-#define LORA_MAX_NB_CHANNELS                        96
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_TX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_TX_MAX_DATARATE                     DR_5
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_RX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_RX_MAX_DATARATE                     DR_5
-
-/*!
- * Default datarate used by the node
- */
-#define LORAMAC_DEFAULT_DATARATE                    DR_0
-
-/*!
- * Minimal Rx1 receive datarate offset
- */
-#define LORAMAC_MIN_RX1_DR_OFFSET                   0
-
-/*!
- * Maximal Rx1 receive datarate offset
- */
-#define LORAMAC_MAX_RX1_DR_OFFSET                   3
-
-/*!
- * Minimal Tx output power that can be used by the node
- */
-#define LORAMAC_MIN_TX_POWER                        TX_POWER_2_DBM
-
-/*!
- * Maximal Tx output power that can be used by the node
- */
-#define LORAMAC_MAX_TX_POWER                        TX_POWER_17_DBM
-
-/*!
- * Default Tx output power used by the node
- */
-#define LORAMAC_DEFAULT_TX_POWER                    TX_POWER_14_DBM
-
-/*!
- * LoRaMac TxPower definition
- */
-#define TX_POWER_17_DBM                             0
-#define TX_POWER_16_DBM                             1
-#define TX_POWER_14_DBM                             2
-#define TX_POWER_12_DBM                             3
-#define TX_POWER_10_DBM                             4
-#define TX_POWER_7_DBM                              5
-#define TX_POWER_5_DBM                              6
-#define TX_POWER_2_DBM                              7
-
-
-/*!
- * LoRaMac datarates definition
- */
-#define DR_0                                        0  // SF12 - BW125 |
-#define DR_1                                        1  // SF11 - BW125 |
-#define DR_2                                        2  // SF10 - BW125 |
-#define DR_3                                        3  // SF9  - BW125 |
-#define DR_4                                        4  // SF8  - BW125 |
-#define DR_5                                        5  // SF7  - BW125 |
-
-/*!
- * Second reception window channel definition.
- */
-// Channel = { Frequency [Hz], Datarate }
-#define RX_WND_2_CHANNEL                                  { 505300000, DR_0 }
-
-/*!
- * LoRaMac maximum number of bands
- */
-#define LORA_MAX_NB_BANDS                           1
-
-// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
-#define BAND0              { 1, TX_POWER_17_DBM, 0,  0 } //  100.0 %
-
-#elif defined( USE_BAND_780 )
-
-/*!
- * LoRaMac maximum number of channels
- */
-#define LORA_MAX_NB_CHANNELS                        16
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_TX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_TX_MAX_DATARATE                     DR_7
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_RX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_RX_MAX_DATARATE                     DR_7
-
-/*!
- * Default datarate used by the node
- */
-#define LORAMAC_DEFAULT_DATARATE                    DR_0
-
-/*!
- * Minimal Rx1 receive datarate offset
- */
-#define LORAMAC_MIN_RX1_DR_OFFSET                   0
-
-/*!
- * Maximal Rx1 receive datarate offset
- */
-#define LORAMAC_MAX_RX1_DR_OFFSET                   5
-
-/*!
- * Minimal Tx output power that can be used by the node
- */
-#define LORAMAC_MIN_TX_POWER                        TX_POWER_M5_DBM
-
-/*!
- * Maximal Tx output power that can be used by the node
- */
-#define LORAMAC_MAX_TX_POWER                        TX_POWER_10_DBM
-
-/*!
- * Default Tx output power used by the node
- */
-#define LORAMAC_DEFAULT_TX_POWER                    TX_POWER_10_DBM
-
-/*!
- * LoRaMac TxPower definition
- */
-#define TX_POWER_10_DBM                             0
-#define TX_POWER_07_DBM                             1
-#define TX_POWER_04_DBM                             2
-#define TX_POWER_01_DBM                             3
-#define TX_POWER_M2_DBM                             4
-#define TX_POWER_M5_DBM                             5
-
-/*!
- * LoRaMac datarates definition
- */
-#define DR_0                                        0  // SF12 - BW125
-#define DR_1                                        1  // SF11 - BW125
-#define DR_2                                        2  // SF10 - BW125
-#define DR_3                                        3  // SF9  - BW125
-#define DR_4                                        4  // SF8  - BW125
-#define DR_5                                        5  // SF7  - BW125
-#define DR_6                                        6  // SF7  - BW250
-#define DR_7                                        7  // FSK
-
-/*!
- * Verification of default datarate
- */
-#if ( LORAMAC_DEFAULT_DATARATE > DR_5 )
-#error "A default DR higher than DR_5 may lead to connectivity loss."
-#endif
-
-/*!
- * Second reception window channel definition.
- */
-// Channel = { Frequency [Hz], Datarate }
-#define RX_WND_2_CHANNEL                                  { 786000000, DR_0 }
-
-/*!
- * LoRaMac maximum number of bands
- */
-#define LORA_MAX_NB_BANDS                           1
-
-// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
-#define BAND0              { 100, TX_POWER_10_DBM, 0,  0 } //  1.0 %
-
-/*!
- * LoRaMac default channels
- */
-// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
-#define LC1                { 779500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-#define LC2                { 779700000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-#define LC3                { 779900000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
-
-/*!
- * LoRaMac channels which are allowed for the join procedure
- */
-#define JOIN_CHANNELS      ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
-
-#elif defined( USE_BAND_868 )
-
-/*!
- * LoRaMac maximum number of channels
- */
-#define LORA_MAX_NB_CHANNELS                        16
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_TX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_TX_MAX_DATARATE                     DR_7
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_RX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_RX_MAX_DATARATE                     DR_7
-
-/*!
- * Default datarate used by the node
- */
-#define LORAMAC_DEFAULT_DATARATE                    DR_0
-
-/*!
- * Minimal Rx1 receive datarate offset
- */
-#define LORAMAC_MIN_RX1_DR_OFFSET                   0
-
-/*!
- * Maximal Rx1 receive datarate offset
- */
-#define LORAMAC_MAX_RX1_DR_OFFSET                   5
-
-/*!
- * Minimal Tx output power that can be used by the node
- */
-#define LORAMAC_MIN_TX_POWER                        TX_POWER_02_DBM
-
-/*!
- * Maximal Tx output power that can be used by the node
- */
-#define LORAMAC_MAX_TX_POWER                        TX_POWER_20_DBM
-
-/*!
- * Default Tx output power used by the node
- */
-#define LORAMAC_DEFAULT_TX_POWER                    TX_POWER_14_DBM
-
-/*!
- * LoRaMac TxPower definition
- */
-#define TX_POWER_20_DBM                             0
-#define TX_POWER_14_DBM                             1
-#define TX_POWER_11_DBM                             2
-#define TX_POWER_08_DBM                             3
-#define TX_POWER_05_DBM                             4
-#define TX_POWER_02_DBM                             5
-
-/*!
- * LoRaMac datarates definition
- */
-#define DR_0                                        0  // SF12 - BW125
-#define DR_1                                        1  // SF11 - BW125
-#define DR_2                                        2  // SF10 - BW125
-#define DR_3                                        3  // SF9  - BW125
-#define DR_4                                        4  // SF8  - BW125
-#define DR_5                                        5  // SF7  - BW125
-#define DR_6                                        6  // SF7  - BW250
-#define DR_7                                        7  // FSK
-
-/*!
- * Verification of default datarate
- */
-#if ( LORAMAC_DEFAULT_DATARATE > DR_5 )
-#error "A default DR higher than DR_5 may lead to connectivity loss."
-#endif
-
-/*!
- * Second reception window channel definition.
- */
-// Channel = { Frequency [Hz], Datarate }
-#define RX_WND_2_CHANNEL                                  { 869525000, DR_0 }
-
-/*!
- * LoRaMac maximum number of bands
- */
-#define LORA_MAX_NB_BANDS                           5
-
-/*!
- * LoRaMac EU868 default bands
- */
-typedef enum
-{
-    BAND_G1_0,
-    BAND_G1_1,
-    BAND_G1_2,
-    BAND_G1_3,
-    BAND_G1_4,
-}BandId_t;
-
-// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
-#define BAND0              { 100 , TX_POWER_14_DBM, 0,  0 } //  1.0 %
-#define BAND1              { 100 , TX_POWER_14_DBM, 0,  0 } //  1.0 %
-#define BAND2              { 1000, TX_POWER_14_DBM, 0,  0 } //  0.1 %
-#define BAND3              { 10  , TX_POWER_14_DBM, 0,  0 } // 10.0 %
-#define BAND4              { 100 , TX_POWER_14_DBM, 0,  0 } //  1.0 %
-
-/*!
- * LoRaMac default channels
- */
-// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
-#define LC1                { 868100000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
-#define LC2                { 868300000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
-#define LC3                { 868500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
-
-/*!
- * LoRaMac channels which are allowed for the join procedure
- */
-#define JOIN_CHANNELS      ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
-
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-
-/*!
- * LoRaMac maximum number of channels
- */
-#define LORA_MAX_NB_CHANNELS                        72
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_TX_MIN_DATARATE                     DR_0
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_TX_MAX_DATARATE                     DR_4
-
-/*!
- * Minimal datarate that can be used by the node
- */
-#define LORAMAC_RX_MIN_DATARATE                     DR_8
-
-/*!
- * Maximal datarate that can be used by the node
- */
-#define LORAMAC_RX_MAX_DATARATE                     DR_13
-
-/*!
- * Default datarate used by the node
- */
-#define LORAMAC_DEFAULT_DATARATE                    DR_0
-
-/*!
- * Minimal Rx1 receive datarate offset
- */
-#define LORAMAC_MIN_RX1_DR_OFFSET                   0
-
-/*!
- * Maximal Rx1 receive datarate offset
- */
-#define LORAMAC_MAX_RX1_DR_OFFSET                   3
-
-/*!
- * Minimal Tx output power that can be used by the node
- */
-#define LORAMAC_MIN_TX_POWER                        TX_POWER_10_DBM
-
-/*!
- * Maximal Tx output power that can be used by the node
- */
-#define LORAMAC_MAX_TX_POWER                        TX_POWER_30_DBM
-
-/*!
- * Default Tx output power used by the node
- */
-#define LORAMAC_DEFAULT_TX_POWER                    TX_POWER_20_DBM
-
-/*!
- * LoRaMac TxPower definition
- */
-#define TX_POWER_30_DBM                             0
-#define TX_POWER_28_DBM                             1
-#define TX_POWER_26_DBM                             2
-#define TX_POWER_24_DBM                             3
-#define TX_POWER_22_DBM                             4
-#define TX_POWER_20_DBM                             5
-#define TX_POWER_18_DBM                             6
-#define TX_POWER_16_DBM                             7
-#define TX_POWER_14_DBM                             8
-#define TX_POWER_12_DBM                             9
-#define TX_POWER_10_DBM                             10
-
-/*!
- * LoRaMac datarates definition
- */
-#define DR_0                                        0  // SF10 - BW125 |
-#define DR_1                                        1  // SF9  - BW125 |
-#define DR_2                                        2  // SF8  - BW125 +-> Up link
-#define DR_3                                        3  // SF7  - BW125 |
-#define DR_4                                        4  // SF8  - BW500 |
-#define DR_5                                        5  // RFU
-#define DR_6                                        6  // RFU
-#define DR_7                                        7  // RFU
-#define DR_8                                        8  // SF12 - BW500 |
-#define DR_9                                        9  // SF11 - BW500 |
-#define DR_10                                       10 // SF10 - BW500 |
-#define DR_11                                       11 // SF9  - BW500 |
-#define DR_12                                       12 // SF8  - BW500 +-> Down link
-#define DR_13                                       13 // SF7  - BW500 |
-#define DR_14                                       14 // RFU          |
-#define DR_15                                       15 // RFU          |
-
-/*!
- * Second reception window channel definition.
- */
-// Channel = { Frequency [Hz], Datarate }
-#define RX_WND_2_CHANNEL                                  { 923300000, DR_8 }
-
-/*!
- * LoRaMac maximum number of bands
- */
-#define LORA_MAX_NB_BANDS                           1
-
-// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
-#define BAND0              { 1, TX_POWER_20_DBM, 0,  0 } //  100.0 %
-
-/*!
- * LoRaMac default channels
- */
-// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
-/*
- * US band channels are initialized using a loop in LoRaMacInit function
- * \code
- * // 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;
- * }
- * \endcode
- */
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
-#endif // __LORAMAC_BOARD_H__
diff --git a/net/lora/node/include/node/mac/LoRaMac.h b/net/lora/node/include/node/mac/LoRaMac.h
index 34b3ac71c..d62e9beeb 100644
--- a/net/lora/node/include/node/mac/LoRaMac.h
+++ b/net/lora/node/include/node/mac/LoRaMac.h
@@ -12,7 +12,7 @@
  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
  *               _____) ) ____| | | || |_| ____( (___| | | |
  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
- *              (C)2013 Semtech
+ *              (C)2013-2017 Semtech
  *
  *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
  *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
@@ -26,7 +26,7 @@
  *
  * \author    Gregory Cristian ( Semtech )
  *
- * \author    Daniel Jäckle ( STACKFORCE )
+ * \author    Daniel Jaeckle ( STACKFORCE )
  *
  * \defgroup  LORAMAC LoRa MAC layer implementation
  *            This module specifies the API implementation of the LoRaMAC layer.
@@ -49,71 +49,13 @@
 #include <stdbool.h>
 
 // Includes board dependent definitions such as channels frequencies
-#include "node/mac/LoRaMac-definitions.h"
 #include "node/utilities.h"
 #include "os/mynewt.h"
+#include "node/lora_band.h"
+#include "radio/radio.h"
 
 struct lora_pkt_info;
 
-/*!
- * Beacon interval in ms
- */
-#define BEACON_INTERVAL                             128000
-
-/*!
- * Class A&B receive delay 1 in ms
- */
-#define RECEIVE_DELAY1                              1000
-
-/*!
- * Class A&B receive delay 2 in ms
- */
-#define RECEIVE_DELAY2                              2000
-
-/*!
- * Join accept receive delay 1 in ms
- */
-#define JOIN_ACCEPT_DELAY1                          5000
-
-/*!
- * Join accept receive delay 2 in ms
- */
-#define JOIN_ACCEPT_DELAY2                          6000
-
-/*!
- * Class A&B maximum receive window delay in ms
- */
-#define MAX_RX_WINDOW                               3000
-
-/*!
- * Maximum allowed gap for the FCNT field
- */
-#define MAX_FCNT_GAP                                16384
-
-/*!
- * ADR acknowledgement counter limit
- */
-#define ADR_ACK_LIMIT                               64
-
-/*!
- * Number of ADR acknowledgement requests before returning to default datarate
- */
-#define ADR_ACK_DELAY                               32
-
-/*!
- * Number of seconds after the start of the second reception window without
- * receiving an acknowledge.
- * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND )
- */
-#define ACK_TIMEOUT                                 2000
-
-/*!
- * Random number of seconds after the start of the second reception window without
- * receiving an acknowledge
- * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND )
- */
-#define ACK_TIMEOUT_RND                             1000
-
 /*!
  * Check the Mac layer state every MAC_STATE_CHECK_TIMEOUT in ms
  */
@@ -124,11 +66,6 @@ struct lora_pkt_info;
  */
 #define MAX_ACK_RETRIES                             8
 
-/*!
- * RSSI free threshold [dBm]
- */
-#define RSSI_FREE_TH                                ( int8_t )( -90 )
-
 /*!
  * Frame direction definition for up-link communications
  */
@@ -145,27 +82,36 @@ struct lora_pkt_info;
  */
 #define LORAMAC_MFR_LEN                             4
 
+/*!
+ * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
+ * in RxWindowSetup function.
+ * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD
+ */
+#define LORA_MAC_FRMPAYLOAD_OVERHEAD                13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
+
 /*!
  * LoRaWAN devices classes definition
+ *
+ * LoRaWAN Specification V1.0.2, chapter 2.1
  */
 typedef enum eDeviceClass
 {
     /*!
      * LoRaWAN device class A
      *
-     * LoRaWAN Specification V1.0.1, chapter 3ff
+     * LoRaWAN Specification V1.0.2, chapter 3
      */
     CLASS_A,
     /*!
      * LoRaWAN device class B
      *
-     * LoRaWAN Specification V1.0.1, chapter 8ff
+     * LoRaWAN Specification V1.0.2, chapter 8
      */
     CLASS_B,
     /*!
      * LoRaWAN device class C
      *
-     * LoRaWAN Specification V1.0.1, chapter 17ff
+     * LoRaWAN Specification V1.0.2, chapter 17
      */
     CLASS_C,
 }DeviceClass_t;
@@ -187,17 +133,17 @@ typedef union uDrRange
          /*!
          * Minimum data rate
          *
-         * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
+         * LoRaWAN Regional Parameters V1.0.2rB
          *
-         * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4]
+         * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
          */
         int8_t Min : 4;
         /*!
          * Maximum data rate
          *
-         * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
+         * LoRaWAN Regional Parameters V1.0.2rB
          *
-         * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4]
+         * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
          */
         int8_t Max : 4;
     }Fields;
@@ -216,14 +162,18 @@ typedef struct sBand
      * Maximum Tx power
      */
     int8_t TxMaxPower;
+    /*!
+     * Time stamp of the last JoinReq Tx frame.
+     */
+    TimerTime_t LastJoinTxDoneTime;
     /*!
      * Time stamp of the last Tx frame
      */
-    uint32_t LastTxDoneTime;
+    TimerTime_t LastTxDoneTime;
     /*!
      * Holds the time where the device is off
      */
-    uint32_t TimeOff;
+    TimerTime_t TimeOff;
 }Band_t;
 
 /*!
@@ -235,6 +185,10 @@ typedef struct sChannelParams
      * Frequency in Hz
      */
     uint32_t Frequency;
+    /*!
+     * Alternative frequency for RX window 1
+     */
+    uint32_t Rx1Frequency;
     /*!
      * Data rate definition
      */
@@ -257,13 +211,36 @@ typedef struct sRx2ChannelParams
     /*!
      * Data rate
      *
-     * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
-     * US915 - [DR_8, DR_9, DR_10, DR_11, DR_12, DR_13]
+     * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
      */
     uint8_t  Datarate;
 }Rx2ChannelParams_t;
 
+/*!
+ * LoRaMAC receive window enumeration
+ */
+typedef enum eLoRaMacRxSlot
+{
+    /*!
+     * LoRaMAC receive window 1
+     */
+    RX_SLOT_WIN_1,
+    /*!
+     * LoRaMAC receive window 2
+     */
+    RX_SLOT_WIN_2,
+    /*!
+     * LoRaMAC receive window 2 for class c - continuous listening
+     */
+    RX_SLOT_WIN_CLASS_C,
+    /*!
+     * LoRaMAC class b ping slot window
+     */
+    RX_SLOT_WIN_PING_SLOT
+}LoRaMacRxSlot_t;
+
 /*!
  * Global MAC layer parameters
  */
@@ -321,9 +298,21 @@ typedef struct sLoRaMacParams
      */
     Rx2ChannelParams_t Rx2Channel;
     /*!
-     * Mask indicating which channels are enabled
+     * Uplink dwell time configuration. 0: No limit, 1: 400ms
      */
-    uint16_t ChannelsMask[6];
+    uint8_t UplinkDwellTime;
+    /*!
+     * Downlink dwell time configuration. 0: No limit, 1: 400ms
+     */
+    uint8_t DownlinkDwellTime;
+    /*!
+     * Maximum possible EIRP
+     */
+    float MaxEirp;
+    /*!
+     * Antenna gain of the node
+     */
+    float AntennaGain;
 }LoRaMacParams_t;
 
 /*!
@@ -356,7 +345,7 @@ typedef struct sMulticastParams
 /*!
  * LoRaMAC frame types
  *
- * LoRaWAN Specification V1.0.1, chapter 4.2.1, table 1
+ * LoRaWAN Specification V1.0.2, chapter 4.2.1, table 1
  */
 typedef enum eLoRaMacFrameType
 {
@@ -397,7 +386,7 @@ typedef enum eLoRaMacFrameType
 /*!
  * LoRaMAC mote MAC commands
  *
- * LoRaWAN Specification V1.0.1, chapter 5, table 4
+ * LoRaWAN Specification V1.0.2, chapter 5, table 4
  */
 typedef enum eLoRaMacMoteCmd
 {
@@ -429,14 +418,22 @@ typedef enum eLoRaMacMoteCmd
      * RXTimingSetupAns
      */
     MOTE_MAC_RX_TIMING_SETUP_ANS     = 0x08,
+    /*!
+     * TXParamSetupAns
+     */
+    MOTE_MAC_TX_PARAM_SETUP_ANS      = 0x09,
+    /*!
+     * DlChannelAns
+     */
+    MOTE_MAC_DL_CHANNEL_ANS          = 0x0A
 }LoRaMacMoteCmd_t;
 
-#define LORA_MAC_MAX_MAC_CMD_CID    (MOTE_MAC_RX_TIMING_SETUP_ANS)
+#define LORA_MAC_MAX_MAC_CMD_CID    (MOTE_MAC_DL_CHANNEL_ANS)
 
 /*!
  * LoRaMAC server MAC commands
  *
- * LoRaWAN Specification V1.0.1 chapter 5, table 4
+ * LoRaWAN Specification V1.0.2 chapter 5, table 4
  */
 typedef enum eLoRaMacSrvCmd
 {
@@ -468,6 +465,14 @@ typedef enum eLoRaMacSrvCmd
      * RXTimingSetupReq
      */
     SRV_MAC_RX_TIMING_SETUP_REQ      = 0x08,
+    /*!
+     * NewChannelReq
+     */
+    SRV_MAC_TX_PARAM_SETUP_REQ       = 0x09,
+    /*!
+     * DlChannelReq
+     */
+    SRV_MAC_DL_CHANNEL_REQ           = 0x0A,
 }LoRaMacSrvCmd_t;
 
 /*!
@@ -496,7 +501,7 @@ typedef enum eLoRaMacBatteryLevel
 /*!
  * LoRaMAC header field definition (MHDR field)
  *
- * LoRaWAN Specification V1.0.1, chapter 4.2
+ * LoRaWAN Specification V1.0.2, chapter 4.2
  */
 typedef union uLoRaMacHeader
 {
@@ -527,7 +532,7 @@ typedef union uLoRaMacHeader
 /*!
  * LoRaMAC frame control field definition (FCtrl)
  *
- * LoRaWAN Specification V1.0.1, chapter 4.3.1
+ * LoRaWAN Specification V1.0.2, chapter 4.3.1
  */
 typedef union uLoRaMacFrameCtrl
 {
@@ -580,6 +585,10 @@ typedef enum eLoRaMacEventInfoStatus
      * A Tx timeout occurred
      */
     LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT,
+    /*!
+     * An Rx timeout occurred on receive window 1
+     */
+    LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT,
     /*!
      * An Rx timeout occurred on receive window 2
      */
@@ -659,6 +668,10 @@ typedef union eLoRaMacFlags_t
          * MLME-Req pending
          */
         uint8_t MlmeReq         : 1;
+        /*!
+         * MLME-Ind pending
+         */
+        uint8_t MlmeInd         : 1;
         /*!
          * MAC cycle done
          */
@@ -685,29 +698,28 @@ typedef union eLoRaMacFlags_t
  *
  * Primitive        | Function
  * ---------------- | :---------------------:
- * MCPS-Request     | \ref lora_node_mcps_request
- * MLME-Confirm    | \ref lora_node_mac_mlme_confirm
- * MCPS-Confirm     | \ref lora_node_mac_mcps_confirm
- * MCPS-Indication  |  \ref lora_node_mac_mcps_indicate
+ * MCPS-Request     | \ref LoRaMacMlmeRequest
+ * MCPS-Confirm     | MacMcpsConfirm in \ref LoRaMacPrimitives_t
+ * MCPS-Indication  | MacMcpsIndication in \ref LoRaMacPrimitives_t
  */
 typedef enum eMcps
 {
     /*!
      * Unconfirmed LoRaMAC frame
      */
-    MCPS_UNCONFIRMED = 0,
+    MCPS_UNCONFIRMED,
     /*!
      * Confirmed LoRaMAC frame
      */
-    MCPS_CONFIRMED = 1,
+    MCPS_CONFIRMED,
     /*!
      * Multicast LoRaMAC frame
      */
-    MCPS_MULTICAST = 2,
+    MCPS_MULTICAST,
     /*!
      * Proprietary frame
      */
-    MCPS_PROPRIETARY = 3,
+    MCPS_PROPRIETARY,
 }Mcps_t;
 
 /*!
@@ -729,33 +741,39 @@ typedef enum eMcps
  * ---------------- | :---------------------:
  * MLME-Request     | \ref LoRaMacMlmeRequest
  * MLME-Confirm     | MacMlmeConfirm in \ref LoRaMacPrimitives_t
+ * MLME-Indication  | MacMlmeIndication in \ref LoRaMacPrimitives_t
  */
 typedef enum eMlme
 {
     /*!
      * Initiates the Over-the-Air activation
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.2
+     * LoRaWAN Specification V1.0.2, chapter 6.2
      */
-    MLME_JOIN = 0,
+    MLME_JOIN,
     /*!
      * LinkCheckReq - Connectivity validation
      *
-     * LoRaWAN Specification V1.0.1, chapter 5, table 4
+     * LoRaWAN Specification V1.0.2, chapter 5, table 4
      */
-    MLME_LINK_CHECK = 1,
+    MLME_LINK_CHECK,
     /*!
      * Sets Tx continuous wave mode
      *
      * LoRaWAN end-device certification
      */
-    MLME_TXCW = 2,
+    MLME_TXCW,
     /*!
      * Sets Tx continuous wave mode (new LoRa-Alliance CC definition)
      *
      * LoRaWAN end-device certification
      */
-    MLME_TXCW_1 = 3,
+    MLME_TXCW_1,
+    /*!
+     * Indicates that the application shall perform an uplink as
+     * soon as possible.
+     */
+    MLME_SCHEDULE_UPLINK
 }Mlme_t;
 
 /*!
@@ -766,23 +784,29 @@ typedef struct sMlmeReqJoin
     /*!
      * Globally unique end-device identifier
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.2.1
+     * LoRaWAN Specification V1.0.2, chapter 6.2.1
      */
     uint8_t *DevEui;
     /*!
      * Application identifier
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.1.2
+     * LoRaWAN Specification V1.0.2, chapter 6.1.2
      */
     uint8_t *AppEui;
     /*!
      * AES-128 application key
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.2.2
+     * LoRaWAN Specification V1.0.2, chapter 6.2.2
      */
     uint8_t *AppKey;
     /*!
-     * Number of trials for the join request.
+     * Datarate used for join request.
+     */
+    uint8_t Datarate;
+
+    /**
+     * Number of join requests to send before stopping join attempt
+     * (signalling upper layer that join process was terminated).
      */
     uint8_t NbTrials;
 }MlmeReqJoin_t;
@@ -867,6 +891,8 @@ typedef struct sMlmeReq
  * \ref MIB_MULTICAST_CHANNEL        | YES | NO
  * \ref MIB_SYSTEM_MAX_RX_ERROR      | YES | YES
  * \ref MIB_MIN_RX_SYMBOLS           | YES | YES
+ * \ref MIB_ANTENNA_GAIN             | YES | YES
+ * \ref MIB_DEFAULT_ANTENNA_GAIN     | YES | YES
  *
  * The following table provides links to the function implementations of the
  * related MIB primitives:
@@ -881,19 +907,19 @@ typedef enum eMib
     /*!
      * LoRaWAN device class
      *
-     * LoRaWAN Specification V1.0.1
+     * LoRaWAN Specification V1.0.2
      */
     MIB_DEVICE_CLASS,
     /*!
      * LoRaWAN Network joined attribute
      *
-     * LoRaWAN Specification V1.0.1
+     * LoRaWAN Specification V1.0.2
      */
     MIB_NETWORK_JOINED,
     /*!
      * Adaptive data rate
      *
-     * LoRaWAN Specification V1.0.1, chapter 4.3.1.1
+     * LoRaWAN Specification V1.0.2, chapter 4.3.1.1
      *
      * [true: ADR enabled, false: ADR disabled]
      */
@@ -901,31 +927,31 @@ typedef enum eMib
     /*!
      * Network identifier
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.1.1
+     * LoRaWAN Specification V1.0.2, chapter 6.1.1
      */
     MIB_NET_ID,
     /*!
      * End-device address
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.1.1
+     * LoRaWAN Specification V1.0.2, chapter 6.1.1
      */
     MIB_DEV_ADDR,
     /*!
      * Network session key
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.1.3
+     * LoRaWAN Specification V1.0.2, chapter 6.1.3
      */
     MIB_NWK_SKEY,
     /*!
      * Application session key
      *
-     * LoRaWAN Specification V1.0.1, chapter 6.1.4
+     * LoRaWAN Specification V1.0.2, chapter 6.1.4
      */
     MIB_APP_SKEY,
     /*!
      * Set the network type to public or private
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
      * [true: public network, false: private network]
      */
@@ -933,7 +959,7 @@ typedef enum eMib
     /*!
      * Support the operation with repeaters
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
      * [true: repeater support enabled, false: repeater support disabled]
      */
@@ -943,127 +969,111 @@ typedef enum eMib
      * pointer which references the first entry of the channel list. The
      * list is of size LORA_MAX_NB_CHANNELS
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_CHANNELS,
     /*!
      * Set receive window 2 channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 3.3.2
+     * LoRaWAN Specification V1.0.2, chapter 3.3.1
      */
     MIB_RX2_CHANNEL,
     /*!
      * Set receive window 2 channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 3.3.2
+     * LoRaWAN Specification V1.0.2, chapter 3.3.2
      */
     MIB_RX2_DEFAULT_CHANNEL,
     /*!
      * LoRaWAN channels mask
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_CHANNELS_MASK,
     /*!
      * LoRaWAN default channels mask
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_CHANNELS_DEFAULT_MASK,
     /*!
      * Set the number of repetitions on a channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 5.2
+     * LoRaWAN Specification V1.0.2, chapter 5.2
      */
     MIB_CHANNELS_NB_REP,
     /*!
      * Maximum receive window duration in [ms]
      *
-     * LoRaWAN Specification V1.0.1, chapter 3.3.3
+     * LoRaWAN Specification V1.0.2, chapter 3.3.3
      */
     MIB_MAX_RX_WINDOW_DURATION,
     /*!
      * Receive delay 1 in [ms]
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_RECEIVE_DELAY_1,
     /*!
      * Receive delay 2 in [ms]
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_RECEIVE_DELAY_2,
     /*!
      * Join accept delay 1 in [ms]
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_JOIN_ACCEPT_DELAY_1,
     /*!
      * Join accept delay 2 in [ms]
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      */
     MIB_JOIN_ACCEPT_DELAY_2,
     /*!
      * Default Data rate of a channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
-     *
-     * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
-     * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13]
+     * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
      */
     MIB_CHANNELS_DEFAULT_DATARATE,
     /*!
      * Data rate of a channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
-     * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
-     *
-     * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13]
+     * The allowed ranges are region specific. Please refer to \ref DR_0 to \ref DR_15 for details.
      */
     MIB_CHANNELS_DATARATE,
     /*!
      * Transmission power of a channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
-     *
-     * EU868 - [TX_POWER_20_DBM, TX_POWER_14_DBM, TX_POWER_11_DBM,
-     *          TX_POWER_08_DBM, TX_POWER_05_DBM, TX_POWER_02_DBM]
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
-     * US915 - [TX_POWER_30_DBM, TX_POWER_28_DBM, TX_POWER_26_DBM,
-     *          TX_POWER_24_DBM, TX_POWER_22_DBM, TX_POWER_20_DBM,
-     *          TX_POWER_18_DBM, TX_POWER_14_DBM, TX_POWER_12_DBM,
-     *          TX_POWER_10_DBM]
+     * The allowed ranges are region specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details.
      */
     MIB_CHANNELS_TX_POWER,
     /*!
      * Transmission power of a channel
      *
-     * LoRaWAN Specification V1.0.1, chapter 7
-     *
-     * EU868 - [TX_POWER_20_DBM, TX_POWER_14_DBM, TX_POWER_11_DBM,
-     *          TX_POWER_08_DBM, TX_POWER_05_DBM, TX_POWER_02_DBM]
+     * LoRaWAN Regional Parameters V1.0.2rB
      *
-     * US915 - [TX_POWER_30_DBM, TX_POWER_28_DBM, TX_POWER_26_DBM,
-     *          TX_POWER_24_DBM, TX_POWER_22_DBM, TX_POWER_20_DBM,
-     *          TX_POWER_18_DBM, TX_POWER_14_DBM, TX_POWER_12_DBM,
-     *          TX_POWER_10_DBM]
+     * The allowed ranges are region specific. Please refer to \ref TX_POWER_0 to \ref TX_POWER_15 for details.
      */
     MIB_CHANNELS_DEFAULT_TX_POWER,
     /*!
      * LoRaWAN Up-link counter
      *
-     * LoRaWAN Specification V1.0.1, chapter 4.3.1.5
+     * LoRaWAN Specification V1.0.2, chapter 4.3.1.5
      */
     MIB_UPLINK_COUNTER,
     /*!
      * LoRaWAN Down-link counter
      *
-     * LoRaWAN Specification V1.0.1, chapter 4.3.1.5
+     * LoRaWAN Specification V1.0.2, chapter 4.3.1.5
      */
     MIB_DOWNLINK_COUNTER,
     /*!
@@ -1083,6 +1093,20 @@ typedef enum eMib
      * Default: 6 symbols
      */
     MIB_MIN_RX_SYMBOLS,
+    /*!
+     * Antenna gain of the node. Default value is region specific.
+     * The antenna gain is used to calculate the TX power of the node.
+     * The formula is:
+     * radioTxPower = ( int8_t )floor( maxEirp - antennaGain )
+     */
+    MIB_ANTENNA_GAIN,
+    /*!
+     * Default antenna gain of the node. Default value is region specific.
+     * The antenna gain is used to calculate the TX power of the node.
+     * The formula is:
+     * radioTxPower = ( int8_t )floor( maxEirp - antennaGain )
+     */
+    MIB_DEFAULT_ANTENNA_GAIN
 }Mib_t;
 
 /*!
@@ -1264,6 +1288,18 @@ typedef union uMibParam
      * Related MIB type: \ref MIB_MIN_RX_SYMBOLS
      */
     uint8_t MinRxSymbols;
+    /*!
+     * Antenna gain
+     *
+     * Related MIB type: \ref MIB_ANTENNA_GAIN
+     */
+    float AntennaGain;
+    /*!
+     * Default antenna gain
+     *
+     * Related MIB type: \ref MIB_DEFAULT_ANTENNA_GAIN
+     */
+    float DefaultAntennaGain;
 }MibParam_t;
 
 /*!
@@ -1335,19 +1371,87 @@ typedef enum eLoRaMacStatus
      */
     LORAMAC_STATUS_NO_NETWORK_JOINED,
     /*!
-     * Service not started - payload lenght error
+     * Service not started - payload length error
      */
     LORAMAC_STATUS_LENGTH_ERROR,
-    /*!
-     * Service not started - payload lenght error
-     */
-    LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR,
     /*!
      * Service not started - the device is switched off
      */
     LORAMAC_STATUS_DEVICE_OFF,
+    /*!
+     * Service not started - the specified region is not supported
+     * or not activated with preprocessor definitions.
+     */
+    LORAMAC_STATUS_REGION_NOT_SUPPORTED,
+    /*!
+     *
+     */
+    LORAMAC_STATUS_DUTYCYCLE_RESTRICTED,
+     /*!
+      *
+      */
+    LORAMAC_STATUS_NO_CHANNEL_FOUND,
+     /*!
+      *
+      */
+    LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND,
+
+    /*!
+     * Cannot send frame due to too many MAC commands
+     */
+    LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR
 }LoRaMacStatus_t;
 
+/*!
+ * LoRaMAC region enumeration
+ */
+typedef enum eLoRaMacRegion_t
+{
+    /*!
+     * AS band on 923MHz
+     */
+    LORAMAC_REGION_AS923,
+    /*!
+     * Australian band on 915MHz
+     */
+    LORAMAC_REGION_AU915,
+    /*!
+     * Chinese band on 470MHz
+     */
+    LORAMAC_REGION_CN470,
+    /*!
+     * Chinese band on 779MHz
+     */
+    LORAMAC_REGION_CN779,
+    /*!
+     * European band on 433MHz
+     */
+    LORAMAC_REGION_EU433,
+    /*!
+     * European band on 868MHz
+     */
+    LORAMAC_REGION_EU868,
+    /*!
+     * South korean band on 920MHz
+     */
+    LORAMAC_REGION_KR920,
+    /*!
+     * India band on 865MHz
+     */
+    LORAMAC_REGION_IN865,
+    /*!
+     * North american band on 915MHz
+     */
+    LORAMAC_REGION_US915,
+    /*!
+     * North american band on 915MHz with a maximum of 16 channels
+     */
+    LORAMAC_REGION_US915_HYBRID,
+}LoRaMacRegion_t;
+
+/*!
+ * LoRaMAC callback structure
+ */
 typedef struct sLoRaMacCallback
 {
     /*!
@@ -1361,22 +1465,35 @@ typedef struct sLoRaMacCallback
     uint8_t ( *GetBatteryLevel )( void );
 }LoRaMacCallback_t;
 
+/*!
+ * LoRaMAC Max EIRP (dBm) table
+ */
+static const uint8_t LoRaMacMaxEirpTable[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 };
+
 /*!
  * \brief   LoRaMAC layer initialization
  *
  * \details In addition to the initialization of the LoRaMAC layer, this
  *          function initializes the callback primitives of the MCPS and
- *          MLME services.
+ *          MLME services. Every data field of \ref LoRaMacPrimitives_t must be
+ *          set to a valid callback function.
+ *
+ * \param   [IN] primitives - Pointer to a structure defining the LoRaMAC
+ *                            event functions. Refer to \ref LoRaMacPrimitives_t.
  *
  * \param   [IN] events - Pointer to a structure defining the LoRaMAC
  *                        callback functions. Refer to \ref LoRaMacCallback_t.
  *
+ * \param   [IN] region - The region to start.
+ *
  * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
  *          returns are:
  *          \ref LORAMAC_STATUS_OK,
- *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID,
+ *          \ref LORAMAC_STATUS_REGION_NOT_SUPPORTED.
  */
-LoRaMacStatus_t LoRaMacInitialization( LoRaMacCallback_t *callbacks );
+LoRaMacStatus_t LoRaMacInitialization(LoRaMacCallback_t *callbacks,
+                                      LoRaMacRegion_t region);
 
 /*!
  * \brief   Queries the LoRaMAC if it is possible to send the next frame with
@@ -1393,11 +1510,13 @@ LoRaMacStatus_t LoRaMacInitialization( LoRaMacCallback_t *callbacks );
  *
  * \retval  LoRaMacStatus_t Status of the operation. When the parameters are
  *          not valid, the function returns \ref LORAMAC_STATUS_PARAMETER_INVALID.
- *          In case of a length error caused by the applicative payload size, the
- *          function returns LORAMAC_STATUS_LENGTH_ERROR. In case of a length error
- *          due to additional MAC commands in the queue, the function returns
- *          LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR. In case the query is valid, and
- *          the LoRaMAC is able to send the frame, the function returns LORAMAC_STATUS_OK. *
+ *          In case of a length error caused by the applicative payload in combination
+ *          with the MAC commands, the function returns \ref LORAMAC_STATUS_LENGTH_ERROR.
+ *          Please note that if the size of the MAC commands which are in the queue do
+ *          not fit into the payload size on the related datarate, the LoRaMAC will
+ *          omit the MAC commands.
+ *          In case the query is valid, and the LoRaMAC is able to send the frame,
+ *          the function returns \ref LORAMAC_STATUS_OK.
  */
 LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo );
 
@@ -1405,14 +1524,10 @@ LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo );
  * \brief   LoRaMAC channel add service
  *
  * \details Adds a new channel to the channel list and activates the id in
- *          the channel mask. For the US915 band, all channels are enabled
- *          by default. It is not possible to activate less than 6 125 kHz
- *          channels.
- *
- * \param   [IN] id - Id of the channel. Possible values are:
+ *          the channel mask. Please note that this functionality is not available
+ *          on all regions. Information about allowed ranges are available at the LoRaWAN Regional Parameters V1.0.2rB
  *
- *          0-15 for EU868
- *          0-72 for US915
+ * \param   [IN] id - Id of the channel.
  *
  * \param   [IN] params - Channel parameters to set.
  *
@@ -1606,6 +1721,8 @@ LoRaMacMcpsRequest(struct os_mbuf *om, struct lora_pkt_info *txi);
  */
 LoRaMacStatus_t lora_mac_tx_state(void);
 
+#include "node/mac/Region.h"
+
 /*! \} defgroup LORAMAC */
 
 #endif // __LORAMAC_H__
diff --git a/net/lora/node/include/node/mac/Region.h b/net/lora/node/include/node/mac/Region.h
new file mode 100644
index 000000000..7d0ad3f5a
--- /dev/null
+++ b/net/lora/node/include/node/mac/Region.h
@@ -0,0 +1,1479 @@
+/*!
+ * \file      Region.h
+ *
+ * \brief     Region implementation.
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGION Region implementation
+ *            This is the common API to access the specific
+ *            regional implementations.
+ *
+ *            Preprocessor options:
+ *            - LoRaWAN regions can be activated by defining the related preprocessor
+ *              definition. It is possible to define more than one region.
+ *              The following regions are supported:
+ *              - #define REGION_AS923
+ *              - #define REGION_AU915
+ *              - #define REGION_CN470
+ *              - #define REGION_CN779
+ *              - #define REGION_EU433
+ *              - #define REGION_EU868
+ *              - #define REGION_KR920
+ *              - #define REGION_IN865
+ *              - #define REGION_US915
+ *              - #define REGION_US915_HYBRID
+ *
+ * \{
+ */
+#ifndef __REGION_H__
+#define __REGION_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/*!
+ * Macro to compute bit of a channel index.
+ */
+#define LC( channelIndex )                          ( uint16_t )( 1 << ( channelIndex - 1 ) )
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF12 - BW125
+ * AU915        | SF10 - BW125
+ * CN470        | SF12 - BW125
+ * CN779        | SF12 - BW125
+ * EU433        | SF12 - BW125
+ * EU868        | SF12 - BW125
+ * IN865        | SF12 - BW125
+ * KR920        | SF12 - BW125
+ * US915        | SF10 - BW125
+ * US915_HYBRID | SF10 - BW125
+ */
+#define DR_0                                        0
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF11 - BW125
+ * AU915        | SF9  - BW125
+ * CN470        | SF11 - BW125
+ * CN779        | SF11 - BW125
+ * EU433        | SF11 - BW125
+ * EU868        | SF11 - BW125
+ * IN865        | SF11 - BW125
+ * KR920        | SF11 - BW125
+ * US915        | SF9  - BW125
+ * US915_HYBRID | SF9  - BW125
+ */
+#define DR_1                                        1
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF10 - BW125
+ * AU915        | SF8  - BW125
+ * CN470        | SF10 - BW125
+ * CN779        | SF10 - BW125
+ * EU433        | SF10 - BW125
+ * EU868        | SF10 - BW125
+ * IN865        | SF10 - BW125
+ * KR920        | SF10 - BW125
+ * US915        | SF8  - BW125
+ * US915_HYBRID | SF8  - BW125
+ */
+#define DR_2                                        2
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF9  - BW125
+ * AU915        | SF7  - BW125
+ * CN470        | SF9  - BW125
+ * CN779        | SF9  - BW125
+ * EU433        | SF9  - BW125
+ * EU868        | SF9  - BW125
+ * IN865        | SF9  - BW125
+ * KR920        | SF9  - BW125
+ * US915        | SF7  - BW125
+ * US915_HYBRID | SF7  - BW125
+ */
+#define DR_3                                        3
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF8  - BW125
+ * AU915        | SF8  - BW500
+ * CN470        | SF8  - BW125
+ * CN779        | SF8  - BW125
+ * EU433        | SF8  - BW125
+ * EU868        | SF8  - BW125
+ * IN865        | SF8  - BW125
+ * KR920        | SF8  - BW125
+ * US915        | SF8  - BW500
+ * US915_HYBRID | SF8  - BW500
+ */
+#define DR_4                                        4
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF7  - BW125
+ * AU915        | RFU
+ * CN470        | SF7  - BW125
+ * CN779        | SF7  - BW125
+ * EU433        | SF7  - BW125
+ * EU868        | SF7  - BW125
+ * IN865        | SF7  - BW125
+ * KR920        | SF7  - BW125
+ * US915        | RFU
+ * US915_HYBRID | RFU
+ */
+#define DR_5                                        5
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | SF7  - BW250
+ * AU915        | RFU
+ * CN470        | SF12 - BW125
+ * CN779        | SF7  - BW250
+ * EU433        | SF7  - BW250
+ * EU868        | SF7  - BW250
+ * IN865        | SF7  - BW250
+ * KR920        | RFU
+ * US915        | RFU
+ * US915_HYBRID | RFU
+ */
+#define DR_6                                        6
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | FSK
+ * AU915        | RFU
+ * CN470        | SF12 - BW125
+ * CN779        | FSK
+ * EU433        | FSK
+ * EU868        | FSK
+ * IN865        | FSK
+ * KR920        | RFU
+ * US915        | RFU
+ * US915_HYBRID | RFU
+ */
+#define DR_7                                        7
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF12 - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF12 - BW500
+ * US915_HYBRID | SF12 - BW500
+ */
+#define DR_8                                        8
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF11 - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF11 - BW500
+ * US915_HYBRID | SF11 - BW500
+ */
+#define DR_9                                        9
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF10 - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF10 - BW500
+ * US915_HYBRID | SF10 - BW500
+ */
+#define DR_10                                       10
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF9  - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF9  - BW500
+ * US915_HYBRID | SF9  - BW500
+ */
+#define DR_11                                       11
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF8  - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF8  - BW500
+ * US915_HYBRID | SF8  - BW500
+ */
+#define DR_12                                       12
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | SF7  - BW500
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | SF7  - BW500
+ * US915_HYBRID | SF7  - BW500
+ */
+#define DR_13                                       13
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | RFU
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | RFU
+ * US915_HYBRID | RFU
+ */
+#define DR_14                                       14
+
+/*!
+ * Region       | SF
+ * ------------ | :-----:
+ * AS923        | RFU
+ * AU915        | RFU
+ * CN470        | RFU
+ * CN779        | RFU
+ * EU433        | RFU
+ * EU868        | RFU
+ * IN865        | RFU
+ * KR920        | RFU
+ * US915        | RFU
+ * US915_HYBRID | RFU
+ */
+#define DR_15                                       15
+
+
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP
+ * AU915        | Max EIRP
+ * CN470        | Max EIRP
+ * CN779        | Max EIRP
+ * EU433        | Max EIRP
+ * EU868        | Max EIRP
+ * IN865        | Max EIRP
+ * KR920        | Max EIRP
+ * US915        | Max ERP
+ * US915_HYBRID | Max ERP
+ */
+#define TX_POWER_0                                  0
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 2
+ * AU915        | Max EIRP - 2
+ * CN470        | Max EIRP - 2
+ * CN779        | Max EIRP - 2
+ * EU433        | Max EIRP - 2
+ * EU868        | Max EIRP - 2
+ * IN865        | Max EIRP - 2
+ * KR920        | Max EIRP - 2
+ * US915        | Max ERP - 2
+ * US915_HYBRID | Max ERP - 2
+ */
+#define TX_POWER_1                                  1
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 4
+ * AU915        | Max EIRP - 4
+ * CN470        | Max EIRP - 4
+ * CN779        | Max EIRP - 4
+ * EU433        | Max EIRP - 4
+ * EU868        | Max EIRP - 4
+ * IN865        | Max EIRP - 4
+ * KR920        | Max EIRP - 4
+ * US915        | Max ERP - 4
+ * US915_HYBRID | Max ERP - 4
+ */
+#define TX_POWER_2                                  2
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 6
+ * AU915        | Max EIRP - 6
+ * CN470        | Max EIRP - 6
+ * CN779        | Max EIRP - 6
+ * EU433        | Max EIRP - 6
+ * EU868        | Max EIRP - 6
+ * IN865        | Max EIRP - 6
+ * KR920        | Max EIRP - 6
+ * US915        | Max ERP - 6
+ * US915_HYBRID | Max ERP - 6
+ */
+#define TX_POWER_3                                  3
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 8
+ * AU915        | Max EIRP - 8
+ * CN470        | Max EIRP - 8
+ * CN779        | Max EIRP - 8
+ * EU433        | Max EIRP - 8
+ * EU868        | Max EIRP - 8
+ * IN865        | Max EIRP - 8
+ * KR920        | Max EIRP - 8
+ * US915        | Max ERP - 8
+ * US915_HYBRID | Max ERP - 8
+ */
+#define TX_POWER_4                                  4
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 10
+ * AU915        | Max EIRP - 10
+ * CN470        | Max EIRP - 10
+ * CN779        | Max EIRP - 10
+ * EU433        | Max EIRP - 10
+ * EU868        | Max EIRP - 10
+ * IN865        | Max EIRP - 10
+ * KR920        | Max EIRP - 10
+ * US915        | Max ERP - 10
+ * US915_HYBRID | Max ERP - 10
+ */
+#define TX_POWER_5                                  5
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 12
+ * AU915        | Max EIRP - 12
+ * CN470        | Max EIRP - 12
+ * CN779        | -
+ * EU433        | -
+ * EU868        | Max EIRP - 12
+ * IN865        | Max EIRP - 12
+ * KR920        | Max EIRP - 12
+ * US915        | Max ERP - 12
+ * US915_HYBRID | Max ERP - 12
+ */
+#define TX_POWER_6                                  6
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | Max EIRP - 14
+ * AU915        | Max EIRP - 14
+ * CN470        | Max EIRP - 14
+ * CN779        | -
+ * EU433        | -
+ * EU868        | Max EIRP - 14
+ * IN865        | Max EIRP - 14
+ * KR920        | Max EIRP - 14
+ * US915        | Max ERP - 14
+ * US915_HYBRID | Max ERP - 14
+ */
+#define TX_POWER_7                                  7
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | -
+ * AU915        | Max EIRP - 16
+ * CN470        | -
+ * CN779        | -
+ * EU433        | -
+ * EU868        | -
+ * IN865        | Max EIRP - 16
+ * KR920        | -
+ * US915        | Max ERP - 16
+ * US915_HYBRID | Max ERP -16
+ */
+#define TX_POWER_8                                  8
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | -
+ * AU915        | Max EIRP - 18
+ * CN470        | -
+ * CN779        | -
+ * EU433        | -
+ * EU868        | -
+ * IN865        | Max EIRP - 18
+ * KR920        | -
+ * US915        | Max ERP - 16
+ * US915_HYBRID | Max ERP - 16
+ */
+#define TX_POWER_9                                  9
+
+/*!
+ * Region       | dBM
+ * ------------ | :-----:
+ * AS923        | -
+ * AU915        | Max EIRP - 20
+ * CN470        | -
+ * CN779        | -
+ * EU433        | -
+ * EU868        | -
+ * IN865        | Max EIRP - 20
+ * KR920        | -
+ * US915        | Max ERP - 10
+ * US915_HYBRID | Max ERP - 10
+ */
+#define TX_POWER_10                                 10
+
+/*!
+ * RFU
+ */
+#define TX_POWER_11                                 11
+
+/*!
+ * RFU
+ */
+#define TX_POWER_12                                 12
+
+/*!
+ * RFU
+ */
+#define TX_POWER_13                                 13
+
+/*!
+ * RFU
+ */
+#define TX_POWER_14                                 14
+
+/*!
+ * RFU
+ */
+#define TX_POWER_15                                 15
+
+
+
+/*!
+ * Enumeration of phy attributes.
+ */
+typedef enum ePhyAttribute
+{
+    /*!
+     * Minimum RX datarate.
+     */
+    PHY_MIN_RX_DR,
+    /*!
+     * Minimum TX datarate.
+     */
+    PHY_MIN_TX_DR,
+    /*!
+     * Maximum RX datarate.
+     */
+    PHY_MAX_RX_DR,
+    /*!
+     * Maximum TX datarate.
+     */
+    PHY_MAX_TX_DR,
+    /*!
+     * TX datarate.
+     */
+    PHY_TX_DR,
+    /*!
+     * Default TX datarate.
+     */
+    PHY_DEF_TX_DR,
+    /*!
+     * RX datarate.
+     */
+    PHY_RX_DR,
+    /*!
+     * TX power.
+     */
+    PHY_TX_POWER,
+    /*!
+     * Default TX power.
+     */
+    PHY_DEF_TX_POWER,
+    /*!
+     * Maximum payload possible.
+     */
+    PHY_MAX_PAYLOAD,
+    /*!
+     * Maximum payload possible when repeater support is enabled.
+     */
+    PHY_MAX_PAYLOAD_REPEATER,
+    /*!
+     * Duty cycle.
+     */
+    PHY_DUTY_CYCLE,
+    /*!
+     * Maximum receive window duration.
+     */
+    PHY_MAX_RX_WINDOW,
+    /*!
+     * Receive delay for window 1.
+     */
+    PHY_RECEIVE_DELAY1,
+    /*!
+     * Receive delay for window 2.
+     */
+    PHY_RECEIVE_DELAY2,
+    /*!
+     * Join accept delay for window 1.
+     */
+    PHY_JOIN_ACCEPT_DELAY1,
+    /*!
+     * Join accept delay for window 2.
+     */
+    PHY_JOIN_ACCEPT_DELAY2,
+    /*!
+     * Maximum frame counter gap.
+     */
+    PHY_MAX_FCNT_GAP,
+    /*!
+     * Acknowledgement time out.
+     */
+    PHY_ACK_TIMEOUT,
+    /*!
+     * Default datarate offset for window 1.
+     */
+    PHY_DEF_DR1_OFFSET,
+    /*!
+     * Default receive window 2 frequency.
+     */
+    PHY_DEF_RX2_FREQUENCY,
+    /*!
+     * Default receive window 2 datarate.
+     */
+    PHY_DEF_RX2_DR,
+    /*!
+     * Channels mask.
+     */
+    PHY_CHANNELS_MASK,
+    /*!
+     * Channels default mask.
+     */
+    PHY_CHANNELS_DEFAULT_MASK,
+    /*!
+     * Maximum number of supported channels
+     */
+    PHY_MAX_NB_CHANNELS,
+    /*!
+     * Channels.
+     */
+    PHY_CHANNELS,
+    /*!
+     * Default value of the uplink dwell time.
+     */
+    PHY_DEF_UPLINK_DWELL_TIME,
+    /*!
+     * Default value of the downlink dwell time.
+     */
+    PHY_DEF_DOWNLINK_DWELL_TIME,
+    /*!
+     * Default value of the MaxEIRP.
+     */
+    PHY_DEF_MAX_EIRP,
+    /*!
+     * Default value of the antenna gain.
+     */
+    PHY_DEF_ANTENNA_GAIN,
+    /*!
+     * Next lower datarate.
+     */
+    PHY_NEXT_LOWER_TX_DR
+}PhyAttribute_t;
+
+/*!
+ * Enumeration of initialization types.
+ */
+typedef enum eInitType
+{
+    /*!
+     * Initializes the region specific data to defaults, according to the
+     * LoRaWAN specification.
+     */
+    INIT_TYPE_INIT,
+    /*!
+     * Restores default channels defined by the LoRaWAN specification only.
+     */
+    INIT_TYPE_RESTORE,
+    /*!
+     * Initializes the region specific data to the defaults which were set by
+     * the application.
+     */
+    INIT_TYPE_APP_DEFAULTS
+}InitType_t;
+
+typedef enum eChannelsMask
+{
+    /*!
+     * The channels mask.
+     */
+    CHANNELS_MASK,
+    /*!
+     * The channels default mask.
+     */
+    CHANNELS_DEFAULT_MASK
+}ChannelsMask_t;
+
+/*!
+ * Union for the structure uGetPhyParams
+ */
+typedef union uPhyParam
+{
+    /*!
+     * A parameter value.
+     */
+    uint32_t Value;
+    /*!
+     * A floating point value.
+     */
+    float fValue;
+    /*!
+     * Pointer to the channels mask.
+     */
+    uint16_t* ChannelsMask;
+    /*!
+     * Pointer to the channels.
+     */
+    ChannelParams_t* Channels;
+}PhyParam_t;
+
+/*!
+ * Parameter structure for the function RegionGetPhyParam.
+ */
+typedef struct sGetPhyParams
+{
+    /*!
+     * Setup the parameter to get.
+     */
+    PhyAttribute_t Attribute;
+    /*!
+     * Datarate.
+     * The parameter is needed for the following queries:
+     * PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR.
+     */
+    int8_t Datarate;
+    /*!
+     * Uplink dwell time.
+     * The parameter is needed for the following queries:
+     * PHY_MIN_TX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER, PHY_NEXT_LOWER_TX_DR.
+     */
+    uint8_t UplinkDwellTime;
+    /*!
+     * Downlink dwell time.
+     * The parameter is needed for the following queries:
+     * PHY_MIN_RX_DR, PHY_MAX_PAYLOAD, PHY_MAX_PAYLOAD_REPEATER.
+     */
+    uint8_t DownlinkDwellTime;
+}GetPhyParams_t;
+
+/*!
+ * Parameter structure for the function RegionSetBandTxDone.
+ */
+typedef struct sSetBandTxDoneParams
+{
+    /*!
+     * Channel to update.
+     */
+    uint8_t Channel;
+    /*!
+     * Joined Set to true, if the node has joined the network
+     */
+    bool Joined;
+    /*!
+     * Last TX done time.
+     */
+    TimerTime_t LastTxDoneTime;
+}SetBandTxDoneParams_t;
+
+/*!
+ * Parameter structure for the function RegionVerify.
+ */
+typedef union uVerifyParams
+{
+    /*!
+     * TX power to verify.
+     */
+    int8_t TxPower;
+    /*!
+     * Set to true, if the duty cycle is enabled, otherwise false.
+     */
+    bool DutyCycle;
+    /*!
+     * Datarate to verify.
+     */
+    struct sDatarateParams
+    {
+        /*!
+        * Datarate to verify.
+        */
+        int8_t Datarate;
+        /*!
+        * The downlink dwell time.
+        */
+        uint8_t DownlinkDwellTime;
+        /*!
+        * The up link dwell time.
+        */
+        uint8_t UplinkDwellTime;
+    }DatarateParams;
+}VerifyParams_t;
+
+/*!
+ * Parameter structure for the function RegionApplyCFList.
+ */
+typedef struct sApplyCFListParams
+{
+    /*!
+     * Payload which contains the CF list.
+     */
+    uint8_t* Payload;
+    /*!
+     * Size of the payload.
+     */
+    uint8_t Size;
+}ApplyCFListParams_t;
+
+/*!
+ * Parameter structure for the function RegionChanMaskSet.
+ */
+typedef struct sChanMaskSetParams
+{
+    /*!
+     * Pointer to the channels mask which should be set.
+     */
+    uint16_t* ChannelsMaskIn;
+    /*!
+     * Pointer to the channels mask which should be set.
+     */
+    ChannelsMask_t ChannelsMaskType;
+}ChanMaskSetParams_t;
+
+/*!
+ * Parameter structure for the function RegionAdrNext.
+ */
+typedef struct sAdrNextParams
+{
+    /*!
+     * Set to true, if the function should update the channels mask.
+     */
+    bool UpdateChanMask;
+    /*!
+     * Set to true, if ADR is enabled.
+     */
+    bool AdrEnabled;
+    /*!
+     * ADR ack counter.
+     */
+    uint32_t AdrAckCounter;
+    /*!
+     * Datarate used currently.
+     */
+    int8_t Datarate;
+    /*!
+     * TX power used currently.
+     */
+    int8_t TxPower;
+    /*!
+     * UplinkDwellTime
+     */
+    uint8_t UplinkDwellTime;
+}AdrNextParams_t;
+
+/*!
+ * Parameter structure for the function RegionRxConfig.
+ */
+typedef struct sRxConfigParams
+{
+    /*!
+     * The RX channel.
+     */
+    uint8_t Channel;
+    /*!
+     * RX datarate.
+     */
+    int8_t Datarate;
+    /*!
+     * RX bandwidth.
+     */
+    uint8_t Bandwidth;
+    /*!
+     * RX datarate offset.
+     */
+    int8_t DrOffset;
+    /*!
+     * RX frequency.
+     */
+    uint32_t Frequency;
+    /*!
+     * RX window timeout (in symbols)
+     */
+     uint32_t WindowTimeout;
+    /*!
+     * RX window offset
+     */
+    int32_t WindowOffset;
+    /*!
+     * Downlink dwell time.
+     */
+    uint8_t DownlinkDwellTime;
+    /*!
+     * Set to true, if a repeater is supported.
+     */
+    bool RepeaterSupport;
+    /*!
+     * Set to true, if RX should be continuous.
+     */
+    bool RxContinuous;
+    /*!
+     * Sets the RX window.
+     */
+    LoRaMacRxSlot_t RxSlot;
+    /*!
+     * The symbol time, in msecs
+     */
+    double tsymbol;
+}RxConfigParams_t;
+
+/*!
+ * Parameter structure for the function RegionTxConfig.
+ */
+typedef struct sTxConfigParams
+{
+    /*!
+     * The TX channel.
+     */
+    uint8_t Channel;
+    /*!
+     * The TX datarate.
+     */
+    int8_t Datarate;
+    /*!
+     * The TX power.
+     */
+    int8_t TxPower;
+    /*!
+     * The Max EIRP, if applicable.
+     */
+    float MaxEirp;
+    /*!
+     * The antenna gain, if applicable.
+     */
+    float AntennaGain;
+    /*!
+     * Frame length to setup.
+     */
+    uint16_t PktLen;
+}TxConfigParams_t;
+
+/*!
+ * Parameter structure for the function RegionLinkAdrReq.
+ */
+typedef struct sLinkAdrReqParams
+{
+    /*!
+     * Pointer to the payload which contains the MAC commands.
+     */
+    uint8_t* Payload;
+    /*!
+     * Size of the payload.
+     */
+    uint8_t PayloadSize;
+    /*!
+     * Uplink dwell time.
+     */
+    uint8_t UplinkDwellTime;
+    /*!
+     * Set to true, if ADR is enabled.
+     */
+    bool AdrEnabled;
+    /*!
+     * The current datarate.
+     */
+    int8_t CurrentDatarate;
+    /*!
+     * The current TX power.
+     */
+    int8_t CurrentTxPower;
+    /*!
+     * The current number of repetitions.
+     */
+    uint8_t CurrentNbRep;
+}LinkAdrReqParams_t;
+
+/*!
+ * Parameter structure for the function RegionRxParamSetupReq.
+ */
+typedef struct sRxParamSetupReqParams
+{
+    /*!
+     * The datarate to setup.
+     */
+    int8_t Datarate;
+    /*!
+     * Datarate offset.
+     */
+    int8_t DrOffset;
+    /*!
+     * The frequency to setup.
+     */
+    uint32_t Frequency;
+}RxParamSetupReqParams_t;
+
+/*!
+ * Parameter structure for the function RegionNewChannelReq.
+ */
+typedef struct sNewChannelReqParams
+{
+    /*!
+     * Pointer to the new channels.
+     */
+    ChannelParams_t* NewChannel;
+    /*!
+     * Channel id.
+     */
+    int8_t ChannelId;
+}NewChannelReqParams_t;
+
+/*!
+ * Parameter structure for the function RegionTxParamSetupReq.
+ */
+typedef struct sTxParamSetupReqParams
+{
+    /*!
+     * Uplink dwell time.
+     */
+    uint8_t UplinkDwellTime;
+    /*!
+     * Downlink dwell time.
+     */
+    uint8_t DownlinkDwellTime;
+    /*!
+     * Max EIRP.
+     */
+    uint8_t MaxEirp;
+}TxParamSetupReqParams_t;
+
+/*!
+ * Parameter structure for the function RegionDlChannelReq.
+ */
+typedef struct sDlChannelReqParams
+{
+    /*!
+     * Channel Id to add the frequency.
+     */
+    uint8_t ChannelId;
+    /*!
+     * Alternative frequency for the Rx1 window.
+     */
+    uint32_t Rx1Frequency;
+}DlChannelReqParams_t;
+
+/*!
+ * Parameter structure for the function RegionCalcBackOff.
+ */
+typedef struct sCalcBackOffParams
+{
+    /*!
+     * Set to true, if the node has already joined a network, otherwise false.
+     */
+    bool Joined;
+    /*!
+     * Joined Set to true, if the last uplink was a join request
+     */
+    bool LastTxIsJoinRequest;
+    /*!
+     * Set to true, if the duty cycle is enabled, otherwise false.
+     */
+    bool DutyCycleEnabled;
+    /*!
+     * Current channel index.
+     */
+    uint8_t Channel;
+    /*!
+     * Elapsed time since the start of the node.
+     */
+    TimerTime_t ElapsedTime;
+    /*!
+     * Time-on-air of the last transmission.
+     */
+    TimerTime_t TxTimeOnAir;
+}CalcBackOffParams_t;
+
+/*!
+ * Parameter structure for the function RegionNextChannel.
+ */
+typedef struct sNextChanParams
+{
+    /*!
+     * Aggregated time-off time.
+     */
+    TimerTime_t AggrTimeOff;
+    /*!
+     * Time of the last aggregated TX.
+     */
+    TimerTime_t LastAggrTx;
+    /*!
+     * Current datarate.
+     */
+    int8_t Datarate;
+    /*!
+     * Set to true, if the node has already joined a network, otherwise false.
+     */
+    bool Joined;
+    /*!
+     * Set to true, if the duty cycle is enabled, otherwise false.
+     */
+    bool DutyCycleEnabled;
+}NextChanParams_t;
+
+/*!
+ * Parameter structure for the function RegionChannelsAdd.
+ */
+typedef struct sChannelAddParams
+{
+    /*!
+     * Pointer to the new channel to add.
+     */
+    ChannelParams_t* NewChannel;
+    /*!
+     * Channel id to add.
+     */
+    uint8_t ChannelId;
+}ChannelAddParams_t;
+
+/*!
+ * Parameter structure for the function RegionChannelsRemove.
+ */
+typedef struct sChannelRemoveParams
+{
+    /*!
+     * Channel id to remove.
+     */
+    uint8_t ChannelId;
+}ChannelRemoveParams_t;
+
+/*!
+ * Parameter structure for the function RegionContinuousWave.
+ */
+typedef struct sContinuousWaveParams
+{
+    /*!
+     * Current channel index.
+     */
+    uint8_t Channel;
+    /*!
+     * Datarate. Used to limit the TX power.
+     */
+    int8_t Datarate;
+    /*!
+     * The TX power to setup.
+     */
+    int8_t TxPower;
+    /*!
+     * Max EIRP, if applicable.
+     */
+    float MaxEirp;
+    /*!
+     * The antenna gain, if applicable.
+     */
+    float AntennaGain;
+    /*!
+     * Specifies the time the radio will stay in CW mode.
+     */
+    uint16_t Timeout;
+}ContinuousWaveParams_t;
+
+
+
+/*!
+ * \brief The function verifies if a region is active or not. If a region
+ *        is not active, it cannot be used.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \retval Return true, if the region is supported.
+ */
+bool RegionIsActive( LoRaMacRegion_t region );
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionGetPhyParam( LoRaMacRegion_t region, GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionSetBandTxDone( LoRaMacRegion_t region, SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionInitDefaults( LoRaMacRegion_t region, InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionVerify( LoRaMacRegion_t region, VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionApplyCFList( LoRaMacRegion_t region, ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionChanMaskSet( LoRaMacRegion_t region, ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionAdrNext( LoRaMacRegion_t region, AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionRxConfig( LoRaMacRegion_t region, RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*
+ * Rx window precise timing
+ *
+ * For more details please consult the following document, chapter 3.1.2.
+ * https://www.semtech.com/uploads/documents/SX1272_settings_for_LoRaWAN_v2.0.pdf
+ * or
+ * https://www.semtech.com/uploads/documents/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 timeout and offset.
+ *
+ * \param [IN] region       LoRaWAN region.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionComputeRxWindowParameters( LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionTxConfig( LoRaMacRegion_t region, TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The datarate which was applied.
+ *
+ * \param [OUT] txPowOut The TX power which was applied.
+ *
+ * \param [OUT] nbRepOut The number of repetitions to apply.
+ *
+ * \param [OUT] nbBytesParsed The number bytes which were parsed.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionLinkAdrReq( LoRaMacRegion_t region, LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionRxParamSetupReq( LoRaMacRegion_t region, RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a New Channel Request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionNewChannelReq( LoRaMacRegion_t region, NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall ignore the command.
+ */
+int8_t RegionTxParamSetupReq( LoRaMacRegion_t region, TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionDlChannelReq( LoRaMacRegion_t region, DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate].
+ */
+LoRaMacStatus_t RegionNextChannel( LoRaMacRegion_t region, NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionChannelAdd( LoRaMacRegion_t region, ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionChannelsRemove( LoRaMacRegion_t region, ChannelRemoveParams_t* channelRemove );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] region LoRaWAN region.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionSetContinuousWave( LoRaMacRegion_t region, ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionApplyDrOffset( LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGION */
+
+#endif // __REGION_H__
diff --git a/net/lora/node/include/node/utilities.h b/net/lora/node/include/node/utilities.h
index 44ab629b4..66bb2a84e 100644
--- a/net/lora/node/include/node/utilities.h
+++ b/net/lora/node/include/node/utilities.h
@@ -1,21 +1,43 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
+/*!
+ * \file      utilities.h
+ *
+ * \brief     Helper functions implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ */
+#ifndef __UTILITIES_H__
+#define __UTILITIES_H__
 
-Description: Helper functions implementation
+#include <stdint.h>
+#include <string.h>
 
-License: Revised BSD License, see LICENSE.TXT file include in the project
+#define TimerTime_t uint32_t
 
-Maintainer: Miguel Luis and Gregory Cristian
-*/
-#ifndef __UTILITIES_H__
-#define __UTILITIES_H__
+/*!
+ * Generic definition
+ */
+#ifndef SUCCESS
+#define SUCCESS                                     1
+#endif
 
-#include <inttypes.h>
+#ifndef FAIL
+#define FAIL                                        0
+#endif
 
 /*!
  * \brief Returns the minimum value between a and b
@@ -43,6 +65,13 @@ Maintainer: Miguel Luis and Gregory Cristian
  */
 #define POW2( n ) ( 1 << n )
 
+/*!
+ * \brief Initializes the pseudo random generator initial value
+ *
+ * \param [IN] seed Pseudo random generator initial value
+ */
+void srand1( uint32_t seed );
+
 /*!
  * \brief Computes a random number between min and max
  *
@@ -52,6 +81,39 @@ Maintainer: Miguel Luis and Gregory Cristian
  */
 int32_t randr( int32_t min, int32_t max );
 
+/*!
+ * \brief Copies size elements of src array to dst array
+ *
+ * \remark STM32 Standard memcpy function only works on pointers that are aligned
+ *
+ * \param [OUT] dst  Destination array
+ * \param [IN]  src  Source array
+ * \param [IN]  size Number of bytes to be copied
+ */
+//void memcpy1( uint8_t *dst, const uint8_t *src, uint16_t size );
+#define memcpy1(dst, src, size)     memcpy(dst, src, size)
+
+/*!
+ * \brief Copies size elements of src array to dst array reversing the byte order
+ *
+ * \param [OUT] dst  Destination array
+ * \param [IN]  src  Source array
+ * \param [IN]  size Number of bytes to be copied
+ */
+void memcpyr( uint8_t *dst, const uint8_t *src, uint16_t size );
+
+/*!
+ * \brief Set size elements of dst array with value
+ *
+ * \remark STM32 Standard memset function only works on pointers that are aligned
+ *
+ * \param [OUT] dst   Destination array
+ * \param [IN]  value Default value
+ * \param [IN]  size  Number of bytes to be copied
+ */
+//void memset1( uint8_t *dst, uint8_t value, uint16_t size );
+#define memset1(dst, value, size)   memset(dst, (int)value, (size_t)size)
+
 /*!
  * \brief Converts a nibble to an hexadecimal character
  *
@@ -60,13 +122,20 @@ int32_t randr( int32_t min, int32_t max );
  */
 int8_t Nibble2HexChar( uint8_t a );
 
+/*!
+ * \brief Read the current time
+ *
+ * \retval time returns current time
+ */
+TimerTime_t TimerGetCurrentTime( void );
+
 /*!
  * \brief Return the Time elapsed since a fix moment in Time
  *
  * \param [IN] savedTime    fix moment in Time
  * \retval time             returns elapsed time
  */
-uint32_t TimerGetElapsedTime( uint32_t savedTime );
+TimerTime_t TimerGetElapsedTime( TimerTime_t savedTime );
 
 /*!
  * \brief Return the Time elapsed since a fix moment in Time
@@ -74,6 +143,6 @@ uint32_t TimerGetElapsedTime( uint32_t savedTime );
  * \param [IN] eventInFuture    fix moment in the future
  * \retval time             returns difference between now and future event
  */
-uint32_t TimerGetFutureTime( uint32_t eventInFuture );
+TimerTime_t TimerGetFutureTime( TimerTime_t eventInFuture );
 
 #endif // __UTILITIES_H__
diff --git a/net/lora/node/pkg.yml b/net/lora/node/pkg.yml
index 348765aff..a5c44dcdd 100644
--- a/net/lora/node/pkg.yml
+++ b/net/lora/node/pkg.yml
@@ -6,7 +6,7 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-# 
+#
 #  http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing,
@@ -34,6 +34,10 @@ pkg.deps.LORA_NODE_CLI:
     - "@apache-mynewt-core/sys/shell"
     - "@apache-mynewt-core/util/parse"
 
+pkg.deps.LORA_NODE_LOG_CLI:
+    - "@apache-mynewt-core/sys/shell"
+    - "@apache-mynewt-core/util/parse"
+
 pkg.req_apis:
     - lora_node_driver
 
diff --git a/net/lora/node/src/lora_cli.c b/net/lora/node/src/lora_cli.c
index 3162c8055..aa193dae4 100644
--- a/net/lora/node/src/lora_cli.c
+++ b/net/lora/node/src/lora_cli.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -18,16 +18,14 @@
  */
 
 #include "os/mynewt.h"
-
-#if MYNEWT_VAL(LORA_NODE_CLI)
-
 #include <inttypes.h>
 #include <string.h>
-
 #include "shell/shell.h"
 #include "console/console.h"
-#include "node/radio.h"
 #include "parse/parse.h"
+#include "node/lora_priv.h"
+
+#if MYNEWT_VAL(LORA_NODE_CLI)
 
 static int lora_cli_cmd_fn(int argc, char **argv);
 static int lora_cli_set_freq(int argc, char **argv);
@@ -566,3 +564,145 @@ lora_cli_init(void)
 }
 
 #endif /* MYNEWT_VAL(LORA_NODE_CLI) */
+
+#if MYNEWT_VAL(LORA_NODE_LOG_CLI) == 1
+
+#if MYNEWT_VAL(LORA_NODE_LOG_CLI) == 1
+static int lora_cli_log_cmd(int argc, char **argv);
+
+static struct shell_cmd lora_node_log_cmd = {
+    .sc_cmd = "ln_log",
+    .sc_cmd_func = lora_cli_log_cmd
+};
+#endif
+
+int
+lora_cli_log_cmd(int argc, char **argv)
+{
+#ifdef LORA_NODE_DEBUG_LOG
+    uint16_t i;
+    uint16_t lines_logged;
+
+    console_printf("Lora node log\n");
+    i = g_lnd_log_index;
+    lines_logged = 0;
+    while (lines_logged != LORA_NODE_DEBUG_LOG_ENTRIES) {
+        /* Do not display empty log lines */
+        if (g_lnd_log[i].lnd_id == 0) {
+            goto next_entry;
+        }
+
+        console_printf("index=%u ", i);
+        switch (g_lnd_log[i].lnd_id) {
+        case LORA_NODE_LOG_TX_DONE:
+            console_printf("TX_DONE chan=%u done_time=%lu",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_TX_SETUP:
+            console_printf("TX_SETUP phytxpwr=%d sf=%u bw=%u freq=%lu",
+                           (int8_t)g_lnd_log[i].lnd_p8,
+                           (uint8_t)(g_lnd_log[i].lnd_p16 >> 8),
+                           (uint8_t)g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_TX_START:
+            console_printf("TX_START pwr=%d dr=%u chan=%u airtime=%lu",
+                           (int8_t)g_lnd_log[i].lnd_p8,
+                           (uint8_t)(g_lnd_log[i].lnd_p16 >> 8),
+                           (uint8_t)g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_TX_DELAY:
+            console_printf("TX_DELAY dc=%u delay_usecs=%lu",
+                           (int8_t)g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p32);
+            break;
+       case LORA_NODE_LOG_TX_PREP_FRAME:
+            console_printf("TX_PREP_FRAME cmdbytes=%u uplink=%u mhdr=%x",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           (uint8_t)g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_RX_WIN1_SETUP:
+            console_printf("RX_WIN1_SETUP dr=%u chan=%u timeout=%lu",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_RX_TIMEOUT:
+            console_printf("RX_TIMEOUT chan=%u rxslot=%u",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16);
+            break;
+        case LORA_NODE_LOG_RX_DONE:
+            console_printf("RX_DONE chan=%u size=%u slot=%u machdr=%x",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           (uint8_t)(g_lnd_log[i].lnd_p32 >> 8),
+                           (uint8_t)g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_RADIO_TIMEOUT_IRQ:
+            break;
+        case LORA_NODE_LOG_RX_CFG:
+            console_printf("RX_CFG bw=%u dr=%u sf=%u freq=%lu",
+                           (int8_t)g_lnd_log[i].lnd_p8,
+                           (uint8_t)(g_lnd_log[i].lnd_p16 >> 8),
+                           (uint8_t)g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_RX_PORT:
+            console_printf("RX_PORT port=%u len=%u",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16);
+            break;
+        case LORA_NODE_LOG_RX_WIN2:
+            console_printf("RX_WIN2 rxslot=%u cont=%u freq=%lu",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_APP_TX:
+            console_printf("APP_TX pktlen=%u om=%lx",
+                           g_lnd_log[i].lnd_p16, g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_RTX_TIMEOUT:
+            console_printf("RTX_TIMEOUT macflags=%x", g_lnd_log[i].lnd_p8);
+            break;
+        case LORA_NODE_LOG_RX_ADR_REQ:
+            console_printf("RX_ADR_REQ dr=%u txpwr=%u chmassk=%u nbrep=%u",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           (uint16_t)(g_lnd_log[i].lnd_p32 >> 16),
+                           (uint16_t)g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_PROC_MAC_CMD:
+            console_printf("PROC_MAC_CMD index=%u snr=%u cmd_size=%lu",
+                           g_lnd_log[i].lnd_p8, g_lnd_log[i].lnd_p16,
+                           g_lnd_log[i].lnd_p32);
+            break;
+        case LORA_NODE_LOG_LINK_CHK:
+            console_printf("LINK_CHK status=%lu", g_lnd_log[i].lnd_p32);
+            break;
+        default:
+            console_printf("id=%u p8=%u p16=%u p32=%lu",
+                           g_lnd_log[i].lnd_id, g_lnd_log[i].lnd_p8,
+                           g_lnd_log[i].lnd_p16, g_lnd_log[i].lnd_p32);
+            break;
+        }
+
+        console_printf(" cputime=%lu\n", g_lnd_log[i].lnd_cputime);
+
+next_entry:
+        ++i;
+        if (i == LORA_NODE_DEBUG_LOG_ENTRIES) {
+            i = 0;
+        }
+        ++lines_logged;
+    }
+#else
+    console_printf("No Lora node log available\n");
+#endif
+    return 0;
+}
+
+
+void
+lora_cli_init(void)
+{
+    int rc;
+    rc = shell_cmd_register(&lora_node_log_cmd);
+    assert(rc == 0);
+}
+#endif /* MYNEWT_VAL(LORA_NODE_LOG_CLI) */
diff --git a/net/lora/node/src/lora_node.c b/net/lora/node/src/lora_node.c
index 371b8909b..4e5bf3f84 100644
--- a/net/lora/node/src/lora_node.c
+++ b/net/lora/node/src/lora_node.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include "os/mynewt.h"
 #include "node/lora_priv.h"
+#include "node/lora_band.h"
 
 STATS_SECT_DECL(lora_mac_stats) lora_mac_stats;
 STATS_NAME_START(lora_mac_stats)
@@ -39,6 +40,10 @@ STATS_NAME_START(lora_mac_stats)
     STATS_NAME(lora_mac_stats, rx_mic_failures)
     STATS_NAME(lora_mac_stats, rx_mlme)
     STATS_NAME(lora_mac_stats, rx_mcps)
+    STATS_NAME(lora_mac_stats, rx_dups)
+    STATS_NAME(lora_mac_stats, rx_invalid)
+    STATS_NAME(lora_mac_stats, no_bufs)
+    STATS_NAME(lora_mac_stats, already_joined)
 STATS_NAME_END(lora_mac_stats)
 
 /* Device EUI */
@@ -214,6 +219,7 @@ lora_node_mac_mcps_indicate(void)
         lora_app_mcps_indicate(om);
     } else {
         /* XXX: cant do anything until the lower stack gets modified */
+        STATS_INC(lora_mac_stats, no_bufs);
     }
 }
 
@@ -635,6 +641,10 @@ lora_node_init(void)
     /* Init app */
     lora_app_init();
 
+#if MYNEWT_VAL(LORA_NODE_LOG_CLI) == 1
+    lora_cli_init();
+#endif
+
     /*--- MAC INIT ---*/
     /* Initialize eventq */
     os_eventq_init(&g_lora_mac_data.lm_evq);
@@ -661,7 +671,7 @@ lora_node_init(void)
     /* Initialize the LoRa mac */
     lora_cb.GetBatteryLevel = lora_node_get_batt_status;
 
-    lms = LoRaMacInitialization(&lora_cb);
+    lms = LoRaMacInitialization(&lora_cb, LORA_NODE_REGION);
     assert(lms == LORAMAC_STATUS_OK);
 #endif
 }
diff --git a/net/lora/node/src/mac/LoRaMac.c b/net/lora/node/src/mac/LoRaMac.c
index 316420eb8..1dd390bf8 100644
--- a/net/lora/node/src/mac/LoRaMac.c
+++ b/net/lora/node/src/mac/LoRaMac.c
@@ -1,28 +1,38 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
- ___ _____ _   ___ _  _____ ___  ___  ___ ___
-/ __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
-\__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
-|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
-embedded.connectivity.solutions===============
-
-Description: LoRa MAC layer implementation
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel J�ckle ( STACKFORCE )
-*/
+/*!
+ * \file      LoRaMac.c
+ *
+ * \brief     LoRa MAC layer implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ */
 
 #include <string.h>
 #include <assert.h>
 #include "os/mynewt.h"
 #include "node/lora.h"
-#include "radio/radio.h"
 #include "node/utilities.h"
 #include "node/mac/LoRaMacCrypto.h"
 #include "node/mac/LoRaMac.h"
@@ -36,21 +46,9 @@ License: Revised BSD License, see LICENSE.TXT file include in the project
 #define LORA_MAC_TIMER_NUM    MYNEWT_VAL(LORA_MAC_TIMER_NUM)
 #endif
 
-/*
- * XXX: TODO. This is radio dependent! Need to put this in driver. For
- * now, just use SX1276 time
- */
-#ifndef RADIO_WAKEUP_TIME
-#define RADIO_WAKEUP_TIME       (3)
-#endif
-
 /* The lora mac timer counts in 1 usec increments */
 #define LORA_MAC_TIMER_FREQ     1000000
 
-/* Convert mac state timeout to os ticks */
-#define MAC_STATE_CHECK_OS_TICKS        \
-    ((MAC_STATE_CHECK_TIMEOUT * OS_TICKS_PER_SEC) / 1000)
-
 /*!
  * Maximum PHY layer payload size
  */
@@ -59,29 +57,17 @@ License: Revised BSD License, see LICENSE.TXT file include in the project
 /*!
  * Maximum MAC commands buffer size
  */
-#define LORA_MAC_COMMAND_MAX_LENGTH                 15
-
-/*!
- * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength
- * in RxWindowSetup function.
- * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD
- */
-#define LORA_MAC_FRMPAYLOAD_OVERHEAD                13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4)
-
-/*!
- * LoRaMac duty cycle for the back-off procedure during the first hour.
- */
-#define BACKOFF_DC_1_HOUR                           100
+#define LORA_MAC_CMD_BUF_LEN                        128
 
 /*!
- * LoRaMac duty cycle for the back-off procedure during the next 10 hours.
+ * Maximum length of the fOpts field
  */
-#define BACKOFF_DC_10_HOURS                         1000
+#define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH           15
 
 /*!
- * LoRaMac duty cycle for the back-off procedure during the next 24 hours.
+ * LoRaMac region.
  */
-#define BACKOFF_DC_24_HOURS                         10000
+static LoRaMacRegion_t LoRaMacRegion;
 
 /*!
  * Device IEEE EUI
@@ -108,22 +94,6 @@ static uint8_t LoRaMacNwkSKey[16];
  */
 static uint8_t LoRaMacAppSKey[16];
 
-/*!
- * Device nonce is a random value extracted by issuing a sequence of RSSI
- * measurements
- */
-static uint16_t LoRaMacDevNonce;
-
-/*!
- * Network ID ( 3 bytes )
- */
-static uint32_t LoRaMacNetID;
-
-/*!
- * Mote Address
- */
-static uint32_t LoRaMacDevAddr;
-
 /*!
  * Multicast channels linked list
  */
@@ -134,16 +104,6 @@ static MulticastParams_t *MulticastChannels = NULL;
  */
 static DeviceClass_t LoRaMacDeviceClass;
 
-/*!
- * Indicates if the node is connected to a private or public network
- */
-static bool PublicNetwork;
-
-/*!
- * Indicates if the node supports repeaters
- */
-static bool RepeaterSupport;
-
 /*!
  * Buffer containing the data to be sent or received.
  */
@@ -154,61 +114,22 @@ static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD];
  */
 static uint16_t LoRaMacBufferPktLen;
 
-/*!
- * Length of the payload in LoRaMacBuffer
- */
-static uint8_t LoRaMacTxPayloadLen;
-
 /*!
  * Buffer containing the upper layer data.
  */
 static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
 
-/*!
- * LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
- * Only the 16 LSB bits are sent
- */
-static uint32_t UpLinkCounter;
-
-/*!
- * LoRaMAC frame counter. Each time a packet is received the counter is incremented.
- * Only the 16 LSB bits are received
- */
-static uint32_t DownLinkCounter;
-
 /*!
  * IsPacketCounterFixed enables the MIC field tests by fixing the
  * UpLinkCounter value
  */
 static bool IsUpLinkCounterFixed = false;
 
-/*!
- * Indicates if the MAC layer has already joined a network.
- */
-static bool IsLoRaMacNetworkJoined = false;
-
 /*!
  * LoRaMac ADR control status
  */
 static bool AdrCtrlOn = false;
 
-/*!
- * Counts the number of missed ADR acknowledgements
- */
-static uint32_t AdrAckCounter;
-
-/*!
- * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
- * if the nodes needs to manage the server acknowledgement.
- */
-static bool NodeAckRequested = false;
-
-/*!
- * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates
- * if the ACK bit must be set for the next transmission
- */
-static bool SrvAckRequested = false;
-
 /*!
  * Contains the current MacCommandsBuffer index
  */
@@ -222,259 +143,12 @@ static uint8_t MacCommandsBufferToRepeatIndex;
 /*!
  * Buffer containing the MAC layer commands
  */
-static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
+static uint8_t MacCommandsBuffer[LORA_MAC_CMD_BUF_LEN];
 
 /*!
  * Buffer containing the MAC layer commands which must be repeated
  */
-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 };
-
-/*!
- * 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 };
-
-/*!
- * 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 };
-
-/*!
- * 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 };
-
-/*!
- * 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 };
-
-/*!
- * 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 };
-
-#if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
-/* XXX: only looked at these for the US band */
-/* (incoded) Symbol times, in usecs, for data rates */
-const uint16_t g_lora_uncoded_symbol_len_usecs[] =
-{
-    8192, 4096, 2048, 1024, 512, 0, 0, 0, 8192, 4096, 2048, 1024, 512, 256, 0, 0
-};
-#endif
-
-/*!
- * 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
+static uint8_t MacCommandsBufferToRepeat[LORA_MAC_CMD_BUF_LEN];
 
 /*!
  * LoRaMac parameters
@@ -486,43 +160,11 @@ LoRaMacParams_t LoRaMacParams;
  */
 LoRaMacParams_t LoRaMacParamsDefaults;
 
-/*!
- * Uplink messages repetitions counter
- */
-static uint8_t ChannelsNbRepCounter = 0;
-
-/*!
- * Maximum duty cycle
- * \remark Possibility to shutdown the device.
- */
-static uint8_t MaxDCycle = 0;
-
-/*!
- * Aggregated duty cycle management
- */
-static uint16_t AggregatedDCycle;
-static uint32_t AggregatedLastTxDoneTime;
-static uint32_t AggregatedTimeOff;
-
 /*!
  * Enables/Disables duty cycle management (Test only)
  */
 static bool DutyCycleOn;
 
-/*!
- * Current channel index
- */
-static uint8_t Channel;
-
-/*!
- * Stores the time at LoRaMac initialization.
- *
- * NOTE: units of this variable are in usecs.
- *
- * \remark Used for the BACKOFF_DC computation.
- */
-static uint64_t LoRaMacInitializationTime;
-
 /*!
  * LoRaMac internal states
  */
@@ -535,6 +177,7 @@ enum eLoRaMacState
     LORAMAC_ACK_RETRY     = 0x00000008,
     LORAMAC_TX_DELAYED    = 0x00000010,
     LORAMAC_TX_CONFIG     = 0x00000020,
+    LORAMAC_RX_ABORT      = 0x00000040,
 };
 
 /*!
@@ -564,52 +207,10 @@ static struct hal_timer RxWindowTimer1;
 static struct hal_timer RxWindowTimer2;
 
 /*!
- * LoRaMac reception windows delay
- * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
- *         join frame  : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
- */
-static uint32_t RxWindow1Delay;
-static uint32_t RxWindow2Delay;
-
-/*!
- * Acknowledge timeout timer. Used for packet retransmissions.
- */
-static struct hal_timer AckTimeoutTimer;
-
-/*!
- * Number of trials to get a frame acknowledged
- */
-static uint8_t AckTimeoutRetries = 1;
-
-/*!
- * Number of trials to get a frame acknowledged
+ * LoRaMac Rx windows configuration
  */
-static uint8_t AckTimeoutRetriesCounter = 1;
-
-/*!
- * Last transmission time on air
- */
-uint32_t TxTimeOnAir = 0;
-
-/*!
- * Number of trials for the Join Request
- */
-static uint8_t JoinRequestTrials;
-
-/*!
- * Maximum number of trials for the Join Request
- */
-static uint8_t MaxJoinRequestTrials;
-
-/*!
- * Holds the current rx window slot
- */
-static uint8_t RxSlot;
-
-/*!
- * LoRaMac tx/rx operation state
- */
-LoRaMacFlags_t LoRaMacFlags;
+static RxConfigParams_t RxWindow1Config;
+static RxConfigParams_t RxWindow2Config;
 
 /* Lengths of MAC commands */
 static const uint8_t
@@ -621,12 +222,40 @@ struct os_event g_lora_mac_radio_tx_event;
 struct os_event g_lora_mac_radio_rx_event;
 struct os_event g_lora_mac_radio_rx_err_event;
 struct os_event g_lora_mac_radio_rx_timeout_event;
-struct os_event g_lora_mac_ack_timeout_event;
+struct os_event g_lora_mac_rtx_timeout_event;
 struct os_event g_lora_mac_rx_win1_event;
 struct os_event g_lora_mac_rx_win2_event;
 struct os_event g_lora_mac_tx_delay_timeout_event;
 
-static void lora_mac_rx_on_window2(bool rx_continuous);
+static void lora_mac_rx_on_window2(void);
+static uint8_t lora_mac_extract_mac_cmds(uint8_t max_cmd_bytes, uint8_t *buf);
+
+/**
+ * lora mac rtx timer stop
+ *
+ * Stops the retransmission timer. Removes any enqueued event (if on queue).
+ */
+static void
+lora_mac_rtx_timer_stop(void)
+{
+    hal_timer_stop(&g_lora_mac_data.rtx_timer);
+    os_eventq_remove(lora_node_mac_evq_get(), &g_lora_mac_rtx_timeout_event);
+}
+
+/**
+ * lora mac rx win2 stop
+ *
+ * Stops the receive window timer. Removes any enqueued event (if on queue)
+ *
+ */
+static void
+lora_mac_rx_win2_stop(void)
+{
+    if (LoRaMacDeviceClass == CLASS_A) {
+        hal_timer_stop(&RxWindowTimer2);
+        os_eventq_remove(lora_node_mac_evq_get(), &g_lora_mac_rx_win2_event);
+    }
+}
 
 /*!
  * \brief Function to be executed on Radio Tx Done event
@@ -719,45 +348,24 @@ OnRxWindow2TimerEvent(void *unused)
 }
 
 /*!
- * \brief Function executed on AckTimeout timer event
+ * \brief Function executed when rtx timer expires. The rtx timer is used
+ * for packet re-transmissions.
+ *
+ * Context: Interrupt and MAC
  */
 static void
-OnAckTimeoutTimerEvent(void *unused)
+lora_mac_rtx_timer_cb(void *unused)
 {
-    os_eventq_put(lora_node_mac_evq_get(), &g_lora_mac_ack_timeout_event);
+    os_eventq_put(lora_node_mac_evq_get(), &g_lora_mac_rtx_timeout_event);
 }
 
-/*!
- * \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( uint32_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]
- */
-static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous );
-
-/*!
- * \brief Verifies if the RX window 2 frequency is in range
- *
- * \param [IN] freq window channel frequency
- *
- * \retval status  Function status [1: OK, 0: Frequency not applicable]
+ * \param [IN] rxContinuous Set to true, if the RX is in continuous mode
+ * \param [IN] maxRxWindow Maximum RX window timeout
  */
-static bool Rx2FreqInRange( uint32_t freq );
+static void RxWindowSetup(bool rxContinuous, uint32_t maxRxWindow);
 
 /*!
  * \brief Adds a new MAC command to be sent.
@@ -808,106 +416,7 @@ static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint
  * \retval [false: payload does not fit into the frame, true: payload fits into
  *          the frame]
  */
-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 );
+static bool ValidatePayloadLength(uint8_t lenN, int8_t datarate, uint8_t fOptsLen);
 
 /*!
  * \brief Decodes MAC commands in the fOpts field and in the payload
@@ -945,13 +454,6 @@ LoRaMacStatus_t PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl,
  */
 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.
  *
@@ -959,24 +461,16 @@ static uint16_t JoinDutyCycle(void);
  */
 static void CalculateBackOff( uint8_t channel );
 
-/*
- * \brief Alternates the datarate of the channel for the join request.
- *
- * \param [IN] nbTrials    Number of performed join requests.
- * \retval Datarate to apply
- */
-static int8_t AlternateDatarate( uint16_t nbTrials );
-
 /*!
  * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
  *
  * \remark PrepareFrame must be called at least once before calling this
  *         function.
  *
- * \param [IN] channel     Channel parameters
+ * \param [IN] channel     Channel to transmit on
  * \retval status          Status of the operation.
  */
-LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
+LoRaMacStatus_t SendFrameOnChannel( uint8_t channel );
 
 /*!
  * \brief Sets the radio in continuous transmission mode
@@ -989,9 +483,16 @@ LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
 LoRaMacStatus_t SetTxContinuousWave(uint16_t timeout);
 
 /*!
- * \brief Resets MAC specific parameters to default
+ * \brief Sets the radio in continuous transmission mode
+ *
+ * \remark Uses the radio parameters set on the previous transmission.
+ *
+ * \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 output power to be set.
+ * \retval status          Status of the operation.
  */
-static void ResetMacParameters(void);
+LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power );
 
 /*
  * XXX: TODO
@@ -1002,7 +503,6 @@ static void ResetMacParameters(void);
  * a downlink.
  */
 
-
 /**
  * Called to send MCPS confirmations
  */
@@ -1011,16 +511,15 @@ lora_mac_send_mcps_confirm(LoRaMacEventInfoStatus_t status)
 {
     /* We are no longer running a tx service */
     LoRaMacState &= ~LORAMAC_TX_RUNNING;
-    /* TODO: deal w/this bit. What exactly does McpsReq mean? Can om be NULL? */
-    if (LoRaMacFlags.Bits.McpsReq == 1) {
+
+    if (LM_F_IS_MCPS_REQ()) {
         assert(g_lora_mac_data.curtx != NULL);
         g_lora_mac_data.curtx->status = status;
         if (g_lora_mac_data.cur_tx_mbuf) {
             lora_app_mcps_confirm(g_lora_mac_data.cur_tx_mbuf);
         }
-        LoRaMacFlags.Bits.McpsReq = 0;
+        LM_F_IS_MCPS_REQ() = 0;
     }
-    lora_node_chk_txq();
 }
 
 /**
@@ -1031,55 +530,150 @@ lora_mac_send_join_confirm(LoRaMacEventInfoStatus_t status, uint8_t attempts)
 {
     LoRaMacState &= ~LORAMAC_TX_RUNNING;
     lora_app_join_confirm(status, attempts);
-    LoRaMacFlags.Bits.MlmeReq = 0;
+    LM_F_IS_JOINING() = 0;
+}
+
+static void
+lora_mac_join_accept_rxd(uint8_t *payload, uint16_t size)
+{
+    uint32_t temp;
+    uint32_t mic;
+    uint32_t micRx;
+    ApplyCFListParams_t apply_cf_list;
+
+    STATS_INC(lora_mac_stats, join_accept_rx);
+
+    if (LM_F_IS_JOINED()) {
+        STATS_INC(lora_mac_stats, already_joined);
+        return;
+    }
+
+    /*
+     * XXX: This is odd, but if we receive a join accept and we are not
+     * joined but have not started the join process not sure what to
+     * do. Guess we will just ignore this packet.
+     */
+    if (!LM_F_IS_JOINING()) {
+        return;
+    }
+
+    /* XXX: check for too small frame! */
+
+    LoRaMacJoinDecrypt(payload + 1, size - 1, LoRaMacAppKey,
+                       LoRaMacRxPayload + 1);
+
+    LoRaMacRxPayload[0] = payload[0];
+
+    LoRaMacJoinComputeMic(LoRaMacRxPayload, size - LORAMAC_MFR_LEN,
+                          LoRaMacAppKey, &mic);
+
+    micRx = ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
+    micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 );
+    micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
+    micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
+
+    if (micRx == mic) {
+        LoRaMacJoinComputeSKeys(LoRaMacAppKey, LoRaMacRxPayload + 1,
+                                g_lora_mac_data.dev_nonce, LoRaMacNwkSKey,
+                                LoRaMacAppSKey);
+
+        temp = ( uint32_t )LoRaMacRxPayload[4];
+        temp |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
+        temp |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 );
+        g_lora_mac_data.netid = temp;
+
+        temp = ( uint32_t )LoRaMacRxPayload[7];
+        temp |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 );
+        temp |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 );
+        temp |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 );
+        g_lora_mac_data.dev_addr = temp;
+
+        // 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
+        apply_cf_list.Payload = &LoRaMacRxPayload[13];
+
+        // Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
+        apply_cf_list.Size = size - 17;
+
+        RegionApplyCFList(LoRaMacRegion, &apply_cf_list);
+
+        /* We are now joined */
+        STATS_INC(lora_mac_stats, joins);
+
+        /* Stop window 2 if class A device */
+        lora_mac_rx_win2_stop();
+
+        LM_F_IS_JOINED() = 1;
+        g_lora_mac_data.uplink_cntr = 0;
+        g_lora_mac_data.nb_rep_cntr = 0;
+
+        /* XXX: why not increment this when sending it? Now
+           it is done on both success and fail */
+        ++g_lora_mac_data.cur_join_attempt;
+        lora_mac_send_join_confirm(LORAMAC_EVENT_INFO_STATUS_OK,
+                                   g_lora_mac_data.cur_join_attempt);
+    } else {
+        STATS_INC(lora_mac_stats, rx_mic_failures);
+    }
 }
 
 static void
 lora_mac_confirmed_tx_fail(struct lora_pkt_info *txi)
 {
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    LoRaMacStatus_t rc;
+    LoRaMacEventInfoStatus_t status;
+
     STATS_INC(lora_mac_stats, confirmed_tx_fail);
 
     /* XXX: how does this work in conjunction with ADR? Will the server
      * tell me to use a higher data rate if we fall back erroneously?
      * Need to understand. This is a bad retry mechanism
      */
-    if (AckTimeoutRetriesCounter < AckTimeoutRetries) {
-        AckTimeoutRetriesCounter++;
-        if ((AckTimeoutRetriesCounter % 2) == 1) {
-            LoRaMacParams.ChannelsDatarate = MAX( LoRaMacParams.ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE );
-        }
-
-        if( ValidatePayloadLength(LoRaMacTxPayloadLen, LoRaMacParams.ChannelsDatarate, MacCommandsBufferIndex) == true)
-        {
-            // Sends the same frame again
-            ScheduleTx( );
-        } else {
+    if (g_lora_mac_data.ack_timeout_retries_cntr < g_lora_mac_data.ack_timeout_retries) {
+        g_lora_mac_data.ack_timeout_retries_cntr++;
+        if ((g_lora_mac_data.ack_timeout_retries_cntr % 2) == 1) {
+            getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+            getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+            getPhy.Datarate = LoRaMacParams.ChannelsDatarate;
+            phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+            LoRaMacParams.ChannelsDatarate = phyParam.Value;
+        }
+
+        /* Attempt to transmit */
+        rc = ScheduleTx();
+        if (rc != LORAMAC_STATUS_OK) {
             // The DR is not applicable for the payload size
-            NodeAckRequested = false;
-            txi->txdinfo.retries = AckTimeoutRetriesCounter;
+            LM_F_NODE_ACK_REQ() = 0;
+            txi->txdinfo.retries = g_lora_mac_data.ack_timeout_retries_cntr;
             txi->txdinfo.datarate = LoRaMacParams.ChannelsDatarate;
-            UpLinkCounter++;
-            lora_mac_send_mcps_confirm(LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR);
+            g_lora_mac_data.uplink_cntr++;
+            if (rc == LORAMAC_STATUS_LENGTH_ERROR) {
+                status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR;
+            } else {
+                status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+            }
+            lora_mac_send_mcps_confirm(status);
         }
     } 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
-        memcpy( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#elif defined( USE_BAND_915 )
-        // Re-enable default channels
-        memcpy( ( 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
-        UpLinkCounter++;
-        NodeAckRequested = false;
-        txi->txdinfo.retries = AckTimeoutRetriesCounter;
+        /* XXX: This seems to be a bit suspect. Why is this done after a
+           confirmed transmission failure? */
+        RegionInitDefaults(LoRaMacRegion, INIT_TYPE_RESTORE);
+        g_lora_mac_data.uplink_cntr++;
+        LM_F_NODE_ACK_REQ() = 0;
+        txi->txdinfo.retries = g_lora_mac_data.ack_timeout_retries_cntr;
         lora_mac_send_mcps_confirm(LORAMAC_EVENT_INFO_STATUS_TX_RETRIES_EXCEEDED);
     }
 }
@@ -1087,48 +681,31 @@ lora_mac_confirmed_tx_fail(struct lora_pkt_info *txi)
 static void
 lora_mac_confirmed_tx_success(struct lora_pkt_info *txi)
 {
-    /* XXX: should this be done on success? */
-#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
-    memcpy( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#elif defined( USE_BAND_915 )
-    // Re-enable default channels
-    memcpy( ( 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
-
     STATS_INC(lora_mac_stats, confirmed_tx_good);
-    UpLinkCounter++;
-    NodeAckRequested = false;
+    g_lora_mac_data.uplink_cntr++;
+    LM_F_NODE_ACK_REQ() = 0;
     txi->txdinfo.ack_rxd = true;
-    txi->txdinfo.retries = AckTimeoutRetriesCounter;
+    txi->txdinfo.retries = g_lora_mac_data.ack_timeout_retries_cntr;
     lora_mac_send_mcps_confirm(LORAMAC_EVENT_INFO_STATUS_OK);
 }
 
 static void
 lora_mac_join_req_tx_fail(void)
 {
+    /* Add to Join Request trials if not joined */
+    ++g_lora_mac_data.cur_join_attempt;
+
     /* Have we exceeded the number of join request attempts */
-    if (JoinRequestTrials >= MaxJoinRequestTrials) {
+    if (g_lora_mac_data.cur_join_attempt >= g_lora_mac_data.max_join_attempt) {
         /* Join was a failure */
         STATS_INC(lora_mac_stats, join_failures);
         lora_mac_send_join_confirm(LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL,
-                                   JoinRequestTrials);
-
-        /*
-         * The reason we do this if failed to join is to flush the transmit
-         * queue and any mac commands.
-         */
-        lora_node_chk_txq();
+                                   g_lora_mac_data.cur_join_attempt);
     } else {
+        /* XXX: see if we want to do this. Not sure it is needed. I added
+           this but probably should be modified */
         /* Add some transmit delay between join request transmissions */
+        LoRaMacState |= LORAMAC_TX_DELAYED;
         hal_timer_stop(&TxDelayedTimer);
         hal_timer_start(&TxDelayedTimer,
             randr(0, MYNEWT_VAL(LORA_JOIN_REQ_RAND_DELAY) * 1000));
@@ -1136,87 +713,112 @@ lora_mac_join_req_tx_fail(void)
 }
 
 static void
-lora_mac_unconfirmed_tx_done(struct lora_pkt_info *txi)
+lora_mac_unconfirmed_tx_done(struct lora_pkt_info *txi, int stop_tx)
 {
     STATS_INC(lora_mac_stats, unconfirmed_tx);
 
+    /*
+     * XXX: this might be wrong, but if we cannot schedule the transmission
+     * we will just hand up the frame even though we have not attempted
+     * it the requisite number of times
+     */
+
     /* Unconfirmed frames get repeated N times. */
-    if (ChannelsNbRepCounter >= LoRaMacParams.ChannelsNbRep) {
-        txi->txdinfo.retries = ChannelsNbRepCounter;
-        ChannelsNbRepCounter = 0;
-        AdrAckCounter++;
-        UpLinkCounter++;
+    if ((g_lora_mac_data.nb_rep_cntr >= LoRaMacParams.ChannelsNbRep) ||
+        (ScheduleTx() != LORAMAC_STATUS_OK)) {
+        txi->txdinfo.retries = g_lora_mac_data.nb_rep_cntr;
+        g_lora_mac_data.nb_rep_cntr = 0;
+        g_lora_mac_data.adr_ack_cntr++;
+        g_lora_mac_data.uplink_cntr++;
         lora_mac_send_mcps_confirm(LORAMAC_EVENT_INFO_STATUS_OK);
-    } else {
-#if 0
-        /* If this is just mac commands or an ack, no need to retry */
-        if (McpsConfirm.om != NULL) {
-           /* Add some transmit delay between unconfirmed transmissions */
-            hal_timer_stop(&TxDelayedTimer);
-            hal_timer_start(&TxDelayedTimer,
-                randr(0, MYNEWT_VAL(LORA_UNCONFIRMED_TX_RAND_DELAY) * 1000));
-        }
-#endif
     }
 }
 
+/**
+ * lora mac tx service done
+ *
+ * The term "tx service" is a made-up term (not in the specification). A tx
+ * service starts when a frame is transmitted and ends when another frame can
+ * be sent (not including duty-cycle limitations).
+ *
+ * @param rxd_confirmation A boolean flag denoting the following:
+ *  -> A confirmed frame was sent and an acknowledgement was received
+ *  -> An unconfirmed frame was sent and a frame was received in either window
+ *  if the device is a class A device or a frame was received in window 1 if
+ *  class C.
+ */
 static void
 lora_mac_tx_service_done(int rxd_confirmation)
 {
     struct lora_pkt_info *txi;
 
-    /* If no MLME or MCPS request in progress we just return. */
-    if ((LoRaMacFlags.Bits.MlmeReq == 0) && (LoRaMacFlags.Bits.McpsReq == 0)) {
+    /* A sanity check to make sure things are in the proper state */
+    if (!LM_F_IS_JOINING() && !LM_F_IS_MCPS_REQ()) {
         assert((LoRaMacState & LORAMAC_TX_RUNNING) == 0);
-        lora_node_chk_txq();
-        return;
+        goto chk_txq;
     }
 
-    if (LoRaMacFlags.Bits.MlmeReq &&
-        (g_lora_mac_data.txpkt.pkt_type == MLME_JOIN)) {
+    if (LM_F_IS_JOINING()) {
         lora_mac_join_req_tx_fail();
     } else {
-        if (LoRaMacFlags.Bits.McpsReq == 1) {
-            txi = g_lora_mac_data.curtx;
-            assert(txi != NULL);
-            if (NodeAckRequested) {
-                if (rxd_confirmation) {
-                    lora_mac_confirmed_tx_success(txi);
-                } else {
-                    lora_mac_confirmed_tx_fail(txi);
-                }
+        txi = g_lora_mac_data.curtx;
+        assert(txi != NULL);
+        if (LM_F_NODE_ACK_REQ()) {
+            if (rxd_confirmation) {
+                lora_mac_confirmed_tx_success(txi);
             } else {
-                lora_mac_unconfirmed_tx_done(txi);
+                lora_mac_confirmed_tx_fail(txi);
             }
+        } else {
+            lora_mac_unconfirmed_tx_done(txi, rxd_confirmation);
         }
     }
+
+    /* For now, always post an event to check the transmit queue for activity */
+chk_txq:
+    lora_node_chk_txq();
 }
 
 static void
 lora_mac_process_radio_tx(struct os_event *ev)
 {
+    uint32_t timeout;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    SetBandTxDoneParams_t txDone;
+
     /* XXX: We need to time this more accurately */
     uint32_t curTime = hal_timer_read(LORA_MAC_TIMER_NUM);
 
     if (LoRaMacDeviceClass != CLASS_C) {
         Radio.Sleep( );
     } else {
-        lora_mac_rx_on_window2(true);
+        lora_mac_rx_on_window2();
     }
 
     /* Always start receive window 1 */
-    hal_timer_start_at(&RxWindowTimer1, curTime + (RxWindow1Delay * 1000));
+    hal_timer_start_at(&RxWindowTimer1,
+                       curTime + (g_lora_mac_data.rx_win1_delay * 1000));
 
     /* Only start receive window 2 if not a class C device */
     if (LoRaMacDeviceClass != CLASS_C) {
         hal_timer_start_at(&RxWindowTimer2,
-                               curTime + (RxWindow2Delay * 1000));
+                           curTime + (g_lora_mac_data.rx_win2_delay * 1000));
+    }
+
+    /* Set flag if tx is a join request and increment tx request stats. */
+    if (LM_F_IS_JOINING()) {
+        STATS_INC(lora_mac_stats, join_req_tx);
+        LM_F_LAST_TX_IS_JOIN_REQ() = 1;
+    } else {
+        LM_F_LAST_TX_IS_JOIN_REQ() = 0;
     }
 
-    if (NodeAckRequested == true) {
-        hal_timer_start_at(&AckTimeoutTimer,  curTime +
-                ((RxWindow2Delay + ACK_TIMEOUT +
-                  randr(-ACK_TIMEOUT_RND, ACK_TIMEOUT_RND)) * 1000));
+    if (LM_F_NODE_ACK_REQ()) {
+        getPhy.Attribute = PHY_ACK_TIMEOUT;
+        phyParam = RegionGetPhyParam(LoRaMacRegion, &getPhy);
+        hal_timer_start_at(&g_lora_mac_data.rtx_timer, curTime +
+                           ((g_lora_mac_data.rx_win2_delay + phyParam.Value) * 1000));
     } else {
         /*
          * For unconfirmed transmisson for class C devices,
@@ -1224,32 +826,39 @@ lora_mac_process_radio_tx(struct os_event *ev)
          * window before moving on to another transmission.
          */
         if (LoRaMacDeviceClass == CLASS_C) {
-            hal_timer_start_at(&RxWindowTimer2,
-                               curTime + (RxWindow2Delay * 1000));
+            timeout = (g_lora_mac_data.rx_win2_delay * 1000);
+            /* XXX: work-around for now. Must insure that we give enough
+             * time to hear a complete join accept in window 2 so we add
+             * 2 seconds here
+             */
+            if (LM_F_LAST_TX_IS_JOIN_REQ()) {
+                timeout += (2000 * 1000);
+            } else {
+                timeout += (uint32_t)((RxWindow2Config.tsymbol * 1000) *
+                    RxWindow2Config.WindowTimeout);
+            }
+            hal_timer_start_at(&g_lora_mac_data.rtx_timer, curTime + timeout);
         }
     }
 
+    // Store last Tx channel
+    g_lora_mac_data.last_tx_chan = g_lora_mac_data.cur_chan;
+
     // Update last tx done time for the current channel
-    Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
+    txDone.Channel = g_lora_mac_data.cur_chan;
+    txDone.Joined = LM_F_IS_JOINED();
+    txDone.LastTxDoneTime = curTime;
+    RegionSetBandTxDone(LoRaMacRegion, &txDone);
 
     // Update Aggregated last tx done time
-    AggregatedLastTxDoneTime = curTime;
-
-    lora_node_log(LORA_NODE_LOG_TX_DONE, Channel, 0, curTime);
+    g_lora_mac_data.aggr_last_tx_done_time = curTime;
 
-    // Update Backoff
-    CalculateBackOff(Channel);
-
-    if (NodeAckRequested == false) {
-        ChannelsNbRepCounter++;
+    if (!LM_F_NODE_ACK_REQ()) {
+        g_lora_mac_data.nb_rep_cntr++;
     }
 
-    /* TODO: move this somewhere else? */
-    /* We increment join request transmissions here */
-    if ((LoRaMacFlags.Bits.MlmeReq == 1) &&
-        (g_lora_mac_data.txpkt.pkt_type == MLME_JOIN)) {
-        STATS_INC(lora_mac_stats, join_req_tx);
-    }
+    lora_node_log(LORA_NODE_LOG_TX_DONE, g_lora_mac_data.cur_chan,
+                  LoRaMacBufferPktLen, curTime);
 }
 
 /**
@@ -1264,23 +873,22 @@ lora_mac_process_radio_rx(struct os_event *ev)
 {
     LoRaMacHeader_t macHdr;
     LoRaMacFrameCtrl_t fCtrl;
-    uint8_t entry_rx_slot;
+    LoRaMacRxSlot_t entry_rx_slot;
     struct lora_pkt_info *rxi;
     bool skipIndication = false;
     bool send_indicate = false;
-    int tx_service_over = 0;
-
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     uint8_t *payload;
     uint16_t size;
     int8_t snr;
-
-    uint8_t hdrlen = 0;
+    uint8_t hdrlen;
     uint32_t address = 0;
     uint8_t appPayloadStartIndex = 0;
     uint8_t port = 0xFF;
-    uint8_t frameLen = 0;
+    uint8_t frameLen;
     uint32_t mic = 0;
-    uint32_t micRx = 0;
+    uint32_t micRx;
 
     uint16_t sequenceCounter = 0;
     uint16_t sequenceCounterPrev = 0;
@@ -1293,7 +901,12 @@ lora_mac_process_radio_rx(struct os_event *ev)
 
     uint8_t multicast = 0;
 
-    bool isMicOk = false;
+    /*
+     * XXX: what if window 2 timeout event already enqueued? If we
+     * receive a frame with a valid MIC we are supposed to not receive
+     * on window 2. We stop the timer below but what if event has been
+     * processed?
+     */
 
     /* Put radio to sleep if not class C */
     if (LoRaMacDeviceClass != CLASS_C) {
@@ -1311,7 +924,7 @@ lora_mac_process_radio_rx(struct os_event *ev)
 
     /* Reset rest of global indication element */
     rxi->port = 0;
-    entry_rx_slot = RxSlot;
+    entry_rx_slot = g_lora_mac_data.rx_slot;
     rxi->rxdinfo.rxslot = entry_rx_slot;
     rxi->rxdinfo.multicast = 0;
     rxi->rxdinfo.frame_pending = 0;
@@ -1319,109 +932,30 @@ lora_mac_process_radio_rx(struct os_event *ev)
     rxi->rxdinfo.ack_rxd = false;
     rxi->rxdinfo.downlink_cntr = 0;
 
-    lora_node_log(LORA_NODE_LOG_RX_DONE, Channel, size, entry_rx_slot);
+    /* Get the MHDR from the received frame */
+    macHdr.Value = payload[0];
+    hdrlen = 1;
 
-    macHdr.Value = payload[hdrlen++];
+    lora_node_log(LORA_NODE_LOG_RX_DONE, g_lora_mac_data.cur_chan, size,
+                  (entry_rx_slot << 8) | macHdr.Value);
 
-    switch (macHdr.Bits.MType)
-    {
+    switch (macHdr.Bits.MType) {
         case FRAME_TYPE_JOIN_ACCEPT:
-            STATS_INC(lora_mac_stats, join_accept_rx);
-
-            if (IsLoRaMacNetworkJoined == true) {
-                /* XXX: count statistic here? */
-                goto process_rx_done;
-            }
-
-            /*
-             * XXX: This is odd, but if we receive a join accept and we are not
-             * joined but have not started the join process not sure what to
-             * do. Guess we will just ignore this packet.
-             */
-            if ((LoRaMacFlags.Bits.MlmeReq == 0) ||
-                (g_lora_mac_data.txpkt.pkt_type != MLME_JOIN)) {
-                goto process_rx_done;
-            }
-            lora_node_qual_sample(rxi->rxdinfo.rssi, snr);
-
-            LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 );
-
-            LoRaMacRxPayload[0] = macHdr.Value;
-
-            LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
-
-            micRx |= ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
-            micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 );
-            micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
-            micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
-
-            if (micRx == mic) {
-                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 *= 1e3;
-                LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3;
-
-#if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-                //CFList
-                if( ( size - 1 ) > 16 ) {
-                    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;
-                }
-#endif
-                STATS_INC(lora_mac_stats, joins);
-                hal_timer_stop(&RxWindowTimer2);
-                IsLoRaMacNetworkJoined = true;
-                UpLinkCounter = 0;
-                ChannelsNbRepCounter = 0;
-                LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
-                lora_mac_send_join_confirm(LORAMAC_EVENT_INFO_STATUS_OK,
-                                           JoinRequestTrials);
-            } else {
-                STATS_INC(lora_mac_stats, rx_mic_failures);
-            }
+            lora_mac_join_accept_rxd(payload, size);
             break;
         case FRAME_TYPE_DATA_CONFIRMED_DOWN:
         case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
             /* If not joined I do not know why we would accept a frame */
-            if (IsLoRaMacNetworkJoined == false) {
+            if (!LM_F_IS_JOINED()) {
                 goto process_rx_done;
             }
 
             address = payload[hdrlen++];
-            address |= ( (uint32_t)payload[hdrlen++] << 8 );
-            address |= ( (uint32_t)payload[hdrlen++] << 16 );
-            address |= ( (uint32_t)payload[hdrlen++] << 24 );
+            address |= ((uint32_t)payload[hdrlen++] << 8);
+            address |= ((uint32_t)payload[hdrlen++] << 16);
+            address |= ((uint32_t)payload[hdrlen++] << 24) ;
 
-            if (address != LoRaMacDevAddr) {
+            if (address != g_lora_mac_data.dev_addr) {
                 curMulticastParams = MulticastChannels;
                 while (curMulticastParams != NULL) {
                     if (address == curMulticastParams->Address) {
@@ -1443,7 +977,7 @@ lora_mac_process_radio_rx(struct os_event *ev)
                 multicast = 0;
                 nwkSKey = LoRaMacNwkSKey;
                 appSKey = LoRaMacAppSKey;
-                downLinkCounter = DownLinkCounter;
+                downLinkCounter = g_lora_mac_data.downlink_cntr;
             }
 
             lora_node_qual_sample(rxi->rxdinfo.rssi, snr);
@@ -1454,7 +988,7 @@ lora_mac_process_radio_rx(struct os_event *ev)
 
             appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
 
-            micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN];
+            micRx = ( uint32_t )payload[size - LORAMAC_MFR_LEN];
             micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 );
             micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 );
             micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 );
@@ -1464,228 +998,277 @@ lora_mac_process_radio_rx(struct os_event *ev)
 
             /* Check for correct MIC */
             downLinkCounter += sequenceCounterDiff;
-            LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
+            LoRaMacComputeMic(payload, size - LORAMAC_MFR_LEN, nwkSKey, address,
+                              DOWN_LINK, downLinkCounter, &mic);
             if (micRx == mic) {
-                isMicOk = true;
                 /* XXX: inc mic good stat */
                 rxi->status = LORAMAC_EVENT_INFO_STATUS_OK;
                 rxi->rxdinfo.multicast = multicast;
                 rxi->rxdinfo.frame_pending = fCtrl.Bits.FPending;
                 rxi->rxdinfo.downlink_cntr = downLinkCounter;
+
+                /*
+                 * Per spec v1.1: a device MUST not open the second receive if
+                 * it receives a frame destined to it and it passes the MIC in
+                 * the first receive window.
+                 *
+                 * NOTE: only class A devices use the window 2 timer. If the
+                 * frame was receiving during the second window stopping the
+                 * timer has no effect so that is why we do not check for
+                 * receiving this in window 1
+                 */
+                lora_mac_rx_win2_stop();
             } else {
                 STATS_INC(lora_mac_stats, rx_mic_failures);
+                goto process_rx_done;
             }
 
             /* 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) {
                 /*
                  * XXX: For now we will hand up the indication with this error
                  * status and let the application handle re-join. Note this in
-                 * the documentation! This is only if the MIC is valid. If not,
-                 * we will just ignore the received frame.
+                 * the documentation!
+                 *
+                 * XXX: this should be handled differently. Flush txq and
+                 * inform upper layer this happened. Indicate is not great.
                  *
                  * NOTE: we wont process an ACK, so confirmed frames would get
                  * re-transmitted here.
                  */
-                if (isMicOk) {
-                    rxi->status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
-                    send_indicate = true;
-                }
+                rxi->status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
+                send_indicate = true;
                 goto process_rx_done;
             }
 
-            if (isMicOk == true) {
-                AdrAckCounter = 0;
-                MacCommandsBufferToRepeatIndex = 0;
+            g_lora_mac_data.adr_ack_cntr = 0;
+            MacCommandsBufferToRepeatIndex = 0;
+
+            /*
+             * XXX: Look into confirmed frames and multicast and the
+             * "gw_ack_req" bit. I think the bit should be reset after
+             * every valid reception (except possibly multicast case).
+             * Need to see if there is a frame already created and if the
+             * ACK bit is set in it. If it is and we just received a
+             * non-confirmd downlink or multicast the ACK bit going up
+             * should be cleared.
+             */
+
+            // Update 32 bits downlink counter
+            if (multicast == 1) {
+                rxi->pkt_type = MCPS_MULTICAST;
 
-                // Update 32 bits downlink counter
-                if (multicast == 1) {
-                    rxi->pkt_type = MCPS_MULTICAST;
+                if((curMulticastParams->DownLinkCounter == downLinkCounter ) &&
+                    (curMulticastParams->DownLinkCounter != 0)) {
+                    /* XXX: I need to understand multicast. Are these sent
+                     * in normal rx windows and act the same as normal
+                       transmissions? */
 
-                    if((curMulticastParams->DownLinkCounter == downLinkCounter ) &&
-                        (curMulticastParams->DownLinkCounter != 0)) {
-                        /* XXX: I need to understand multicast. Are these sent
-                         * in normal rx windows and act the same as normal
-                           transmissions? */
+                    /* XXX: count stat */
+                    rxi->status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
+                    send_indicate = true;
+                    goto process_rx_done;
+                }
+                curMulticastParams->DownLinkCounter = downLinkCounter;
+            } else {
+                if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN) {
+                    LM_F_GW_ACK_REQ() = 1;
+                    rxi->pkt_type = MCPS_CONFIRMED;
+
+                    /* XXX: why not initialize the DownLinkCounter to
+                       all 0xf instead of check for 0 */
+                    if ((g_lora_mac_data.downlink_cntr == downLinkCounter) &&
+                        (g_lora_mac_data.downlink_cntr != 0) ) {
+                        /* Duplicated confirmed downlink. Skip indication.*/
+                        STATS_INC(lora_mac_stats, rx_dups);
+                        skipIndication = true;
+                    }
+                } else {
+                    LM_F_GW_ACK_REQ() = 0;
+                    rxi->pkt_type = MCPS_UNCONFIRMED;
 
-                        /* XXX: count stat */
+                    /*
+                     * XXX: this should be handled differently. Something
+                     * akin to what happens if we get a frame counter gap
+                     * that is too big.
+                     */
+                    if ((g_lora_mac_data.downlink_cntr == downLinkCounter ) &&
+                        (g_lora_mac_data.downlink_cntr != 0)) {
                         rxi->status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
+
+                        /* Duplicated unconfirmed downlink. */
+                        STATS_INC(lora_mac_stats, rx_dups);
+
                         send_indicate = true;
                         goto process_rx_done;
                     }
-                    curMulticastParams->DownLinkCounter = downLinkCounter;
-                } else {
-                    if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN) {
-                        SrvAckRequested = true;
-                        rxi->pkt_type = MCPS_CONFIRMED;
-
-                        if ((DownLinkCounter == downLinkCounter) &&
-                            (DownLinkCounter != 0) ) {
-                            /* Duplicated confirmed downlink. Skip indication.*/
-                            skipIndication = true;
-                        }
-                    } else {
-                        SrvAckRequested = false;
-                        rxi->pkt_type = MCPS_UNCONFIRMED;
-
-                        /* XXX: this should never happen. What should we do?
-                           Count stat */
-                        if ((DownLinkCounter == downLinkCounter ) &&
-                            (DownLinkCounter != 0)) {
-                            rxi->status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
-                            send_indicate = true;
-                            goto process_rx_done;
-                        }
-                    }
-                    DownLinkCounter = downLinkCounter;
                 }
+                g_lora_mac_data.downlink_cntr = downLinkCounter;
+            }
 
-                /* XXX: Make sure MacCommands are handled properly */
-                // 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.
-                if ((g_lora_mac_data.curtx != NULL) &&
-                    (g_lora_mac_data.curtx->pkt_type == MCPS_CONFIRMED)) {
-                    if (fCtrl.Bits.Ack == 1) {
-                        // Reset MacCommandsBufferIndex when we have received an ACK.
-                        MacCommandsBufferIndex = 0;
-                    }
-                } else {
-                    // Reset the variable if we have received any valid frame.
+            /* XXX: Make sure MacCommands are handled properly */
+            // 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.
+            if ((g_lora_mac_data.curtx != NULL) &&
+                (g_lora_mac_data.curtx->pkt_type == MCPS_CONFIRMED)) {
+                if (fCtrl.Bits.Ack == 1) {
+                    // Reset MacCommandsBufferIndex when we have received an ACK.
                     MacCommandsBufferIndex = 0;
                 }
+            } else {
+                // Reset the variable if we have received any valid frame.
+                MacCommandsBufferIndex = 0;
+            }
 
-                if (((size - 4) - appPayloadStartIndex) > 0) {
-                    port = payload[appPayloadStartIndex++];
-                    frameLen = (size - 4) - appPayloadStartIndex;
-
-                    rxi->port = port;
-
-                    lora_node_log(LORA_NODE_LOG_RX_PORT, port, frameLen, 0);
-
-                    if (port == 0) {
-                        STATS_INC(lora_mac_stats, rx_mlme);
-                        if (fCtrl.Bits.FOptsLen == 0) {
-                            LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
-                                                   frameLen,
-                                                   nwkSKey,
-                                                   address,
-                                                   DOWN_LINK,
-                                                   downLinkCounter,
-                                                   LoRaMacRxPayload );
-
-                            // Decode frame payload MAC commands
-                            ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr );
-                        } else {
-                            /* This is an invalid frame. Ignore it */
-                            goto process_rx_done;
-                            /* XXX: stat */
-                        }
-                    } else {
-                        STATS_INC(lora_mac_stats, rx_mcps);
+            if (((size - 4) - appPayloadStartIndex) > 0) {
+                port = payload[appPayloadStartIndex++];
+                frameLen = (size - 4) - appPayloadStartIndex;
 
-                        if( fCtrl.Bits.FOptsLen > 0 ) {
-                            // Decode Options field MAC commands. Omit the fPort.
-                            ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr );
-                        }
+                rxi->port = port;
 
+                lora_node_log(LORA_NODE_LOG_RX_PORT, port, frameLen, 0);
+
+                /* If port is 0 it means frame has MAC commands in payload */
+                if (port == 0) {
+                    STATS_INC(lora_mac_stats, rx_mlme);
+                    if (fCtrl.Bits.FOptsLen == 0) {
                         LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
                                                frameLen,
-                                               appSKey,
+                                               nwkSKey,
                                                address,
                                                DOWN_LINK,
                                                downLinkCounter,
                                                LoRaMacRxPayload );
 
-                        if (skipIndication == false ) {
-                            g_lora_mac_data.rxbuf = LoRaMacRxPayload;
-                            g_lora_mac_data.rxbufsize = frameLen;
-                            rxi->rxdinfo.rxdata = true;
-                            send_indicate = true;
-                        }
+                        // Decode frame payload MAC commands
+                        ProcessMacCommands(LoRaMacRxPayload, 0, frameLen, snr);
+                    } else {
+                        /* This is an invalid frame. Ignore it */
+                        STATS_INC(lora_mac_stats, rx_invalid);
+                        goto process_rx_done;
                     }
                 } else {
+                    STATS_INC(lora_mac_stats, rx_mcps);
+
                     if (fCtrl.Bits.FOptsLen > 0) {
-                        // Decode Options field MAC commands
-                        ProcessMacCommands( payload, 8, appPayloadStartIndex, snr );
+                        // Decode Options field MAC commands. Omit the fPort.
+                        ProcessMacCommands(payload, 8, appPayloadStartIndex - 1,
+                                           snr);
                     }
-                }
 
-                /* We received a valid frame. */
-                if (NodeAckRequested) {
-                    if (skipIndication == false) {
-                        // Check if the frame is an acknowledgement
-                        if (fCtrl.Bits.Ack == 1) {
-                            rxi->rxdinfo.ack_rxd = true;
-                            hal_timer_stop(&AckTimeoutTimer);
-                            hal_timer_stop(&RxWindowTimer2);
-                            lora_mac_tx_service_done(1);
-                            goto process_rx_done;
-                        }
+                    LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
+                                           frameLen,
+                                           appSKey,
+                                           address,
+                                           DOWN_LINK,
+                                           downLinkCounter,
+                                           LoRaMacRxPayload );
+
+                    if (skipIndication == false ) {
+                        g_lora_mac_data.rxbuf = LoRaMacRxPayload;
+                        g_lora_mac_data.rxbufsize = frameLen;
+                        rxi->rxdinfo.rxdata = true;
+                        send_indicate = true;
                     }
+                }
+            } else {
+                /*
+                 * No application payload. Process any mac commands in the
+                 * fopts field. No need to send indicate
+                 */
+                if (fCtrl.Bits.FOptsLen > 0) {
+                    // Decode Options field MAC commands
+                    ProcessMacCommands( payload, 8, appPayloadStartIndex, snr );
+                }
+            }
 
-                    /*
-                     * XXX:
-                     * We received a valid frame but no ack. If class
-                     * A should we stop rx window 2 since we received
-                     * a frame? Not sure about this.
-                     */
-                    if (LoRaMacDeviceClass == CLASS_A) {
-                        hal_timer_stop(&RxWindowTimer2);
+            /* We received a valid frame. */
+            if (LM_F_NODE_ACK_REQ()) {
+                if (skipIndication == false) {
+                    // Check if the frame is an acknowledgement
+                    if (fCtrl.Bits.Ack == 1) {
+                        rxi->rxdinfo.ack_rxd = true;
+
+                        /*
+                         * We received an ACK. Stop the retransmit timer
+                         * and confirm successful transmission.
+                         */
+                        lora_mac_rtx_timer_stop();
+                        lora_mac_tx_service_done(1);
                     }
-                } else {
+                }
+            } else {
+                /*
+                 * The specification is not the greatest here. It states
+                 * that a frame cannot be retransmitted unless a valid
+                 * frame was received in either window 1 or window 2. This
+                 * makes sense for Class A but what about class C? They
+                 * mean the actual receive window 2 and not receiving on
+                 * window 2 parameters (if you know what I mean). Thus,
+                 * the check below is if the device is class A or this
+                 * was receive window 1 we end the transmission service.
+                 */
+                if ((LoRaMacDeviceClass == CLASS_A) ||
+                    (entry_rx_slot == RX_SLOT_WIN_1)) {
+
+                    /* Stop the retransmit timer as we can now transmit */
+                    lora_mac_rtx_timer_stop();
+
                     /*
-                     * No need to stop window 2 if class A and we received
-                     * a frame on window 2. For any class we are
-                     * allowed to transmit again since we heard a frame.
+                     * The spec is clear in this case: an unconfirmed
+                     * frame should not be retransmitted NbTrans # of times
+                     * if a valid frame was received in either window 1
+                     * or window 2 for class A or in receive window 1 for
+                     * class C. Calling the tx service done function with
+                     * 1 will make sure no more retransmissions occur.
                      */
-                    if ((LoRaMacDeviceClass == CLASS_C) || (!entry_rx_slot)) {
-                        hal_timer_stop(&RxWindowTimer2);
-                    }
-                    tx_service_over = 1;
+                    lora_mac_tx_service_done(1);
+                    goto chk_send_indicate;
                 }
             }
             break;
         case FRAME_TYPE_PROPRIETARY:
-            /* XXX: we do not handle proprietary frames right now */
-            /* XXX: stat */
             break;
         default:
-            /* XXX: stat */
             break;
     }
 
 process_rx_done:
     if (LoRaMacDeviceClass == CLASS_C) {
-        lora_mac_rx_on_window2(true);
-        if (tx_service_over) {
-            lora_mac_tx_service_done(0);
-        } else {
-            /* If an ack is being requested it means that the ack retry
-             * timer will dictate when we can send again. Note that
-             * the original frame cannot be handed up yet (the tx
-             * service is not done).
-             *
-             * If not a confirmed frame and we received on window 2, we
-             * are now allowed to transmit.
-             */
-            if ((NodeAckRequested == false) && (entry_rx_slot == 1)) {
-                lora_mac_tx_service_done(0);
-            }
+        /* If we are not receiving, start receiving on window 2 parameters */
+        if (Radio.GetStatus() == RF_IDLE) {
+            lora_mac_rx_on_window2();
         }
     } else {
-        /* If second receive window and a transmit service is running end it */
-        if (tx_service_over ||
-            ((NodeAckRequested == false) && (entry_rx_slot == 1) &&
+        /*
+         * If second receive window and a transmit service is running end it.
+         * If a confirmed frame the retransmission timer will handle ending
+         * the transmit service. Note that we put the retransmit timeout
+         * event on the queue as opposed to calling tx service done so that
+         * we do not attempt to retransmit the frame in this call.
+         */
+        if ((!LM_F_NODE_ACK_REQ() && (entry_rx_slot == RX_SLOT_WIN_2) &&
              (LoRaMacState & LORAMAC_TX_RUNNING))) {
-            lora_mac_tx_service_done(0);
+            os_eventq_put(lora_node_mac_evq_get(), &g_lora_mac_rtx_timeout_event);
         }
     }
 
     /* Send MCPS indication if flag set */
+chk_send_indicate:
     if (send_indicate) {
         lora_node_mac_mcps_indicate();
     }
+
+    /*
+     * If gw wants an ack, make sure we check on transmit queue to send it if
+     * no other frames enqueued
+     */
+    if (LM_F_GW_ACK_REQ()) {
+        lora_node_chk_txq();
+    }
 }
 
 /**
@@ -1703,7 +1286,7 @@ lora_mac_process_radio_tx_timeout(struct os_event *ev)
     if (LoRaMacDeviceClass != CLASS_C) {
         Radio.Sleep( );
     } else {
-        lora_mac_rx_on_window2(true);
+        lora_mac_rx_on_window2();
     }
     STATS_INC(lora_mac_stats, tx_timeouts);
 
@@ -1719,48 +1302,37 @@ lora_mac_process_radio_rx_err(struct os_event *ev)
 
     if (LoRaMacDeviceClass != CLASS_C) {
         Radio.Sleep( );
-        if (RxSlot == 1) {
-            if (NodeAckRequested == false) {
+        if (g_lora_mac_data.rx_slot == RX_SLOT_WIN_2) {
+            if (!LM_F_NODE_ACK_REQ()) {
                 lora_mac_tx_service_done(0);
             }
         }
     } else {
-        /*
-         * If this is a class C device and the RxSlot is 1 it means that
-         * we got an error during rx window 2. No way this could happen unless
-         * there is an unconfirmed frame waiting to be transmitted.
-         */
-        if (RxSlot == 1) {
-            lora_mac_tx_service_done(0);
+        /* If we are not receiving start receiving on window 2 */
+        if (Radio.GetStatus() == RF_IDLE) {
+            lora_mac_rx_on_window2();
         }
-        lora_mac_rx_on_window2(true);
     }
 }
 
 static void
 lora_mac_process_radio_rx_timeout(struct os_event *ev)
 {
-    lora_node_log(LORA_NODE_LOG_RX_TIMEOUT, Channel, RxSlot, 0);
+    lora_node_log(LORA_NODE_LOG_RX_TIMEOUT, g_lora_mac_data.cur_chan,
+                  g_lora_mac_data.rx_slot, 0);
 
     if (LoRaMacDeviceClass != CLASS_C) {
         Radio.Sleep( );
-        if (RxSlot == 1) {
+        if (g_lora_mac_data.rx_slot == RX_SLOT_WIN_2) {
             /* Let the ACK retry timer handle confirmed transmissions */
-            if (NodeAckRequested == false) {
+            if (!LM_F_NODE_ACK_REQ()) {
                 lora_mac_tx_service_done(0);
             }
         }
     } else {
-        /*
-         * If class C and we sent an unconfirmed frame, we can only
-         * re-transmit after window 2 expires. If this is a confirmed frame
-         * we never started window 2 and re-transmission occurs after ACK
-         * retry timer.
-         */
-        if ((NodeAckRequested == false) && (RxSlot == 1)) {
-            lora_mac_tx_service_done(0);
-        }
-        lora_mac_rx_on_window2(true);
+        /* Rx timeout for class C devices should only occur in rx window 1 */
+        assert(g_lora_mac_data.rx_slot == RX_SLOT_WIN_1);
+        lora_mac_rx_on_window2();
     }
 }
 
@@ -1769,24 +1341,34 @@ lora_mac_process_tx_delay_timeout(struct os_event *ev)
 {
     LoRaMacHeader_t macHdr;
     LoRaMacFrameCtrl_t fCtrl;
+    LoRaMacStatus_t rc;
 
+    /*
+     * XXX: not sure if we should keep this code the way it is. I am thinking
+     * probably better to not call ScheduleTx() here and remove all this
+     * code that is basically duplicated for the join process.
+     *
+     * I guess the main question is this: should the process transmit queue
+     * function only be taking a packet off the queue and then starting
+     * the whole transmit process (the transmit service I will call it) or
+     * should that code also notice that a transmit process is currently
+     * happening and deal with that?.
+     */
     LoRaMacState &= ~LORAMAC_TX_DELAYED;
 
     /*
      * It is possible that the delay timer is running but we finished
      * the transmit service. If that is the case, just return
      */
-    if ((LoRaMacFlags.Bits.MlmeReq == 0) && (LoRaMacFlags.Bits.McpsReq == 0)) {
+    if (!LM_F_IS_JOINING() && !LM_F_IS_MCPS_REQ()) {
         lora_node_chk_txq();
         return;
     }
 
-    if ((LoRaMacFlags.Bits.MlmeReq == 1) &&
-        (g_lora_mac_data.txpkt.pkt_type == MLME_JOIN)) {
-        ResetMacParameters( );
-
-        // Add a +1, since we start to count from 0
-        LoRaMacParams.ChannelsDatarate = AlternateDatarate(JoinRequestTrials + 1);
+    if (LM_F_IS_JOINING()) {
+        /* Since this is a join we may need to change datarate */
+        LoRaMacParams.ChannelsDatarate =
+            RegionAlternateDr(LoRaMacRegion, LoRaMacParams.ChannelsDatarate);
 
         macHdr.Value = 0;
         macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
@@ -1800,695 +1382,189 @@ lora_mac_process_tx_delay_timeout(struct os_event *ev)
         PrepareFrame(&macHdr, &fCtrl, 0, NULL);
     }
 
-    ScheduleTx( );
+    rc = ScheduleTx();
+    if (rc != LORAMAC_STATUS_OK) {
+        lora_mac_tx_service_done(0);
+    }
 }
 
 static void
 lora_mac_process_rx_win1_timeout(struct os_event *ev)
 {
-    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
-    int8_t datarate;
-    uint32_t bandwidth = 0; // LoRa 125 kHz
-
-#if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID))
-    uint16_t symb_usecs;
-#endif
+    g_lora_mac_data.rx_slot = RX_SLOT_WIN_1;
 
-    RxSlot = 0;
+    RxWindow1Config.Channel = g_lora_mac_data.cur_chan;
+    RxWindow1Config.DrOffset = LoRaMacParams.Rx1DrOffset;
+    RxWindow1Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+    RxWindow1Config.RepeaterSupport = LM_F_REPEATER_SUPP();
+    RxWindow1Config.RxContinuous = false;
+    RxWindow1Config.RxSlot = RX_SLOT_WIN_1;
 
     if (LoRaMacDeviceClass == CLASS_C) {
         Radio.Standby( );
     }
 
-    datarate = LoRaMacParams.ChannelsDatarate;
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    datarate -= LoRaMacParams.Rx1DrOffset;
-    if (datarate < 0) {
-        datarate = DR_0;
-    }
-
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if ((datarate == DR_3) || (datarate == DR_4)) {
-        // DR_4, DR_3
-        symbTimeout = 8;
-    } else if (datarate == DR_5) {
-        symbTimeout = 10;
-    } else if( datarate == DR_6 ) {
-        // LoRa 250 kHz
-        bandwidth  = 1;
-        symbTimeout = 14;
-    }
-    RxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
-#elif defined( USE_BAND_470 )
-    datarate -= LoRaMacParams.Rx1DrOffset;
-    if (datarate < 0) {
-        datarate = DR_0;
-    }
-
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if ((datarate == DR_3) || (datarate == DR_4)) {
-        // DR_4, DR_3
-        symbTimeout = 8;
-    } else if( datarate == DR_5 ) {
-        symbTimeout = 10;
-    }
-    RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, datarate, bandwidth, symbTimeout, false );
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    datarate = datarateOffsets[datarate][LoRaMacParams.Rx1DrOffset];
-
-    /*
-     * XXX: why is this done? We are searching for a preamble and the preamble
-     * is fixed at 8 symbols. Why does this need to change for based on the
-     * datarate?
-     */
+    lora_node_log(LORA_NODE_LOG_RX_WIN1_SETUP, RxWindow1Config.Datarate,
+                  g_lora_mac_data.cur_chan, RxWindow1Config.WindowTimeout);
 
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    switch (datarate) {
-        case DR_0:       // SF10 - BW125
-            /* XXX: this was 5, I made it 8 */
-            //symbTimeout = 5;
-            symbTimeout = 8;
-            break;
-
-        case DR_1:       // SF9  - BW125
-        case DR_2:       // SF8  - BW125
-        case DR_8:       // SF12 - BW500
-        case DR_9:       // SF11 - BW500
-        case DR_10:      // SF10 - BW500
-            symbTimeout = 8;
-            break;
+    /* XXX: check error codes! */
+    RegionRxConfig(LoRaMacRegion, &RxWindow1Config,
+                   (int8_t *)&g_lora_mac_data.rxpkt.rxdinfo.rxdatarate);
 
-        case DR_3:       // SF7  - BW125
-        case DR_11:      // SF9  - BW500
-            symbTimeout = 10;
-            break;
-
-        case DR_4:       // SF8  - BW500
-        case DR_12:      // SF8  - BW500
-            symbTimeout = 14;
-            break;
-
-        case DR_13:      // SF7  - BW500
-            symbTimeout = 16;
-            break;
-        default:
-            break;
-    }
-
-    /*
-     * XXX: this seems to me to be quite chip specific. Probably should be moved
-     * into radio code as only the radio knows the details of the timer. Note
-      * that we use the uncoded symbol length to give us a bit more wait time.
-     */
-    symb_usecs = g_lora_uncoded_symbol_len_usecs[datarate];
-    symbTimeout += ((RADIO_WAKEUP_TIME * 1000) + (symb_usecs - 1)) / symb_usecs;
-
-    // LoRa 500 kHz
-    if (datarate >= DR_4) {
-        bandwidth  = 2;
-    }
-    RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 8 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, datarate, bandwidth, symbTimeout, false );
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
+    RxWindowSetup(RxWindow1Config.RxContinuous, LoRaMacParams.MaxRxWindow);
 }
 
 /**
- * Called to set receiver on window 2 parameters. The parameter rx_continuous
- * is used exclusively for Class C devices. It is used when receiving at the
- * start of receive window 2 and it used so that we can generate a timeout if
- * no packet is received.
+ * lora mac rx on window 2
  *
- *
- * @param rx_continuous
+ * Called to receive on Rx Window 2 parameters. When this function is called
+ * it is expected that the radio is not currently receiving on window 2
+ * parameters
  */
 void
-lora_mac_rx_on_window2(bool rx_continuous)
+lora_mac_rx_on_window2(void)
 {
-    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
-    uint32_t bandwidth = 0; // LoRa 125 kHz
+    bool rc;
+    bool rx_continuous;
+    uint8_t rx_slot;
 
-    /*
-     * RxSlot = 1 means we are receiving on the "real" window 2. RxSlot = 2
-     * means we are a class C device receiving on window 2 parameters but
-     * not during the actual second receive window.
-     */
     if (LoRaMacDeviceClass == CLASS_C) {
-        if (rx_continuous) {
-            RxSlot = 2;
-        } else {
-            RxSlot = 1;
-        }
+        rx_slot = RX_SLOT_WIN_CLASS_C;
+        rx_continuous = 1;
     } else {
-        RxSlot = 1;
+        rx_slot = RX_SLOT_WIN_2;
+        rx_continuous = 0;
     }
 
-    lora_node_log(LORA_NODE_LOG_RX_WIN2, RxSlot, 0, rx_continuous);
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( ( LoRaMacParams.Rx2Channel.Datarate == DR_3 ) || ( LoRaMacParams.Rx2Channel.Datarate == DR_4 ) )
-    { // DR_4, DR_3
-        symbTimeout = 8;
-    }
-    else if( LoRaMacParams.Rx2Channel.Datarate == DR_5 )
-    {
-        symbTimeout = 10;
-    }
-    else if( LoRaMacParams.Rx2Channel.Datarate == DR_6 )
-    {// LoRa 250 kHz
-        bandwidth  = 1;
-        symbTimeout = 14;
-    }
-#elif defined( USE_BAND_470 )
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( ( LoRaMacParams.Rx2Channel.Datarate == DR_3 ) || ( LoRaMacParams.Rx2Channel.Datarate == DR_4 ) )
-    { // DR_4, DR_3
-        symbTimeout = 8;
-    }
-    else if( LoRaMacParams.Rx2Channel.Datarate == DR_5 )
-    {
-        symbTimeout = 10;
-    }
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    switch( LoRaMacParams.Rx2Channel.Datarate )
-    {
-        case DR_0:       // SF10 - BW125
-            symbTimeout = 5;
-            break;
+    lora_node_log(LORA_NODE_LOG_RX_WIN2, rx_slot, 0,
+                  LoRaMacParams.Rx2Channel.Frequency);
 
-        case DR_1:       // SF9  - BW125
-        case DR_2:       // SF8  - BW125
-        case DR_8:       // SF12 - BW500
-        case DR_9:       // SF11 - BW500
-        case DR_10:      // SF10 - BW500
-            symbTimeout = 8;
-            break;
+    g_lora_mac_data.rx_slot = rx_slot;
 
-        case DR_3:       // SF7  - BW125
-        case DR_11:      // SF9  - BW500
-            symbTimeout = 10;
-            break;
+    RxWindow2Config.Channel = g_lora_mac_data.cur_chan;
+    RxWindow2Config.Frequency = LoRaMacParams.Rx2Channel.Frequency;
+    RxWindow2Config.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+    RxWindow2Config.RepeaterSupport = LM_F_REPEATER_SUPP();
+    RxWindow2Config.RxSlot = RX_SLOT_WIN_2;
+    RxWindow2Config.RxContinuous = rx_continuous;
 
-        case DR_4:       // SF8  - BW500
-        case DR_12:      // SF8  - BW500
-            symbTimeout = 14;
-            break;
-
-        case DR_13:      // SF7  - BW500
-            symbTimeout = 16;
-            break;
-        default:
-            break;
-    }
-    if( LoRaMacParams.Rx2Channel.Datarate >= DR_4 )
-    {// LoRa 500 kHz
-        bandwidth  = 2;
-    }
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
+    /*
+     * NOTE: this should never fail since we made sure radio was idle and
+     * this is the only way this should fail!
+     */
+    rc = RegionRxConfig(LoRaMacRegion, &RxWindow2Config, (int8_t *)
+                        &g_lora_mac_data.rxpkt.rxdinfo.rxdatarate);
+    assert(rc);
 
-    /* XXX: what happens if call to this fails? Can it? */
-    RxWindowSetup(LoRaMacParams.Rx2Channel.Frequency,
-                  LoRaMacParams.Rx2Channel.Datarate, bandwidth, symbTimeout,
-                  rx_continuous);
+    RxWindowSetup(RxWindow2Config.RxContinuous, LoRaMacParams.MaxRxWindow);
 }
 
 /**
  * Receive Window 2 timeout
  *
- * Called when the receive window 2 timer expires.
+ * Called when the receive window 2 timer expires. This timer is only started
+ * for class A devices.
+ *
+ * Context: MAC task
  *
- * Context: MAC
+ * XXX: I think we may want to modify the code such that window 2 timer only
+ * starts if there is a timeout for window 1. Would make things much easier
+ * I think (simpler).
  *
  * @param unused
  */
 static void
 lora_mac_process_rx_win2_timeout(struct os_event *ev)
 {
-    if (LoRaMacDeviceClass == CLASS_C) {
-        Radio.Standby( );
+    /*
+     * There are two cases here. Either the radio is still receiving in which
+     * case the radio status is not idle, or the radio finished receiving
+     * a frame and posted an event but there was a race condition and this
+     * timer fired off just before the packet was finished. In the latter case,
+     * a receive done event will be enqueued but not processed.
+     */
+    if ((Radio.GetStatus() == RF_IDLE) &&
+        (g_lora_mac_radio_rx_event.ev_queued == 0)) {
+        lora_mac_rx_on_window2();
     }
-    lora_mac_rx_on_window2(false);
 }
 
+/**
+ * lora mac process rtx timeout
+ *
+ * Called when the retransmit timer expires. This timer is set under the
+ * following conditions:
+ *  1) The previous frame sent was a confirmed frame.
+ *  2) The device is class C and an unconfirmed frame was sent.
+ *  3) The device is class A and the second receive window ended and the frame
+ *  is unconfirmed.
+ *
+ *  If this timer does actually expire it means either no ACK was received or
+ *  a class C device is now allowed to transmit another frame.
+ *
+ * @param ev    Pointer to event.
+ */
 static void
-lora_mac_process_ack_timeout(struct os_event *ev)
+lora_mac_process_rtx_timeout(struct os_event *ev)
 {
-    /* This should only be called for Confirmed packets */
-    if (NodeAckRequested) {
-        lora_mac_tx_service_done(0);
-    } else {
-        /* XXX: stat */
-    }
+    lora_node_log(LORA_NODE_LOG_RTX_TIMEOUT, g_lora_mac_data.lmflags.lmf_all, 0,
+                  0);
+    lora_mac_tx_service_done(0);
 }
 
-static bool
-SetNextChannel(uint32_t *time)
+static void
+RxWindowSetup(bool rxContinuous, uint32_t maxRxWindow)
 {
-    uint8_t i, k, j;
-    uint8_t nbEnabledChannels = 0;
-    uint8_t delay_tx = 0;
-    uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
-    uint32_t next_tx_delay = ( uint32_t )( -1 );
-    uint32_t elapsed_tx_done_time;
-
-    memset(enabledChannels, 0, LORA_MAX_NB_CHANNELS);
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    /* Add all 125kHz channels if none left */
-    if (CountNbEnabled125kHzChannels(ChannelsMaskRemaining) == 0) {
-        memcpy((uint8_t*)ChannelsMaskRemaining, (uint8_t*) LoRaMacParams.ChannelsMask, 8 );
-    }
-
-    /* If 500 kHz channels needed, make sure there are some */
-    if ((LoRaMacParams.ChannelsDatarate >= DR_4) &&
-        ((ChannelsMaskRemaining[4] & 0x00FF) == 0)) {
-        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 ) )
-    {
-        memcpy( ( 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
-    elapsed_tx_done_time = TimerGetElapsedTime(AggregatedLastTxDoneTime);
-    if (AggregatedTimeOff <= elapsed_tx_done_time) {
-        AggregatedTimeOff = 0;
-
-        // Update bands Time OFF
-        for (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) {
-                    next_tx_delay = MIN( Bands[i].TimeOff - TimerGetElapsedTime(Bands[i].LastTxDoneTime), next_tx_delay);
-                }
-            } else {
-                if (DutyCycleOn == false) {
-                    Bands[i].TimeOff = 0;
-                }
-            }
-        }
-
-        // Search how many channels are enabled
-        for (i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++) {
-            for (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
-                        delay_tx++;
-                        continue;
-                    }
-                    enabledChannels[nbEnabledChannels++] = i + j;
-                }
-            }
-        }
-    } else {
-        delay_tx++;
-        next_tx_delay = AggregatedTimeOff - elapsed_tx_done_time;
-    }
-
-    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;
+    if (rxContinuous == false) {
+        Radio.Rx(maxRxWindow);
     } else {
-        if (delay_tx > 0) {
-            // Delay transmission due to aggregated time off or to a band time off
-            *time = next_tx_delay;
-            return true;
-        }
-        // Datarate not supported by any channel
-        *time = 0;
-        return false;
+        Radio.Rx(0);
     }
 }
 
 static bool
-RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
-{
-    uint8_t downlinkDatarate = Datarates[datarate];
-    RadioState_t rstate;
-    RadioModems_t modem;
-
-    rstate = Radio.GetStatus();
-    if (rstate != RF_IDLE) {
-        lora_node_log(LORA_NODE_LOG_RX_WIN_SETUP_FAIL, 0, 0, rstate);
-        return false;
-    }
-
-    lora_node_log(LORA_NODE_LOG_RX_WIN_SETUP, datarate, timeout, freq);
-
-    Radio.SetChannel( freq );
-
-    // Store downlink datarate
-    g_lora_mac_data.rxpkt.rxdinfo.rxdatarate = ( uint8_t ) datarate;
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( datarate == DR_7 ) {
-        modem = MODEM_FSK;
-        Radio.SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, 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 );
-    } else {
-        Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD );
-    }
-
-    if( rxContinuous == false ) {
-        Radio.Rx( LoRaMacParams.MaxRxWindow );
-    } else {
-        Radio.Rx( 0 ); // Continuous mode
-    }
-    return true;
-}
-
-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;
-}
-
-static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
+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) {
-        maxN = MaxPayloadOfDatarateRepeater[datarate];
-    } else {
-        maxN = MaxPayloadOfDatarate[datarate];
+    if (LM_F_REPEATER_SUPP()) {
+        getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
     }
+    phyParam = RegionGetPhyParam(LoRaMacRegion, &getPhy);
+    maxN = phyParam.Value;
 
     // Calculate the resulting payload size
     payloadSize = (lenN + fOptsLen);
 
     // Validation of the application payload size
-    if ((payloadSize <= maxN ) && (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) {
-        return true;
-    }
-    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 )
-{
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    int8_t dr;
-#endif
-    int8_t resultTxPower;
-
-    // Limit tx power to the band max
-    resultTxPower =  MAX( txPower, maxBandTxPower );
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    dr = LoRaMacParams.ChannelsDatarate;
-    if ((dr == DR_4) || ((dr >= DR_8) && (dr <= 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)) {
+    if ((payloadSize <= maxN) && (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) {
         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)
+/**
+ * This is called to make sure we schedule an uplink frame ASAP.
+ *
+ * XXX: Not sure if we need to inform the application about any of this. Look
+ * into providing an upper layer callback for the MAC commands that cause this
+ * to happen
+ */
+void
+SetMlmeScheduleUplinkIndication( void )
 {
-    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) == 0) {
-#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
-                            memcpy( ( 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--;
-                    }
-
-                    if (datarate == LORAMAC_TX_MIN_DATARATE) {
-                        if (updateChannelMask == true) {
-#if defined( USE_BAND_915 )
-                            // Re-enable default channels
-                            memcpy( ( 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
-                }
-            }
-        }
+    if (lora_node_txq_empty()) {
+        lora_node_chk_txq();
     }
-
-    *datarateOut = datarate;
-
-    return adrAckReq;
 }
 
 static LoRaMacStatus_t
@@ -2497,7 +1573,7 @@ AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2)
     LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
 
     // The maximum buffer length must take MAC commands to re-send into account.
-    uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex;
+    uint8_t bufLen = LORA_MAC_CMD_BUF_LEN - MacCommandsBufferToRepeatIndex;
 
     switch(cmd) {
         case MOTE_MAC_LINK_CHECK_REQ:
@@ -2527,6 +1603,8 @@ AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2)
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // Status: Datarate ACK, Channel ACK
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+                // This is a sticky MAC command answer. Setup indication
+                SetMlmeScheduleUplinkIndication( );
                 status = LORAMAC_STATUS_OK;
             }
             break;
@@ -2552,6 +1630,27 @@ AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2)
             if (MacCommandsBufferIndex < bufLen) {
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // No payload for this answer
+                // This is a sticky MAC command answer. Setup indication
+                SetMlmeScheduleUplinkIndication( );
+                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;
+
+                // This is a sticky MAC command answer. Setup indication
+                SetMlmeScheduleUplinkIndication( );
+
                 status = LORAMAC_STATUS_OK;
             }
             break;
@@ -2575,6 +1674,7 @@ static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint
     for (i = 0; i < length; i++) {
         switch( cmdBufIn[i] ) {
             // STICKY
+            case MOTE_MAC_DL_CHANNEL_ANS:
             case MOTE_MAC_RX_PARAM_SETUP_ANS:
                 cmdBufOut[cmdCount++] = cmdBufIn[i++];
                 cmdBufOut[cmdCount++] = cmdBufIn[i];
@@ -2592,6 +1692,7 @@ static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint
                 // 1 byte payload
                 i++;
                 break;
+            case MOTE_MAC_TX_PARAM_SETUP_ANS:
             case MOTE_MAC_DUTY_CYCLE_ANS:
             case MOTE_MAC_LINK_CHECK_REQ:
                 // 0 byte payload
@@ -2605,354 +1706,170 @@ static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint
 }
 
 static void
-ProcessMacCommands(uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr)
+ProcessMacCommands(uint8_t *payload, uint8_t macIndex, uint8_t commandsSize,
+                   uint8_t snr)
 {
+    uint8_t status;
     uint8_t i;
+    uint8_t delay;
     uint8_t demod_margin;
     uint8_t gateways;
-    uint8_t status = 0x07;
-    uint16_t chMask;
-    int8_t txPower = 0;
-    int8_t datarate = 0;
-    int8_t drOffset;
-    uint8_t nbRep = 0;
-    uint8_t chMaskCntl = 0;
-    uint16_t channelsMask[6];
-    uint32_t freq;
+    uint8_t batteryLevel;
+    uint8_t eirpDwellTime;
+    LinkAdrReqParams_t linkAdrReq;
+    int8_t linkAdrDatarate = DR_0;
+    int8_t linkAdrTxPower = TX_POWER_0;
+    uint8_t linkAdrNbRep = 0;
+    uint8_t linkAdrNbBytesParsed = 0;
+    NewChannelReqParams_t newChannelReq;
+    ChannelParams_t chParam;
+    RxParamSetupReqParams_t rxParamSetupReq;
+    TxParamSetupReqParams_t txParamSetupReq;
+    DlChannelReqParams_t dlChannelReq;
 
     lora_node_log(LORA_NODE_LOG_PROC_MAC_CMD, macIndex, snr, commandsSize);
 
     while (macIndex < commandsSize) {
         // Decode Frame MAC commands
-        switch( payload[macIndex++] )
-        {
-            case SRV_MAC_LINK_CHECK_ANS:
-                demod_margin = payload[macIndex++];
-                gateways = payload[macIndex++];
-                STATS_INC(lora_mac_stats, link_chk_ans_rxd);
-                lora_app_link_chk_confirm(LORAMAC_EVENT_INFO_STATUS_OK,
-                                          gateways, demod_margin);
-                break;
-            case SRV_MAC_LINK_ADR_REQ:
-                // 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++];
+        switch(payload[macIndex++]) {
+        case SRV_MAC_LINK_CHECK_ANS:
+            demod_margin = payload[macIndex++];
+            gateways = payload[macIndex++];
+            STATS_INC(lora_mac_stats, link_chk_ans_rxd);
+            lora_app_link_chk_confirm(LORAMAC_EVENT_INFO_STATUS_OK,
+                                      gateways, demod_margin);
+            break;
+        case SRV_MAC_LINK_ADR_REQ:
+            // 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 = linkAdrDatarate;
+                LoRaMacParams.ChannelsTxPower = linkAdrTxPower;
+                LoRaMacParams.ChannelsNbRep = linkAdrNbRep;
+            }
 
-                lora_node_log(LORA_NODE_LOG_RX_ADR_REQ, datarate, txPower,
-                              (((uint32_t)chMask << 16) | nbRep));
+            // Add the answers to the buffer
+            for (i = 0; i < ( linkAdrNbBytesParsed / 5 ); i++) {
+                AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
+            }
+            // Update MAC index
+            macIndex += linkAdrNbBytesParsed - 1;
+
+            /* XXX: This does not show the raw data sent. It shows the
+               processed output. Would be nice to see each piece */
+            lora_node_log(LORA_NODE_LOG_RX_ADR_REQ, linkAdrDatarate,
+                          linkAdrTxPower,linkAdrNbRep);
+            break;
+        case SRV_MAC_DUTY_CYCLE_REQ:
+            g_lora_mac_data.max_dc = payload[macIndex++];
+            g_lora_mac_data.aggr_dc = 1 << g_lora_mac_data.max_dc;
+            AddMacCommand(MOTE_MAC_DUTY_CYCLE_ANS, 0, 0);
+            break;
+        case SRV_MAC_RX_PARAM_SETUP_REQ:
+            status = 0x07;
+
+            rxParamSetupReq.DrOffset = ( payload[macIndex] >> 4 ) & 0x07;
+            rxParamSetupReq.Datarate = payload[macIndex] & 0x0F;
+            macIndex++;
+
+            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 = rxParamSetupReq.Datarate;
+                LoRaMacParams.Rx2Channel.Frequency = rxParamSetupReq.Frequency;
+                LoRaMacParams.Rx1DrOffset = rxParamSetupReq.DrOffset;
+            }
+            AddMacCommand(MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0);
+            break;
+        case SRV_MAC_DEV_STATUS_REQ:
+            batteryLevel = BAT_LEVEL_NO_MEASURE;
+            if ((LoRaMacCallbacks != NULL) && (LoRaMacCallbacks->GetBatteryLevel != NULL)) {
+                batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
+            }
+            AddMacCommand(MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr & 0x3F);
+            break;
+        case SRV_MAC_NEW_CHANNEL_REQ:
+            status = 0x03;
 
-                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
-                    }
+            newChannelReq.ChannelId = payload[macIndex++];
+            newChannelReq.NewChannel = &chParam;
 
-#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
-                }
+            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++];
 
-                //
-                // Remark MaxTxPower = 0 and MinTxPower = 5
-                //
-                if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
-                {
-                    status &= 0xFB; // TxPower KO
-                }
+            status = RegionNewChannelReq( LoRaMacRegion, &newChannelReq );
 
-                /* XXX: I do not understand this for DR_4 in US915
-                 * band. We want to give up transmitting on all the 50
-                 * channels? This is messed up!!! What I mean is that I am not
-                 * sure the proper behavior if the server wants the end
-                 * device to use DR_4. DR_4 cannot be used in the 64,
-                 * 125kHz channels upstream. Seems like the code should send
-                 * some messages using DR_4 and others using DR_3.
-                 */
-                if ((status & 0x07) == 0x07) {
-                    LoRaMacParams.ChannelsDatarate = datarate;
-                    LoRaMacParams.ChannelsTxPower = txPower;
-
-                    memcpy( ( 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
-                }
-                AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );
-                break;
-            case SRV_MAC_DUTY_CYCLE_REQ:
-                MaxDCycle = payload[macIndex++];
-                AggregatedDCycle = 1 << MaxDCycle;
-                AddMacCommand(MOTE_MAC_DUTY_CYCLE_ANS, 0, 0);
-                break;
-            case SRV_MAC_RX_PARAM_SETUP_REQ:
-                status = 0x07;
-                drOffset = ( payload[macIndex] >> 4 ) & 0x07;
-                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
-                }
+            AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
+            break;
+        case SRV_MAC_RX_TIMING_SETUP_REQ:
+            delay = payload[macIndex++] & 0x0F;
+            if (delay == 0) {
+                delay++;
+            }
+            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:
+            eirpDwellTime = payload[macIndex++];
+            txParamSetupReq.UplinkDwellTime = 0;
+            txParamSetupReq.DownlinkDwellTime = 0;
 
-                if (!ValueInRange(datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ))
-                {
-                    status &= 0xFD; // Datarate KO
-                }
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-                if (ValueInRange(datarate, DR_5, DR_7) ||(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
-                }
+            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:
+            status = 0x03;
 
-                if( ( status & 0x07 ) == 0x07 )
-                {
-                    LoRaMacParams.Rx2Channel.Datarate = datarate;
-                    LoRaMacParams.Rx2Channel.Frequency = freq;
-                    LoRaMacParams.Rx1DrOffset = drOffset;
-                }
-                AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 );
-                break;
-            case SRV_MAC_DEV_STATUS_REQ:
-                {
-                    uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
-                    if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
-                    {
-                        batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
-                    }
-                    AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
-                    break;
-                }
-            case SRV_MAC_NEW_CHANNEL_REQ:
-                {
-                    uint8_t 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;
 
-#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;
-                    ChannelParams_t chParam;
-
-                    channelIndex = payload[macIndex++];
-                    chParam.Frequency = ( uint32_t )payload[macIndex++];
-                    chParam.Frequency |= ( uint32_t )payload[macIndex++] << 8;
-                    chParam.Frequency |= ( uint32_t )payload[macIndex++] << 16;
-                    chParam.Frequency *= 100;
-                    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
-                    AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
-                }
-                break;
-            case SRV_MAC_RX_TIMING_SETUP_REQ:
-                {
-                    uint8_t delay = payload[macIndex++] & 0x0F;
+            status = RegionDlChannelReq(LoRaMacRegion, &dlChannelReq);
 
-                    if( delay == 0 )
-                    {
-                        delay++;
-                    }
-                    LoRaMacParams.ReceiveDelay1 = delay * 1e3;
-                    LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3;
-                    AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 );
-                }
-                break;
-            default:
-                // Unknown command. ABORT MAC commands processing
-                return;
+            AddMacCommand(MOTE_MAC_DL_CHANNEL_ANS, status, 0);
+            break;
+        default:
+            // Unknown command. ABORT MAC commands processing
+            return;
         }
     }
 }
@@ -2980,181 +1897,186 @@ Send(LoRaMacHeader_t *macHdr, uint8_t fPort, struct os_mbuf *om)
     return status;
 }
 
+/**
+ * ScheduleTx
+ *
+ * Attempt to send a frame.
+ *
+ * @return LoRaMacStatus_t This function can return the following status
+ *  LORAMAC_STATUS_OK:              The transmission attempt was successful.
+ *  LORAMAC_STATUS_LENGTH_ERROR:    The transmission cannot be attempted as the
+ *                                  payload is too large
+ *  LORAMAC_STATUS_DEVICE_OFF:      The transmission cannot be attempte as the
+ *                                  device is off.
+ *  LORAMAC_STATUS_NO_CHANNEL_FOUND Transmission cannot be attempted due to no
+ *                                  channel available.
+ *
+ */
 static LoRaMacStatus_t
 ScheduleTx(void)
 {
     uint32_t duty_cycle_time_off = 0;
+    LoRaMacStatus_t status;
+    NextChanParams_t nextChan;
 
     // Check if the device is off
-    if (MaxDCycle == 255) {
+    if (g_lora_mac_data.max_dc == 255) {
         return LORAMAC_STATUS_DEVICE_OFF;
     }
 
-    if (MaxDCycle == 0) {
-        AggregatedTimeOff = 0;
+    if (g_lora_mac_data.max_dc == 0) {
+        g_lora_mac_data.aggr_time_off = 0;
     }
 
-    /* XXX: I do not like the fact that SetNextChannel can fail and then the
-     * datarate gets set back to default. If ADR is on, this is weird. Seems
-     * like something is very wrong if this happens. Not sure what to do but
-       using the default seems wrong. If ADR is on we need to switch datarates.
-      If ADR is not on, well, this should be an assert I think. */
-    // Select channel
-    while (SetNextChannel(&duty_cycle_time_off) == 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 Backoff
+    CalculateBackOff(g_lora_mac_data.last_tx_chan);
 
-    // Schedule transmission of frame
-    if (duty_cycle_time_off == 0) {
-        // Try to send now
-        return SendFrameOnChannel(Channels[Channel]);
-    } else {
-        // Send later - prepare timer
-        LoRaMacState |= LORAMAC_TX_DELAYED;
+    // Select channel
+    nextChan.AggrTimeOff = g_lora_mac_data.aggr_time_off;
+    nextChan.Datarate = LoRaMacParams.ChannelsDatarate;
+    nextChan.DutyCycleEnabled = DutyCycleOn;
+    nextChan.Joined = LM_F_IS_JOINED();
+    nextChan.LastAggrTx = g_lora_mac_data.aggr_last_tx_done_time;
 
-        /* NOTE: dutyCycleTimeOff is already in cputime timer units. */
-        hal_timer_stop(&TxDelayedTimer);
-        hal_timer_start(&TxDelayedTimer, duty_cycle_time_off);
+    status = RegionNextChannel(LoRaMacRegion, &nextChan,
+                               &g_lora_mac_data.cur_chan, &duty_cycle_time_off,
+                               &g_lora_mac_data.aggr_time_off);
 
-        return LORAMAC_STATUS_OK;
-    }
-}
+    if (status != LORAMAC_STATUS_OK) {
+        if (status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED) {
+            assert(duty_cycle_time_off != 0);
 
-static uint16_t
-JoinDutyCycle(void)
-{
-    uint16_t duty_cycle;
-    uint32_t elapsed_secs;
-    uint64_t elapsed_usecs;
+            // Send later - prepare timer
+            LoRaMacState |= LORAMAC_TX_DELAYED;
+            hal_timer_stop(&TxDelayedTimer);
+            hal_timer_start(&TxDelayedTimer, duty_cycle_time_off);
 
-    elapsed_usecs = os_get_uptime_usec() - LoRaMacInitializationTime;
-    elapsed_secs = (uint32_t)(elapsed_usecs / 1000000);
+            lora_node_log(LORA_NODE_LOG_TX_DELAY, g_lora_mac_data.max_dc, 0,
+                          duty_cycle_time_off);
 
-    if (elapsed_secs < 3600) {
-        duty_cycle = BACKOFF_DC_1_HOUR;
-    } else if (elapsed_secs < (3600 + 36000)) {
-        duty_cycle = BACKOFF_DC_10_HOURS;
+            return LORAMAC_STATUS_OK;
+        } else {
+            // State where the MAC cannot send a frame
+            return status;
+        }
+    }
+
+    // Compute Rx1 windows parameters
+    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                     RegionApplyDrOffset( LoRaMacRegion, LoRaMacParams.DownlinkDwellTime, LoRaMacParams.ChannelsDatarate, LoRaMacParams.Rx1DrOffset ),
+                                     LoRaMacParams.MinRxSymbols,
+                                     LoRaMacParams.SystemMaxRxError,
+                                     &RxWindow1Config );
+
+    // Compute Rx2 windows parameters
+    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                     LoRaMacParams.Rx2Channel.Datarate,
+                                     LoRaMacParams.MinRxSymbols,
+                                     LoRaMacParams.SystemMaxRxError,
+                                     &RxWindow2Config );
+
+    /* XXX: Thi should be based on whether or not the transmission is a
+       join request! */
+    if (!LM_F_IS_JOINED()) {
+        g_lora_mac_data.rx_win1_delay = LoRaMacParams.JoinAcceptDelay1 +
+            RxWindow1Config.WindowOffset;
+        g_lora_mac_data.rx_win2_delay = LoRaMacParams.JoinAcceptDelay2 +
+            RxWindow2Config.WindowOffset;
     } else {
-        duty_cycle = BACKOFF_DC_24_HOURS;
+        if (!ValidatePayloadLength(g_lora_mac_data.cur_tx_pyld,
+                                   LoRaMacParams.ChannelsDatarate, 0)) {
+            return LORAMAC_STATUS_LENGTH_ERROR;
+        }
+        g_lora_mac_data.rx_win1_delay = LoRaMacParams.ReceiveDelay1 +
+            RxWindow1Config.WindowOffset;
+        g_lora_mac_data.rx_win2_delay = LoRaMacParams.ReceiveDelay2 +
+            RxWindow2Config.WindowOffset;
     }
-    return duty_cycle;
+
+    // Try to send now
+    return SendFrameOnChannel(g_lora_mac_data.cur_chan);
 }
 
 static void
 CalculateBackOff(uint8_t channel)
 {
-    uint16_t duty_cycle = Bands[Channels[channel].Band].DCycle;
-    uint16_t join_duty_cycle;
+    uint32_t elapsed_msecs;
     uint32_t tx_ticks;
-
-    // Reset time-off to initial value.
-    Bands[Channels[channel].Band].TimeOff = 0;
+    CalcBackOffParams_t calc_backoff;
 
     /* Convert the tx time on air (which is in msecs) to lora mac timer ticks */
-    tx_ticks = TxTimeOnAir * 1000;
+    tx_ticks = g_lora_mac_data.tx_time_on_air * 1000;
 
-    if (IsLoRaMacNetworkJoined == false) {
-        // The node has not joined yet. Apply join duty cycle to all regions.
-        join_duty_cycle = JoinDutyCycle( );
-        duty_cycle = MAX(duty_cycle, join_duty_cycle);
-
-        // Update Band time-off.
-        Bands[Channels[channel].Band].TimeOff = (tx_ticks * duty_cycle) - tx_ticks;
-    } else {
-        if (DutyCycleOn == true) {
-            Bands[Channels[channel].Band].TimeOff = (tx_ticks * duty_cycle) - tx_ticks;
-        }
+    /*
+     * Calculcate the elasped time (in msecs) from when we started the
+     * join process. We do not ever expect this to wrap.
+     */
+    elapsed_msecs = (uint32_t)(os_time_get() - g_lora_mac_data.init_time);
+    if (os_time_ticks_to_ms(elapsed_msecs, &elapsed_msecs)) {
+        elapsed_msecs = 0xFFFFFFFF;
     }
 
-    // Update Aggregated Time OFF
-    AggregatedTimeOff = AggregatedTimeOff + ((tx_ticks * AggregatedDCycle) - tx_ticks);
-}
+    calc_backoff.Joined = LM_F_IS_JOINED();
+    calc_backoff.DutyCycleEnabled = DutyCycleOn;
+    calc_backoff.Channel = channel;
+    calc_backoff.ElapsedTime =  elapsed_msecs;
+    calc_backoff.TxTimeOnAir = tx_ticks;
+    calc_backoff.LastTxIsJoinRequest = (bool)LM_F_LAST_TX_IS_JOIN_REQ();
 
-static int8_t
-AlternateDatarate(uint16_t nbTrials)
-{
-    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
+    // Update regional back-off
+    RegionCalcBackOff(LoRaMacRegion, &calc_backoff);
 
-    if ((nbTrials & 0x01) == 0x01) {
-        datarate = DR_4;
-    } else {
-        datarate = DR_0;
-    }
-#else
-    if( ( nbTrials % 48 ) == 0 ) {
-        datarate = DR_0;
-    } else if( ( nbTrials % 32 ) == 0 ) {
-        datarate = DR_1;
-    } else if( ( nbTrials % 24 ) == 0 ) {
-        datarate = DR_2;
-    } else if( ( nbTrials % 16 ) == 0 ) {
-        datarate = DR_3;
-    } else if( ( nbTrials % 8 ) == 0 ) {
-        datarate = DR_4;
-    } else {
-        datarate = DR_5;
-    }
-#endif
-    return datarate;
+    // Update aggregated time-off. This must be an assignment and no incremental
+    // update as we do only calculate the time-off based on the last transmission
+    g_lora_mac_data.aggr_time_off = ((tx_ticks * g_lora_mac_data.aggr_dc) - tx_ticks);
 }
 
+/*!
+ * \brief Resets MAC specific parameters to default
+ */
 static void
 ResetMacParameters(void)
 {
-    IsLoRaMacNetworkJoined = false;
+    uint8_t pub_nwk;
+    uint8_t repeater;
+
+    // Store the current initialization time
+    g_lora_mac_data.init_time = os_time_get();
 
     // Counters
-    UpLinkCounter = 0;
-    DownLinkCounter = 0;
-    AdrAckCounter = 0;
+    g_lora_mac_data.uplink_cntr = 0;
+    g_lora_mac_data.downlink_cntr = 0;
+    g_lora_mac_data.adr_ack_cntr = 0;
 
-    ChannelsNbRepCounter = 0;
+    g_lora_mac_data.nb_rep_cntr = 0;
 
-    AckTimeoutRetries = 1;
-    AckTimeoutRetriesCounter = 1;
+    g_lora_mac_data.ack_timeout_retries = 1;
+    g_lora_mac_data.ack_timeout_retries_cntr = 1;
 
-    MaxDCycle = 0;
-    AggregatedDCycle = 1;
+    g_lora_mac_data.max_dc = 0;
+    g_lora_mac_data.aggr_dc = 1;
 
     MacCommandsBufferIndex = 0;
     MacCommandsBufferToRepeatIndex = 0;
 
     LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower;
     LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
-
-    LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow;
-    LoRaMacParams.ReceiveDelay1 = LoRaMacParamsDefaults.ReceiveDelay1;
-    LoRaMacParams.ReceiveDelay2 = LoRaMacParamsDefaults.ReceiveDelay2;
-    LoRaMacParams.JoinAcceptDelay1 = LoRaMacParamsDefaults.JoinAcceptDelay1;
-    LoRaMacParams.JoinAcceptDelay2 = LoRaMacParamsDefaults.JoinAcceptDelay2;
-
     LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset;
-    LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep;
-
     LoRaMacParams.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel;
+    LoRaMacParams.UplinkDwellTime = LoRaMacParamsDefaults.UplinkDwellTime;
+    LoRaMacParams.DownlinkDwellTime = LoRaMacParamsDefaults.DownlinkDwellTime;
+    LoRaMacParams.MaxEirp = LoRaMacParamsDefaults.MaxEirp;
+    LoRaMacParams.AntennaGain = LoRaMacParamsDefaults.AntennaGain;
 
-    memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    memcpy( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#endif
+    // Reset to application defaults
+    RegionInitDefaults( LoRaMacRegion, INIT_TYPE_APP_DEFAULTS );
 
-    NodeAckRequested = false;
-    SrvAckRequested = false;
+    /* Reset mac flags but retain those that need it */
+    pub_nwk = LM_F_IS_PUBLIC_NWK();
+    repeater = LM_F_REPEATER_SUPP();
+    g_lora_mac_data.lmflags.lmf_all = 0;
+    LM_F_IS_PUBLIC_NWK() = pub_nwk;
+    LM_F_REPEATER_SUPP() = repeater;
 
     // Reset Multicast downlink counters
     MulticastParams_t *cur = MulticastChannels;
@@ -3165,63 +2087,17 @@ ResetMacParameters(void)
     }
 
     // Initialize channel index.
-    Channel = LORA_MAX_NB_CHANNELS;
-
-    // Store the current initialization time
-    LoRaMacInitializationTime = os_get_uptime_usec();
-}
-
-/* Extract only the mac commands that will fit */
-uint8_t
-lora_mac_extract_mac_cmds(uint8_t max_cmd_bytes, uint8_t *buf)
-{
-    uint8_t cmd;
-    uint8_t i;
-    uint8_t bytes_added;
-    uint8_t bytes_left;
-    uint8_t cmd_len;
-
-    i = 0;
-    bytes_left = MacCommandsBufferIndex;
-    bytes_added = 0;
-    while (bytes_left != 0) {
-        /*
-         * Determine how many bytes are needed for the given MAC command. We
-         * will always send them in order and if we cannot fit we stop.
-         */
-        cmd = MacCommandsBuffer[i];
-        assert((cmd <= MOTE_MAC_RX_TIMING_SETUP_ANS) &&
-               (cmd >= MOTE_MAC_LINK_CHECK_REQ));
-
-        /* Get length of this command */
-        cmd_len = g_lora_mac_cmd_lens[cmd];
-
-        /* Make sure we can add this to the messgae */
-        if ((cmd_len + bytes_added) > max_cmd_bytes) {
-            break;
-        }
-
-        /*
-         * There had better be enough room in the buffer! If not, just clear
-         * the remaining bytes in the buffer
-         */
-        assert(cmd_len <= bytes_left);
-
-        /* copy bytes into buffer */
-        memcpy(buf, &MacCommandsBuffer[i], cmd_len);
-        bytes_added += cmd_len;
-        bytes_left -= cmd_len;
-        buf += cmd_len;
-        i += cmd_len;
-    }
-
-    return bytes_added;
+    g_lora_mac_data.cur_chan = 0;
+    g_lora_mac_data.last_tx_chan = 0;
 }
 
 LoRaMacStatus_t
 PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
              struct os_mbuf *om)
 {
+    AdrNextParams_t adrNext;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     uint8_t hdrlen = 0;
     uint16_t bufsize;
     uint32_t mic = 0;
@@ -3230,8 +2106,11 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
     uint8_t maxbytes;
     uint8_t max_cmd_bytes;
     uint8_t cmd_bytes_txd;
+    uint8_t pyld_len;
+    uint16_t dev_nonce;
+    uint32_t dev_addr;
 
-    NodeAckRequested = false;
+    LM_F_NODE_ACK_REQ() = 0;
 
     /* Get the mac payload size from the mbuf. A NULL mbuf is valid */
     if (om == NULL) {
@@ -3242,14 +2121,11 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
     }
 
     LoRaMacBufferPktLen = 0;
-    LoRaMacTxPayloadLen = bufsize;
+    pyld_len = bufsize;
     LoRaMacBuffer[hdrlen++] = macHdr->Value;
 
     switch(macHdr->Bits.MType) {
         case FRAME_TYPE_JOIN_REQ:
-            RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
-            RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
-
             LoRaMacBufferPktLen = hdrlen;
 
             swap_buf(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8);
@@ -3257,12 +2133,13 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
             swap_buf(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8);
             LoRaMacBufferPktLen += 8;
 
-            LoRaMacDevNonce = Radio.Random( );
+            dev_nonce = Radio.Random( );
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = dev_nonce & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = (dev_nonce >> 8) & 0xFF;
+            g_lora_mac_data.dev_nonce = dev_nonce;
 
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = (LoRaMacDevNonce >> 8) & 0xFF;
-
-            LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic );
+            LoRaMacJoinComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF,
+                                  LoRaMacAppKey, &mic);
 
             LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
             LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 8) & 0xFF;
@@ -3270,47 +2147,55 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
             LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 24) & 0xFF;
             break;
         case FRAME_TYPE_DATA_CONFIRMED_UP:
-            NodeAckRequested = true;
+            LM_F_NODE_ACK_REQ() = 1;
             //Intentional fallthrough
         case FRAME_TYPE_DATA_UNCONFIRMED_UP:
-            // No network has been joined yet
-            if (IsLoRaMacNetworkJoined == false) {
-                return LORAMAC_STATUS_NO_NETWORK_JOINED;
+            // Adr next request
+            adrNext.UpdateChanMask = true;
+            adrNext.AdrEnabled = fCtrl->Bits.Adr;
+            adrNext.AdrAckCounter = g_lora_mac_data.adr_ack_cntr;
+            adrNext.Datarate = LoRaMacParams.ChannelsDatarate;
+            adrNext.TxPower = LoRaMacParams.ChannelsTxPower;
+            adrNext.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+            fCtrl->Bits.AdrAckReq = RegionAdrNext(LoRaMacRegion, &adrNext,
+                                                  &LoRaMacParams.ChannelsDatarate,
+                                                  &LoRaMacParams.ChannelsTxPower,
+                                                  &g_lora_mac_data.adr_ack_cntr);
+
+            /* Can we send payload now that ADR changed? */
+            if (!ValidatePayloadLength(pyld_len,LoRaMacParams.ChannelsDatarate, 0)) {
+                return LORAMAC_STATUS_LENGTH_ERROR;
             }
 
-            fCtrl->Bits.AdrAckReq = AdrNextDr(fCtrl->Bits.Adr, true,
-                                              &LoRaMacParams.ChannelsDatarate);
+            // Setup PHY request
+            getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+            getPhy.Datarate = LoRaMacParams.ChannelsDatarate;
+            getPhy.Attribute = PHY_MAX_PAYLOAD;
 
-            /* Determine the maximum payload we can send at this datarate */
-            if (RepeaterSupport == true) {
-                maxbytes = MaxPayloadOfDatarateRepeater[LoRaMacParams.ChannelsDatarate];
-            } else {
-                maxbytes = MaxPayloadOfDatarate[LoRaMacParams.ChannelsDatarate];
-            }
-
-            /* If this frame is too big we have to deny it */
-            if (LoRaMacTxPayloadLen > maxbytes) {
-                return LORAMAC_STATUS_LENGTH_ERROR;
+            // Get the maximum payload length
+            if (LM_F_REPEATER_SUPP()) {
+                getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
             }
+            phyParam = RegionGetPhyParam(LoRaMacRegion, &getPhy);
+            maxbytes = (uint8_t)phyParam.Value;
 
-            RxWindow1Delay = LoRaMacParams.ReceiveDelay1 - RADIO_WAKEUP_TIME;
-            RxWindow2Delay = LoRaMacParams.ReceiveDelay2 - RADIO_WAKEUP_TIME;
-
-            if (SrvAckRequested == true) {
-                SrvAckRequested = false;
+            if (LM_F_GW_ACK_REQ()) {
+                LM_F_GW_ACK_REQ() = 0;
                 fCtrl->Bits.Ack = 1;
             }
 
-            LoRaMacBuffer[hdrlen++] = ( LoRaMacDevAddr ) & 0xFF;
-            LoRaMacBuffer[hdrlen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
-            LoRaMacBuffer[hdrlen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
-            LoRaMacBuffer[hdrlen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
+            dev_addr = g_lora_mac_data.dev_addr;
+            LoRaMacBuffer[hdrlen++] = (uint8_t)(dev_addr & 0xFF);
+            LoRaMacBuffer[hdrlen++] = (dev_addr >> 8)  & 0xFF;
+            LoRaMacBuffer[hdrlen++] = (dev_addr >> 16) & 0xFF;
+            LoRaMacBuffer[hdrlen++] = (dev_addr >> 24) & 0xFF;
             LoRaMacBuffer[hdrlen++] = fCtrl->Value;
-            LoRaMacBuffer[hdrlen++] = UpLinkCounter & 0xFF;
-            LoRaMacBuffer[hdrlen++] = ( UpLinkCounter >> 8 ) & 0xFF;
+            LoRaMacBuffer[hdrlen++] = g_lora_mac_data.uplink_cntr & 0xFF;
+            LoRaMacBuffer[hdrlen++] = ( g_lora_mac_data.uplink_cntr >> 8 ) & 0xFF;
 
             /* Determine maximum MAC command bytes we can allow */
-            max_cmd_bytes = maxbytes - LoRaMacTxPayloadLen;
+            max_cmd_bytes = maxbytes - pyld_len;
 
             // Copy MAC commands which must be re-sent into MAC command buffer
             memcpy(&MacCommandsBuffer[MacCommandsBufferIndex],
@@ -3321,8 +2206,8 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
             if (om != NULL) {
                 if ((MacCommandsBufferIndex != 0) && (max_cmd_bytes != 0)) {
                     /* fopts cannot exceed 15 bytes */
-                    if (max_cmd_bytes > LORA_MAC_COMMAND_MAX_LENGTH) {
-                        max_cmd_bytes = LORA_MAC_COMMAND_MAX_LENGTH;
+                    if (max_cmd_bytes > LORA_MAC_COMMAND_MAX_FOPTS_LENGTH) {
+                        max_cmd_bytes = LORA_MAC_COMMAND_MAX_FOPTS_LENGTH;
                     }
                     /* Extract only the mac commands that will fit */
                     cmd_bytes_txd = lora_mac_extract_mac_cmds(max_cmd_bytes,
@@ -3337,8 +2222,7 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
 
                 /* Set the port and copy in the application payload */
                 LoRaMacBuffer[hdrlen++] = port;
-                os_mbuf_copydata(om, 0, LoRaMacTxPayloadLen,
-                                 LoRaMacBuffer + hdrlen);
+                os_mbuf_copydata(om, 0, pyld_len, LoRaMacBuffer + hdrlen);
             } else {
                 if (MacCommandsBufferIndex > 0) {
                     port = 0;
@@ -3346,11 +2230,20 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
                     cmd_bytes_txd = lora_mac_extract_mac_cmds(max_cmd_bytes,
                                                               &LoRaMacBuffer[hdrlen]);
 
-                    LoRaMacTxPayloadLen = cmd_bytes_txd;
+                    pyld_len = cmd_bytes_txd;
                     assert(cmd_bytes_txd != 0);
                 }
             }
 
+            /*
+             * At this point, we know the amount of payload we are going to
+             * send. We need to remember this so we can validate the frame
+             * length if we have to re-transmit the frame at a lower data rate.
+             * Note that payload length we are storing in basically N (from
+             * the lorawan specification.
+             */
+            g_lora_mac_data.cur_tx_pyld = cmd_bytes_txd + pyld_len;
+
             /*
              * Store MAC commands which must be re-sent in case the device does
              * not receive a downlink anymore.
@@ -3370,20 +2263,29 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
                 }
             }
 
-            if (LoRaMacTxPayloadLen > 0) {
+            if (pyld_len > 0) {
                 /* Encrypt the MAC payload using appropriate key */
                 if (port == 0) {
                     key = LoRaMacNwkSKey;
                 } else {
                     key = LoRaMacAppSKey;
                 }
-                LoRaMacPayloadEncrypt(LoRaMacBuffer + hdrlen, LoRaMacTxPayloadLen,
-                                      key, LoRaMacDevAddr, UP_LINK, UpLinkCounter,
+                LoRaMacPayloadEncrypt(LoRaMacBuffer + hdrlen,
+                                      pyld_len,
+                                      key,
+                                      g_lora_mac_data.dev_addr,
+                                      UP_LINK,
+                                      g_lora_mac_data.uplink_cntr,
                                       LoRaMacBuffer + hdrlen);
             }
-            LoRaMacBufferPktLen = hdrlen + LoRaMacTxPayloadLen;
-            LoRaMacComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey,
-                              LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic);
+            LoRaMacBufferPktLen = hdrlen + pyld_len;
+            LoRaMacComputeMic(LoRaMacBuffer,
+                              LoRaMacBufferPktLen,
+                              LoRaMacNwkSKey,
+                              g_lora_mac_data.dev_addr,
+                              UP_LINK,
+                              g_lora_mac_data.uplink_cntr,
+                              &mic);
 
             LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
             LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF;
@@ -3391,11 +2293,15 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
             LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
 
             LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
+
+            lora_node_log(LORA_NODE_LOG_TX_PREP_FRAME, cmd_bytes_txd,
+                          (uint16_t)g_lora_mac_data.uplink_cntr,
+                          macHdr->Value);
             break;
         case FRAME_TYPE_PROPRIETARY:
-            if ((om != NULL) && (LoRaMacTxPayloadLen > 0)) {
-                os_mbuf_copydata(om, 0, LoRaMacTxPayloadLen, LoRaMacBuffer + hdrlen);
-                LoRaMacBufferPktLen = hdrlen + LoRaMacTxPayloadLen;
+            if ((om != NULL) && (pyld_len > 0)) {
+                os_mbuf_copydata(om, 0, pyld_len, LoRaMacBuffer + hdrlen);
+                LoRaMacBufferPktLen = hdrlen + pyld_len;
             }
             break;
         default:
@@ -3406,199 +2312,157 @@ PrepareFrame(LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort,
 }
 
 LoRaMacStatus_t
-SendFrameOnChannel( ChannelParams_t channel )
+SendFrameOnChannel(uint8_t channel)
 {
+    TxConfigParams_t txConfig;
     struct lora_pkt_info *txi;
-    int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate];
-    int8_t txPowerIndex = 0;
     int8_t txPower = 0;
 
-    txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[channel.Band].TxMaxPower );
-    txPower = TxPowers[txPowerIndex];
+    txConfig.Channel = channel;
+    txConfig.Datarate = LoRaMacParams.ChannelsDatarate;
+    txConfig.TxPower = LoRaMacParams.ChannelsTxPower;
+    txConfig.MaxEirp = LoRaMacParams.MaxEirp;
+    txConfig.AntennaGain = LoRaMacParams.AntennaGain;
+    txConfig.PktLen = LoRaMacBufferPktLen;
+
+    RegionTxConfig(LoRaMacRegion, &txConfig, &txPower,
+                   &g_lora_mac_data.tx_time_on_air);
 
     /* Set MCPS confirm information */
     txi = g_lora_mac_data.curtx;
     txi->txdinfo.datarate = LoRaMacParams.ChannelsDatarate;
     txi->txdinfo.txpower = txPower;
-    txi->txdinfo.uplink_freq = 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
-
-    // Store the time on air
-    txi->txdinfo.tx_time_on_air = TxTimeOnAir;
-
-    if (IsLoRaMacNetworkJoined == false) {
-        JoinRequestTrials++;
-    }
+    txi->txdinfo.uplink_chan = channel;
+    txi->txdinfo.tx_time_on_air = g_lora_mac_data.tx_time_on_air;
 
     // Send now
-    Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
+    Radio.Send(LoRaMacBuffer, LoRaMacBufferPktLen);
 
     LoRaMacState |= LORAMAC_TX_RUNNING;
 
+    lora_node_log(LORA_NODE_LOG_TX_START, txPower,
+                  ((uint16_t)LoRaMacParams.ChannelsDatarate << 8) | channel,
+                  g_lora_mac_data.tx_time_on_air);
+
     return LORAMAC_STATUS_OK;
 }
 
-LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout )
+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];
-
-    //Radio.SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout );
-
-    LoRaMacState |= LORAMAC_TX_RUNNING;
+    return LORAMAC_STATUS_SERVICE_UNKNOWN;
+}
 
-    return LORAMAC_STATUS_OK;
+LoRaMacStatus_t
+SetTxContinuousWave1(uint16_t timeout, uint32_t frequency, uint8_t power)
+{
+    return LORAMAC_STATUS_SERVICE_UNKNOWN;
 }
 
 LoRaMacStatus_t
-LoRaMacInitialization(LoRaMacCallback_t *callbacks )
+LoRaMacInitialization(LoRaMacCallback_t *callbacks, LoRaMacRegion_t region)
 {
-    LoRaMacCallbacks = callbacks;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    /* XXX: note that we used to use the LORA_NODE_DEFAULT_DATARATE here
+     * See if we should still use it or change that mynewt_val. The code
+     * below just uses the PHY default data upon init. I think this needs
+     * more thought. We could always just change the default rate with a
+     * MIB call I suspect (after initialization).
+     */
 
-    LoRaMacFlags.Value = 0;
+    // Verify if the region is supported
+    if (RegionIsActive(region) == false) {
+        return LORAMAC_STATUS_REGION_NOT_SUPPORTED;
+    }
+
+    LoRaMacCallbacks = callbacks;
+    LoRaMacRegion = region;
 
     LoRaMacDeviceClass = CLASS_A;
     LoRaMacState = LORAMAC_IDLE;
 
-    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
+    g_lora_mac_data.aggr_last_tx_done_time = 0;
+    g_lora_mac_data.aggr_time_off = 0;
 
     // Reset to defaults
-    LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
-    LoRaMacParamsDefaults.ChannelsDatarate =
-        MYNEWT_VAL(LORA_NODE_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;
 
-    LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW;
-    LoRaMacParamsDefaults.ReceiveDelay1 = RECEIVE_DELAY1;
-    LoRaMacParamsDefaults.ReceiveDelay2 = RECEIVE_DELAY2;
-    LoRaMacParamsDefaults.JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
-    LoRaMacParamsDefaults.JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
+    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
     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
+    LoRaMacParamsDefaults.SystemMaxRxError = 10;
+    LoRaMacParamsDefaults.MinRxSymbols = 6;
 
-#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
+    LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError;
+    LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols;
+    LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow;
+    LoRaMacParams.ReceiveDelay1 = LoRaMacParamsDefaults.ReceiveDelay1;
+    LoRaMacParams.ReceiveDelay2 = LoRaMacParamsDefaults.ReceiveDelay2;
+    LoRaMacParams.JoinAcceptDelay1 = LoRaMacParamsDefaults.JoinAcceptDelay1;
+    LoRaMacParams.JoinAcceptDelay2 = LoRaMacParamsDefaults.JoinAcceptDelay2;
+    LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep;
 
     ResetMacParameters( );
 
@@ -3610,8 +2474,8 @@ LoRaMacInitialization(LoRaMacCallback_t *callbacks )
                      NULL);
     hal_timer_set_cb(LORA_MAC_TIMER_NUM, &RxWindowTimer2, OnRxWindow2TimerEvent,
                      NULL);
-    hal_timer_set_cb(LORA_MAC_TIMER_NUM, &AckTimeoutTimer,
-                     OnAckTimeoutTimerEvent, NULL);
+    hal_timer_set_cb(LORA_MAC_TIMER_NUM, &g_lora_mac_data.rtx_timer,
+                     lora_mac_rtx_timer_cb, NULL);
 
     /* Init MAC radio events */
     g_lora_mac_radio_tx_timeout_event.ev_cb = lora_mac_process_radio_tx_timeout;
@@ -3619,7 +2483,7 @@ LoRaMacInitialization(LoRaMacCallback_t *callbacks )
     g_lora_mac_radio_rx_event.ev_cb = lora_mac_process_radio_rx;
     g_lora_mac_radio_rx_timeout_event.ev_cb = lora_mac_process_radio_rx_timeout;
     g_lora_mac_radio_rx_err_event.ev_cb = lora_mac_process_radio_rx_err;
-    g_lora_mac_ack_timeout_event.ev_cb = lora_mac_process_ack_timeout;
+    g_lora_mac_rtx_timeout_event.ev_cb = lora_mac_process_rtx_timeout;
     g_lora_mac_rx_win1_event.ev_cb = lora_mac_process_rx_win1_timeout;
     g_lora_mac_rx_win2_event.ev_cb = lora_mac_process_rx_win2_timeout;
     g_lora_mac_tx_delay_timeout_event.ev_cb = lora_mac_process_tx_delay_timeout;
@@ -3635,8 +2499,13 @@ LoRaMacInitialization(LoRaMacCallback_t *callbacks )
     // Random seed initialization
     //srand1( Radio.Random( ) );
 
-    PublicNetwork = true;
-    Radio.SetPublicNetwork( PublicNetwork );
+#if MYNEWT_VAL(LORA_NODE_PUBLIC_NWK)
+    LM_F_IS_PUBLIC_NWK() = 1;
+    Radio.SetPublicNetwork(true);
+#else
+    LM_F_IS_PUBLIC_NWK() = 0;
+    Radio.SetPublicNetwork(false);
+#endif
     Radio.Sleep( );
 
     return LORAMAC_STATUS_OK;
@@ -3645,19 +2514,39 @@ LoRaMacInitialization(LoRaMacCallback_t *callbacks )
 LoRaMacStatus_t
 LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo)
 {
-    int8_t datarate;
+    AdrNextParams_t adrNext;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    int8_t datarate = LoRaMacParamsDefaults.ChannelsDatarate;
+    int8_t txPower = LoRaMacParamsDefaults.ChannelsTxPower;
     uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
 
     assert(txInfo != NULL);
 
-    /* NOTE: datarate always set by this call. */
-    AdrNextDr(AdrCtrlOn, false, &datarate);
+    // Setup ADR request
+    adrNext.UpdateChanMask = false;
+    adrNext.AdrEnabled = AdrCtrlOn;
+    adrNext.AdrAckCounter = g_lora_mac_data.adr_ack_cntr;
+    adrNext.Datarate = LoRaMacParams.ChannelsDatarate;
+    adrNext.TxPower = LoRaMacParams.ChannelsTxPower;
+    adrNext.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
 
-    if (RepeaterSupport == true) {
-        txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate];
-    } else {
-        txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
+    // 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,
+                  &g_lora_mac_data.adr_ack_cntr);
+
+    // Setup PHY request
+    getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+    getPhy.Datarate = datarate;
+    getPhy.Attribute = PHY_MAX_PAYLOAD;
+
+    // Change request in case repeater is supported
+    if (LM_F_REPEATER_SUPP() == true) {
+        getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
     }
+    phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
+    txInfo->CurrentPayloadSize = phyParam.Value;
 
     if (txInfo->CurrentPayloadSize >= fOptLen) {
         txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen;
@@ -3665,11 +2554,11 @@ LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo)
         return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
     }
 
-    if (ValidatePayloadLength(size, datarate, 0) == false) {
+    if (!ValidatePayloadLength(size, datarate, 0)) {
         return LORAMAC_STATUS_LENGTH_ERROR;
     }
 
-    if (ValidatePayloadLength(size, datarate, fOptLen) == false) {
+    if (!ValidatePayloadLength(size, datarate, fOptLen)) {
         return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
     }
 
@@ -3679,26 +2568,28 @@ LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo)
 LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
 
     if (mibGet == NULL) {
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
 
-    switch(mibGet->Type) {
+    switch (mibGet->Type) {
         case MIB_DEVICE_CLASS:
             mibGet->Param.Class = LoRaMacDeviceClass;
             break;
         case MIB_NETWORK_JOINED:
-            mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined;
+            mibGet->Param.IsNetworkJoined = LM_F_IS_JOINED();
             break;
         case MIB_ADR:
             mibGet->Param.AdrEnable = AdrCtrlOn;
             break;
         case MIB_NET_ID:
-            mibGet->Param.NetID = LoRaMacNetID;
+            mibGet->Param.NetID = g_lora_mac_data.netid;
             break;
         case MIB_DEV_ADDR:
-            mibGet->Param.DevAddr = LoRaMacDevAddr;
+            mibGet->Param.DevAddr = g_lora_mac_data.dev_addr;
             break;
         case MIB_NWK_SKEY:
             mibGet->Param.NwkSKey = LoRaMacNwkSKey;
@@ -3707,13 +2598,16 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
             mibGet->Param.AppSKey = LoRaMacAppSKey;
             break;
         case MIB_PUBLIC_NETWORK:
-            mibGet->Param.EnablePublicNetwork = PublicNetwork;
+            mibGet->Param.EnablePublicNetwork = (bool)LM_F_IS_PUBLIC_NWK();
             break;
         case MIB_REPEATER_SUPPORT:
-            mibGet->Param.EnableRepeaterSupport = RepeaterSupport;
+            mibGet->Param.EnableRepeaterSupport = LM_F_REPEATER_SUPP();
             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:
             mibGet->Param.Rx2Channel = LoRaMacParams.Rx2Channel;
@@ -3722,10 +2616,16 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
             mibGet->Param.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel;
             break;
         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:
             mibGet->Param.ChannelNbRep = LoRaMacParams.ChannelsNbRep;
@@ -3758,14 +2658,26 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
             mibGet->Param.ChannelsTxPower = LoRaMacParams.ChannelsTxPower;
             break;
         case MIB_UPLINK_COUNTER:
-            mibGet->Param.UpLinkCounter = UpLinkCounter;
+            mibGet->Param.UpLinkCounter = g_lora_mac_data.uplink_cntr;
             break;
         case MIB_DOWNLINK_COUNTER:
-            mibGet->Param.DownLinkCounter = DownLinkCounter;
+            mibGet->Param.DownLinkCounter = g_lora_mac_data.downlink_cntr;
             break;
         case MIB_MULTICAST_CHANNEL:
             mibGet->Param.MulticastList = MulticastChannels;
             break;
+        case MIB_SYSTEM_MAX_RX_ERROR:
+            mibGet->Param.SystemMaxRxError = LoRaMacParams.SystemMaxRxError;
+            break;
+        case MIB_MIN_RX_SYMBOLS:
+            mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols;
+            break;
+        case MIB_ANTENNA_GAIN:
+            mibGet->Param.AntennaGain = LoRaMacParams.AntennaGain;
+            break;
+        case MIB_DEFAULT_ANTENNA_GAIN:
+            mibGet->Param.DefaultAntennaGain = LoRaMacParamsDefaults.AntennaGain;
+            break;
         default:
             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
             break;
@@ -3778,6 +2690,8 @@ LoRaMacStatus_t
 LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet)
 {
     LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+    ChanMaskSetParams_t chanMaskSet;
+    VerifyParams_t verify;
 
     assert(mibSet != NULL);
 
@@ -3786,7 +2700,12 @@ LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet)
     }
 
     switch (mibSet->Type) {
-        case MIB_DEVICE_CLASS:
+    case MIB_DEVICE_CLASS:
+            /* Do not allow device class to be set if tx delayed either! */
+            if (lora_mac_tx_state() == LORAMAC_STATUS_BUSY) {
+                return LORAMAC_STATUS_BUSY;
+            }
+
             LoRaMacDeviceClass = mibSet->Param.Class;
             switch( LoRaMacDeviceClass )
             {
@@ -3797,265 +2716,185 @@ LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet)
                 case CLASS_B:
                     break;
                 case CLASS_C:
-                    // Set the NodeAckRequested indicator to default
-                    NodeAckRequested = false;
-                    lora_mac_rx_on_window2(true);
+                    Radio.Sleep();
+
+                    // Compute Rx2 windows parameters in case the RX2 datarate has changed
+                    RegionComputeRxWindowParameters( LoRaMacRegion,
+                                                     LoRaMacParams.Rx2Channel.Datarate,
+                                                     LoRaMacParams.MinRxSymbols,
+                                                     LoRaMacParams.SystemMaxRxError,
+                                                     &RxWindow2Config );
+
+                    lora_mac_rx_on_window2();
                     break;
             }
             break;
         case MIB_NETWORK_JOINED:
-            IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
+            LM_F_IS_JOINED() = mibSet->Param.IsNetworkJoined;
             break;
         case MIB_ADR:
             AdrCtrlOn = mibSet->Param.AdrEnable;
             break;
         case MIB_NET_ID:
-            LoRaMacNetID = mibSet->Param.NetID;
+            g_lora_mac_data.netid = mibSet->Param.NetID;
             break;
         case MIB_DEV_ADDR:
-            LoRaMacDevAddr = mibSet->Param.DevAddr;
+            g_lora_mac_data.dev_addr = mibSet->Param.DevAddr;
             break;
         case MIB_NWK_SKEY:
-            if( mibSet->Param.NwkSKey != NULL )
-            {
+            if (mibSet->Param.NwkSKey != NULL) {
                 memcpy( LoRaMacNwkSKey, mibSet->Param.NwkSKey,
                                sizeof( LoRaMacNwkSKey ) );
-            }
-            else
-            {
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
         case MIB_APP_SKEY:
-        {
-            if( mibSet->Param.AppSKey != NULL )
-            {
+            if (mibSet->Param.AppSKey != NULL) {
                 memcpy( LoRaMacAppSKey, mibSet->Param.AppSKey,
                                sizeof( LoRaMacAppSKey ) );
-            }
-            else
-            {
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_PUBLIC_NETWORK:
-        {
-            PublicNetwork = mibSet->Param.EnablePublicNetwork;
-            Radio.SetPublicNetwork( PublicNetwork );
+            LM_F_IS_PUBLIC_NWK() = mibSet->Param.EnablePublicNetwork;
+            Radio.SetPublicNetwork((bool)LM_F_IS_PUBLIC_NWK());
             break;
-        }
         case MIB_REPEATER_SUPPORT:
-        {
-             RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
+             LM_F_REPEATER_SUPP() = mibSet->Param.EnableRepeaterSupport;
             break;
-        }
         case MIB_RX2_CHANNEL:
-        {
-            LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel;
+            verify.DatarateParams.Datarate = mibSet->Param.Rx2Channel.Datarate;
+            verify.DatarateParams.DownlinkDwellTime = LoRaMacParams.DownlinkDwellTime;
+
+            if (RegionVerify( LoRaMacRegion, &verify, PHY_RX_DR) == true) {
+                LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel;
+
+                if ((LoRaMacDeviceClass == CLASS_C ) && LM_F_IS_JOINED()) {
+                    // We can only compute the RX window parameters directly, if we are already
+                    // in class c mode and joined. We cannot setup an RX window in case of any other
+                    // class type.
+                    // Set the radio into sleep mode in case we are still in RX mode
+                    Radio.Sleep( );
+
+                    // Compute Rx2 windows parameters
+                    RegionComputeRxWindowParameters(LoRaMacRegion,
+                                                    LoRaMacParams.Rx2Channel.Datarate,
+                                                    LoRaMacParams.MinRxSymbols,
+                                                    LoRaMacParams.SystemMaxRxError,
+                                                    &RxWindow2Config);
+                    /* Use our function */
+                    lora_mac_rx_on_window2();
+                }
+            } else {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
             break;
-        }
         case MIB_RX2_DEFAULT_CHANNEL:
-        {
-            LoRaMacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel;
+            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:
-        {
-            if (mibSet->Param.ChannelsDefaultMask) {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                bool chanMaskState = true;
+            chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
+            chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
 
-#if defined( USE_BAND_915_HYBRID )
-                chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsDefaultMask );
-#endif
-                if( chanMaskState == true ) {
-                    if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) &&
-                        ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ){
-                        status = LORAMAC_STATUS_PARAMETER_INVALID;
-                    }
-                    else {
-                        memcpy( ( 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 )
-                memcpy( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) );
-#else
-                memcpy( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, 2 );
-#endif
-            } else {
+            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;
+            chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
+            chanMaskSet.ChannelsMaskType = CHANNELS_MASK;
 
-#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
-                    {
-                        memcpy( ( 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 )
-                memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) );
-#else
-                memcpy( ( uint8_t* ) LoRaMacParams.ChannelsMask,
-                         ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
-#endif
-            }
-            else
-            {
+            if (RegionChanMaskSet( LoRaMacRegion, &chanMaskSet) == false){
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_CHANNELS_NB_REP:
-        {
-            if( ( mibSet->Param.ChannelNbRep >= 1 ) &&
-                ( mibSet->Param.ChannelNbRep <= 15 ) )
-            {
+            if ((mibSet->Param.ChannelNbRep >= 1 ) &&
+                (mibSet->Param.ChannelNbRep <= 15 )) {
                 LoRaMacParams.ChannelsNbRep = mibSet->Param.ChannelNbRep;
-            }
-            else
-            {
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_MAX_RX_WINDOW_DURATION:
-        {
             LoRaMacParams.MaxRxWindow = mibSet->Param.MaxRxWindow;
             break;
-        }
         case MIB_RECEIVE_DELAY_1:
-        {
             LoRaMacParams.ReceiveDelay1 = mibSet->Param.ReceiveDelay1;
             break;
-        }
         case MIB_RECEIVE_DELAY_2:
-        {
             LoRaMacParams.ReceiveDelay2 = mibSet->Param.ReceiveDelay2;
             break;
-        }
         case MIB_JOIN_ACCEPT_DELAY_1:
-        {
             LoRaMacParams.JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1;
             break;
-        }
         case MIB_JOIN_ACCEPT_DELAY_2:
-        {
             LoRaMacParams.JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
             break;
-        }
         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 ) )
-            {
-                LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate;
-            }
-#else
-            if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate,
-                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
-            {
-                LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate;
-            }
-#endif
-            else
-            {
+            verify.DatarateParams.Datarate = mibSet->Param.ChannelsDefaultDatarate;
+
+            if (RegionVerify( LoRaMacRegion, &verify, PHY_DEF_TX_DR ) == true) {
+                LoRaMacParamsDefaults.ChannelsDatarate = verify.DatarateParams.Datarate;
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_CHANNELS_DATARATE:
-        {
-            /*
-             * XXX: shouldn't this also check to make sure a channel can
-             * handle this?
-             */
-            if( ValueInRange( mibSet->Param.ChannelsDatarate,
-                              LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) )
-            {
-                LoRaMacParams.ChannelsDatarate = mibSet->Param.ChannelsDatarate;
-            }
-            else
-            {
+            verify.DatarateParams.Datarate = mibSet->Param.ChannelsDatarate;
+            verify.DatarateParams.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+            if (RegionVerify( LoRaMacRegion, &verify, PHY_TX_DR ) == true) {
+                LoRaMacParams.ChannelsDatarate = verify.DatarateParams.Datarate;
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_CHANNELS_DEFAULT_TX_POWER:
-        {
-            if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower,
-                              LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
-            {
-                LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower;
-            }
-            else
-            {
+            verify.TxPower = mibSet->Param.ChannelsDefaultTxPower;
+
+            if (RegionVerify(LoRaMacRegion, &verify, PHY_DEF_TX_POWER) == true) {
+                LoRaMacParamsDefaults.ChannelsTxPower = verify.TxPower;
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_CHANNELS_TX_POWER:
-        {
-            if( ValueInRange( mibSet->Param.ChannelsTxPower,
-                              LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) )
-            {
-                LoRaMacParams.ChannelsTxPower = mibSet->Param.ChannelsTxPower;
-            }
-            else
-            {
+            verify.TxPower = mibSet->Param.ChannelsTxPower;
+
+            if (RegionVerify( LoRaMacRegion, &verify, PHY_TX_POWER ) == true) {
+                LoRaMacParams.ChannelsTxPower = verify.TxPower;
+            } else {
                 status = LORAMAC_STATUS_PARAMETER_INVALID;
             }
             break;
-        }
         case MIB_UPLINK_COUNTER:
-        {
-            UpLinkCounter = mibSet->Param.UpLinkCounter;
+            g_lora_mac_data.uplink_cntr = mibSet->Param.UpLinkCounter;
             break;
-        }
         case MIB_DOWNLINK_COUNTER:
-        {
-            DownLinkCounter = mibSet->Param.DownLinkCounter;
+            g_lora_mac_data.downlink_cntr = mibSet->Param.DownLinkCounter;
+            break;
+        case MIB_SYSTEM_MAX_RX_ERROR:
+            LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError;
+            break;
+        case MIB_MIN_RX_SYMBOLS:
+            LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols;
+            break;
+        case MIB_ANTENNA_GAIN:
+            LoRaMacParams.AntennaGain = mibSet->Param.AntennaGain;
+            break;
+        case MIB_DEFAULT_ANTENNA_GAIN:
+            LoRaMacParamsDefaults.AntennaGain = mibSet->Param.DefaultAntennaGain;
             break;
-        }
         default:
             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
             break;
@@ -4064,148 +2903,40 @@ LoRaMacMibSetRequestConfirm(MibRequestConfirm_t *mibSet)
     return status;
 }
 
-LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
+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;
+    ChannelAddParams_t channelAdd;
 
-    // The id must not exceed LORA_MAX_NB_CHANNELS
-    if( id >= LORA_MAX_NB_CHANNELS )
-    {
-        return LORAMAC_STATUS_PARAMETER_INVALID;
-    }
     // Validate if the MAC is in a correct state
-    if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
-    {
-        if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
-        {
+    if ((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) {
+        if ((LoRaMacState & LORAMAC_TX_CONFIG) != LORAMAC_TX_CONFIG) {
             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 );
+    channelAdd.NewChannel = &params;
+    channelAdd.ChannelId = id;
 
-    return LORAMAC_STATUS_OK;
-#endif
+    return RegionChannelAdd(LoRaMacRegion, &channelAdd);
 }
 
 LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
 {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
-    {
-        if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
-        {
+    ChannelRemoveParams_t channelRemove;
+
+    if ((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) {
+        if ((LoRaMacState & LORAMAC_TX_CONFIG) != LORAMAC_TX_CONFIG) {
             return LORAMAC_STATUS_BUSY;
         }
     }
 
-    if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
-    {
-        return LORAMAC_STATUS_PARAMETER_INVALID;
-    }
-    else
-    {
-        // Remove the channel from the list of channels
-        Channels[id] = ( ChannelParams_t ){ 0, { 0 }, 0 };
+    channelRemove.ChannelId = id;
 
-        // Disable the channel as it doesn't exist anymore
-        if( DisableChannelInMask( id, LoRaMacParams.ChannelsMask ) == false )
-        {
-            return LORAMAC_STATUS_PARAMETER_INVALID;
-        }
+    if (RegionChannelsRemove( LoRaMacRegion, &channelRemove) == 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
@@ -4242,34 +2973,28 @@ LoRaMacMulticastChannelLink( MulticastParams_t *channelParam )
 LoRaMacStatus_t
 LoRaMacMulticastChannelUnlink(MulticastParams_t *channelParam)
 {
-    if( channelParam == NULL )
-    {
+    if (channelParam == NULL) {
         return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-    if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
-    {
+
+    if ((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) {
         return LORAMAC_STATUS_BUSY;
     }
 
-    if( MulticastChannels != NULL )
-    {
-        if( MulticastChannels == channelParam )
-        {
+    if (MulticastChannels != NULL) {
+        if (MulticastChannels == channelParam) {
           // First element
           MulticastChannels = channelParam->Next;
-        }
-        else
-        {
+        } else {
             MulticastParams_t *cur = MulticastChannels;
 
             // Search the node in the list
-            while( cur->Next && cur->Next != channelParam )
-            {
+            while( cur->Next && cur->Next != channelParam ) {
                 cur = cur->Next;
             }
+
             // If we found the node, remove it
-            if( cur->Next )
-            {
+            if( cur->Next ) {
                 cur->Next = channelParam->Next;
             }
         }
@@ -4287,66 +3012,50 @@ LoRaMacMlmeRequest(MlmeReq_t *mlmeRequest)
 
     assert(mlmeRequest != NULL);
 
-    /* If currently running or MLME request in progress, return busy */
-    if ((LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING) {
+    /* If currently running return busy */
+    if ((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) {
         return LORAMAC_STATUS_BUSY;
     }
 
-    if (LoRaMacFlags.Bits.MlmeReq == 1) {
+    /* If we are joining do not allow another MLME request */
+    if (LM_F_IS_JOINING()) {
         return LORAMAC_STATUS_BUSY;
     }
 
+    /* XXX: do these need to be set? */
     g_lora_mac_data.txpkt.port = 0;
     g_lora_mac_data.txpkt.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
     g_lora_mac_data.txpkt.pkt_type = mlmeRequest->Type;
 
-    switch( mlmeRequest->Type )
-    {
+    switch (mlmeRequest->Type) {
         case MLME_JOIN:
-            if ((LoRaMacState & LORAMAC_TX_DELAYED) == LORAMAC_TX_DELAYED) {
-                return LORAMAC_STATUS_BUSY;
-            }
-
-            if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
-                ( mlmeRequest->Req.Join.AppEui == NULL ) ||
-                ( mlmeRequest->Req.Join.AppKey == NULL ) ||
-                ( mlmeRequest->Req.Join.NbTrials == 0 ) )
-            {
+            if ((mlmeRequest->Req.Join.DevEui == NULL) ||
+                (mlmeRequest->Req.Join.AppEui == NULL) ||
+                (mlmeRequest->Req.Join.AppKey == NULL) ||
+                (mlmeRequest->Req.Join.NbTrials == 0)) {
                 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) {
-                mlmeRequest->Req.Join.NbTrials = 2;
-            }
-#else
-            // Enables at least the usage of all datarates.
-            if (mlmeRequest->Req.Join.NbTrials < 48) {
-                mlmeRequest->Req.Join.NbTrials = 48;
-            }
-#endif
+            ResetMacParameters();
 
-            LoRaMacFlags.Bits.MlmeReq = 1;
+            g_lora_mac_data.cur_join_attempt = 0;
+            g_lora_mac_data.max_join_attempt = mlmeRequest->Req.Join.NbTrials;
 
             LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
             LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
             LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
-            MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
+            LoRaMacParams.ChannelsDatarate =
+                RegionAlternateDr(LoRaMacRegion,LoRaMacParams.ChannelsDatarate);
 
-            // Reset variable JoinRequestTrials
-            JoinRequestTrials = 0;
+            /* Set flag to denote we are trying to join */
+            LM_F_IS_JOINING() = 1;
 
-            // Setup header information
             macHdr.Value = 0;
             macHdr.Bits.MType  = FRAME_TYPE_JOIN_REQ;
-
-            ResetMacParameters( );
-
-            // Add a +1, since we start to count from 0
-            LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 );
-
             status = Send(&macHdr, 0, NULL);
+            if (status != LORAMAC_STATUS_OK) {
+                LM_F_IS_JOINING() = 0;
+            }
             break;
         case MLME_LINK_CHECK:
             // LoRaMac will send this command piggy-back.
@@ -4356,54 +3065,56 @@ LoRaMacMlmeRequest(MlmeReq_t *mlmeRequest)
             }
             break;
         case MLME_TXCW:
-            LoRaMacFlags.Bits.MlmeReq = 1;
-            status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout );
+            /* XXX: make sure we can handle this. Set TX_RUNNING? */
+            status = SetTxContinuousWave(mlmeRequest->Req.TxCw.Timeout);
             break;
         default:
             status = LORAMAC_STATUS_SERVICE_UNKNOWN;
             break;
     }
 
-    if (status != LORAMAC_STATUS_OK) {
-        LoRaMacFlags.Bits.MlmeReq = 0;
-    }
-
     return status;
 }
 
 LoRaMacStatus_t
 LoRaMacMcpsRequest(struct os_mbuf *om, struct lora_pkt_info *txi)
 {
-    LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+    LoRaMacStatus_t status;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
     LoRaMacHeader_t macHdr;
+    VerifyParams_t verify;
 
     assert(txi != NULL);
 
-    if (((LoRaMacState & LORAMAC_TX_RUNNING) == LORAMAC_TX_RUNNING) ||
-        ((LoRaMacState & LORAMAC_TX_DELAYED) == LORAMAC_TX_DELAYED)) {
+    if (LM_F_IS_JOINING() || (lora_mac_tx_state() == LORAMAC_STATUS_BUSY)) {
         return LORAMAC_STATUS_BUSY;
     }
 
     macHdr.Value = 0;
 
+    /*
+     * ack timeout retries counter must be reset every time a new request
+     * (unconfirmed or confirmed) is performed.
+     */
+    g_lora_mac_data.ack_timeout_retries_cntr = 1;
+
     switch (txi->pkt_type) {
         case MCPS_UNCONFIRMED:
-            AckTimeoutRetries = 1;
+            g_lora_mac_data.ack_timeout_retries = 1;
             macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
             break;
         case MCPS_CONFIRMED:
-            AckTimeoutRetriesCounter = 1;
             /* The retries field is seeded with trials, then cleared */
-            AckTimeoutRetries = txi->txdinfo.retries;
-            if (AckTimeoutRetries > MAX_ACK_RETRIES) {
-                AckTimeoutRetries = MAX_ACK_RETRIES;
+            g_lora_mac_data.ack_timeout_retries = txi->txdinfo.retries;
+            if (g_lora_mac_data.ack_timeout_retries > MAX_ACK_RETRIES) {
+                g_lora_mac_data.ack_timeout_retries = MAX_ACK_RETRIES;
             }
 
             macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
             break;
-
         case MCPS_PROPRIETARY:
-            AckTimeoutRetries = 1;
+            g_lora_mac_data.ack_timeout_retries = 1;
             macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
             break;
         default:
@@ -4414,15 +3125,34 @@ LoRaMacMcpsRequest(struct os_mbuf *om, struct lora_pkt_info *txi)
     /* Default packet status to error; will get set if ok later */
     txi->status = LORAMAC_EVENT_INFO_STATUS_ERROR;
 
+    if (AdrCtrlOn == false) {
+        /* Verify data rate valid */
+        getPhy.Attribute = PHY_MIN_TX_DR;
+        getPhy.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+        phyParam = RegionGetPhyParam(LoRaMacRegion, &getPhy);
+        verify.DatarateParams.Datarate =
+            MAX(LoRaMacParams.ChannelsDatarate, phyParam.Value);
+        verify.DatarateParams.UplinkDwellTime = LoRaMacParams.UplinkDwellTime;
+
+        if (RegionVerify(LoRaMacRegion, &verify, PHY_TX_DR) == true) {
+            LoRaMacParams.ChannelsDatarate = verify.DatarateParams.Datarate;
+        } else {
+            return LORAMAC_STATUS_PARAMETER_INVALID;
+        }
+    }
+
     /* Clear out all transmitted information. */
     memset(&txi->txdinfo, 0, sizeof(struct lora_txd_info));
-    txi->txdinfo.uplink_cntr = UpLinkCounter;
+    txi->txdinfo.uplink_cntr = g_lora_mac_data.uplink_cntr;
+
+    /* Set flag denoting we are sending a MCPS data packet */
+    LM_F_IS_MCPS_REQ() = 1;
 
+    /* Attempt to send. If failed clear flags */
     status = Send(&macHdr, txi->port, om);
-    if (status == LORAMAC_STATUS_OK) {
-        LoRaMacFlags.Bits.McpsReq = 1;
-    } else {
-        NodeAckRequested = false;
+    if (status != LORAMAC_STATUS_OK) {
+        LM_F_NODE_ACK_REQ() = 0;
+        LM_F_IS_MCPS_REQ() = 0;
     }
 
     return status;
@@ -4434,22 +3164,23 @@ void LoRaMacTestRxWindowsOn( bool enable )
 
 void LoRaMacTestSetMic( uint16_t txPacketCounter )
 {
-    UpLinkCounter = txPacketCounter;
+    g_lora_mac_data.uplink_cntr = txPacketCounter;
     IsUpLinkCounterFixed = true;
 }
 
 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;
+    g_lora_mac_data.cur_chan = channel;
 }
 
 LoRaMacStatus_t
@@ -4461,7 +3192,7 @@ lora_mac_tx_state(void)
         ((LoRaMacState & LORAMAC_TX_DELAYED) == LORAMAC_TX_DELAYED)) {
         rc = LORAMAC_STATUS_BUSY;
     } else {
-        rc = LORAMAC_STATUS_OK;;
+        rc = LORAMAC_STATUS_OK;
     }
 
     return rc;
@@ -4470,7 +3201,7 @@ lora_mac_tx_state(void)
 bool
 lora_mac_srv_ack_requested(void)
 {
-    return SrvAckRequested;
+    return LM_F_GW_ACK_REQ() ? true : false;
 }
 
 /**
@@ -4484,3 +3215,49 @@ lora_mac_cmd_buffer_len(void)
     return MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex;
 }
 
+/* Extract only the mac commands that will fit */
+static uint8_t
+lora_mac_extract_mac_cmds(uint8_t max_cmd_bytes, uint8_t *buf)
+{
+    uint8_t cmd;
+    uint8_t i;
+    uint8_t bytes_added;
+    uint8_t bytes_left;
+    uint8_t cmd_len;
+
+    i = 0;
+    bytes_left = MacCommandsBufferIndex;
+    bytes_added = 0;
+    while (bytes_left != 0) {
+        /*
+         * Determine how many bytes are needed for the given MAC command. We
+         * will always send them in order and if we cannot fit we stop.
+         */
+        cmd = MacCommandsBuffer[i];
+        assert((cmd <= MOTE_MAC_RX_TIMING_SETUP_ANS) &&
+               (cmd >= MOTE_MAC_LINK_CHECK_REQ));
+
+        /* Get length of this command */
+        cmd_len = g_lora_mac_cmd_lens[cmd];
+
+        /* Make sure we can add this to the messgae */
+        if ((cmd_len + bytes_added) > max_cmd_bytes) {
+            break;
+        }
+
+        /*
+         * There had better be enough room in the buffer! If not, just clear
+         * the remaining bytes in the buffer
+         */
+        assert(cmd_len <= bytes_left);
+
+        /* copy bytes into buffer */
+        memcpy(buf, &MacCommandsBuffer[i], cmd_len);
+        bytes_added += cmd_len;
+        bytes_left -= cmd_len;
+        buf += cmd_len;
+        i += cmd_len;
+    }
+
+    return bytes_added;
+}
diff --git a/net/lora/node/src/mac/region/Region.c b/net/lora/node/src/mac/region/Region.c
new file mode 100644
index 000000000..72fee1474
--- /dev/null
+++ b/net/lora/node/src/mac/region/Region.c
@@ -0,0 +1,1036 @@
+/*!
+ * \file      Region.c
+ *
+ * \brief     Region implementation.
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ */
+#include "node/mac/LoRaMac.h"
+
+// Setup regions
+#ifdef REGION_AS923
+#include "RegionAS923.h"
+#define AS923_CASE                                 case LORAMAC_REGION_AS923:
+#define AS923_IS_ACTIVE( )                         AS923_CASE { return true; }
+#define AS923_GET_PHY_PARAM( )                     AS923_CASE { return RegionAS923GetPhyParam( getPhy ); }
+#define AS923_SET_BAND_TX_DONE( )                  AS923_CASE { RegionAS923SetBandTxDone( txDone ); break; }
+#define AS923_INIT_DEFAULTS( )                     AS923_CASE { RegionAS923InitDefaults( type ); break; }
+#define AS923_VERIFY( )                            AS923_CASE { return RegionAS923Verify( verify, phyAttribute ); }
+#define AS923_APPLY_CF_LIST( )                     AS923_CASE { RegionAS923ApplyCFList( applyCFList ); break; }
+#define AS923_CHAN_MASK_SET( )                     AS923_CASE { return RegionAS923ChanMaskSet( chanMaskSet ); }
+#define AS923_ADR_NEXT( )                          AS923_CASE { return RegionAS923AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define AS923_COMPUTE_RX_WINDOW_PARAMETERS( )      AS923_CASE { RegionAS923ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define AS923_RX_CONFIG( )                         AS923_CASE { return RegionAS923RxConfig( rxConfig, datarate ); }
+#define AS923_TX_CONFIG( )                         AS923_CASE { return RegionAS923TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define AS923_LINK_ADR_REQ( )                      AS923_CASE { return RegionAS923LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define AS923_RX_PARAM_SETUP_REQ( )                AS923_CASE { return RegionAS923RxParamSetupReq( rxParamSetupReq ); }
+#define AS923_NEW_CHANNEL_REQ( )                   AS923_CASE { return RegionAS923NewChannelReq( newChannelReq ); }
+#define AS923_TX_PARAM_SETUP_REQ( )                AS923_CASE { return RegionAS923TxParamSetupReq( txParamSetupReq ); }
+#define AS923_DL_CHANNEL_REQ( )                    AS923_CASE { return RegionAS923DlChannelReq( dlChannelReq ); }
+#define AS923_ALTERNATE_DR( )                      AS923_CASE { return RegionAS923AlternateDr( currentDr ); }
+#define AS923_CALC_BACKOFF( )                      AS923_CASE { RegionAS923CalcBackOff( calcBackOff ); break; }
+#define AS923_NEXT_CHANNEL( )                      AS923_CASE { return RegionAS923NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define AS923_CHANNEL_ADD( )                       AS923_CASE { return RegionAS923ChannelAdd( channelAdd ); }
+#define AS923_CHANNEL_REMOVE( )                    AS923_CASE { return RegionAS923ChannelsRemove( channelRemove ); }
+#define AS923_SET_CONTINUOUS_WAVE( )               AS923_CASE { RegionAS923SetContinuousWave( continuousWave ); break; }
+#define AS923_APPLY_DR_OFFSET( )                   AS923_CASE { return RegionAS923ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define AS923_IS_ACTIVE( )
+#define AS923_GET_PHY_PARAM( )
+#define AS923_SET_BAND_TX_DONE( )
+#define AS923_INIT_DEFAULTS( )
+#define AS923_VERIFY( )
+#define AS923_APPLY_CF_LIST( )
+#define AS923_CHAN_MASK_SET( )
+#define AS923_ADR_NEXT( )
+#define AS923_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define AS923_RX_CONFIG( )
+#define AS923_TX_CONFIG( )
+#define AS923_LINK_ADR_REQ( )
+#define AS923_RX_PARAM_SETUP_REQ( )
+#define AS923_NEW_CHANNEL_REQ( )
+#define AS923_TX_PARAM_SETUP_REQ( )
+#define AS923_DL_CHANNEL_REQ( )
+#define AS923_ALTERNATE_DR( )
+#define AS923_CALC_BACKOFF( )
+#define AS923_NEXT_CHANNEL( )
+#define AS923_CHANNEL_ADD( )
+#define AS923_CHANNEL_REMOVE( )
+#define AS923_SET_CONTINUOUS_WAVE( )
+#define AS923_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_AU915
+#include "RegionAU915.h"
+#define AU915_CASE                                 case LORAMAC_REGION_AU915:
+#define AU915_IS_ACTIVE( )                         AU915_CASE { return true; }
+#define AU915_GET_PHY_PARAM( )                     AU915_CASE { return RegionAU915GetPhyParam( getPhy ); }
+#define AU915_SET_BAND_TX_DONE( )                  AU915_CASE { RegionAU915SetBandTxDone( txDone ); break; }
+#define AU915_INIT_DEFAULTS( )                     AU915_CASE { RegionAU915InitDefaults( type ); break; }
+#define AU915_VERIFY( )                            AU915_CASE { return RegionAU915Verify( verify, phyAttribute ); }
+#define AU915_APPLY_CF_LIST( )                     AU915_CASE { RegionAU915ApplyCFList( applyCFList ); break; }
+#define AU915_CHAN_MASK_SET( )                     AU915_CASE { return RegionAU915ChanMaskSet( chanMaskSet ); }
+#define AU915_ADR_NEXT( )                          AU915_CASE { return RegionAU915AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define AU915_COMPUTE_RX_WINDOW_PARAMETERS( )      AU915_CASE { RegionAU915ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define AU915_RX_CONFIG( )                         AU915_CASE { return RegionAU915RxConfig( rxConfig, datarate ); }
+#define AU915_TX_CONFIG( )                         AU915_CASE { return RegionAU915TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define AU915_LINK_ADR_REQ( )                      AU915_CASE { return RegionAU915LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define AU915_RX_PARAM_SETUP_REQ( )                AU915_CASE { return RegionAU915RxParamSetupReq( rxParamSetupReq ); }
+#define AU915_NEW_CHANNEL_REQ( )                   AU915_CASE { return RegionAU915NewChannelReq( newChannelReq ); }
+#define AU915_TX_PARAM_SETUP_REQ( )                AU915_CASE { return RegionAU915TxParamSetupReq( txParamSetupReq ); }
+#define AU915_DL_CHANNEL_REQ( )                    AU915_CASE { return RegionAU915DlChannelReq( dlChannelReq ); }
+#define AU915_ALTERNATE_DR( )                      AU915_CASE { return RegionAU915AlternateDr( currentDr ); }
+#define AU915_CALC_BACKOFF( )                      AU915_CASE { RegionAU915CalcBackOff( calcBackOff ); break; }
+#define AU915_NEXT_CHANNEL( )                      AU915_CASE { return RegionAU915NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define AU915_CHANNEL_ADD( )                       AU915_CASE { return RegionAU915ChannelAdd( channelAdd ); }
+#define AU915_CHANNEL_REMOVE( )                    AU915_CASE { return RegionAU915ChannelsRemove( channelRemove ); }
+#define AU915_SET_CONTINUOUS_WAVE( )               AU915_CASE { RegionAU915SetContinuousWave( continuousWave ); break; }
+#define AU915_APPLY_DR_OFFSET( )                   AU915_CASE { return RegionAU915ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define AU915_IS_ACTIVE( )
+#define AU915_GET_PHY_PARAM( )
+#define AU915_SET_BAND_TX_DONE( )
+#define AU915_INIT_DEFAULTS( )
+#define AU915_VERIFY( )
+#define AU915_APPLY_CF_LIST( )
+#define AU915_CHAN_MASK_SET( )
+#define AU915_ADR_NEXT( )
+#define AU915_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define AU915_RX_CONFIG( )
+#define AU915_TX_CONFIG( )
+#define AU915_LINK_ADR_REQ( )
+#define AU915_RX_PARAM_SETUP_REQ( )
+#define AU915_NEW_CHANNEL_REQ( )
+#define AU915_TX_PARAM_SETUP_REQ( )
+#define AU915_DL_CHANNEL_REQ( )
+#define AU915_ALTERNATE_DR( )
+#define AU915_CALC_BACKOFF( )
+#define AU915_NEXT_CHANNEL( )
+#define AU915_CHANNEL_ADD( )
+#define AU915_CHANNEL_REMOVE( )
+#define AU915_SET_CONTINUOUS_WAVE( )
+#define AU915_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_CN470
+#include "RegionCN470.h"
+#define CN470_CASE                                 case LORAMAC_REGION_CN470:
+#define CN470_IS_ACTIVE( )                         CN470_CASE { return true; }
+#define CN470_GET_PHY_PARAM( )                     CN470_CASE { return RegionCN470GetPhyParam( getPhy ); }
+#define CN470_SET_BAND_TX_DONE( )                  CN470_CASE { RegionCN470SetBandTxDone( txDone ); break; }
+#define CN470_INIT_DEFAULTS( )                     CN470_CASE { RegionCN470InitDefaults( type ); break; }
+#define CN470_VERIFY( )                            CN470_CASE { return RegionCN470Verify( verify, phyAttribute ); }
+#define CN470_APPLY_CF_LIST( )                     CN470_CASE { RegionCN470ApplyCFList( applyCFList ); break; }
+#define CN470_CHAN_MASK_SET( )                     CN470_CASE { return RegionCN470ChanMaskSet( chanMaskSet ); }
+#define CN470_ADR_NEXT( )                          CN470_CASE { return RegionCN470AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define CN470_COMPUTE_RX_WINDOW_PARAMETERS( )      CN470_CASE { RegionCN470ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define CN470_RX_CONFIG( )                         CN470_CASE { return RegionCN470RxConfig( rxConfig, datarate ); }
+#define CN470_TX_CONFIG( )                         CN470_CASE { return RegionCN470TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define CN470_LINK_ADR_REQ( )                      CN470_CASE { return RegionCN470LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define CN470_RX_PARAM_SETUP_REQ( )                CN470_CASE { return RegionCN470RxParamSetupReq( rxParamSetupReq ); }
+#define CN470_NEW_CHANNEL_REQ( )                   CN470_CASE { return RegionCN470NewChannelReq( newChannelReq ); }
+#define CN470_TX_PARAM_SETUP_REQ( )                CN470_CASE { return RegionCN470TxParamSetupReq( txParamSetupReq ); }
+#define CN470_DL_CHANNEL_REQ( )                    CN470_CASE { return RegionCN470DlChannelReq( dlChannelReq ); }
+#define CN470_ALTERNATE_DR( )                      CN470_CASE { return RegionCN470AlternateDr( currentDr ); }
+#define CN470_CALC_BACKOFF( )                      CN470_CASE { RegionCN470CalcBackOff( calcBackOff ); break; }
+#define CN470_NEXT_CHANNEL( )                      CN470_CASE { return RegionCN470NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define CN470_CHANNEL_ADD( )                       CN470_CASE { return RegionCN470ChannelAdd( channelAdd ); }
+#define CN470_CHANNEL_REMOVE( )                    CN470_CASE { return RegionCN470ChannelsRemove( channelRemove ); }
+#define CN470_SET_CONTINUOUS_WAVE( )               CN470_CASE { RegionCN470SetContinuousWave( continuousWave ); break; }
+#define CN470_APPLY_DR_OFFSET( )                   CN470_CASE { return RegionCN470ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define CN470_IS_ACTIVE( )
+#define CN470_GET_PHY_PARAM( )
+#define CN470_SET_BAND_TX_DONE( )
+#define CN470_INIT_DEFAULTS( )
+#define CN470_VERIFY( )
+#define CN470_APPLY_CF_LIST( )
+#define CN470_CHAN_MASK_SET( )
+#define CN470_ADR_NEXT( )
+#define CN470_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define CN470_RX_CONFIG( )
+#define CN470_TX_CONFIG( )
+#define CN470_LINK_ADR_REQ( )
+#define CN470_RX_PARAM_SETUP_REQ( )
+#define CN470_NEW_CHANNEL_REQ( )
+#define CN470_TX_PARAM_SETUP_REQ( )
+#define CN470_DL_CHANNEL_REQ( )
+#define CN470_ALTERNATE_DR( )
+#define CN470_CALC_BACKOFF( )
+#define CN470_NEXT_CHANNEL( )
+#define CN470_CHANNEL_ADD( )
+#define CN470_CHANNEL_REMOVE( )
+#define CN470_SET_CONTINUOUS_WAVE( )
+#define CN470_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_CN779
+#include "RegionCN779.h"
+#define CN779_CASE                                 case LORAMAC_REGION_CN779:
+#define CN779_IS_ACTIVE( )                         CN779_CASE { return true; }
+#define CN779_GET_PHY_PARAM( )                     CN779_CASE { return RegionCN779GetPhyParam( getPhy ); }
+#define CN779_SET_BAND_TX_DONE( )                  CN779_CASE { RegionCN779SetBandTxDone( txDone ); break; }
+#define CN779_INIT_DEFAULTS( )                     CN779_CASE { RegionCN779InitDefaults( type ); break; }
+#define CN779_VERIFY( )                            CN779_CASE { return RegionCN779Verify( verify, phyAttribute ); }
+#define CN779_APPLY_CF_LIST( )                     CN779_CASE { RegionCN779ApplyCFList( applyCFList ); break; }
+#define CN779_CHAN_MASK_SET( )                     CN779_CASE { return RegionCN779ChanMaskSet( chanMaskSet ); }
+#define CN779_ADR_NEXT( )                          CN779_CASE { return RegionCN779AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define CN779_COMPUTE_RX_WINDOW_PARAMETERS( )      CN779_CASE { RegionCN779ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define CN779_RX_CONFIG( )                         CN779_CASE { return RegionCN779RxConfig( rxConfig, datarate ); }
+#define CN779_TX_CONFIG( )                         CN779_CASE { return RegionCN779TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define CN779_LINK_ADR_REQ( )                      CN779_CASE { return RegionCN779LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define CN779_RX_PARAM_SETUP_REQ( )                CN779_CASE { return RegionCN779RxParamSetupReq( rxParamSetupReq ); }
+#define CN779_NEW_CHANNEL_REQ( )                   CN779_CASE { return RegionCN779NewChannelReq( newChannelReq ); }
+#define CN779_TX_PARAM_SETUP_REQ( )                CN779_CASE { return RegionCN779TxParamSetupReq( txParamSetupReq ); }
+#define CN779_DL_CHANNEL_REQ( )                    CN779_CASE { return RegionCN779DlChannelReq( dlChannelReq ); }
+#define CN779_ALTERNATE_DR( )                      CN779_CASE { return RegionCN779AlternateDr( currentDr ); }
+#define CN779_CALC_BACKOFF( )                      CN779_CASE { RegionCN779CalcBackOff( calcBackOff ); break; }
+#define CN779_NEXT_CHANNEL( )                      CN779_CASE { return RegionCN779NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define CN779_CHANNEL_ADD( )                       CN779_CASE { return RegionCN779ChannelAdd( channelAdd ); }
+#define CN779_CHANNEL_REMOVE( )                    CN779_CASE { return RegionCN779ChannelsRemove( channelRemove ); }
+#define CN779_SET_CONTINUOUS_WAVE( )               CN779_CASE { RegionCN779SetContinuousWave( continuousWave ); break; }
+#define CN779_APPLY_DR_OFFSET( )                   CN779_CASE { return RegionCN779ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define CN779_IS_ACTIVE( )
+#define CN779_GET_PHY_PARAM( )
+#define CN779_SET_BAND_TX_DONE( )
+#define CN779_INIT_DEFAULTS( )
+#define CN779_VERIFY( )
+#define CN779_APPLY_CF_LIST( )
+#define CN779_CHAN_MASK_SET( )
+#define CN779_ADR_NEXT( )
+#define CN779_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define CN779_RX_CONFIG( )
+#define CN779_TX_CONFIG( )
+#define CN779_LINK_ADR_REQ( )
+#define CN779_RX_PARAM_SETUP_REQ( )
+#define CN779_NEW_CHANNEL_REQ( )
+#define CN779_TX_PARAM_SETUP_REQ( )
+#define CN779_DL_CHANNEL_REQ( )
+#define CN779_ALTERNATE_DR( )
+#define CN779_CALC_BACKOFF( )
+#define CN779_NEXT_CHANNEL( )
+#define CN779_CHANNEL_ADD( )
+#define CN779_CHANNEL_REMOVE( )
+#define CN779_SET_CONTINUOUS_WAVE( )
+#define CN779_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_EU433
+#include "RegionEU433.h"
+#define EU433_CASE                                 case LORAMAC_REGION_EU433:
+#define EU433_IS_ACTIVE( )                         EU433_CASE { return true; }
+#define EU433_GET_PHY_PARAM( )                     EU433_CASE { return RegionEU433GetPhyParam( getPhy ); }
+#define EU433_SET_BAND_TX_DONE( )                  EU433_CASE { RegionEU433SetBandTxDone( txDone ); break; }
+#define EU433_INIT_DEFAULTS( )                     EU433_CASE { RegionEU433InitDefaults( type ); break; }
+#define EU433_VERIFY( )                            EU433_CASE { return RegionEU433Verify( verify, phyAttribute ); }
+#define EU433_APPLY_CF_LIST( )                     EU433_CASE { RegionEU433ApplyCFList( applyCFList ); break; }
+#define EU433_CHAN_MASK_SET( )                     EU433_CASE { return RegionEU433ChanMaskSet( chanMaskSet ); }
+#define EU433_ADR_NEXT( )                          EU433_CASE { return RegionEU433AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define EU433_COMPUTE_RX_WINDOW_PARAMETERS( )      EU433_CASE { RegionEU433ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define EU433_RX_CONFIG( )                         EU433_CASE { return RegionEU433RxConfig( rxConfig, datarate ); }
+#define EU433_TX_CONFIG( )                         EU433_CASE { return RegionEU433TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define EU433_LINK_ADR_REQ( )                      EU433_CASE { return RegionEU433LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define EU433_RX_PARAM_SETUP_REQ( )                EU433_CASE { return RegionEU433RxParamSetupReq( rxParamSetupReq ); }
+#define EU433_NEW_CHANNEL_REQ( )                   EU433_CASE { return RegionEU433NewChannelReq( newChannelReq ); }
+#define EU433_TX_PARAM_SETUP_REQ( )                EU433_CASE { return RegionEU433TxParamSetupReq( txParamSetupReq ); }
+#define EU433_DL_CHANNEL_REQ( )                    EU433_CASE { return RegionEU433DlChannelReq( dlChannelReq ); }
+#define EU433_ALTERNATE_DR( )                      EU433_CASE { return RegionEU433AlternateDr( currentDr ); }
+#define EU433_CALC_BACKOFF( )                      EU433_CASE { RegionEU433CalcBackOff( calcBackOff ); break; }
+#define EU433_NEXT_CHANNEL( )                      EU433_CASE { return RegionEU433NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define EU433_CHANNEL_ADD( )                       EU433_CASE { return RegionEU433ChannelAdd( channelAdd ); }
+#define EU433_CHANNEL_REMOVE( )                    EU433_CASE { return RegionEU433ChannelsRemove( channelRemove ); }
+#define EU433_SET_CONTINUOUS_WAVE( )               EU433_CASE { RegionEU433SetContinuousWave( continuousWave ); break; }
+#define EU433_APPLY_DR_OFFSET( )                   EU433_CASE { return RegionEU433ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define EU433_IS_ACTIVE( )
+#define EU433_GET_PHY_PARAM( )
+#define EU433_SET_BAND_TX_DONE( )
+#define EU433_INIT_DEFAULTS( )
+#define EU433_VERIFY( )
+#define EU433_APPLY_CF_LIST( )
+#define EU433_CHAN_MASK_SET( )
+#define EU433_ADR_NEXT( )
+#define EU433_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define EU433_RX_CONFIG( )
+#define EU433_TX_CONFIG( )
+#define EU433_LINK_ADR_REQ( )
+#define EU433_RX_PARAM_SETUP_REQ( )
+#define EU433_NEW_CHANNEL_REQ( )
+#define EU433_TX_PARAM_SETUP_REQ( )
+#define EU433_DL_CHANNEL_REQ( )
+#define EU433_ALTERNATE_DR( )
+#define EU433_CALC_BACKOFF( )
+#define EU433_NEXT_CHANNEL( )
+#define EU433_CHANNEL_ADD( )
+#define EU433_CHANNEL_REMOVE( )
+#define EU433_SET_CONTINUOUS_WAVE( )
+#define EU433_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_EU868
+#include "RegionEU868.h"
+#define EU868_CASE                                 case LORAMAC_REGION_EU868:
+#define EU868_IS_ACTIVE( )                         EU868_CASE { return true; }
+#define EU868_GET_PHY_PARAM( )                     EU868_CASE { return RegionEU868GetPhyParam( getPhy ); }
+#define EU868_SET_BAND_TX_DONE( )                  EU868_CASE { RegionEU868SetBandTxDone( txDone ); break; }
+#define EU868_INIT_DEFAULTS( )                     EU868_CASE { RegionEU868InitDefaults( type ); break; }
+#define EU868_VERIFY( )                            EU868_CASE { return RegionEU868Verify( verify, phyAttribute ); }
+#define EU868_APPLY_CF_LIST( )                     EU868_CASE { RegionEU868ApplyCFList( applyCFList ); break; }
+#define EU868_CHAN_MASK_SET( )                     EU868_CASE { return RegionEU868ChanMaskSet( chanMaskSet ); }
+#define EU868_ADR_NEXT( )                          EU868_CASE { return RegionEU868AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define EU868_COMPUTE_RX_WINDOW_PARAMETERS( )      EU868_CASE { RegionEU868ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define EU868_RX_CONFIG( )                         EU868_CASE { return RegionEU868RxConfig( rxConfig, datarate ); }
+#define EU868_TX_CONFIG( )                         EU868_CASE { return RegionEU868TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define EU868_LINK_ADR_REQ( )                      EU868_CASE { return RegionEU868LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define EU868_RX_PARAM_SETUP_REQ( )                EU868_CASE { return RegionEU868RxParamSetupReq( rxParamSetupReq ); }
+#define EU868_NEW_CHANNEL_REQ( )                   EU868_CASE { return RegionEU868NewChannelReq( newChannelReq ); }
+#define EU868_TX_PARAM_SETUP_REQ( )                EU868_CASE { return RegionEU868TxParamSetupReq( txParamSetupReq ); }
+#define EU868_DL_CHANNEL_REQ( )                    EU868_CASE { return RegionEU868DlChannelReq( dlChannelReq ); }
+#define EU868_ALTERNATE_DR( )                      EU868_CASE { return RegionEU868AlternateDr( currentDr ); }
+#define EU868_CALC_BACKOFF( )                      EU868_CASE { RegionEU868CalcBackOff( calcBackOff ); break; }
+#define EU868_NEXT_CHANNEL( )                      EU868_CASE { return RegionEU868NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define EU868_CHANNEL_ADD( )                       EU868_CASE { return RegionEU868ChannelAdd( channelAdd ); }
+#define EU868_CHANNEL_REMOVE( )                    EU868_CASE { return RegionEU868ChannelsRemove( channelRemove ); }
+#define EU868_SET_CONTINUOUS_WAVE( )               EU868_CASE { RegionEU868SetContinuousWave( continuousWave ); break; }
+#define EU868_APPLY_DR_OFFSET( )                   EU868_CASE { return RegionEU868ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define EU868_IS_ACTIVE( )
+#define EU868_GET_PHY_PARAM( )
+#define EU868_SET_BAND_TX_DONE( )
+#define EU868_INIT_DEFAULTS( )
+#define EU868_VERIFY( )
+#define EU868_APPLY_CF_LIST( )
+#define EU868_CHAN_MASK_SET( )
+#define EU868_ADR_NEXT( )
+#define EU868_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define EU868_RX_CONFIG( )
+#define EU868_TX_CONFIG( )
+#define EU868_LINK_ADR_REQ( )
+#define EU868_RX_PARAM_SETUP_REQ( )
+#define EU868_NEW_CHANNEL_REQ( )
+#define EU868_TX_PARAM_SETUP_REQ( )
+#define EU868_DL_CHANNEL_REQ( )
+#define EU868_ALTERNATE_DR( )
+#define EU868_CALC_BACKOFF( )
+#define EU868_NEXT_CHANNEL( )
+#define EU868_CHANNEL_ADD( )
+#define EU868_CHANNEL_REMOVE( )
+#define EU868_SET_CONTINUOUS_WAVE( )
+#define EU868_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_KR920
+#include "RegionKR920.h"
+#define KR920_CASE                                 case LORAMAC_REGION_KR920:
+#define KR920_IS_ACTIVE( )                         KR920_CASE { return true; }
+#define KR920_GET_PHY_PARAM( )                     KR920_CASE { return RegionKR920GetPhyParam( getPhy ); }
+#define KR920_SET_BAND_TX_DONE( )                  KR920_CASE { RegionKR920SetBandTxDone( txDone ); break; }
+#define KR920_INIT_DEFAULTS( )                     KR920_CASE { RegionKR920InitDefaults( type ); break; }
+#define KR920_VERIFY( )                            KR920_CASE { return RegionKR920Verify( verify, phyAttribute ); }
+#define KR920_APPLY_CF_LIST( )                     KR920_CASE { RegionKR920ApplyCFList( applyCFList ); break; }
+#define KR920_CHAN_MASK_SET( )                     KR920_CASE { return RegionKR920ChanMaskSet( chanMaskSet ); }
+#define KR920_ADR_NEXT( )                          KR920_CASE { return RegionKR920AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define KR920_COMPUTE_RX_WINDOW_PARAMETERS( )      KR920_CASE { RegionKR920ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define KR920_RX_CONFIG( )                         KR920_CASE { return RegionKR920RxConfig( rxConfig, datarate ); }
+#define KR920_TX_CONFIG( )                         KR920_CASE { return RegionKR920TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define KR920_LINK_ADR_REQ( )                      KR920_CASE { return RegionKR920LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define KR920_RX_PARAM_SETUP_REQ( )                KR920_CASE { return RegionKR920RxParamSetupReq( rxParamSetupReq ); }
+#define KR920_NEW_CHANNEL_REQ( )                   KR920_CASE { return RegionKR920NewChannelReq( newChannelReq ); }
+#define KR920_TX_PARAM_SETUP_REQ( )                KR920_CASE { return RegionKR920TxParamSetupReq( txParamSetupReq ); }
+#define KR920_DL_CHANNEL_REQ( )                    KR920_CASE { return RegionKR920DlChannelReq( dlChannelReq ); }
+#define KR920_ALTERNATE_DR( )                      KR920_CASE { return RegionKR920AlternateDr( currentDr ); }
+#define KR920_CALC_BACKOFF( )                      KR920_CASE { RegionKR920CalcBackOff( calcBackOff ); break; }
+#define KR920_NEXT_CHANNEL( )                      KR920_CASE { return RegionKR920NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define KR920_CHANNEL_ADD( )                       KR920_CASE { return RegionKR920ChannelAdd( channelAdd ); }
+#define KR920_CHANNEL_REMOVE( )                    KR920_CASE { return RegionKR920ChannelsRemove( channelRemove ); }
+#define KR920_SET_CONTINUOUS_WAVE( )               KR920_CASE { RegionKR920SetContinuousWave( continuousWave ); break; }
+#define KR920_APPLY_DR_OFFSET( )                   KR920_CASE { return RegionKR920ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define KR920_IS_ACTIVE( )
+#define KR920_GET_PHY_PARAM( )
+#define KR920_SET_BAND_TX_DONE( )
+#define KR920_INIT_DEFAULTS( )
+#define KR920_VERIFY( )
+#define KR920_APPLY_CF_LIST( )
+#define KR920_CHAN_MASK_SET( )
+#define KR920_ADR_NEXT( )
+#define KR920_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define KR920_RX_CONFIG( )
+#define KR920_TX_CONFIG( )
+#define KR920_LINK_ADR_REQ( )
+#define KR920_RX_PARAM_SETUP_REQ( )
+#define KR920_NEW_CHANNEL_REQ( )
+#define KR920_TX_PARAM_SETUP_REQ( )
+#define KR920_DL_CHANNEL_REQ( )
+#define KR920_ALTERNATE_DR( )
+#define KR920_CALC_BACKOFF( )
+#define KR920_NEXT_CHANNEL( )
+#define KR920_CHANNEL_ADD( )
+#define KR920_CHANNEL_REMOVE( )
+#define KR920_SET_CONTINUOUS_WAVE( )
+#define KR920_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_IN865
+#include "RegionIN865.h"
+#define IN865_CASE                                 case LORAMAC_REGION_IN865:
+#define IN865_IS_ACTIVE( )                         IN865_CASE { return true; }
+#define IN865_GET_PHY_PARAM( )                     IN865_CASE { return RegionIN865GetPhyParam( getPhy ); }
+#define IN865_SET_BAND_TX_DONE( )                  IN865_CASE { RegionIN865SetBandTxDone( txDone ); break; }
+#define IN865_INIT_DEFAULTS( )                     IN865_CASE { RegionIN865InitDefaults( type ); break; }
+#define IN865_VERIFY( )                            IN865_CASE { return RegionIN865Verify( verify, phyAttribute ); }
+#define IN865_APPLY_CF_LIST( )                     IN865_CASE { RegionIN865ApplyCFList( applyCFList ); break; }
+#define IN865_CHAN_MASK_SET( )                     IN865_CASE { return RegionIN865ChanMaskSet( chanMaskSet ); }
+#define IN865_ADR_NEXT( )                          IN865_CASE { return RegionIN865AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define IN865_COMPUTE_RX_WINDOW_PARAMETERS( )      IN865_CASE { RegionIN865ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define IN865_RX_CONFIG( )                         IN865_CASE { return RegionIN865RxConfig( rxConfig, datarate ); }
+#define IN865_TX_CONFIG( )                         IN865_CASE { return RegionIN865TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define IN865_LINK_ADR_REQ( )                      IN865_CASE { return RegionIN865LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define IN865_RX_PARAM_SETUP_REQ( )                IN865_CASE { return RegionIN865RxParamSetupReq( rxParamSetupReq ); }
+#define IN865_NEW_CHANNEL_REQ( )                   IN865_CASE { return RegionIN865NewChannelReq( newChannelReq ); }
+#define IN865_TX_PARAM_SETUP_REQ( )                IN865_CASE { return RegionIN865TxParamSetupReq( txParamSetupReq ); }
+#define IN865_DL_CHANNEL_REQ( )                    IN865_CASE { return RegionIN865DlChannelReq( dlChannelReq ); }
+#define IN865_ALTERNATE_DR( )                      IN865_CASE { return RegionIN865AlternateDr( currentDr ); }
+#define IN865_CALC_BACKOFF( )                      IN865_CASE { RegionIN865CalcBackOff( calcBackOff ); break; }
+#define IN865_NEXT_CHANNEL( )                      IN865_CASE { return RegionIN865NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define IN865_CHANNEL_ADD( )                       IN865_CASE { return RegionIN865ChannelAdd( channelAdd ); }
+#define IN865_CHANNEL_REMOVE( )                    IN865_CASE { return RegionIN865ChannelsRemove( channelRemove ); }
+#define IN865_SET_CONTINUOUS_WAVE( )               IN865_CASE { RegionIN865SetContinuousWave( continuousWave ); break; }
+#define IN865_APPLY_DR_OFFSET( )                   IN865_CASE { return RegionIN865ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define IN865_IS_ACTIVE( )
+#define IN865_GET_PHY_PARAM( )
+#define IN865_SET_BAND_TX_DONE( )
+#define IN865_INIT_DEFAULTS( )
+#define IN865_VERIFY( )
+#define IN865_APPLY_CF_LIST( )
+#define IN865_CHAN_MASK_SET( )
+#define IN865_ADR_NEXT( )
+#define IN865_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define IN865_RX_CONFIG( )
+#define IN865_TX_CONFIG( )
+#define IN865_LINK_ADR_REQ( )
+#define IN865_RX_PARAM_SETUP_REQ( )
+#define IN865_NEW_CHANNEL_REQ( )
+#define IN865_TX_PARAM_SETUP_REQ( )
+#define IN865_DL_CHANNEL_REQ( )
+#define IN865_ALTERNATE_DR( )
+#define IN865_CALC_BACKOFF( )
+#define IN865_NEXT_CHANNEL( )
+#define IN865_CHANNEL_ADD( )
+#define IN865_CHANNEL_REMOVE( )
+#define IN865_SET_CONTINUOUS_WAVE( )
+#define IN865_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_US915
+#include "RegionUS915.h"
+#define US915_CASE                                 case LORAMAC_REGION_US915:
+#define US915_IS_ACTIVE( )                         US915_CASE { return true; }
+#define US915_GET_PHY_PARAM( )                     US915_CASE { return RegionUS915GetPhyParam( getPhy ); }
+#define US915_SET_BAND_TX_DONE( )                  US915_CASE { RegionUS915SetBandTxDone( txDone ); break; }
+#define US915_INIT_DEFAULTS( )                     US915_CASE { RegionUS915InitDefaults( type ); break; }
+#define US915_VERIFY( )                            US915_CASE { return RegionUS915Verify( verify, phyAttribute ); }
+#define US915_APPLY_CF_LIST( )                     US915_CASE { RegionUS915ApplyCFList( applyCFList ); break; }
+#define US915_CHAN_MASK_SET( )                     US915_CASE { return RegionUS915ChanMaskSet( chanMaskSet ); }
+#define US915_ADR_NEXT( )                          US915_CASE { return RegionUS915AdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define US915_COMPUTE_RX_WINDOW_PARAMETERS( )      US915_CASE { RegionUS915ComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define US915_RX_CONFIG( )                         US915_CASE { return RegionUS915RxConfig( rxConfig, datarate ); }
+#define US915_TX_CONFIG( )                         US915_CASE { return RegionUS915TxConfig( txConfig, txPower, txTimeOnAir ); }
+#define US915_LINK_ADR_REQ( )                      US915_CASE { return RegionUS915LinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define US915_RX_PARAM_SETUP_REQ( )                US915_CASE { return RegionUS915RxParamSetupReq( rxParamSetupReq ); }
+#define US915_NEW_CHANNEL_REQ( )                   US915_CASE { return RegionUS915NewChannelReq( newChannelReq ); }
+#define US915_TX_PARAM_SETUP_REQ( )                US915_CASE { return RegionUS915TxParamSetupReq( txParamSetupReq ); }
+#define US915_DL_CHANNEL_REQ( )                    US915_CASE { return RegionUS915DlChannelReq( dlChannelReq ); }
+#define US915_ALTERNATE_DR( )                      US915_CASE { return RegionUS915AlternateDr( currentDr ); }
+#define US915_CALC_BACKOFF( )                      US915_CASE { RegionUS915CalcBackOff( calcBackOff ); break; }
+#define US915_NEXT_CHANNEL( )                      US915_CASE { return RegionUS915NextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define US915_CHANNEL_ADD( )                       US915_CASE { return RegionUS915ChannelAdd( channelAdd ); }
+#define US915_CHANNEL_REMOVE( )                    US915_CASE { return RegionUS915ChannelsRemove( channelRemove ); }
+#define US915_SET_CONTINUOUS_WAVE( )               US915_CASE { RegionUS915SetContinuousWave( continuousWave ); break; }
+#define US915_APPLY_DR_OFFSET( )                   US915_CASE { return RegionUS915ApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define US915_IS_ACTIVE( )
+#define US915_GET_PHY_PARAM( )
+#define US915_SET_BAND_TX_DONE( )
+#define US915_INIT_DEFAULTS( )
+#define US915_VERIFY( )
+#define US915_APPLY_CF_LIST( )
+#define US915_CHAN_MASK_SET( )
+#define US915_ADR_NEXT( )
+#define US915_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define US915_RX_CONFIG( )
+#define US915_TX_CONFIG( )
+#define US915_LINK_ADR_REQ( )
+#define US915_RX_PARAM_SETUP_REQ( )
+#define US915_NEW_CHANNEL_REQ( )
+#define US915_TX_PARAM_SETUP_REQ( )
+#define US915_DL_CHANNEL_REQ( )
+#define US915_ALTERNATE_DR( )
+#define US915_CALC_BACKOFF( )
+#define US915_NEXT_CHANNEL( )
+#define US915_CHANNEL_ADD( )
+#define US915_CHANNEL_REMOVE( )
+#define US915_SET_CONTINUOUS_WAVE( )
+#define US915_APPLY_DR_OFFSET( )
+#endif
+
+#ifdef REGION_US915_HYBRID
+#include "RegionUS915-Hybrid.h"
+#define US915_HYBRID_CASE                                 case LORAMAC_REGION_US915_HYBRID:
+#define US915_HYBRID_IS_ACTIVE( )                         US915_HYBRID_CASE { return true; }
+#define US915_HYBRID_GET_PHY_PARAM( )                     US915_HYBRID_CASE { return RegionUS915HybridGetPhyParam( getPhy ); }
+#define US915_HYBRID_SET_BAND_TX_DONE( )                  US915_HYBRID_CASE { RegionUS915HybridSetBandTxDone( txDone ); break; }
+#define US915_HYBRID_INIT_DEFAULTS( )                     US915_HYBRID_CASE { RegionUS915HybridInitDefaults( type ); break; }
+#define US915_HYBRID_VERIFY( )                            US915_HYBRID_CASE { return RegionUS915HybridVerify( verify, phyAttribute ); }
+#define US915_HYBRID_APPLY_CF_LIST( )                     US915_HYBRID_CASE { RegionUS915HybridApplyCFList( applyCFList ); break; }
+#define US915_HYBRID_CHAN_MASK_SET( )                     US915_HYBRID_CASE { return RegionUS915HybridChanMaskSet( chanMaskSet ); }
+#define US915_HYBRID_ADR_NEXT( )                          US915_HYBRID_CASE { return RegionUS915HybridAdrNext( adrNext, drOut, txPowOut, adrAckCounter ); }
+#define US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS( )      US915_HYBRID_CASE { RegionUS915HybridComputeRxWindowParameters( datarate, minRxSymbols, rxError, rxConfigParams ); break; }
+#define US915_HYBRID_RX_CONFIG( )                         US915_HYBRID_CASE { return RegionUS915HybridRxConfig( rxConfig, datarate ); }
+#define US915_HYBRID_TX_CONFIG( )                         US915_HYBRID_CASE { return RegionUS915HybridTxConfig( txConfig, txPower, txTimeOnAir ); }
+#define US915_HYBRID_LINK_ADR_REQ( )                      US915_HYBRID_CASE { return RegionUS915HybridLinkAdrReq( linkAdrReq, drOut, txPowOut, nbRepOut, nbBytesParsed ); }
+#define US915_HYBRID_RX_PARAM_SETUP_REQ( )                US915_HYBRID_CASE { return RegionUS915HybridRxParamSetupReq( rxParamSetupReq ); }
+#define US915_HYBRID_NEW_CHANNEL_REQ( )                   US915_HYBRID_CASE { return RegionUS915HybridNewChannelReq( newChannelReq ); }
+#define US915_HYBRID_TX_PARAM_SETUP_REQ( )                US915_HYBRID_CASE { return RegionUS915HybridTxParamSetupReq( txParamSetupReq ); }
+#define US915_HYBRID_DL_CHANNEL_REQ( )                    US915_HYBRID_CASE { return RegionUS915HybridDlChannelReq( dlChannelReq ); }
+#define US915_HYBRID_ALTERNATE_DR( )                      US915_HYBRID_CASE { return RegionUS915HybridAlternateDr( currentDr ); }
+#define US915_HYBRID_CALC_BACKOFF( )                      US915_HYBRID_CASE { RegionUS915HybridCalcBackOff( calcBackOff ); break; }
+#define US915_HYBRID_NEXT_CHANNEL( )                      US915_HYBRID_CASE { return RegionUS915HybridNextChannel( nextChanParams, channel, time, aggregatedTimeOff ); }
+#define US915_HYBRID_CHANNEL_ADD( )                       US915_HYBRID_CASE { return RegionUS915HybridChannelAdd( channelAdd ); }
+#define US915_HYBRID_CHANNEL_REMOVE( )                    US915_HYBRID_CASE { return RegionUS915HybridChannelsRemove( channelRemove ); }
+#define US915_HYBRID_SET_CONTINUOUS_WAVE( )               US915_HYBRID_CASE { RegionUS915HybridSetContinuousWave( continuousWave ); break; }
+#define US915_HYBRID_APPLY_DR_OFFSET( )                   US915_HYBRID_CASE { return RegionUS915HybridApplyDrOffset( downlinkDwellTime, dr, drOffset ); }
+#else
+#define US915_HYBRID_IS_ACTIVE( )
+#define US915_HYBRID_GET_PHY_PARAM( )
+#define US915_HYBRID_SET_BAND_TX_DONE( )
+#define US915_HYBRID_INIT_DEFAULTS( )
+#define US915_HYBRID_VERIFY( )
+#define US915_HYBRID_APPLY_CF_LIST( )
+#define US915_HYBRID_CHAN_MASK_SET( )
+#define US915_HYBRID_ADR_NEXT( )
+#define US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS( )
+#define US915_HYBRID_RX_CONFIG( )
+#define US915_HYBRID_TX_CONFIG( )
+#define US915_HYBRID_LINK_ADR_REQ( )
+#define US915_HYBRID_RX_PARAM_SETUP_REQ( )
+#define US915_HYBRID_NEW_CHANNEL_REQ( )
+#define US915_HYBRID_TX_PARAM_SETUP_REQ( )
+#define US915_HYBRID_DL_CHANNEL_REQ( )
+#define US915_HYBRID_ALTERNATE_DR( )
+#define US915_HYBRID_CALC_BACKOFF( )
+#define US915_HYBRID_NEXT_CHANNEL( )
+#define US915_HYBRID_CHANNEL_ADD( )
+#define US915_HYBRID_CHANNEL_REMOVE( )
+#define US915_HYBRID_SET_CONTINUOUS_WAVE( )
+#define US915_HYBRID_APPLY_DR_OFFSET( )
+#endif
+
+bool RegionIsActive( LoRaMacRegion_t region )
+{
+    switch( region )
+    {
+        AS923_IS_ACTIVE( );
+        AU915_IS_ACTIVE( );
+        CN470_IS_ACTIVE( );
+        CN779_IS_ACTIVE( );
+        EU433_IS_ACTIVE( );
+        EU868_IS_ACTIVE( );
+        KR920_IS_ACTIVE( );
+        IN865_IS_ACTIVE( );
+        US915_IS_ACTIVE( );
+        US915_HYBRID_IS_ACTIVE( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+PhyParam_t RegionGetPhyParam( LoRaMacRegion_t region, GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+    switch( region )
+    {
+        AS923_GET_PHY_PARAM( );
+        AU915_GET_PHY_PARAM( );
+        CN470_GET_PHY_PARAM( );
+        CN779_GET_PHY_PARAM( );
+        EU433_GET_PHY_PARAM( );
+        EU868_GET_PHY_PARAM( );
+        KR920_GET_PHY_PARAM( );
+        IN865_GET_PHY_PARAM( );
+        US915_GET_PHY_PARAM( );
+        US915_HYBRID_GET_PHY_PARAM( );
+        default:
+        {
+            return phyParam;
+        }
+    }
+}
+
+void RegionSetBandTxDone( LoRaMacRegion_t region, SetBandTxDoneParams_t* txDone )
+{
+    switch( region )
+    {
+        AS923_SET_BAND_TX_DONE( );
+        AU915_SET_BAND_TX_DONE( );
+        CN470_SET_BAND_TX_DONE( );
+        CN779_SET_BAND_TX_DONE( );
+        EU433_SET_BAND_TX_DONE( );
+        EU868_SET_BAND_TX_DONE( );
+        KR920_SET_BAND_TX_DONE( );
+        IN865_SET_BAND_TX_DONE( );
+        US915_SET_BAND_TX_DONE( );
+        US915_HYBRID_SET_BAND_TX_DONE( );
+        default:
+        {
+            return;
+        }
+    }
+}
+
+void RegionInitDefaults( LoRaMacRegion_t region, InitType_t type )
+{
+    switch( region )
+    {
+        AS923_INIT_DEFAULTS( );
+        AU915_INIT_DEFAULTS( );
+        CN470_INIT_DEFAULTS( );
+        CN779_INIT_DEFAULTS( );
+        EU433_INIT_DEFAULTS( );
+        EU868_INIT_DEFAULTS( );
+        KR920_INIT_DEFAULTS( );
+        IN865_INIT_DEFAULTS( );
+        US915_INIT_DEFAULTS( );
+        US915_HYBRID_INIT_DEFAULTS( );
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionVerify( LoRaMacRegion_t region, VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( region )
+    {
+        AS923_VERIFY( );
+        AU915_VERIFY( );
+        CN470_VERIFY( );
+        CN779_VERIFY( );
+        EU433_VERIFY( );
+        EU868_VERIFY( );
+        KR920_VERIFY( );
+        IN865_VERIFY( );
+        US915_VERIFY( );
+        US915_HYBRID_VERIFY( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+void RegionApplyCFList( LoRaMacRegion_t region, ApplyCFListParams_t* applyCFList )
+{
+    switch( region )
+    {
+        AS923_APPLY_CF_LIST( );
+        AU915_APPLY_CF_LIST( );
+        CN470_APPLY_CF_LIST( );
+        CN779_APPLY_CF_LIST( );
+        EU433_APPLY_CF_LIST( );
+        EU868_APPLY_CF_LIST( );
+        KR920_APPLY_CF_LIST( );
+        IN865_APPLY_CF_LIST( );
+        US915_APPLY_CF_LIST( );
+        US915_HYBRID_APPLY_CF_LIST( );
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionChanMaskSet( LoRaMacRegion_t region, ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( region )
+    {
+        AS923_CHAN_MASK_SET( );
+        AU915_CHAN_MASK_SET( );
+        CN470_CHAN_MASK_SET( );
+        CN779_CHAN_MASK_SET( );
+        EU433_CHAN_MASK_SET( );
+        EU868_CHAN_MASK_SET( );
+        KR920_CHAN_MASK_SET( );
+        IN865_CHAN_MASK_SET( );
+        US915_CHAN_MASK_SET( );
+        US915_HYBRID_CHAN_MASK_SET( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+bool RegionAdrNext( LoRaMacRegion_t region, AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    switch( region )
+    {
+        AS923_ADR_NEXT( );
+        AU915_ADR_NEXT( );
+        CN470_ADR_NEXT( );
+        CN779_ADR_NEXT( );
+        EU433_ADR_NEXT( );
+        EU868_ADR_NEXT( );
+        KR920_ADR_NEXT( );
+        IN865_ADR_NEXT( );
+        US915_ADR_NEXT( );
+        US915_HYBRID_ADR_NEXT( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+void RegionComputeRxWindowParameters( LoRaMacRegion_t region, int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    switch( region )
+    {
+        AS923_COMPUTE_RX_WINDOW_PARAMETERS( );
+        AU915_COMPUTE_RX_WINDOW_PARAMETERS( );
+        CN470_COMPUTE_RX_WINDOW_PARAMETERS( );
+        CN779_COMPUTE_RX_WINDOW_PARAMETERS( );
+        EU433_COMPUTE_RX_WINDOW_PARAMETERS( );
+        EU868_COMPUTE_RX_WINDOW_PARAMETERS( );
+        KR920_COMPUTE_RX_WINDOW_PARAMETERS( );
+        IN865_COMPUTE_RX_WINDOW_PARAMETERS( );
+        US915_COMPUTE_RX_WINDOW_PARAMETERS( );
+        US915_HYBRID_COMPUTE_RX_WINDOW_PARAMETERS( );
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionRxConfig( LoRaMacRegion_t region, RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    switch( region )
+    {
+        AS923_RX_CONFIG( );
+        AU915_RX_CONFIG( );
+        CN470_RX_CONFIG( );
+        CN779_RX_CONFIG( );
+        EU433_RX_CONFIG( );
+        EU868_RX_CONFIG( );
+        KR920_RX_CONFIG( );
+        IN865_RX_CONFIG( );
+        US915_RX_CONFIG( );
+        US915_HYBRID_RX_CONFIG( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+bool RegionTxConfig( LoRaMacRegion_t region, TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    switch( region )
+    {
+        AS923_TX_CONFIG( );
+        AU915_TX_CONFIG( );
+        CN470_TX_CONFIG( );
+        CN779_TX_CONFIG( );
+        EU433_TX_CONFIG( );
+        EU868_TX_CONFIG( );
+        KR920_TX_CONFIG( );
+        IN865_TX_CONFIG( );
+        US915_TX_CONFIG( );
+        US915_HYBRID_TX_CONFIG( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+uint8_t RegionLinkAdrReq( LoRaMacRegion_t region, LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    switch( region )
+    {
+        AS923_LINK_ADR_REQ( );
+        AU915_LINK_ADR_REQ( );
+        CN470_LINK_ADR_REQ( );
+        CN779_LINK_ADR_REQ( );
+        EU433_LINK_ADR_REQ( );
+        EU868_LINK_ADR_REQ( );
+        KR920_LINK_ADR_REQ( );
+        IN865_LINK_ADR_REQ( );
+        US915_LINK_ADR_REQ( );
+        US915_HYBRID_LINK_ADR_REQ( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+uint8_t RegionRxParamSetupReq( LoRaMacRegion_t region, RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    switch( region )
+    {
+        AS923_RX_PARAM_SETUP_REQ( );
+        AU915_RX_PARAM_SETUP_REQ( );
+        CN470_RX_PARAM_SETUP_REQ( );
+        CN779_RX_PARAM_SETUP_REQ( );
+        EU433_RX_PARAM_SETUP_REQ( );
+        EU868_RX_PARAM_SETUP_REQ( );
+        KR920_RX_PARAM_SETUP_REQ( );
+        IN865_RX_PARAM_SETUP_REQ( );
+        US915_RX_PARAM_SETUP_REQ( );
+        US915_HYBRID_RX_PARAM_SETUP_REQ( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+uint8_t RegionNewChannelReq( LoRaMacRegion_t region, NewChannelReqParams_t* newChannelReq )
+{
+    switch( region )
+    {
+        AS923_NEW_CHANNEL_REQ( );
+        AU915_NEW_CHANNEL_REQ( );
+        CN470_NEW_CHANNEL_REQ( );
+        CN779_NEW_CHANNEL_REQ( );
+        EU433_NEW_CHANNEL_REQ( );
+        EU868_NEW_CHANNEL_REQ( );
+        KR920_NEW_CHANNEL_REQ( );
+        IN865_NEW_CHANNEL_REQ( );
+        US915_NEW_CHANNEL_REQ( );
+        US915_HYBRID_NEW_CHANNEL_REQ( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+int8_t RegionTxParamSetupReq( LoRaMacRegion_t region, TxParamSetupReqParams_t* txParamSetupReq )
+{
+    switch( region )
+    {
+        AS923_TX_PARAM_SETUP_REQ( );
+        AU915_TX_PARAM_SETUP_REQ( );
+        CN470_TX_PARAM_SETUP_REQ( );
+        CN779_TX_PARAM_SETUP_REQ( );
+        EU433_TX_PARAM_SETUP_REQ( );
+        EU868_TX_PARAM_SETUP_REQ( );
+        KR920_TX_PARAM_SETUP_REQ( );
+        IN865_TX_PARAM_SETUP_REQ( );
+        US915_TX_PARAM_SETUP_REQ( );
+        US915_HYBRID_TX_PARAM_SETUP_REQ( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+uint8_t RegionDlChannelReq( LoRaMacRegion_t region, DlChannelReqParams_t* dlChannelReq )
+{
+    switch( region )
+    {
+        AS923_DL_CHANNEL_REQ( );
+        AU915_DL_CHANNEL_REQ( );
+        CN470_DL_CHANNEL_REQ( );
+        CN779_DL_CHANNEL_REQ( );
+        EU433_DL_CHANNEL_REQ( );
+        EU868_DL_CHANNEL_REQ( );
+        KR920_DL_CHANNEL_REQ( );
+        IN865_DL_CHANNEL_REQ( );
+        US915_DL_CHANNEL_REQ( );
+        US915_HYBRID_DL_CHANNEL_REQ( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+int8_t RegionAlternateDr( LoRaMacRegion_t region, int8_t currentDr )
+{
+    switch( region )
+    {
+        AS923_ALTERNATE_DR( );
+        AU915_ALTERNATE_DR( );
+        CN470_ALTERNATE_DR( );
+        CN779_ALTERNATE_DR( );
+        EU433_ALTERNATE_DR( );
+        EU868_ALTERNATE_DR( );
+        KR920_ALTERNATE_DR( );
+        IN865_ALTERNATE_DR( );
+        US915_ALTERNATE_DR( );
+        US915_HYBRID_ALTERNATE_DR( );
+        default:
+        {
+            return 0;
+        }
+    }
+}
+
+void RegionCalcBackOff( LoRaMacRegion_t region, CalcBackOffParams_t* calcBackOff )
+{
+    switch( region )
+    {
+        AS923_CALC_BACKOFF( );
+        AU915_CALC_BACKOFF( );
+        CN470_CALC_BACKOFF( );
+        CN779_CALC_BACKOFF( );
+        EU433_CALC_BACKOFF( );
+        EU868_CALC_BACKOFF( );
+        KR920_CALC_BACKOFF( );
+        IN865_CALC_BACKOFF( );
+        US915_CALC_BACKOFF( );
+        US915_HYBRID_CALC_BACKOFF( );
+        default:
+        {
+            break;
+        }
+    }
+}
+
+LoRaMacStatus_t RegionNextChannel( LoRaMacRegion_t region, NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    switch( region )
+    {
+        AS923_NEXT_CHANNEL( );
+        AU915_NEXT_CHANNEL( );
+        CN470_NEXT_CHANNEL( );
+        CN779_NEXT_CHANNEL( );
+        EU433_NEXT_CHANNEL( );
+        EU868_NEXT_CHANNEL( );
+        KR920_NEXT_CHANNEL( );
+        IN865_NEXT_CHANNEL( );
+        US915_NEXT_CHANNEL( );
+        US915_HYBRID_NEXT_CHANNEL( );
+        default:
+        {
+            return LORAMAC_STATUS_REGION_NOT_SUPPORTED;
+        }
+    }
+}
+
+LoRaMacStatus_t RegionChannelAdd( LoRaMacRegion_t region, ChannelAddParams_t* channelAdd )
+{
+    switch( region )
+    {
+        AS923_CHANNEL_ADD( );
+        AU915_CHANNEL_ADD( );
+        CN470_CHANNEL_ADD( );
+        CN779_CHANNEL_ADD( );
+        EU433_CHANNEL_ADD( );
+        EU868_CHANNEL_ADD( );
+        KR920_CHANNEL_ADD( );
+        IN865_CHANNEL_ADD( );
+        US915_CHANNEL_ADD( );
+        US915_HYBRID_CHANNEL_ADD( );
+        default:
+        {
+            return LORAMAC_STATUS_PARAMETER_INVALID;
+        }
+    }
+}
+
+bool RegionChannelsRemove( LoRaMacRegion_t region, ChannelRemoveParams_t* channelRemove )
+{
+    switch( region )
+    {
+        AS923_CHANNEL_REMOVE( );
+        AU915_CHANNEL_REMOVE( );
+        CN470_CHANNEL_REMOVE( );
+        CN779_CHANNEL_REMOVE( );
+        EU433_CHANNEL_REMOVE( );
+        EU868_CHANNEL_REMOVE( );
+        KR920_CHANNEL_REMOVE( );
+        IN865_CHANNEL_REMOVE( );
+        US915_CHANNEL_REMOVE( );
+        US915_HYBRID_CHANNEL_REMOVE( );
+        default:
+        {
+            return false;
+        }
+    }
+}
+
+void RegionSetContinuousWave( LoRaMacRegion_t region, ContinuousWaveParams_t* continuousWave )
+{
+    switch( region )
+    {
+        AS923_SET_CONTINUOUS_WAVE( );
+        AU915_SET_CONTINUOUS_WAVE( );
+        CN470_SET_CONTINUOUS_WAVE( );
+        CN779_SET_CONTINUOUS_WAVE( );
+        EU433_SET_CONTINUOUS_WAVE( );
+        EU868_SET_CONTINUOUS_WAVE( );
+        KR920_SET_CONTINUOUS_WAVE( );
+        IN865_SET_CONTINUOUS_WAVE( );
+        US915_SET_CONTINUOUS_WAVE( );
+        US915_HYBRID_SET_CONTINUOUS_WAVE( );
+        default:
+        {
+            break;
+        }
+    }
+}
+
+uint8_t RegionApplyDrOffset( LoRaMacRegion_t region, uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    switch( region )
+    {
+        AS923_APPLY_DR_OFFSET( );
+        AU915_APPLY_DR_OFFSET( );
+        CN470_APPLY_DR_OFFSET( );
+        CN779_APPLY_DR_OFFSET( );
+        EU433_APPLY_DR_OFFSET( );
+        EU868_APPLY_DR_OFFSET( );
+        KR920_APPLY_DR_OFFSET( );
+        IN865_APPLY_DR_OFFSET( );
+        US915_APPLY_DR_OFFSET( );
+        US915_HYBRID_APPLY_DR_OFFSET( );
+        default:
+        {
+            return dr;
+        }
+    }
+}
diff --git a/net/lora/node/src/mac/region/RegionAS923.c b/net/lora/node/src/mac/region/RegionAS923.c
new file mode 100644
index 000000000..a712c4d2a
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionAS923.c
@@ -0,0 +1,1094 @@
+/*!
+ * \file      RegionAS923.c
+ *
+ * \brief     Region implementation for AS923
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+#include "RegionCommon.h"
+#include "RegionAS923.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              1
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[AS923_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[AS923_MAX_NB_BANDS] =
+{
+    AS923_BAND0
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsAS923[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static bool VerifyTxFreq( uint32_t freq )
+{
+    // Check radio driver support
+    if( Radio.CheckRfFrequency( freq ) == false )
+    {
+        return false;
+    }
+
+    if( ( freq < 915000000 ) || ( freq > 928000000 ) )
+    {
+        return false;
+    }
+    return true;
+}
+
+static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < AS923_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( joined == false )
+                {
+                    if( ( AS923_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
+                    {
+                        continue;
+                    }
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            if( getPhy->DownlinkDwellTime == 0 )
+            {
+                phyParam.Value = AS923_RX_MIN_DATARATE;
+            }
+            else
+            {
+                phyParam.Value = AS923_DWELL_LIMIT_DATARATE;
+            }
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            if( getPhy->UplinkDwellTime == 0 )
+            {
+                phyParam.Value = AS923_TX_MIN_DATARATE;
+            }
+            else
+            {
+                phyParam.Value = AS923_DWELL_LIMIT_DATARATE;
+            }
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = AS923_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            if( getPhy->UplinkDwellTime == 0 )
+            {
+                phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, AS923_TX_MIN_DATARATE );
+            }
+            else
+            {
+                phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, AS923_DWELL_LIMIT_DATARATE );
+            }
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = AS923_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            if( getPhy->UplinkDwellTime == 0 )
+            {
+                phyParam.Value = MaxPayloadOfDatarateDwell0AS923[getPhy->Datarate];
+            }
+            else
+            {
+                phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate];
+            }
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            if( getPhy->UplinkDwellTime == 0 )
+            {
+                phyParam.Value = MaxPayloadOfDatarateRepeaterDwell0AS923[getPhy->Datarate];
+            }
+            else
+            {
+                phyParam.Value = MaxPayloadOfDatarateDwell1UpAS923[getPhy->Datarate];
+            }
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = AS923_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = AS923_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = AS923_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = AS923_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = AS923_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = AS923_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = AS923_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( AS923_ACKTIMEOUT + randr( -AS923_ACK_TIMEOUT_RND, AS923_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = AS923_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = AS923_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = AS923_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = AS923_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        {
+            phyParam.Value = AS923_DEFAULT_UPLINK_DWELL_TIME;
+            break;
+        }
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = AS923_DEFAULT_DOWNLINK_DWELL_TIME;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = AS923_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = AS923_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionAS923SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionAS923InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            Channels[0] = ( ChannelParams_t ) AS923_LC1;
+            Channels[1] = ( ChannelParams_t ) AS923_LC2;
+
+            // Initialize the channels default mask
+            ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 );
+            // Update the channels mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Restore channels default mask
+            ChannelsMask[0] |= ChannelsDefaultMask[0];
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Update the channels mask defaults
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionAS923Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        {
+            if( verify->DatarateParams.UplinkDwellTime == 0 )
+            {
+                return RegionCommonValueInRange( verify->DatarateParams.Datarate, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE );
+            }
+            else
+            {
+                return RegionCommonValueInRange( verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_TX_MAX_DATARATE );
+            }
+        }
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
+        }
+        case PHY_RX_DR:
+        {
+            if( verify->DatarateParams.DownlinkDwellTime == 0 )
+            {
+                return RegionCommonValueInRange( verify->DatarateParams.Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE );
+            }
+            else
+            {
+                return RegionCommonValueInRange( verify->DatarateParams.Datarate, AS923_DWELL_LIMIT_DATARATE, AS923_RX_MAX_DATARATE );
+            }
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, AS923_MAX_TX_POWER, AS923_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return AS923_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionAS923ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    ChannelParams_t newChannel;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    // Setup default datarate range
+    newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
+
+    // Size of the optional CF list
+    if( applyCFList->Size != 16 )
+    {
+        return;
+    }
+
+    // Last byte is RFU, don't take it into account
+    for( uint8_t i = 0, chanIdx = AS923_NUMB_DEFAULT_CHANNELS; chanIdx < AS923_MAX_NB_CHANNELS; i+=3, chanIdx++ )
+    {
+        if( chanIdx < ( AS923_NUMB_CHANNELS_CF_LIST + AS923_NUMB_DEFAULT_CHANNELS ) )
+        {
+            // Channel frequency
+            newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
+            newChannel.Frequency *= 100;
+
+            // Initialize alternative frequency to 0
+            newChannel.Rx1Frequency = 0;
+        }
+        else
+        {
+            newChannel.Frequency = 0;
+            newChannel.DrRange.Value = 0;
+            newChannel.Rx1Frequency = 0;
+        }
+
+        if( newChannel.Frequency != 0 )
+        {
+            channelAdd.NewChannel = &newChannel;
+            channelAdd.ChannelId = chanIdx;
+
+            // Try to add all channels
+            RegionAS923ChannelAdd( &channelAdd );
+        }
+        else
+        {
+            channelRemove.ChannelId = chanIdx;
+
+            RegionAS923ChannelsRemove( &channelRemove );
+        }
+    }
+}
+
+bool RegionAS923ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionAS923AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t minTxDatarate = 0;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+    phyParam = RegionAS923GetPhyParam( &getPhy );
+    minTxDatarate = phyParam.Value;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    // Apply the minimum possible datarate.
+    datarate = MAX( datarate, minTxDatarate );
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == minTxDatarate )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= AS923_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = AS923_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( AS923_ADR_ACK_LIMIT + AS923_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % AS923_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionAS923GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == minTxDatarate )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] |= LC( 1 ) + LC( 2 );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionAS923ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, AS923_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    if( rxConfigParams->Datarate == DR_7 )
+    { // FSK
+        tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesAS923[rxConfigParams->Datarate] );
+    }
+    else
+    { // LoRa
+        tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesAS923[rxConfigParams->Datarate], BandwidthsAS923[rxConfigParams->Datarate] );
+    }
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    RadioModems_t modem;
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = Channels[rxConfig->Channel].Frequency;
+        // Apply the alternative RX 1 window frequency, if it is available
+        if( Channels[rxConfig->Channel].Rx1Frequency != 0 )
+        {
+            frequency = Channels[rxConfig->Channel].Rx1Frequency;
+        }
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesAS923[dr];
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    if( dr == DR_7 )
+    {
+        modem = MODEM_FSK;
+        Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+    }
+
+    // Check for repeater support
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterDwell0AS923[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateDwell0AS923[dr];
+    }
+
+    Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionAS923TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    RadioModems_t modem;
+    int8_t phyDr = DataratesAS923[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    if( txConfig->Datarate == DR_7 )
+    { // High Speed FSK channel
+        modem = MODEM_FSK;
+        Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+    }
+
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
+    // Get the time-on-air of the next tx frame
+    *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
+
+    *txPower = txPowerLimited;
+    return true;
+}
+
+uint8_t RegionAS923LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t chMask = 0;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        // Get ADR request parameters
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        // Setup temporary channels mask
+        chMask = linkAdrParams.ChMask;
+
+        // Verify channels mask
+        if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
+        {
+            status &= 0xFE; // Channel mask KO
+        }
+        else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
+                ( linkAdrParams.ChMaskCtrl >= 7 ) )
+        {
+            // RFU
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            for( uint8_t i = 0; i < AS923_MAX_NB_CHANNELS; i++ )
+            {
+                if( linkAdrParams.ChMaskCtrl == 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
+                    }
+                }
+            }
+        }
+    }
+
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
+    phyParam = RegionAS923GetPhyParam( &getPhy );
+
+    linkAdrVerifyParams.Status = status;
+    linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
+    linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
+    linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
+    linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
+    linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
+    linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
+    linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
+    linkAdrVerifyParams.NbChannels = AS923_MAX_NB_CHANNELS;
+    linkAdrVerifyParams.ChannelsMask = &chMask;
+    linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
+    linkAdrVerifyParams.MaxDatarate = AS923_TX_MAX_DATARATE;
+    linkAdrVerifyParams.Channels = Channels;
+    linkAdrVerifyParams.MinTxPower = AS923_MIN_TX_POWER;
+    linkAdrVerifyParams.MaxTxPower = AS923_MAX_TX_POWER;
+
+    // Verify the parameters and update, if necessary
+    status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
+
+    // Update channelsMask if everything is correct
+    if( status == 0x07 )
+    {
+        // Set the channels mask to a default value
+        memset1( ( uint8_t* )ChannelsMask, 0, sizeof( ChannelsMask ) );
+        // Update the channels mask
+        ChannelsMask[0] = chMask;
+    }
+
+    // Update status variables
+    *drOut = linkAdrParams.Datarate;
+    *txPowOut = linkAdrParams.TxPower;
+    *nbRepOut = linkAdrParams.NbRep;
+    *nbBytesParsed = bytesProcessed;
+
+    return status;
+}
+
+uint8_t RegionAS923RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    uint8_t status = 0x07;
+
+    // Verify radio frequency
+    if( Radio.CheckRfFrequency( rxParamSetupReq->Frequency ) == false )
+    {
+        status &= 0xFE; // Channel frequency KO
+    }
+
+    // Verify datarate
+    if( RegionCommonValueInRange( rxParamSetupReq->Datarate, AS923_RX_MIN_DATARATE, AS923_RX_MAX_DATARATE ) == false )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+
+    // Verify datarate offset
+    if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, AS923_MIN_RX1_DR_OFFSET, AS923_MAX_RX1_DR_OFFSET ) == false )
+    {
+        status &= 0xFB; // Rx1DrOffset range KO
+    }
+
+    return status;
+}
+
+uint8_t RegionAS923NewChannelReq( NewChannelReqParams_t* newChannelReq )
+{
+    uint8_t status = 0x03;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    if( newChannelReq->NewChannel->Frequency == 0 )
+    {
+        channelRemove.ChannelId = newChannelReq->ChannelId;
+
+        // Remove
+        if( RegionAS923ChannelsRemove( &channelRemove ) == false )
+        {
+            status &= 0xFC;
+        }
+    }
+    else
+    {
+        channelAdd.NewChannel = newChannelReq->NewChannel;
+        channelAdd.ChannelId = newChannelReq->ChannelId;
+
+        switch( RegionAS923ChannelAdd( &channelAdd ) )
+        {
+            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;
+            }
+        }
+    }
+
+    return status;
+}
+
+int8_t RegionAS923TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
+{
+    // Accept the request
+    return 0;
+}
+
+uint8_t RegionAS923DlChannelReq( DlChannelReqParams_t* dlChannelReq )
+{
+    uint8_t status = 0x03;
+
+    // Verify if the frequency is supported
+    if( VerifyTxFreq( dlChannelReq->Rx1Frequency ) == false )
+    {
+        status &= 0xFE;
+    }
+
+    // Verify if an uplink frequency exists
+    if( Channels[dlChannelReq->ChannelId].Frequency == 0 )
+    {
+        status &= 0xFD;
+    }
+
+    // Apply Rx1 frequency, if the status is OK
+    if( status == 0x03 )
+    {
+        Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
+    }
+
+    return status;
+}
+
+int8_t RegionAS923AlternateDr( int8_t currentDr )
+{
+    // Only AS923_DWELL_LIMIT_DATARATE is supported
+    return AS923_DWELL_LIMIT_DATARATE;
+}
+
+void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff )
+{
+    RegionCommonCalcBackOffParams_t calcBackOffParams;
+
+    calcBackOffParams.Channels = Channels;
+    calcBackOffParams.Bands = Bands;
+    calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
+    calcBackOffParams.Joined = calcBackOff->Joined;
+    calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
+    calcBackOffParams.Channel = calcBackOff->Channel;
+    calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
+    calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
+
+    RegionCommonCalcBackOff( &calcBackOffParams );
+}
+
+LoRaMacStatus_t RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    uint8_t channelNext = 0;
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTx = 0;
+    uint8_t enabledChannels[AS923_MAX_NB_CHANNELS] = { 0 };
+    TimerTime_t nextTxDelay = 0;
+
+    if( RegionCommonCountChannels( ChannelsMask, 0, 1 ) == 0 )
+    { // Reactivate default channels
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 );
+    }
+
+    if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+    {
+        // Reset Aggregated time off
+        *aggregatedTimeOff = 0;
+
+        // Update bands Time OFF
+        nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AS923_MAX_NB_BANDS );
+
+        // Search how many channels are enabled
+        nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
+                                                      ChannelsMask, Channels,
+                                                      Bands, enabledChannels, &delayTx );
+    }
+    else
+    {
+        delayTx++;
+        nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        for( uint8_t  i = 0, j = randr( 0, nbEnabledChannels - 1 ); i < AS923_MAX_NB_CHANNELS; i++ )
+        {
+            channelNext = enabledChannels[j];
+            j = ( j + 1 ) % nbEnabledChannels;
+
+            // Perform carrier sense for AS923_CARRIER_SENSE_TIME
+            // If the channel is free, we can stop the LBT mechanism
+            if( Radio.IsChannelFree( MODEM_LORA, Channels[channelNext].Frequency, AS923_RSSI_FREE_TH, AS923_CARRIER_SENSE_TIME ) == true )
+            {
+                // Free channel found
+                *channel = channelNext;
+                *time = 0;
+                return LORAMAC_STATUS_OK;
+            }
+        }
+        return LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND;
+    }
+    else
+    {
+        if( delayTx > 0 )
+        {
+            // Delay transmission due to AggregatedTimeOff or to a band time off
+            *time = nextTxDelay;
+            return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+        }
+        // Datarate not supported by any channel, restore defaults
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 );
+        *time = 0;
+        return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+    }
+}
+
+LoRaMacStatus_t RegionAS923ChannelAdd( ChannelAddParams_t* channelAdd )
+{
+    uint8_t band = 0;
+    bool drInvalid = false;
+    bool freqInvalid = false;
+    uint8_t id = channelAdd->ChannelId;
+
+    if( id >= AS923_MAX_NB_CHANNELS )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    // Validate the datarate range
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, AS923_TX_MIN_DATARATE, AS923_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
+    {
+        drInvalid = true;
+    }
+
+    // Default channels don't accept all values
+    if( id < AS923_NUMB_DEFAULT_CHANNELS )
+    {
+        // Validate the datarate range for min: must be DR_0
+        if( channelAdd->NewChannel->DrRange.Fields.Min > DR_0 )
+        {
+            drInvalid = true;
+        }
+        // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE
+        if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, DR_5, AS923_TX_MAX_DATARATE ) == false )
+        {
+            drInvalid = true;
+        }
+        // We are not allowed to change the frequency
+        if( channelAdd->NewChannel->Frequency != Channels[id].Frequency )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check frequency
+    if( freqInvalid == false )
+    {
+        if( VerifyTxFreq( channelAdd->NewChannel->Frequency ) == false )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check status
+    if( ( drInvalid == true ) && ( freqInvalid == true ) )
+    {
+        return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
+    }
+    if( drInvalid == true )
+    {
+        return LORAMAC_STATUS_DATARATE_INVALID;
+    }
+    if( freqInvalid == true )
+    {
+        return LORAMAC_STATUS_FREQUENCY_INVALID;
+    }
+
+    memcpy1( ( uint8_t* )( Channels + id ), ( uint8_t* )channelAdd->NewChannel, sizeof( Channels[id] ) );
+    Channels[id].Band = band;
+    ChannelsMask[0] |= ( 1 << id );
+    return LORAMAC_STATUS_OK;
+}
+
+bool RegionAS923ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
+{
+    uint8_t id = channelRemove->ChannelId;
+
+    if( id < AS923_NUMB_DEFAULT_CHANNELS )
+    {
+        return false;
+    }
+
+    // Remove the channel from the list of channels
+    Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
+
+    return RegionCommonChanDisable( ChannelsMask, id, AS923_MAX_NB_CHANNELS );
+}
+
+void RegionAS923SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+    int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+    uint32_t frequency = Channels[continuousWave->Channel].Frequency;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
+
+    Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
+}
+
+uint8_t RegionAS923ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    // Initialize minDr for a downlink dwell time configuration of 0
+    int8_t minDr = DR_0;
+
+    // Update the minDR for a downlink dwell time configuration of 1
+    if( downlinkDwellTime == 1 )
+    {
+        minDr = AS923_DWELL_LIMIT_DATARATE;
+    }
+
+    // Apply offset formula
+    return MIN( DR_5, MAX( minDr, dr - EffectiveRx1DrOffsetAS923[drOffset] ) );
+}
diff --git a/net/lora/node/src/mac/region/RegionAS923.h b/net/lora/node/src/mac/region/RegionAS923.h
new file mode 100644
index 000000000..3079f8256
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionAS923.h
@@ -0,0 +1,505 @@
+/*!
+ * \file      RegionAS923.h
+ *
+ * \brief     Region definition for AS923
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONAS923 Region AS923
+ *            Implementation according to LoRaWAN Specification v1.0.2.
+ * \{
+ */
+#ifndef __REGION_AS923_H__
+#define __REGION_AS923_H__
+
+#include "node/mac/LoRaMac.h"
+
+/*!
+ * LoRaMac maximum number of channels
+ */
+#define AS923_MAX_NB_CHANNELS                       16
+
+/*!
+ * Number of default channels
+ */
+#define AS923_NUMB_DEFAULT_CHANNELS                 2
+
+/*!
+ * Number of channels to apply for the CF list
+ */
+#define AS923_NUMB_CHANNELS_CF_LIST                 5
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define AS923_TX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define AS923_TX_MAX_DATARATE                       DR_7
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define AS923_RX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define AS923_RX_MAX_DATARATE                       DR_7
+
+/*!
+ * Default datarate used by the node
+ */
+#define AS923_DEFAULT_DATARATE                      DR_2
+
+/*!
+ * The minimum datarate which is used when the
+ * dwell time is limited.
+ */
+#define AS923_DWELL_LIMIT_DATARATE                  DR_2
+
+/*!
+ * Minimal Rx1 receive datarate offset
+ */
+#define AS923_MIN_RX1_DR_OFFSET                     0
+
+/*!
+ * Maximal Rx1 receive datarate offset
+ */
+#define AS923_MAX_RX1_DR_OFFSET                     7
+
+/*!
+ * Default Rx1 receive datarate offset
+ */
+#define AS923_DEFAULT_RX1_DR_OFFSET                 0
+
+/*!
+ * Minimal Tx output power that can be used by the node
+ */
+#define AS923_MIN_TX_POWER                          TX_POWER_7
+
+/*!
+ * Maximal Tx output power that can be used by the node
+ */
+#define AS923_MAX_TX_POWER                          TX_POWER_0
+
+/*!
+ * Default Tx output power used by the node
+ */
+#define AS923_DEFAULT_TX_POWER                      TX_POWER_0
+
+/*!
+ * Default uplink dwell time configuration
+ */
+#define AS923_DEFAULT_UPLINK_DWELL_TIME             1
+
+/*!
+ * Default downlink dwell time configuration
+ */
+#define AS923_DEFAULT_DOWNLINK_DWELL_TIME           1
+
+/*!
+ * Default Max EIRP
+ */
+#define AS923_DEFAULT_MAX_EIRP                      16.0f
+
+/*!
+ * Default antenna gain
+ */
+#define AS923_DEFAULT_ANTENNA_GAIN                  2.15f
+
+/*!
+ * ADR Ack limit
+ */
+#define AS923_ADR_ACK_LIMIT                         64
+
+/*!
+ * ADR Ack delay
+ */
+#define AS923_ADR_ACK_DELAY                         32
+
+/*!
+ * Enabled or disabled the duty cycle
+ */
+#define AS923_DUTY_CYCLE_ENABLED                    0
+
+/*!
+ * Maximum RX window duration
+ */
+#define AS923_MAX_RX_WINDOW                         3000
+
+/*!
+ * Receive delay 1
+ */
+#define AS923_RECEIVE_DELAY1                        1000
+
+/*!
+ * Receive delay 2
+ */
+#define AS923_RECEIVE_DELAY2                        2000
+
+/*!
+ * Join accept delay 1
+ */
+#define AS923_JOIN_ACCEPT_DELAY1                    5000
+
+/*!
+ * Join accept delay 2
+ */
+#define AS923_JOIN_ACCEPT_DELAY2                    6000
+
+/*!
+ * Maximum frame counter gap
+ */
+#define AS923_MAX_FCNT_GAP                          16384
+
+/*!
+ * Ack timeout
+ */
+#define AS923_ACKTIMEOUT                            2000
+
+/*!
+ * Random ack timeout limits
+ */
+#define AS923_ACK_TIMEOUT_RND                       1000
+
+#if ( AS923_DEFAULT_DATARATE > DR_5 )
+#error "A default DR higher than DR_5 may lead to connectivity loss."
+#endif
+
+/*!
+ * Second reception window channel frequency definition.
+ */
+#define AS923_RX_WND_2_FREQ                         923200000
+
+/*!
+ * Second reception window channel datarate definition.
+ */
+#define AS923_RX_WND_2_DR                           DR_2
+
+/*!
+ * Maximum number of bands
+ */
+#define AS923_MAX_NB_BANDS                          1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define AS923_BAND0                                 { 100, AS923_MAX_TX_POWER, 0, 0, 0 } //  1.0 %
+
+/*!
+ * LoRaMac default channel 1
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define AS923_LC1                                   { 923200000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac default channel 2
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define AS923_LC2                                   { 923400000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac channels which are allowed for the join procedure
+ */
+#define AS923_JOIN_CHANNELS                         ( uint16_t )( LC( 1 ) | LC( 2 ) )
+
+/*!
+ * RSSI threshold for a free channel [dBm]
+ */
+#define AS923_RSSI_FREE_TH                          -85
+
+/*!
+ * Specifies the time the node performs a carrier sense
+ */
+#define AS923_CARRIER_SENSE_TIME                    6
+
+/*!
+ * Data rates table definition
+ */
+static const uint8_t DataratesAS923[]  = { 12, 11, 10,  9,  8,  7, 7, 50 };
+
+/*!
+ * Bandwidths table definition in Hz
+ */
+static const uint32_t BandwidthsAS923[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ * The table is valid for the dwell time configuration of 0 for uplinks and downlinks.
+ */
+static const uint8_t MaxPayloadOfDatarateDwell0AS923[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with repeater.
+ * The table is valid for the dwell time configuration of 0 for uplinks and downlinks. The table provides
+ * repeater support.
+ */
+static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AS923[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with and without repeater.
+ * The table proides repeater support. The table is only valid for uplinks.
+ */
+static const uint8_t MaxPayloadOfDatarateDwell1UpAS923[] = { 0, 0, 11, 53, 125, 242, 242, 242 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with and without repeater.
+ * The table proides repeater support. The table is only valid for downlinks.
+ */
+static const uint8_t MaxPayloadOfDatarateDwell1DownAS923[] = { 0, 0, 11, 53, 126, 242, 242, 242 };
+
+/*!
+ * Effective datarate offsets for receive window 1.
+ */
+static const int8_t EffectiveRx1DrOffsetAS923[] = { 0, 1, 2, 3, 4, 5, -1, -2 };
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionAS923SetBandTxDone( SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionAS923InitDefaults( InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionAS923Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionAS923ApplyCFList( ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionAS923ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionAS923AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * Computes the Rx window timeout and offset.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionAS923ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionAS923TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAS923LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAS923RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a Channel Request.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAS923NewChannelReq( NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall not process the command.
+ */
+int8_t RegionAS923TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAS923DlChannelReq( DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionAS923AlternateDr( int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
+ */
+LoRaMacStatus_t RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionAS923ChannelAdd( ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionAS923ChannelsRemove( ChannelRemoveParams_t* channelRemove  );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionAS923SetContinuousWave( ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionAS923ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGIONAS923 */
+
+#endif // __REGION_AS923_H__
diff --git a/net/lora/node/src/mac/region/RegionAU915.c b/net/lora/node/src/mac/region/RegionAU915.c
new file mode 100644
index 000000000..f1ff4f6b8
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionAU915.c
@@ -0,0 +1,854 @@
+/*!
+ * \file      RegionAU915.c
+ *
+ * \brief     Region implementation for AU915
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+#include "RegionCommon.h"
+#include "RegionAU915.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              6
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[AU915_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[AU915_MAX_NB_BANDS] =
+{
+    AU915_BAND0
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels remaining
+ */
+static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsAU915[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < AU915_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            phyParam.Value = AU915_RX_MIN_DATARATE;
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            phyParam.Value = AU915_TX_MIN_DATARATE;
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = AU915_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, AU915_TX_MIN_DATARATE );
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = AU915_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            phyParam.Value = MaxPayloadOfDatarateAU915[getPhy->Datarate];
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            phyParam.Value = MaxPayloadOfDatarateRepeaterAU915[getPhy->Datarate];
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = AU915_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = AU915_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = AU915_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = AU915_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = AU915_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = AU915_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = AU915_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( AU915_ACKTIMEOUT + randr( -AU915_ACK_TIMEOUT_RND, AU915_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = AU915_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = AU915_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = AU915_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = AU915_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = 0;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = AU915_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionAU915InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            // 125 kHz channels
+            for( uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++ )
+            {
+                Channels[i].Frequency = 915200000 + i * 200000;
+                Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
+                Channels[i].Band = 0;
+            }
+            // 500 kHz channels
+            for( uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++ )
+            {
+                Channels[i].Frequency = 915900000 + ( i - ( AU915_MAX_NB_CHANNELS - 8 ) ) * 1600000;
+                Channels[i].DrRange.Value = ( DR_6 << 4 ) | DR_6;
+                Channels[i].Band = 0;
+            }
+
+            // Initialize channels default mask
+            ChannelsDefaultMask[0] = 0xFFFF;
+            ChannelsDefaultMask[1] = 0xFFFF;
+            ChannelsDefaultMask[2] = 0xFFFF;
+            ChannelsDefaultMask[3] = 0xFFFF;
+            ChannelsDefaultMask[4] = 0x00FF;
+            ChannelsDefaultMask[5] = 0x0000;
+
+            // Copy channels default mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+
+            // Copy into channels mask remaining
+            RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 6 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Copy channels default mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+
+            for( uint8_t i = 0; i < 6; i++ )
+            { // Copy-And the channels mask
+                ChannelsMaskRemaining[i] &= ChannelsMask[i];
+            }
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Copy channels default mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+
+            // Copy into channels mask remaining
+            RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 6 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE );
+        }
+        case PHY_RX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return AU915_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    return;
+}
+
+bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    uint8_t nbChannels = RegionCommonCountChannels( chanMaskSet->ChannelsMaskIn, 0, 4 );
+
+    // Check the number of active channels
+    // According to ACMA regulation, we require at least 20 125KHz channels, if
+    // the node shall utilize 125KHz channels.
+    if( ( nbChannels < 20 ) &&
+        ( nbChannels > 0 ) )
+    {
+        return false;
+    }
+
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
+
+            for( uint8_t i = 0; i < 6; i++ )
+            { // Copy-And the channels mask
+                ChannelsMaskRemaining[i] &= ChannelsMask[i];
+            }
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == AU915_TX_MIN_DATARATE )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= AU915_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = AU915_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( AU915_ADR_ACK_LIMIT + AU915_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % AU915_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionAU915GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == AU915_TX_MIN_DATARATE )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] = 0xFFFF;
+                            ChannelsMask[1] = 0xFFFF;
+                            ChannelsMask[2] = 0xFFFF;
+                            ChannelsMask[3] = 0xFFFF;
+                            ChannelsMask[4] = 0x00FF;
+                            ChannelsMask[5] = 0x0000;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, AU915_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesAU915[rxConfigParams->Datarate], BandwidthsAU915[rxConfigParams->Datarate] );
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = AU915_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * AU915_STEPWIDTH_RX1_CHANNEL;
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesAU915[dr];
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterAU915[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateAU915[dr];
+    }
+    Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    int8_t phyDr = DataratesAU915[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
+
+    *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
+    *txPower = txPowerLimited;
+
+    return true;
+}
+
+uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    // Initialize local copy of channels mask
+    RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        if( linkAdrParams.ChMaskCtrl == 6 )
+        {
+            // Enable all 125 kHz channels
+            channelsMask[0] = 0xFFFF;
+            channelsMask[1] = 0xFFFF;
+            channelsMask[2] = 0xFFFF;
+            channelsMask[3] = 0xFFFF;
+            // Apply chMask to channels 64 to 71
+            channelsMask[4] = linkAdrParams.ChMask;
+        }
+        else if( linkAdrParams.ChMaskCtrl == 7 )
+        {
+            // Disable all 125 kHz channels
+            channelsMask[0] = 0x0000;
+            channelsMask[1] = 0x0000;
+            channelsMask[2] = 0x0000;
+            channelsMask[3] = 0x0000;
+            // Apply chMask to channels 64 to 71
+            channelsMask[4] = linkAdrParams.ChMask;
+        }
+        else if( linkAdrParams.ChMaskCtrl == 5 )
+        {
+            // RFU
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
+        }
+    }
+
+    // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
+    if( ( linkAdrParams.Datarate < DR_6 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
+    {
+        status &= 0xFE; // Channel mask KO
+    }
+
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
+    phyParam = RegionAU915GetPhyParam( &getPhy );
+
+    linkAdrVerifyParams.Status = status;
+    linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
+    linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
+    linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
+    linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
+    linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
+    linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
+    linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
+    linkAdrVerifyParams.NbChannels = AU915_MAX_NB_CHANNELS;
+    linkAdrVerifyParams.ChannelsMask = channelsMask;
+    linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
+    linkAdrVerifyParams.MaxDatarate = AU915_TX_MAX_DATARATE;
+    linkAdrVerifyParams.Channels = Channels;
+    linkAdrVerifyParams.MinTxPower = AU915_MIN_TX_POWER;
+    linkAdrVerifyParams.MaxTxPower = AU915_MAX_TX_POWER;
+
+    // Verify the parameters and update, if necessary
+    status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
+
+    // Update channelsMask if everything is correct
+    if( status == 0x07 )
+    {
+        // Copy Mask
+        RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
+
+        ChannelsMaskRemaining[0] &= ChannelsMask[0];
+        ChannelsMaskRemaining[1] &= ChannelsMask[1];
+        ChannelsMaskRemaining[2] &= ChannelsMask[2];
+        ChannelsMaskRemaining[3] &= ChannelsMask[3];
+        ChannelsMaskRemaining[4] = ChannelsMask[4];
+        ChannelsMaskRemaining[5] = ChannelsMask[5];
+    }
+
+    // Update status variables
+    *drOut = linkAdrParams.Datarate;
+    *txPowOut = linkAdrParams.TxPower;
+    *nbRepOut = linkAdrParams.NbRep;
+    *nbBytesParsed = bytesProcessed;
+
+    return status;
+}
+
+uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    uint8_t status = 0x07;
+    uint32_t freq = rxParamSetupReq->Frequency;
+
+    // Verify radio frequency
+    if( ( Radio.CheckRfFrequency( freq ) == false ) ||
+        ( freq < AU915_FIRST_RX1_CHANNEL ) ||
+        ( freq > AU915_LAST_RX1_CHANNEL ) ||
+        ( ( ( freq - ( uint32_t ) AU915_FIRST_RX1_CHANNEL ) % ( uint32_t ) AU915_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
+    {
+        status &= 0xFE; // Channel frequency KO
+    }
+
+    // Verify datarate
+    if( RegionCommonValueInRange( rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE ) == false )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+    if( ( rxParamSetupReq->Datarate == DR_7 ) ||
+        ( rxParamSetupReq->Datarate > DR_13 ) )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+
+    // Verify datarate offset
+    if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET ) == false )
+    {
+        status &= 0xFB; // Rx1DrOffset range KO
+    }
+
+    return status;
+}
+
+uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq )
+{
+    // Datarate and frequency KO
+    return 0;
+}
+
+int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
+{
+    return -1;
+}
+
+uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq )
+{
+    return 0;
+}
+
+int8_t RegionAU915AlternateDr( int8_t currentDr )
+{
+    static int8_t trialsCount = 0;
+
+    // Re-enable 500 kHz default channels
+    ChannelsMask[4] = 0x00FF;
+
+    if( ( trialsCount & 0x01 ) == 0x01 )
+    {
+        currentDr = DR_6;
+    }
+    else
+    {
+        currentDr = DR_0;
+    }
+    trialsCount++;
+    return currentDr;
+}
+
+void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff )
+{
+    RegionCommonCalcBackOffParams_t calcBackOffParams;
+
+    calcBackOffParams.Channels = Channels;
+    calcBackOffParams.Bands = Bands;
+    calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
+    calcBackOffParams.Joined = calcBackOff->Joined;
+    calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
+    calcBackOffParams.Channel = calcBackOff->Channel;
+    calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
+    calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
+
+    RegionCommonCalcBackOff( &calcBackOffParams );
+}
+
+LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTx = 0;
+    uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = { 0 };
+    TimerTime_t nextTxDelay = 0;
+
+    // Count 125kHz channels
+    if( RegionCommonCountChannels( ChannelsMaskRemaining, 0, 4 ) == 0 )
+    { // Reactivate default channels
+        RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 4  );
+    }
+    // Check other channels
+    if( nextChanParams->Datarate >= DR_6 )
+    {
+        if( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 )
+        {
+            ChannelsMaskRemaining[4] = ChannelsMask[4];
+        }
+    }
+
+    if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+    {
+        // Reset Aggregated time off
+        *aggregatedTimeOff = 0;
+
+        // Update bands Time OFF
+        nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, AU915_MAX_NB_BANDS );
+
+        // Search how many channels are enabled
+        nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
+                                                      ChannelsMaskRemaining, Channels,
+                                                      Bands, enabledChannels, &delayTx );
+    }
+    else
+    {
+        delayTx++;
+        nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        // We found a valid channel
+        *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+        // Disable the channel in the mask
+        RegionCommonChanDisable( ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS - 8 );
+
+        *time = 0;
+        return LORAMAC_STATUS_OK;
+    }
+    else
+    {
+        if( delayTx > 0 )
+        {
+            // Delay transmission due to AggregatedTimeOff or to a band time off
+            *time = nextTxDelay;
+            return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+        }
+        // Datarate not supported by any channel
+        *time = 0;
+        return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+    }
+}
+
+LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd )
+{
+    return LORAMAC_STATUS_PARAMETER_INVALID;
+}
+
+bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
+{
+    return LORAMAC_STATUS_PARAMETER_INVALID;
+}
+
+void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+    int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+    uint32_t frequency = Channels[continuousWave->Channel].Frequency;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
+
+    Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
+}
+
+uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    int8_t datarate = DatarateOffsetsAU915[dr][drOffset];
+
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+    return datarate;
+}
diff --git a/net/lora/node/src/mac/region/RegionAU915.h b/net/lora/node/src/mac/region/RegionAU915.h
new file mode 100644
index 000000000..789e4665a
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionAU915.h
@@ -0,0 +1,457 @@
+/*!
+ * \file      RegionAU915.h
+ *
+ * \brief     Region definition for AU915
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONAU915 Region AU915
+ *            Implementation according to LoRaWAN Specification v1.0.2.
+ * \{
+ */
+#ifndef __REGION_AU915_H__
+#define __REGION_AU915_H__
+
+#include "node/mac/LoRaMac.h"
+
+/*!
+ * LoRaMac maximum number of channels
+ */
+#define AU915_MAX_NB_CHANNELS                       72
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define AU915_TX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define AU915_TX_MAX_DATARATE                       DR_6
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define AU915_RX_MIN_DATARATE                       DR_8
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define AU915_RX_MAX_DATARATE                       DR_13
+
+/*!
+ * Default datarate used by the node
+ */
+#define AU915_DEFAULT_DATARATE                      DR_0
+
+/*!
+ * Minimal Rx1 receive datarate offset
+ */
+#define AU915_MIN_RX1_DR_OFFSET                     0
+
+/*!
+ * Maximal Rx1 receive datarate offset
+ */
+#define AU915_MAX_RX1_DR_OFFSET                     6
+
+/*!
+ * Default Rx1 receive datarate offset
+ */
+#define AU915_DEFAULT_RX1_DR_OFFSET                 0
+
+/*!
+ * Minimal Tx output power that can be used by the node
+ */
+#define AU915_MIN_TX_POWER                          TX_POWER_10
+
+/*!
+ * Maximal Tx output power that can be used by the node
+ */
+#define AU915_MAX_TX_POWER                          TX_POWER_0
+
+/*!
+ * Default Tx output power used by the node
+ */
+#define AU915_DEFAULT_TX_POWER                      TX_POWER_0
+
+/*!
+ * Default Max EIRP
+ */
+#define AU915_DEFAULT_MAX_EIRP                      30.0f
+
+/*!
+ * Default antenna gain
+ */
+#define AU915_DEFAULT_ANTENNA_GAIN                  2.15f
+
+/*!
+ * ADR Ack limit
+ */
+#define AU915_ADR_ACK_LIMIT                         64
+
+/*!
+ * ADR Ack delay
+ */
+#define AU915_ADR_ACK_DELAY                         32
+
+/*!
+ * Enabled or disabled the duty cycle
+ */
+#define AU915_DUTY_CYCLE_ENABLED                    0
+
+/*!
+ * Maximum RX window duration
+ */
+#define AU915_MAX_RX_WINDOW                         3000
+
+/*!
+ * Receive delay 1
+ */
+#define AU915_RECEIVE_DELAY1                        1000
+
+/*!
+ * Receive delay 2
+ */
+#define AU915_RECEIVE_DELAY2                        2000
+
+/*!
+ * Join accept delay 1
+ */
+#define AU915_JOIN_ACCEPT_DELAY1                    5000
+
+/*!
+ * Join accept delay 2
+ */
+#define AU915_JOIN_ACCEPT_DELAY2                    6000
+
+/*!
+ * Maximum frame counter gap
+ */
+#define AU915_MAX_FCNT_GAP                          16384
+
+/*!
+ * Ack timeout
+ */
+#define AU915_ACKTIMEOUT                            2000
+
+/*!
+ * Random ack timeout limits
+ */
+#define AU915_ACK_TIMEOUT_RND                       1000
+
+/*!
+ * Second reception window channel frequency definition.
+ */
+#define AU915_RX_WND_2_FREQ                         923300000
+
+/*!
+ * Second reception window channel datarate definition.
+ */
+#define AU915_RX_WND_2_DR                           DR_8
+
+/*!
+ * LoRaMac maximum number of bands
+ */
+#define AU915_MAX_NB_BANDS                           1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define AU915_BAND0                                 { 1, AU915_MAX_TX_POWER, 0, 0, 0 } //  100.0 %
+
+/*!
+ * Defines the first channel for RX window 1 for US band
+ */
+#define AU915_FIRST_RX1_CHANNEL                     ( (uint32_t) 923300000 )
+
+/*!
+ * Defines the last channel for RX window 1 for US band
+ */
+#define AU915_LAST_RX1_CHANNEL                      ( (uint32_t) 927500000 )
+
+/*!
+ * Defines the step width of the channels for RX window 1
+ */
+#define AU915_STEPWIDTH_RX1_CHANNEL                 ( (uint32_t) 600000 )
+
+/*!
+ * Data rates table definition
+ */
+static const uint8_t DataratesAU915[]  = { 12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
+
+/*!
+ * Bandwidths table definition in Hz
+ */
+static const uint32_t BandwidthsAU915[] = { 125000, 125000, 125000, 125000, 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 };
+
+/*!
+ * Up/Down link data rates offset definition
+ */
+static const int8_t DatarateOffsetsAU915[7][6] =
+{
+    { DR_8 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8  }, // DR_0
+    { DR_9 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8  }, // DR_1
+    { DR_10, DR_9 , DR_8 , DR_8 , DR_8 , DR_8  }, // DR_2
+    { DR_11, DR_10, DR_9 , DR_8 , DR_8 , DR_8  }, // DR_3
+    { DR_12, DR_11, DR_10, DR_9 , DR_8 , DR_8  }, // DR_4
+    { DR_13, DR_12, DR_11, DR_10, DR_9 , DR_8  }, // DR_5
+    { DR_13, DR_13, DR_12, DR_11, DR_10, DR_9  }, // DR_6
+};
+
+/*!
+ * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateAU915[] = { 51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateRepeaterAU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionAU915InitDefaults( InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * Computes the Rx window timeout and offset.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a Channel Request.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall not process the command.
+ */
+int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionAU915AlternateDr( int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
+ */
+LoRaMacStatus_t RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove  );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGIONAU915 */
+
+#endif // __REGION_AU915_H__
diff --git a/net/lora/node/src/mac/region/RegionCN470.c b/net/lora/node/src/mac/region/RegionCN470.c
new file mode 100644
index 000000000..21f38c26c
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCN470.c
@@ -0,0 +1,774 @@
+/*!
+ * \file      RegionCN470.c
+ *
+ * \brief     Region implementation for CN470
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+#include "RegionCommon.h"
+#include "RegionCN470.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              6
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[CN470_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[CN470_MAX_NB_BANDS] =
+{
+    CN470_BAND0
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsCN470[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < CN470_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            phyParam.Value = CN470_RX_MIN_DATARATE;
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            phyParam.Value = CN470_TX_MIN_DATARATE;
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = CN470_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, CN470_TX_MIN_DATARATE );
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = CN470_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            phyParam.Value = MaxPayloadOfDatarateCN470[getPhy->Datarate];
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            phyParam.Value = MaxPayloadOfDatarateRepeaterCN470[getPhy->Datarate];
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = CN470_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = CN470_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = CN470_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = CN470_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = CN470_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = CN470_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = CN470_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( CN470_ACKTIMEOUT + randr( -CN470_ACK_TIMEOUT_RND, CN470_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = CN470_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = CN470_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = CN470_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = CN470_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = 0;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = CN470_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = CN470_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionCN470InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            // 125 kHz channels
+            for( uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++ )
+            {
+                Channels[i].Frequency = 470300000 + i * 200000;
+                Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
+                Channels[i].Band = 0;
+            }
+
+            // Initialize the channels default mask
+            ChannelsDefaultMask[0] = 0xFFFF;
+            ChannelsDefaultMask[1] = 0xFFFF;
+            ChannelsDefaultMask[2] = 0xFFFF;
+            ChannelsDefaultMask[3] = 0xFFFF;
+            ChannelsDefaultMask[4] = 0xFFFF;
+            ChannelsDefaultMask[5] = 0xFFFF;
+
+            // Update the channels mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Restore channels default mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Update the channels mask defaults
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN470_TX_MIN_DATARATE, CN470_TX_MAX_DATARATE );
+        }
+        case PHY_RX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, CN470_MAX_TX_POWER, CN470_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return CN470_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionCN470ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    return;
+}
+
+bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == CN470_TX_MIN_DATARATE )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= CN470_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = CN470_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( CN470_ADR_ACK_LIMIT + CN470_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % CN470_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionCN470GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == CN470_TX_MIN_DATARATE )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] = 0xFFFF;
+                            ChannelsMask[1] = 0xFFFF;
+                            ChannelsMask[2] = 0xFFFF;
+                            ChannelsMask[3] = 0xFFFF;
+                            ChannelsMask[4] = 0xFFFF;
+                            ChannelsMask[5] = 0xFFFF;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, CN470_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesCN470[rxConfigParams->Datarate], BandwidthsCN470[rxConfigParams->Datarate] );
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = CN470_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 48 ) * CN470_STEPWIDTH_RX1_CHANNEL;
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesCN470[dr];
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterCN470[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateCN470[dr];
+    }
+    Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    int8_t phyDr = DataratesCN470[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
+    // Get the time-on-air of the next tx frame
+    *txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
+    *txPower = txPowerLimited;
+
+    return true;
+}
+
+uint8_t RegionCN470LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    // Initialize local copy of channels mask
+    RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        // Get ADR request parameters
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        if( linkAdrParams.ChMaskCtrl == 6 )
+        {
+            // Enable all 125 kHz channels
+            channelsMask[0] = 0xFFFF;
+            channelsMask[1] = 0xFFFF;
+            channelsMask[2] = 0xFFFF;
+            channelsMask[3] = 0xFFFF;
+            channelsMask[4] = 0xFFFF;
+            channelsMask[5] = 0xFFFF;
+        }
+        else if( linkAdrParams.ChMaskCtrl == 7 )
+        {
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            for( uint8_t i = 0; i < 16; i++ )
+            {
+                if( ( ( linkAdrParams.ChMask & ( 1 << i ) ) != 0 ) &&
+                    ( Channels[linkAdrParams.ChMaskCtrl * 16 + i].Frequency == 0 ) )
+                {// Trying to enable an undefined channel
+                    status &= 0xFE; // Channel mask KO
+                }
+            }
+            channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
+        }
+    }
+
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
+    phyParam = RegionCN470GetPhyParam( &getPhy );
+
+    linkAdrVerifyParams.Status = status;
+    linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
+    linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
+    linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
+    linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
+    linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
+    linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
+    linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
+    linkAdrVerifyParams.NbChannels = CN470_MAX_NB_CHANNELS;
+    linkAdrVerifyParams.ChannelsMask = channelsMask;
+    linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
+    linkAdrVerifyParams.MaxDatarate = CN470_TX_MAX_DATARATE;
+    linkAdrVerifyParams.Channels = Channels;
+    linkAdrVerifyParams.MinTxPower = CN470_MIN_TX_POWER;
+    linkAdrVerifyParams.MaxTxPower = CN470_MAX_TX_POWER;
+
+    // Verify the parameters and update, if necessary
+    status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
+
+    // Update channelsMask if everything is correct
+    if( status == 0x07 )
+    {
+        // Copy Mask
+        RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
+    }
+
+    // Update status variables
+    *drOut = linkAdrParams.Datarate;
+    *txPowOut = linkAdrParams.TxPower;
+    *nbRepOut = linkAdrParams.NbRep;
+    *nbBytesParsed = bytesProcessed;
+
+    return status;
+}
+
+uint8_t RegionCN470RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    uint8_t status = 0x07;
+    uint32_t freq = rxParamSetupReq->Frequency;
+
+    // Verify radio frequency
+    if( ( Radio.CheckRfFrequency( freq ) == false ) ||
+        ( freq < CN470_FIRST_RX1_CHANNEL ) ||
+        ( freq > CN470_LAST_RX1_CHANNEL ) ||
+        ( ( ( freq - ( uint32_t ) CN470_FIRST_RX1_CHANNEL ) % ( uint32_t ) CN470_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
+    {
+        status &= 0xFE; // Channel frequency KO
+    }
+
+    // Verify datarate
+    if( RegionCommonValueInRange( rxParamSetupReq->Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE ) == false )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+
+    // Verify datarate offset
+    if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET ) == false )
+    {
+        status &= 0xFB; // Rx1DrOffset range KO
+    }
+
+    return status;
+}
+
+uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq )
+{
+    // Datarate and frequency KO
+    return 0;
+}
+
+int8_t RegionCN470TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
+{
+    return -1;
+}
+
+uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq )
+{
+    return 0;
+}
+
+int8_t RegionCN470AlternateDr( int8_t currentDr )
+{
+    return currentDr;
+}
+
+void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff )
+{
+    RegionCommonCalcBackOffParams_t calcBackOffParams;
+
+    calcBackOffParams.Channels = Channels;
+    calcBackOffParams.Bands = Bands;
+    calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
+    calcBackOffParams.Joined = calcBackOff->Joined;
+    calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
+    calcBackOffParams.Channel = calcBackOff->Channel;
+    calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
+    calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
+
+    RegionCommonCalcBackOff( &calcBackOffParams );
+}
+
+LoRaMacStatus_t RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTx = 0;
+    uint8_t enabledChannels[CN470_MAX_NB_CHANNELS] = { 0 };
+    TimerTime_t nextTxDelay = 0;
+
+    // Count 125kHz channels
+    if( RegionCommonCountChannels( ChannelsMask, 0, 6 ) == 0 )
+    { // Reactivate default channels
+        ChannelsMask[0] = 0xFFFF;
+        ChannelsMask[1] = 0xFFFF;
+        ChannelsMask[2] = 0xFFFF;
+        ChannelsMask[3] = 0xFFFF;
+        ChannelsMask[4] = 0xFFFF;
+        ChannelsMask[5] = 0xFFFF;
+    }
+
+    if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+    {
+        // Reset Aggregated time off
+        *aggregatedTimeOff = 0;
+
+        // Update bands Time OFF
+        nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN470_MAX_NB_BANDS );
+
+        // Search how many channels are enabled
+        nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
+                                                      ChannelsMask, Channels,
+                                                      Bands, enabledChannels, &delayTx );
+    }
+    else
+    {
+        delayTx++;
+        nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        // We found a valid channel
+        *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+
+        *time = 0;
+        return LORAMAC_STATUS_OK;
+    }
+    else
+    {
+        if( delayTx > 0 )
+        {
+            // Delay transmission due to AggregatedTimeOff or to a band time off
+            *time = nextTxDelay;
+            return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+        }
+        // Datarate not supported by any channel
+        *time = 0;
+        return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+    }
+}
+
+LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd )
+{
+    return LORAMAC_STATUS_PARAMETER_INVALID;
+}
+
+bool RegionCN470ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
+{
+    return LORAMAC_STATUS_PARAMETER_INVALID;
+}
+
+void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+    int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+    uint32_t frequency = Channels[continuousWave->Channel].Frequency;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
+
+    Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
+}
+
+uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    int8_t datarate = dr - drOffset;
+
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+    return datarate;
+}
diff --git a/net/lora/node/src/mac/region/RegionCN470.h b/net/lora/node/src/mac/region/RegionCN470.h
new file mode 100644
index 000000000..f77df5a5b
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCN470.h
@@ -0,0 +1,443 @@
+/*!
+ * \file      RegionCN470.h
+ *
+ * \brief     Region definition for CN470
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONCN470 Region CN470
+ *            Implementation according to LoRaWAN Specification v1.0.2.
+ * \{
+ */
+#ifndef __REGION_CN470_H__
+#define __REGION_CN470_H__
+
+#include "node/mac/LoRaMac.h"
+
+/*!
+ * LoRaMac maximum number of channels
+ */
+#define CN470_MAX_NB_CHANNELS                        96
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define CN470_TX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define CN470_TX_MAX_DATARATE                       DR_5
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define CN470_RX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define CN470_RX_MAX_DATARATE                       DR_5
+
+/*!
+ * Default datarate used by the node
+ */
+#define CN470_DEFAULT_DATARATE                      DR_0
+
+/*!
+ * Minimal Rx1 receive datarate offset
+ */
+#define CN470_MIN_RX1_DR_OFFSET                     0
+
+/*!
+ * Maximal Rx1 receive datarate offset
+ */
+#define CN470_MAX_RX1_DR_OFFSET                     3
+
+/*!
+ * Default Rx1 receive datarate offset
+ */
+#define CN470_DEFAULT_RX1_DR_OFFSET                 0
+
+/*!
+ * Minimal Tx output power that can be used by the node
+ */
+#define CN470_MIN_TX_POWER                        TX_POWER_7
+
+/*!
+ * Maximal Tx output power that can be used by the node
+ */
+#define CN470_MAX_TX_POWER                        TX_POWER_0
+
+/*!
+ * Default Tx output power used by the node
+ */
+#define CN470_DEFAULT_TX_POWER                    TX_POWER_0
+
+/*!
+ * Default Max EIRP
+ */
+#define CN470_DEFAULT_MAX_EIRP                      19.15f
+
+/*!
+ * Default antenna gain
+ */
+#define CN470_DEFAULT_ANTENNA_GAIN                  2.15f
+
+/*!
+ * ADR Ack limit
+ */
+#define CN470_ADR_ACK_LIMIT                         64
+
+/*!
+ * ADR Ack delay
+ */
+#define CN470_ADR_ACK_DELAY                         32
+
+/*!
+ * Enabled or disabled the duty cycle
+ */
+#define CN470_DUTY_CYCLE_ENABLED                    0
+
+/*!
+ * Maximum RX window duration
+ */
+#define CN470_MAX_RX_WINDOW                         3000
+
+/*!
+ * Receive delay 1
+ */
+#define CN470_RECEIVE_DELAY1                        1000
+
+/*!
+ * Receive delay 2
+ */
+#define CN470_RECEIVE_DELAY2                        2000
+
+/*!
+ * Join accept delay 1
+ */
+#define CN470_JOIN_ACCEPT_DELAY1                    5000
+
+/*!
+ * Join accept delay 2
+ */
+#define CN470_JOIN_ACCEPT_DELAY2                    6000
+
+/*!
+ * Maximum frame counter gap
+ */
+#define CN470_MAX_FCNT_GAP                          16384
+
+/*!
+ * Ack timeout
+ */
+#define CN470_ACKTIMEOUT                            2000
+
+/*!
+ * Random ack timeout limits
+ */
+#define CN470_ACK_TIMEOUT_RND                       1000
+
+/*!
+ * Second reception window channel frequency definition.
+ */
+#define CN470_RX_WND_2_FREQ                         505300000
+
+/*!
+ * Second reception window channel datarate definition.
+ */
+#define CN470_RX_WND_2_DR                           DR_0
+
+/*!
+ * LoRaMac maximum number of bands
+ */
+#define CN470_MAX_NB_BANDS                           1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define CN470_BAND0                                 { 1, CN470_MAX_TX_POWER, 0, 0, 0 } //  100.0 %
+
+/*!
+ * Defines the first channel for RX window 1 for CN470 band
+ */
+#define CN470_FIRST_RX1_CHANNEL                     ( (uint32_t) 500300000 )
+
+/*!
+ * Defines the last channel for RX window 1 for CN470 band
+ */
+#define CN470_LAST_RX1_CHANNEL                      ( (uint32_t) 509700000 )
+
+/*!
+ * Defines the step width of the channels for RX window 1
+ */
+#define CN470_STEPWIDTH_RX1_CHANNEL                 ( (uint32_t) 200000 )
+
+/*!
+ * Data rates table definition
+ */
+static const uint8_t DataratesCN470[]  = { 12, 11, 10,  9,  8,  7 };
+
+/*!
+ * Bandwidths table definition in Hz
+ */
+static const uint32_t BandwidthsCN470[] = { 125000, 125000, 125000, 125000, 125000, 125000 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateCN470[] = { 51, 51, 51, 115, 222, 222 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateRepeaterCN470[] = { 51, 51, 51, 115, 222, 222 };
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionCN470InitDefaults( InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionCN470ApplyCFList( ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * Computes the Rx window timeout and offset.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN470LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN470RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a Channel Request.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall not process the command.
+ */
+int8_t RegionCN470TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionCN470AlternateDr( int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
+ */
+LoRaMacStatus_t RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionCN470ChannelsRemove( ChannelRemoveParams_t* channelRemove  );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGIONCN470 */
+
+#endif // __REGION_CN470_H__
diff --git a/net/lora/node/src/mac/region/RegionCN779.c b/net/lora/node/src/mac/region/RegionCN779.c
new file mode 100644
index 000000000..cf29997a1
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCN779.c
@@ -0,0 +1,1013 @@
+/*!
+ * \file      RegionCN779.c
+ *
+ * \brief     Region implementation for CN779
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+
+#include "RegionCommon.h"
+#include "RegionCN779.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              1
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[CN779_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[CN779_MAX_NB_BANDS] =
+{
+    CN779_BAND0
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsCN779[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static bool VerifyTxFreq( uint32_t freq )
+{
+    // Check radio driver support
+    if( Radio.CheckRfFrequency( freq ) == false )
+    {
+        return false;
+    }
+
+    if( ( freq < 779500000 ) || ( freq > 786500000 ) )
+    {
+        return false;
+    }
+    return true;
+}
+
+static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < CN779_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( joined == false )
+                {
+                    if( ( CN779_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
+                    {
+                        continue;
+                    }
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            phyParam.Value = CN779_RX_MIN_DATARATE;
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            phyParam.Value = CN779_TX_MIN_DATARATE;
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = CN779_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, CN779_TX_MIN_DATARATE );
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = CN779_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            phyParam.Value = MaxPayloadOfDatarateCN779[getPhy->Datarate];
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            phyParam.Value = MaxPayloadOfDatarateRepeaterCN779[getPhy->Datarate];
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = CN779_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = CN779_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = CN779_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = CN779_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = CN779_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = CN779_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = CN779_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( CN779_ACKTIMEOUT + randr( -CN779_ACK_TIMEOUT_RND, CN779_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = CN779_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = CN779_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = CN779_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = CN779_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = 0;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = CN779_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = CN779_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionCN779SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionCN779InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            Channels[0] = ( ChannelParams_t ) CN779_LC1;
+            Channels[1] = ( ChannelParams_t ) CN779_LC2;
+            Channels[2] = ( ChannelParams_t ) CN779_LC3;
+
+            // Initialize the channels default mask
+            ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+            // Update the channels mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Restore channels default mask
+            ChannelsMask[0] |= ChannelsDefaultMask[0];
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Update the channels mask defaults
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionCN779Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
+        }
+        case PHY_RX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, CN779_MAX_TX_POWER, CN779_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return CN779_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionCN779ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    ChannelParams_t newChannel;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    // Setup default datarate range
+    newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
+
+    // Size of the optional CF list
+    if( applyCFList->Size != 16 )
+    {
+        return;
+    }
+
+    // Last byte is RFU, don't take it into account
+    for( uint8_t i = 0, chanIdx = CN779_NUMB_DEFAULT_CHANNELS; chanIdx < CN779_MAX_NB_CHANNELS; i+=3, chanIdx++ )
+    {
+        if( chanIdx < ( CN779_NUMB_CHANNELS_CF_LIST + CN779_NUMB_DEFAULT_CHANNELS ) )
+        {
+            // Channel frequency
+            newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
+            newChannel.Frequency *= 100;
+
+            // Initialize alternative frequency to 0
+            newChannel.Rx1Frequency = 0;
+        }
+        else
+        {
+            newChannel.Frequency = 0;
+            newChannel.DrRange.Value = 0;
+            newChannel.Rx1Frequency = 0;
+        }
+
+        if( newChannel.Frequency != 0 )
+        {
+            channelAdd.NewChannel = &newChannel;
+            channelAdd.ChannelId = chanIdx;
+
+            // Try to add all channels
+            RegionCN779ChannelAdd( &channelAdd );
+        }
+        else
+        {
+            channelRemove.ChannelId = chanIdx;
+
+            RegionCN779ChannelsRemove( &channelRemove );
+        }
+    }
+}
+
+bool RegionCN779ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionCN779AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == CN779_TX_MIN_DATARATE )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= CN779_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = CN779_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( CN779_ADR_ACK_LIMIT + CN779_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % CN779_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionCN779GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == CN779_TX_MIN_DATARATE )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionCN779ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, CN779_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    if( rxConfigParams->Datarate == DR_7 )
+    { // FSK
+        tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesCN779[rxConfigParams->Datarate] );
+    }
+    else
+    { // LoRa
+        tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesCN779[rxConfigParams->Datarate], BandwidthsCN779[rxConfigParams->Datarate] );
+    }
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    RadioModems_t modem;
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = Channels[rxConfig->Channel].Frequency;
+        // Apply the alternative RX 1 window frequency, if it is available
+        if( Channels[rxConfig->Channel].Rx1Frequency != 0 )
+        {
+            frequency = Channels[rxConfig->Channel].Rx1Frequency;
+        }
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesCN779[dr];
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    if( dr == DR_7 )
+    {
+        modem = MODEM_FSK;
+        Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+    }
+
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterCN779[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateCN779[dr];
+    }
+    Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionCN779TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    RadioModems_t modem;
+    int8_t phyDr = DataratesCN779[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    if( txConfig->Datarate == DR_7 )
+    { // High Speed FSK channel
+        modem = MODEM_FSK;
+        Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+    }
+
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
+    // Get the time-on-air of the next tx frame
+    *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
+
+    *txPower = txPowerLimited;
+    return true;
+}
+
+uint8_t RegionCN779LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t chMask = 0;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        // Get ADR request parameters
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        // Setup temporary channels mask
+        chMask = linkAdrParams.ChMask;
+
+        // Verify channels mask
+        if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
+        {
+            status &= 0xFE; // Channel mask KO
+        }
+        else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
+                ( linkAdrParams.ChMaskCtrl >= 7 ) )
+        {
+            // RFU
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            for( uint8_t i = 0; i < CN779_MAX_NB_CHANNELS; i++ )
+            {
+                if( linkAdrParams.ChMaskCtrl == 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
+                    }
+                }
+            }
+        }
+    }
+
+    // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
+    phyParam = RegionCN779GetPhyParam( &getPhy );
+
+    linkAdrVerifyParams.Status = status;
+    linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
+    linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
+    linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
+    linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
+    linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
+    linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
+    linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
+    linkAdrVerifyParams.NbChannels = CN779_MAX_NB_CHANNELS;
+    linkAdrVerifyParams.ChannelsMask = &chMask;
+    linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
+    linkAdrVerifyParams.MaxDatarate = CN779_TX_MAX_DATARATE;
+    linkAdrVerifyParams.Channels = Channels;
+    linkAdrVerifyParams.MinTxPower = CN779_MIN_TX_POWER;
+    linkAdrVerifyParams.MaxTxPower = CN779_MAX_TX_POWER;
+
+    // Verify the parameters and update, if necessary
+    status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
+
+    // Update channelsMask if everything is correct
+    if( status == 0x07 )
+    {
+        // Set the channels mask to a default value
+        memset1( ( uint8_t* )ChannelsMask, 0, sizeof( ChannelsMask ) );
+        // Update the channels mask
+        ChannelsMask[0] = chMask;
+    }
+
+    // Update status variables
+    *drOut = linkAdrParams.Datarate;
+    *txPowOut = linkAdrParams.TxPower;
+    *nbRepOut = linkAdrParams.NbRep;
+    *nbBytesParsed = bytesProcessed;
+
+    return status;
+}
+
+uint8_t RegionCN779RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    uint8_t status = 0x07;
+
+    // Verify radio frequency
+    if( Radio.CheckRfFrequency( rxParamSetupReq->Frequency ) == false )
+    {
+        status &= 0xFE; // Channel frequency KO
+    }
+
+    // Verify datarate
+    if( RegionCommonValueInRange( rxParamSetupReq->Datarate, CN779_RX_MIN_DATARATE, CN779_RX_MAX_DATARATE ) == false )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+
+    // Verify datarate offset
+    if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, CN779_MIN_RX1_DR_OFFSET, CN779_MAX_RX1_DR_OFFSET ) == false )
+    {
+        status &= 0xFB; // Rx1DrOffset range KO
+    }
+
+    return status;
+}
+
+uint8_t RegionCN779NewChannelReq( NewChannelReqParams_t* newChannelReq )
+{
+    uint8_t status = 0x03;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    if( newChannelReq->NewChannel->Frequency == 0 )
+    {
+        channelRemove.ChannelId = newChannelReq->ChannelId;
+
+        // Remove
+        if( RegionCN779ChannelsRemove( &channelRemove ) == false )
+        {
+            status &= 0xFC;
+        }
+    }
+    else
+    {
+        channelAdd.NewChannel = newChannelReq->NewChannel;
+        channelAdd.ChannelId = newChannelReq->ChannelId;
+
+        switch( RegionCN779ChannelAdd( &channelAdd ) )
+        {
+            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;
+            }
+        }
+    }
+
+    return status;
+}
+
+int8_t RegionCN779TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
+{
+    return -1;
+}
+
+uint8_t RegionCN779DlChannelReq( DlChannelReqParams_t* dlChannelReq )
+{
+    uint8_t status = 0x03;
+
+    // Verify if the frequency is supported
+    if( VerifyTxFreq( dlChannelReq->Rx1Frequency ) == false )
+    {
+        status &= 0xFE;
+    }
+
+    // Verify if an uplink frequency exists
+    if( Channels[dlChannelReq->ChannelId].Frequency == 0 )
+    {
+        status &= 0xFD;
+    }
+
+    // Apply Rx1 frequency, if the status is OK
+    if( status == 0x03 )
+    {
+        Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
+    }
+
+    return status;
+}
+
+int8_t RegionCN779AlternateDr( int8_t currentDr )
+{
+    return currentDr;
+}
+
+void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff )
+{
+    RegionCommonCalcBackOffParams_t calcBackOffParams;
+
+    calcBackOffParams.Channels = Channels;
+    calcBackOffParams.Bands = Bands;
+    calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
+    calcBackOffParams.Joined = calcBackOff->Joined;
+    calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
+    calcBackOffParams.Channel = calcBackOff->Channel;
+    calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
+    calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
+
+    RegionCommonCalcBackOff( &calcBackOffParams );
+}
+
+LoRaMacStatus_t RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTx = 0;
+    uint8_t enabledChannels[CN779_MAX_NB_CHANNELS] = { 0 };
+    TimerTime_t nextTxDelay = 0;
+
+    if( RegionCommonCountChannels( ChannelsMask, 0, 1 ) == 0 )
+    { // Reactivate default channels
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+    }
+
+    if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+    {
+        // Reset Aggregated time off
+        *aggregatedTimeOff = 0;
+
+        // Update bands Time OFF
+        nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN779_MAX_NB_BANDS );
+
+        // Search how many channels are enabled
+        nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
+                                                      ChannelsMask, Channels,
+                                                      Bands, enabledChannels, &delayTx );
+    }
+    else
+    {
+        delayTx++;
+        nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        // We found a valid channel
+        *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+
+        *time = 0;
+        return LORAMAC_STATUS_OK;
+    }
+    else
+    {
+        if( delayTx > 0 )
+        {
+            // Delay transmission due to AggregatedTimeOff or to a band time off
+            *time = nextTxDelay;
+            return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+        }
+        // Datarate not supported by any channel, restore defaults
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+        *time = 0;
+        return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+    }
+}
+
+LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd )
+{
+    uint8_t band = 0;
+    bool drInvalid = false;
+    bool freqInvalid = false;
+    uint8_t id = channelAdd->ChannelId;
+
+    if( id >= CN779_MAX_NB_CHANNELS )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    // Validate the datarate range
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, CN779_TX_MIN_DATARATE, CN779_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
+    {
+        drInvalid = true;
+    }
+
+    // Default channels don't accept all values
+    if( id < CN779_NUMB_DEFAULT_CHANNELS )
+    {
+        // Validate the datarate range for min: must be DR_0
+        if( channelAdd->NewChannel->DrRange.Fields.Min > DR_0 )
+        {
+            drInvalid = true;
+        }
+        // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE
+        if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, DR_5, CN779_TX_MAX_DATARATE ) == false )
+        {
+            drInvalid = true;
+        }
+        // We are not allowed to change the frequency
+        if( channelAdd->NewChannel->Frequency != Channels[id].Frequency )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check frequency
+    if( freqInvalid == false )
+    {
+        if( VerifyTxFreq( channelAdd->NewChannel->Frequency ) == false )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check status
+    if( ( drInvalid == true ) && ( freqInvalid == true ) )
+    {
+        return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
+    }
+    if( drInvalid == true )
+    {
+        return LORAMAC_STATUS_DATARATE_INVALID;
+    }
+    if( freqInvalid == true )
+    {
+        return LORAMAC_STATUS_FREQUENCY_INVALID;
+    }
+
+    memcpy1( ( uint8_t* )( Channels + id ), ( uint8_t* )channelAdd->NewChannel, sizeof( Channels[id] ) );
+    Channels[id].Band = band;
+    ChannelsMask[0] |= ( 1 << id );
+    return LORAMAC_STATUS_OK;
+}
+
+bool RegionCN779ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
+{
+    uint8_t id = channelRemove->ChannelId;
+
+    if( id < CN779_NUMB_DEFAULT_CHANNELS )
+    {
+        return false;
+    }
+
+    // Remove the channel from the list of channels
+    Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
+
+    return RegionCommonChanDisable( ChannelsMask, id, CN779_MAX_NB_CHANNELS );
+}
+
+void RegionCN779SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+    int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+    uint32_t frequency = Channels[continuousWave->Channel].Frequency;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
+
+    Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
+}
+
+uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    int8_t datarate = dr - drOffset;
+
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+    return datarate;
+}
diff --git a/net/lora/node/src/mac/region/RegionCN779.h b/net/lora/node/src/mac/region/RegionCN779.h
new file mode 100644
index 000000000..28fb2ee9d
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCN779.h
@@ -0,0 +1,467 @@
+/*!
+ * \file      RegionCN779.h
+ *
+ * \brief     Region definition for CN779
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONCN779 Region CN779
+ *            Implementation according to LoRaWAN Specification v1.0.2.
+ * \{
+ */
+#ifndef __REGION_CN779_H__
+#define __REGION_CN779_H__
+
+#include "node/mac/LoRaMac.h"
+
+/*!
+ * LoRaMac maximum number of channels
+ */
+#define CN779_MAX_NB_CHANNELS                       16
+
+/*!
+ * Number of default channels
+ */
+#define CN779_NUMB_DEFAULT_CHANNELS                 3
+
+/*!
+ * Number of channels to apply for the CF list
+ */
+#define CN779_NUMB_CHANNELS_CF_LIST                 5
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define CN779_TX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define CN779_TX_MAX_DATARATE                       DR_7
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define CN779_RX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define CN779_RX_MAX_DATARATE                       DR_7
+
+/*!
+ * Default datarate used by the node
+ */
+#define CN779_DEFAULT_DATARATE                      DR_0
+
+/*!
+ * Minimal Rx1 receive datarate offset
+ */
+#define CN779_MIN_RX1_DR_OFFSET                     0
+
+/*!
+ * Maximal Rx1 receive datarate offset
+ */
+#define CN779_MAX_RX1_DR_OFFSET                     5
+
+/*!
+ * Default Rx1 receive datarate offset
+ */
+#define CN779_DEFAULT_RX1_DR_OFFSET                 0
+
+/*!
+ * Minimal Tx output power that can be used by the node
+ */
+#define CN779_MIN_TX_POWER                          TX_POWER_5
+
+/*!
+ * Maximal Tx output power that can be used by the node
+ */
+#define CN779_MAX_TX_POWER                          TX_POWER_0
+
+/*!
+ * Default Tx output power used by the node
+ */
+#define CN779_DEFAULT_TX_POWER                      TX_POWER_0
+
+/*!
+ * Default Max EIRP
+ */
+#define CN779_DEFAULT_MAX_EIRP                      12.15f
+
+/*!
+ * Default antenna gain
+ */
+#define CN779_DEFAULT_ANTENNA_GAIN                  2.15f
+
+/*!
+ * ADR Ack limit
+ */
+#define CN779_ADR_ACK_LIMIT                         64
+
+/*!
+ * ADR Ack delay
+ */
+#define CN779_ADR_ACK_DELAY                         32
+
+/*!
+ * Enabled or disabled the duty cycle
+ */
+#define CN779_DUTY_CYCLE_ENABLED                    1
+
+/*!
+ * Maximum RX window duration
+ */
+#define CN779_MAX_RX_WINDOW                         3000
+
+/*!
+ * Receive delay 1
+ */
+#define CN779_RECEIVE_DELAY1                        1000
+
+/*!
+ * Receive delay 2
+ */
+#define CN779_RECEIVE_DELAY2                        2000
+
+/*!
+ * Join accept delay 1
+ */
+#define CN779_JOIN_ACCEPT_DELAY1                    5000
+
+/*!
+ * Join accept delay 2
+ */
+#define CN779_JOIN_ACCEPT_DELAY2                    6000
+
+/*!
+ * Maximum frame counter gap
+ */
+#define CN779_MAX_FCNT_GAP                          16384
+
+/*!
+ * Ack timeout
+ */
+#define CN779_ACKTIMEOUT                            2000
+
+/*!
+ * Random ack timeout limits
+ */
+#define CN779_ACK_TIMEOUT_RND                       1000
+
+/*!
+ * Verification of default datarate
+ */
+#if ( CN779_DEFAULT_DATARATE > DR_5 )
+#error "A default DR higher than DR_5 may lead to connectivity loss."
+#endif
+
+/*!
+ * Second reception window channel frequency definition.
+ */
+#define CN779_RX_WND_2_FREQ                         786000000
+
+/*!
+ * Second reception window channel datarate definition.
+ */
+#define CN779_RX_WND_2_DR                           DR_0
+
+/*!
+ * LoRaMac maximum number of bands
+ */
+#define CN779_MAX_NB_BANDS                           1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define CN779_BAND0                                 { 100, CN779_MAX_TX_POWER, 0, 0, 0 } //  1.0 %
+
+/*!
+ * LoRaMac default channel 1
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define CN779_LC1                                   { 779500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+/*!
+ * LoRaMac default channel 2
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define CN779_LC2                                   { 779700000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac default channel 3
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define CN779_LC3                                   { 779900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac channels which are allowed for the join procedure
+ */
+#define CN779_JOIN_CHANNELS                         ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
+
+/*!
+ * Data rates table definition
+ */
+static const uint8_t DataratesCN779[]  = { 12, 11, 10,  9,  8,  7,  7, 50 };
+
+/*!
+ * Bandwidths table definition in Hz
+ */
+static const uint32_t BandwidthsCN779[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateCN779[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateRepeaterCN779[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionCN779SetBandTxDone( SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionCN779InitDefaults( InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionCN779Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionCN779ApplyCFList( ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionCN779ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionCN779AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * Computes the Rx window timeout and offset.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionCN779ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionCN779TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN779LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN779RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a Channel Request.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN779NewChannelReq( NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall not process the command.
+ */
+int8_t RegionCN779TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionCN779DlChannelReq( DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionCN779AlternateDr( int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
+ */
+LoRaMacStatus_t RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionCN779ChannelsRemove( ChannelRemoveParams_t* channelRemove  );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionCN779SetContinuousWave( ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGIONCN779 */
+
+#endif // __REGION_CN779_H__
diff --git a/net/lora/node/src/mac/region/RegionCommon.c b/net/lora/node/src/mac/region/RegionCommon.c
new file mode 100644
index 000000000..e0fb5d31d
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCommon.c
@@ -0,0 +1,373 @@
+/*!
+ * \file      RegionCommon.c
+ *
+ * \brief     LoRa MAC common region implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ */
+#include <math.h>
+#include "node/utilities.h"
+#include "RegionCommon.h"
+
+#define BACKOFF_DC_1_HOUR       100
+#define BACKOFF_DC_10_HOURS     1000
+#define BACKOFF_DC_24_HOURS     10000
+
+static uint8_t CountChannels( 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;
+}
+
+uint16_t RegionCommonGetJoinDc( TimerTime_t elapsedTime )
+{
+    uint16_t dutyCycle = 0;
+
+    if( elapsedTime < 3600000 )
+    {
+        dutyCycle = BACKOFF_DC_1_HOUR;
+    }
+    else if( elapsedTime < ( 3600000 + 36000000 ) )
+    {
+        dutyCycle = BACKOFF_DC_10_HOURS;
+    }
+    else
+    {
+        dutyCycle = BACKOFF_DC_24_HOURS;
+    }
+    return dutyCycle;
+}
+
+bool RegionCommonChanVerifyDr( uint8_t nbChannels, uint16_t* channelsMask, int8_t dr, int8_t minDr, int8_t maxDr, ChannelParams_t* channels )
+{
+    if( RegionCommonValueInRange( dr, minDr, maxDr ) == 0 )
+    {
+        return false;
+    }
+
+    for( uint8_t i = 0, k = 0; i < nbChannels; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) )
+            {// Check datarate validity for enabled channels
+                if( RegionCommonValueInRange( dr, ( channels[i + j].DrRange.Fields.Min & 0x0F ),
+                                                  ( channels[i + j].DrRange.Fields.Max & 0x0F ) ) == 1 )
+                {
+                    // At least 1 channel has been found we can return OK.
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+uint8_t RegionCommonValueInRange( int8_t value, int8_t min, int8_t max )
+{
+    if( ( value >= min ) && ( value <= max ) )
+    {
+        return 1;
+    }
+    return 0;
+}
+
+bool RegionCommonChanDisable( uint16_t* channelsMask, uint8_t id, uint8_t maxChannels )
+{
+    uint8_t index = id / 16;
+
+    if( ( index > ( maxChannels / 16 ) ) || ( id >= maxChannels ) )
+    {
+        return false;
+    }
+
+    // Deactivate channel
+    channelsMask[index] &= ~( 1 << ( id % 16 ) );
+
+    return true;
+}
+
+uint8_t RegionCommonCountChannels( uint16_t* channelsMask, uint8_t startIdx, uint8_t stopIdx )
+{
+    uint8_t nbChannels = 0;
+
+    if( channelsMask == NULL )
+    {
+        return 0;
+    }
+
+    for( uint8_t i = startIdx; i < stopIdx; i++ )
+    {
+        nbChannels += CountChannels( channelsMask[i], 16 );
+    }
+
+    return nbChannels;
+}
+
+void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMaskSrc, uint8_t len )
+{
+    if( ( channelsMaskDest != NULL ) && ( channelsMaskSrc != NULL ) )
+    {
+        for( uint8_t i = 0; i < len; i++ )
+        {
+            channelsMaskDest[i] = channelsMaskSrc[i];
+        }
+    }
+}
+
+void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDone )
+{
+    if( joined == true )
+    {
+        band->LastTxDoneTime = lastTxDone;
+    }
+    else
+    {
+        band->LastTxDoneTime = lastTxDone;
+        band->LastJoinTxDoneTime = lastTxDone;
+    }
+}
+
+TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* bands, uint8_t nbBands )
+{
+    TimerTime_t nextTxDelay = ( TimerTime_t )( -1 );
+
+    // Update bands Time OFF
+    for( uint8_t i = 0; i < nbBands; i++ )
+    {
+        if( joined == false )
+        {
+            uint32_t txDoneTime =  MAX( TimerGetElapsedTime( bands[i].LastJoinTxDoneTime ),
+                                        ( dutyCycle == true ) ? TimerGetElapsedTime( bands[i].LastTxDoneTime ) : 0 );
+
+            if( bands[i].TimeOff <= txDoneTime )
+            {
+                bands[i].TimeOff = 0;
+            }
+            if( bands[i].TimeOff != 0 )
+            {
+                nextTxDelay = MIN( bands[i].TimeOff - txDoneTime, nextTxDelay );
+            }
+        }
+        else
+        {
+            if( dutyCycle == 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
+            {
+                nextTxDelay = 0;
+                bands[i].TimeOff = 0;
+            }
+        }
+    }
+    return nextTxDelay;
+}
+
+uint8_t RegionCommonParseLinkAdrReq( uint8_t* payload, RegionCommonLinkAdrParams_t* linkAdrParams )
+{
+    uint8_t retIndex = 0;
+
+    if( payload[0] == SRV_MAC_LINK_ADR_REQ )
+    {
+        // Parse datarate and tx power
+        linkAdrParams->Datarate = payload[1];
+        linkAdrParams->TxPower = linkAdrParams->Datarate & 0x0F;
+        linkAdrParams->Datarate = ( linkAdrParams->Datarate >> 4 ) & 0x0F;
+        // Parse ChMask
+        linkAdrParams->ChMask = ( uint16_t )payload[2];
+        linkAdrParams->ChMask |= ( uint16_t )payload[3] << 8;
+        // Parse ChMaskCtrl and nbRep
+        linkAdrParams->NbRep = payload[4];
+        linkAdrParams->ChMaskCtrl = ( linkAdrParams->NbRep >> 4 ) & 0x07;
+        linkAdrParams->NbRep &= 0x0F;
+
+        // LinkAdrReq has 4 bytes length + 1 byte CMD
+        retIndex = 5;
+    }
+    return retIndex;
+}
+
+uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t* verifyParams, int8_t* dr, int8_t* txPow, uint8_t* nbRep )
+{
+    uint8_t status = verifyParams->Status;
+    int8_t datarate = verifyParams->Datarate;
+    int8_t txPower = verifyParams->TxPower;
+    int8_t nbRepetitions = verifyParams->NbRep;
+
+    // Handle the case when ADR is off.
+    if( verifyParams->AdrEnabled == false )
+    {
+        // When ADR is off, we are allowed to change the channels mask and the NbRep,
+        // if the datarate and the TX power of the LinkAdrReq are set to 0x0F.
+        if( ( verifyParams->Datarate != 0x0F ) || ( verifyParams->TxPower != 0x0F ) )
+        {
+            status = 0;
+            nbRepetitions = verifyParams->CurrentNbRep;
+        }
+        // Get the current datarate and tx power
+        datarate = verifyParams->CurrentDatarate;
+        txPower = verifyParams->CurrentTxPower;
+    }
+
+    if( status != 0 )
+    {
+        // Verify datarate. The variable phyParam. Value contains the minimum allowed datarate.
+        if( RegionCommonChanVerifyDr( verifyParams->NbChannels, verifyParams->ChannelsMask, datarate,
+                                      verifyParams->MinDatarate, verifyParams->MaxDatarate, verifyParams->Channels  ) == false )
+        {
+            status &= 0xFD; // Datarate KO
+        }
+
+        // Verify tx power
+        if( RegionCommonValueInRange( txPower, verifyParams->MaxTxPower, verifyParams->MinTxPower ) == 0 )
+        {
+            // Verify if the maximum TX power is exceeded
+            if( verifyParams->MaxTxPower > txPower )
+            { // Apply maximum TX power. Accept TX power.
+                txPower = verifyParams->MaxTxPower;
+            }
+            else
+            {
+                status &= 0xFB; // TxPower KO
+            }
+        }
+    }
+
+    // If the status is ok, verify the NbRep
+    if( status == 0x07 )
+    {
+        if( nbRepetitions == 0 )
+        { // Restore the default value according to the LoRaWAN specification
+            nbRepetitions = 1;
+        }
+    }
+
+    // Apply changes
+    *dr = datarate;
+    *txPow = txPower;
+    *nbRep = nbRepetitions;
+
+    return status;
+}
+
+double RegionCommonComputeSymbolTimeLoRa( uint8_t phyDr, uint32_t bandwidth )
+{
+    return ( ( double )( 1 << phyDr ) / ( double )bandwidth ) * 1000;
+}
+
+double RegionCommonComputeSymbolTimeFsk( uint8_t phyDr )
+{
+    return ( 8.0 / ( double )phyDr ); // 1 symbol equals 1 byte
+}
+
+void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t* windowTimeout, int32_t* windowOffset )
+{
+/* XXX: I do not understand this */
+#if 0
+    *windowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * minRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), minRxSymbols ); // Computed number of symbols
+    *windowOffset = ( int32_t )ceil( ( 4.0 * tSymbol ) - ( ( *windowTimeout * tSymbol ) / 2.0 ) - wakeUpTime );
+#else
+    uint16_t add_symbols;
+
+    *windowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * minRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), minRxSymbols ); // Computed number of symbols
+    add_symbols = 1;
+    if (wakeUpTime >= tSymbol) {
+        add_symbols += ((double)wakeUpTime / tSymbol);
+    }
+    *windowTimeout += add_symbols;
+    *windowOffset = -1 * wakeUpTime;
+#endif
+}
+
+int8_t RegionCommonComputeTxPower( int8_t txPowerIndex, float maxEirp, float antennaGain )
+{
+    int8_t phyTxPower = 0;
+
+    phyTxPower = ( int8_t )floor( ( maxEirp - ( txPowerIndex * 2U ) ) - antennaGain );
+
+    return phyTxPower;
+}
+
+void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams )
+{
+    uint8_t bandIdx = calcBackOffParams->Channels[calcBackOffParams->Channel].Band;
+    uint16_t dutyCycle = calcBackOffParams->Bands[bandIdx].DCycle;
+    uint16_t joinDutyCycle = 0;
+
+    // Reset time-off to initial value.
+    calcBackOffParams->Bands[bandIdx].TimeOff = 0;
+
+    if( calcBackOffParams->Joined == false )
+    {
+        // Get the join duty cycle
+        joinDutyCycle = RegionCommonGetJoinDc( calcBackOffParams->ElapsedTime );
+        // Apply the most restricting duty cycle
+        dutyCycle = MAX( dutyCycle, joinDutyCycle );
+        // Reset the timeoff if the last frame was not a join request and when the duty cycle is not enabled
+        if( ( calcBackOffParams->DutyCycleEnabled == false ) && ( calcBackOffParams->LastTxIsJoinRequest == false ) )
+        {
+            // This is the case when the duty cycle is off and the last uplink frame was not a join.
+            // This could happen in case of a rejoin, e.g. in compliance test mode.
+            // In this special case we have to set the time off to 0, since the join duty cycle shall only
+            // be applied after the first join request.
+            calcBackOffParams->Bands[bandIdx].TimeOff = 0;
+        }
+        else
+        {
+            // Apply band time-off.
+            calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir;
+        }
+    }
+    else
+    {
+        if( calcBackOffParams->DutyCycleEnabled == true )
+        {
+            calcBackOffParams->Bands[bandIdx].TimeOff = calcBackOffParams->TxTimeOnAir * dutyCycle - calcBackOffParams->TxTimeOnAir;
+        }
+        else
+        {
+            calcBackOffParams->Bands[bandIdx].TimeOff = 0;
+        }
+    }
+}
diff --git a/net/lora/node/src/mac/region/RegionCommon.h b/net/lora/node/src/mac/region/RegionCommon.h
new file mode 100644
index 000000000..ca2beb3b1
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionCommon.h
@@ -0,0 +1,370 @@
+/*!
+ * \file      RegionCommon.h
+ *
+ * \brief     Region independent implementations which are common to all regions.
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONCOMMON Common region implementation
+ *            Region independent implementations which are common to all regions.
+ * \{
+ */
+#ifndef __REGIONCOMMON_H__
+#define __REGIONCOMMON_H__
+
+//#include "node/mac/LoRaMac.h"
+#include "node/lora_priv.h"
+
+typedef struct sRegionCommonLinkAdrParams
+{
+    /*!
+     * Number of repetitions.
+     */
+    uint8_t NbRep;
+    /*!
+     * Datarate.
+     */
+    int8_t Datarate;
+    /*!
+     * Tx power.
+     */
+    int8_t TxPower;
+    /*!
+     * Channels mask control field.
+     */
+    uint8_t ChMaskCtrl;
+    /*!
+     * Channels mask field.
+     */
+    uint16_t ChMask;
+}RegionCommonLinkAdrParams_t;
+
+typedef struct sRegionCommonLinkAdrReqVerifyParams
+{
+    /*!
+     * The current status of the AdrLinkRequest.
+     */
+    uint8_t Status;
+    /*!
+     * Set to true, if ADR is enabled.
+     */
+    bool AdrEnabled;
+    /*!
+     * The datarate the AdrLinkRequest wants to set.
+     */
+    int8_t Datarate;
+    /*!
+     * The TX power the AdrLinkRequest wants to set.
+     */
+    int8_t TxPower;
+    /*!
+     * The number of repetitions the AdrLinkRequest wants to set.
+     */
+    uint8_t NbRep;
+    /*!
+     * The current datarate the node is using.
+     */
+    int8_t CurrentDatarate;
+    /*!
+     * The current TX power the node is using.
+     */
+    int8_t CurrentTxPower;
+    /*!
+     * The current number of repetitions the node is using.
+     */
+    int8_t CurrentNbRep;
+    /*!
+     * The number of channels.
+     */
+    uint8_t NbChannels;
+    /*!
+     * Pointer to the first element of the channels mask.
+     */
+    uint16_t* ChannelsMask;
+    /*!
+     * The minimum possible datarate.
+     */
+    int8_t MinDatarate;
+    /*!
+     * The maximum possible datarate.
+     */
+    int8_t MaxDatarate;
+    /*!
+     * Pointer to the channels.
+     */
+    ChannelParams_t* Channels;
+    /*!
+     * The minimum possible TX power.
+     */
+    int8_t MinTxPower;
+    /*!
+     * The maximum possible TX power.
+     */
+    int8_t MaxTxPower;
+}RegionCommonLinkAdrReqVerifyParams_t;
+
+typedef struct sRegionCommonCalcBackOffParams
+{
+    /*!
+     * A pointer to region specific channels.
+     */
+    ChannelParams_t* Channels;
+    /*!
+     * A pointer to region specific bands.
+     */
+    Band_t* Bands;
+    /*!
+     * Set to true, if the last uplink was a join request.
+     */
+    bool LastTxIsJoinRequest;
+    /*!
+     * Set to true, if the node is joined.
+     */
+    bool Joined;
+    /*!
+     * Set to true, if the duty cycle is enabled.
+     */
+    bool DutyCycleEnabled;
+    /*!
+     * The current channel.
+     */
+    uint8_t Channel;
+    /*!
+     * The elapsed time since initialization.
+     */
+    TimerTime_t ElapsedTime;
+    /*!
+     * The time on air of the last Tx frame.
+     */
+    TimerTime_t TxTimeOnAir;
+}RegionCommonCalcBackOffParams_t;
+
+/*!
+ * \brief Calculates the join duty cycle.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] elapsedTime Elapsed time since the start of the device.
+ *
+ * \retval Duty cycle restriction.
+ */
+uint16_t RegionCommonGetJoinDc( TimerTime_t elapsedTime );
+
+/*!
+ * \brief Verifies, if a value is in a given range.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] value Value to verify, if it is in range.
+ *
+ * \param [IN] min Minimum possible value.
+ *
+ * \param [IN] max Maximum possible value.
+ *
+ * \retval Returns 1 if the value is in range, otherwise 0.
+ */
+uint8_t RegionCommonValueInRange( int8_t value, int8_t min, int8_t max );
+
+/*!
+ * \brief Verifies, if a datarate is available on an active channel.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] nbChannels Number of channels.
+ *
+ * \param [IN] channelsMask The channels mask of the region.
+ *
+ * \param [IN] dr The datarate to verify.
+ *
+ * \param [IN] minDr Minimum datarate.
+ *
+ * \param [IN] maxDr Maximum datarate.
+ *
+ * \param [IN] channels The channels of the region.
+ *
+ * \retval Returns true if the datarate is supported, false if not.
+ */
+bool RegionCommonChanVerifyDr( uint8_t nbChannels, uint16_t* channelsMask, int8_t dr,
+                            int8_t minDr, int8_t maxDr, ChannelParams_t* channels );
+
+/*!
+ * \brief Disables a channel in a given channels mask.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] channelsMask The channels mask of the region.
+ *
+ * \param [IN] id The id of the channels mask to disable.
+ *
+ * \param [IN] maxChannels Maximum number of channels.
+ *
+ * \retval Returns true if the channel could be disabled, false if not.
+ */
+bool RegionCommonChanDisable( uint16_t* channelsMask, uint8_t id, uint8_t maxChannels );
+
+/*!
+ * \brief Counts the number of active channels in a given channels mask.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] channelsMask The channels mask of the region.
+ *
+ * \param [IN] startIdx Start index.
+ *
+ * \param [IN] stopIdx Stop index ( the channels of this index will not be counted ).
+ *
+ * \retval Returns the number of active channels.
+ */
+uint8_t RegionCommonCountChannels( uint16_t* channelsMask, uint8_t startIdx, uint8_t stopIdx );
+
+/*!
+ * \brief Copy a channels mask.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] channelsMaskDest The destination channels mask.
+ *
+ * \param [IN] channelsMaskSrc The source channels mask.
+ *
+ * \param [IN] len The index length to copy.
+ */
+void RegionCommonChanMaskCopy( uint16_t* channelsMaskDest, uint16_t* channelsMaskSrc, uint8_t len );
+
+/*!
+ * \brief Sets the last tx done property.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] joined Set to true, if the node has joined the network
+ *
+ * \param [IN] band The band to be updated.
+ *
+ * \param [IN] lastTxDone The time of the last TX done.
+ */
+void RegionCommonSetBandTxDone( bool joined, Band_t* band, TimerTime_t lastTxDone );
+
+/*!
+ * \brief Updates the time-offs of the bands.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] joined Set to true, if the node has joined the network
+ *
+ * \param [IN] dutyCycle Set to true, if the duty cycle is enabled.
+ *
+ * \param [IN] bands A pointer to the bands.
+ *
+ * \param [IN] nbBands The number of bands available.
+ *
+ * \retval Returns the time which must be waited to perform the next uplink.
+ */
+TimerTime_t RegionCommonUpdateBandTimeOff( bool joined, bool dutyCycle, Band_t* bands, uint8_t nbBands );
+
+/*!
+ * \brief Parses the parameter of an LinkAdrRequest.
+ *        This is a generic function and valid for all regions.
+ *
+ * \param [IN] payload Pointer to the payload containing the MAC commands. The payload
+ *                     must contain the CMD identifier, following by the parameters.
+ *
+ * \param [OUT] parseLinkAdr The function fills the structure with the ADR parameters.
+ *
+ * \retval Returns the length of the ADR request, if a request was found. Otherwise, the
+ *         function returns 0.
+ */
+uint8_t RegionCommonParseLinkAdrReq( uint8_t* payload, RegionCommonLinkAdrParams_t* parseLinkAdr );
+
+/*!
+ * \brief Verifies and updates the datarate, the TX power and the number of repetitions
+ *        of a LinkAdrRequest. This depends on the configuration of ADR also.
+ *
+ * \param [IN] verifyParams Pointer to a structure containing input parameters.
+ *
+ * \param [OUT] dr The updated datarate.
+ *
+ * \param [OUT] txPow The updated TX power.
+ *
+ * \param [OUT] nbRep The updated number of repetitions.
+ *
+ * \retval Returns the status according to the LinkAdrRequest definition.
+ */
+uint8_t RegionCommonLinkAdrReqVerifyParams( RegionCommonLinkAdrReqVerifyParams_t* verifyParams, int8_t* dr, int8_t* txPow, uint8_t* nbRep );
+
+/*!
+ * \brief Computes the symbol time for LoRa modulation.
+ *
+ * \param [IN] phyDr Physical datarate to use.
+ *
+ * \param [IN] bandwidth Bandwidth to use.
+ *
+ * \retval Returns the symbol time (in msecs)
+ */
+double RegionCommonComputeSymbolTimeLoRa( uint8_t phyDr, uint32_t bandwidth );
+
+/*!
+ * \brief Computes the symbol time for FSK modulation.
+ *
+ * \param [IN] phyDr Physical datarate to use.
+ *
+ * \param [IN] bandwidth Bandwidth to use.
+ *
+ * \retval Returns the symbol time.
+ */
+double RegionCommonComputeSymbolTimeFsk( uint8_t phyDr );
+
+/*!
+ * \brief Computes the RX window timeout and the RX window offset.
+ *
+ * \param [IN] tSymbol Symbol timeout.
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError System maximum timing error of the receiver. In milliseconds
+ *                     The receiver will turn on in a [-rxError : +rxError] ms interval around RxOffset.
+ *
+ * \param [IN] wakeUpTime Wakeup time of the system.
+ *
+ * \param [OUT] windowTimeout RX window timeout.
+ *
+ * \param [OUT] windowOffset RX window time offset to be applied to the RX delay.
+ */
+void RegionCommonComputeRxWindowParameters( double tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime, uint32_t* windowTimeout, int32_t* windowOffset );
+
+/*!
+ * \brief Computes the txPower, based on the max EIRP and the antenna gain.
+ *
+ * \param [IN] txPower TX power index.
+ *
+ * \param [IN] maxEirp Maximum EIRP.
+ *
+ * \param [IN] antennaGain Antenna gain.
+ *
+ * \retval Returns the physical TX power.
+ */
+int8_t RegionCommonComputeTxPower( int8_t txPowerIndex, float maxEirp, float antennaGain );
+
+/*!
+ * \brief Calculates the duty cycle for the current band.
+ *
+ * \param [IN] calcBackOffParams A pointer to the input parameters.
+ */
+void RegionCommonCalcBackOff( RegionCommonCalcBackOffParams_t* calcBackOffParams );
+
+/*! \} defgroup REGIONCOMMON */
+
+#endif // __REGIONCOMMON_H__
diff --git a/net/lora/node/src/mac/region/RegionEU433.c b/net/lora/node/src/mac/region/RegionEU433.c
new file mode 100644
index 000000000..e2fd19b3f
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionEU433.c
@@ -0,0 +1,1013 @@
+/*!
+ * \file      RegionEU433.c
+ *
+ * \brief     Region implementation for EU433
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+
+#include "RegionCommon.h"
+#include "RegionEU433.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              1
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[EU433_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[EU433_MAX_NB_BANDS] =
+{
+    EU433_BAND0
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsEU433[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static bool VerifyTxFreq( uint32_t freq )
+{
+    // Check radio driver support
+    if( Radio.CheckRfFrequency( freq ) == false )
+    {
+        return false;
+    }
+
+    if( ( freq < 433175000 ) || ( freq > 434665000 ) )
+    {
+        return false;
+    }
+    return true;
+}
+
+static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < EU433_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( joined == false )
+                {
+                    if( ( EU433_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
+                    {
+                        continue;
+                    }
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            phyParam.Value = EU433_RX_MIN_DATARATE;
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            phyParam.Value = EU433_TX_MIN_DATARATE;
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = EU433_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, EU433_TX_MIN_DATARATE );
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = EU433_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            phyParam.Value = MaxPayloadOfDatarateEU433[getPhy->Datarate];
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            phyParam.Value = MaxPayloadOfDatarateRepeaterEU433[getPhy->Datarate];
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = EU433_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = EU433_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = EU433_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = EU433_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = EU433_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = EU433_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = EU433_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( EU433_ACKTIMEOUT + randr( -EU433_ACK_TIMEOUT_RND, EU433_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = EU433_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = EU433_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = EU433_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = EU433_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = 0;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = EU433_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = EU433_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionEU433SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionEU433InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            Channels[0] = ( ChannelParams_t ) EU433_LC1;
+            Channels[1] = ( ChannelParams_t ) EU433_LC2;
+            Channels[2] = ( ChannelParams_t ) EU433_LC3;
+
+            // Initialize the channels default mask
+            ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+            // Update the channels mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Restore channels default mask
+            ChannelsMask[0] |= ChannelsDefaultMask[0];
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Update the channels mask defaults
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionEU433Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU433_TX_MIN_DATARATE, EU433_TX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
+        }
+        case PHY_RX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU433_RX_MIN_DATARATE, EU433_RX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, EU433_MAX_TX_POWER, EU433_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return EU433_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionEU433ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    ChannelParams_t newChannel;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    // Setup default datarate range
+    newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
+
+    // Size of the optional CF list
+    if( applyCFList->Size != 16 )
+    {
+        return;
+    }
+
+    // Last byte is RFU, don't take it into account
+    for( uint8_t i = 0, chanIdx = EU433_NUMB_DEFAULT_CHANNELS; chanIdx < EU433_MAX_NB_CHANNELS; i+=3, chanIdx++ )
+    {
+        if( chanIdx < ( EU433_NUMB_CHANNELS_CF_LIST + EU433_NUMB_DEFAULT_CHANNELS ) )
+        {
+            // Channel frequency
+            newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
+            newChannel.Frequency *= 100;
+
+            // Initialize alternative frequency to 0
+            newChannel.Rx1Frequency = 0;
+        }
+        else
+        {
+            newChannel.Frequency = 0;
+            newChannel.DrRange.Value = 0;
+            newChannel.Rx1Frequency = 0;
+        }
+
+        if( newChannel.Frequency != 0 )
+        {
+            channelAdd.NewChannel = &newChannel;
+            channelAdd.ChannelId = chanIdx;
+
+            // Try to add all channels
+            RegionEU433ChannelAdd( &channelAdd );
+        }
+        else
+        {
+            channelRemove.ChannelId = chanIdx;
+
+            RegionEU433ChannelsRemove( &channelRemove );
+        }
+    }
+}
+
+bool RegionEU433ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionEU433AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == EU433_TX_MIN_DATARATE )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= EU433_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = EU433_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( EU433_ADR_ACK_LIMIT + EU433_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % EU433_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionEU433GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == EU433_TX_MIN_DATARATE )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionEU433ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, EU433_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    if( rxConfigParams->Datarate == DR_7 )
+    { // FSK
+        tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesEU433[rxConfigParams->Datarate] );
+    }
+    else
+    { // LoRa
+        tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesEU433[rxConfigParams->Datarate], BandwidthsEU433[rxConfigParams->Datarate] );
+    }
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    RadioModems_t modem;
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = Channels[rxConfig->Channel].Frequency;
+        // Apply the alternative RX 1 window frequency, if it is available
+        if( Channels[rxConfig->Channel].Rx1Frequency != 0 )
+        {
+            frequency = Channels[rxConfig->Channel].Rx1Frequency;
+        }
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesEU433[dr];
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    if( dr == DR_7 )
+    {
+        modem = MODEM_FSK;
+        Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+    }
+
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterEU433[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateEU433[dr];
+    }
+    Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionEU433TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    RadioModems_t modem;
+    int8_t phyDr = DataratesEU433[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    if( txConfig->Datarate == DR_7 )
+    { // High Speed FSK channel
+        modem = MODEM_FSK;
+        Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+    }
+
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
+    // Get the time-on-air of the next tx frame
+    *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
+
+    *txPower = txPowerLimited;
+    return true;
+}
+
+uint8_t RegionEU433LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t chMask = 0;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        // Get ADR request parameters
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        // Setup temporary channels mask
+        chMask = linkAdrParams.ChMask;
+
+        // Verify channels mask
+        if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
+        {
+            status &= 0xFE; // Channel mask KO
+        }
+        else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
+                ( linkAdrParams.ChMaskCtrl >= 7 ) )
+        {
+            // RFU
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            for( uint8_t i = 0; i < EU433_MAX_NB_CHANNELS; i++ )
+            {
+                if( linkAdrParams.ChMaskCtrl == 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
+                    }
+                }
+            }
+        }
+    }
+
+        // Get the minimum possible datarate
+    getPhy.Attribute = PHY_MIN_TX_DR;
+    getPhy.UplinkDwellTime = linkAdrReq->UplinkDwellTime;
+    phyParam = RegionEU433GetPhyParam( &getPhy );
+
+    linkAdrVerifyParams.Status = status;
+    linkAdrVerifyParams.AdrEnabled = linkAdrReq->AdrEnabled;
+    linkAdrVerifyParams.Datarate = linkAdrParams.Datarate;
+    linkAdrVerifyParams.TxPower = linkAdrParams.TxPower;
+    linkAdrVerifyParams.NbRep = linkAdrParams.NbRep;
+    linkAdrVerifyParams.CurrentDatarate = linkAdrReq->CurrentDatarate;
+    linkAdrVerifyParams.CurrentTxPower = linkAdrReq->CurrentTxPower;
+    linkAdrVerifyParams.CurrentNbRep = linkAdrReq->CurrentNbRep;
+    linkAdrVerifyParams.NbChannels = EU433_MAX_NB_CHANNELS;
+    linkAdrVerifyParams.ChannelsMask = &chMask;
+    linkAdrVerifyParams.MinDatarate = ( int8_t )phyParam.Value;
+    linkAdrVerifyParams.MaxDatarate = EU433_TX_MAX_DATARATE;
+    linkAdrVerifyParams.Channels = Channels;
+    linkAdrVerifyParams.MinTxPower = EU433_MIN_TX_POWER;
+    linkAdrVerifyParams.MaxTxPower = EU433_MAX_TX_POWER;
+
+    // Verify the parameters and update, if necessary
+    status = RegionCommonLinkAdrReqVerifyParams( &linkAdrVerifyParams, &linkAdrParams.Datarate, &linkAdrParams.TxPower, &linkAdrParams.NbRep );
+
+    // Update channelsMask if everything is correct
+    if( status == 0x07 )
+    {
+        // Set the channels mask to a default value
+        memset1( ( uint8_t* )ChannelsMask, 0, sizeof( ChannelsMask ) );
+        // Update the channels mask
+        ChannelsMask[0] = chMask;
+    }
+
+    // Update status variables
+    *drOut = linkAdrParams.Datarate;
+    *txPowOut = linkAdrParams.TxPower;
+    *nbRepOut = linkAdrParams.NbRep;
+    *nbBytesParsed = bytesProcessed;
+
+    return status;
+}
+
+uint8_t RegionEU433RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
+{
+    uint8_t status = 0x07;
+
+    // Verify radio frequency
+    if( Radio.CheckRfFrequency( rxParamSetupReq->Frequency ) == false )
+    {
+        status &= 0xFE; // Channel frequency KO
+    }
+
+    // Verify datarate
+    if( RegionCommonValueInRange( rxParamSetupReq->Datarate, EU433_RX_MIN_DATARATE, EU433_RX_MAX_DATARATE ) == false )
+    {
+        status &= 0xFD; // Datarate KO
+    }
+
+    // Verify datarate offset
+    if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, EU433_MIN_RX1_DR_OFFSET, EU433_MAX_RX1_DR_OFFSET ) == false )
+    {
+        status &= 0xFB; // Rx1DrOffset range KO
+    }
+
+    return status;
+}
+
+uint8_t RegionEU433NewChannelReq( NewChannelReqParams_t* newChannelReq )
+{
+    uint8_t status = 0x03;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    if( newChannelReq->NewChannel->Frequency == 0 )
+    {
+        channelRemove.ChannelId = newChannelReq->ChannelId;
+
+        // Remove
+        if( RegionEU433ChannelsRemove( &channelRemove ) == false )
+        {
+            status &= 0xFC;
+        }
+    }
+    else
+    {
+        channelAdd.NewChannel = newChannelReq->NewChannel;
+        channelAdd.ChannelId = newChannelReq->ChannelId;
+
+        switch( RegionEU433ChannelAdd( &channelAdd ) )
+        {
+            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;
+            }
+        }
+    }
+
+    return status;
+}
+
+int8_t RegionEU433TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
+{
+    return -1;
+}
+
+uint8_t RegionEU433DlChannelReq( DlChannelReqParams_t* dlChannelReq )
+{
+    uint8_t status = 0x03;
+
+    // Verify if the frequency is supported
+    if( VerifyTxFreq( dlChannelReq->Rx1Frequency ) == false )
+    {
+        status &= 0xFE;
+    }
+
+    // Verify if an uplink frequency exists
+    if( Channels[dlChannelReq->ChannelId].Frequency == 0 )
+    {
+        status &= 0xFD;
+    }
+
+    // Apply Rx1 frequency, if the status is OK
+    if( status == 0x03 )
+    {
+        Channels[dlChannelReq->ChannelId].Rx1Frequency = dlChannelReq->Rx1Frequency;
+    }
+
+    return status;
+}
+
+int8_t RegionEU433AlternateDr( int8_t currentDr )
+{
+    return currentDr;
+}
+
+void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff )
+{
+    RegionCommonCalcBackOffParams_t calcBackOffParams;
+
+    calcBackOffParams.Channels = Channels;
+    calcBackOffParams.Bands = Bands;
+    calcBackOffParams.LastTxIsJoinRequest = calcBackOff->LastTxIsJoinRequest;
+    calcBackOffParams.Joined = calcBackOff->Joined;
+    calcBackOffParams.DutyCycleEnabled = calcBackOff->DutyCycleEnabled;
+    calcBackOffParams.Channel = calcBackOff->Channel;
+    calcBackOffParams.ElapsedTime = calcBackOff->ElapsedTime;
+    calcBackOffParams.TxTimeOnAir = calcBackOff->TxTimeOnAir;
+
+    RegionCommonCalcBackOff( &calcBackOffParams );
+}
+
+LoRaMacStatus_t RegionEU433NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTx = 0;
+    uint8_t enabledChannels[EU433_MAX_NB_CHANNELS] = { 0 };
+    TimerTime_t nextTxDelay = 0;
+
+    if( RegionCommonCountChannels( ChannelsMask, 0, 1 ) == 0 )
+    { // Reactivate default channels
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+    }
+
+    if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
+    {
+        // Reset Aggregated time off
+        *aggregatedTimeOff = 0;
+
+        // Update bands Time OFF
+        nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, EU433_MAX_NB_BANDS );
+
+        // Search how many channels are enabled
+        nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
+                                                      ChannelsMask, Channels,
+                                                      Bands, enabledChannels, &delayTx );
+    }
+    else
+    {
+        delayTx++;
+        nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        // We found a valid channel
+        *channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+
+        *time = 0;
+        return LORAMAC_STATUS_OK;
+    }
+    else
+    {
+        if( delayTx > 0 )
+        {
+            // Delay transmission due to AggregatedTimeOff or to a band time off
+            *time = nextTxDelay;
+            return LORAMAC_STATUS_DUTYCYCLE_RESTRICTED;
+        }
+        // Datarate not supported by any channel, restore defaults
+        ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+        *time = 0;
+        return LORAMAC_STATUS_NO_CHANNEL_FOUND;
+    }
+}
+
+LoRaMacStatus_t RegionEU433ChannelAdd( ChannelAddParams_t* channelAdd )
+{
+    uint8_t band = 0;
+    bool drInvalid = false;
+    bool freqInvalid = false;
+    uint8_t id = channelAdd->ChannelId;
+
+    if( id >= EU433_MAX_NB_CHANNELS )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    // Validate the datarate range
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Min, EU433_TX_MIN_DATARATE, EU433_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, EU433_TX_MIN_DATARATE, EU433_TX_MAX_DATARATE ) == false )
+    {
+        drInvalid = true;
+    }
+    if( channelAdd->NewChannel->DrRange.Fields.Min > channelAdd->NewChannel->DrRange.Fields.Max )
+    {
+        drInvalid = true;
+    }
+
+    // Default channels don't accept all values
+    if( id < EU433_NUMB_DEFAULT_CHANNELS )
+    {
+        // Validate the datarate range for min: must be DR_0
+        if( channelAdd->NewChannel->DrRange.Fields.Min > DR_0 )
+        {
+            drInvalid = true;
+        }
+        // Validate the datarate range for max: must be DR_5 <= Max <= TX_MAX_DATARATE
+        if( RegionCommonValueInRange( channelAdd->NewChannel->DrRange.Fields.Max, DR_5, EU433_TX_MAX_DATARATE ) == false )
+        {
+            drInvalid = true;
+        }
+        // We are not allowed to change the frequency
+        if( channelAdd->NewChannel->Frequency != Channels[id].Frequency )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check frequency
+    if( freqInvalid == false )
+    {
+        if( VerifyTxFreq( channelAdd->NewChannel->Frequency ) == false )
+        {
+            freqInvalid = true;
+        }
+    }
+
+    // Check status
+    if( ( drInvalid == true ) && ( freqInvalid == true ) )
+    {
+        return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
+    }
+    if( drInvalid == true )
+    {
+        return LORAMAC_STATUS_DATARATE_INVALID;
+    }
+    if( freqInvalid == true )
+    {
+        return LORAMAC_STATUS_FREQUENCY_INVALID;
+    }
+
+    memcpy1( ( uint8_t* )( Channels + id ), ( uint8_t* )channelAdd->NewChannel, sizeof( Channels[id] ) );
+    Channels[id].Band = band;
+    ChannelsMask[0] |= ( 1 << id );
+    return LORAMAC_STATUS_OK;
+}
+
+bool RegionEU433ChannelsRemove( ChannelRemoveParams_t* channelRemove  )
+{
+    uint8_t id = channelRemove->ChannelId;
+
+    if( id < EU433_NUMB_DEFAULT_CHANNELS )
+    {
+        return false;
+    }
+
+    // Remove the channel from the list of channels
+    Channels[id] = ( ChannelParams_t ){ 0, 0, { 0 }, 0 };
+
+    return RegionCommonChanDisable( ChannelsMask, id, EU433_MAX_NB_CHANNELS );
+}
+
+void RegionEU433SetContinuousWave( ContinuousWaveParams_t* continuousWave )
+{
+    int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
+    int8_t phyTxPower = 0;
+    uint32_t frequency = Channels[continuousWave->Channel].Frequency;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
+
+    Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
+}
+
+uint8_t RegionEU433ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
+{
+    int8_t datarate = dr - drOffset;
+
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+    return datarate;
+}
diff --git a/net/lora/node/src/mac/region/RegionEU433.h b/net/lora/node/src/mac/region/RegionEU433.h
new file mode 100644
index 000000000..586559bdd
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionEU433.h
@@ -0,0 +1,468 @@
+/*!
+ * \file      RegionEU433.h
+ *
+ * \brief     Region definition for EU433
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+ *
+ * \defgroup  REGIONEU433 Region EU433
+ *            Implementation according to LoRaWAN Specification v1.0.2.
+ * \{
+ */
+#ifndef __REGION_EU433_H__
+#define __REGION_EU433_H__
+
+#include "node/mac/LoRaMac.h"
+
+/*!
+ * LoRaMac maximum number of channels
+ */
+#define EU433_MAX_NB_CHANNELS                       16
+
+/*!
+ * Number of default channels
+ */
+#define EU433_NUMB_DEFAULT_CHANNELS                 3
+
+/*!
+ * Number of channels to apply for the CF list
+ */
+#define EU433_NUMB_CHANNELS_CF_LIST                 5
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define EU433_TX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define EU433_TX_MAX_DATARATE                       DR_7
+
+/*!
+ * Minimal datarate that can be used by the node
+ */
+#define EU433_RX_MIN_DATARATE                       DR_0
+
+/*!
+ * Maximal datarate that can be used by the node
+ */
+#define EU433_RX_MAX_DATARATE                       DR_7
+
+/*!
+ * Default datarate used by the node
+ */
+#define EU433_DEFAULT_DATARATE                      DR_0
+
+/*!
+ * Minimal Rx1 receive datarate offset
+ */
+#define EU433_MIN_RX1_DR_OFFSET                     0
+
+/*!
+ * Maximal Rx1 receive datarate offset
+ */
+#define EU433_MAX_RX1_DR_OFFSET                     5
+
+/*!
+ * Default Rx1 receive datarate offset
+ */
+#define EU433_DEFAULT_RX1_DR_OFFSET                 0
+
+/*!
+ * Minimal Tx output power that can be used by the node
+ */
+#define EU433_MIN_TX_POWER                          TX_POWER_5
+
+/*!
+ * Maximal Tx output power that can be used by the node
+ */
+#define EU433_MAX_TX_POWER                          TX_POWER_0
+
+/*!
+ * Default Tx output power used by the node
+ */
+#define EU433_DEFAULT_TX_POWER                      TX_POWER_0
+
+/*!
+ * Default Max EIRP
+ */
+#define EU433_DEFAULT_MAX_EIRP                      12.15f
+
+/*!
+ * Default antenna gain
+ */
+#define EU433_DEFAULT_ANTENNA_GAIN                  2.15f
+
+/*!
+ * ADR Ack limit
+ */
+#define EU433_ADR_ACK_LIMIT                         64
+
+/*!
+ * ADR Ack delay
+ */
+#define EU433_ADR_ACK_DELAY                         32
+
+/*!
+ * Enabled or disabled the duty cycle
+ */
+#define EU433_DUTY_CYCLE_ENABLED                    1
+
+/*!
+ * Maximum RX window duration
+ */
+#define EU433_MAX_RX_WINDOW                         3000
+
+/*!
+ * Receive delay 1
+ */
+#define EU433_RECEIVE_DELAY1                        1000
+
+/*!
+ * Receive delay 2
+ */
+#define EU433_RECEIVE_DELAY2                        2000
+
+/*!
+ * Join accept delay 1
+ */
+#define EU433_JOIN_ACCEPT_DELAY1                    5000
+
+/*!
+ * Join accept delay 2
+ */
+#define EU433_JOIN_ACCEPT_DELAY2                    6000
+
+/*!
+ * Maximum frame counter gap
+ */
+#define EU433_MAX_FCNT_GAP                          16384
+
+/*!
+ * Ack timeout
+ */
+#define EU433_ACKTIMEOUT                            2000
+
+/*!
+ * Random ack timeout limits
+ */
+#define EU433_ACK_TIMEOUT_RND                       1000
+
+/*!
+ * Verification of default datarate
+ */
+#if ( EU433_DEFAULT_DATARATE > DR_5 )
+#error "A default DR higher than DR_5 may lead to connectivity loss."
+#endif
+
+/*!
+ * Second reception window channel frequency definition.
+ */
+#define EU433_RX_WND_2_FREQ                         434665000
+
+/*!
+ * Second reception window channel datarate definition.
+ */
+#define EU433_RX_WND_2_DR                           DR_0
+
+/*!
+ * LoRaMac maximum number of bands
+ */
+#define EU433_MAX_NB_BANDS                          1
+
+/*!
+ * Band 0 definition
+ * { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
+ */
+#define EU433_BAND0                                 { 100, EU433_MAX_TX_POWER, 0, 0, 0 } //  1.0 %
+
+/*!
+ * LoRaMac default channel 1
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define EU433_LC1                                   { 433175000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac default channel 2
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define EU433_LC2                                   { 433375000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac default channel 3
+ * Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
+ */
+#define EU433_LC3                                   { 433575000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
+
+/*!
+ * LoRaMac channels which are allowed for the join procedure
+ */
+#define EU433_JOIN_CHANNELS                         ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
+
+/*!
+ * Data rates table definition
+ */
+static const uint8_t DataratesEU433[] = { 12, 11, 10,  9,  8,  7,  7, 50 };
+
+/*!
+ * Bandwidths table definition in Hz
+ */
+static const uint32_t BandwidthsEU433[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Cannot operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateEU433[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
+
+/*!
+ * Maximum payload with respect to the datarate index. Can operate with repeater.
+ */
+static const uint8_t MaxPayloadOfDatarateRepeaterEU433[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
+
+/*!
+ * \brief The function gets a value of a specific phy attribute.
+ *
+ * \param [IN] getPhy Pointer to the function parameters.
+ *
+ * \retval Returns a structure containing the PHY parameter.
+ */
+PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy );
+
+/*!
+ * \brief Updates the last TX done parameters of the current channel.
+ *
+ * \param [IN] txDone Pointer to the function parameters.
+ */
+void RegionEU433SetBandTxDone( SetBandTxDoneParams_t* txDone );
+
+/*!
+ * \brief Initializes the channels masks and the channels.
+ *
+ * \param [IN] type Sets the initialization type.
+ */
+void RegionEU433InitDefaults( InitType_t type );
+
+/*!
+ * \brief Verifies a parameter.
+ *
+ * \param [IN] verify Pointer to the function parameters.
+ *
+ * \param [IN] type Sets the initialization type.
+ *
+ * \retval Returns true, if the parameter is valid.
+ */
+bool RegionEU433Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
+
+/*!
+ * \brief The function parses the input buffer and sets up the channels of the
+ *        CF list.
+ *
+ * \param [IN] applyCFList Pointer to the function parameters.
+ */
+void RegionEU433ApplyCFList( ApplyCFListParams_t* applyCFList );
+
+/*!
+ * \brief Sets a channels mask.
+ *
+ * \param [IN] chanMaskSet Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channels mask could be set.
+ */
+bool RegionEU433ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
+
+/*!
+ * \brief Calculates the next datarate to set, when ADR is on or off.
+ *
+ * \param [IN] adrNext Pointer to the function parameters.
+ *
+ * \param [OUT] drOut The calculated datarate for the next TX.
+ *
+ * \param [OUT] txPowOut The TX power for the next TX.
+ *
+ * \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
+ *
+ * \retval Returns true, if an ADR request should be performed.
+ */
+bool RegionEU433AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
+
+/*!
+ * Computes the Rx window timeout and offset.
+ *
+ * \param [IN] datarate     Rx window datarate index to be used
+ *
+ * \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
+ *
+ * \param [IN] rxError      System maximum timing error of the receiver. In milliseconds
+ *                          The receiver will turn on in a [-rxError : +rxError] ms
+ *                          interval around RxOffset
+ *
+ * \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
+ */
+void RegionEU433ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
+
+/*!
+ * \brief Configuration of the RX windows.
+ *
+ * \param [IN] rxConfig Pointer to the function parameters.
+ *
+ * \param [OUT] datarate The datarate index which was set.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
+
+/*!
+ * \brief TX configuration.
+ *
+ * \param [IN] txConfig Pointer to the function parameters.
+ *
+ * \param [OUT] txPower The tx power index which was set.
+ *
+ * \param [OUT] txTimeOnAir The time-on-air of the frame.
+ *
+ * \retval Returns true, if the configuration was applied successfully.
+ */
+bool RegionEU433TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
+
+/*!
+ * \brief The function processes a Link ADR Request.
+ *
+ * \param [IN] linkAdrReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionEU433LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
+
+/*!
+ * \brief The function processes a RX Parameter Setup Request.
+ *
+ * \param [IN] rxParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionEU433RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
+
+/*!
+ * \brief The function processes a Channel Request.
+ *
+ * \param [IN] newChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionEU433NewChannelReq( NewChannelReqParams_t* newChannelReq );
+
+/*!
+ * \brief The function processes a TX ParamSetup Request.
+ *
+ * \param [IN] txParamSetupReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ *         Returns -1, if the functionality is not implemented. In this case, the end node
+ *         shall not process the command.
+ */
+int8_t RegionEU433TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
+
+/*!
+ * \brief The function processes a DlChannel Request.
+ *
+ * \param [IN] dlChannelReq Pointer to the function parameters.
+ *
+ * \retval Returns the status of the operation, according to the LoRaMAC specification.
+ */
+uint8_t RegionEU433DlChannelReq( DlChannelReqParams_t* dlChannelReq );
+
+/*!
+ * \brief Alternates the datarate of the channel for the join request.
+ *
+ * \param [IN] currentDr Current datarate.
+ *
+ * \retval Datarate to apply.
+ */
+int8_t RegionEU433AlternateDr( int8_t currentDr );
+
+/*!
+ * \brief Calculates the back-off time.
+ *
+ * \param [IN] calcBackOff Pointer to the function parameters.
+ */
+void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff );
+
+/*!
+ * \brief Searches and set the next random available channel
+ *
+ * \param [OUT] channel Next channel to use for TX.
+ *
+ * \param [OUT] time Time to wait for the next transmission according to the duty
+ *              cycle.
+ *
+ * \param [OUT] aggregatedTimeOff Updates the aggregated time off.
+ *
+ * \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
+ */
+LoRaMacStatus_t RegionEU433NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
+
+/*!
+ * \brief Adds a channel.
+ *
+ * \param [IN] channelAdd Pointer to the function parameters.
+ *
+ * \retval Status of the operation.
+ */
+LoRaMacStatus_t RegionEU433ChannelAdd( ChannelAddParams_t* channelAdd );
+
+/*!
+ * \brief Removes a channel.
+ *
+ * \param [IN] channelRemove Pointer to the function parameters.
+ *
+ * \retval Returns true, if the channel was removed successfully.
+ */
+bool RegionEU433ChannelsRemove( ChannelRemoveParams_t* channelRemove  );
+
+/*!
+ * \brief Sets the radio into continuous wave mode.
+ *
+ * \param [IN] continuousWave Pointer to the function parameters.
+ */
+void RegionEU433SetContinuousWave( ContinuousWaveParams_t* continuousWave );
+
+/*!
+ * \brief Computes new datarate according to the given offset
+ *
+ * \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
+ *
+ * \param [IN] dr Current datarate
+ *
+ * \param [IN] drOffset Offset to be applied
+ *
+ * \retval newDr Computed datarate.
+ */
+uint8_t RegionEU433ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
+
+/*! \} defgroup REGIONEU433 */
+
+#endif // __REGION_EU433_H__
diff --git a/net/lora/node/src/mac/region/RegionEU868.c b/net/lora/node/src/mac/region/RegionEU868.c
new file mode 100644
index 000000000..64b82a68d
--- /dev/null
+++ b/net/lora/node/src/mac/region/RegionEU868.c
@@ -0,0 +1,1050 @@
+/*!
+ * \file      RegionEU868.c
+ *
+ * \brief     Region implementation for EU868
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013-2017 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jaeckle ( STACKFORCE )
+*/
+#include "node/utilities.h"
+#include "RegionCommon.h"
+#include "RegionEU868.h"
+
+// Definitions
+#define CHANNELS_MASK_SIZE              1
+
+// Global attributes
+/*!
+ * LoRaMAC channels
+ */
+static ChannelParams_t Channels[EU868_MAX_NB_CHANNELS];
+
+/*!
+ * LoRaMac bands
+ */
+static Band_t Bands[EU868_MAX_NB_BANDS] =
+{
+    EU868_BAND0,
+    EU868_BAND1,
+    EU868_BAND2,
+    EU868_BAND3,
+    EU868_BAND4,
+};
+
+/*!
+ * LoRaMac channels mask
+ */
+static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
+
+/*!
+ * LoRaMac channels default mask
+ */
+static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
+
+// Static functions
+static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
+{
+    uint8_t nextLowerDr = 0;
+
+    if( dr == minDr )
+    {
+        nextLowerDr = minDr;
+    }
+    else
+    {
+        nextLowerDr = dr - 1;
+    }
+    return nextLowerDr;
+}
+
+static uint32_t GetBandwidth( uint32_t drIndex )
+{
+    switch( BandwidthsEU868[drIndex] )
+    {
+        default:
+        case 125000:
+            return 0;
+        case 250000:
+            return 1;
+        case 500000:
+            return 2;
+    }
+}
+
+static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
+{
+    int8_t txPowerResult = txPower;
+
+    // Limit tx power to the band max
+    txPowerResult =  MAX( txPower, maxBandTxPower );
+
+    return txPowerResult;
+}
+
+static bool VerifyTxFreq( uint32_t freq, uint8_t *band )
+{
+    // Check radio driver support
+    if( Radio.CheckRfFrequency( freq ) == false )
+    {
+        return false;
+    }
+
+    // Check frequency bands
+    if( ( freq >= 863000000 ) && ( freq < 865000000 ) )
+    {
+        *band = 2;
+    }
+    else if( ( freq >= 865000000 ) && ( freq <= 868000000 ) )
+    {
+        *band = 0;
+    }
+    else if( ( freq > 868000000 ) && ( freq <= 868600000 ) )
+    {
+        *band = 1;
+    }
+    else if( ( freq >= 868700000 ) && ( freq <= 869200000 ) )
+    {
+        *band = 2;
+    }
+    else if( ( freq >= 869400000 ) && ( freq <= 869650000 ) )
+    {
+        *band = 3;
+    }
+    else if( ( freq >= 869700000 ) && ( freq <= 870000000 ) )
+    {
+        *band = 4;
+    }
+    else
+    {
+        return false;
+    }
+    return true;
+}
+
+static uint8_t CountNbOfEnabledChannels( bool joined, uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
+{
+    uint8_t nbEnabledChannels = 0;
+    uint8_t delayTransmission = 0;
+
+    for( uint8_t i = 0, k = 0; i < EU868_MAX_NB_CHANNELS; i += 16, k++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {
+            if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
+            {
+                if( channels[i + j].Frequency == 0 )
+                { // Check if the channel is enabled
+                    continue;
+                }
+                if( joined == false )
+                {
+                    if( ( EU868_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
+                    {
+                        continue;
+                    }
+                }
+                if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
+                                              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
+                    delayTransmission++;
+                    continue;
+                }
+                enabledChannels[nbEnabledChannels++] = i + j;
+            }
+        }
+    }
+
+    *delayTx = delayTransmission;
+    return nbEnabledChannels;
+}
+
+PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy )
+{
+    PhyParam_t phyParam = { 0 };
+
+    switch( getPhy->Attribute )
+    {
+        case PHY_MIN_RX_DR:
+        {
+            phyParam.Value = EU868_RX_MIN_DATARATE;
+            break;
+        }
+        case PHY_MIN_TX_DR:
+        {
+            phyParam.Value = EU868_TX_MIN_DATARATE;
+            break;
+        }
+        case PHY_DEF_TX_DR:
+        {
+            phyParam.Value = EU868_DEFAULT_DATARATE;
+            break;
+        }
+        case PHY_NEXT_LOWER_TX_DR:
+        {
+            phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, EU868_TX_MIN_DATARATE );
+            break;
+        }
+        case PHY_DEF_TX_POWER:
+        {
+            phyParam.Value = EU868_DEFAULT_TX_POWER;
+            break;
+        }
+        case PHY_MAX_PAYLOAD:
+        {
+            phyParam.Value = MaxPayloadOfDatarateEU868[getPhy->Datarate];
+            break;
+        }
+        case PHY_MAX_PAYLOAD_REPEATER:
+        {
+            phyParam.Value = MaxPayloadOfDatarateRepeaterEU868[getPhy->Datarate];
+            break;
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            phyParam.Value = EU868_DUTY_CYCLE_ENABLED;
+            break;
+        }
+        case PHY_MAX_RX_WINDOW:
+        {
+            phyParam.Value = EU868_MAX_RX_WINDOW;
+            break;
+        }
+        case PHY_RECEIVE_DELAY1:
+        {
+            phyParam.Value = EU868_RECEIVE_DELAY1;
+            break;
+        }
+        case PHY_RECEIVE_DELAY2:
+        {
+            phyParam.Value = EU868_RECEIVE_DELAY2;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY1:
+        {
+            phyParam.Value = EU868_JOIN_ACCEPT_DELAY1;
+            break;
+        }
+        case PHY_JOIN_ACCEPT_DELAY2:
+        {
+            phyParam.Value = EU868_JOIN_ACCEPT_DELAY2;
+            break;
+        }
+        case PHY_MAX_FCNT_GAP:
+        {
+            phyParam.Value = EU868_MAX_FCNT_GAP;
+            break;
+        }
+        case PHY_ACK_TIMEOUT:
+        {
+            phyParam.Value = ( EU868_ACKTIMEOUT + randr( -EU868_ACK_TIMEOUT_RND, EU868_ACK_TIMEOUT_RND ) );
+            break;
+        }
+        case PHY_DEF_DR1_OFFSET:
+        {
+            phyParam.Value = EU868_DEFAULT_RX1_DR_OFFSET;
+            break;
+        }
+        case PHY_DEF_RX2_FREQUENCY:
+        {
+            phyParam.Value = EU868_RX_WND_2_FREQ;
+            break;
+        }
+        case PHY_DEF_RX2_DR:
+        {
+            phyParam.Value = EU868_RX_WND_2_DR;
+            break;
+        }
+        case PHY_CHANNELS_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsMask;
+            break;
+        }
+        case PHY_CHANNELS_DEFAULT_MASK:
+        {
+            phyParam.ChannelsMask = ChannelsDefaultMask;
+            break;
+        }
+        case PHY_MAX_NB_CHANNELS:
+        {
+            phyParam.Value = EU868_MAX_NB_CHANNELS;
+            break;
+        }
+        case PHY_CHANNELS:
+        {
+            phyParam.Channels = Channels;
+            break;
+        }
+        case PHY_DEF_UPLINK_DWELL_TIME:
+        case PHY_DEF_DOWNLINK_DWELL_TIME:
+        {
+            phyParam.Value = 0;
+            break;
+        }
+        case PHY_DEF_MAX_EIRP:
+        {
+            phyParam.fValue = EU868_DEFAULT_MAX_EIRP;
+            break;
+        }
+        case PHY_DEF_ANTENNA_GAIN:
+        {
+            phyParam.fValue = EU868_DEFAULT_ANTENNA_GAIN;
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+
+    return phyParam;
+}
+
+void RegionEU868SetBandTxDone( SetBandTxDoneParams_t* txDone )
+{
+    RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
+}
+
+void RegionEU868InitDefaults( InitType_t type )
+{
+    switch( type )
+    {
+        case INIT_TYPE_INIT:
+        {
+            // Channels
+            Channels[0] = ( ChannelParams_t ) EU868_LC1;
+            Channels[1] = ( ChannelParams_t ) EU868_LC2;
+            Channels[2] = ( ChannelParams_t ) EU868_LC3;
+
+            // Initialize the channels default mask
+            ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+            // Update the channels mask
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        case INIT_TYPE_RESTORE:
+        {
+            // Restore channels default mask
+            ChannelsMask[0] |= ChannelsDefaultMask[0];
+            break;
+        }
+        case INIT_TYPE_APP_DEFAULTS:
+        {
+            // Update the channels mask defaults
+            RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 1 );
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+bool RegionEU868Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
+{
+    switch( phyAttribute )
+    {
+        case PHY_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU868_TX_MIN_DATARATE, EU868_TX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
+        }
+        case PHY_RX_DR:
+        {
+            return RegionCommonValueInRange( verify->DatarateParams.Datarate, EU868_RX_MIN_DATARATE, EU868_RX_MAX_DATARATE );
+        }
+        case PHY_DEF_TX_POWER:
+        case PHY_TX_POWER:
+        {
+            // Remark: switched min and max!
+            return RegionCommonValueInRange( verify->TxPower, EU868_MAX_TX_POWER, EU868_MIN_TX_POWER );
+        }
+        case PHY_DUTY_CYCLE:
+        {
+            return EU868_DUTY_CYCLE_ENABLED;
+        }
+        default:
+            return false;
+    }
+}
+
+void RegionEU868ApplyCFList( ApplyCFListParams_t* applyCFList )
+{
+    ChannelParams_t newChannel;
+    ChannelAddParams_t channelAdd;
+    ChannelRemoveParams_t channelRemove;
+
+    // Setup default datarate range
+    newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0;
+
+    // Size of the optional CF list
+    if( applyCFList->Size != 16 )
+    {
+        return;
+    }
+
+    // Last byte is RFU, don't take it into account
+    for( uint8_t i = 0, chanIdx = EU868_NUMB_DEFAULT_CHANNELS; chanIdx < EU868_MAX_NB_CHANNELS; i+=3, chanIdx++ )
+    {
+        if( chanIdx < ( EU868_NUMB_CHANNELS_CF_LIST + EU868_NUMB_DEFAULT_CHANNELS ) )
+        {
+            // Channel frequency
+            newChannel.Frequency = (uint32_t) applyCFList->Payload[i];
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
+            newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
+            newChannel.Frequency *= 100;
+
+            // Initialize alternative frequency to 0
+            newChannel.Rx1Frequency = 0;
+        }
+        else
+        {
+            newChannel.Frequency = 0;
+            newChannel.DrRange.Value = 0;
+            newChannel.Rx1Frequency = 0;
+        }
+
+        if( newChannel.Frequency != 0 )
+        {
+            channelAdd.NewChannel = &newChannel;
+            channelAdd.ChannelId = chanIdx;
+
+            // Try to add all channels
+            RegionEU868ChannelAdd( &channelAdd );
+        }
+        else
+        {
+            channelRemove.ChannelId = chanIdx;
+
+            RegionEU868ChannelsRemove( &channelRemove );
+        }
+    }
+}
+
+bool RegionEU868ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
+{
+    switch( chanMaskSet->ChannelsMaskType )
+    {
+        case CHANNELS_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        case CHANNELS_DEFAULT_MASK:
+        {
+            RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 1 );
+            break;
+        }
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool RegionEU868AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
+{
+    bool adrAckReq = false;
+    int8_t datarate = adrNext->Datarate;
+    int8_t txPower = adrNext->TxPower;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+
+    // Report back the adr ack counter
+    *adrAckCounter = adrNext->AdrAckCounter;
+
+    if( adrNext->AdrEnabled == true )
+    {
+        if( datarate == EU868_TX_MIN_DATARATE )
+        {
+            *adrAckCounter = 0;
+            adrAckReq = false;
+        }
+        else
+        {
+            if( adrNext->AdrAckCounter >= EU868_ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+                txPower = EU868_MAX_TX_POWER;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( adrNext->AdrAckCounter >= ( EU868_ADR_ACK_LIMIT + EU868_ADR_ACK_DELAY ) )
+            {
+                if( ( adrNext->AdrAckCounter % EU868_ADR_ACK_DELAY ) == 1 )
+                {
+                    // Decrease the datarate
+                    getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
+                    getPhy.Datarate = datarate;
+                    getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
+                    phyParam = RegionEU868GetPhyParam( &getPhy );
+                    datarate = phyParam.Value;
+
+                    if( datarate == EU868_TX_MIN_DATARATE )
+                    {
+                        // We must set adrAckReq to false as soon as we reach the lowest datarate
+                        adrAckReq = false;
+                        if( adrNext->UpdateChanMask == true )
+                        {
+                            // Re-enable default channels
+                            ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    *drOut = datarate;
+    *txPowOut = txPower;
+    return adrAckReq;
+}
+
+void RegionEU868ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
+{
+    double tSymbol = 0.0;
+
+    // Get the datarate, perform a boundary check
+    rxConfigParams->Datarate = MIN( datarate, EU868_RX_MAX_DATARATE );
+    rxConfigParams->Bandwidth = GetBandwidth( rxConfigParams->Datarate );
+
+    if( rxConfigParams->Datarate == DR_7 )
+    { // FSK
+        tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesEU868[rxConfigParams->Datarate] );
+    }
+    else
+    { // LoRa
+        tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesEU868[rxConfigParams->Datarate], BandwidthsEU868[rxConfigParams->Datarate] );
+    }
+    rxConfigParams->tsymbol = tSymbol;
+
+    RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, Radio.GetWakeupTime( ), &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
+}
+
+bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
+{
+    RadioModems_t modem;
+    int8_t dr = rxConfig->Datarate;
+    uint8_t maxPayload = 0;
+    int8_t phyDr = 0;
+    uint32_t frequency = rxConfig->Frequency;
+
+    if( Radio.GetStatus( ) != RF_IDLE )
+    {
+        return false;
+    }
+
+    if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
+    {
+        // Apply window 1 frequency
+        frequency = Channels[rxConfig->Channel].Frequency;
+        // Apply the alternative RX 1 window frequency, if it is available
+        if( Channels[rxConfig->Channel].Rx1Frequency != 0 )
+        {
+            frequency = Channels[rxConfig->Channel].Rx1Frequency;
+        }
+    }
+
+    // Read the physical datarate from the datarates table
+    phyDr = DataratesEU868[dr];
+
+    lora_node_log(LORA_NODE_LOG_RX_CFG, rxConfig->Bandwidth,
+                  ((uint16_t)dr << 16) | phyDr, frequency);
+
+    Radio.SetChannel( frequency );
+
+    // Radio configuration
+    if( dr == DR_7 )
+    {
+        modem = MODEM_FSK;
+        Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
+    }
+
+    if( rxConfig->RepeaterSupport == true )
+    {
+        maxPayload = MaxPayloadOfDatarateRepeaterEU868[dr];
+    }
+    else
+    {
+        maxPayload = MaxPayloadOfDatarateEU868[dr];
+    }
+
+    Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
+
+    *datarate = (uint8_t) dr;
+    return true;
+}
+
+bool RegionEU868TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
+{
+    RadioModems_t modem;
+    int8_t phyDr = DataratesEU868[txConfig->Datarate];
+    int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
+    uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
+    int8_t phyTxPower = 0;
+
+    // Calculate physical TX power
+    phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
+
+    // Setup the radio frequency
+    Radio.SetChannel( Channels[txConfig->Channel].Frequency );
+
+    if( txConfig->Datarate == DR_7 )
+    { // High Speed FSK channel
+        modem = MODEM_FSK;
+        Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 3000 );
+    }
+    else
+    {
+        modem = MODEM_LORA;
+        Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
+    }
+
+    // Setup maximum payload lenght of the radio driver
+    Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
+    // Get the time-on-air of the next tx frame
+    *txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
+
+    *txPower = txPowerLimited;
+
+    lora_node_log(LORA_NODE_LOG_TX_SETUP, phyTxPower,
+                  ((uint16_t)phyDr << 8) | bandwidth,
+                  Channels[txConfig->Channel].Frequency);
+    return true;
+}
+
+uint8_t RegionEU868LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
+{
+    uint8_t status = 0x07;
+    RegionCommonLinkAdrParams_t linkAdrParams;
+    uint8_t nextIndex = 0;
+    uint8_t bytesProcessed = 0;
+    uint16_t chMask = 0;
+    GetPhyParams_t getPhy;
+    PhyParam_t phyParam;
+    RegionCommonLinkAdrReqVerifyParams_t linkAdrVerifyParams;
+
+    while( bytesProcessed < linkAdrReq->PayloadSize )
+    {
+        // Get ADR request parameters
+        nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
+
+        if( nextIndex == 0 )
+            break; // break loop, since no more request has been found
+
+        // Update bytes processed
+        bytesProcessed += nextIndex;
+
+        // Revert status, as we only check the last ADR request for the channel mask KO
+        status = 0x07;
+
+        // Setup temporary channels mask
+        chMask = linkAdrParams.ChMask;
+
+        // Verify channels mask
+        if( ( linkAdrParams.ChMaskCtrl == 0 ) && ( chMask == 0 ) )
+        {
+            status &= 0xFE; // Channel mask KO
+        }
+        else if( ( ( linkAdrParams.ChMaskCtrl >= 1 ) && ( linkAdrParams.ChMaskCtrl <= 5 )) ||
+                ( linkAdrParams.ChMaskCtrl >= 7 ) )
+        {
+            // RFU
+            status &= 0xFE; // Channel mask KO
+        }
+        else
+        {
+            for( uint8_t i = 0; i < EU868_MAX_NB_CHANNELS; i++ )
+            {
+                if( linkAdrParams.ChMaskCtrl == 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
+                    }
+                }
+            }
+        }
+    }
+
+    // Get the minimum possible datarate

  (This diff was longer than 20,000 lines, and has been truncated...)


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services