LoRaWAN MAC layer implementation
Dependents: LoRaWAN-demo-72_tjm LoRaWAN-demo-72_jlc LoRaWAN-demo-elmo frdm_LoRa_Connect_Woodstream_Demo_tjm ... more
LoRAWAN-lib is a port of the GitHub LoRaMac-node LoRaWAN MAC layer implementation.
This library depends on the SX1276Lib or SX1272Lib radio drivers depending on the used mbed component shield.
This library depends also on some cryptographic helper functions as well as helper functions for the timers management. These can be found on the example projects under the system directory.
The example projects are:
The LoRaWAN specification specifies different ISM bands operating parameters. These are all implemented under the LoRaMac-board.h file.
In order to select which band to use, please change line 24 of board.h file provided on the examples projects as follows:
EU868
board.h
#define USE_BAND_868
US915
board.h
#define USE_BAND_915
US915 - Hybrid
board.h
#define USE_BAND_915_HYBRID
CN780
board.h
#define USE_BAND_780
EU433
board.h
#define USE_BAND_433
Revision 4:37c12dbc8dc7, committed 2016-05-13
- Comitter:
- mluis
- Date:
- Fri May 13 14:51:50 2016 +0000
- Parent:
- 3:b9d87593a8ae
- Child:
- 5:2477c924494a
- Commit message:
- Synchronized with https://github.com/Lora-net/LoRaMac-node git revision 55d16ca8949c09ee241c87b7600e2a8bc90d3743
Changed in this revision
--- a/LoRaMac-api-v3.cpp Mon Mar 14 09:09:54 2016 +0000 +++ b/LoRaMac-api-v3.cpp Fri May 13 14:51:50 2016 +0000 @@ -105,8 +105,7 @@ { case MLME_JOIN: { - // Status is OK, node has joined the network - LoRaMacEventInfo.Status = mlmeConfirm->Status; + // Status is OK, node has joined the network LoRaMacEventFlags.Bits.Tx = 1; LoRaMacEventFlags.Bits.Rx = 1; LoRaMacEventFlags.Bits.JoinAccept = 1; @@ -126,6 +125,7 @@ break; } } + LoRaMacEventInfo.Status = mlmeConfirm->Status; if( LoRaMacFlags.Bits.McpsInd != 1 ) {
--- a/LoRaMac-api-v3.h Mon Mar 14 09:09:54 2016 +0000 +++ b/LoRaMac-api-v3.h Fri May 13 14:51:50 2016 +0000 @@ -41,15 +41,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 /*! @@ -75,19 +83,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 @@ -97,14 +105,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 /*!
--- a/LoRaMac-board.h Mon Mar 14 09:09:54 2016 +0000 +++ b/LoRaMac-board.h Fri May 13 14:51:50 2016 +0000 @@ -33,12 +33,22 @@ /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node @@ -111,9 +121,19 @@ */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } #define LC1 { 433175000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC2 { 433375000, { ( ( DR_7 << 4 ) | DR_0 ) }, 0 } +#define LC2 { 433375000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } #define LC3 { 433575000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +/*! + * LoRaMac duty cycle for the join procedure + */ +#define JOIN_DC 1000 + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + #elif defined( USE_BAND_780 ) /*! @@ -124,12 +144,22 @@ /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node @@ -202,9 +232,19 @@ */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } #define LC1 { 779500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } -#define LC2 { 779700000, { ( ( DR_7 << 4 ) | DR_0 ) }, 0 } +#define LC2 { 779700000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } #define LC3 { 779900000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +/*! + * LoRaMac duty cycle for the join procedure + */ +#define JOIN_DC 1000 + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + #elif defined( USE_BAND_868 ) /*! @@ -215,12 +255,22 @@ /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MAX_DATARATE DR_7 +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 /*! * Default datarate used by the node @@ -309,9 +359,19 @@ */ // Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } #define LC1 { 868100000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } -#define LC2 { 868300000, { ( ( DR_6 << 4 ) | DR_0 ) }, 1 } +#define LC2 { 868300000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } #define LC3 { 868500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +/*! + * LoRaMac duty cycle for the join procedure + */ +#define JOIN_DC 1000 + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) /*! @@ -322,12 +382,22 @@ /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MIN_DATARATE DR_0 +#define LORAMAC_TX_MIN_DATARATE DR_0 /*! * Minimal datarate that can be used by the node */ -#define LORAMAC_MAX_DATARATE DR_4 +#define LORAMAC_TX_MAX_DATARATE DR_4 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_8 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_13 /*! * Default datarate used by the node
--- a/LoRaMac.cpp Mon Mar 14 09:09:54 2016 +0000 +++ b/LoRaMac.cpp Fri May 13 14:51:50 2016 +0000 @@ -34,6 +34,13 @@ #define LORA_MAC_COMMAND_MAX_LENGTH 15 /*! + * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength + * in RxWindowSetup function. + * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD + */ +#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) + +/*! * Device IEEE EUI */ static uint8_t *LoRaMacDevEui; @@ -362,7 +369,6 @@ * Contains the channels which remain to be applied. */ static uint16_t ChannelsMaskRemaining[6]; - #else #error "Please define a frequency band in the compiler options." #endif @@ -430,6 +436,8 @@ */ static uint8_t Channel; +static uint8_t LastTxChannel; + /*! * LoRaMac internal states */ @@ -442,6 +450,7 @@ MAC_ACK_RETRY = 0x00000008, MAC_TX_DELAYED = 0x00000010, MAC_TX_CONFIG = 0x00000020, + MAC_RX_ABORT = 0x00000040, }; /*! @@ -672,16 +681,46 @@ */ static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ); +/*! + * \brief Counts the number of bits in a mask. + * + * \param [IN] mask A mask from which the function counts the active bits. + * \param [IN] nbBits The number of bits to check. + * + * \retval Number of enabled bits in the mask. + */ +static uint8_t CountBits( uint16_t mask, uint8_t nbBits ); + #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) /*! * \brief Counts the number of enabled 125 kHz channels in the channel mask. * This function can only be applied to US915 band. * - * \param channelsMask Pointer to the first element of the channel mask + * \param [IN] channelsMask Pointer to the first element of the channel mask * * \retval Number of enabled channels in the channel mask */ static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ); + +#if defined( USE_BAND_915_HYBRID ) +/*! + * \brief Validates the correctness of the channel mask for US915, hybrid mode. + * + * \param [IN] mask Block definition to set. + * \param [OUT] channelsMask Pointer to the first element of the channel mask + */ +static void ReenableChannels( uint16_t mask, uint16_t* channelMask ); + +/*! + * \brief Validates the correctness of the channel mask for US915, hybrid mode. + * + * \param [IN] channelsMask Pointer to the first element of the channel mask + * + * \retval [true: channel mask correct, false: channel mask not correct] + */ +static bool ValidateChannelMask( uint16_t* channelMask ); +#endif + #endif /*! @@ -764,6 +803,13 @@ */ static LoRaMacStatus_t ScheduleTx( void ); +/* + * \brief Calculates the back-off time for the band of a channel. + * + * \param [IN] channel The last Tx channel index + */ +static void CalculateBackOff( uint8_t channel ); + /*! * \brief LoRaMAC layer prepared frame buffer transmission with channel specification * @@ -789,19 +835,12 @@ OnRxWindow2TimerEvent( ); } - // Update Band Time OFF - Bands[Channels[Channel].Band].LastTxDoneTime = curTime; - if( DutyCycleOn == true ) - { - Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir; - } - else - { - Bands[Channels[Channel].Band].TimeOff = 0; - } - // Update Aggregated Time OFF + // Store last Tx channel + LastTxChannel = Channel; + // Update last tx done time for the current channel + Bands[Channels[LastTxChannel].Band].LastTxDoneTime = curTime; + // Update Aggregated last tx done time AggregatedLastTxDoneTime = curTime; - AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir ); if( IsRxWindowsEnabled == true ) { @@ -840,7 +879,7 @@ static void PrepareRxDoneAbort( void ) { - LoRaMacState &= ~MAC_TX_RUNNING; + LoRaMacState |= MAC_RX_ABORT; if( NodeAckRequested ) { @@ -864,6 +903,7 @@ { LoRaMacHeader_t macHdr; LoRaMacFrameCtrl_t fCtrl; + bool skipIndication = false; uint8_t pktHeaderLen = 0; uint32_t address = 0; @@ -1061,6 +1101,15 @@ } } + // Check for a the maximum allowed counter difference + if( sequenceCounterDiff >= MAX_FCNT_GAP ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort( ); + return; + } + if( isMicOk == true ) { McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; @@ -1095,19 +1144,27 @@ { SrvAckRequested = true; McpsIndication.McpsIndication = MCPS_CONFIRMED; + + if( ( DownLinkCounter == downLinkCounter ) && + ( DownLinkCounter != 0 ) ) + { + // Duplicated confirmed downlink. Skip indication. + skipIndication = true; + } } else { SrvAckRequested = false; McpsIndication.McpsIndication = MCPS_UNCONFIRMED; - } - if( ( DownLinkCounter == downLinkCounter ) && - ( DownLinkCounter != 0 ) ) - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - McpsIndication.DownLinkCounter = downLinkCounter; - PrepareRxDoneAbort( ); - return; + + if( ( DownLinkCounter == downLinkCounter ) && + ( DownLinkCounter != 0 ) ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort( ); + return; + } } DownLinkCounter = downLinkCounter; } @@ -1169,12 +1226,18 @@ downLinkCounter, LoRaMacRxPayload ); - McpsIndication.Buffer = LoRaMacRxPayload; - McpsIndication.BufferSize = frameLen; - McpsIndication.RxData = true; + if( skipIndication == false ) + { + McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.BufferSize = frameLen; + McpsIndication.RxData = true; + } } } - LoRaMacFlags.Bits.McpsInd = 1; + if( skipIndication == false ) + { + LoRaMacFlags.Bits.McpsInd = 1; + } } else { @@ -1281,6 +1344,12 @@ if( LoRaMacFlags.Bits.MacDone == 1 ) { + if( ( LoRaMacState & MAC_RX_ABORT ) == MAC_RX_ABORT ) + { + LoRaMacState &= ~MAC_RX_ABORT; + LoRaMacState &= ~MAC_TX_RUNNING; + } + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) { if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) || @@ -1357,7 +1426,7 @@ if( ( AckTimeoutRetriesCounter % 2 ) == 1 ) { - ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE ); + ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE ); } LoRaMacFlags.Bits.MacDone = 0; // Sends the same frame again @@ -1378,12 +1447,7 @@ ChannelsMask[5] = 0x0000; #elif defined( USE_BAND_915_HYBRID ) // Re-enable default channels - ChannelsMask[0] = 0x00FF; - ChannelsMask[1] = 0x0000; - ChannelsMask[2] = 0x0000; - ChannelsMask[3] = 0x0000; - ChannelsMask[4] = 0x0001; - ChannelsMask[5] = 0x0000; + ReenableChannels( ChannelsMask[4], ChannelsMask ); #else #error "Please define a frequency band in the compiler options." #endif @@ -1464,13 +1528,18 @@ } // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( datarate >= DR_3 ) - { // DR_6, DR_5, DR_4, DR_3 + if( ( datarate == DR_3 ) || ( datarate == DR_4 ) ) + { // DR_4, DR_3 symbTimeout = 8; } - if( datarate == DR_6 ) + else if( datarate == DR_5 ) + { + symbTimeout = 10; + } + else if( datarate == DR_6 ) {// LoRa 250 kHz bandwidth = 1; + symbTimeout = 14; } RxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false ); #elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) @@ -1480,9 +1549,35 @@ datarate = DR_0; } // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( datarate > DR_0 ) - { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13 - symbTimeout = 8; + switch( datarate ) + { + case DR_0: // SF10 - BW125 + symbTimeout = 5; + break; + + case DR_1: // SF9 - BW125 + case DR_2: // SF8 - BW125 + case DR_8: // SF12 - BW500 + case DR_9: // SF11 - BW500 + case DR_10: // SF10 - BW500 + symbTimeout = 8; + break; + + case DR_3: // SF7 - BW125 + case DR_11: // SF9 - BW500 + symbTimeout = 10; + break; + + case DR_4: // SF8 - BW500 + case DR_12: // SF8 - BW500 + symbTimeout = 14; + break; + + case DR_13: // SF7 - BW500 + symbTimeout = 16; + break; + default: + break; } if( datarate >= DR_4 ) {// LoRa 500 kHz @@ -1504,19 +1599,50 @@ #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( Rx2Channel.Datarate >= DR_3 ) - { // DR_6, DR_5, DR_4, DR_3 + if( ( Rx2Channel.Datarate == DR_3 ) || ( Rx2Channel.Datarate == DR_4 ) ) + { // DR_4, DR_3 symbTimeout = 8; } - if( Rx2Channel.Datarate == DR_6 ) + else if( Rx2Channel.Datarate == DR_5 ) + { + symbTimeout = 10; + } + else if( Rx2Channel.Datarate == DR_6 ) {// LoRa 250 kHz bandwidth = 1; + symbTimeout = 14; } #elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( Rx2Channel.Datarate > DR_0 ) - { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13 - symbTimeout = 8; + switch( Rx2Channel.Datarate ) + { + case DR_0: // SF10 - BW125 + symbTimeout = 5; + break; + + case DR_1: // SF9 - BW125 + case DR_2: // SF8 - BW125 + case DR_8: // SF12 - BW500 + case DR_9: // SF11 - BW500 + case DR_10: // SF10 - BW500 + symbTimeout = 8; + break; + + case DR_3: // SF7 - BW125 + case DR_11: // SF9 - BW500 + symbTimeout = 10; + break; + + case DR_4: // SF8 - BW500 + case DR_12: // SF8 - BW500 + symbTimeout = 14; + break; + + case DR_13: // SF7 - BW500 + symbTimeout = 16; + break; + default: + break; } if( Rx2Channel.Datarate >= DR_4 ) {// LoRa 500 kHz @@ -1555,7 +1681,6 @@ uint8_t nbEnabledChannels = 0; uint8_t delayTx = 0; uint8_t enabledChannels[LORA_MAX_NB_CHANNELS]; - TimerTime_t curTime = TimerGetCurrentTime( ); TimerTime_t nextTxDelay = ( TimerTime_t )( -1 ); memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS ); @@ -1570,16 +1695,7 @@ ChannelsMaskRemaining[4] = ChannelsMask[4]; } #else - uint8_t chanCnt = 0; - for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) - { - if( ChannelsMask[k] != 0 ) - { - chanCnt++; - break; - } - } - if( chanCnt == 0 ) + if( CountBits( ChannelsMask[0], 16 ) == 0 ) { // Re-enable default channels, if no channel is enabled ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); @@ -1587,7 +1703,7 @@ #endif // Update Aggregated duty cycle - if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) ) + if( AggregatedTimeOff <= TimerGetElapsedTime( AggregatedLastTxDoneTime ) ) { AggregatedTimeOff = 0; @@ -1596,14 +1712,14 @@ { if( DutyCycleOn == true ) { - if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) ) + if( Bands[i].TimeOff <= TimerGetElapsedTime( Bands[i].LastTxDoneTime ) ) { Bands[i].TimeOff = 0; } if( Bands[i].TimeOff != 0 ) { nextTxDelay = MIN( Bands[i].TimeOff - - ( curTime - Bands[i].LastTxDoneTime ), + TimerGetElapsedTime( Bands[i].LastTxDoneTime ), nextTxDelay ); } } @@ -1629,6 +1745,15 @@ { // Check if the channel is enabled continue; } +#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) + if( IsLoRaMacNetworkJoined == false ) + { + if( ( JOIN_CHANNELS & ( 1 << j ) ) == 0 ) + { + continue; + } + } +#endif if( ( ( Channels[i + j].DrRange.Fields.Min <= ChannelsDatarate ) && ( ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false ) { // Check if the current channel selection supports the given datarate @@ -1647,7 +1772,7 @@ else { delayTx++; - nextTxDelay = AggregatedTimeOff - ( curTime - AggregatedLastTxDoneTime ); + nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime( AggregatedLastTxDoneTime ); } if( nbEnabledChannels > 0 ) @@ -1722,11 +1847,11 @@ if( RepeaterSupport == true ) { - Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] ); + Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); } else { - Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] ); + Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); } if( rxContinuous == false ) @@ -1766,6 +1891,20 @@ return false; } +static uint8_t CountBits( uint16_t mask, uint8_t nbBits ) +{ + uint8_t nbActiveBits = 0; + + for( uint8_t j = 0; j < nbBits; j++ ) + { + if( ( mask & ( 1 << j ) ) == ( 1 << j ) ) + { + nbActiveBits++; + } + } + return nbActiveBits; +} + #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ) { @@ -1773,17 +1912,75 @@ for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ ) { - for( uint8_t j = 0; j < 16; j++ ) - {// Verify if the channel is active - if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) ) - { - nb125kHzChannels++; - } - } + nb125kHzChannels += CountBits( channelsMask[k], 16 ); } return nb125kHzChannels; } + +#if defined( USE_BAND_915_HYBRID ) +static void ReenableChannels( uint16_t mask, uint16_t* channelMask ) +{ + uint16_t blockMask = mask; + + for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 ) + { + channelMask[i] = 0; + if( ( blockMask & ( 1 << j ) ) != 0 ) + { + channelMask[i] |= 0x00FF; + } + if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 ) + { + channelMask[i] |= 0xFF00; + } + } + channelMask[4] = blockMask; + channelMask[5] = 0x0000; +} + +static bool ValidateChannelMask( uint16_t* channelMask ) +{ + bool chanMaskState = false; + uint16_t block1 = 0; + uint16_t block2 = 0; + uint8_t index = 0; + + for( uint8_t i = 0; i < 4; i++ ) + { + block1 = channelMask[i] & 0x00FF; + block2 = channelMask[i] & 0xFF00; + + if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) ) + { + channelMask[i] &= block1; + channelMask[4] = 1 << ( i * 2 ); + chanMaskState = true; + index = i; + } + else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) ) + { + channelMask[i] &= block2; + channelMask[4] = 1 << ( i * 2 + 1 ); + chanMaskState = true; + index = i; + } + } + + // Do only change the channel mask, if we have found a valid block. + if( chanMaskState == true ) + { + for( uint8_t i = 0; i < 4; i++ ) + { + if( i != index ) + { + channelMask[i] = 0; + } + } + } + return chanMaskState; +} +#endif #endif static int8_t LimitTxPower( int8_t txPower ) @@ -1838,7 +2035,7 @@ if( adrEnabled == true ) { - if( datarate == LORAMAC_MIN_DATARATE ) + if( datarate == LORAMAC_TX_MIN_DATARATE ) { AdrAckCounter = 0; adrAckReq = false; @@ -1858,11 +2055,11 @@ if( ( ( AdrAckCounter - ADR_ACK_DELAY ) % ADR_ACK_LIMIT ) == 0 ) { #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - if( datarate > LORAMAC_MIN_DATARATE ) + if( datarate > LORAMAC_TX_MIN_DATARATE ) { datarate--; } - if( datarate == LORAMAC_MIN_DATARATE ) + if( datarate == LORAMAC_TX_MIN_DATARATE ) { if( updateChannelMask == true ) { @@ -1872,15 +2069,15 @@ } } #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( ( datarate > LORAMAC_MIN_DATARATE ) && ( datarate == DR_8 ) ) + if( ( datarate > LORAMAC_TX_MIN_DATARATE ) && ( datarate == DR_8 ) ) { datarate = DR_4; } - else if( datarate > LORAMAC_MIN_DATARATE ) + else if( datarate > LORAMAC_TX_MIN_DATARATE ) { datarate--; } - if( datarate == LORAMAC_MIN_DATARATE ) + if( datarate == LORAMAC_TX_MIN_DATARATE ) { if( updateChannelMask == true ) { @@ -1894,12 +2091,7 @@ ChannelsMask[5] = 0x0000; #else // defined( USE_BAND_915_HYBRID ) // Re-enable default channels - ChannelsMask[0] = 0x00FF; - ChannelsMask[1] = 0x0000; - ChannelsMask[2] = 0x0000; - ChannelsMask[3] = 0x0000; - ChannelsMask[4] = 0x0001; - ChannelsMask[5] = 0x0000; + ReenableChannels( ChannelsMask[4], ChannelsMask ); #endif } } @@ -2124,11 +2316,18 @@ { status &= 0xFE; // Channel mask KO } + +#if defined( USE_BAND_915_HYBRID ) + if( ValidateChannelMask( channelsMask ) == false ) + { + status &= 0xFE; // Channel mask KO + } +#endif } #else #error "Please define a frequency band in the compiler options." #endif - if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false ) + if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false ) { status &= 0xFD; // Datarate KO } @@ -2144,21 +2343,14 @@ { ChannelsDatarate = datarate; ChannelsTxPower = txPower; -#if defined( USE_BAND_915_HYBRID ) - ChannelsMask[0] = channelsMask[0] & 0x00FF; - ChannelsMask[1] = channelsMask[1] & 0x0000; - ChannelsMask[2] = channelsMask[2] & 0x0000; - ChannelsMask[3] = channelsMask[3] & 0x0000; - ChannelsMask[4] = channelsMask[4] & 0x0001; - ChannelsMask[5] = channelsMask[5] & 0x0000; -#else + ChannelsMask[0] = channelsMask[0]; ChannelsMask[1] = channelsMask[1]; ChannelsMask[2] = channelsMask[2]; ChannelsMask[3] = channelsMask[3]; ChannelsMask[4] = channelsMask[4]; ChannelsMask[5] = channelsMask[5]; -#endif + ChannelsNbRep = nbRep; } AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 ); @@ -2190,7 +2382,7 @@ status &= 0xFE; // Channel frequency KO } - if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false ) + if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false ) { status &= 0xFD; // Datarate KO } @@ -2358,6 +2550,8 @@ AggregatedTimeOff = 0; } + CalculateBackOff( LastTxChannel ); + // Select channel while( SetNextChannel( &dutyCycleTimeOff ) == false ) { @@ -2387,6 +2581,30 @@ } } +static void CalculateBackOff( uint8_t channel ) +{ + uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle; + + if( IsLoRaMacNetworkJoined == false ) + { +#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) + dutyCycle = JOIN_DC; +#endif + } + + // Update Band Time OFF + if( DutyCycleOn == true ) + { + Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; + } + else + { + Bands[Channels[channel].Band].TimeOff = 0; + } + // Update Aggregated Time OFF + AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir ); +} + LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) { uint16_t i; @@ -2537,15 +2755,16 @@ LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ) { int8_t datarate = Datarates[ChannelsDatarate]; + int8_t txPowerIndex = 0; int8_t txPower = 0; - ChannelsTxPower = LimitTxPower( ChannelsTxPower ); - txPower = TxPowers[ChannelsTxPower]; + txPowerIndex = LimitTxPower( ChannelsTxPower ); + txPower = TxPowers[txPowerIndex]; MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; McpsConfirm.Datarate = ChannelsDatarate; - McpsConfirm.TxPower = ChannelsTxPower; + McpsConfirm.TxPower = txPowerIndex; Radio.SetChannel( channel.Frequency ); @@ -2876,6 +3095,11 @@ mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2; break; } + case MIB_CHANNELS_DEFAULT_DATARATE: + { + mibGet->Param.ChannelsDefaultDatarate = ChannelsDefaultDatarate; + break; + } case MIB_CHANNELS_DATARATE: { mibGet->Param.ChannelsDatarate = ChannelsDatarate; @@ -3015,19 +3239,32 @@ if( mibSet->Param.ChannelsMask ) { #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) && - ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) + bool chanMaskState = true; + +#if defined( USE_BAND_915_HYBRID ) + chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask ); +#endif + if( chanMaskState == true ) { - status = LORAMAC_STATUS_PARAMETER_INVALID; + if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) && + ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + else + { + memcpy1( ( uint8_t* ) ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) ); + for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ ) + { + // Disable channels which are no longer available + ChannelsMaskRemaining[i] &= ChannelsMask[i]; + } + } } else { - memcpy1( ( uint8_t* ) ChannelsMask, - ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) ); - for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ ) - { - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } + status = LORAMAC_STATUS_PARAMETER_INVALID; } #else memcpy1( ( uint8_t* ) ChannelsMask, @@ -3078,10 +3315,23 @@ JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2; break; } + case MIB_CHANNELS_DEFAULT_DATARATE: + { + if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, + LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) + { + ChannelsDefaultDatarate = mibSet->Param.ChannelsDefaultDatarate; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } case MIB_CHANNELS_DATARATE: { if( ValueInRange( mibSet->Param.ChannelsDatarate, - LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) ) + LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) { ChannelsDatarate = mibSet->Param.ChannelsDatarate; } @@ -3116,6 +3366,16 @@ } break; } + case MIB_UPLINK_COUNTER: + { + UpLinkCounter = mibSet->Param.UpLinkCounter; + break; + } + case MIB_DOWNLINK_COUNTER: + { + DownLinkCounter = mibSet->Param.DownLinkCounter; + break; + } default: status = LORAMAC_STATUS_SERVICE_UNKNOWN; break; @@ -3148,10 +3408,10 @@ } // Validate the datarate if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) || - ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_MIN_DATARATE, - LORAMAC_MAX_DATARATE ) == false ) || - ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_MIN_DATARATE, - LORAMAC_MAX_DATARATE ) == false ) ) + ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE ) == false ) || + ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE ) == false ) ) { datarateInvalid = true; } @@ -3164,11 +3424,11 @@ frequencyInvalid = true; } - if( params.DrRange.Fields.Min > LORAMAC_DEFAULT_DATARATE ) + if( params.DrRange.Fields.Min > ChannelsDefaultDatarate ) { datarateInvalid = true; } - if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_MAX_DATARATE ) == false ) + if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE ) == false ) { datarateInvalid = true; } @@ -3243,7 +3503,7 @@ } } - if( id < 3 ) + if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) ) { return LORAMAC_STATUS_PARAMETER_INVALID; } @@ -3251,7 +3511,7 @@ { // Remove the channel from the list of channels Channels[id] = ( ChannelParams_t ){ 0, { 0 }, 0 }; - + // Disable the channel as it doesn't exist anymore if( DisableChannelInMask( id, ChannelsMask ) == false ) { @@ -3501,7 +3761,7 @@ { if( AdrCtrlOn == false ) { - if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == true ) + if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true ) { ChannelsDatarate = datarate; }
--- a/LoRaMac.h Mon Mar 14 09:09:54 2016 +0000 +++ b/LoRaMac.h Fri May 13 14:51:50 2016 +0000 @@ -480,6 +480,9 @@ * Byte-access to the bits */ uint8_t Value; + /*! + * Structure containing single access to bits + */ struct sCtrlBits { /*! @@ -541,6 +544,10 @@ */ LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, /*! + * The node has lost MAX_FCNT_GAP or more frames. + */ + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS, + /*! * An address error occured */ LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, @@ -559,6 +566,9 @@ * Byte-access to the bits */ uint8_t Value; + /*! + * Structure containing single access to bits + */ struct sMacFlagBits { /*! @@ -910,7 +920,7 @@ }MlmeReqJoin_t; /*! - * + * LoRaMAC MLME-Request structure */ typedef struct sMlmeReq { @@ -985,9 +995,10 @@ * \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_DEFAULT_DATARATE| YES | YES * \ref MIB_CHANNELS_TX_POWER | YES | YES - * \ref MIB_UPLINK_COUNTER | YES | NO - * \ref MIB_DOWNLINK_COUNTER | YES | NO + * \ref MIB_UPLINK_COUNTER | YES | YES + * \ref MIB_DOWNLINK_COUNTER | YES | YES * \ref MIB_MULTICAST_CHANNEL | YES | NO * * The following table provides links to the function implementations of the @@ -1117,6 +1128,16 @@ */ MIB_JOIN_ACCEPT_DELAY_2, /*! + * Default 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_DEFAULT_DATARATE, + /*! * Data rate of a channel * * LoRaWAN Specification V1.0, chapter 7 @@ -1276,6 +1297,12 @@ /*! * Channels data rate * + * Related MIB type: \ref MIB_CHANNELS_DEFAULT_DATARATE + */ + int8_t ChannelsDefaultDatarate; + /*! + * Channels data rate + * * Related MIB type: \ref MIB_CHANNELS_DATARATE */ int8_t ChannelsDatarate;