LoRaWAN-lib-st-murata

Dependents:   DISCO-L072CZ-LRWAN1-base

Fork of LoRaWAN-lib by Semtech

Files at this revision

API Documentation at this revision

Comitter:
mluis
Date:
Tue Jan 05 16:41:54 2016 +0000
Parent:
1:91e4e6c60d1e
Child:
3:b9d87593a8ae
Commit message:
Synchronized with https://github.com/Lora-net/LoRaMac-node git revision a2226468d470eceb251338e1acfb24cfd121effa

Changed in this revision

LoRaMac-api-v3.cpp Show annotated file Show diff for this revision Revisions of this file
LoRaMac-api-v3.h Show annotated file Show diff for this revision Revisions of this file
LoRaMac-board.h Show annotated file Show diff for this revision Revisions of this file
LoRaMac.cpp Show annotated file Show diff for this revision Revisions of this file
LoRaMac.h Show annotated file Show diff for this revision Revisions of this file
LoRaMacCrypto.cpp Show annotated file Show diff for this revision Revisions of this file
LoRaMacCrypto.h Show annotated file Show diff for this revision Revisions of this file
LoRaMacTest.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaMac-api-v3.cpp	Tue Jan 05 16:41:54 2016 +0000
@@ -0,0 +1,626 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (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 )
+*/
+#include "board.h"
+
+#include "LoRaMac-api-v3.h"
+#include "LoRaMacTest.h"
+
+/*!
+ *  Extern function declarations.
+ */
+extern LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort,
+                             void *fBuffer, uint16_t fBufferSize );
+extern LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl,
+                                     uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+extern LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
+extern uint32_t LoRaMacState;
+extern LoRaMacFlags_t LoRaMacFlags;
+
+/*!
+ * Static variables
+ */
+static LoRaMacEventFlags_t LoRaMacEventFlags;
+static LoRaMacEventInfo_t LoRaMacEventInfo;
+static LoRaMacPrimitives_t LoRaMacPrimitives;
+static LoRaMacCallback_t LoRaMacCallback;
+static LoRaMacCallbacks_t LoRaMacCallbacks;
+
+/*!
+ * \brief   MCPS-Confirm event function
+ *
+ * \param   [IN] mcpsConfirm - Pointer to the confirm structure,
+ *               containing confirm attributes.
+ */
+static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
+{
+    LoRaMacEventInfo.Status = mcpsConfirm->Status;
+    LoRaMacEventFlags.Bits.Tx = 1;
+
+    LoRaMacEventInfo.TxDatarate = mcpsConfirm->Datarate;
+    LoRaMacEventInfo.TxNbRetries = mcpsConfirm->NbRetries;
+    LoRaMacEventInfo.TxAckReceived = mcpsConfirm->AckReceived;
+
+    if( ( LoRaMacFlags.Bits.McpsInd != 1 ) && ( LoRaMacFlags.Bits.MlmeReq != 1 ) )
+    {
+        LoRaMacCallbacks.MacEvent( &LoRaMacEventFlags, &LoRaMacEventInfo );
+        LoRaMacEventFlags.Value = 0;
+    }
+}
+
+/*!
+ * \brief   MCPS-Indication event function
+ *
+ * \param   [IN] mcpsIndication - Pointer to the indication structure,
+ *               containing indication attributes.
+ */
+static void McpsIndication( McpsIndication_t *mcpsIndication )
+{
+    LoRaMacEventInfo.Status = mcpsIndication->Status;
+    LoRaMacEventFlags.Bits.Rx = 1;
+    LoRaMacEventFlags.Bits.RxSlot = mcpsIndication->RxSlot;
+    LoRaMacEventFlags.Bits.Multicast = mcpsIndication->Multicast;
+    if( mcpsIndication->RxData == true )
+    {
+        LoRaMacEventFlags.Bits.RxData = 1;
+    }
+
+    LoRaMacEventInfo.RxPort = mcpsIndication->Port;
+    LoRaMacEventInfo.RxBuffer = mcpsIndication->Buffer;
+    LoRaMacEventInfo.RxBufferSize = mcpsIndication->BufferSize;
+    LoRaMacEventInfo.RxRssi = mcpsIndication->Rssi;
+    LoRaMacEventInfo.RxSnr = mcpsIndication->Snr;
+
+    LoRaMacCallbacks.MacEvent( &LoRaMacEventFlags, &LoRaMacEventInfo );
+    LoRaMacEventFlags.Value = 0;
+}
+
+/*!
+ * \brief   MLME-Confirm event function
+ *
+ * \param   [IN] mlmeConfirm - Pointer to the confirm structure,
+ *               containing confirm attributes.
+ */
+static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
+{
+    if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
+    {
+        switch( mlmeConfirm->MlmeRequest )
+        {
+            case MLME_JOIN:
+            {
+                 // Status is OK, node has joined the network
+                LoRaMacEventInfo.Status = mlmeConfirm->Status;
+                LoRaMacEventFlags.Bits.Tx = 1;
+                LoRaMacEventFlags.Bits.Rx = 1;
+                LoRaMacEventFlags.Bits.JoinAccept = 1;
+                break;
+            }
+            case MLME_LINK_CHECK:
+            {
+                LoRaMacEventFlags.Bits.Tx = 1;
+                LoRaMacEventFlags.Bits.Rx = 1;
+                LoRaMacEventFlags.Bits.LinkCheck = 1;
+
+                LoRaMacEventInfo.DemodMargin = mlmeConfirm->DemodMargin;
+                LoRaMacEventInfo.NbGateways = mlmeConfirm->NbGateways;
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if( LoRaMacFlags.Bits.McpsInd != 1 )
+    {
+        LoRaMacCallbacks.MacEvent( &LoRaMacEventFlags, &LoRaMacEventInfo );
+        LoRaMacEventFlags.Value = 0;
+    }
+}
+
+void LoRaMacInit( LoRaMacCallbacks_t *callbacks )
+{
+    LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
+    LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
+    LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
+
+    LoRaMacCallbacks.MacEvent = callbacks->MacEvent;
+    LoRaMacCallbacks.GetBatteryLevel = callbacks->GetBatteryLevel;
+    LoRaMacCallback.GetBatteryLevel = callbacks->GetBatteryLevel;
+
+    LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallback );
+}
+
+void LoRaMacSetAdrOn( bool enable )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_ADR;
+    mibSet.Param.AdrEnable = enable;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_NET_ID;
+    mibSet.Param.NetID = netID;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+
+    mibSet.Type = MIB_DEV_ADDR;
+    mibSet.Param.DevAddr = devAddr;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+
+    mibSet.Type = MIB_NWK_SKEY;
+    mibSet.Param.NwkSKey = nwkSKey;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+
+    mibSet.Type = MIB_APP_SKEY;
+    mibSet.Param.AppSKey = appSKey;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+
+    mibSet.Type = MIB_NETWORK_JOINED;
+    mibSet.Param.IsNetworkJoined = true;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam )
+{
+    LoRaMacMulticastChannelLink( channelParam );
+}
+
+void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam )
+{
+    LoRaMacMulticastChannelUnlink( channelParam );
+}
+
+uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey )
+{
+    MlmeReq_t mlmeRequest;
+    uint8_t status;
+
+    mlmeRequest.Type = MLME_JOIN;
+    mlmeRequest.Req.Join.AppEui = appEui;
+    mlmeRequest.Req.Join.AppKey = appKey;
+    mlmeRequest.Req.Join.DevEui = devEui;
+
+    switch( LoRaMacMlmeRequest( &mlmeRequest ) )
+    {
+        case LORAMAC_STATUS_OK:
+        {
+            status = 0;
+            break;
+        }
+        case LORAMAC_STATUS_BUSY:
+        {
+            status = 1;
+            break;
+        }
+        case LORAMAC_STATUS_NO_NETWORK_JOINED:
+        {
+            status = 2;
+            break;
+        }
+        case LORAMAC_STATUS_LENGTH_ERROR:
+        case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR:
+        {
+            status = 3;
+            break;
+        }
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+        {
+            status = 4;
+            break;
+        }
+        case LORAMAC_STATUS_DEVICE_OFF:
+        {
+            status = 6;
+            break;
+        }
+        default:
+        {
+            status = 1;
+            break;
+        }
+    }
+
+    return status;
+}
+
+uint8_t LoRaMacLinkCheckReq( void )
+{
+    MlmeReq_t mlmeRequest;
+    uint8_t status;
+
+    mlmeRequest.Type = MLME_LINK_CHECK;
+
+    switch( LoRaMacMlmeRequest( &mlmeRequest ) )
+    {
+        case LORAMAC_STATUS_OK:
+        {
+            status = 0;
+            break;
+        }
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+        {
+            status = 1;
+            break;
+        }
+        default:
+        {
+            status = 1;
+            break;
+        }
+    }
+
+    return status;
+}
+
+uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+{
+    MibRequestConfirm_t mibGet;
+    McpsReq_t mcpsRequest;
+    uint8_t retStatus;
+
+    memset1( ( uint8_t* )&LoRaMacEventInfo, 0, sizeof( LoRaMacEventInfo ) );
+
+    mibGet.Type = MIB_CHANNELS_DATARATE;
+    LoRaMacMibGetRequestConfirm( &mibGet );
+
+    mcpsRequest.Type = MCPS_UNCONFIRMED;
+    mcpsRequest.Req.Unconfirmed.fBuffer = fBuffer;
+    mcpsRequest.Req.Unconfirmed.fBufferSize = fBufferSize;
+    mcpsRequest.Req.Unconfirmed.fPort = fPort;
+    mcpsRequest.Req.Unconfirmed.Datarate = mibGet.Param.ChannelsDatarate;
+
+    switch( LoRaMacMcpsRequest( &mcpsRequest ) )
+    {
+        case LORAMAC_STATUS_OK:
+            retStatus = 0U;
+            break;
+        case LORAMAC_STATUS_BUSY:
+            retStatus = 1U;
+            break;
+        case LORAMAC_STATUS_NO_NETWORK_JOINED:
+            retStatus = 2U;
+            break;
+        case LORAMAC_STATUS_LENGTH_ERROR:
+        case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR:
+            retStatus = 3U;
+            break;
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+            retStatus = 4U;
+            break;
+        case LORAMAC_STATUS_DEVICE_OFF:
+            retStatus = 6U;
+            break;
+        default:
+            retStatus = 1U;
+            break;
+    }
+
+    return retStatus;
+}
+
+uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t nbRetries )
+{
+    MibRequestConfirm_t mibGet;
+    McpsReq_t mcpsRequest;
+    uint8_t retStatus;
+
+    memset1( ( uint8_t* )&LoRaMacEventInfo, 0, sizeof( LoRaMacEventInfo ) );
+
+    mibGet.Type = MIB_CHANNELS_DATARATE;
+    LoRaMacMibGetRequestConfirm( &mibGet );
+
+    mcpsRequest.Type = MCPS_CONFIRMED;
+    mcpsRequest.Req.Confirmed.fBuffer = fBuffer;
+    mcpsRequest.Req.Confirmed.fBufferSize = fBufferSize;
+    mcpsRequest.Req.Confirmed.fPort = fPort;
+    mcpsRequest.Req.Confirmed.nbRetries = nbRetries;
+    mcpsRequest.Req.Confirmed.Datarate = mibGet.Param.ChannelsDatarate;
+
+    switch( LoRaMacMcpsRequest( &mcpsRequest ) )
+    {
+        case LORAMAC_STATUS_OK:
+            retStatus = 0U;
+            break;
+        case LORAMAC_STATUS_BUSY:
+            retStatus = 1U;
+            break;
+        case LORAMAC_STATUS_NO_NETWORK_JOINED:
+            retStatus = 2U;
+            break;
+        case LORAMAC_STATUS_LENGTH_ERROR:
+        case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR:
+            retStatus = 3U;
+            break;
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+            retStatus = 4U;
+            break;
+        case LORAMAC_STATUS_DEVICE_OFF:
+            retStatus = 6U;
+            break;
+        default:
+            retStatus = 1U;
+            break;
+    }
+
+    return retStatus;
+}
+
+uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+{
+    uint8_t retStatus;
+
+    memset1( ( uint8_t* ) &LoRaMacEventInfo, 0, sizeof( LoRaMacEventInfo ) );
+
+    switch( Send( macHdr, fPort, fBuffer, fBufferSize ) )
+    {
+        case LORAMAC_STATUS_OK:
+            retStatus = 0U;
+            break;
+        case LORAMAC_STATUS_BUSY:
+            retStatus = 1U;
+            break;
+        case LORAMAC_STATUS_NO_NETWORK_JOINED:
+            retStatus = 2U;
+            break;
+        case LORAMAC_STATUS_LENGTH_ERROR:
+        case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR:
+            retStatus = 3U;
+            break;
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+            retStatus = 4U;
+            break;
+        case LORAMAC_STATUS_DEVICE_OFF:
+            retStatus = 6U;
+            break;
+        default:
+            retStatus = 1U;
+            break;
+    }
+
+    return retStatus;
+}
+
+uint8_t LoRaMacPrepareFrame( ChannelParams_t channel,LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+{
+    uint8_t retStatus;
+
+    switch( PrepareFrame( macHdr, fCtrl, fPort, fBuffer, fBufferSize ) )
+    {
+        case LORAMAC_STATUS_OK:
+            retStatus = 0U;
+            break;
+        case LORAMAC_STATUS_BUSY:
+            retStatus = 1U;
+            break;
+        case LORAMAC_STATUS_NO_NETWORK_JOINED:
+            retStatus = 2U;
+            break;
+        case LORAMAC_STATUS_LENGTH_ERROR:
+        case LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR:
+            retStatus = 3U;
+            break;
+        case LORAMAC_STATUS_SERVICE_UNKNOWN:
+            retStatus = 4U;
+            break;
+        default:
+            retStatus = 1U;
+            break;
+    }
+
+    return retStatus;
+}
+
+uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel )
+{
+    memset1( ( uint8_t* ) &LoRaMacEventInfo, 0, sizeof( LoRaMacEventInfo ) );
+
+    SendFrameOnChannel( channel );
+
+    /* SendFrameOnChannel has always status "OK" */
+    return 0;
+}
+
+uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+{
+    uint8_t status = 0;
+
+    if( ( LoRaMacState & 0x00000001 ) == 0x00000001 )
+    {
+        return 1; // MAC is busy transmitting a previous frame
+    }
+
+    status = LoRaMacPrepareFrame( channel, macHdr, fCtrl, fOpts, fPort, fBuffer, fBufferSize );
+    if( status != 0 )
+    {
+        return status;
+    }
+
+    LoRaMacEventInfo.TxNbRetries = 0;
+    LoRaMacEventInfo.TxAckReceived = false;
+
+    return LoRaMacSendFrameOnChannel( channel );
+}
+
+void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_DEVICE_CLASS;
+    mibSet.Param.Class = deviceClass;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetPublicNetwork( bool enable )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_PUBLIC_NETWORK;
+    mibSet.Param.EnablePublicNetwork = enable;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetDutyCycleOn( bool enable )
+{
+    LoRaMacTestSetDutyCycleOn( enable );
+}
+
+void LoRaMacSetChannel( uint8_t id, ChannelParams_t params )
+{
+    LoRaMacChannelAdd( id, params );
+}
+
+void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_RX2_CHANNEL;
+    mibSet.Param.Rx2Channel = param;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetChannelsMask( uint16_t *mask )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_CHANNELS_MASK;
+    mibSet.Param.ChannelsMask = mask;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetChannelsNbRep( uint8_t nbRep )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_CHANNELS_NB_REP;
+    mibSet.Param.ChannelNbRep = nbRep;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetMaxRxWindow( uint32_t delay )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_MAX_RX_WINDOW_DURATION;
+    mibSet.Param.MaxRxWindow = delay;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetReceiveDelay1( uint32_t delay )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_RECEIVE_DELAY_1;
+    mibSet.Param.ReceiveDelay1 = delay;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetReceiveDelay2( uint32_t delay )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_RECEIVE_DELAY_2;
+    mibSet.Param.ReceiveDelay2 = delay;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetJoinAcceptDelay1( uint32_t delay )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_JOIN_ACCEPT_DELAY_1;
+    mibSet.Param.JoinAcceptDelay1 = delay;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_JOIN_ACCEPT_DELAY_2;
+    mibSet.Param.JoinAcceptDelay2 = delay;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetChannelsDatarate( int8_t datarate )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_CHANNELS_DATARATE;
+    mibSet.Param.ChannelsDatarate = datarate;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+void LoRaMacSetChannelsTxPower( int8_t txPower )
+{
+    MibRequestConfirm_t mibSet;
+
+    mibSet.Type = MIB_CHANNELS_TX_POWER;
+    mibSet.Param.ChannelsTxPower = txPower;
+
+    LoRaMacMibSetRequestConfirm( &mibSet );
+}
+
+uint32_t LoRaMacGetUpLinkCounter( void )
+{
+    MibRequestConfirm_t mibGet;
+
+    mibGet.Type = MIB_UPLINK_COUNTER;
+
+    LoRaMacMibGetRequestConfirm( &mibGet );
+
+    return mibGet.Param.UpLinkCounter;
+}
+
+uint32_t LoRaMacGetDownLinkCounter( void )
+{
+    MibRequestConfirm_t mibGet;
+
+    mibGet.Type = MIB_DOWNLINK_COUNTER;
+
+    LoRaMacMibGetRequestConfirm( &mibGet );
+
+    return mibGet.Param.DownLinkCounter;
+}
+
+void LoRaMacSetMicTest( uint16_t txPacketCounter )
+{
+    LoRaMacTestSetMic( txPacketCounter );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaMac-api-v3.h	Tue Jan 05 16:41:54 2016 +0000
@@ -0,0 +1,463 @@
+/*!
+ * \file      LoRaMac-api-v3.h
+ *
+ * \brief     LoRa MAC wrapper layer implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jäckle ( STACKFORCE )
+ */
+#ifndef __LORAMAC_API_V3_H__
+#define __LORAMAC_API_V3_H__
+
+// Includes board dependent definitions such as channels frequencies
+#include "LoRaMac.h"
+#include "LoRaMac-board.h"
+
+/*!
+ * Beacon interval in us
+ */
+#define BEACON_INTERVAL                             128000000
+
+/*!
+ * Class A&B receive delay in us
+ */
+#define RECEIVE_DELAY1                              1000000
+#define RECEIVE_DELAY2                              2000000
+
+/*!
+ * Join accept receive delay in us
+ */
+#define JOIN_ACCEPT_DELAY1                          5000000
+#define JOIN_ACCEPT_DELAY2                          6000000
+
+/*!
+ * Class A&B maximum receive window delay in us
+ */
+#define MAX_RX_WINDOW                               3000000
+
+/*!
+ * 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 = ACK_TIMEOUT + Random( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND )
+ */
+#define ACK_TIMEOUT                                 2000000
+
+/*!
+ * Random number of seconds after the start of the second reception window without
+ * receiving an acknowledge
+ * AckTimeout = ACK_TIMEOUT + Random( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND )
+ */
+#define ACK_TIMEOUT_RND                             1000000
+
+/*!
+ * Check the Mac layer state every MAC_STATE_CHECK_TIMEOUT
+ */
+#define MAC_STATE_CHECK_TIMEOUT                     1000000
+
+/*!
+ * Maximum number of times the MAC layer tries to get an acknowledge.
+ */
+#define MAX_ACK_RETRIES                             8
+
+/*!
+ * RSSI free threshold
+ */
+#define RSSI_FREE_TH                                ( int8_t )( -90 ) // [dBm]
+
+/*!
+ * Frame direction definition
+ */
+#define UP_LINK                                     0
+#define DOWN_LINK                                   1
+
+/*!
+ * Sets the length of the LoRaMAC footer field.
+ * Mainly indicates the MIC field length
+ */
+#define LORAMAC_MFR_LEN                             4
+
+/*!
+ * Syncword for Private LoRa networks
+ */
+#define LORA_MAC_PRIVATE_SYNCWORD                   0x12
+
+/*!
+ * Syncword for Public LoRa networks
+ */
+#define LORA_MAC_PUBLIC_SYNCWORD                    0x34
+
+/*!
+ * LoRaMAC event flags
+ */
+typedef union
+{
+    uint8_t Value;
+    struct
+    {
+        uint8_t Tx              : 1;
+        uint8_t Rx              : 1;
+        uint8_t RxData          : 1;
+        uint8_t Multicast       : 1;
+        uint8_t RxSlot          : 2;
+        uint8_t LinkCheck       : 1;
+        uint8_t JoinAccept      : 1;
+    }Bits;
+}LoRaMacEventFlags_t;
+
+/*!
+ * LoRaMAC event information
+ */
+typedef struct
+{
+    LoRaMacEventInfoStatus_t Status;
+    bool TxAckReceived;
+    uint8_t TxNbRetries;
+    uint8_t TxDatarate;
+    uint8_t RxPort;
+    uint8_t *RxBuffer;
+    uint8_t RxBufferSize;
+    int16_t RxRssi;
+    uint8_t RxSnr;
+    uint16_t Energy;
+    uint8_t DemodMargin;
+    uint8_t NbGateways;
+}LoRaMacEventInfo_t;
+
+/*!
+ * LoRaMAC events structure
+ * Used to notify upper layers of MAC events
+ */
+typedef struct sLoRaMacCallbacks
+{
+    /*!
+     * MAC layer event callback prototype.
+     *
+     * \param [IN] flags Bit field indicating the MAC events occurred
+     * \param [IN] info  Details about MAC events occurred
+     */
+    void ( *MacEvent )( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info );
+    /*!
+     * Function callback to get the current battery level
+     *
+     * \retval batteryLevel Current battery level
+     */
+    uint8_t ( *GetBatteryLevel )( void );
+}LoRaMacCallbacks_t;
+
+/*!
+ * LoRaMAC layer initialization
+ *
+ * \param [IN] callbacks     Pointer to a structure defining the LoRaMAC
+ *                           callback functions.
+ */
+void LoRaMacInit( LoRaMacCallbacks_t *callbacks );
+
+/*!
+ * Enables/Disables the ADR (Adaptive Data Rate)
+ *
+ * \param [IN] enable [true: ADR ON, false: ADR OFF]
+ */
+void LoRaMacSetAdrOn( bool enable );
+
+/*!
+ * Initializes the network IDs. Device address,
+ * network session AES128 key and application session AES128 key.
+ *
+ * \remark To be only used when Over-the-Air activation isn't used.
+ *
+ * \param [IN] netID   24 bits network identifier
+ *                     ( provided by network operator )
+ * \param [IN] devAddr 32 bits device address on the network
+ *                     (must be unique to the network)
+ * \param [IN] nwkSKey Pointer to the network session AES128 key array
+ *                     ( 16 bytes )
+ * \param [IN] appSKey Pointer to the application session AES128 key array
+ *                     ( 16 bytes )
+ */
+void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMulticastChannelLink.
+ */
+void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMulticastChannelUnlink.
+ */
+void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam );
+
+/*!
+ * Initiates the Over-the-Air activation
+ *
+ * \param [IN] devEui Pointer to the device EUI array ( 8 bytes )
+ * \param [IN] appEui Pointer to the application EUI array ( 8 bytes )
+ * \param [IN] appKey Pointer to the application AES128 key array ( 16 bytes )
+ *
+ * \retval status [0: OK, 1: Tx error, 2: Already joined a network]
+ */
+uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey );
+
+/*!
+ * Sends a LinkCheckReq MAC command on the next uplink frame
+ *
+ * \retval status Function status [0: OK, 1: Busy]
+ */
+uint8_t LoRaMacLinkCheckReq( void );
+
+/*!
+ * LoRaMAC layer send frame
+ *
+ * \param [IN] fPort       MAC payload port (must be > 0)
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ *
+ * \retval status          [0: OK, 1: Busy, 2: No network joined,
+ *                          3: Length or port error, 4: Unknown MAC command
+ *                          5: Unable to find a free channel
+ *                          6: Device switched off]
+ */
+uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*!
+ * LoRaMAC layer send frame
+ *
+ * \param [IN] fPort       MAC payload port (must be > 0)
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \param [IN] fBufferSize MAC data buffer size
+ * \param [IN] nbRetries   Number of retries to receive the acknowledgement
+ *
+ * \retval status          [0: OK, 1: Busy, 2: No network joined,
+ *                          3: Length or port error, 4: Unknown MAC command
+ *                          5: Unable to find a free channel
+ *                          6: Device switched off]
+ */
+uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t nbRetries );
+
+/*!
+ * ============================================================================
+ * = LoRaMac test functions                                                   =
+ * ============================================================================
+ */
+
+/*!
+ * LoRaMAC layer generic send frame
+ *
+ * \param [IN] macHdr      MAC header field
+ * \param [IN] fOpts       MAC commands buffer
+ * \param [IN] fPort       MAC payload port
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \retval status          [0: OK, 1: Busy, 2: No network joined,
+ *                          3: Length or port error, 4: Unknown MAC command
+ *                          5: Unable to find a free channel
+ *                          6: Device switched off]
+ */
+uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*!
+ * LoRaMAC layer frame buffer initialization.
+ *
+ * \param [IN] channel     Channel parameters
+ * \param [IN] macHdr      MAC header field
+ * \param [IN] fCtrl       MAC frame control field
+ * \param [IN] fOpts       MAC commands buffer
+ * \param [IN] fPort       MAC payload port
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \retval status          [0: OK, 1: N/A, 2: No network joined,
+ *                          3: Length or port error, 4: Unknown MAC command]
+ */
+uint8_t LoRaMacPrepareFrame( ChannelParams_t channel,LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*!
+ * LoRaMAC layer prepared frame buffer transmission with channel specification
+ *
+ * \remark LoRaMacPrepareFrame must be called at least once before calling this
+ *         function.
+ *
+ * \param [IN] channel     Channel parameters
+ * \retval status          [0: OK, 1: Busy]
+ */
+uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel );
+
+/*!
+ * LoRaMAC layer generic send frame with channel specification
+ *
+ * \param [IN] channel     Channel parameters
+ * \param [IN] macHdr      MAC header field
+ * \param [IN] fCtrl       MAC frame control field
+ * \param [IN] fOpts       MAC commands buffer
+ * \param [IN] fPort       MAC payload port
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \retval status          [0: OK, 1: Busy, 2: No network joined,
+ *                          3: Length or port error, 4: Unknown MAC command]
+ */
+uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*!
+ * ============================================================================
+ * = LoRaMac setup functions                                                  =
+ * ============================================================================
+ */
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the LoRaWan device class.
+ */
+void LoRaMacSetDeviceClass( DeviceClass_t deviceClass );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the network type to public or private.
+ */
+void LoRaMacSetPublicNetwork( bool enable );
+
+/*
+ * Wrapper function which calls \ref LoRaMacChannelAdd.
+ */
+void LoRaMacSetChannel( uint8_t id, ChannelParams_t params );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the receive window 2 channel.
+ */
+void LoRaMacSetRx2Channel( Rx2ChannelParams_t param );
+
+/*!
+ * Sets channels tx output power
+ *
+ * \param [IN] txPower [TX_POWER_20_DBM, TX_POWER_14_DBM,
+                        TX_POWER_11_DBM, TX_POWER_08_DBM,
+                        TX_POWER_05_DBM, TX_POWER_02_DBM]
+ */
+void LoRaMacSetChannelsTxPower( int8_t txPower );
+
+/*!
+ * Sets channels datarate
+ *
+ * \param [IN] datarate 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]
+ */
+void LoRaMacSetChannelsDatarate( int8_t datarate );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the channels mask.
+ */
+void LoRaMacSetChannelsMask( uint16_t *mask );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the number of repetitions on a channel.
+ */
+void LoRaMacSetChannelsNbRep( uint8_t nbRep );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the maximum receive window duration in [us].
+ */
+void LoRaMacSetMaxRxWindow( uint32_t delay );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the receive delay 1 in [us].
+ */
+void LoRaMacSetReceiveDelay1( uint32_t delay );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the receive delay 2 in [us].
+ */
+void LoRaMacSetReceiveDelay2( uint32_t delay );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the join accept delay 1 in [us].
+ */
+void LoRaMacSetJoinAcceptDelay1( uint32_t delay );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibSetRequestConfirm to
+ * set the join accept delay 2 in [us].
+ */
+void LoRaMacSetJoinAcceptDelay2( uint32_t delay );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibGetRequestConfirm to
+ * get the up-link counter.
+ */
+uint32_t LoRaMacGetUpLinkCounter( void );
+
+/*
+ * Wrapper function which calls \ref LoRaMacMibGetRequestConfirm to
+ * get the down-link counter.
+ */
+uint32_t LoRaMacGetDownLinkCounter( void );
+
+/*
+ * ============================================================================
+ * = LoRaMac test functions                                                   =
+ * ============================================================================
+ */
+
+/*!
+ * Disables/Enables the duty cycle enforcement (EU868)
+ *
+ * \param   [IN] enable - Enabled or disables the duty cycle
+ */
+void LoRaMacTestSetDutyCycleOn( bool enable );
+
+/*!
+ * Disables/Enables the reception windows opening
+ *
+ * \param [IN] enable [true: enable, false: disable]
+ */
+void LoRaMacTestRxWindowsOn( bool enable );
+
+/*!
+ * Enables the MIC field test
+ *
+ * \param [IN] upLinkCounter Fixed Tx packet counter value
+ */
+void LoRaMacTestSetMic( uint16_t upLinkCounter );
+
+#endif /* __LORAMAC_API_V3_H__ */
--- a/LoRaMac-board.h	Mon Nov 23 10:09:43 2015 +0000
+++ b/LoRaMac-board.h	Tue Jan 05 16:41:54 2016 +0000
@@ -428,7 +428,7 @@
  *     Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
  *     Channels[i].Band = 0;
  * }
- * // 500 kHz channels 
+ * // 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;
--- a/LoRaMac.cpp	Mon Nov 23 10:09:43 2015 +0000
+++ b/LoRaMac.cpp	Tue Jan 05 16:41:54 2016 +0000
@@ -5,17 +5,23 @@
  _____) ) ____| | | || |_| ____( (___| | | |
 (______/|_____)_|_|_| \__)_____)\____)_| |_|
     (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 and Gregory Cristian
+Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
 */
 #include "board.h"
 
 #include "LoRaMacCrypto.h"
 #include "LoRaMac.h"
+#include "LoRaMacTest.h"
 
 /*!
  * Maximum PHY layer payload size
@@ -77,7 +83,7 @@
 static uint32_t LoRaMacDevAddr;
 
 /*!
- * Mutlicast channels linked list
+ * Multicast channels linked list
  */
 static MulticastParams_t *MulticastChannels = NULL;
 
@@ -310,7 +316,7 @@
 /*!
  * Up/Down link data rates offset definition
  */
-const int8_t datarateOffsets[16][4] = 
+const int8_t datarateOffsets[16][4] =
 {
     { DR_10, DR_9 , DR_8 , DR_8  }, // DR_0
     { DR_11, DR_10, DR_9 , DR_8  }, // DR_1
@@ -358,6 +364,11 @@
  */
 static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
 
+/*!
+ * Contains the channels which remain to be applied.
+ */
+static uint16_t ChannelsMaskRemaining[6];
+
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
@@ -409,7 +420,7 @@
 static uint8_t MaxDCycle = 0;
 
 /*!
- * Agregated duty cycle management
+ * Aggregated duty cycle management
  */
 static uint16_t AggregatedDCycle;
 static TimerTime_t AggregatedLastTxDoneTime;
@@ -428,14 +439,14 @@
 /*!
  * LoRaMac internal states
  */
-enum LoRaMacState_e
+enum eLoRaMacState
 {
     MAC_IDLE          = 0x00000000,
     MAC_TX_RUNNING    = 0x00000001,
     MAC_RX            = 0x00000002,
     MAC_ACK_REQ       = 0x00000004,
     MAC_ACK_RETRY     = 0x00000008,
-    MAC_CHANNEL_CHECK = 0x00000010,
+    MAC_TX_DELAYED    = 0x00000010,
 };
 
 /*!
@@ -451,22 +462,17 @@
 /*!
  * LoRaMac upper layer event functions
  */
-static LoRaMacCallbacks_t *LoRaMacCallbacks;
-
-/*!
- * LoRaMac notification event flags
- */
-LoRaMacEventFlags_t LoRaMacEventFlags;
+static LoRaMacPrimitives_t *LoRaMacPrimitives;
 
 /*!
- * LoRaMac notification event info
+ * LoRaMac upper layer callback functions
  */
-LoRaMacEventInfo_t LoRaMacEventInfo;
+static LoRaMacCallback_t *LoRaMacCallbacks;
 
 /*!
- * LoRaMac channel check timer
+ * Radio events function pointer
  */
-static TimerEvent_t ChannelCheckTimer;
+static RadioEvents_t RadioEvents;
 
 /*!
  * LoRaMac duty cycle delayed Tx timer
@@ -526,64 +532,122 @@
 TimerTime_t TxTimeOnAir = 0;
 
 /*!
- * Function to be executed on Radio Tx Done event
+ * Structure to hold an MCPS indication data.
+ */
+static McpsIndication_t McpsIndication;
+
+/*!
+ * Structure to hold MCPS confirm data.
+ */
+static McpsConfirm_t McpsConfirm;
+
+/*!
+ * Structure to hold MLME confirm data.
+ */
+static MlmeConfirm_t MlmeConfirm;
+
+/*!
+ * Holds the current rx window slot
+ */
+static uint8_t RxSlot = 0;
+
+/*!
+ * LoRaMac tx/rx operation state
+ */
+LoRaMacFlags_t LoRaMacFlags;
+
+/*!
+ * \brief Function to be executed on Radio Tx Done event
  */
 static void OnRadioTxDone( void );
 
 /*!
- * Function to be executed on Radio Rx Done event
+ * \brief Function to be executed on Radio Rx Done event
  */
 static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
 
 /*!
- * Function executed on Radio Tx Timeout event
+ * \brief Function executed on Radio Tx Timeout event
  */
 static void OnRadioTxTimeout( void );
 
 /*!
- * Function executed on Radio Rx error event
+ * \brief Function executed on Radio Rx error event
  */
 static void OnRadioRxError( void );
 
 /*!
- * Function executed on Radio Rx Timeout event
+ * \brief Function executed on Radio Rx Timeout event
  */
 static void OnRadioRxTimeout( void );
 
 /*!
- * Function executed on Resend Frame timer event.
+ * \brief Function executed on Resend Frame timer event.
  */
 static void OnMacStateCheckTimerEvent( void );
 
 /*!
- * Function executed on duty cycle delayed Tx  timer event
+ * \brief Function executed on duty cycle delayed Tx  timer event
  */
 static void OnTxDelayedTimerEvent( void );
 
 /*!
- * Function executed on channel check timer event
- */
-static void OnChannelCheckTimerEvent( void );
-
-/*!
- * Function executed on first Rx window timer event
+ * \brief Function executed on first Rx window timer event
  */
 static void OnRxWindow1TimerEvent( void );
 
 /*!
- * Function executed on second Rx window timer event
+ * \brief Function executed on second Rx window timer event
  */
 static void OnRxWindow2TimerEvent( void );
 
 /*!
- * Function executed on AckTimeout timer event
+ * \brief Function executed on AckTimeout timer event
  */
 static void OnAckTimeoutTimerEvent( void );
 
 /*!
- * Radio events function pointer
+ * \brief Searches and set the next random available channel
+ *
+ * \retval status  Function status [0: OK, 1: Unable to find a free channel]
+ */
+static TimerTime_t SetNextChannel( void );
+
+/*!
+ * \brief Sets the network to public or private. Updates the sync byte.
+ *
+ * \param [IN] enable if true, it enables a public network
+ */
+static void SetPublicNetwork( bool enable );
+
+/*!
+ * \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
  */
-static RadioEvents_t RadioEvents;
+static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous );
+
+/*!
+ * \brief Adds a new MAC command to be sent.
+ *
+ * \Remark MAC layer internal function
+ *
+ * \param [in] cmd MAC command to be added
+ *                 [MOTE_MAC_LINK_CHECK_REQ,
+ *                  MOTE_MAC_LINK_ADR_ANS,
+ *                  MOTE_MAC_DUTY_CYCLE_ANS,
+ *                  MOTE_MAC_RX2_PARAM_SET_ANS,
+ *                  MOTE_MAC_DEV_STATUS_ANS
+ *                  MOTE_MAC_NEW_CHANNEL_ANS]
+ * \param [in] p1  1st parameter ( optional depends on the command )
+ * \param [in] p2  2nd parameter ( optional depends on the command )
+ *
+ * \retval status  Function status [0: OK, 1: Unknown command, 2: Buffer full]
+ */
+static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 );
 
 /*!
  * \brief Validates if the payload fits into the frame, taking the datarate
@@ -596,10 +660,12 @@
  *
  * \param datarate Current datarate
  *
+ * \param fOptsLen Length of the fOpts field
+ *
  * \retval [false: payload does not fit into the frame, true: payload fits into
  *          the frame]
  */
-static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate );
+static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
 
 #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
 /*!
@@ -621,132 +687,1203 @@
 static int8_t LimitTxPower( int8_t txPower );
 
 /*!
- * Searches and set the next random available channel
+ * \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 status  Function status [0: OK, 1: Unable to find a free channel]
+ * \retval [true, if disable was successful, false if not]
+ */
+static bool DisableChannelInMask( uint8_t id, uint16_t* mask );
+
+/*!
+ * \brief Decodes MAC commands in the fOpts field and in the payload
+ */
+static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
+
+/*!
+ * \brief LoRaMAC layer generic send frame
+ *
+ * \param [IN] macHdr      MAC header field
+ * \param [IN] fPort       MAC payload port
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \retval status          Status of the operation.
+ */
+LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*!
+ * \brief LoRaMAC layer frame buffer initialization
+ *
+ * \param [IN] macHdr      MAC header field
+ * \param [IN] fCtrl       MAC frame control field
+ * \param [IN] fOpts       MAC commands buffer
+ * \param [IN] fPort       MAC payload port
+ * \param [IN] fBuffer     MAC data buffer to be sent
+ * \param [IN] fBufferSize MAC data buffer size
+ * \retval status          Status of the operation.
+ */
+LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+
+/*
+ * \brief Schedules the frame according to the duty cycle
+ *
+ * \retval Status of the operation
+ */
+static LoRaMacStatus_t ScheduleTx( void );
+
+/*!
+ * \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
+ * \retval status          Status of the operation.
  */
-static uint8_t LoRaMacSetNextChannel( void )
+LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
+
+
+
+static void OnRadioTxDone( void )
+{
+    TimerTime_t curTime = TimerGetCurrentTime( );
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        Radio.Sleep( );
+    }
+    else
+    {
+        OnRxWindow2TimerEvent( );
+    }
+
+    // Update Band Time OFF
+    Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
+    if( DutyCycleOn == true )
+    {
+        Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
+    }
+    else
+    {
+        Bands[Channels[Channel].Band].TimeOff = 0;
+    }
+    // Update Aggregated Time OFF
+    AggregatedLastTxDoneTime = curTime;
+    AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
+
+    if( IsRxWindowsEnabled == true )
+    {
+        TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
+        TimerStart( &RxWindowTimer1 );
+        if( LoRaMacDeviceClass != CLASS_C )
+        {
+            TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
+            TimerStart( &RxWindowTimer2 );
+        }
+        if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
+        {
+            TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT +
+                                             randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
+            TimerStart( &AckTimeoutTimer );
+        }
+    }
+    else
+    {
+        McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+
+        if( LoRaMacFlags.Value == 0 )
+        {
+            LoRaMacFlags.Bits.McpsReq = 1;
+        }
+        LoRaMacFlags.Bits.MacDone = 1;
+    }
+
+    if( NodeAckRequested == false )
+    {
+        McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+        ChannelsNbRepCounter++;
+    }
+}
+
+static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
 {
-    uint8_t i = 0;
-    uint8_t j = 0;
-    uint8_t k = 0;
+    LoRaMacHeader_t macHdr;
+    LoRaMacFrameCtrl_t fCtrl;
+
+    uint8_t pktHeaderLen = 0;
+    uint32_t address = 0;
+    uint8_t appPayloadStartIndex = 0;
+    uint8_t port = 0xFF;
+    uint8_t frameLen = 0;
+    uint32_t mic = 0;
+    uint32_t micRx = 0;
+
+    uint16_t sequenceCounter = 0;
+    uint16_t sequenceCounterPrev = 0;
+    uint16_t sequenceCounterDiff = 0;
+    uint32_t downLinkCounter = 0;
+
+    MulticastParams_t *curMulticastParams = NULL;
+    uint8_t *nwkSKey = LoRaMacNwkSKey;
+    uint8_t *appSKey = LoRaMacAppSKey;
+
+    uint8_t multicast = 0;
+
+    bool isMicOk = false;
+
+    McpsConfirm.AckReceived = false;
+    McpsIndication.Rssi = rssi;
+    McpsIndication.Snr = snr;
+    McpsIndication.RxSlot = RxSlot;
+    McpsIndication.Port = 0;
+    McpsIndication.Multicast = 0;
+    McpsIndication.FramePending = 0;
+    McpsIndication.Buffer = NULL;
+    McpsIndication.BufferSize = 0;
+    McpsIndication.RxData = false;
+    McpsIndication.AckReceived = false;
+    McpsIndication.DownLinkCounter = 0;
+    McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
+
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        Radio.Sleep( );
+    }
+    TimerStop( &RxWindowTimer2 );
+
+    macHdr.Value = payload[pktHeaderLen++];
+
+    switch( macHdr.Bits.MType )
+    {
+        case FRAME_TYPE_JOIN_ACCEPT:
+            if( IsLoRaMacNetworkJoined == true )
+            {
+                break;
+            }
+            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
+                Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
+                Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                /*
+                 * WARNING: To be removed once Semtech server implementation
+                 *          is corrected.
+                 */
+                if( Rx2Channel.Datarate == DR_3 )
+                {
+                    Rx2Channel.Datarate = DR_8;
+                }
+#endif
+                // RxDelay
+                ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
+                if( ReceiveDelay1 == 0 )
+                {
+                    ReceiveDelay1 = 1;
+                }
+                ReceiveDelay1 *= 1e6;
+                ReceiveDelay2 = ReceiveDelay1 + 1e6;
+
+#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;
+
+                    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;
+                        LoRaMacChannelAdd( i, param );
+                    }
+                }
+#endif
+                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                IsLoRaMacNetworkJoined = true;
+                ChannelsDatarate = ChannelsDefaultDatarate;
+            }
+            else
+            {
+                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
+            }
+            break;
+        case FRAME_TYPE_DATA_CONFIRMED_DOWN:
+        case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
+            {
+                LoRaMacFlags.Bits.McpsInd = 1;
+
+                address = payload[pktHeaderLen++];
+                address |= ( (uint32_t)payload[pktHeaderLen++] << 8 );
+                address |= ( (uint32_t)payload[pktHeaderLen++] << 16 );
+                address |= ( (uint32_t)payload[pktHeaderLen++] << 24 );
+
+                if( address != LoRaMacDevAddr )
+                {
+                    curMulticastParams = MulticastChannels;
+                    while( curMulticastParams != NULL )
+                    {
+                        if( address == curMulticastParams->Address )
+                        {
+                            multicast = 1;
+                            nwkSKey = curMulticastParams->NwkSKey;
+                            appSKey = curMulticastParams->AppSKey;
+                            downLinkCounter = curMulticastParams->DownLinkCounter;
+                            break;
+                        }
+                        curMulticastParams = curMulticastParams->Next;
+                    }
+                    if( multicast == 0 )
+                    {
+                        // We are not the destination of this frame.
+                        LoRaMacFlags.Bits.MacDone = 1;
+                        McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
+                        LoRaMacState &= ~MAC_TX_RUNNING;
+                        if( NodeAckRequested )
+                        {
+                            OnAckTimeoutTimerEvent( );
+                        }
+                        return;
+                    }
+                }
+                else
+                {
+                    multicast = 0;
+                    nwkSKey = LoRaMacNwkSKey;
+                    appSKey = LoRaMacAppSKey;
+                    downLinkCounter = DownLinkCounter;
+                }
+
+                if( LoRaMacDeviceClass != CLASS_A )
+                {
+                    LoRaMacState |= MAC_RX;
+                    // Starts the MAC layer status check timer
+                    TimerStart( &MacStateCheckTimer );
+                }
+                fCtrl.Value = payload[pktHeaderLen++];
+
+                sequenceCounter = ( uint16_t )payload[pktHeaderLen++];
+                sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8;
+
+                appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
+
+                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 );
+
+                sequenceCounterPrev = ( uint16_t )downLinkCounter;
+                sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
+
+                if( sequenceCounterDiff < ( 1 << 15 ) )
+                {
+                    downLinkCounter += sequenceCounterDiff;
+                    LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
+                    if( micRx == mic )
+                    {
+                        isMicOk = true;
+                    }
+                }
+                else
+                {
+                    // check for sequence roll-over
+                    uint32_t  downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
+                    LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
+                    if( micRx == mic )
+                    {
+                        isMicOk = true;
+                        downLinkCounter = downLinkCounterTmp;
+                    }
+                }
+
+                if( isMicOk == true )
+                {
+                    McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                    McpsIndication.Multicast = multicast;
+                    McpsIndication.FramePending = fCtrl.Bits.FPending;
+                    McpsIndication.Buffer = NULL;
+                    McpsIndication.BufferSize = 0;
+                    McpsIndication.DownLinkCounter = downLinkCounter;
+
+                    McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+
+                    AdrAckCounter = 0;
+
+                    // Update 32 bits downlink counter
+                    if( multicast == 1 )
+                    {
+                        McpsIndication.McpsIndication = MCPS_MULTICAST;
+
+                        if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) &&
+                            ( curMulticastParams->DownLinkCounter != 0 ) )
+                        {
+                            LoRaMacFlags.Bits.MacDone = 1;
+                            McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
+                            McpsIndication.DownLinkCounter = downLinkCounter;
+                            LoRaMacState &= ~MAC_TX_RUNNING;
+                            if( NodeAckRequested == true )
+                            {
+                                OnAckTimeoutTimerEvent( );
+                            }
+                            return;
+                        }
+                        curMulticastParams->DownLinkCounter = downLinkCounter;
+                    }
+                    else
+                    {
+                        if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
+                        {
+                            McpsIndication.McpsIndication = MCPS_CONFIRMED;
+                        }
+                        else
+                        {
+                            McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
+                        }
+                        if( ( DownLinkCounter == downLinkCounter ) &&
+                            ( DownLinkCounter != 0 ) )
+                        {
+                            LoRaMacFlags.Bits.MacDone = 1;
+                            McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
+                            McpsIndication.DownLinkCounter = downLinkCounter;
+                            LoRaMacState &= ~MAC_TX_RUNNING;
+                            if( NodeAckRequested == true )
+                            {
+                                OnAckTimeoutTimerEvent( );
+                            }
+                            return;
+                        }
+                        DownLinkCounter = downLinkCounter;
+                    }
+
+                    if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
+                    {
+                        SrvAckRequested = true;
+                    }
+                    else
+                    {
+                        SrvAckRequested = false;
+                    }
+                    // Check if the frame is an acknowledgement
+                    if( fCtrl.Bits.Ack == 1 )
+                    {
+                        McpsConfirm.AckReceived = true;
+                        McpsIndication.AckReceived = true;
+
+                        // Stop the AckTimeout timer as no more retransmissions
+                        // are needed.
+                        TimerStop( &AckTimeoutTimer );
+                    }
+                    else
+                    {
+                        McpsConfirm.AckReceived = false;
+
+                        if( AckTimeoutRetriesCounter > AckTimeoutRetries )
+                        {
+                            // Stop the AckTimeout timer as no more retransmissions
+                            // are needed.
+                            TimerStop( &AckTimeoutTimer );
+                        }
+                    }
+
+                    if( fCtrl.Bits.FOptsLen > 0 )
+                    {
+                        // Decode Options field MAC commands
+                        ProcessMacCommands( payload, 8, appPayloadStartIndex, snr );
+                    }
+                    if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
+                    {
+                        port = payload[appPayloadStartIndex++];
+                        frameLen = ( size - 4 ) - appPayloadStartIndex;
+
+                        McpsIndication.Port = port;
+
+                        if( port == 0 )
+                        {
+                            LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
+                                                   frameLen,
+                                                   nwkSKey,
+                                                   address,
+                                                   DOWN_LINK,
+                                                   downLinkCounter,
+                                                   LoRaMacRxPayload );
+
+                            // Decode frame payload MAC commands
+                            ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr );
+                        }
+                        else
+                        {
+                            LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
+                                                   frameLen,
+                                                   appSKey,
+                                                   address,
+                                                   DOWN_LINK,
+                                                   downLinkCounter,
+                                                   LoRaMacRxPayload );
+
+                            McpsIndication.Buffer = LoRaMacRxPayload;
+                            McpsIndication.BufferSize = frameLen;
+                            McpsIndication.RxData = true;
+                        }
+                    }
+                }
+                else
+                {
+                    McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
+                    LoRaMacState &= ~MAC_TX_RUNNING;
+                    if( NodeAckRequested == true )
+                    {
+                        OnAckTimeoutTimerEvent( );
+                    }
+                }
+            }
+            break;
+        case FRAME_TYPE_PROPRIETARY:
+            {
+                LoRaMacFlags.Bits.McpsInd = 1;
+
+                memcpy1( LoRaMacRxPayload, &payload[pktHeaderLen], size );
+
+                McpsIndication.McpsIndication = MCPS_PROPRIETARY;
+                McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                McpsIndication.Buffer = LoRaMacRxPayload;
+                McpsIndication.BufferSize = size - pktHeaderLen;
+                break;
+            }
+        default:
+            LoRaMacFlags.Bits.McpsInd = 1;
+            McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+            LoRaMacState &= ~MAC_TX_RUNNING;
+            break;
+    }
+
+    if( ( RxSlot == 0 ) && ( LoRaMacDeviceClass == CLASS_C ) )
+    {
+        OnRxWindow2TimerEvent( );
+    }
+
+    LoRaMacFlags.Bits.MacDone = 1;
+}
+
+static void OnRadioTxTimeout( void )
+{
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        Radio.Sleep( );
+    }
+    else
+    {
+        OnRxWindow2TimerEvent( );
+    }
+
+    McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
+    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
+    LoRaMacFlags.Bits.MacDone = 1;
+}
+
+static void OnRadioRxError( void )
+{
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        Radio.Sleep( );
+    }
+    else
+    {
+        OnRxWindow2TimerEvent( );
+    }
+
+    if( RxSlot == 1 )
+    {
+        if( NodeAckRequested == true )
+        {
+            McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
+        }
+        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
+        LoRaMacFlags.Bits.MacDone = 1;
+    }
+}
+
+static void OnRadioRxTimeout( void )
+{
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        Radio.Sleep( );
+    }
+    else
+    {
+        OnRxWindow2TimerEvent( );
+    }
+
+    if( RxSlot == 1 )
+    {
+        if( NodeAckRequested == true )
+        {
+            McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+        }
+        MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+        LoRaMacFlags.Bits.MacDone = 1;
+    }
+}
+
+static void OnMacStateCheckTimerEvent( void )
+{
+    TimerStop( &MacStateCheckTimer );
+    bool txTimeout = false;
+
+    if( LoRaMacFlags.Bits.MacDone == 1 )
+    {
+        if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) )
+        {
+            if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ||
+                ( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) )
+            {
+                // Stop transmit cycle due to tx timeout.
+                LoRaMacState &= ~MAC_TX_RUNNING;
+                McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
+                McpsConfirm.AckReceived = false;
+                McpsConfirm.TxTimeOnAir = 0;
+                txTimeout = true;
+            }
+        }
+
+        if( ( NodeAckRequested == false ) && ( txTimeout == false ) )
+        {
+            if( LoRaMacFlags.Bits.MlmeReq == 1 )
+            {
+                if( MlmeConfirm.MlmeRequest == MLME_JOIN )
+                {
+                    if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK )
+                    {
+                        UpLinkCounter = 0;
+                    }
+                    // Join messages aren't repeated automatically
+                    ChannelsNbRepCounter = ChannelsNbRep;
+                }
+            }
+            if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) )
+            {
+                if( ( ChannelsNbRepCounter >= ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) )
+                {
+                    ChannelsNbRepCounter = 0;
+
+                    AdrAckCounter++;
+                    if( IsUpLinkCounterFixed == false )
+                    {
+                        UpLinkCounter++;
+                    }
+
+                    LoRaMacState &= ~MAC_TX_RUNNING;
+                }
+                else
+                {
+                    LoRaMacFlags.Bits.MacDone = 0;
+                    // Sends the same frame again
+                    ScheduleTx( );
+                }
+            }
+        }
+
+        if( LoRaMacFlags.Bits.McpsInd == 1 )
+        {
+            if( ( McpsConfirm.AckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) )
+            {
+                AckTimeoutRetry = false;
+                if( IsUpLinkCounterFixed == false )
+                {
+                    UpLinkCounter++;
+                }
+                McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
+
+                LoRaMacState &= ~MAC_TX_RUNNING;
+            }
+        }
+
+        if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_TX_DELAYED ) == 0 ) )
+        {
+            AckTimeoutRetry = false;
+            if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
+            {
+                AckTimeoutRetriesCounter++;
+
+                if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
+                {
+                    ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
+                }
+                LoRaMacFlags.Bits.MacDone = 0;
+                // Sends the same frame again
+                ScheduleTx( );
+            }
+            else
+            {
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+                // Re-enable default channels LC1, LC2, LC3
+                ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
+#elif defined( USE_BAND_915 )
+                // Re-enable default channels
+                ChannelsMask[0] = 0xFFFF;
+                ChannelsMask[1] = 0xFFFF;
+                ChannelsMask[2] = 0xFFFF;
+                ChannelsMask[3] = 0xFFFF;
+                ChannelsMask[4] = 0x00FF;
+                ChannelsMask[5] = 0x0000;
+#elif defined( USE_BAND_915_HYBRID )
+                // Re-enable default channels
+                ChannelsMask[0] = 0x00FF;
+                ChannelsMask[1] = 0x0000;
+                ChannelsMask[2] = 0x0000;
+                ChannelsMask[3] = 0x0000;
+                ChannelsMask[4] = 0x0001;
+                ChannelsMask[5] = 0x0000;
+#else
+    #error "Please define a frequency band in the compiler options."
+#endif
+                LoRaMacState &= ~MAC_TX_RUNNING;
+
+                McpsConfirm.AckReceived = false;
+                McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
+                if( IsUpLinkCounterFixed == false )
+                {
+                    UpLinkCounter++;
+                }
+            }
+        }
+    }
+    // Handle reception for Class B and Class C
+    if( ( LoRaMacState & MAC_RX ) == MAC_RX )
+    {
+        LoRaMacState &= ~MAC_RX;
+    }
+    if( LoRaMacState == MAC_IDLE )
+    {
+        if( LoRaMacFlags.Bits.McpsReq == 1 )
+        {
+            LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm );
+            LoRaMacFlags.Bits.McpsReq = 0;
+        }
+
+        if( LoRaMacFlags.Bits.MlmeReq == 1 )
+        {
+            LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm );
+            LoRaMacFlags.Bits.MlmeReq = 0;
+        }
+
+        LoRaMacFlags.Bits.MacDone = 0;
+    }
+    else
+    {
+        // Operation not finished restart timer
+        TimerStart( &MacStateCheckTimer );
+    }
+
+    if( LoRaMacFlags.Bits.McpsInd == 1 )
+    {
+        LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
+        LoRaMacFlags.Bits.McpsInd = 0;
+    }
+}
+
+static void OnTxDelayedTimerEvent( void )
+{
+    TimerStop( &TxDelayedTimer );
+    LoRaMacState &= ~MAC_TX_DELAYED;
+
+    ScheduleTx( );
+}
+
+static void OnRxWindow1TimerEvent( void )
+{
+    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
+    int8_t datarate = 0;
+    uint32_t bandwidth = 0; // LoRa 125 kHz
+
+    TimerStop( &RxWindowTimer1 );
+    RxSlot = 0;
+
+    if( LoRaMacDeviceClass == CLASS_C )
+    {
+        Radio.Standby( );
+    }
+
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+    datarate = ChannelsDatarate - Rx1DrOffset;
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+
+    // For higher datarates, we increase the number of symbols generating a Rx Timeout
+    if( datarate >= DR_3 )
+    { // DR_6, DR_5, DR_4, DR_3
+        symbTimeout = 8;
+    }
+    if( datarate == DR_6 )
+    {// LoRa 250 kHz
+        bandwidth  = 1;
+    }
+    RxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
+#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+    datarate = datarateOffsets[ChannelsDatarate][Rx1DrOffset];
+    if( datarate < 0 )
+    {
+        datarate = DR_0;
+    }
+    // For higher datarates, we increase the number of symbols generating a Rx Timeout
+    if( datarate > DR_0 )
+    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
+        symbTimeout = 8;
+    }
+    if( datarate >= DR_4 )
+    {// LoRa 500 kHz
+        bandwidth  = 2;
+    }
+    RxWindowSetup( 923.3e6 + ( Channel % 8 ) * 600e3, datarate, bandwidth, symbTimeout, false );
+#else
+    #error "Please define a frequency band in the compiler options."
+#endif
+}
+
+static void OnRxWindow2TimerEvent( void )
+{
+    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
+    uint32_t bandwidth = 0; // LoRa 125 kHz
+
+    TimerStop( &RxWindowTimer2 );
+    RxSlot = 1;
+
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+    // For higher datarates, we increase the number of symbols generating a Rx Timeout
+    if( Rx2Channel.Datarate >= DR_3 )
+    { // DR_6, DR_5, DR_4, DR_3
+        symbTimeout = 8;
+    }
+    if( Rx2Channel.Datarate == DR_6 )
+    {// LoRa 250 kHz
+        bandwidth  = 1;
+    }
+#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+    // For higher datarates, we increase the number of symbols generating a Rx Timeout
+    if( Rx2Channel.Datarate > DR_0 )
+    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
+        symbTimeout = 8;
+    }
+    if( Rx2Channel.Datarate >= DR_4 )
+    {// LoRa 500 kHz
+        bandwidth  = 2;
+    }
+#else
+    #error "Please define a frequency band in the compiler options."
+#endif
+    if( LoRaMacDeviceClass != CLASS_C )
+    {
+        RxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false );
+    }
+    else
+    {
+        RxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true );
+    }
+}
+
+static void OnAckTimeoutTimerEvent( void )
+{
+    TimerStop( &AckTimeoutTimer );
+
+    if( NodeAckRequested == true )
+    {
+        AckTimeoutRetry = true;
+        LoRaMacState &= ~MAC_ACK_REQ;
+    }
+    if( LoRaMacDeviceClass == CLASS_C )
+    {
+        LoRaMacFlags.Bits.MacDone = 1;
+    }
+}
+
+static TimerTime_t SetNextChannel( void )
+{
     uint8_t nbEnabledChannels = 0;
     uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
     TimerTime_t curTime = TimerGetCurrentTime( );
+    TimerTime_t nextTxDelay = ( TimerTime_t )( -1 );
 
     memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
 
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+    if( ( CountNbEnabled125kHzChannels( ChannelsMaskRemaining ) +
+        ( ChannelsMaskRemaining[4] & 0x00FF ) ) == 0 )
+    {
+        memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask,
+                 sizeof( ChannelsMask ) );
+    }
+#endif
+
     // Update Aggregated duty cycle
     if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) )
     {
         AggregatedTimeOff = 0;
-    }
-
-    // Update bands Time OFF
-    TimerTime_t minTime = ( TimerTime_t )( -1 );
-    for( i = 0; i < LORA_MAX_NB_BANDS; i++ )
-    {
-        if( DutyCycleOn == true )
+
+        // Update bands Time OFF
+        for( uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++ )
         {
-            if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) )
+            if( DutyCycleOn == true )
             {
+                if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) )
+                {
+                    Bands[i].TimeOff = 0;
+                }
+                if( Bands[i].TimeOff != 0 )
+                {
+                    nextTxDelay = MIN( Bands[i].TimeOff -
+                                       ( curTime - Bands[i].LastTxDoneTime ),
+                                       nextTxDelay );
+                }
+            }
+            else
+            {
+                nextTxDelay = 0;
                 Bands[i].TimeOff = 0;
             }
-            if( Bands[i].TimeOff != 0 )
+        }
+
+        // Search how many channels are enabled
+        for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
+        {
+            for( uint8_t j = 0; j < 16; j++ )
             {
-                minTime = MIN( Bands[i].TimeOff, minTime );
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                if( ( ChannelsMaskRemaining[k] & ( 1 << j ) ) != 0 )
+#else
+                if( ( ChannelsMask[k] & ( 1 << j ) ) != 0 )
+#endif
+                {
+                    if( Channels[i + j].Frequency == 0 )
+                    { // Check if the channel is enabled
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                        DisableChannelInMask( i + j, ChannelsMaskRemaining );
+#endif
+                        continue;
+                    }
+                    if( ( ( Channels[i + j].DrRange.Fields.Min <= ChannelsDatarate ) &&
+                          ( ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
+                    { // Check if the current channel selection supports the given datarate
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                        DisableChannelInMask( i + j, ChannelsMaskRemaining );
+#endif
+                        continue;
+                    }
+                    if( Bands[Channels[i + j].Band].TimeOff > 0 )
+                    { // Check if the band is available for transmission
+                        continue;
+                    }
+                    enabledChannels[nbEnabledChannels++] = i + j;
+                }
+            }
+        }
+    }
+    else
+    {
+        nextTxDelay = AggregatedTimeOff - ( curTime - AggregatedLastTxDoneTime );
+    }
+
+    if( nbEnabledChannels > 0 )
+    {
+        Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+        DisableChannelInMask( Channel, ChannelsMaskRemaining );
+#endif
+        return 0;
+    }
+    else
+    {
+        // Protect the function of returning the initialization value of nextTxDelay
+        return ( nextTxDelay == ( TimerTime_t )( -1 ) ) ? 0 : nextTxDelay;
+    }
+}
+
+static void SetPublicNetwork( bool enable )
+{
+    PublicNetwork = enable;
+    Radio.SetModem( MODEM_LORA );
+    if( PublicNetwork == true )
+    {
+        // Change LoRa modem SyncWord
+        Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD );
+    }
+    else
+    {
+        // Change LoRa modem SyncWord
+        Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD );
+    }
+}
+
+static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
+{
+    uint8_t downlinkDatarate = Datarates[datarate];
+    RadioModems_t modem;
+
+    if( Radio.GetStatus( ) == RF_IDLE )
+    {
+        Radio.SetChannel( freq );
+
+        // Store downlink datarate
+        McpsIndication.RxDatarate = ( uint8_t ) datarate;
+
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+        if( datarate == DR_7 )
+        {
+            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_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] );
+        }
+        else
+        {
+            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] );
+        }
+
+        if( rxContinuous == false )
+        {
+            Radio.Rx( MaxRxWindow );
+        }
+        else
+        {
+            Radio.Rx( 0 ); // Continuous mode
+        }
+    }
+}
+
+static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
+{
+    uint16_t maxN = 0;
+    uint16_t payloadSize = 0;
+
+    // Get the maximum payload length
+    if( RepeaterSupport == true )
+    {
+        maxN = MaxPayloadOfDatarateRepeater[datarate];
+    }
+    else
+    {
+        maxN = MaxPayloadOfDatarate[datarate];
+    }
+
+    // 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;
+}
+
+#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++ )
+    {
+        for( uint8_t j = 0; j < 16; j++ )
+        {// Verify if the channel is active
+            if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) )
+            {
+                nb125kHzChannels++;
+            }
+        }
+    }
+
+    return nb125kHzChannels;
+}
+#endif
+
+static int8_t LimitTxPower( int8_t txPower )
+{
+    int8_t resultTxPower = txPower;
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+    if( ( ChannelsDatarate == DR_4 ) ||
+        ( ( ChannelsDatarate >= DR_8 ) && ( ChannelsDatarate <= DR_13 ) ) )
+    {// Limit tx power to max 26dBm
+        resultTxPower =  MAX( txPower, TX_POWER_26_DBM );
+    }
+    else
+    {
+        if( CountNbEnabled125kHzChannels( ChannelsMask ) < 50 )
+        {// Limit tx power to max 21dBm
+            resultTxPower = MAX( txPower, TX_POWER_20_DBM );
+        }
+    }
+#endif
+    return resultTxPower;
+}
+
+static bool ValueInRange( int8_t value, int8_t min, int8_t max )
+{
+    if( ( value >= min ) && ( value <= max ) )
+    {
+        return true;
+    }
+    return false;
+}
+
+static bool DisableChannelInMask( uint8_t id, uint16_t* mask )
+{
+    uint8_t index = 0;
+    index = id / 16;
+
+    if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
+    {
+        return false;
+    }
+
+    // Deactivate channel
+    mask[index] &= ~( 1 << ( id % 16 ) );
+
+    return true;
+}
+
+static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut )
+{
+    bool adrAckReq = false;
+    int8_t datarate = ChannelsDatarate;
+
+    if( adrEnabled == true )
+    {
+        if( datarate == LORAMAC_MIN_DATARATE )
+        {
+            AdrAckCounter = 0;
+            adrAckReq = false;
+
+            if( updateChannelMask == true )
+            {
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+                // Re-enable default channels LC1, LC2, LC3
+                ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
+#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+#if defined( USE_BAND_915 )
+                // Re-enable default channels
+                ChannelsMask[0] = 0xFFFF;
+                ChannelsMask[1] = 0xFFFF;
+                ChannelsMask[2] = 0xFFFF;
+                ChannelsMask[3] = 0xFFFF;
+                ChannelsMask[4] = 0x00FF;
+                ChannelsMask[5] = 0x0000;
+#else // defined( USE_BAND_915_HYBRID )
+                // Re-enable default channels
+                ChannelsMask[0] = 0x00FF;
+                ChannelsMask[1] = 0x0000;
+                ChannelsMask[2] = 0x0000;
+                ChannelsMask[3] = 0x0000;
+                ChannelsMask[4] = 0x0001;
+                ChannelsMask[5] = 0x0000;
+#endif
+#else
+#error "Please define a frequency band in the compiler options."
+#endif
             }
         }
         else
         {
-            minTime = 0;
-            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( ( ChannelsMask[k] & ( 1 << j ) ) != 0 )
+            if( AdrAckCounter > ADR_ACK_LIMIT )
+            {
+                adrAckReq = true;
+            }
+            else
+            {
+                adrAckReq = false;
+            }
+            if( AdrAckCounter > ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
             {
-                if( Channels[i + j].Frequency == 0 )
-                { // Check if the channel is enabled
-                    continue;
-                }
-                if( ( ( Channels[i + j].DrRange.Fields.Min <= ChannelsDatarate ) &&
-                      ( ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
-                { // Check if the current channel selection supports the given datarate
-                    continue;
+                AdrAckCounter = 0;
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+                if( datarate > LORAMAC_MIN_DATARATE )
+                {
+                    datarate--;
                 }
-                if( Bands[Channels[i + j].Band].TimeOff > 0 )
-                { // Check if the band is available for transmission
-                    continue;
+#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                if( ( datarate > LORAMAC_MIN_DATARATE ) && ( datarate == DR_8 ) )
+                {
+                    datarate = DR_4;
                 }
-                if( AggregatedTimeOff > 0 )
-                { // Check if there is time available for transmission
-                    continue;
+                else if( datarate > LORAMAC_MIN_DATARATE )
+                {
+                    datarate--;
                 }
-                enabledChannels[nbEnabledChannels++] = i + j;
+#else
+#error "Please define a frequency band in the compiler options."
+#endif
             }
         }
     }
-    if( nbEnabledChannels > 0 )
-    {
-        Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
-        LoRaMacState &= ~MAC_CHANNEL_CHECK;
-        TimerStop( &ChannelCheckTimer );
-        return 0;
-    }
-    // No free channel found. 
-    // Check again
-    if( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 )
-    {
-        TimerSetValue( &ChannelCheckTimer, minTime );
-        TimerStart( &ChannelCheckTimer );
-        LoRaMacState |= MAC_CHANNEL_CHECK;
-    }
-    return 1;
+
+    *datarateOut = datarate;
+
+    return adrAckReq;
 }
 
-/*
- * TODO: Add documentation
- */
-void OnChannelCheckTimerEvent( void )
+static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
 {
-    TimerStop( &ChannelCheckTimer );
-    
-    LoRaMacState &= ~MAC_CHANNEL_CHECK;
-    if( LoRaMacSetNextChannel( ) == 0 )
-    {
-        if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
-        {
-           LoRaMacSendFrameOnChannel( Channels[Channel] );
-        }
-    }
-}
-
-/*!
- * Adds a new MAC command to be sent.
- *
- * \Remark MAC layer internal function
- *
- * \param [in] cmd MAC command to be added
- *                 [MOTE_MAC_LINK_CHECK_REQ,
- *                  MOTE_MAC_LINK_ADR_ANS,
- *                  MOTE_MAC_DUTY_CYCLE_ANS,
- *                  MOTE_MAC_RX2_PARAM_SET_ANS,
- *                  MOTE_MAC_DEV_STATUS_ANS
- *                  MOTE_MAC_NEW_CHANNEL_ANS]
- * \param [in] p1  1st parameter ( optional depends on the command )
- * \param [in] p2  2nd parameter ( optional depends on the command )
- *
- * \retval status  Function status [0: OK, 1: Unknown command, 2: Busy]
- */
-static uint8_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
-{
-    uint8_t status = 2; // Busy
+    LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
 
     switch( cmd )
     {
@@ -755,7 +1892,7 @@
             {
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // No payload for this command
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_LINK_ADR_ANS:
@@ -764,7 +1901,7 @@
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // Margin
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_DUTY_CYCLE_ANS:
@@ -772,7 +1909,7 @@
             {
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // No payload for this answer
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_RX_PARAM_SETUP_ANS:
@@ -781,7 +1918,7 @@
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // Status: Datarate ACK, Channel ACK
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_DEV_STATUS_ANS:
@@ -792,7 +1929,7 @@
                 // 2nd byte Margin
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_NEW_CHANNEL_ANS:
@@ -801,7 +1938,7 @@
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // Status: Datarate range OK, Channel frequency OK
                 MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         case MOTE_MAC_RX_TIMING_SETUP_ANS:
@@ -809,642 +1946,20 @@
             {
                 MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
                 // No payload for this answer
-                status = 0; // OK
+                status = LORAMAC_STATUS_OK;
             }
             break;
         default:
-            return 1; // Unknown command
+            return LORAMAC_STATUS_SERVICE_UNKNOWN;
     }
-    if( status == 0 )
+    if( status == LORAMAC_STATUS_OK )
     {
         MacCommandsInNextTx = true;
     }
     return status;
 }
 
-// TODO: Add Documentation
-static void LoRaMacNotify( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
-{
-    if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->MacEvent != NULL ) )
-    {
-        LoRaMacCallbacks->MacEvent( flags, info );
-    }
-    flags->Value = 0;
-}
-
-void LoRaMacInit( LoRaMacCallbacks_t *callbacks )
-{
-    LoRaMacCallbacks = callbacks;
-
-    LoRaMacEventFlags.Value = 0;
-    
-    LoRaMacEventInfo.TxAckReceived = false;
-    LoRaMacEventInfo.TxNbRetries = 0;
-    LoRaMacEventInfo.TxDatarate = 7;
-    LoRaMacEventInfo.RxPort = 1;
-    LoRaMacEventInfo.RxBuffer = NULL;
-    LoRaMacEventInfo.RxBufferSize = 0;
-    LoRaMacEventInfo.RxRssi = 0;
-    LoRaMacEventInfo.RxSnr = 0;
-    LoRaMacEventInfo.Energy = 0;
-    LoRaMacEventInfo.DemodMargin = 0;
-    LoRaMacEventInfo.NbGateways = 0;
-    LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-   
-    LoRaMacDeviceClass = CLASS_A;
-    
-    UpLinkCounter = 1;
-    DownLinkCounter = 0;
-    
-    IsLoRaMacNetworkJoined = false;
-    LoRaMacState = MAC_IDLE;
-
-#if defined( USE_BAND_433 )
-    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined( USE_BAND_780 )
-    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined( USE_BAND_868 )
-    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
-#elif defined( USE_BAND_915 )
-    ChannelsMask[0] = 0xFFFF;
-    ChannelsMask[1] = 0xFFFF;
-    ChannelsMask[2] = 0xFFFF;
-    ChannelsMask[3] = 0xFFFF;
-    ChannelsMask[4] = 0x00FF;
-    ChannelsMask[5] = 0x0000;
-#elif defined( USE_BAND_915_HYBRID )
-    ChannelsMask[0] = 0x00FF;
-    ChannelsMask[1] = 0x0000;
-    ChannelsMask[2] = 0x0000;
-    ChannelsMask[3] = 0x0000;
-    ChannelsMask[4] = 0x0001;
-    ChannelsMask[5] = 0x0000;
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    // 125 kHz channels
-    for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ )
-    {
-        Channels[i].Frequency = 902.3e6 + i * 200e3;
-        Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
-        Channels[i].Band = 0;
-    }
-    // 500 kHz channels
-    for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ )
-    {
-        Channels[i].Frequency = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6;
-        Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
-        Channels[i].Band = 0;
-    }
-#endif
-
-    ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
-    ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
-    ChannelsNbRep = 1;
-    ChannelsNbRepCounter = 0;
-    
-    MaxDCycle = 0;
-    AggregatedDCycle = 1;
-    AggregatedLastTxDoneTime = 0;
-    AggregatedTimeOff = 0;
-
-#if defined( USE_BAND_433 )
-    DutyCycleOn = false;
-#elif defined( USE_BAND_780 )
-    DutyCycleOn = false;
-#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
-
-    MaxRxWindow = MAX_RX_WINDOW;
-    ReceiveDelay1 = RECEIVE_DELAY1;
-    ReceiveDelay2 = RECEIVE_DELAY2;
-    JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
-    JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
-
-    TimerInit( &MacStateCheckTimer, OnMacStateCheckTimerEvent );
-    TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT );
-
-    TimerInit( &ChannelCheckTimer, OnChannelCheckTimerEvent );
-    TimerInit( &TxDelayedTimer, OnTxDelayedTimerEvent );
-    TimerInit( &RxWindowTimer1, OnRxWindow1TimerEvent );
-    TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent );
-    TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent );
-    
-    // Initialize Radio driver
-    RadioEvents.TxDone = OnRadioTxDone;
-    RadioEvents.RxDone = OnRadioRxDone;
-    RadioEvents.RxError = OnRadioRxError;
-    RadioEvents.TxTimeout = OnRadioTxTimeout;
-    RadioEvents.RxTimeout = OnRadioRxTimeout;
-    Radio.Init( &RadioEvents );
-
-    // Random seed initialization
-    srand1( Radio.Random( ) );
-
-    // Initialize channel index.
-    Channel = LORA_MAX_NB_CHANNELS;
-
-    PublicNetwork = true;
-    LoRaMacSetPublicNetwork( PublicNetwork );
-    Radio.Sleep( );
-}
-
-void LoRaMacSetAdrOn( bool enable )
-{
-    AdrCtrlOn = enable;
-}
-
-void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey )
-{
-    LoRaMacNetID = netID;
-    LoRaMacDevAddr = devAddr;
-    LoRaMacMemCpy( nwkSKey, LoRaMacNwkSKey, 16 );
-    LoRaMacMemCpy( appSKey, LoRaMacAppSKey, 16 );
-    
-    IsLoRaMacNetworkJoined = true;
-}
-
-void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam )
-{
-    // Reset downlink counter
-    channelParam->DownLinkCounter = 0;
-    
-    if( MulticastChannels == NULL )
-    {
-        MulticastChannels = channelParam;
-    }
-    else
-    {
-        MulticastParams_t *cur = MulticastChannels;
-        while( cur->Next != NULL )
-        {
-            cur = cur->Next;
-        }
-        cur->Next = channelParam;
-    }
-}
-
-void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam )
-{
-    MulticastParams_t *cur = NULL;
-    
-    // Remove the front element
-    if( MulticastChannels == channelParam )
-    {
-        if( MulticastChannels != NULL )
-        {
-            cur = MulticastChannels;
-            MulticastChannels = MulticastChannels->Next;
-            cur->Next = NULL;
-            // Last node in the list
-            if( cur == MulticastChannels )
-            {
-                MulticastChannels = NULL;
-            }
-        }
-        return;
-    }
-    
-    // Remove last element
-    if( channelParam->Next == NULL )
-    {
-        if( MulticastChannels != NULL )
-        {
-            cur = MulticastChannels;
-            MulticastParams_t *last = NULL;
-            while( cur->Next != NULL )
-            {
-                last = cur;
-                cur = cur->Next;
-            }
-            if( last != NULL )
-            {
-                last->Next = NULL;
-            }
-            // Last node in the list
-            if( cur == last )
-            {
-                MulticastChannels = NULL;
-            }
-        }
-        return;
-    }
-    
-    // Remove a middle element
-    cur = MulticastChannels;
-    while( cur != NULL )
-    {
-        if( cur->Next == channelParam )
-        {
-            break;
-        }
-        cur = cur->Next;
-    }
-    if( cur != NULL )
-    {
-        MulticastParams_t *tmp = cur ->Next;
-        cur->Next = tmp->Next;
-        tmp->Next = NULL;
-    }
-}
-
-uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey )
-{
-    LoRaMacHeader_t macHdr;
-
-    LoRaMacDevEui = devEui;
-    LoRaMacAppEui = appEui;
-    LoRaMacAppKey = appKey;
-    
-    macHdr.Value = 0;
-    macHdr.Bits.MType        = FRAME_TYPE_JOIN_REQ;
-    
-    IsLoRaMacNetworkJoined = false;
-    
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    static uint8_t drSwitch = 0;
-    
-    if( ( ++drSwitch & 0x01 ) == 0x01 )
-    {
-        ChannelsDatarate = DR_0;
-    }
-    else
-    {
-        ChannelsDatarate = DR_4;
-    }
-#endif
-    return LoRaMacSend( &macHdr, NULL, 0, NULL, 0 );
-}
-
-uint8_t LoRaMacLinkCheckReq( void )
-{
-    return AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
-}
-
-uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
-    LoRaMacHeader_t macHdr;
-
-    macHdr.Value = 0;
-
-    macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
-    return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
-}
-
-uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t retries )
-{
-    LoRaMacHeader_t macHdr;
-
-    if( AdrCtrlOn == false )
-    {
-        ChannelsDatarate = ChannelsDefaultDatarate;
-    }
-    AckTimeoutRetries = retries;
-    AckTimeoutRetriesCounter = 1;
-    
-    macHdr.Value = 0;
-
-    macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
-    return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
-}
-
-uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
-    LoRaMacFrameCtrl_t fCtrl;
-
-    fCtrl.Value = 0;
-
-    fCtrl.Bits.FOptsLen      = 0;
-    fCtrl.Bits.FPending      = 0;
-    fCtrl.Bits.Ack           = false;
-    fCtrl.Bits.AdrAckReq     = false;
-    fCtrl.Bits.Adr           = AdrCtrlOn;
-
-    if( LoRaMacSetNextChannel( ) == 0 )
-    {
-        return LoRaMacSendOnChannel( Channels[Channel], macHdr, &fCtrl, fOpts, fPort, fBuffer, fBufferSize );
-    }
-    return 5;
-}
-
-uint8_t LoRaMacPrepareFrame( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
-    uint16_t i;
-    uint8_t pktHeaderLen = 0;
-    uint32_t mic = 0;
-    
-    LoRaMacBufferPktLen = 0;
-    
-    NodeAckRequested = false;
-    
-    if( fBuffer == NULL )
-    {
-        fBufferSize = 0;
-    }
-    else
-    {
-        if( ValidatePayloadLength( fBufferSize, ChannelsDatarate ) == false )
-        {
-            return 3;
-        }
-    }
-
-    LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
-
-    switch( macHdr->Bits.MType )
-    {
-        case FRAME_TYPE_JOIN_REQ:            
-            RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
-            RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
-
-            LoRaMacBufferPktLen = pktHeaderLen;
-        
-            LoRaMacMemCpy( LoRaMacAppEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
-            LoRaMacBufferPktLen += 8;
-            LoRaMacMemCpy( LoRaMacDevEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
-            LoRaMacBufferPktLen += 8;
-
-            LoRaMacDevNonce = Radio.Random( );
-            
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
-
-            LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic );
-            
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF;
-            
-            break;
-        case FRAME_TYPE_DATA_CONFIRMED_UP:
-            NodeAckRequested = true;
-            //Intentional falltrough
-        case FRAME_TYPE_DATA_UNCONFIRMED_UP:
-            if( IsLoRaMacNetworkJoined == false )
-            {
-                return 2; // No network has been joined yet
-            }
-            
-            RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
-            RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
-
-            if( fOpts == NULL )
-            {
-                fCtrl->Bits.FOptsLen = 0;
-            }
-
-            if( SrvAckRequested == true )
-            {
-                SrvAckRequested = false;
-                fCtrl->Bits.Ack = 1;
-            }
-            
-            if( fCtrl->Bits.Adr == true )
-            {
-                if( ChannelsDatarate == LORAMAC_MIN_DATARATE )
-                {
-                    AdrAckCounter = 0;
-                    fCtrl->Bits.AdrAckReq = false;
-                }
-                else
-                {
-                    if( AdrAckCounter > ADR_ACK_LIMIT )
-                    {
-                        fCtrl->Bits.AdrAckReq = true;
-                    }
-                    else
-                    {
-                        fCtrl->Bits.AdrAckReq = false;
-                    }
-                    if( AdrAckCounter > ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
-                    {
-                        AdrAckCounter = 0;
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                        if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
-                        {
-                            ChannelsDatarate--;
-                        }
-                        else
-                        {
-                            // Re-enable default channels LC1, LC2, LC3
-                            ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-                        }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                        if( ( ChannelsDatarate > LORAMAC_MIN_DATARATE ) && ( ChannelsDatarate == DR_8 ) )
-                        {
-                            ChannelsDatarate = DR_4;
-                        }
-                        if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
-                        {
-                            ChannelsDatarate--;
-                        }
-                        else
-                        {
-#if defined( USE_BAND_915 )
-                            // Re-enable default channels
-                            ChannelsMask[0] = 0xFFFF;
-                            ChannelsMask[1] = 0xFFFF;
-                            ChannelsMask[2] = 0xFFFF;
-                            ChannelsMask[3] = 0xFFFF;
-                            ChannelsMask[4] = 0x00FF;
-                            ChannelsMask[5] = 0x0000;
-#else // defined( USE_BAND_915_HYBRID )
-                            // Re-enable default channels
-                            ChannelsMask[0] = 0x00FF;
-                            ChannelsMask[1] = 0x0000;
-                            ChannelsMask[2] = 0x0000;
-                            ChannelsMask[3] = 0x0000;
-                            ChannelsMask[4] = 0x0001;
-                            ChannelsMask[5] = 0x0000;
-#endif
-                        }
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-                    }
-                }
-            }
-            
-            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
-            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
-            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
-            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
-
-            LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value;
-
-            LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
-            LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
-
-            if( fOpts != NULL )
-            {
-                for( i = 0; i < fCtrl->Bits.FOptsLen; i++ )
-                {
-                    LoRaMacBuffer[pktHeaderLen++] = fOpts[i];
-                }
-            }
-            if( ( MacCommandsBufferIndex + fCtrl->Bits.FOptsLen ) <= 15 )
-            {
-                if( MacCommandsInNextTx == true )
-                {
-                    fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
-                    
-                    // Update FCtrl field with new value of OptionsLength
-                    LoRaMacBuffer[0x05] = fCtrl->Value;
-                    for( i = 0; i < MacCommandsBufferIndex; i++ )
-                    {
-                        LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
-                    }
-                }
-            }
-            MacCommandsInNextTx = false;
-            MacCommandsBufferIndex = 0;
-            
-            if( ( pktHeaderLen + fBufferSize ) > LORAMAC_PHY_MAXPAYLOAD )
-            {
-                return 3;
-            }
-
-            if( fBuffer != NULL )
-            {
-                LoRaMacBuffer[pktHeaderLen++] = fPort;
-                
-                if( fPort == 0 )
-                {
-                    LoRaMacPayloadEncrypt( ( uint8_t* )fBuffer, fBufferSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
-                }
-                else
-                {
-                    LoRaMacPayloadEncrypt( ( uint8_t* )fBuffer, fBufferSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
-                }
-                LoRaMacMemCpy( LoRaMacPayload, LoRaMacBuffer + pktHeaderLen, fBufferSize );
-            }
-            LoRaMacBufferPktLen = pktHeaderLen + fBufferSize;
-
-            LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
-
-            if( ( LoRaMacBufferPktLen + LORAMAC_MFR_LEN ) > LORAMAC_PHY_MAXPAYLOAD )
-            {
-                return 3;
-            }
-            LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF;
-            LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
-            
-            LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
-            break;
-        default:
-            return 4;
-    }
-
-    return 0;
-}
-
-uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel )
-{
-    LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
-    LoRaMacEventInfo.TxDatarate = ChannelsDatarate;
-
-    ChannelsTxPower = LimitTxPower( ChannelsTxPower );
-
-    Radio.SetChannel( channel.Frequency );
-    Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    if( ChannelsDatarate == DR_7 )
-    { // High Speed FSK channel
-        Radio.SetTxConfig( MODEM_FSK, TxPowers[ChannelsTxPower], 25e3, 0, Datarates[ChannelsDatarate] * 1e3, 0, 5, false, true, 0, 0, false, 3e6 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
-    }
-    else if( ChannelsDatarate == DR_6 )
-    { // High speed LoRa channel
-        Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 1, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-    else
-    { // Normal LoRa channel
-        Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( ChannelsDatarate >= DR_4 )
-    { // High speed LoRa channel BW500 kHz
-        Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 2, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-    else
-    { // Normal LoRa channel
-        Radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
-        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
-    }
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-
-    if( MaxDCycle == 255 )
-    {
-        return 6;
-    }
-    if( MaxDCycle == 0 )
-    {
-        AggregatedTimeOff = 0;
-    }
-
-    LoRaMacState |= MAC_TX_RUNNING;
-    // Starts the MAC layer status check timer
-    TimerStart( &MacStateCheckTimer );
-    
-    if( MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) > ( TimerGetCurrentTime( ) ) )
-    {
-        // Schedule transmission
-        TimerSetValue( &TxDelayedTimer, MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) );
-        TimerStart( &TxDelayedTimer );
-    }
-    else
-    {
-        // Send now
-        Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
-    }
-    return 0;
-}
-
-
-void OnTxDelayedTimerEvent( void )
-{
-    TimerStop( &TxDelayedTimer );
-    Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
-}
-
-uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
-    uint8_t status = 0;
-    
-    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
-    {
-        return 1; // MAC is busy transmitting a previous frame
-    }
-
-    status = LoRaMacPrepareFrame( channel, macHdr, fCtrl, fOpts, fPort, fBuffer, fBufferSize );
-    if( status != 0 )
-    {
-        return status;
-    }
-
-    LoRaMacEventInfo.TxNbRetries = 0;
-    LoRaMacEventInfo.TxAckReceived = false;
-
-    return LoRaMacSendFrameOnChannel( channel );
-}
-
-static void LoRaMacProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize )
+static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
 {
     while( macIndex < commandsSize )
     {
@@ -1452,12 +1967,13 @@
         switch( payload[macIndex++] )
         {
             case SRV_MAC_LINK_CHECK_ANS:
-                LoRaMacEventFlags.Bits.LinkCheck = 1;
-                LoRaMacEventInfo.DemodMargin = payload[macIndex++];
-                LoRaMacEventInfo.NbGateways = payload[macIndex++];
+                MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+                MlmeConfirm.DemodMargin = payload[macIndex++];
+                MlmeConfirm.NbGateways = payload[macIndex++];
                 break;
             case SRV_MAC_LINK_ADR_REQ:
                 {
+                    uint8_t i;
                     uint8_t status = 0x07;
                     uint16_t chMask;
                     int8_t txPower = 0;
@@ -1465,9 +1981,9 @@
                     uint8_t nbRep = 0;
                     uint8_t chMaskCntl = 0;
                     uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
-                    
+
                     // Initialize local copy of the channels mask array
-                    for( uint8_t i = 0; i < 6; i++ )
+                    for( i = 0; i < 6; i++ )
                     {
                         channelsMask[i] = ChannelsMask[i];
                     }
@@ -1475,7 +1991,7 @@
                     txPower = datarate & 0x0F;
                     datarate = ( datarate >> 4 ) & 0x0F;
 
-                    if( ( AdrCtrlOn == false ) && 
+                    if( ( AdrCtrlOn == false ) &&
                         ( ( ChannelsDatarate != datarate ) || ( ChannelsTxPower != txPower ) ) )
                     { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower
                         // Answer the server with fail status
@@ -1501,14 +2017,15 @@
                     {
                         status &= 0xFE; // Channel mask KO
                     }
-                    else if( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 ) )
+                    else if( ( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 )) ||
+                             ( chMaskCntl >= 7 ) )
                     {
                         // RFU
                         status &= 0xFE; // Channel mask KO
                     }
                     else
                     {
-                        for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
+                        for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
                         {
                             if( chMaskCntl == 6 )
                             {
@@ -1567,7 +2084,7 @@
                             }
                         }
                         channelsMask[chMaskCntl] = chMask;
-                        
+
                         if( CountNbEnabled125kHzChannels( channelsMask ) < 6 )
                         {
                             status &= 0xFE; // Channel mask KO
@@ -1576,8 +2093,7 @@
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
-                    if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
-                          ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
+                    if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
                     {
                         status &= 0xFD; // Datarate KO
                     }
@@ -1585,8 +2101,7 @@
                     //
                     // Remark MaxTxPower = 0 and MinTxPower = 5
                     //
-                    if( ( ( LORAMAC_MAX_TX_POWER <= txPower ) &&
-                          ( txPower <= LORAMAC_MIN_TX_POWER ) ) == false )
+                    if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
                     {
                         status &= 0xFB; // TxPower KO
                     }
@@ -1625,32 +2140,37 @@
                     int8_t datarate = 0;
                     int8_t drOffset = 0;
                     uint32_t freq = 0;
-                
+
                     drOffset = ( payload[macIndex] >> 4 ) & 0x07;
                     datarate = payload[macIndex] & 0x0F;
                     macIndex++;
-                    freq = ( uint32_t )payload[macIndex++];
+
+                    freq =  ( uint32_t )payload[macIndex++];
                     freq |= ( uint32_t )payload[macIndex++] << 8;
                     freq |= ( uint32_t )payload[macIndex++] << 16;
                     freq *= 100;
-                    
+
                     if( Radio.CheckRfFrequency( freq ) == false )
                     {
                         status &= 0xFE; // Channel frequency KO
                     }
-                    
-                    if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
-                          ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
+
+                    if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
                     {
                         status &= 0xFD; // Datarate KO
                     }
-
-                    if( ( ( drOffset < LORAMAC_MIN_RX1_DR_OFFSET ) ||
-                          ( drOffset > LORAMAC_MAX_RX1_DR_OFFSET ) ) == true )
+#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+                    if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) ||
+                        ( datarate > DR_13 ) )
+                    {
+                        status &= 0xFD; // Datarate KO
+                    }
+#endif
+                    if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false )
                     {
                         status &= 0xFB; // Rx1DrOffset range KO
                     }
-                    
+
                     if( ( status & 0x07 ) == 0x07 )
                     {
                         Rx2Channel.Datarate = datarate;
@@ -1667,51 +2187,48 @@
                     {
                         batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
                     }
-                    AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, LoRaMacEventInfo.RxSnr );
+                    AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
+                    break;
                 }
-                break;
             case SRV_MAC_NEW_CHANNEL_REQ:
                 {
                     uint8_t status = 0x03;
+#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+                    status &= 0xFE; // Channel frequency KO
+#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++];
-                    
-                    if( ( channelIndex < 3 ) || ( channelIndex > LORA_MAX_NB_CHANNELS ) )
+
+                    if( ValueInRange( channelIndex, 3, LORA_MAX_NB_CHANNELS - 1 ) == false )
+
                     {
                         status &= 0xFE; // Channel frequency KO
                     }
-                
+
                     if( Radio.CheckRfFrequency( chParam.Frequency ) == false )
                     {
                         status &= 0xFE; // Channel frequency KO
                     }
 
-                    if( ( chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max ) ||
-                        ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Min ) &&
-                            ( chParam.DrRange.Fields.Min <= LORAMAC_MAX_DATARATE ) ) == false ) ||
-                        ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Max ) &&
-                            ( chParam.DrRange.Fields.Max <= LORAMAC_MAX_DATARATE ) ) == false ) )
+                    if( LoRaMacChannelAdd( channelIndex, chParam ) != LORAMAC_STATUS_OK )
                     {
                         status &= 0xFD; // Datarate range KO
                     }
-                    if( ( status & 0x03 ) == 0x03 )
-                    {
-                        LoRaMacSetChannel( channelIndex, chParam );
-                    }
+#endif
                     AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 );
                 }
                 break;
             case SRV_MAC_RX_TIMING_SETUP_REQ:
                 {
                     uint8_t delay = payload[macIndex++] & 0x0F;
-                    
+
                     if( delay == 0 )
                     {
                         delay++;
@@ -1728,891 +2245,836 @@
     }
 }
 
-/*!
- * Function to be executed on Tx Done event
- */
-static void OnRadioTxDone( void )
+LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
 {
-    TimerTime_t curTime = TimerGetCurrentTime( );
-    if( LoRaMacDeviceClass != CLASS_C )
-    {
-        Radio.Sleep( );
-    }
-    else
-    {
-        OnRxWindow2TimerEvent( );
-    }
-
-    // Update Band Time OFF
-    Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
-    if( DutyCycleOn == true )
-    {
-        Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
-    }
-    else
-    {
-        Bands[Channels[Channel].Band].TimeOff = 0;
-    }
-    // Update Agregated Time OFF
-    AggregatedLastTxDoneTime = curTime;
-    AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
-
-    if( IsRxWindowsEnabled == true )
+    LoRaMacFrameCtrl_t fCtrl;
+    LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
+
+    fCtrl.Value = 0;
+    fCtrl.Bits.FOptsLen      = 0;
+    fCtrl.Bits.FPending      = 0;
+    fCtrl.Bits.Ack           = false;
+    fCtrl.Bits.AdrAckReq     = false;
+    fCtrl.Bits.Adr           = AdrCtrlOn;
+
+    // Prepare the frame
+    status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize );
+
+    // Validate status
+    if( status != LORAMAC_STATUS_OK )
     {
-        TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
-        TimerStart( &RxWindowTimer1 );
-        if( LoRaMacDeviceClass != CLASS_C )
-        {
-            TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
-            TimerStart( &RxWindowTimer2 );
-        }
-        if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
-        {
-            TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT +
-                                             randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
-            TimerStart( &AckTimeoutTimer );
-        }
+        return status;
     }
-    else
-    {
-        LoRaMacEventFlags.Bits.Tx = 1;
-        LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-    }
-    
-    if( NodeAckRequested == false )
-    {
-        LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-        ChannelsNbRepCounter++;
-    }
+
+    // Reset confirm parameters
+    McpsConfirm.NbRetries = 0;
+    McpsConfirm.AckReceived = false;
+    McpsConfirm.UpLinkCounter = UpLinkCounter;
+
+    status = ScheduleTx( );
+
+    return status;
 }
 
-/*!
- * Function to be executed on Rx Done event
- */
-static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
+static LoRaMacStatus_t ScheduleTx( )
 {
-    LoRaMacHeader_t macHdr;
-    LoRaMacFrameCtrl_t fCtrl;
-
-    uint8_t pktHeaderLen = 0;
-    uint32_t address = 0;
-    uint8_t appPayloadStartIndex = 0;
-    uint8_t port = 0xFF;
-    uint8_t frameLen = 0;
-    uint32_t mic = 0;
-    uint32_t micRx = 0;
-    
-    uint16_t sequenceCounter = 0;
-    uint16_t sequenceCounterPrev = 0;
-    uint16_t sequenceCounterDiff = 0;
-    uint32_t downLinkCounter = 0;
-
-    MulticastParams_t *curMulticastParams = NULL;
-    uint8_t *nwkSKey = LoRaMacNwkSKey;
-    uint8_t *appSKey = LoRaMacAppSKey;
-    
-    bool isMicOk = false;
-
-    if( LoRaMacDeviceClass != CLASS_C )
+    TimerTime_t dutyCycleTimeOff = 0;
+
+    // Check if the device is off
+    if( MaxDCycle == 255 )
+    {
+        return LORAMAC_STATUS_DEVICE_OFF;
+    }
+    if( MaxDCycle == 0 )
     {
-        Radio.Sleep( );
+        AggregatedTimeOff = 0;
+    }
+
+    // Select channel
+    dutyCycleTimeOff = SetNextChannel( );
+
+    // Schedule transmission of frame
+    if( dutyCycleTimeOff == 0 )
+    {
+        // Try to send now
+        return SendFrameOnChannel( Channels[Channel] );
     }
     else
     {
-        if( LoRaMacEventFlags.Bits.RxSlot == 0 )
-        {
-            OnRxWindow2TimerEvent( );
-        }
+        // Send later - prepare timer
+        LoRaMacState |= MAC_TX_DELAYED;
+        TimerSetValue( &TxDelayedTimer, dutyCycleTimeOff );
+        TimerStart( &TxDelayedTimer );
+
+        return LORAMAC_STATUS_OK;
     }
-    TimerStop( &RxWindowTimer2 );
-
-    macHdr.Value = payload[pktHeaderLen++];
-    
-    switch( macHdr.Bits.MType )
+}
+
+LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+{
+    uint16_t i;
+    uint8_t pktHeaderLen = 0;
+    uint32_t mic = 0;
+    const void* payload = fBuffer;
+    uint8_t payloadSize = fBufferSize;
+    uint8_t framePort = fPort;
+
+    LoRaMacBufferPktLen = 0;
+
+    NodeAckRequested = false;
+
+    if( fBuffer == NULL )
     {
-        case FRAME_TYPE_JOIN_ACCEPT:
-            if( IsLoRaMacNetworkJoined == true )
-            {
-                break;
-            }
-            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 )
+        fBufferSize = 0;
+    }
+
+    LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
+
+    switch( macHdr->Bits.MType )
+    {
+        case FRAME_TYPE_JOIN_REQ:
+            RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
+            RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
+
+            LoRaMacBufferPktLen = pktHeaderLen;
+
+            memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 );
+            LoRaMacBufferPktLen += 8;
+            memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8 );
+            LoRaMacBufferPktLen += 8;
+
+            LoRaMacDevNonce = Radio.Random( );
+
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF;
+
+            LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic );
+
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF;
+
+            break;
+        case FRAME_TYPE_DATA_CONFIRMED_UP:
+            NodeAckRequested = true;
+            //Intentional falltrough
+        case FRAME_TYPE_DATA_UNCONFIRMED_UP:
+            if( IsLoRaMacNetworkJoined == false )
             {
-                LoRaMacEventFlags.Bits.Rx = 1;
-                LoRaMacEventInfo.RxSnr = snr;
-                LoRaMacEventInfo.RxRssi = rssi;
-
-                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
-                Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
-                Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-                /*
-                 * WARNING: To be removed once Semtech server implementation
-                 *          is corrected.
-                 */
-                if( Rx2Channel.Datarate == DR_3 )
+                return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
+            }
+
+            if( ValidatePayloadLength( fBufferSize, ChannelsDatarate, MacCommandsBufferIndex ) == false )
+            {
+                return LORAMAC_STATUS_LENGTH_ERROR;
+            }
+
+            RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
+            RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
+
+            if( SrvAckRequested == true )
+            {
+                SrvAckRequested = false;
+                fCtrl->Bits.Ack = 1;
+            }
+
+            fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &ChannelsDatarate );
+
+            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
+            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
+            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
+            LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF;
+
+            LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value;
+
+            LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
+            LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
+
+            if( ( payload != NULL ) && ( payloadSize > 0 ) )
+            {
+                if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
                 {
-                    Rx2Channel.Datarate = DR_8;
-                }
-#endif
-                // RxDelay
-                ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
-                if( ReceiveDelay1 == 0 )
-                {
-                    ReceiveDelay1 = 1;
-                }
-                ReceiveDelay1 *= 1e6;
-                ReceiveDelay2 = ReceiveDelay1 + 1e6;
-
-#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;
-
-                    for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
+                    fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
+
+                    // Update FCtrl field with new value of OptionsLength
+                    LoRaMacBuffer[0x05] = fCtrl->Value;
+                    for( i = 0; i < MacCommandsBufferIndex; i++ )
                     {
-                        param.Frequency = ( ( uint32_t )LoRaMacRxPayload[13 + j] | ( ( uint32_t )LoRaMacRxPayload[14 + j] << 8 ) | ( ( uint32_t )LoRaMacRxPayload[15 + j] << 16 ) ) * 100;
-                        LoRaMacSetChannel( i, param );
+                        LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
                     }
                 }
-#endif
-                LoRaMacEventFlags.Bits.JoinAccept = 1;
-                IsLoRaMacNetworkJoined = true;
-                ChannelsDatarate = ChannelsDefaultDatarate;
-                LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
             }
             else
             {
-                LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
-            }
-            break;
-        case FRAME_TYPE_DATA_CONFIRMED_DOWN:
-        case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
-            {
-                address = payload[pktHeaderLen++];
-                address |= ( (uint32_t)payload[pktHeaderLen++] << 8 );
-                address |= ( (uint32_t)payload[pktHeaderLen++] << 16 );
-                address |= ( (uint32_t)payload[pktHeaderLen++] << 24 );
-
-                if( address != LoRaMacDevAddr )
+                if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
                 {
-                    curMulticastParams = MulticastChannels;
-                    while( curMulticastParams != NULL )
-                    {
-                        if( address == curMulticastParams->Address )
-                        {
-                            LoRaMacEventFlags.Bits.Multicast = 1;
-                            nwkSKey = curMulticastParams->NwkSKey;
-                            appSKey = curMulticastParams->AppSKey;
-                            downLinkCounter = curMulticastParams->DownLinkCounter;
-                            break;
-                        }
-                        curMulticastParams = curMulticastParams->Next;
-                    }
-                    if( LoRaMacEventFlags.Bits.Multicast == 0 )
-                    {
-                        // We are not the destination of this frame.
-                        LoRaMacEventFlags.Bits.Tx = 1;
-                        LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
-                        LoRaMacState &= ~MAC_TX_RUNNING;
-                        return;
-                    }
+                    payloadSize = MacCommandsBufferIndex;
+                    payload = MacCommandsBuffer;
+                    framePort = 0;
                 }
-                else
-                {
-                    LoRaMacEventFlags.Bits.Multicast = 0;
-                    nwkSKey = LoRaMacNwkSKey;
-                    appSKey = LoRaMacAppSKey;
-                    downLinkCounter = DownLinkCounter;
-                }
-                
-                if( LoRaMacDeviceClass != CLASS_A )
+            }
+            MacCommandsInNextTx = false;
+            MacCommandsBufferIndex = 0;
+
+            if( ( payload != NULL ) && ( payloadSize > 0 ) )
+            {
+                LoRaMacBuffer[pktHeaderLen++] = framePort;
+
+                if( framePort == 0 )
                 {
-                    LoRaMacState |= MAC_RX;
-                    // Starts the MAC layer status check timer
-                    TimerStart( &MacStateCheckTimer );
-                }
-                fCtrl.Value = payload[pktHeaderLen++];
-                
-                sequenceCounter = ( uint16_t )payload[pktHeaderLen++];
-                sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8;
-
-                appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
-
-                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 );
-
-                sequenceCounterPrev = ( uint16_t )downLinkCounter;
-                sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
-
-                if( sequenceCounterDiff < ( 1 << 15 ) )
-                {
-                    downLinkCounter += sequenceCounterDiff;
-                    LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
-                    if( micRx == mic )
-                    {
-                        isMicOk = true;
-                    }
+                    LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
                 }
                 else
                 {
-                    // check for downlink counter roll-over
-                    uint32_t  downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
-                    LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
-                    if( micRx == mic )
-                    {
-                        isMicOk = true;
-                        downLinkCounter = downLinkCounterTmp;
-                    }
+                    LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
                 }
-
-                if( isMicOk == true )
-                {
-                    LoRaMacEventFlags.Bits.Rx = 1;
-                    LoRaMacEventInfo.RxSnr = snr;
-                    LoRaMacEventInfo.RxRssi = rssi;
-                    LoRaMacEventInfo.RxBufferSize = 0;
-                    AdrAckCounter = 0;
-
-                    // Update 32 bits downlink counter
-                    if( LoRaMacEventFlags.Bits.Multicast == 1 )
-                    {
-                        curMulticastParams->DownLinkCounter = downLinkCounter;
-                    }
-                    else
-                    {
-                        DownLinkCounter = downLinkCounter;
-                    }
-
-                    if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
-                    {
-                        SrvAckRequested = true;
-                    }
-                    else
-                    {
-                        SrvAckRequested = false;
-                    }
-                    // Check if the frame is an acknowledgement
-                    if( fCtrl.Bits.Ack == 1 )
-                    {
-                        LoRaMacEventInfo.TxAckReceived = true;
-
-                        // Stop the AckTimeout timer as no more retransmissions 
-                        // are needed.
-                        TimerStop( &AckTimeoutTimer );
-                    }
-                    else
-                    {
-                        LoRaMacEventInfo.TxAckReceived = false;
-                        if( AckTimeoutRetriesCounter > AckTimeoutRetries )
-                        {
-                            // Stop the AckTimeout timer as no more retransmissions 
-                            // are needed.
-                            TimerStop( &AckTimeoutTimer );
-                        }
-                    }
-                    
-                    if( fCtrl.Bits.FOptsLen > 0 )
-                    {
-                        // Decode Options field MAC commands
-                        LoRaMacProcessMacCommands( payload, 8, appPayloadStartIndex );
-                    }
-                    
-                    if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
-                    {
-                        port = payload[appPayloadStartIndex++];
-                        frameLen = ( size - 4 ) - appPayloadStartIndex;
-                        
-                        if( port == 0 )
-                        {
-                            LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
-                                                   frameLen,
-                                                   nwkSKey,
-                                                   address,
-                                                   DOWN_LINK,
-                                                   downLinkCounter,
-                                                   LoRaMacRxPayload );
-                            
-                            // Decode frame payload MAC commands
-                            LoRaMacProcessMacCommands( LoRaMacRxPayload, 0, frameLen );
-                        }
-                        else
-                        {
-                            LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
-                                                   frameLen,
-                                                   appSKey,
-                                                   address,
-                                                   DOWN_LINK,
-                                                   downLinkCounter,
-                                                   LoRaMacRxPayload );
-
-                            LoRaMacEventFlags.Bits.RxData = 1;
-                            LoRaMacEventInfo.RxPort = port;
-                            LoRaMacEventInfo.RxBuffer = LoRaMacRxPayload;
-                            LoRaMacEventInfo.RxBufferSize = frameLen;
-                        }
-                    }
-
-                    LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-                }
-                else
-                {
-                    LoRaMacEventInfo.TxAckReceived = false;
-                    
-                    LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
-                    LoRaMacState &= ~MAC_TX_RUNNING;
-                    if( NodeAckRequested == true )
-                    {
-                        OnAckTimeoutTimerEvent( );
-                    }
-                }
+                memcpy1( LoRaMacBuffer + pktHeaderLen, LoRaMacPayload, payloadSize );
+            }
+            LoRaMacBufferPktLen = pktHeaderLen + payloadSize;
+
+            LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
+
+            LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF;
+            LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
+
+            LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
+
+            break;
+        case FRAME_TYPE_PROPRIETARY:
+            if( ( fBuffer != NULL ) && ( fBufferSize > 0 ) )
+            {
+                memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, fBufferSize );
+                LoRaMacBufferPktLen = pktHeaderLen + fBufferSize;
             }
             break;
-        case FRAME_TYPE_PROPRIETARY:
-            //Intentional falltrough
         default:
-            LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
-            LoRaMacState &= ~MAC_TX_RUNNING;
-            break;
+            return LORAMAC_STATUS_SERVICE_UNKNOWN;
     }
-    LoRaMacEventFlags.Bits.Tx = 1;
+
+    return LORAMAC_STATUS_OK;
 }
 
-/*!
- * Function executed on Radio Tx Timeout event
- */
-static void OnRadioTxTimeout( void )
+LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel )
 {
-    if( LoRaMacDeviceClass != CLASS_C )
-    {
-        Radio.Sleep( );
-    }
-    else
-    {
-        OnRxWindow2TimerEvent( );
+    int8_t datarate = Datarates[ChannelsDatarate];
+    int8_t txPower = 0;
+
+    ChannelsTxPower = LimitTxPower( ChannelsTxPower );
+    txPower = TxPowers[ChannelsTxPower];
+
+    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+    McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+    McpsConfirm.Datarate = ChannelsDatarate;
+    McpsConfirm.TxPower = ChannelsTxPower;
+
+    Radio.SetChannel( channel.Frequency );
+
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+    if( 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, 3e6 );
+        TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
+
     }
-    
-    LoRaMacEventFlags.Bits.Tx = 1;
-    LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
-}
-
-/*!
- * Function executed on Radio Rx Timeout event
- */
-static void OnRadioRxTimeout( void )
-{
-    if( LoRaMacDeviceClass != CLASS_C )
-    {
-        Radio.Sleep( );
+    else if( 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, 3e6 );
+        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
     }
     else
-    {
-        OnRxWindow2TimerEvent( );
-    }
-    if( LoRaMacEventFlags.Bits.RxSlot == 1 )
-    {
-        LoRaMacEventFlags.Bits.Tx = 1;
-        LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
+    { // Normal LoRa channel
+        Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
+        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 );
+        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
     }
-}
-
-/*!
- * Function executed on Radio Rx Error event
- */
-static void OnRadioRxError( void )
-{
-    if( LoRaMacDeviceClass != CLASS_C )
-    {
-        Radio.Sleep( );
+#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+    Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
+    if( ChannelsDatarate >= DR_4 )
+    { // High speed LoRa channel BW500 kHz
+        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e6 );
+        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
     }
     else
-    {
-        OnRxWindow2TimerEvent( );
-    }
-    if( LoRaMacEventFlags.Bits.RxSlot == 1 )
-    {
-        LoRaMacEventFlags.Bits.Tx = 1;
-        LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
-    }
-}
-
-/*!
- * 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
- */
-void LoRaMacRxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
-{
-    uint8_t downlinkDatarate = Datarates[datarate];
-    RadioModems_t modem;
-
-    if( Radio.GetStatus( ) == RF_IDLE )
-    {
-        Radio.SetChannel( freq );
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-        if( datarate == DR_7 )
-        {
-            modem = MODEM_FSK;
-            Radio.SetRxConfig( MODEM_FSK, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
-        }
-        else
-        {
-            modem = MODEM_LORA;
-            Radio.SetRxConfig( MODEM_LORA, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
-        }
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-        modem = MODEM_LORA;
-        Radio.SetRxConfig( MODEM_LORA, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
-#endif
-        if( RepeaterSupport == true )
-        {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] );
-        }
-        else
-        {
-            Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] );
-        }
-
-        if( rxContinuous == false )
-        {
-            Radio.Rx( MaxRxWindow );
-        }
-        else
-        {
-            Radio.Rx( 0 ); // Continuous mode
-        }
-    }
-}
-
-/*!
- * Function executed on first Rx window timer event
- */
-static void OnRxWindow1TimerEvent( void )
-{
-    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
-    int8_t datarate = 0;
-    uint32_t bandwidth = 0; // LoRa 125 kHz
-
-    TimerStop( &RxWindowTimer1 );
-    LoRaMacEventFlags.Bits.RxSlot = 0;
-
-    if( LoRaMacDeviceClass == CLASS_C )
-    {
-        Radio.Standby( );
-    }
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    datarate = ChannelsDatarate - Rx1DrOffset;
-    if( datarate < 0 )
-    {
-        datarate = DR_0;
-    }
-
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( datarate >= DR_3 )
-    { // DR_6, DR_5, DR_4, DR_3
-        symbTimeout = 8;
-    }
-    if( datarate == DR_6 )
-    {// LoRa 250 kHz
-        bandwidth  = 1;
-    }
-    LoRaMacRxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    datarate = datarateOffsets[ChannelsDatarate][Rx1DrOffset];
-    if( datarate < 0 )
-    {
-        datarate = DR_0;
-    }
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( datarate > DR_0 )
-    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
-        symbTimeout = 8;
-    }
-    if( datarate >= DR_4 )
-    {// LoRa 500 kHz
-        bandwidth  = 2;
-    }
-    LoRaMacRxWindowSetup( 923.3e6 + ( Channel % 8 ) * 600e3, datarate, bandwidth, symbTimeout, false );
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-}
-
-/*!
- * Function executed on second Rx window timer event
- */
-static void OnRxWindow2TimerEvent( void )
-{
-    uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
-    uint32_t bandwidth = 0; // LoRa 125 kHz
-
-    TimerStop( &RxWindowTimer2 );
-    LoRaMacEventFlags.Bits.RxSlot = 1;
-
-    if( NodeAckRequested == true )
-    {
-        TimerSetValue( &AckTimeoutTimer, ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
-        TimerStart( &AckTimeoutTimer );
-    }
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( Rx2Channel.Datarate >= DR_3 )
-    { // DR_6, DR_5, DR_4, DR_3
-        symbTimeout = 8;
-    }
-    if( Rx2Channel.Datarate == DR_6 )
-    {// LoRa 250 kHz
-        bandwidth  = 1;
-    }
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    // For higher datarates, we increase the number of symbols generating a Rx Timeout
-    if( Rx2Channel.Datarate > DR_0 )
-    { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
-        symbTimeout = 8;
-    }
-    if( Rx2Channel.Datarate >= DR_4 )
-    {// LoRa 500 kHz
-        bandwidth  = 2;
+    { // Normal LoRa channel
+        Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 );
+        TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
     }
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
-    if( LoRaMacDeviceClass != CLASS_C )
+
+    // Store the time on air
+    McpsConfirm.TxTimeOnAir = TxTimeOnAir;
+    MlmeConfirm.TxTimeOnAir = TxTimeOnAir;
+
+    // Starts the MAC layer status check timer
+    TimerStart( &MacStateCheckTimer );
+
+    // Send now
+    Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
+
+    LoRaMacState |= MAC_TX_RUNNING;
+
+    return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks )
+{
+    if( primitives == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    if( ( primitives->MacMcpsConfirm == NULL ) ||
+        ( primitives->MacMcpsIndication == NULL ) ||
+        ( primitives->MacMlmeConfirm == NULL ))
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    LoRaMacPrimitives = primitives;
+    LoRaMacCallbacks = callbacks;
+
+    LoRaMacFlags.Value = 0;
+
+    LoRaMacDeviceClass = CLASS_A;
+
+    UpLinkCounter = 1;
+    DownLinkCounter = 0;
+    AdrAckCounter = 0;
+
+    RepeaterSupport = false;
+    IsRxWindowsEnabled = true;
+    IsLoRaMacNetworkJoined = false;
+    LoRaMacState = MAC_IDLE;
+
+#if defined( USE_BAND_433 )
+    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+#elif defined( USE_BAND_780 )
+    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+#elif defined( USE_BAND_868 )
+    ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 );
+#elif defined( USE_BAND_915 )
+    ChannelsMask[0] = 0xFFFF;
+    ChannelsMask[1] = 0xFFFF;
+    ChannelsMask[2] = 0xFFFF;
+    ChannelsMask[3] = 0xFFFF;
+    ChannelsMask[4] = 0x00FF;
+    ChannelsMask[5] = 0x0000;
+
+    memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask, sizeof( ChannelsMask ) );
+#elif defined( USE_BAND_915_HYBRID )
+    ChannelsMask[0] = 0x00FF;
+    ChannelsMask[1] = 0x0000;
+    ChannelsMask[2] = 0x0000;
+    ChannelsMask[3] = 0x0000;
+    ChannelsMask[4] = 0x0001;
+    ChannelsMask[5] = 0x0000;
+
+    memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask, sizeof( ChannelsMask ) );
+#else
+    #error "Please define a frequency band in the compiler options."
+#endif
+
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+    // 125 kHz channels
+    for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ )
     {
-        LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false );
+        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;
+    }
+#endif
+
+    ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
+    ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
+    ChannelsNbRep = 1;
+    ChannelsNbRepCounter = 0;
+
+    MaxDCycle = 0;
+    AggregatedDCycle = 1;
+    AggregatedLastTxDoneTime = 0;
+    AggregatedTimeOff = 0;
+
+#if defined( USE_BAND_433 )
+    DutyCycleOn = false;
+#elif defined( USE_BAND_780 )
+    DutyCycleOn = false;
+#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
+
+    MaxRxWindow = MAX_RX_WINDOW;
+    ReceiveDelay1 = RECEIVE_DELAY1;
+    ReceiveDelay2 = RECEIVE_DELAY2;
+    JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1;
+    JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2;
+
+    TimerInit( &MacStateCheckTimer, OnMacStateCheckTimerEvent );
+    TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT );
+
+    TimerInit( &TxDelayedTimer, OnTxDelayedTimerEvent );
+    TimerInit( &RxWindowTimer1, OnRxWindow1TimerEvent );
+    TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent );
+    TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent );
+
+    // Initialize Radio driver
+    RadioEvents.TxDone = OnRadioTxDone;
+    RadioEvents.RxDone = OnRadioRxDone;
+    RadioEvents.RxError = OnRadioRxError;
+    RadioEvents.TxTimeout = OnRadioTxTimeout;
+    RadioEvents.RxTimeout = OnRadioRxTimeout;
+    Radio.Init( &RadioEvents );
+
+    // Random seed initialization
+    srand1( Radio.Random( ) );
+
+    // Initialize channel index.
+    Channel = LORA_MAX_NB_CHANNELS;
+
+    PublicNetwork = true;
+    SetPublicNetwork( PublicNetwork );
+    Radio.Sleep( );
+
+    return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo )
+{
+    int8_t datarate = ChannelsDefaultDatarate;
+
+    if( txInfo == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    AdrNextDr( AdrCtrlOn, false, &datarate );
+
+    if( RepeaterSupport == true )
+    {
+        txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate];
     }
     else
     {
-        LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true );
+        txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
     }
-}
-
-/*!
- * Function executed on MacStateCheck timer event
- */
-static void OnMacStateCheckTimerEvent( void )
-{
-    TimerStop( &MacStateCheckTimer );
-
-    if( LoRaMacEventFlags.Bits.Tx == 1 )
+
+    if( txInfo->CurrentPayloadSize >= MacCommandsBufferIndex )
     {
-        if( NodeAckRequested == false )
-        {
-            if( LoRaMacEventFlags.Bits.JoinAccept == true )
-            {
-                // Join messages aren't repeated automatically
-                ChannelsNbRepCounter = ChannelsNbRep;
-                UpLinkCounter = 0;
-            }
-            if( ChannelsNbRepCounter >= ChannelsNbRep )
-            {
-                ChannelsNbRepCounter = 0;
-
-                LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-
-                AdrAckCounter++;
-                if( IsUpLinkCounterFixed == false )
-                {
-                    UpLinkCounter++;
-                }
-
-                LoRaMacState &= ~MAC_TX_RUNNING;
-            }
-            else
-            {
-                LoRaMacEventFlags.Bits.Tx = 0;
-                // Sends the same frame again
-                if( LoRaMacSetNextChannel( ) == 0 )
-                {
-                    LoRaMacSendFrameOnChannel( Channels[Channel] );
-                }
-            }
-        }
-
-        if( LoRaMacEventFlags.Bits.Rx == 1 )
-        {
-            if( ( LoRaMacEventInfo.TxAckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) )
-            {
-                AckTimeoutRetry = false;
-                if( IsUpLinkCounterFixed == false )
-                {
-                    UpLinkCounter++;
-                }
-                LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
-                
-                LoRaMacState &= ~MAC_TX_RUNNING;
-            }
-        }
-        
-        if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 ) )
-        {
-            AckTimeoutRetry = false;
-            if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
-            {
-                AckTimeoutRetriesCounter++;
-                
-                if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
-                {
-                    ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
-                }
-                LoRaMacEventFlags.Bits.Tx = 0;
-                // Sends the same frame again
-                if( LoRaMacSetNextChannel( ) == 0 )
-                {
-                    LoRaMacSendFrameOnChannel( Channels[Channel] );
-                }
-            }
-            else
-            {
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
-                // Re-enable default channels LC1, LC2, LC3
-                ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
-#elif defined( USE_BAND_915 )
-                // Re-enable default channels
-                ChannelsMask[0] = 0xFFFF;
-                ChannelsMask[1] = 0xFFFF;
-                ChannelsMask[2] = 0xFFFF;
-                ChannelsMask[3] = 0xFFFF;
-                ChannelsMask[4] = 0x00FF;
-                ChannelsMask[5] = 0x0000;
-#elif defined( USE_BAND_915_HYBRID )
-                // Re-enable default channels
-                ChannelsMask[0] = 0x00FF;
-                ChannelsMask[1] = 0x0000;
-                ChannelsMask[2] = 0x0000;
-                ChannelsMask[3] = 0x0000;
-                ChannelsMask[4] = 0x0001;
-                ChannelsMask[5] = 0x0000;
-#else
-    #error "Please define a frequency band in the compiler options."
-#endif
-                LoRaMacState &= ~MAC_TX_RUNNING;
-                
-                LoRaMacEventInfo.TxAckReceived = false;
-                LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
-                if( IsUpLinkCounterFixed == false )
-                {
-                    UpLinkCounter++;
-                }
-            }
-        }
-    }
-    // Handle reception for Class B and Class C
-    if( ( LoRaMacState & MAC_RX ) == MAC_RX )
-    {
-        LoRaMacState &= ~MAC_RX;
-    }
-    if( LoRaMacState == MAC_IDLE )
-    {
-        LoRaMacNotify( &LoRaMacEventFlags, &LoRaMacEventInfo );
-        LoRaMacEventFlags.Bits.Tx = 0;
+        txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - MacCommandsBufferIndex;
     }
     else
     {
-        // Operation not finished restart timer
-        TimerStart( &MacStateCheckTimer );
+        return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
+    }
+
+    if( ValidatePayloadLength( size, datarate, 0 ) == false )
+    {
+        return LORAMAC_STATUS_LENGTH_ERROR;
     }
-}
-
-static void OnAckTimeoutTimerEvent( void )
-{
-    TimerStop( &AckTimeoutTimer );
-
-    AckTimeoutRetry = true;
-    LoRaMacState &= ~MAC_ACK_REQ;
-}
-
-/*!
- * ============================================================================
- * = LoRaMac utility functions                                                =
- * ============================================================================
- */
-static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate )
-{
-    bool payloadSizeOk = false;
-    uint8_t maxN = 0;
-
-    // Get the maximum payload length
-    if( RepeaterSupport == true )
+
+    if( ValidatePayloadLength( size, datarate, MacCommandsBufferIndex ) == false )
     {
-        maxN = MaxPayloadOfDatarateRepeater[datarate];
-    }
-    else
-    {
-        maxN = MaxPayloadOfDatarate[datarate];
+        return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
     }
 
-    // Validation of the application payload size
-    if( lenN <= maxN )
-    {
-        payloadSizeOk = true;
-    }
-
-    return payloadSizeOk;
+    return LORAMAC_STATUS_OK;
 }
 
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask )
+LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
 {
-    uint8_t nb125kHzChannels = 0;
-
-    for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ )
+    LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+
+    if( mibGet == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    switch( mibGet->Type )
     {
-        for( uint8_t j = 0; j < 16; j++ )
-        {// Verify if the channel is active
-            if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) )
-            {
-                nb125kHzChannels++;
-            }
+        case MIB_DEVICE_CLASS:
+        {
+            mibGet->Param.Class = LoRaMacDeviceClass;
+            break;
+        }
+        case MIB_NETWORK_JOINED:
+        {
+            mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined;
+            break;
+        }
+        case MIB_ADR:
+        {
+            mibGet->Param.AdrEnable = AdrCtrlOn;
+            break;
+        }
+        case MIB_NET_ID:
+        {
+            mibGet->Param.NetID = LoRaMacNetID;
+            break;
+        }
+        case MIB_DEV_ADDR:
+        {
+            mibGet->Param.DevAddr = LoRaMacDevAddr;
+            break;
+        }
+        case MIB_NWK_SKEY:
+        {
+            mibGet->Param.NwkSKey = LoRaMacNwkSKey;
+            break;
+        }
+        case MIB_APP_SKEY:
+        {
+            mibGet->Param.AppSKey = LoRaMacAppSKey;
+            break;
+        }
+        case MIB_PUBLIC_NETWORK:
+        {
+            mibGet->Param.EnablePublicNetwork = PublicNetwork;
+            break;
+        }
+        case MIB_REPEATER_SUPPORT:
+        {
+            mibGet->Param.EnableRepeaterSupport = RepeaterSupport;
+            break;
+        }
+        case MIB_CHANNELS:
+        {
+            mibGet->Param.ChannelList = Channels;
+            break;
+        }
+        case MIB_RX2_CHANNEL:
+        {
+            mibGet->Param.Rx2Channel = Rx2Channel;
+            break;
+        }
+        case MIB_CHANNELS_MASK:
+        {
+            mibGet->Param.ChannelsMask = ChannelsMask;
+            break;
         }
+        case MIB_CHANNELS_NB_REP:
+        {
+            mibGet->Param.ChannelNbRep = ChannelsNbRep;
+            break;
+        }
+        case MIB_MAX_RX_WINDOW_DURATION:
+        {
+            mibGet->Param.MaxRxWindow = MaxRxWindow;
+            break;
+        }
+        case MIB_RECEIVE_DELAY_1:
+        {
+            mibGet->Param.ReceiveDelay1 = ReceiveDelay1;
+            break;
+        }
+        case MIB_RECEIVE_DELAY_2:
+        {
+            mibGet->Param.ReceiveDelay2 = ReceiveDelay2;
+            break;
+        }
+        case MIB_JOIN_ACCEPT_DELAY_1:
+        {
+            mibGet->Param.JoinAcceptDelay1 = JoinAcceptDelay1;
+            break;
+        }
+        case MIB_JOIN_ACCEPT_DELAY_2:
+        {
+            mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2;
+            break;
+        }
+        case MIB_CHANNELS_DATARATE:
+        {
+            mibGet->Param.ChannelsDatarate = ChannelsDatarate;
+            break;
+        }
+        case MIB_CHANNELS_TX_POWER:
+        {
+            mibGet->Param.ChannelsTxPower = ChannelsTxPower;
+            break;
+        }
+        case MIB_UPLINK_COUNTER:
+        {
+            mibGet->Param.UpLinkCounter = UpLinkCounter;
+            break;
+        }
+        case MIB_DOWNLINK_COUNTER:
+        {
+            mibGet->Param.DownLinkCounter = DownLinkCounter;
+            break;
+        }
+        case MIB_MULTICAST_CHANNEL:
+        {
+            mibGet->Param.MulticastList = MulticastChannels;
+            break;
+        }
+        default:
+            status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+            break;
     }
 
-    return nb125kHzChannels;
+    return status;
 }
-#endif
-
-static int8_t LimitTxPower( int8_t txPower )
+
+LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
 {
-    int8_t resultTxPower = txPower;
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( ( ChannelsDatarate == DR_4 ) ||
-        ( ( ChannelsDatarate >= DR_8 ) && ( ChannelsDatarate <= DR_13 ) ) )
-    {// Limit tx power to max 26dBm
-        resultTxPower =  MAX( txPower, TX_POWER_26_DBM );
+    LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+
+    if( mibSet == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-    else
-    {
-        if( CountNbEnabled125kHzChannels( ChannelsMask ) < 50 )
-        {// Limit tx power to max 21dBm
-            resultTxPower = MAX( txPower, TX_POWER_20_DBM );
-        }
-    }
-#endif
-    return resultTxPower;
-}
-
-void LoRaMacChannelRemove( uint8_t id )
-{
     if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
     {
-        return;
+        return LORAMAC_STATUS_BUSY;
     }
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    if( id < 64 )
+
+    switch( mibSet->Type )
     {
-        if( CountNbEnabled125kHzChannels( ChannelsMask ) <= 6 )
+        case MIB_DEVICE_CLASS:
+        {
+            LoRaMacDeviceClass = mibSet->Param.Class;
+            switch( LoRaMacDeviceClass )
+            {
+                case CLASS_A:
+                {
+                    // Set the radio into sleep to setup a defined state
+                    Radio.Sleep( );
+                    break;
+                }
+                case CLASS_B:
+                {
+                    break;
+                }
+                case CLASS_C:
+                {
+                    // Set the NodeAckRequested indicator to default
+                    NodeAckRequested = false;
+                    OnRxWindow2TimerEvent( );
+                    break;
+                }
+            }
+            break;
+        }
+        case MIB_NETWORK_JOINED:
+        {
+            IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
+            break;
+        }
+        case MIB_ADR:
+        {
+            AdrCtrlOn = mibSet->Param.AdrEnable;
+            break;
+        }
+        case MIB_NET_ID:
+        {
+            LoRaMacNetID = mibSet->Param.NetID;
+            break;
+        }
+        case MIB_DEV_ADDR:
+        {
+            LoRaMacDevAddr = mibSet->Param.DevAddr;
+            break;
+        }
+        case MIB_NWK_SKEY:
         {
-            return;
+            if( mibSet->Param.NwkSKey != NULL )
+            {
+                memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey,
+                               sizeof( LoRaMacNwkSKey ) );
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        case MIB_APP_SKEY:
+        {
+            if( mibSet->Param.AppSKey != NULL )
+            {
+                memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey,
+                               sizeof( LoRaMacAppSKey ) );
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        case MIB_PUBLIC_NETWORK:
+        {
+            SetPublicNetwork( mibSet->Param.EnablePublicNetwork );
+            break;
         }
-    }
+        case MIB_REPEATER_SUPPORT:
+        {
+             RepeaterSupport = mibSet->Param.EnableRepeaterSupport;
+            break;
+        }
+        case MIB_RX2_CHANNEL:
+        {
+            Rx2Channel = mibSet->Param.Rx2Channel;
+            break;
+        }
+        case MIB_CHANNELS_MASK:
+        {
+            if( mibSet->Param.ChannelsMask )
+            {
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) &&
+                    ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
+                {
+                    status = LORAMAC_STATUS_PARAMETER_INVALID;
+                }
+                else
+                {
+                    memcpy1( ( uint8_t* ) ChannelsMask,
+                             ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) );
+                    for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ )
+                    {
+                        ChannelsMaskRemaining[i] &= ChannelsMask[i];
+                    }
+                }
 #else
-    if( id < 3 )
-    {
-        return;
-    }
+                memcpy1( ( uint8_t* ) ChannelsMask,
+                         ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
 #endif
-
-    uint8_t index = 0;
-    index = id / 16;
-
-    if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
-    {
-        return;
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        case MIB_CHANNELS_NB_REP:
+        {
+            if( ( mibSet->Param.ChannelNbRep >= 1 ) &&
+                ( mibSet->Param.ChannelNbRep <= 15 ) )
+            {
+                ChannelsNbRep = mibSet->Param.ChannelNbRep;
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        case MIB_MAX_RX_WINDOW_DURATION:
+        {
+            MaxRxWindow = mibSet->Param.MaxRxWindow;
+            break;
+        }
+        case MIB_RECEIVE_DELAY_1:
+        {
+            ReceiveDelay1 = mibSet->Param.ReceiveDelay1;
+            break;
+        }
+        case MIB_RECEIVE_DELAY_2:
+        {
+            ReceiveDelay2 = mibSet->Param.ReceiveDelay2;
+            break;
+        }
+        case MIB_JOIN_ACCEPT_DELAY_1:
+        {
+            JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1;
+            break;
+        }
+        case MIB_JOIN_ACCEPT_DELAY_2:
+        {
+            JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2;
+            break;
+        }
+        case MIB_CHANNELS_DATARATE:
+        {
+            if( ValueInRange( mibSet->Param.ChannelsDatarate,
+                              LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) )
+            {
+                ChannelsDatarate = mibSet->Param.ChannelsDatarate;
+            }
+            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 ) )
+            {
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+                int8_t txPower = LimitTxPower( mibSet->Param.ChannelsTxPower );
+                if( txPower == mibSet->Param.ChannelsTxPower )
+                {
+                    ChannelsTxPower = mibSet->Param.ChannelsTxPower;
+                }
+                else
+                {
+                    status = LORAMAC_STATUS_PARAMETER_INVALID;
+                }
+#else
+                ChannelsTxPower = mibSet->Param.ChannelsTxPower;
+#endif
+            }
+            else
+            {
+                status = LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+            break;
+        }
+        default:
+            status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+            break;
     }
 
-    // Deactivate channel
-    ChannelsMask[index] &= ~( 1 << ( id % 16 ) );
-
-    return;
+    return status;
 }
 
-/*!
- * ============================================================================
- * = LoRaMac setup functions                                                  =
- * ============================================================================
- */
-void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
-{
-    LoRaMacDeviceClass = deviceClass;
-}
-
-void LoRaMacSetPublicNetwork( bool enable )
+LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
 {
-    PublicNetwork = enable;
-    Radio.SetModem( MODEM_LORA );
-    if( PublicNetwork == true )
-    {
-        // Change LoRa modem SyncWord
-        Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD );
-    }
-    else
+    if( id >= LORA_MAX_NB_CHANNELS )
     {
-        // Change LoRa modem SyncWord
-        Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD );
+        return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-}
-
-void LoRaMacSetChannel( uint8_t id, ChannelParams_t params )
-{
-    params.Band = 0;
-    Channels[id] = params;
-    // Activate the newly created channel
-    if( id < 16 )
+    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
     {
-        ChannelsMask[0] |= 1 << id;
+        return LORAMAC_STATUS_BUSY;
     }
-    else if( id < 32 )
-    {
-        ChannelsMask[1] |= 1 << ( id - 16 );
-    }
-    else if( id < 48 )
+    if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) ||
+        ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_MIN_DATARATE,
+                        LORAMAC_MAX_DATARATE ) == false ) ||
+        ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_MIN_DATARATE,
+                        LORAMAC_MAX_DATARATE ) == false ) )
     {
-        ChannelsMask[2] |= 1 << ( id - 32 );
-    }
-    else if( id < 64 )
-    {
-        ChannelsMask[3] |= 1 << ( id - 48 );
+        return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-    else if( id < 72 )
-    {
-        ChannelsMask[4] |= 1 << ( id - 64 );
-    }
-    else
-    {
-        // Don't activate the channel
-    }
+
+    params.Band = 0;
+
+#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+    return LORAMAC_STATUS_PARAMETER_INVALID;
+#else
 #if defined( USE_BAND_433 ) || defined( USE_BAND_780 )
-    Channels[id].Band = 0; // 1% duty cycle on EU433 and CN780 bands
+    Channels[id] = params;
+    Channels[id].Band = 0; // No duty cycle on EU433 and CN470 bands
 #elif defined( USE_BAND_868 )
+    Channels[id] = params;
     if( ( Channels[id].Frequency >= 865000000 ) && ( Channels[id].Frequency <= 868000000 ) )
     {
         if( Channels[id].Band != BAND_G1_0 )
@@ -2653,126 +3115,304 @@
         Channels[id].Frequency = 0;
         Channels[id].DrRange.Value = 0;
     }
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
-    Channels[id].Band = 0; // No duty cycle on US915 band
 #else
     #error "Please define a frequency band in the compiler options."
 #endif
     // Check if it is a valid channel
-    if( Channels[id].Frequency == 0 )
+    if( Channels[id].Frequency > 0 )
     {
-        LoRaMacChannelRemove( id );
-    }
-}
-
-void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
-{
-    Rx2Channel = param;
-}
-
-void LoRaMacSetChannelsTxPower( int8_t txPower )
-{
-    if( ( txPower >= LORAMAC_MAX_TX_POWER ) &&
-        ( txPower <= LORAMAC_MIN_TX_POWER ) )
-    {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-        int8_t txPwr = LimitTxPower( txPower );
-        if( txPwr == txPower )
+        // Activate the newly created channel
+        if( id < 16 )
         {
-            ChannelsTxPower = txPower;
+            ChannelsMask[0] |= 1 << id;
         }
-#else
-        ChannelsTxPower = txPower;
+    }
+
+    return LORAMAC_STATUS_OK;
 #endif
-    }
-}
-
-void LoRaMacSetChannelsDatarate( int8_t datarate )
-{
-    ChannelsDefaultDatarate = ChannelsDatarate = datarate;
 }
 
-void LoRaMacSetChannelsMask( uint16_t *mask )
+LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
 {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
-    if( ( CountNbEnabled125kHzChannels( mask ) < 6 ) &&
-        ( CountNbEnabled125kHzChannels( mask ) > 0 ) )
+    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
     {
-
+        return LORAMAC_STATUS_BUSY;
     }
-    else
+#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+    if( id < 64 )
     {
-        LoRaMacMemCpy( (uint8_t* ) mask,
-                       ( uint8_t* ) ChannelsMask, 10 );
+        if( CountNbEnabled125kHzChannels( ChannelsMask ) <= 6 )
+        {
+            return LORAMAC_STATUS_PARAMETER_INVALID;
+        }
     }
 #else
-    if( ( mask[0] & 0x0007 ) != 0x0007 )
+    if( id < 3 )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+#endif
+
+    if( DisableChannelInMask( id, ChannelsMask ) == false )
     {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+
+    return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam )
+{
+    if( channelParam == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+    {
+        return LORAMAC_STATUS_BUSY;
+    }
+
+    // Reset downlink counter
+    channelParam->DownLinkCounter = 0;
+
+    if( MulticastChannels == NULL )
+    {
+        // New node is the fist element
+        MulticastChannels = channelParam;
     }
     else
     {
-        LoRaMacMemCpy( ( uint8_t* ) mask,
-                       ( uint8_t* ) ChannelsMask, 2 );
+        MulticastParams_t *cur = MulticastChannels;
+
+        // Search the last node in the list
+        while( cur->Next != NULL )
+        {
+            cur = cur->Next;
+        }
+        // This function always finds the last node
+        cur->Next = channelParam;
     }
-#endif
+
+    return LORAMAC_STATUS_OK;
 }
 
-void LoRaMacSetChannelsNbRep( uint8_t nbRep )
+LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam )
 {
-    if( nbRep < 1 )
+    if( channelParam == NULL )
     {
-        nbRep = 1;
+        return LORAMAC_STATUS_PARAMETER_INVALID;
     }
-    if( nbRep > 15 )
+    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+    {
+        return LORAMAC_STATUS_BUSY;
+    }
+
+    if( MulticastChannels != NULL )
     {
-        nbRep = 15;
+        if( MulticastChannels == channelParam )
+        {
+          // First element
+          MulticastChannels = channelParam->Next;
+        }
+        else
+        {
+            MulticastParams_t *cur = MulticastChannels;
+
+            // Search the node in the list
+            while( cur->Next && cur->Next != channelParam )
+            {
+                cur = cur->Next;
+            }
+            // If we found the node, remove it
+            if( cur->Next )
+            {
+                cur->Next = channelParam->Next;
+            }
+        }
+        channelParam->Next = NULL;
     }
-    ChannelsNbRep = nbRep;
+
+    return LORAMAC_STATUS_OK;
 }
 
-void LoRaMacSetMaxRxWindow( uint32_t delay )
-{
-    MaxRxWindow = delay;
-}
-
-void LoRaMacSetReceiveDelay1( uint32_t delay )
-{
-    ReceiveDelay1 = delay;
-}
-
-void LoRaMacSetReceiveDelay2( uint32_t delay )
+LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
 {
-    ReceiveDelay2 = delay;
-}
-
-void LoRaMacSetJoinAcceptDelay1( uint32_t delay )
-{
-    JoinAcceptDelay1 = delay;
+    LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+    LoRaMacHeader_t macHdr;
+
+    if( mlmeRequest == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+    if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+    {
+        return LORAMAC_STATUS_BUSY;
+    }
+
+    memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
+
+    MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+
+    switch( mlmeRequest->Type )
+    {
+        case MLME_JOIN:
+        {
+            if( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED )
+            {
+                status = LORAMAC_STATUS_BUSY;
+            }
+
+            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
+
+            if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
+                ( mlmeRequest->Req.Join.AppEui == NULL ) ||
+                ( mlmeRequest->Req.Join.AppKey == NULL ) )
+            {
+                return LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+
+            LoRaMacFlags.Bits.MlmeReq = 1;
+
+            LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
+            LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
+            LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
+
+            macHdr.Value = 0;
+            macHdr.Bits.MType  = FRAME_TYPE_JOIN_REQ;
+
+            IsLoRaMacNetworkJoined = false;
+
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+            static uint8_t drSwitch = 0;
+
+            if( ( ++drSwitch & 0x01 ) == 0x01 )
+            {
+                ChannelsDatarate = DR_0;
+            }
+            else
+            {
+                ChannelsDatarate = DR_4;
+            }
+#endif
+
+            status = Send( &macHdr, 0, NULL, 0 );
+            break;
+        }
+        case MLME_LINK_CHECK:
+        {
+            LoRaMacFlags.Bits.MlmeReq = 1;
+            // LoRaMac will send this command piggy-pack
+            MlmeConfirm.MlmeRequest = mlmeRequest->Type;
+
+            status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
+            break;
+        }
+        default:
+            break;
+    }
+
+    if( status != LORAMAC_STATUS_OK )
+    {
+        NodeAckRequested = false;
+        LoRaMacFlags.Bits.MlmeReq = 0;
+    }
+
+    return status;
 }
 
-void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
-{
-    JoinAcceptDelay2 = delay;
-}
-
-uint32_t LoRaMacGetUpLinkCounter( void )
+LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest )
 {
-    return UpLinkCounter;
-}
-
-uint32_t LoRaMacGetDownLinkCounter( void )
-{
-    return DownLinkCounter;
-}
-
-/*!
- * ============================================================================
- * = LoRaMac test functions                                                   =
- * ============================================================================
- */
-void LoRaMacTestSetDutyCycleOn( bool enable )
-{
-    DutyCycleOn = enable;
+    LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+    LoRaMacHeader_t macHdr;
+    uint8_t fPort = 0;
+    void *fBuffer;
+    uint16_t fBufferSize;
+    int8_t datarate;
+    bool readyToSend = false;
+
+    if( mcpsRequest == NULL )
+    {
+        return LORAMAC_STATUS_PARAMETER_INVALID;
+    }
+    if( ( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) ||
+        ( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED ) )
+    {
+        return LORAMAC_STATUS_BUSY;
+    }
+
+    macHdr.Value = 0;
+    memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
+    McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+
+    switch( mcpsRequest->Type )
+    {
+        case MCPS_UNCONFIRMED:
+        {
+            readyToSend = true;
+            AckTimeoutRetries = 1;
+
+            macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
+            fPort = mcpsRequest->Req.Unconfirmed.fPort;
+            fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer;
+            fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize;
+            datarate = mcpsRequest->Req.Unconfirmed.Datarate;
+            break;
+        }
+        case MCPS_CONFIRMED:
+        {
+            readyToSend = true;
+            AckTimeoutRetriesCounter = 1;
+            AckTimeoutRetries = mcpsRequest->Req.Confirmed.nbRetries;
+
+            macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
+            fPort = mcpsRequest->Req.Confirmed.fPort;
+            fBuffer = mcpsRequest->Req.Confirmed.fBuffer;
+            fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize;
+            datarate = mcpsRequest->Req.Confirmed.Datarate;
+            break;
+        }
+        case MCPS_PROPRIETARY:
+        {
+            readyToSend = true;
+            AckTimeoutRetries = 1;
+
+            macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY;
+            fBuffer = mcpsRequest->Req.Proprietary.fBuffer;
+            fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize;
+            datarate = mcpsRequest->Req.Proprietary.Datarate;
+            break;
+        }
+        default:
+            break;
+    }
+
+    if( readyToSend == true )
+    {
+        if( AdrCtrlOn == false )
+        {
+            if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == true )
+            {
+                ChannelsDatarate = datarate;
+            }
+            else
+            {
+                return LORAMAC_STATUS_PARAMETER_INVALID;
+            }
+        }
+
+        status = Send( &macHdr, fPort, fBuffer, fBufferSize );
+        if( status == LORAMAC_STATUS_OK )
+        {
+            McpsConfirm.McpsRequest = mcpsRequest->Type;
+            LoRaMacFlags.Bits.McpsReq = 1;
+        }
+        else
+        {
+            NodeAckRequested = false;
+        }
+    }
+
+    return status;
 }
 
 void LoRaMacTestRxWindowsOn( bool enable )
@@ -2780,8 +3420,13 @@
     IsRxWindowsEnabled = enable;
 }
 
-void LoRaMacTestSetMic( uint16_t upLinkCounter )
+void LoRaMacTestSetMic( uint16_t txPacketCounter )
 {
-    UpLinkCounter = upLinkCounter;
+    UpLinkCounter = txPacketCounter;
     IsUpLinkCounterFixed = true;
 }
+
+void LoRaMacTestSetDutyCycleOn( bool enable )
+{
+    DutyCycleOn = enable;
+}
--- a/LoRaMac.h	Mon Nov 23 10:09:43 2015 +0000
+++ b/LoRaMac.h	Tue Jan 05 16:41:54 2016 +0000
@@ -1,17 +1,48 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
-
-Description: LoRa MAC layer implementation
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis and Gregory Cristian
-*/
+/*!
+ * \file      LoRaMac.h
+ *
+ * \brief     LoRa MAC layer implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jäckle ( STACKFORCE )
+ *
+ * \defgroup  LORAMAC LoRa MAC layer implementation
+ *            This module specifies the API implementation of the LoRaMAC layer.
+ *            This is a placeholder for a detailed description of the LoRaMac
+ *            layer and the supported features.
+ * \{
+ *
+ * \example   classA/LoRaMote/main.c
+ *            LoRaWAN class A application example for the LoRaMote.
+ *
+ * \example   classB/LoRaMote/main.c
+ *            LoRaWAN class B application example for the LoRaMote.
+ *
+ * \example   classC/LoRaMote/main.c
+ *            LoRaWAN class C application example for the LoRaMote.
+ */
 #ifndef __LORAMAC_H__
 #define __LORAMAC_H__
 
@@ -24,15 +55,23 @@
 #define BEACON_INTERVAL                             128000000
 
 /*!
- * Class A&B receive delay in us
+ * Class A&B receive delay 1 in us
  */
 #define RECEIVE_DELAY1                              1000000
+
+/*!
+ * Class A&B receive delay 2 in us
+ */
 #define RECEIVE_DELAY2                              2000000
 
 /*!
- * Join accept receive delay in us
+ * Join accept receive delay 1 in us
  */
 #define JOIN_ACCEPT_DELAY1                          5000000
+
+/*!
+ * Join accept receive delay 2 in us
+ */
 #define JOIN_ACCEPT_DELAY2                          6000000
 
 /*!
@@ -58,19 +97,19 @@
 /*!
  * Number of seconds after the start of the second reception window without
  * receiving an acknowledge.
- * AckTimeout = ACK_TIMEOUT + Random( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND )
+ * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND )
  */
 #define ACK_TIMEOUT                                 2000000
 
 /*!
  * Random number of seconds after the start of the second reception window without
  * receiving an acknowledge
- * AckTimeout = ACK_TIMEOUT + Random( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND )
+ * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND )
  */
 #define ACK_TIMEOUT_RND                             1000000
 
 /*!
- * Check the Mac layer state every MAC_STATE_CHECK_TIMEOUT
+ * Check the Mac layer state every MAC_STATE_CHECK_TIMEOUT in us
  */
 #define MAC_STATE_CHECK_TIMEOUT                     1000000
 
@@ -80,14 +119,18 @@
 #define MAX_ACK_RETRIES                             8
 
 /*!
- * RSSI free threshold
+ * RSSI free threshold [dBm]
  */
-#define RSSI_FREE_TH                                ( int8_t )( -90 ) // [dBm]
+#define RSSI_FREE_TH                                ( int8_t )( -90 )
 
-/*! 
- * Frame direction definition
+/*!
+ * Frame direction definition for up-link communications
  */
 #define UP_LINK                                     0
+
+/*!
+ * Frame direction definition for down-link communications
+ */
 #define DOWN_LINK                                   1
 
 /*!
@@ -106,480 +149,1503 @@
  */
 #define LORA_MAC_PUBLIC_SYNCWORD                    0x34
 
+ /*!
+ * LoRaMac internal state
+ */
+//uint32_t LoRaMacState;
+
 /*!
  * LoRaWAN devices classes definition
  */
-typedef enum
+typedef enum eDeviceClass
 {
+    /*!
+     * LoRaWAN device class A
+     *
+     * LoRaWAN Specification V1.0, chapter 3ff
+     */
     CLASS_A,
+    /*!
+     * LoRaWAN device class B
+     *
+     * LoRaWAN Specification V1.0, chapter 8ff
+     */
     CLASS_B,
+    /*!
+     * LoRaWAN device class C
+     *
+     * LoRaWAN Specification V1.0, chapter 17ff
+     */
     CLASS_C,
 }DeviceClass_t;
 
 /*!
  * LoRaMAC channels parameters definition
  */
-typedef union
+typedef union uDrRange
 {
+    /*!
+     * Byte-access to the bits
+     */
     int8_t Value;
-    struct
+    /*!
+     * Structure to store the minimum and the maximum datarate
+     */
+    struct sFields
     {
+         /*!
+         * Minimum data rate
+         *
+         * 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]
+         */
         int8_t Min : 4;
+        /*!
+         * Maximum data rate
+         *
+         * 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]
+         */
         int8_t Max : 4;
     }Fields;
 }DrRange_t;
 
-typedef struct
+/*!
+ * LoRaMAC band parameters definition
+ */
+typedef struct sBand
 {
+    /*!
+     * Duty cycle
+     */
     uint16_t DCycle;
+    /*!
+     * Maximum Tx power
+     */
     int8_t TxMaxPower;
-    uint64_t LastTxDoneTime;
-    uint64_t TimeOff;
+    /*!
+     * Time stamp of the last Tx frame
+     */
+    TimerTime_t LastTxDoneTime;
+    /*!
+     * Holds the time where the device is off
+     */
+    TimerTime_t TimeOff;
 }Band_t;
 
-typedef struct
+/*!
+ * LoRaMAC channel definition
+ */
+typedef struct sChannelParams
 {
-    uint32_t Frequency; // Hz
-    DrRange_t DrRange;  // Max datarate [0: SF12, 1: SF11, 2: SF10, 3: SF9, 4: SF8, 5: SF7, 6: SF7, 7: FSK]
-                        // Min datarate [0: SF12, 1: SF11, 2: SF10, 3: SF9, 4: SF8, 5: SF7, 6: SF7, 7: FSK]
-    uint8_t Band;       // Band index
+    /*!
+     * Frequency in Hz
+     */
+    uint32_t Frequency;
+    /*!
+     * Data rate definition
+     */
+    DrRange_t DrRange;
+    /*!
+     * Band index
+     */
+    uint8_t Band;
 }ChannelParams_t;
 
-typedef struct
+/*!
+ * LoRaMAC receive window 2 channel parameters
+ */
+typedef struct sRx2ChannelParams
 {
-    uint32_t Frequency; // Hz
-    uint8_t  Datarate;  // [0: SF12, 1: SF11, 2: SF10, 3: SF9, 4: SF8, 5: SF7, 6: SF7, 7: FSK]
+    /*!
+     * Frequency in Hz
+     */
+    uint32_t Frequency;
+    /*!
+     * Data rate
+     *
+     * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7]
+     *
+     * US915 - [DR_8, DR_9, DR_10, DR_11, DR_12, DR_13]
+     */
+    uint8_t  Datarate;
 }Rx2ChannelParams_t;
 
-typedef struct MulticastParams_s
+/*!
+ * LoRaMAC multicast channel parameter
+ */
+typedef struct sMulticastParams
 {
+    /*!
+     * Address
+     */
     uint32_t Address;
+    /*!
+     * Network session key
+     */
     uint8_t NwkSKey[16];
+    /*!
+     * Application session key
+     */
     uint8_t AppSKey[16];
+    /*!
+     * Downlink counter
+     */
     uint32_t DownLinkCounter;
-    struct MulticastParams_s *Next;
+    /*!
+     * Reference pointer to the next multicast channel parameters in the list
+     */
+    struct sMulticastParams *Next;
 }MulticastParams_t;
 
 /*!
  * LoRaMAC frame types
+ *
+ * LoRaWAN Specification V1.0, chapter 4.2.1, table 1
  */
-typedef enum
+typedef enum eLoRaMacFrameType
 {
+    /*!
+     * LoRaMAC join request frame
+     */
     FRAME_TYPE_JOIN_REQ              = 0x00,
+    /*!
+     * LoRaMAC join accept frame
+     */
     FRAME_TYPE_JOIN_ACCEPT           = 0x01,
+    /*!
+     * LoRaMAC unconfirmed up-link frame
+     */
     FRAME_TYPE_DATA_UNCONFIRMED_UP   = 0x02,
+    /*!
+     * LoRaMAC unconfirmed down-link frame
+     */
     FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03,
+    /*!
+     * LoRaMAC confirmed up-link frame
+     */
     FRAME_TYPE_DATA_CONFIRMED_UP     = 0x04,
+    /*!
+     * LoRaMAC confirmed down-link frame
+     */
     FRAME_TYPE_DATA_CONFIRMED_DOWN   = 0x05,
+    /*!
+     * LoRaMAC RFU frame
+     */
     FRAME_TYPE_RFU                   = 0x06,
+    /*!
+     * LoRaMAC proprietary frame
+     */
     FRAME_TYPE_PROPRIETARY           = 0x07,
 }LoRaMacFrameType_t;
 
 /*!
  * LoRaMAC mote MAC commands
+ *
+ * LoRaWAN Specification V1.0, chapter 5, table 4
  */
-typedef enum
+typedef enum eLoRaMacMoteCmd
 {
+    /*!
+     * LinkCheckReq
+     */
     MOTE_MAC_LINK_CHECK_REQ          = 0x02,
+    /*!
+     * LinkADRAns
+     */
     MOTE_MAC_LINK_ADR_ANS            = 0x03,
+    /*!
+     * DutyCycleAns
+     */
     MOTE_MAC_DUTY_CYCLE_ANS          = 0x04,
+    /*!
+     * RXParamSetupAns
+     */
     MOTE_MAC_RX_PARAM_SETUP_ANS      = 0x05,
+    /*!
+     * DevStatusAns
+     */
     MOTE_MAC_DEV_STATUS_ANS          = 0x06,
+    /*!
+     * NewChannelAns
+     */
     MOTE_MAC_NEW_CHANNEL_ANS         = 0x07,
+    /*!
+     * RXTimingSetupAns
+     */
     MOTE_MAC_RX_TIMING_SETUP_ANS     = 0x08,
 }LoRaMacMoteCmd_t;
 
 /*!
  * LoRaMAC server MAC commands
+ *
+ * LoRaWAN Specification V1.0, chapter 5, table 4
  */
-typedef enum
+typedef enum eLoRaMacSrvCmd
 {
+    /*!
+     * LinkCheckAns
+     */
     SRV_MAC_LINK_CHECK_ANS           = 0x02,
+    /*!
+     * LinkADRReq
+     */
     SRV_MAC_LINK_ADR_REQ             = 0x03,
+    /*!
+     * DutyCycleReq
+     */
     SRV_MAC_DUTY_CYCLE_REQ           = 0x04,
+    /*!
+     * RXParamSetupReq
+     */
     SRV_MAC_RX_PARAM_SETUP_REQ       = 0x05,
+    /*!
+     * DevStatusReq
+     */
     SRV_MAC_DEV_STATUS_REQ           = 0x06,
+    /*!
+     * NewChannelReq
+     */
     SRV_MAC_NEW_CHANNEL_REQ          = 0x07,
+    /*!
+     * RXTimingSetupReq
+     */
     SRV_MAC_RX_TIMING_SETUP_REQ      = 0x08,
 }LoRaMacSrvCmd_t;
 
 /*!
  * LoRaMAC Battery level indicator
  */
-typedef enum
+typedef enum eLoRaMacBatteryLevel
 {
+    /*!
+     * External power source
+     */
     BAT_LEVEL_EXT_SRC                = 0x00,
+    /*!
+     * Battery level empty
+     */
     BAT_LEVEL_EMPTY                  = 0x01,
+    /*!
+     * Battery level full
+     */
     BAT_LEVEL_FULL                   = 0xFE,
+    /*!
+     * Battery level - no measurement available
+     */
     BAT_LEVEL_NO_MEASURE             = 0xFF,
 }LoRaMacBatteryLevel_t;
 
 /*!
- * LoRaMAC header field definition
+ * LoRaMAC header field definition (MHDR field)
+ *
+ * LoRaWAN Specification V1.0, chapter 4.2
  */
-typedef union
+typedef union uLoRaMacHeader
 {
+    /*!
+     * Byte-access to the bits
+     */
     uint8_t Value;
-    struct
+    /*!
+     * Structure containing single access to header bits
+     */
+    struct sHdrBits
     {
+        /*!
+         * Major version
+         */
         uint8_t Major           : 2;
+        /*!
+         * RFU
+         */
         uint8_t RFU             : 3;
+        /*!
+         * Message type
+         */
         uint8_t MType           : 3;
     }Bits;
 }LoRaMacHeader_t;
 
 /*!
- * LoRaMAC frame header field definition
+ * LoRaMAC frame control field definition (FCtrl)
+ *
+ * LoRaWAN Specification V1.0, chapter 4.3.1
  */
-typedef union
+typedef union uLoRaMacFrameCtrl
 {
+    /*!
+     * Byte-access to the bits
+     */
     uint8_t Value;
-    struct
+    struct sCtrlBits
     {
+        /*!
+         * Frame options length
+         */
         uint8_t FOptsLen        : 4;
+        /*!
+         * Frame pending bit
+         */
         uint8_t FPending        : 1;
+        /*!
+         * Message acknowledge bit
+         */
         uint8_t Ack             : 1;
+        /*!
+         * ADR acknowledgment request bit
+         */
         uint8_t AdrAckReq       : 1;
+        /*!
+         * ADR control in frame header
+         */
         uint8_t Adr             : 1;
     }Bits;
 }LoRaMacFrameCtrl_t;
 
 /*!
- * LoRaMAC event flags
+ * Enumeration containing the status of the operation of a MAC service
  */
-typedef union
+typedef enum eLoRaMacEventInfoStatus
 {
-    uint8_t Value;
-    struct
-    {
-        uint8_t Tx              : 1;
-        uint8_t Rx              : 1;
-        uint8_t RxData          : 1;
-        uint8_t Multicast       : 1;
-        uint8_t RxSlot          : 2;
-        uint8_t LinkCheck       : 1;
-        uint8_t JoinAccept      : 1;
-    }Bits;
-}LoRaMacEventFlags_t;
-
-typedef enum
-{
+    /*!
+     * Service performed successfully
+     */
     LORAMAC_EVENT_INFO_STATUS_OK = 0,
+    /*!
+     * An error occured during the execution of the service
+     */
     LORAMAC_EVENT_INFO_STATUS_ERROR,
+    /*!
+     * A Tx timeouit occured
+     */
     LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT,
+    /*!
+     * An Rx timeout occured on receive window 2
+     */
     LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT,
+    /*!
+     * An Rx error occured on receive window 2
+     */
     LORAMAC_EVENT_INFO_STATUS_RX2_ERROR,
+    /*!
+     * An error occured in the join procedure
+     */
     LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL,
-    LORAMAC_EVENT_INFO_STATUS_DOWNLINK_FAIL,
+    /*!
+     * A frame with an invalid downlink counter was received. The
+     * downlink counter of the frame was equal to the local copy
+     * of the downlink counter of the node.
+     */
+    LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED,
+    /*!
+     * An address error occured
+     */
     LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL,
+    /*!
+     * message integrity check failure
+     */
     LORAMAC_EVENT_INFO_STATUS_MIC_FAIL,
 }LoRaMacEventInfoStatus_t;
 
 /*!
- * LoRaMAC event information
+ * LoRaMac tx/rx operation state
+ */
+typedef union eLoRaMacFlags_t
+{
+    /*!
+     * Byte-access to the bits
+     */
+    uint8_t Value;
+    struct sMacFlagBits
+    {
+        /*!
+         * MCPS-Req pending
+         */
+        uint8_t McpsReq         : 1;
+        /*!
+         * MCPS-Ind pending
+         */
+        uint8_t McpsInd         : 1;
+        /*!
+         * MLME-Req pending
+         */
+        uint8_t MlmeReq         : 1;
+        /*!
+         * MAC cycle done
+         */
+        uint8_t MacDone         : 1;
+    }Bits;
+}LoRaMacFlags_t;
+
+/*!
+ *
+ * \brief   LoRaMAC data services
+ *
+ * \details The following table list the primitives which are supported by the
+ *          specific MAC data service:
+ *
+ * Name                  | Request | Indication | Response | Confirm
+ * --------------------- | :-----: | :--------: | :------: | :-----:
+ * \ref MCPS_UNCONFIRMED | YES     | YES        | NO       | YES
+ * \ref MCPS_CONFIRMED   | YES     | YES        | NO       | YES
+ * \ref MCPS_MULTICAST   | NO      | YES        | NO       | NO
+ * \ref MCPS_PROPRIETARY | YES     | YES        | NO       | YES
+ *
+ * The following table provides links to the function implementations of the
+ * related MCPS primitives:
+ *
+ * Primitive        | Function
+ * ---------------- | :---------------------:
+ * 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,
+    /*!
+     * Confirmed LoRaMAC frame
+     */
+    MCPS_CONFIRMED,
+    /*!
+     * Multicast LoRaMAC frame
+     */
+    MCPS_MULTICAST,
+    /*!
+     * Proprietary frame
+     */
+    MCPS_PROPRIETARY,
+}Mcps_t;
+
+/*!
+ * LoRaMAC MCPS-Request for an unconfirmed frame
+ */
+typedef struct sMcpsReqUnconfirmed
+{
+    /*!
+     * Frame port field. Must be set if the payload is not empty. Use the
+     * application specific frame port values: [1...223]
+     *
+     * LoRaWAN Specification V1.0, chapter 4.3.2
+     */
+    uint8_t fPort;
+    /*!
+     * Pointer to the buffer of the frame payload
+     */
+    void *fBuffer;
+    /*!
+     * Size of the frame payload
+     */
+    uint16_t fBufferSize;
+    /*!
+     * Uplink datarate, if ADR is off
+     */
+    int8_t Datarate;
+}McpsReqUnconfirmed_t;
+
+/*!
+ * LoRaMAC MCPS-Request for a confirmed frame
+ */
+typedef struct sMcpsReqConfirmed
+{
+    /*!
+     * Frame port field. Must be set if the payload is not empty. Use the
+     * application specific frame port values: [1...223]
+     *
+     * LoRaWAN Specification V1.0, chapter 4.3.2
+     */
+    uint8_t fPort;
+    /*!
+     * Pointer to the buffer of the frame payload
+     */
+    void *fBuffer;
+    /*!
+     * Size of the frame payload
+     */
+    uint16_t fBufferSize;
+    /*!
+     * Uplink datarate, if ADR is off
+     */
+    int8_t Datarate;
+    /*!
+     * Number of attempts to transmit the frame, if frame could not be send, or
+     * if the LoRaMAC layer did not receive an acknowledgment
+     */
+    uint8_t nbRetries;
+}McpsReqConfirmed_t;
+
+/*!
+ * LoRaMAC MCPS-Request for a proprietary frame
+ */
+typedef struct sMcpsReqProprietary
+{
+    /*!
+     * Pointer to the buffer of the frame payload
+     */
+    void *fBuffer;
+    /*!
+     * Size of the frame payload
+     */
+    uint16_t fBufferSize;
+    /*!
+     * Uplink datarate, if ADR is off
+     */
+    int8_t Datarate;
+}McpsReqProprietary_t;
+
+/*!
+ * LoRaMAC MCPS-Request structure
+ */
+typedef struct sMcpsReq
+{
+    /*!
+     * MCPS-Request type
+     */
+    Mcps_t Type;
+
+    /*!
+     * MCPS-Request parameters
+     */
+    union uMcpsParam
+    {
+        /*!
+         * MCPS-Request parameters for an unconfirmed frame
+         */
+        McpsReqUnconfirmed_t Unconfirmed;
+        /*!
+         * MCPS-Request parameters for a confirmed frame
+         */
+        McpsReqConfirmed_t Confirmed;
+        /*!
+         * MCPS-Request parameters for a proprietary frame
+         */
+        McpsReqProprietary_t Proprietary;
+    }Req;
+}McpsReq_t;
+
+/*!
+ * LoRaMAC MCPS-Confirm
  */
-typedef struct
+typedef struct sMcpsConfirm
+{
+    /*!
+     * Holds the previously performed MCPS-Request
+     */
+    Mcps_t McpsRequest;
+    /*!
+     * Status of the operation
+     */
+    LoRaMacEventInfoStatus_t Status;
+    /*!
+     * Uplink datarate
+     */
+    uint8_t Datarate;
+    /*!
+     * Transmission power
+     */
+    int8_t TxPower;
+    /*!
+     * Set if an acknowledgement was received
+     */
+    bool AckReceived;
+    /*!
+     * Provides the number of retransmissions
+     */
+    uint8_t NbRetries;
+    /*!
+     * The transmission time on air of the frame
+     */
+    TimerTime_t TxTimeOnAir;
+    /*!
+     * The uplink counter value related to the frame
+     */
+    uint32_t UpLinkCounter;
+}McpsConfirm_t;
+
+/*!
+ * LoRaMAC MCPS-Indication primitive
+ */
+typedef struct sMcpsIndication
 {
+    /*!
+     * MCPS-Indication type
+     */
+    Mcps_t McpsIndication;
+    /*!
+     * Status of the operation
+     */
+    LoRaMacEventInfoStatus_t Status;
+    /*!
+     * Multicast
+     */
+    uint8_t Multicast;
+    /*!
+     * Application port
+     */
+    uint8_t Port;
+    /*!
+     * Downlink datarate
+     */
+    uint8_t RxDatarate;
+    /*!
+     * Frame pending status
+     */
+    uint8_t FramePending;
+    /*!
+     * Pointer to the received data stream
+     */
+    uint8_t *Buffer;
+    /*!
+     * Size of the received data stream
+     */
+    uint8_t BufferSize;
+    /*!
+     * Indicates, if data is available
+     */
+    bool RxData;
+    /*!
+     * Rssi of the received packet
+     */
+    int16_t Rssi;
+    /*!
+     * Snr of the received packet
+     */
+    uint8_t Snr;
+    /*!
+     * Receive window
+     *
+     * [0: Rx window 1, 1: Rx window 2]
+     */
+    uint8_t RxSlot;
+    /*!
+     * Set if an acknowledgement was received
+     */
+    bool AckReceived;
+    /*!
+     * The downlink counter value for the received frame
+     */
+    uint32_t DownLinkCounter;
+}McpsIndication_t;
+
+/*!
+ * \brief LoRaMAC management services
+ *
+ * \details The following table list the primitives which are supported by the
+ *          specific MAC management service:
+ *
+ * Name                  | Request | Indication | Response | Confirm
+ * --------------------- | :-----: | :--------: | :------: | :-----:
+ * \ref MLME_JOIN        | YES     | NO         | NO       | YES
+ * \ref MLME_LINK_CHECK  | YES     | NO         | NO       | YES
+ *
+ * The following table provides links to the function implementations of the
+ * related MLME primitives.
+ *
+ * Primitive        | Function
+ * ---------------- | :---------------------:
+ * MLME-Request     | \ref LoRaMacMlmeRequest
+ * MLME-Confirm     | MacMlmeConfirm in \ref LoRaMacPrimitives_t
+ */
+typedef enum eMlme
+{
+    /*!
+     * Initiates the Over-the-Air activation
+     *
+     * LoRaWAN Specification V1.0, chapter 6.2
+     */
+    MLME_JOIN,
+    /*!
+     * LinkCheckReq - Connectivity validation
+     *
+     * LoRaWAN Specification V1.0, chapter 5, table 4
+     */
+    MLME_LINK_CHECK,
+}Mlme_t;
+
+/*!
+ * LoRaMAC MLME-Request for the join service
+ */
+typedef struct sMlmeReqJoin
+{
+    /*!
+     * Globally unique end-device identifier
+     *
+     * LoRaWAN Specification V1.0, chapter 6.2.1
+     */
+    uint8_t *DevEui;
+    /*!
+     * Application identifier
+     *
+     * LoRaWAN Specification V1.0, chapter 6.1.2
+     */
+    uint8_t *AppEui;
+    /*!
+     * AES-128 application key
+     *
+     * LoRaWAN Specification V1.0, chapter 6.2.2
+     */
+    uint8_t *AppKey;
+}MlmeReqJoin_t;
+
+/*!
+ *
+ */
+typedef struct sMlmeReq
+{
+    /*!
+     * MLME-Request type
+     */
+    Mlme_t Type;
+
+    /*!
+     * MLME-Request parameters
+     */
+    union uMlmeParam
+    {
+        /*!
+         * MLME-Request parameters for a join request
+         */
+        MlmeReqJoin_t Join;
+    }Req;
+}MlmeReq_t;
+
+/*!
+ * LoRaMAC MLME-Confirm primitive
+ */
+typedef struct sMlmeConfirm
+{
+    /*!
+     * Holds the previously performed MLME-Request
+     */
+    Mlme_t MlmeRequest;
+    /*!
+     * Status of the operation
+     */
     LoRaMacEventInfoStatus_t Status;
-    bool TxAckReceived;
-    uint8_t TxNbRetries;
-    uint8_t TxDatarate;
-    uint8_t RxPort;
-    uint8_t *RxBuffer;
-    uint8_t RxBufferSize;
-    int16_t RxRssi;
-    uint8_t RxSnr;
-    uint16_t Energy;
+    /*!
+     * The transmission time on air of the frame
+     */
+    TimerTime_t TxTimeOnAir;
+    /*!
+     * Demodulation margin. Contains the link margin [dB] of the last
+     * successfully received LinkCheckReq
+     */
     uint8_t DemodMargin;
+    /*!
+     * Number of gateways which received the last LinkCheckReq
+     */
     uint8_t NbGateways;
-}LoRaMacEventInfo_t;
+}MlmeConfirm_t;
+
+/*!
+ * LoRa Mac Information Base (MIB)
+ *
+ * The following table lists the MIB parameters and the related attributes:
+ *
+ * Attribute                         | Get | Set
+ * --------------------------------- | :-: | :-:
+ * \ref MIB_DEVICE_CLASS             | YES | YES
+ * \ref MIB_NETWORK_JOINED           | YES | YES
+ * \ref MIB_ADR                      | YES | YES
+ * \ref MIB_NET_ID                   | YES | YES
+ * \ref MIB_DEV_ADDR                 | YES | YES
+ * \ref MIB_NWK_SKEY                 | YES | YES
+ * \ref MIB_APP_SKEY                 | YES | YES
+ * \ref MIB_PUBLIC_NETWORK           | YES | YES
+ * \ref MIB_CHANNELS                 | YES | NO
+ * \ref MIB_RX2_CHANNEL              | YES | YES
+ * \ref MIB_CHANNELS_MASK            | YES | YES
+ * \ref MIB_CHANNELS_NB_REP          | YES | YES
+ * \ref MIB_MAX_RX_WINDOW_DURATION   | YES | YES
+ * \ref MIB_RECEIVE_DELAY_1          | YES | YES
+ * \ref MIB_RECEIVE_DELAY_2          | YES | YES
+ * \ref MIB_JOIN_ACCEPT_DELAY_1      | YES | YES
+ * \ref MIB_JOIN_ACCEPT_DELAY_2      | YES | YES
+ * \ref MIB_CHANNELS_DATARATE        | YES | YES
+ * \ref MIB_CHANNELS_TX_POWER        | YES | YES
+ * \ref MIB_UPLINK_COUNTER           | YES | NO
+ * \ref MIB_DOWNLINK_COUNTER         | YES | NO
+ * \ref MIB_MULTICAST_CHANNEL        | YES | NO
+ *
+ * The following table provides links to the function implementations of the
+ * related MIB primitives:
+ *
+ * Primitive        | Function
+ * ---------------- | :---------------------:
+ * MIB-Set          | \ref LoRaMacMibSetRequestConfirm
+ * MIB-Get          | \ref LoRaMacMibGetRequestConfirm
+ */
+typedef enum eMib
+{
+    /*!
+     * LoRaWAN device class
+     *
+     * LoRaWAN Specification V1.0
+     */
+    MIB_DEVICE_CLASS,
+    /*!
+     * LoRaWAN Network joined attribute
+     *
+     * LoRaWAN Specification V1.0
+     */
+    MIB_NETWORK_JOINED,
+    /*!
+     * Adaptive data rate
+     *
+     * LoRaWAN Specification V1.0, chapter 4.3.1.1
+     *
+     * [true: ADR enabled, false: ADR disabled]
+     */
+    MIB_ADR,
+    /*!
+     * Network identifier
+     *
+     * LoRaWAN Specification V1.0, chapter 6.2.5
+     */
+    MIB_NET_ID,
+    /*!
+     * End-device address
+     *
+     * LoRaWAN Specification V1.0, chapter 6.1.2
+     */
+    MIB_DEV_ADDR,
+    /*!
+     * Network session key
+     *
+     * LoRaWAN Specification V1.0, chapter 6.1.3
+     */
+    MIB_NWK_SKEY,
+    /*!
+     * Application session key
+     *
+     * LoRaWAN Specification V1.0, chapter 6.1.4
+     */
+    MIB_APP_SKEY,
+    /*!
+     * Set the network type to public or private
+     *
+     * LoRaWAN Specification V1.0, chapter 7
+     *
+     * [true: public network, false: private network]
+     */
+    MIB_PUBLIC_NETWORK,
+    /*!
+     * Support the operation with repeaters
+     *
+     * LoRaWAN Specification V1.0, chapter 7
+     *
+     * [true: repeater support enabled, false: repeater support disabled]
+     */
+    MIB_REPEATER_SUPPORT,
+    /*!
+     * Communication channels. A get request will return a
+     * pointer which references the first entry of the channel list. The
+     * list is of size LORA_MAX_NB_CHANNELS
+     *
+     * LoRaWAN Specification V1.0, chapter 7
+     */
+    MIB_CHANNELS,
+    /*!
+     * Set receive window 2 channel
+     *
+     * LoRaWAN Specification V1.0, chapter 3.3.2
+     */
+    MIB_RX2_CHANNEL,
+    /*!
+     * LoRaWAN channels mask
+     *
+     * LoRaWAN Specification V1.0, chapter 5.2
+     */
+    MIB_CHANNELS_MASK,
+    /*!
+     * Set the number of repetitions on a channel
+     *
+     * LoRaWAN Specification V1.0, chapter 5.2
+     */
+    MIB_CHANNELS_NB_REP,
+    /*!
+     * Maximum receive window duration in [us]
+     *
+     * LoRaWAN Specification V1.0, chapter 3.3.3
+     */
+    MIB_MAX_RX_WINDOW_DURATION,
+    /*!
+     * Receive delay 1 in [us]
+     *
+     * LoRaWAN Specification V1.0, chapter 6
+     */
+    MIB_RECEIVE_DELAY_1,
+    /*!
+     * Receive delay 2 in [us]
+     *
+     * LoRaWAN Specification V1.0, chapter 6
+     */
+    MIB_RECEIVE_DELAY_2,
+    /*!
+     * Join accept delay 1 in [us]
+     *
+     * LoRaWAN Specification V1.0, chapter 6
+     */
+    MIB_JOIN_ACCEPT_DELAY_1,
+    /*!
+     * Join accept delay 2 in [us]
+     *
+     * LoRaWAN Specification V1.0, chapter 6
+     */
+    MIB_JOIN_ACCEPT_DELAY_2,
+    /*!
+     * Data rate of a channel
+     *
+     * LoRaWAN Specification V1.0, chapter 7
+     *
+     * 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]
+     */
+    MIB_CHANNELS_DATARATE,
+    /*!
+     * Transmission power of a channel
+     *
+     * LoRaWAN Specification V1.0, 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]
+     *
+     * 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]
+     */
+    MIB_CHANNELS_TX_POWER,
+    /*!
+     * LoRaWAN Up-link counter
+     *
+     * LoRaWAN Specification V1.0, chapter 4.3.1.5
+     */
+    MIB_UPLINK_COUNTER,
+    /*!
+     * LoRaWAN Down-link counter
+     *
+     * LoRaWAN Specification V1.0, chapter 4.3.1.5
+     */
+    MIB_DOWNLINK_COUNTER,
+    /*!
+     * Multicast channels. A get request will return a pointer to the first
+     * entry of the multicast channel linked list. If the pointer is equal to
+     * NULL, the list is empty.
+     */
+    MIB_MULTICAST_CHANNEL,
+}Mib_t;
+
+/*!
+ * LoRaMAC MIB parameters
+ */
+typedef union uMibParam
+{
+    /*!
+     * LoRaWAN device class
+     *
+     * Related MIB type: \ref MIB_DEVICE_CLASS
+     */
+    DeviceClass_t Class;
+    /*!
+     * LoRaWAN network joined attribute
+     *
+     * Related MIB type: \ref MIB_NETWORK_JOINED
+     */
+    bool IsNetworkJoined;
+    /*!
+     * Activation state of ADR
+     *
+     * Related MIB type: \ref MIB_ADR
+     */
+    bool AdrEnable;
+    /*!
+     * Network identifier
+     *
+     * Related MIB type: \ref MIB_NET_ID
+     */
+    uint32_t NetID;
+    /*!
+     * End-device address
+     *
+     * Related MIB type: \ref MIB_DEV_ADDR
+     */
+    uint32_t DevAddr;
+    /*!
+     * Network session key
+     *
+     * Related MIB type: \ref MIB_NWK_SKEY
+     */
+    uint8_t *NwkSKey;
+    /*!
+     * Application session key
+     *
+     * Related MIB type: \ref MIB_APP_SKEY
+     */
+    uint8_t *AppSKey;
+    /*!
+     * Enable or disable a public network
+     *
+     * Related MIB type: \ref MIB_PUBLIC_NETWORK
+     */
+    bool EnablePublicNetwork;
+    /*!
+     * Enable or disable repeater support
+     *
+     * Related MIB type: \ref MIB_REPEATER_SUPPORT
+     */
+    bool EnableRepeaterSupport;
+    /*!
+     * LoRaWAN Channel
+     *
+     * Related MIB type: \ref MIB_CHANNELS
+     */
+    ChannelParams_t* ChannelList;
+     /*!
+     * Channel for the receive window 2
+     *
+     * Related MIB type: \ref MIB_RX2_CHANNEL
+     */
+    Rx2ChannelParams_t Rx2Channel;
+    /*!
+     * Channel mask
+     *
+     * Related MIB type: \ref MIB_CHANNELS_MASK
+     */
+    uint16_t* ChannelsMask;
+    /*!
+     * Number of frame repetitions
+     *
+     * Related MIB type: \ref MIB_CHANNELS_NB_REP
+     */
+    uint8_t ChannelNbRep;
+    /*!
+     * Maximum receive window duration
+     *
+     * Related MIB type: \ref MIB_MAX_RX_WINDOW_DURATION
+     */
+    uint32_t MaxRxWindow;
+    /*!
+     * Receive delay 1
+     *
+     * Related MIB type: \ref MIB_RECEIVE_DELAY_1
+     */
+    uint32_t ReceiveDelay1;
+    /*!
+     * Receive delay 2
+     *
+     * Related MIB type: \ref MIB_RECEIVE_DELAY_2
+     */
+    uint32_t ReceiveDelay2;
+    /*!
+     * Join accept delay 1
+     *
+     * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_1
+     */
+    uint32_t JoinAcceptDelay1;
+    /*!
+     * Join accept delay 2
+     *
+     * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_2
+     */
+    uint32_t JoinAcceptDelay2;
+    /*!
+     * Channels data rate
+     *
+     * Related MIB type: \ref MIB_CHANNELS_DATARATE
+     */
+    int8_t ChannelsDatarate;
+    /*!
+     * Channels TX power
+     *
+     * Related MIB type: \ref MIB_CHANNELS_TX_POWER
+     */
+    int8_t ChannelsTxPower;
+    /*!
+     * LoRaWAN Up-link counter
+     *
+     * Related MIB type: \ref MIB_UPLINK_COUNTER
+     */
+    uint32_t UpLinkCounter;
+    /*!
+     * LoRaWAN Down-link counter
+     *
+     * Related MIB type: \ref MIB_DOWNLINK_COUNTER
+     */
+    uint32_t DownLinkCounter;
+    /*!
+     * Multicast channel
+     *
+     * Related MIB type: \ref MIB_MULTICAST_CHANNEL
+     */
+    MulticastParams_t* MulticastList;
+}MibParam_t;
+
+/*!
+ * LoRaMAC MIB-RequestConfirm structure
+ */
+typedef struct eMibRequestConfirm
+{
+    /*!
+     * MIB-Request type
+     */
+    Mib_t Type;
+
+    /*!
+     * MLME-RequestConfirm parameters
+     */
+    MibParam_t Param;
+}MibRequestConfirm_t;
+
+/*!
+ * LoRaMAC tx information
+ */
+typedef struct sLoRaMacTxInfo
+{
+    /*!
+     * Defines the size of the applicative payload which can be processed
+     */
+    uint8_t MaxPossiblePayload;
+    /*!
+     * The current payload size, dependent on the current datarate
+     */
+    uint8_t CurrentPayloadSize;
+}LoRaMacTxInfo_t;
+
+/*!
+ * LoRaMAC Status
+ */
+typedef enum eLoRaMacStatus
+{
+    /*!
+     * Service started successfully
+     */
+    LORAMAC_STATUS_OK,
+    /*!
+     * Service not started - LoRaMAC is busy
+     */
+    LORAMAC_STATUS_BUSY,
+    /*!
+     * Service unknown
+     */
+    LORAMAC_STATUS_SERVICE_UNKNOWN,
+    /*!
+     * Service not started - invalid parameter
+     */
+    LORAMAC_STATUS_PARAMETER_INVALID,
+    /*!
+     * Service not started - the device is not in a LoRaWAN
+     */
+    LORAMAC_STATUS_NO_NETWORK_JOINED,
+    /*!
+     * Service not started - playload lenght error
+     */
+    LORAMAC_STATUS_LENGTH_ERROR,
+    /*!
+     * Service not started - playload lenght error
+     */
+    LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR,
+    /*!
+     * Service not started - the device is switched off
+     */
+    LORAMAC_STATUS_DEVICE_OFF,
+}LoRaMacStatus_t;
 
 /*!
  * LoRaMAC events structure
  * Used to notify upper layers of MAC events
  */
-typedef struct sLoRaMacCallbacks
+typedef struct sLoRaMacPrimitives
 {
     /*!
-     * MAC layer event callback prototype.
+     * \brief   MCPS-Confirm primitive
      *
-     * \param [IN] flags Bit field indicating the MAC events occurred
-     * \param [IN] info  Details about MAC events occurred
+     * \param   [OUT] MCPS-Confirm parameters
+     */
+    void ( *MacMcpsConfirm )( McpsConfirm_t *McpsConfirm );
+    /*!
+     * \brief   MCPS-Indication primitive
+     *
+     * \param   [OUT] MCPS-Indication parameters
      */
-    void ( *MacEvent )( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info );
+    void ( *MacMcpsIndication )( McpsIndication_t *McpsIndication );
     /*!
-     * Function callback to get the current battery level
+     * \brief   MLME-Confirm primitive
      *
-     * \retval batteryLevel Current battery level
+     * \param   [OUT] MLME-Confirm parameters
+     */
+    void ( *MacMlmeConfirm )( MlmeConfirm_t *MlmeConfirm );
+}LoRaMacPrimitives_t;
+
+typedef struct sLoRaMacCallback
+{
+    /*!
+     * \brief   Measures the battery level
+     *
+     * \retval  Battery level [0: node is connected to an external
+     *          power source, 1..254: battery level, where 1 is the minimum
+     *          and 254 is the maximum value, 255: the node was not able
+     *          to measure the battery level]
      */
     uint8_t ( *GetBatteryLevel )( void );
-}LoRaMacCallbacks_t;
-
-/*!
- * LoRaMAC layer initialization
- *
- * \param [IN] callabcks       Pointer to a structure defining the LoRaMAC
- *                             callback functions.
- */
-void LoRaMacInit( LoRaMacCallbacks_t *callabcks );
+}LoRaMacCallback_t;
 
 /*!
- * Enables/Disables the ADR (Adaptive Data Rate)
- * 
- * \param [IN] enable [true: ADR ON, false: ADR OFF]
- */
-void LoRaMacSetAdrOn( bool enable );
-
-/*!
- * Initializes the network IDs. Device address, 
- * network session AES128 key and application session AES128 key.
+ * \brief   LoRaMAC layer initialization
  *
- * \remark To be only used when Over-the-Air activation isn't used.
+ * \details In addition to the initialization of the LoRaMAC layer, this
+ *          function initializes the callback primitives of the MCPS and
+ *          MLME services. Every data field of \ref LoRaMacPrimitives_t must be
+ *          set to a valid callback function.
+ *
+ * \param   [IN] events - Pointer to a structure defining the LoRaMAC
+ *                        event functions. Refer to \ref LoRaMacPrimitives_t.
  *
- * \param [IN] netID   24 bits network identifier 
- *                     ( provided by network operator )
- * \param [IN] devAddr 32 bits device address on the network 
- *                     (must be unique to the network)
- * \param [IN] nwkSKey Pointer to the network session AES128 key array
- *                     ( 16 bytes )
- * \param [IN] appSKey Pointer to the application session AES128 key array
- *                     ( 16 bytes )
+ * \param   [IN] events - Pointer to a structure defining the LoRaMAC
+ *                        callback functions. Refer to \ref LoRaMacCallback_t.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
-void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam );
+LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks );
 
 /*!
- * Initiates the Over-the-Air activation 
- * 
- * \param [IN] devEui Pointer to the device EUI array ( 8 bytes )
- * \param [IN] appEui Pointer to the application EUI array ( 8 bytes )
- * \param [IN] appKey Pointer to the application AES128 key array ( 16 bytes )
+ * \brief   Queries the LoRaMAC if it is possible to send the next frame with
+ *          a given payload size. The LoRaMAC takes scheduled MAC commands into
+ *          account and reports, when the frame can be send or not.
+ *
+ * \param   [IN] size - Size of applicative payload to be send next
  *
- * \retval status [0: OK, 1: Tx error, 2: Already joined a network]
- */
-uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey );
-
-/*!
- * Sends a LinkCheckReq MAC command on the next uplink frame
+ * \param   [OUT] txInfo - The structure \ref LoRaMacTxInfo_t contains
+ *                         information about the actual maximum payload possible
+ *                         ( according to the configured datarate or the next
+ *                         datarate according to ADR ), and the maximum frame
+ *                         size, taking the scheduled MAC commands into account.
  *
- * \retval status Function status [0: OK, 1: Busy]
+ * \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. *
  */
-uint8_t LoRaMacLinkCheckReq( void );
-
-/*!
- * LoRaMAC layer send frame
- *
- * \param [IN] fPort       MAC payload port (must be > 0)
- * \param [IN] fBuffer     MAC data buffer to be sent
- * \param [IN] fBufferSize MAC data buffer size
- *
- * \retval status          [0: OK, 1: Busy, 2: No network joined,
- *                          3: Length or port error, 4: Unknown MAC command
- *                          5: Unable to find a free channel
- *                          6: Device switched off]
- */
-uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo );
 
 /*!
- * LoRaMAC layer send frame
+ * \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:
  *
- * \param [IN] fPort       MAC payload port (must be > 0)
- * \param [IN] fBuffer     MAC data buffer to be sent
- * \param [IN] fBufferSize MAC data buffer size
- * \param [IN] fBufferSize MAC data buffer size
- * \param [IN] nbRetries   Number of retries to receive the acknowledgement
+ *          0-15 for EU868
+ *          0-72 for US915
+ *
+ * \param   [IN] params - Channel parameters to set.
  *
- * \retval status          [0: OK, 1: Busy, 2: No network joined,
- *                          3: Length or port error, 4: Unknown MAC command
- *                          5: Unable to find a free channel
- *                          6: Device switched off]
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
-uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t nbRetries );
+LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params );
 
 /*!
- * ============================================================================
- * = LoRaMac test functions                                                   =
- * ============================================================================
+ * \brief   LoRaMAC channel remove service
+ *
+ * \details Deactivates the id in the channel mask.
+ *
+ * \param   [IN] id - Id of the channel.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
+LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id );
 
 /*!
- * LoRaMAC layer generic send frame
+ * \brief   LoRaMAC multicast channel link service
+ *
+ * \details Links a multicast channel into the linked list.
+ *
+ * \param   [IN] channelParam - Multicast channel parameters to link.
  *
- * \param [IN] macHdr      MAC header field
- * \param [IN] fOpts       MAC commands buffer
- * \param [IN] fPort       MAC payload port
- * \param [IN] fBuffer     MAC data buffer to be sent
- * \param [IN] fBufferSize MAC data buffer size
- * \retval status          [0: OK, 1: Busy, 2: No network joined,
- *                          3: Length or port error, 4: Unknown MAC command
- *                          5: Unable to find a free channel
- *                          6: Device switched off]
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
-uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
+LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam );
+
+/*!
+ * \brief   LoRaMAC multicast channel unlink service
+ *
+ * \details Unlinks a multicast channel from the linked list.
+ *
+ * \param   [IN] channelParam - Multicast channel parameters to unlink.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
+ */
+LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam );
 
 /*!
- * LoRaMAC layer frame buffer initialization.
+ * \brief   LoRaMAC MIB-Get
+ *
+ * \details The mac information base service to get attributes of the LoRaMac
+ *          layer.
+ *
+ *          The following code-snippet shows how to use the API to get the
+ *          parameter AdrEnable, defined by the enumeration type
+ *          \ref MIB_ADR.
+ * \code
+ * MibRequestConfirm_t mibReq;
+ * mibReq.Type = MIB_ADR;
  *
- * \param [IN] channel     Channel parameters
- * \param [IN] macHdr      MAC header field
- * \param [IN] fCtrl       MAC frame control field
- * \param [IN] fOpts       MAC commands buffer
- * \param [IN] fPort       MAC payload port
- * \param [IN] fBuffer     MAC data buffer to be sent
- * \param [IN] fBufferSize MAC data buffer size
- * \retval status          [0: OK, 1: N/A, 2: No network joined,
- *                          3: Length or port error, 4: Unknown MAC command]
+ * if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
+ * {
+ *   // LoRaMAC updated the parameter mibParam.AdrEnable
+ * }
+ * \endcode
+ *
+ * \param   [IN] mibRequest - MIB-GET-Request to perform. Refer to \ref MibRequestConfirm_t.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
-uint8_t LoRaMacPrepareFrame( ChannelParams_t channel,LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
-
-/*!
- * LoRaMAC layer prepared frame buffer transmission with channel specification
- *
- * \remark LoRaMacPrepareFrame must be called at least once before calling this
- *         function.
- *
- * \param [IN] channel     Channel parameters
- * \retval status          [0: OK, 1: Busy]
- */
-uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel );
+LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet );
 
 /*!
- * LoRaMAC layer generic send frame with channel specification
+ * \brief   LoRaMAC MIB-Set
+ *
+ * \details The mac information base service to set attributes of the LoRaMac
+ *          layer.
+ *
+ *          The following code-snippet shows how to use the API to set the
+ *          parameter AdrEnable, defined by the enumeration type
+ *          \ref MIB_ADR.
+ *
+ * \code
+ * MibRequestConfirm_t mibReq;
+ * mibReq.Type = MIB_ADR;
+ * mibReq.Param.AdrEnable = true;
  *
- * \param [IN] channel     Channel parameters
- * \param [IN] macHdr      MAC header field
- * \param [IN] fCtrl       MAC frame control field
- * \param [IN] fOpts       MAC commands buffer
- * \param [IN] fPort       MAC payload port
- * \param [IN] fBuffer     MAC data buffer to be sent
- * \param [IN] fBufferSize MAC data buffer size
- * \retval status          [0: OK, 1: Busy, 2: No network joined,
- *                          3: Length or port error, 4: Unknown MAC command]
- */
-uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
-
-/*!
- * ============================================================================
- * = LoRaMac setup functions                                                  =
- * ============================================================================
- */
-
-/*
- * TODO: Add documentation
+ * if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
+ * {
+ *   // LoRaMAC updated the parameter
+ * }
+ * \endcode
+ *
+ * \param   [IN] mibRequest - MIB-SET-Request to perform. Refer to \ref MibRequestConfirm_t.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID.
  */
-void LoRaMacSetDeviceClass( DeviceClass_t deviceClass );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetPublicNetwork( bool enable );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetChannel( uint8_t id, ChannelParams_t params );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetRx2Channel( Rx2ChannelParams_t param );
-
-/*!
- * Sets channels tx output power
- *
- * \param [IN] txPower [TX_POWER_20_DBM, TX_POWER_14_DBM,
-                        TX_POWER_11_DBM, TX_POWER_08_DBM,
-                        TX_POWER_05_DBM, TX_POWER_02_DBM]
- */
-void LoRaMacSetChannelsTxPower( int8_t txPower );
+LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet );
 
 /*!
- * Sets channels datarate
+ * \brief   LoRaMAC MLME-Request
+ *
+ * \details The Mac layer management entity handles management services. The
+ *          following code-snippet shows how to use the API to perform a
+ *          network join request.
+ *
+ * \code
+ * static uint8_t DevEui[] =
+ * {
+ *   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ * };
+ * static uint8_t AppEui[] =
+ * {
+ *   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ * };
+ * static uint8_t AppKey[] =
+ * {
+ *   0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
+ *   0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
+ * };
  *
- * \param [IN] datarate 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]
- */
-void LoRaMacSetChannelsDatarate( int8_t datarate );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetChannelsMask( uint16_t *mask );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetChannelsNbRep( uint8_t nbRep );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetMaxRxWindow( uint32_t delay );
-
-/*
- * TODO: Add documentation
+ * MlmeReq_t mlmeReq;
+ * mlmeReq.Type = MLME_JOIN;
+ * mlmeReq.Req.Join.DevEui = DevEui;
+ * mlmeReq.Req.Join.AppEui = AppEui;
+ * mlmeReq.Req.Join.AppKey = AppKey;
+ *
+ * if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
+ * {
+ *   // Service started successfully. Waiting for the Mlme-Confirm event
+ * }
+ * \endcode
+ *
+ * \param   [IN] mlmeRequest - MLME-Request to perform. Refer to \ref MlmeReq_t.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID,
+ *          \ref LORAMAC_STATUS_NO_NETWORK_JOINED,
+ *          \ref LORAMAC_STATUS_LENGTH_ERROR,
+ *          \ref LORAMAC_STATUS_DEVICE_OFF.
  */
-void LoRaMacSetReceiveDelay1( uint32_t delay );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetReceiveDelay2( uint32_t delay );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetJoinAcceptDelay1( uint32_t delay );
-
-/*
- * TODO: Add documentation
- */
-void LoRaMacSetJoinAcceptDelay2( uint32_t delay );
-
-/*
- * TODO: Add documentation
- */
-uint32_t LoRaMacGetUpLinkCounter( void );
-
-/*
- * TODO: Add documentation
- */
-uint32_t LoRaMacGetDownLinkCounter( void );
-
-/*
- * ============================================================================
- * = LoRaMac test functions                                                   =
- * ============================================================================
- */
+LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest );
 
 /*!
- * Disables/Enables the duty cycle enforcement (EU868)
+ * \brief   LoRaMAC MCPS-Request
+ *
+ * \details The Mac Common Part Sublayer handles data services. The following
+ *          code-snippet shows how to use the API to send an unconfirmed
+ *          LoRaMAC frame.
  *
- * \param   [IN] enable - Enabled or disables the duty cycle
- */
-void LoRaMacTestSetDutyCycleOn( bool enable );
-
-/*!
- * Disables/Enables the reception windows opening
+ * \code
+ * uint8_t myBuffer[] = { 1, 2, 3 };
+ *
+ * McpsReq_t mcpsReq;
+ * mcpsReq.Type = MCPS_UNCONFIRMED;
+ * mcpsReq.Req.Unconfirmed.fPort = 1;
+ * mcpsReq.Req.Unconfirmed.fBuffer = myBuffer;
+ * mcpsReq.Req.Unconfirmed.fBufferSize = sizeof( myBuffer );
  *
- * \param [IN] enable [true: enable, false: disable]
+ * if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
+ * {
+ *   // Service started successfully. Waiting for the MCPS-Confirm event
+ * }
+ * \endcode
+ *
+ * \param   [IN] mcpsRequest - MCPS-Request to perform. Refer to \ref McpsReq_t.
+ *
+ * \retval  LoRaMacStatus_t Status of the operation. Possible returns are:
+ *          \ref LORAMAC_STATUS_OK,
+ *          \ref LORAMAC_STATUS_BUSY,
+ *          \ref LORAMAC_STATUS_SERVICE_UNKNOWN,
+ *          \ref LORAMAC_STATUS_PARAMETER_INVALID,
+ *          \ref LORAMAC_STATUS_NO_NETWORK_JOINED,
+ *          \ref LORAMAC_STATUS_LENGTH_ERROR,
+ *          \ref LORAMAC_STATUS_DEVICE_OFF.
  */
-void LoRaMacTestRxWindowsOn( bool enable );
+LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest );
 
-/*!
- * Enables the MIC field test
- *
- * \param [IN] upLinkCounter Fixed Tx packet counter value
- */
-void LoRaMacTestSetMic( uint16_t upLinkCounter );
+/*! \} defgroup LORAMAC */
 
 #endif // __LORAMAC_H__
--- a/LoRaMacCrypto.cpp	Mon Nov 23 10:09:43 2015 +0000
+++ b/LoRaMacCrypto.cpp	Tue Jan 05 16:41:54 2016 +0000
@@ -5,12 +5,17 @@
  _____) ) ____| | | || |_| ____( (___| | | |
 (______/|_____)_|_|_| \__)_____)\____)_| |_|
     (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 and Gregory Cristian
+Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
 */
 #include <stdlib.h>
 #include <stdint.h>
@@ -185,13 +190,13 @@
 
     memset1( nonce, 0, sizeof( nonce ) );
     nonce[0] = 0x01;
-    LoRaMacMemCpy( appNonce, nonce + 1, 6 );
-    LoRaMacMemCpy( pDevNonce, nonce + 7, 2 );
+    memcpy1( nonce + 1, appNonce, 6 );
+    memcpy1( nonce + 7, pDevNonce, 2 );
     aes_encrypt( nonce, nwkSKey, &AesContext );
 
     memset1( nonce, 0, sizeof( nonce ) );
     nonce[0] = 0x02;
-    LoRaMacMemCpy( appNonce, nonce + 1, 6 );
-    LoRaMacMemCpy( pDevNonce, nonce + 7, 2 );
+    memcpy1( nonce + 1, appNonce, 6 );
+    memcpy1( nonce + 7, pDevNonce, 2 );
     aes_encrypt( nonce, appSKey, &AesContext );
 }
--- a/LoRaMacCrypto.h	Mon Nov 23 10:09:43 2015 +0000
+++ b/LoRaMacCrypto.h	Tue Jan 05 16:41:54 2016 +0000
@@ -1,99 +1,111 @@
-/*
- / _____)             _              | |
-( (____  _____ ____ _| |_ _____  ____| |__
- \____ \| ___ |    (_   _) ___ |/ ___)  _ \
- _____) ) ____| | | || |_| ____( (___| | | |
-(______/|_____)_|_|_| \__)_____)\____)_| |_|
-    (C)2013 Semtech
-
-Description: LoRa MAC layer implementation
-
-License: Revised BSD License, see LICENSE.TXT file include in the project
-
-Maintainer: Miguel Luis and Gregory Cristian
-*/
+/*!
+ * \file      LoRaMacCrypto.h
+ *
+ * \brief     LoRa MAC layer cryptography implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jäckle ( STACKFORCE )
+ *
+ * \defgroup    LORAMAC_CRYPTO  LoRa MAC layer cryptography implementation
+ *              This module covers the implementation of cryptographic functions
+ *              of the LoRaMAC layer.
+ * \{
+ */
 #ifndef __LORAMAC_CRYPTO_H__
 #define __LORAMAC_CRYPTO_H__
 
 /*!
- * Copies size elements of src array to dst array
- * 
- * \remark STM32 Standard memcpy function only works on pointers that are aligned
+ * Computes the LoRaMAC frame MIC field
  *
- * \param [IN]  src  Source array
- * \param [OUT] dst  Destination array
- * \param [IN]  size Number of bytes to be copied
- */
-#define LoRaMacMemCpy( src, dst, size ) memcpy1( dst, src, size )
-
-/*!
- * Computes the LoRaMAC frame MIC field  
- *
- * \param [IN]  buffer          Data buffer
- * \param [IN]  size            Data buffer size
- * \param [IN]  key             AES key to be used
- * \param [IN]  address         Frame address
- * \param [IN]  dir             Frame direction [0: uplink, 1: downlink]
- * \param [IN]  sequenceCounter Frame sequence counter
- * \param [OUT] mic             Computed MIC field
+ * \param [IN]  buffer          - Data buffer
+ * \param [IN]  size            - Data buffer size
+ * \param [IN]  key             - AES key to be used
+ * \param [IN]  address         - Frame address
+ * \param [IN]  dir             - Frame direction [0: uplink, 1: downlink]
+ * \param [IN]  sequenceCounter - Frame sequence counter
+ * \param [OUT] mic             - Computed MIC field
  */
 void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic );
 
 /*!
- * Computes the LoRaMAC payload encryption 
+ * Computes the LoRaMAC payload encryption
  *
- * \param [IN]  buffer          Data buffer
- * \param [IN]  size            Data buffer size
- * \param [IN]  key             AES key to be used
- * \param [IN]  address         Frame address
- * \param [IN]  dir             Frame direction [0: uplink, 1: downlink]
- * \param [IN]  sequenceCounter Frame sequence counter
- * \param [OUT] encBuffer       Encrypted buffer
+ * \param [IN]  buffer          - Data buffer
+ * \param [IN]  size            - Data buffer size
+ * \param [IN]  key             - AES key to be used
+ * \param [IN]  address         - Frame address
+ * \param [IN]  dir             - Frame direction [0: uplink, 1: downlink]
+ * \param [IN]  sequenceCounter - Frame sequence counter
+ * \param [OUT] encBuffer       - Encrypted buffer
  */
 void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer );
 
 /*!
- * Computes the LoRaMAC payload decryption 
+ * Computes the LoRaMAC payload decryption
  *
- * \param [IN]  buffer          Data buffer
- * \param [IN]  size            Data buffer size
- * \param [IN]  key             AES key to be used
- * \param [IN]  address         Frame address
- * \param [IN]  dir             Frame direction [0: uplink, 1: downlink]
- * \param [IN]  sequenceCounter Frame sequence counter
- * \param [OUT] decBuffer       Decrypted buffer
+ * \param [IN]  buffer          - Data buffer
+ * \param [IN]  size            - Data buffer size
+ * \param [IN]  key             - AES key to be used
+ * \param [IN]  address         - Frame address
+ * \param [IN]  dir             - Frame direction [0: uplink, 1: downlink]
+ * \param [IN]  sequenceCounter - Frame sequence counter
+ * \param [OUT] decBuffer       - Decrypted buffer
  */
 void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer );
 
 /*!
- * Computes the LoRaMAC Join Request frame MIC field  
+ * Computes the LoRaMAC Join Request frame MIC field
  *
- * \param [IN]  buffer          Data buffer
- * \param [IN]  size            Data buffer size
- * \param [IN]  key             AES key to be used
- * \param [OUT] mic             Computed MIC field
+ * \param [IN]  buffer          - Data buffer
+ * \param [IN]  size            - Data buffer size
+ * \param [IN]  key             - AES key to be used
+ * \param [OUT] mic             - Computed MIC field
  */
 void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic );
 
 /*!
- * Computes the LoRaMAC join frame decryption 
+ * Computes the LoRaMAC join frame decryption
  *
- * \param [IN]  buffer          Data buffer
- * \param [IN]  size            Data buffer size
- * \param [IN]  key             AES key to be used
- * \param [OUT] decBuffer       Decrypted buffer
+ * \param [IN]  buffer          - Data buffer
+ * \param [IN]  size            - Data buffer size
+ * \param [IN]  key             - AES key to be used
+ * \param [OUT] decBuffer       - Decrypted buffer
  */
 void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer );
 
 /*!
- * Computes the LoRaMAC join frame decryption 
+ * Computes the LoRaMAC join frame decryption
  *
- * \param [IN]  key             AES key to be used
- * \param [IN]  appNonce        Application nonce
- * \param [IN]  devNonce        Device nonce
- * \param [OUT] nwkSKey         Network session key
- * \param [OUT] appSKey         Application session key
+ * \param [IN]  key             - AES key to be used
+ * \param [IN]  appNonce        - Application nonce
+ * \param [IN]  devNonce        - Device nonce
+ * \param [OUT] nwkSKey         - Network session key
+ * \param [OUT] appSKey         - Application session key
  */
 void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey );
 
+/*! \} defgroup LORAMAC */
+
 #endif // __LORAMAC_CRYPTO_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaMacTest.h	Tue Jan 05 16:41:54 2016 +0000
@@ -0,0 +1,71 @@
+/*!
+ * \file      LoRaMacTest.h
+ *
+ * \brief     LoRa MAC layer test function implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ *                ______                              _
+ *               / _____)             _              | |
+ *              ( (____  _____ ____ _| |_ _____  ____| |__
+ *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ *               _____) ) ____| | | || |_| ____( (___| | | |
+ *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ *              (C)2013 Semtech
+ *
+ *               ___ _____ _   ___ _  _____ ___  ___  ___ ___
+ *              / __|_   _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ *              \__ \ | |/ _ \ (__| ' <| _| (_) |   / (__| _|
+ *              |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ *              embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author    Miguel Luis ( Semtech )
+ *
+ * \author    Gregory Cristian ( Semtech )
+ *
+ * \author    Daniel Jäckle ( STACKFORCE )
+ *
+ * \defgroup  LORAMACTEST LoRa MAC layer test function implementation
+ *            This module specifies the API implementation of test function of the LoRaMAC layer.
+ *            The functions in this file are only for testing purposes only.
+ * \{
+ */
+#ifndef __LORAMACTEST_H__
+#define __LORAMACTEST_H__
+
+/*!
+ * \brief   Enabled or disables the reception windows
+ *
+ * \details This is a test function. It shall be used for testing purposes only.
+ *          Changing this attribute may lead to a non-conformance LoRaMac operation.
+ *
+ * \param   [IN] enable - Enabled or disables the reception windows
+ */
+void LoRaMacTestRxWindowsOn( bool enable );
+
+/*!
+ * \brief   Enables the MIC field test
+ *
+ * \details This is a test function. It shall be used for testing purposes only.
+ *          Changing this attribute may lead to a non-conformance LoRaMac operation.
+ *
+ * \param   [IN] txPacketCounter - Fixed Tx packet counter value
+ */
+void LoRaMacTestSetMic( uint16_t txPacketCounter );
+
+/*!
+ * \brief   Enabled or disables the duty cycle
+ *
+ * \details This is a test function. It shall be used for testing purposes only.
+ *          Changing this attribute may lead to a non-conformance LoRaMac operation.
+ *
+ * \param   [IN] enable - Enabled or disables the duty cycle
+ */
+void LoRaMacTestSetDutyCycleOn( bool enable );
+
+/*! \} defgroup LORAMACTEST */
+
+#endif // __LORAMACTEST_H__