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