Fork of Semtech LoRaWAN stack
Fork of LoRaWAN-lib by
Diff: LoRaMac.cpp
- Branch:
- SenetNetTool
- Revision:
- 49:8b9e6442a02a
- Parent:
- 31:930f949fdd9e
diff -r fc9baa35ae1a -r 8b9e6442a02a LoRaMac.cpp --- a/LoRaMac.cpp Tue Aug 08 11:21:18 2017 -0400 +++ b/LoRaMac.cpp Mon Oct 15 09:15:20 2018 -0400 @@ -15,7 +15,8 @@ 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 +Jäckle ( STACKFORCE ) */ #include "board.h" @@ -26,19 +27,20 @@ /*! * Maximum PHY layer payload size */ -#define LORAMAC_PHY_MAXPAYLOAD 255 +#define LORAMAC_PHY_MAXPAYLOAD 255 /*! * Maximum MAC commands buffer size */ -#define LORA_MAC_COMMAND_MAX_LENGTH 15 +#define LORA_MAC_COMMAND_MAX_LENGTH 15 /*! * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength * in RxWindowSetup function. - * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD + * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + + * LORA_MAC_FRMPAYLOAD_OVERHEAD */ -#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) +#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) /*! * Minimum number of available channels in Frequency Hopping Mode @@ -50,39 +52,32 @@ */ #define HYBRD_CHNLS_MIN 4 - /*! * Device IEEE EUI */ -static uint8_t *LoRaMacDevEui; +static uint8_t* LoRaMacDevEui; /*! * Application IEEE EUI */ -static uint8_t *LoRaMacAppEui; +static uint8_t* LoRaMacAppEui; /*! * AES encryption/decryption cipher application key */ -static uint8_t *LoRaMacAppKey; +static uint8_t* LoRaMacAppKey; /*! * AES encryption/decryption cipher network session key */ -static uint8_t LoRaMacNwkSKey[] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; +static uint8_t LoRaMacNwkSKey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*! * AES encryption/decryption cipher application session key */ -static uint8_t LoRaMacAppSKey[] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; +static uint8_t LoRaMacAppSKey[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; /*! * Device nonce is a random value extracted by issuing a sequence of RSSI @@ -103,7 +98,7 @@ /*! * Multicast channels linked list */ -static MulticastParams_t *MulticastChannels = NULL; +static MulticastParams_t* MulticastChannels = NULL; /*! * Actual device class @@ -140,13 +135,14 @@ * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. * Only the 16 LSB bits are sent */ -static uint32_t UpLinkCounter = 1; +uint32_t UpLinkCounter = 1; /*! - * LoRaMAC frame counter. Each time a packet is received the counter is incremented. + * LoRaMAC frame counter. Each time a packet is received the counter is + * incremented. * Only the 16 LSB bits are received */ -static uint32_t DownLinkCounter = 0; +uint32_t DownLinkCounter = 0; /*! * IsPacketCounterFixed enables the MIC field tests by fixing the @@ -181,7 +177,8 @@ static bool NodeAckRequested = false; /*! - * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates + * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable + * indicates * if the ACK bit must be set for the next transmission */ static bool SrvAckRequested = false; @@ -211,174 +208,159 @@ */ static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH]; -#if defined( USE_BAND_433 ) +#if defined(USE_BAND_433) /*! * Data rates table definition */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; +const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50}; /*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. + * Maximum payload with respect to the datarate index. Cannot operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; +const uint8_t MaxPayloadOfDatarate[] = {59, 59, 59, 123, 250, 250, 250, 250}; /*! - * Maximum payload with respect to the datarate index. Can operate with repeater. + * Maximum payload with respect to the datarate index. Can operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarateRepeater[] = { 59, 59, 59, 123, 230, 230, 230, 230 }; +const uint8_t MaxPayloadOfDatarateRepeater[] = {59, 59, 59, 123, 230, 230, 230, 230}; /*! * Tx output powers table definition */ -const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; +const int8_t TxPowers[] = {20, 14, 11, 8, 5, 2}; /*! * LoRaMac bands */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, +static Band_t Bands[LORA_MAX_NB_BANDS] = { + BAND0, }; /*! * LoRaMAC channels */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = -{ - LC1, - LC2, - LC3, +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = { + LC1, LC2, LC3, }; -#elif defined( USE_BAND_780 ) +#elif defined(USE_BAND_780) /*! * Data rates table definition */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; +const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50}; /*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. + * Maximum payload with respect to the datarate index. Cannot operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; +const uint8_t MaxPayloadOfDatarate[] = {59, 59, 59, 123, 250, 250, 250, 250}; /*! - * Maximum payload with respect to the datarate index. Can operate with repeater. + * Maximum payload with respect to the datarate index. Can operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarateRepeater[] = { 59, 59, 59, 123, 230, 230, 230, 230 }; +const uint8_t MaxPayloadOfDatarateRepeater[] = {59, 59, 59, 123, 230, 230, 230, 230}; /*! * Tx output powers table definition */ -const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; +const int8_t TxPowers[] = {20, 14, 11, 8, 5, 2}; /*! * LoRaMac bands */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, +static Band_t Bands[LORA_MAX_NB_BANDS] = { + BAND0, }; /*! * LoRaMAC channels */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = -{ - LC1, - LC2, - LC3, +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = { + LC1, LC2, LC3, }; -#elif defined( USE_BAND_868 ) +#elif defined(USE_BAND_868) /*! * Data rates table definition */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; +const uint8_t Datarates[] = {12, 11, 10, 9, 8, 7, 7, 50}; /*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. + * Maximum payload with respect to the datarate index. Cannot operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; +const uint8_t MaxPayloadOfDatarate[] = {51, 51, 51, 115, 242, 242, 242, 242}; /*! - * Maximum payload with respect to the datarate index. Can operate with repeater. + * Maximum payload with respect to the datarate index. Can operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; +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 }; +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, +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, +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = { + LC1, LC2, LC3, }; -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +#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 }; +const uint8_t Datarates[] = {10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0}; /*! * Up/Down link data rates offset definition */ -const uint8_t datarateOffsets[16][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 - { 0xFF , 0xFF , 0xFF , 0xFF }, - { 0xFF , 0xFF , 0xFF , 0xFF }, - { 0xFF , 0xFF , 0xFF , 0xFF }, - { DR_8 , DR_8 , DR_8 , DR_8 }, - { DR_9 , DR_8 , DR_8 , DR_8 }, - { DR_10, DR_9 , DR_8 , DR_8 }, - { DR_11, DR_10, DR_9 , DR_8 }, - { DR_12, DR_11, DR_10, DR_9 }, - { DR_13, DR_12, DR_11, DR_10 }, - { 0xFF , 0xFF , 0xFF , 0xFF }, - { 0xFF , 0xFF , 0xFF , 0xFF }, +const uint8_t datarateOffsets[16][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 + {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, + {DR_8, DR_8, DR_8, DR_8}, {DR_9, DR_8, DR_8, DR_8}, {DR_10, DR_9, DR_8, DR_8}, + {DR_11, DR_10, DR_9, DR_8}, {DR_12, DR_11, DR_10, DR_9}, {DR_13, DR_12, DR_11, DR_10}, + {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, }; /*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. + * Maximum payload with respect to the datarate index. Cannot operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 11, 53, 126, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; +const uint8_t MaxPayloadOfDatarate[] = {11, 53, 126, 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. + * Maximum payload with respect to the datarate index. Can operate with + * repeater. */ -const uint8_t MaxPayloadOfDatarateRepeater[] = { 11, 53, 126, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; +const uint8_t MaxPayloadOfDatarateRepeater[] = {11, 53, 126, 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 }; +const int8_t TxPowers[] = {30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2}; /*! * LoRaMac bands */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, +static Band_t Bands[LORA_MAX_NB_BANDS] = { + BAND0, }; /*! @@ -391,33 +373,34 @@ */ static uint16_t ChannelsMaskRemaining[6]; -#if defined( USE_BAND_915 ) +#if defined(USE_BAND_915) /*! - * Last join request sub-band + * Last join request sub-band */ static int8_t LastJoinBlock; /*! * Next join sub-band block */ -static uint8_t NextJoinBlock; +static uint8_t NextJoinBlock; + +/*! + * Mask of 125 KHz sub-bands not used for join transmit + */ +static uint8_t JoinBlocksRemaining; /*! - * Mask of 125 KHz sub-bands not used for join transmit + * Mask of 500 KHz sub-bands not used for join transmit */ -static uint8_t JoinBlocksRemaining; - -/*! - * Mask of 500 KHz sub-bands not used for join transmit - */ -static uint8_t Join500KHzRemaining; +static uint8_t Join500KHzRemaining; #ifndef JOIN_BLOCK_ORDER -#define JOIN_BLOCK_ORDER { -1, -1, -1, -1, -1, -1, -1, -1 } +#define JOIN_BLOCK_ORDER \ + { -1, -1, -1, -1, -1, -1, -1, -1 } #endif /*! - * join sub-band block order + * join sub-band block order */ static int8_t JoinBlock[8] = JOIN_BLOCK_ORDER; @@ -426,21 +409,20 @@ /*! * Defines the first channel for RX window 2 for US band */ -#define LORAMAC_FIRST_RX2_CHANNEL ( (uint32_t) 923.3e6 ) +#define LORAMAC_FIRST_RX2_CHANNEL ((uint32_t)923.3e6) /*! * Defines the last channel for RX window 2 for US band */ -#define LORAMAC_LAST_RX2_CHANNEL ( (uint32_t) 927.5e6 ) +#define LORAMAC_LAST_RX2_CHANNEL ((uint32_t)927.5e6) /*! * Defines the step width of the channels for RX window 2 */ -#define LORAMAC_STEPWIDTH_RX2_CHANNEL ( (uint32_t) 600e3 ) - +#define LORAMAC_STEPWIDTH_RX2_CHANNEL ((uint32_t)600e3) #else - #error "Please define a frequency band in the compiler options." +#error "Please define a frequency band in the compiler options." #endif /*! @@ -492,7 +474,7 @@ /*! * Aggregated duty cycle management */ -static uint16_t AggregatedDCycle; +static uint16_t AggregatedDCycle; static TimerTime_t AggregatedLastTxDoneTime; static TimerTime_t AggregatedTimeOff; @@ -511,16 +493,15 @@ /*! * LoRaMac internal states */ -enum eLoRaMacState -{ - MAC_IDLE = 0x00000000, - MAC_TX_RUNNING = 0x00000001, - MAC_RX = 0x00000002, - MAC_ACK_REQ = 0x00000004, - MAC_ACK_RETRY = 0x00000008, - MAC_TX_DELAYED = 0x00000010, - MAC_TX_CONFIG = 0x00000020, - MAC_RX_ABORT = 0x00000040, +enum eLoRaMacState { + MAC_IDLE = 0x00000000, + MAC_TX_RUNNING = 0x00000001, + MAC_RX = 0x00000002, + MAC_ACK_REQ = 0x00000004, + MAC_ACK_RETRY = 0x00000008, + MAC_TX_DELAYED = 0x00000010, + MAC_TX_CONFIG = 0x00000020, + MAC_RX_ABORT = 0x00000040, }; /*! @@ -536,12 +517,12 @@ /*! * LoRaMac upper layer event functions */ -static LoRaMacPrimitives_t *LoRaMacPrimitives; +static LoRaMacPrimitives_t* LoRaMacPrimitives; /*! * LoRaMac upper layer callback functions */ -static LoRaMacCallback_t *LoRaMacCallbacks; +static LoRaMacCallback_t* LoRaMacCallbacks; /*! * Radio events function pointer @@ -633,12 +614,8 @@ /*! * Join Retransmission back-off configuration */ -LoRaMacRetransmissionDCycle_t JoinReTransmitDCycle[JOIN_NB_RETRANSMISSION_DCYCLES] = -{ - JOIN_RETRANSMISSION_DCYCLE1, - JOIN_RETRANSMISSION_DCYCLE2, - JOIN_RETRANSMISSION_DCYCLE3 -}; +LoRaMacRetransmissionDCycle_t JoinReTransmitDCycle[JOIN_NB_RETRANSMISSION_DCYCLES] = { + JOIN_RETRANSMISSION_DCYCLE1, JOIN_RETRANSMISSION_DCYCLE2, JOIN_RETRANSMISSION_DCYCLE3}; /*! * Uptime of the last sent join request @@ -646,66 +623,65 @@ static TimerTime_t LastJoinTxTime; /*! - * Aggregated join request time on air + * Aggregated join request time on air */ -static TimerTime_t JoinAggTimeOnAir; - +static TimerTime_t JoinAggTimeOnAir; /*! * \brief Function to be executed on Radio Tx Done event */ -static void OnRadioTxDone( void ); +static void OnRadioTxDone(void); /*! * \brief This function prepares the MAC to abort the execution of function * OnRadioRxDone in case of a reception error. */ -static void PrepareRxDoneAbort( void ); +static void PrepareRxDoneAbort(void); /*! * \brief Function to be executed on Radio Rx Done event */ -static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); +static void OnRadioRxDone(uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr); /*! * \brief Function executed on Radio Tx Timeout event */ -static void OnRadioTxTimeout( void ); +static void OnRadioTxTimeout(void); /*! * \brief Function executed on Radio Rx error event */ -static void OnRadioRxError( void ); +static void OnRadioRxError(void); /*! * \brief Function executed on Radio Rx Timeout event */ -static void OnRadioRxTimeout( void ); +static void OnRadioRxTimeout(void); /*! * \brief Function executed on Resend Frame timer event. */ -static void OnMacStateCheckTimerEvent( void ); +static void OnMacStateCheckTimerEvent(void); /*! * \brief Function executed on duty cycle delayed Tx timer event */ -static void OnTxDelayedTimerEvent( void ); +static void OnTxDelayedTimerEvent(void); /*! * \brief Function executed on first Rx window timer event */ -static void OnRxWindow1TimerEvent( void ); +static void OnRxWindow1TimerEvent(void); /*! * \brief Function executed on second Rx window timer event */ -static void OnRxWindow2TimerEvent( void ); +static void OnRxWindow2TimerEvent(void); /*! * \brief Function executed on AckTimeout timer event */ -static void OnAckTimeoutTimerEvent( void ); +static void OnAckTimeoutTimerEvent(void); /*! * \brief Searches and set the next random available channel @@ -716,14 +692,14 @@ * \retval status Function status [1: OK, 0: Unable to find a channel on the * current datarate] */ -static bool SetNextChannel( TimerTime_t* time ); +static bool SetNextChannel(TimerTime_t* time); /*! * \brief Sets the network to public or private. Updates the sync byte. * * \param [IN] enable if true, it enables a public network */ -static void SetPublicNetwork( bool enable ); +static void SetPublicNetwork(bool enable); /*! * \brief Initializes and opens the reception window @@ -733,7 +709,8 @@ * \param [IN] bandwidth window channel bandwidth * \param [IN] timeout window channel timeout */ -static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ); +static void RxWindowSetup(uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, + bool rxContinuous); /*! * \brief Verifies if the RX window 2 frequency is in range @@ -742,8 +719,7 @@ * * \retval status Function status [1: OK, 0: Frequency not applicable] */ -static bool Rx2FreqInRange( uint32_t freq ); - +static bool Rx2FreqInRange(uint32_t freq); /*! * \brief Adds a new MAC command to be sent. @@ -762,7 +738,7 @@ * * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full] */ -static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 ); +static LoRaMacStatus_t AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2); /*! * \brief Parses the MAC commands which must be repeated. @@ -776,7 +752,7 @@ * * \retval Size of the MAC commands to repeat. */ -static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut ); +static uint8_t ParseMacCommandsToRepeat(uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut); /*! * \brief Validates if the payload fits into the frame, taking the datarate @@ -794,7 +770,7 @@ * \retval [false: payload does not fit into the frame, true: payload fits into * the frame] */ -static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ); +static bool ValidatePayloadLength(uint8_t lenN, int8_t datarate, uint8_t fOptsLen); /*! * \brief Counts the number of bits in a mask. @@ -804,9 +780,9 @@ * * \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 ) +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. @@ -815,16 +791,16 @@ * * \retval Number of enabled channels in the channel mask */ -static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ); - -#if defined( USE_BAND_915_HYBRID ) +static uint8_t CountNbEnabled125kHzChannels(uint16_t* channelsMask); + +#if defined(USE_BAND_915_HYBRID) /*! * \brief Validates the correctness of the channel mask for US915, hybrid mode. * * \param [IN] mask Block definition to set. * \param [OUT] channelsMask Pointer to the first element of the channel mask */ -static void ReenableChannels( uint16_t mask, uint16_t* channelMask ); +static void ReenableChannels(uint16_t mask, uint16_t* channelMask); /*! * \brief Validates the correctness of the channel mask for US915, hybrid mode. @@ -833,7 +809,7 @@ * * \retval [true: channel mask correct, false: channel mask not correct] */ -static bool ValidateChannelMask( uint16_t* channelMask ); +static bool ValidateChannelMask(uint16_t* channelMask); #endif #endif @@ -843,7 +819,7 @@ * * \retval Returns the maximum valid tx power */ -static int8_t LimitTxPower( int8_t txPower ); +static int8_t LimitTxPower(int8_t txPower); /*! * \brief Verifies, if a value is in a given range. @@ -856,7 +832,7 @@ * * \retval Returns the maximum valid tx power */ -static bool ValueInRange( int8_t value, int8_t min, int8_t max ); +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 @@ -871,7 +847,7 @@ * * \retval Returns the state of ADR ack request */ -static bool AdrNextDr( bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut ); +static bool AdrNextDr(bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut); /*! * \brief Disables channel in a specified channel mask @@ -882,12 +858,13 @@ * * \retval [true, if disable was successful, false if not] */ -static bool DisableChannelInMask( uint8_t id, uint16_t* mask ); +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 ); +static void ProcessMacCommands(uint8_t* payload, uint8_t macIndex, uint8_t commandsSize, + uint8_t snr); /*! * \brief LoRaMAC layer generic send frame @@ -898,7 +875,7 @@ * \param [IN] fBufferSize MAC data buffer size * \retval status Status of the operation. */ -LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); +LoRaMacStatus_t Send(LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize); /*! * \brief LoRaMAC layer frame buffer initialization @@ -911,24 +888,26 @@ * \param [IN] fBufferSize MAC data buffer size * \retval status Status of the operation. */ -LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); +LoRaMacStatus_t PrepareFrame(LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, + void* fBuffer, uint16_t fBufferSize); /* * \brief Schedules the frame according to the duty cycle * * \retval Status of the operation */ -static LoRaMacStatus_t ScheduleTx( void ); +static LoRaMacStatus_t ScheduleTx(void); /* * \brief Calculates the back-off time for the band of a channel. * * \param [IN] channel The last Tx channel index */ -static void CalculateBackOff( uint8_t channel ); +static void CalculateBackOff(uint8_t channel); /*! - * \brief LoRaMAC layer prepared frame buffer transmission with channel specification + * \brief LoRaMAC layer prepared frame buffer transmission with channel + * specification * * \remark PrepareFrame must be called at least once before calling this * function. @@ -936,3124 +915,2673 @@ * \param [IN] channel Channel parameters * \retval status Status of the operation. */ -LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ); - - - -static void OnRadioTxDone( void ) -{ - TimerTime_t curTime = TimerGetCurrentTime( ); - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); - } - else - { - OnRxWindow2TimerEvent( ); - } - - // Store last Tx channel - LastTxChannel = Channel; - // Update last tx done time for the current channel - Bands[Channels[LastTxChannel].Band].LastTxDoneTime = curTime; - // Update Aggregated last tx done time - AggregatedLastTxDoneTime = curTime; - - // Update join tx done and time on air - if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) ) - { - JoinAggTimeOnAir += TxTimeOnAir; - LastJoinTxTime = curTime; - } - - if( IsRxWindowsEnabled == true ) - { - TimerSetValue( &RxWindowTimer1, RxWindow1Delay ); - TimerStart( &RxWindowTimer1 ); - if( LoRaMacDeviceClass != CLASS_C ) - { - TimerSetValue( &RxWindowTimer2, RxWindow2Delay ); - TimerStart( &RxWindowTimer2 ); - } - if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) ) - { - TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT + - randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) ); - TimerStart( &AckTimeoutTimer ); - } - } - else - { - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - - if( LoRaMacFlags.Value == 0 ) - { - LoRaMacFlags.Bits.McpsReq = 1; - } - LoRaMacFlags.Bits.MacDone = 1; - } - - if( NodeAckRequested == false ) - { - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; - ChannelsNbRepCounter++; - } -} - -static void PrepareRxDoneAbort( void ) -{ - LoRaMacState |= MAC_RX_ABORT; - - if( NodeAckRequested ) - { - OnAckTimeoutTimerEvent( ); - } - - if( ( RxSlot == 0 ) && ( LoRaMacDeviceClass == CLASS_C ) ) - { - OnRxWindow2TimerEvent( ); - } - - LoRaMacFlags.Bits.McpsInd = 1; - LoRaMacFlags.Bits.MacDone = 1; - - // Trig OnMacCheckTimerEvent call as soon as possible - TimerSetValue( &MacStateCheckTimer, 1000 ); - TimerStart( &MacStateCheckTimer ); -} - -static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) -{ - LoRaMacHeader_t macHdr; - LoRaMacFrameCtrl_t fCtrl; - bool skipIndication = false; - - uint8_t pktHeaderLen = 0; - uint32_t address = 0; - uint8_t appPayloadStartIndex = 0; - uint8_t port = 0xFF; - uint8_t frameLen = 0; - uint32_t mic = 0; - uint32_t micRx = 0; - - uint16_t sequenceCounter = 0; - uint16_t sequenceCounterPrev = 0; - uint16_t sequenceCounterDiff = 0; - uint32_t downLinkCounter = 0; - - MulticastParams_t *curMulticastParams = NULL; - uint8_t *nwkSKey = LoRaMacNwkSKey; - uint8_t *appSKey = LoRaMacAppSKey; - - uint8_t multicast = 0; - - bool isMicOk = false; - - McpsConfirm.AckReceived = false; - McpsIndication.Rssi = rssi; - McpsIndication.Snr = snr; - McpsIndication.RxSlot = RxSlot; - McpsIndication.Port = 0; - McpsIndication.Multicast = 0; - McpsIndication.FramePending = 0; - McpsIndication.Buffer = NULL; - McpsIndication.BufferSize = 0; - McpsIndication.RxData = false; - McpsIndication.AckReceived = false; - McpsIndication.DownLinkCounter = 0; - McpsIndication.McpsIndication = MCPS_UNCONFIRMED; - - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); +LoRaMacStatus_t SendFrameOnChannel(ChannelParams_t channel); + +static void OnRadioTxDone(void) { + TimerTime_t curTime = TimerGetCurrentTime(); + if (LoRaMacDeviceClass != CLASS_C) { + Radio.Sleep(); + } + else { + OnRxWindow2TimerEvent(); + } + + // Store last Tx channel + LastTxChannel = Channel; + // Update last tx done time for the current channel + Bands[Channels[LastTxChannel].Band].LastTxDoneTime = curTime; + // Update Aggregated last tx done time + AggregatedLastTxDoneTime = curTime; + + // Update join tx done and time on air + if ((LoRaMacFlags.Bits.MlmeReq == 1) && (MlmeConfirm.MlmeRequest == MLME_JOIN)) { + JoinAggTimeOnAir += TxTimeOnAir; + LastJoinTxTime = curTime; + } + + if (IsRxWindowsEnabled == true) { + TimerSetValue(&RxWindowTimer1, RxWindow1Delay); + TimerStart(&RxWindowTimer1); + if (LoRaMacDeviceClass != CLASS_C) { + TimerSetValue(&RxWindowTimer2, RxWindow2Delay); + TimerStart(&RxWindowTimer2); } - TimerStop( &RxWindowTimer2 ); - - macHdr.Value = payload[pktHeaderLen++]; - - switch( macHdr.Bits.MType ) - { - case FRAME_TYPE_JOIN_ACCEPT: - if( IsLoRaMacNetworkJoined == true ) - { - break; - } - LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 ); - - LoRaMacRxPayload[0] = macHdr.Value; - - LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic ); - - micRx |= ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN]; - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 ); - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 ); - micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 ); - - if( micRx == mic ) - { - LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey ); - - LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4]; - LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 ); - LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 ); - - LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7]; - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 ); - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 ); - LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 ); - - // DLSettings - Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07; - Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F; - // RxDelay - ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F ); - if( ReceiveDelay1 == 0 ) - { - ReceiveDelay1 = 1; - } - ReceiveDelay1 *= 1e6; - ReceiveDelay2 = ReceiveDelay1 + 1e6; - -#if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - //CFList - if( ( size - 1 ) > 16 ) - { - ChannelParams_t param; - param.DrRange.Value = ( DR_5 << 4 ) | DR_0; - - LoRaMacState |= MAC_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; - LoRaMacChannelAdd( i, param ); - } - LoRaMacState &= ~MAC_TX_CONFIG; - } -#endif - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; - IsLoRaMacNetworkJoined = true; - - // Do not change the datarate - // ChannelsDatarate = ChannelsDefaultDatarate; - } - else - { - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; - } - break; - case FRAME_TYPE_DATA_CONFIRMED_DOWN: - case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: - { - address = payload[pktHeaderLen++]; - address |= ( (uint32_t)payload[pktHeaderLen++] << 8 ); - address |= ( (uint32_t)payload[pktHeaderLen++] << 16 ); - address |= ( (uint32_t)payload[pktHeaderLen++] << 24 ); - - if( address != LoRaMacDevAddr ) - { - curMulticastParams = MulticastChannels; - while( curMulticastParams != NULL ) - { - if( address == curMulticastParams->Address ) - { - multicast = 1; - nwkSKey = curMulticastParams->NwkSKey; - appSKey = curMulticastParams->AppSKey; - downLinkCounter = curMulticastParams->DownLinkCounter; - break; - } - curMulticastParams = curMulticastParams->Next; - } - if( multicast == 0 ) - { - // We are not the destination of this frame. - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; - PrepareRxDoneAbort( ); - return; - } - } - else - { - multicast = 0; - nwkSKey = LoRaMacNwkSKey; - appSKey = LoRaMacAppSKey; - downLinkCounter = DownLinkCounter; - } - - fCtrl.Value = payload[pktHeaderLen++]; - - sequenceCounter = ( uint16_t )payload[pktHeaderLen++]; - sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8; - - appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen; - - micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN]; - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 ); - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 ); - micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 ); - - sequenceCounterPrev = ( uint16_t )downLinkCounter; - sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev ); - - if( sequenceCounterDiff < ( 1 << 15 ) ) - { - downLinkCounter += sequenceCounterDiff; - LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic ); - if( micRx == mic ) - { - isMicOk = true; - } - } - else - { - // check for sequence roll-over - uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff; - LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic ); - if( micRx == mic ) - { - isMicOk = true; - downLinkCounter = downLinkCounterTmp; - } - } - - // Check for a the maximum allowed counter difference - if( sequenceCounterDiff >= MAX_FCNT_GAP ) - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; - McpsIndication.DownLinkCounter = downLinkCounter; - PrepareRxDoneAbort( ); - return; - } - - if( isMicOk == true ) - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; - McpsIndication.Multicast = multicast; - McpsIndication.FramePending = fCtrl.Bits.FPending; - McpsIndication.Buffer = NULL; - McpsIndication.BufferSize = 0; - McpsIndication.DownLinkCounter = downLinkCounter; - - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; - - MacCommandsBufferToRepeatIndex = 0; - - // Update 32 bits downlink counter - if( multicast == 1 ) - { - McpsIndication.McpsIndication = MCPS_MULTICAST; - - if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) && - ( curMulticastParams->DownLinkCounter != 0 ) ) - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - McpsIndication.DownLinkCounter = downLinkCounter; - PrepareRxDoneAbort( ); - return; - } - curMulticastParams->DownLinkCounter = downLinkCounter; - } - else - { - if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN ) - { - SrvAckRequested = true; - McpsIndication.McpsIndication = MCPS_CONFIRMED; - - if( ( DownLinkCounter == downLinkCounter ) && - ( DownLinkCounter != 0 ) ) - { - // Duplicated confirmed downlink. Skip indication. - skipIndication = true; - } - } - else - { - SrvAckRequested = false; - McpsIndication.McpsIndication = MCPS_UNCONFIRMED; - - if( ( DownLinkCounter == downLinkCounter ) && - ( DownLinkCounter != 0 ) ) - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; - McpsIndication.DownLinkCounter = downLinkCounter; - PrepareRxDoneAbort( ); - return; - } - } - DownLinkCounter = downLinkCounter; - } - - if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 ) - { - port = payload[appPayloadStartIndex++]; - frameLen = ( size - 4 ) - appPayloadStartIndex; - - McpsIndication.Port = port; - - if( port == 0 ) - { - if( fCtrl.Bits.FOptsLen == 0 ) - { - LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, - frameLen, - nwkSKey, - address, - DOWN_LINK, - downLinkCounter, - LoRaMacRxPayload ); - - // Decode frame payload MAC commands - ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr ); - } - else - { - skipIndication = true; - } - } - else - { - if( fCtrl.Bits.FOptsLen > 0 ) - { - // Decode Options field MAC commands. Omit the fPort. - ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr ); - } - - LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, - frameLen, - appSKey, - address, - DOWN_LINK, - downLinkCounter, - LoRaMacRxPayload ); - - if( skipIndication == false ) - { - McpsIndication.Buffer = LoRaMacRxPayload; - McpsIndication.BufferSize = frameLen; - McpsIndication.RxData = true; - } - } - } - else - { - if( fCtrl.Bits.FOptsLen > 0 ) - { - // Decode Options field MAC commands - ProcessMacCommands( payload, 8, appPayloadStartIndex, snr ); - } - } - - if( skipIndication == false ) - { - // Check if the frame is an acknowledgement - if( fCtrl.Bits.Ack == 1 ) - { - McpsConfirm.AckReceived = true; - McpsIndication.AckReceived = true; - - // Stop the AckTimeout timer as no more retransmissions - // are needed. - TimerStop( &AckTimeoutTimer ); - } - else - { - McpsConfirm.AckReceived = false; - - if( AckTimeoutRetriesCounter > AckTimeoutRetries ) - { - // Stop the AckTimeout timer as no more retransmissions - // are needed. - TimerStop( &AckTimeoutTimer ); - } - } - LoRaMacFlags.Bits.McpsInd = 1; - } - } - else - { - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; - - PrepareRxDoneAbort( ); - return; - } - } - break; - case FRAME_TYPE_PROPRIETARY: - { - memcpy1( LoRaMacRxPayload, &payload[pktHeaderLen], size ); - - McpsIndication.McpsIndication = MCPS_PROPRIETARY; - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; - McpsIndication.Buffer = LoRaMacRxPayload; - McpsIndication.BufferSize = size - pktHeaderLen; - - LoRaMacFlags.Bits.McpsInd = 1; - break; - } - default: - McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; - PrepareRxDoneAbort( ); - break; + if ((LoRaMacDeviceClass == CLASS_C) || (NodeAckRequested == true)) { + TimerSetValue(&AckTimeoutTimer, + RxWindow2Delay + ACK_TIMEOUT + randr(-ACK_TIMEOUT_RND, ACK_TIMEOUT_RND)); + TimerStart(&AckTimeoutTimer); } - - if( ( RxSlot == 0 ) && ( LoRaMacDeviceClass == CLASS_C ) ) - { - OnRxWindow2TimerEvent( ); + } + else { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + + if (LoRaMacFlags.Value == 0) { + LoRaMacFlags.Bits.McpsReq = 1; } LoRaMacFlags.Bits.MacDone = 1; - - // Trig OnMacCheckTimerEvent call as soon as possible - TimerSetValue( &MacStateCheckTimer, 1000 ); - TimerStart( &MacStateCheckTimer ); + } + + if (NodeAckRequested == false) { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + ChannelsNbRepCounter++; + } +} + +static void PrepareRxDoneAbort(void) { + LoRaMacState |= MAC_RX_ABORT; + + if (NodeAckRequested) { + OnAckTimeoutTimerEvent(); + } + + if ((RxSlot == 0) && (LoRaMacDeviceClass == CLASS_C)) { + OnRxWindow2TimerEvent(); + } + + LoRaMacFlags.Bits.McpsInd = 1; + LoRaMacFlags.Bits.MacDone = 1; + + // Trig OnMacCheckTimerEvent call as soon as possible + TimerSetValue(&MacStateCheckTimer, 1000); + TimerStart(&MacStateCheckTimer); } -static void OnRadioTxTimeout( void ) -{ - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); +static void OnRadioRxDone(uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr) { + LoRaMacHeader_t macHdr; + LoRaMacFrameCtrl_t fCtrl; + bool skipIndication = false; + + uint8_t pktHeaderLen = 0; + uint32_t address = 0; + uint8_t appPayloadStartIndex = 0; + uint8_t port = 0xFF; + uint8_t frameLen = 0; + uint32_t mic = 0; + uint32_t micRx = 0; + + uint16_t sequenceCounter = 0; + uint16_t sequenceCounterPrev = 0; + uint16_t sequenceCounterDiff = 0; + uint32_t downLinkCounter = 0; + + MulticastParams_t* curMulticastParams = NULL; + uint8_t* nwkSKey = LoRaMacNwkSKey; + uint8_t* appSKey = LoRaMacAppSKey; + + uint8_t multicast = 0; + + bool isMicOk = false; + + McpsConfirm.AckReceived = false; + McpsIndication.Rssi = rssi; + McpsIndication.Snr = snr; + McpsIndication.RxSlot = RxSlot; + McpsIndication.Port = 0; + McpsIndication.Multicast = 0; + McpsIndication.FramePending = 0; + McpsIndication.Buffer = NULL; + McpsIndication.BufferSize = 0; + McpsIndication.RxData = false; + McpsIndication.AckReceived = false; + McpsIndication.DownLinkCounter = 0; + McpsIndication.McpsIndication = MCPS_UNCONFIRMED; + + if (LoRaMacDeviceClass != CLASS_C) { + Radio.Sleep(); + } + TimerStop(&RxWindowTimer2); + + macHdr.Value = payload[pktHeaderLen++]; + + switch (macHdr.Bits.MType) { + case FRAME_TYPE_JOIN_ACCEPT: + if (IsLoRaMacNetworkJoined == true) { + break; + } + LoRaMacJoinDecrypt(payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1); + + LoRaMacRxPayload[0] = macHdr.Value; + + LoRaMacJoinComputeMic(LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic); + + micRx |= (uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN]; + micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8); + micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16); + micRx |= ((uint32_t)LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24); + + if (micRx == mic) { + LoRaMacJoinComputeSKeys(LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, + LoRaMacNwkSKey, LoRaMacAppSKey); + + LoRaMacNetID = (uint32_t)LoRaMacRxPayload[4]; + LoRaMacNetID |= ((uint32_t)LoRaMacRxPayload[5] << 8); + LoRaMacNetID |= ((uint32_t)LoRaMacRxPayload[6] << 16); + + LoRaMacDevAddr = (uint32_t)LoRaMacRxPayload[7]; + LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[8] << 8); + LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[9] << 16); + LoRaMacDevAddr |= ((uint32_t)LoRaMacRxPayload[10] << 24); + + // DLSettings + Rx1DrOffset = (LoRaMacRxPayload[11] >> 4) & 0x07; + Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F; + // RxDelay + ReceiveDelay1 = (LoRaMacRxPayload[12] & 0x0F); + if (ReceiveDelay1 == 0) { + ReceiveDelay1 = 1; + } + ReceiveDelay1 *= 1e6; + ReceiveDelay2 = ReceiveDelay1 + 1e6; + +#if !(defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)) + // CFList + if ((size - 1) > 16) { + ChannelParams_t param; + param.DrRange.Value = (DR_5 << 4) | DR_0; + + LoRaMacState |= MAC_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; + LoRaMacChannelAdd(i, param); + } + LoRaMacState &= ~MAC_TX_CONFIG; + } +#endif + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + IsLoRaMacNetworkJoined = true; + + // Do not change the datarate + // ChannelsDatarate = ChannelsDefaultDatarate; + } + else { + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; + } + break; + case FRAME_TYPE_DATA_CONFIRMED_DOWN: + case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: { + address = payload[pktHeaderLen++]; + address |= ((uint32_t)payload[pktHeaderLen++] << 8); + address |= ((uint32_t)payload[pktHeaderLen++] << 16); + address |= ((uint32_t)payload[pktHeaderLen++] << 24); + + if (address != LoRaMacDevAddr) { + curMulticastParams = MulticastChannels; + while (curMulticastParams != NULL) { + if (address == curMulticastParams->Address) { + multicast = 1; + nwkSKey = curMulticastParams->NwkSKey; + appSKey = curMulticastParams->AppSKey; + downLinkCounter = curMulticastParams->DownLinkCounter; + break; + } + curMulticastParams = curMulticastParams->Next; + } + if (multicast == 0) { + // We are not the destination of this frame. + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; + PrepareRxDoneAbort(); + return; + } + } + else { + multicast = 0; + nwkSKey = LoRaMacNwkSKey; + appSKey = LoRaMacAppSKey; + downLinkCounter = DownLinkCounter; + } + + fCtrl.Value = payload[pktHeaderLen++]; + + sequenceCounter = (uint16_t)payload[pktHeaderLen++]; + sequenceCounter |= (uint16_t)payload[pktHeaderLen++] << 8; + + appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen; + + micRx |= (uint32_t)payload[size - LORAMAC_MFR_LEN]; + micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 1] << 8); + micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 2] << 16); + micRx |= ((uint32_t)payload[size - LORAMAC_MFR_LEN + 3] << 24); + + sequenceCounterPrev = (uint16_t)downLinkCounter; + sequenceCounterDiff = (sequenceCounter - sequenceCounterPrev); + + if (sequenceCounterDiff < (1 << 15)) { + downLinkCounter += sequenceCounterDiff; + LoRaMacComputeMic(payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, + downLinkCounter, &mic); + if (micRx == mic) { + isMicOk = true; + } + } + else { + // check for sequence roll-over + uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + (int16_t)sequenceCounterDiff; + LoRaMacComputeMic(payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, + downLinkCounterTmp, &mic); + if (micRx == mic) { + isMicOk = true; + downLinkCounter = downLinkCounterTmp; + } + } + + // Check for a the maximum allowed counter difference + if (sequenceCounterDiff >= MAX_FCNT_GAP) { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort(); + return; + } + + if (isMicOk == true) { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; + McpsIndication.Multicast = multicast; + McpsIndication.FramePending = fCtrl.Bits.FPending; + McpsIndication.Buffer = NULL; + McpsIndication.BufferSize = 0; + McpsIndication.DownLinkCounter = downLinkCounter; + + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + + MacCommandsBufferToRepeatIndex = 0; + + // Update 32 bits downlink counter + if (multicast == 1) { + McpsIndication.McpsIndication = MCPS_MULTICAST; + + if ((curMulticastParams->DownLinkCounter == downLinkCounter) && + (curMulticastParams->DownLinkCounter != 0)) { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort(); + return; + } + curMulticastParams->DownLinkCounter = downLinkCounter; + } + else { + if (macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN) { + SrvAckRequested = true; + McpsIndication.McpsIndication = MCPS_CONFIRMED; + + if ((DownLinkCounter == downLinkCounter) && (DownLinkCounter != 0)) { + // Duplicated confirmed downlink. Skip indication. + skipIndication = true; + } + } + else { + SrvAckRequested = false; + McpsIndication.McpsIndication = MCPS_UNCONFIRMED; + + if ((DownLinkCounter == downLinkCounter) && (DownLinkCounter != 0)) { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort(); + return; + } + } + DownLinkCounter = downLinkCounter; + } + + if (((size - 4) - appPayloadStartIndex) > 0) { + port = payload[appPayloadStartIndex++]; + frameLen = (size - 4) - appPayloadStartIndex; + + McpsIndication.Port = port; + + if (port == 0) { + if (fCtrl.Bits.FOptsLen == 0) { + LoRaMacPayloadDecrypt(payload + appPayloadStartIndex, frameLen, nwkSKey, address, + DOWN_LINK, downLinkCounter, LoRaMacRxPayload); + + // Decode frame payload MAC commands + ProcessMacCommands(LoRaMacRxPayload, 0, frameLen, snr); + } + else { + skipIndication = true; + } + } + else { + if (fCtrl.Bits.FOptsLen > 0) { + // Decode Options field MAC commands. Omit the fPort. + ProcessMacCommands(payload, 8, appPayloadStartIndex - 1, snr); + } + + LoRaMacPayloadDecrypt(payload + appPayloadStartIndex, frameLen, appSKey, address, + DOWN_LINK, downLinkCounter, LoRaMacRxPayload); + + if (skipIndication == false) { + McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.BufferSize = frameLen; + McpsIndication.RxData = true; + } + } + } + else { + if (fCtrl.Bits.FOptsLen > 0) { + // Decode Options field MAC commands + ProcessMacCommands(payload, 8, appPayloadStartIndex, snr); + } + } + + if (skipIndication == false) { + // Check if the frame is an acknowledgement + if (fCtrl.Bits.Ack == 1) { + McpsConfirm.AckReceived = true; + McpsIndication.AckReceived = true; + + // Stop the AckTimeout timer as no more retransmissions + // are needed. + TimerStop(&AckTimeoutTimer); + } + else { + McpsConfirm.AckReceived = false; + + if (AckTimeoutRetriesCounter > AckTimeoutRetries) { + // Stop the AckTimeout timer as no more retransmissions + // are needed. + TimerStop(&AckTimeoutTimer); + } + } + LoRaMacFlags.Bits.McpsInd = 1; + } + } + else { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; + + PrepareRxDoneAbort(); + return; + } + } break; + case FRAME_TYPE_PROPRIETARY: { + memcpy1(LoRaMacRxPayload, &payload[pktHeaderLen], size); + + McpsIndication.McpsIndication = MCPS_PROPRIETARY; + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; + McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.BufferSize = size - pktHeaderLen; + + LoRaMacFlags.Bits.McpsInd = 1; + break; } - else - { - OnRxWindow2TimerEvent( ); + default: + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + PrepareRxDoneAbort(); + break; + } + + if ((RxSlot == 0) && (LoRaMacDeviceClass == CLASS_C)) { + OnRxWindow2TimerEvent(); + } + LoRaMacFlags.Bits.MacDone = 1; + + // Trig OnMacCheckTimerEvent call as soon as possible + TimerSetValue(&MacStateCheckTimer, 1000); + TimerStart(&MacStateCheckTimer); +} + +static void OnRadioTxTimeout(void) { + if (LoRaMacDeviceClass != CLASS_C) { + Radio.Sleep(); + } + else { + OnRxWindow2TimerEvent(); + } + + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + LoRaMacFlags.Bits.MacDone = 1; +} + +static void OnRadioRxError(void) { + if (LoRaMacDeviceClass != CLASS_C) { + Radio.Sleep(); + } + else { + OnRxWindow2TimerEvent(); + } + + if (RxSlot == 1) { + if (NodeAckRequested == true) { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; } - - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; LoRaMacFlags.Bits.MacDone = 1; + } +} + +static void OnRadioRxTimeout(void) { + if (LoRaMacDeviceClass != CLASS_C) { + Radio.Sleep(); + } + else { + OnRxWindow2TimerEvent(); + } + + if (RxSlot == 1) { + if (NodeAckRequested == true) { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + } + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + LoRaMacFlags.Bits.MacDone = 1; + } } -static void OnRadioRxError( void ) -{ - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); +static void OnMacStateCheckTimerEvent(void) { + TimerStop(&MacStateCheckTimer); + bool txTimeout = false; + bool txDone = false; + + if (LoRaMacFlags.Bits.MacDone == 1) { + if ((LoRaMacState & MAC_RX_ABORT) == MAC_RX_ABORT) { + LoRaMacState &= ~MAC_RX_ABORT; + LoRaMacState &= ~MAC_TX_RUNNING; + } + + if ((LoRaMacFlags.Bits.MlmeReq == 1) || ((LoRaMacFlags.Bits.McpsReq == 1))) { + if ((McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT) || + (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT)) { + // Stop transmit cycle due to tx timeout. + LoRaMacState &= ~MAC_TX_RUNNING; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + McpsConfirm.AckReceived = false; + McpsConfirm.TxTimeOnAir = 0; + txTimeout = true; + } + } + + if ((NodeAckRequested == false) && (txTimeout == false)) { + if (LoRaMacFlags.Bits.MlmeReq == 1) { + if (MlmeConfirm.MlmeRequest == MLME_JOIN) { + if (MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK) { + UpLinkCounter = 0; + } + // Join messages aren't repeated automatically + ChannelsNbRepCounter = ChannelsNbRep; + } + } + if ((LoRaMacFlags.Bits.MlmeReq == 1) || ((LoRaMacFlags.Bits.McpsReq == 1))) { + if ((ChannelsNbRepCounter >= ChannelsNbRep) || (LoRaMacFlags.Bits.McpsInd == 1)) { + ChannelsNbRepCounter = 0; + + txDone = true; + LoRaMacState &= ~MAC_TX_RUNNING; + } + else { + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + ScheduleTx(); + } + } + } + + if (LoRaMacFlags.Bits.McpsInd == 1) { + if ((McpsConfirm.AckReceived == true) || (AckTimeoutRetriesCounter > AckTimeoutRetries)) { + AckTimeoutRetry = false; + NodeAckRequested = false; + txDone = true; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + + LoRaMacState &= ~MAC_TX_RUNNING; + } } - else - { - OnRxWindow2TimerEvent( ); + + if ((AckTimeoutRetry == true) && ((LoRaMacState & MAC_TX_DELAYED) == 0)) { + AckTimeoutRetry = false; + if ((AckTimeoutRetriesCounter < AckTimeoutRetries) && + (AckTimeoutRetriesCounter <= MAX_ACK_RETRIES)) { + AckTimeoutRetriesCounter++; + + if ((AckTimeoutRetriesCounter % 2) == 1) { + ChannelsDatarate = MAX(ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE); + // Check if new datarate is valid for the Payload length + if (ValidatePayloadLength(LoRaMacBufferPktLen - 13, ChannelsDatarate, 0) == false) { + // If invalid payload length, then revert to previous datarate + ChannelsDatarate++; + } + } + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + ScheduleTx(); + } + else { +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + // Re-enable default channels LC1, LC2, LC3 + ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3)); +#elif !defined(USE_BAND_915) && !defined(USE_BAND_915_HYBRID) +#error "Please define a frequency band in the compiler options." +#endif + LoRaMacState &= ~MAC_TX_RUNNING; + + NodeAckRequested = false; + McpsConfirm.AckReceived = false; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + txDone = true; + } + } + + // Update uplink counter + if ((txDone == true) && (IsUpLinkCounterFixed == false)) { + UpLinkCounter++; + + // Reset AdrAckCounter if downlink received + if ((LoRaMacFlags.Bits.McpsInd == 1) || (UpLinkCounter == 1)) { + AdrAckCounter = 0; + } + else { + AdrAckCounter++; + } + } + } + // Handle reception for Class B and Class C + if ((LoRaMacState & MAC_RX) == MAC_RX) { + LoRaMacState &= ~MAC_RX; + } + + if (LoRaMacState == MAC_IDLE) { + if (LoRaMacFlags.Bits.McpsReq == 1) { + LoRaMacPrimitives->MacMcpsConfirm(&McpsConfirm); + LoRaMacFlags.Bits.McpsReq = 0; + } + + if (LoRaMacFlags.Bits.MlmeReq == 1) { + LoRaMacPrimitives->MacMlmeConfirm(&MlmeConfirm); + LoRaMacFlags.Bits.MlmeReq = 0; } - if( RxSlot == 1 ) - { - if( NodeAckRequested == true ) - { - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + LoRaMacFlags.Bits.MacDone = 0; + } + else { + // Operation not finished restart timer + TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT); + TimerStart(&MacStateCheckTimer); + } + + if (LoRaMacFlags.Bits.McpsInd == 1) { + LoRaMacPrimitives->MacMcpsIndication(&McpsIndication); + LoRaMacFlags.Bits.McpsInd = 0; + } +} + +static void OnTxDelayedTimerEvent(void) { + TimerStop(&TxDelayedTimer); + LoRaMacState &= ~MAC_TX_DELAYED; + + ScheduleTx(); +} + +static void OnRxWindow1TimerEvent(void) { + uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0 + int8_t datarate = 0; + uint32_t bandwidth = 0; // LoRa 125 kHz + + TimerStop(&RxWindowTimer1); + RxSlot = 0; + + if (LoRaMacDeviceClass == CLASS_C) { + Radio.Standby(); + } + +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + datarate = ChannelsDatarate - Rx1DrOffset; + if (datarate < 0) { + datarate = DR_0; + } + + // For higher datarates, we increase the number of symbols generating a Rx + // Timeout + if ((datarate == DR_3) || (datarate == DR_4)) { // DR_4, DR_3 + symbTimeout = 8; + } + else if (datarate == DR_5) { + symbTimeout = 10; + } + else if (datarate == DR_6) { // LoRa 250 kHz + bandwidth = 1; + symbTimeout = 14; + } + RxWindowSetup(Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false); +#elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)) + datarate = datarateOffsets[ChannelsDatarate][Rx1DrOffset]; + if (datarate < 0) { + datarate = DR_0; + } + // For higher datarates, we increase the number of symbols generating a Rx + // Timeout + + symbTimeout = 10; + // For low SF, we increase the number of symbols generating a Rx Timeout + switch (datarate) { + case DR_0: + case DR_8: + case DR_9: + case DR_10: + symbTimeout += 5; + break; + case DR_1: + case DR_11: + symbTimeout += 8; + break; + case DR_2: + case DR_4: + case DR_12: + symbTimeout += 9; + break; + case DR_3: + case DR_13: + symbTimeout += 10; + break; + default: + symbTimeout += 5; + break; + } + + if (datarate >= DR_4) { // LoRa 500 kHz + bandwidth = 2; + } + RxWindowSetup(923.3e6 + (Channel % 8) * 600e3, datarate, bandwidth, symbTimeout, false); +#else +#error "Please define a frequency band in the compiler options." +#endif +} + +static void OnRxWindow2TimerEvent(void) { + uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0 + uint32_t bandwidth = 0; // LoRa 125 kHz + + TimerStop(&RxWindowTimer2); + RxSlot = 1; + +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + // For higher datarates, we increase the number of symbols generating a Rx + // Timeout + if ((Rx2Channel.Datarate == DR_3) || (Rx2Channel.Datarate == DR_4)) { // DR_4, DR_3 + symbTimeout = 8; + } + else if (Rx2Channel.Datarate == DR_5) { + symbTimeout = 10; + } + else if (Rx2Channel.Datarate == DR_6) { // LoRa 250 kHz + bandwidth = 1; + symbTimeout = 14; + } +#elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)) + // For higher datarates, we increase the number of symbols generating a Rx + // Timeout + switch (Rx2Channel.Datarate) { + case DR_0: // SF10 - BW125 + symbTimeout = 5; + break; + + case DR_1: // SF9 - BW125 + case DR_2: // SF8 - BW125 + case DR_8: // SF12 - BW500 + case DR_9: // SF11 - BW500 + case DR_10: // SF10 - BW500 + symbTimeout = 8; + break; + + case DR_3: // SF7 - BW125 + case DR_11: // SF9 - BW500 + symbTimeout = 10; + break; + + case DR_4: // SF8 - BW500 + case DR_12: // SF8 - BW500 + symbTimeout = 14; + break; + + case DR_13: // SF7 - BW500 + symbTimeout = 16; + break; + default: + break; + } + if (Rx2Channel.Datarate >= DR_4) { // LoRa 500 kHz + bandwidth = 2; + } +#else +#error "Please define a frequency band in the compiler options." +#endif + if (LoRaMacDeviceClass != CLASS_C) { + RxWindowSetup(Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false); + } + else { + RxWindowSetup(Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true); + } +} + +static void OnAckTimeoutTimerEvent(void) { + TimerStop(&AckTimeoutTimer); + + if (NodeAckRequested == true) { + AckTimeoutRetry = true; + LoRaMacState &= ~MAC_ACK_REQ; + } + if (LoRaMacDeviceClass == CLASS_C) { + LoRaMacFlags.Bits.MacDone = 1; + } +} + +#if defined(USE_BAND_915) +uint8_t GetNextJoinChannel(uint8_t* enabledChannels, uint8_t nbEnabledChannels) { + int8_t channel = -1; + uint8_t block; + uint8_t i; + + // Use 125KHz channel + if (ChannelsDatarate < DR_4) { + block = JoinBlock[NextJoinBlock]; + NextJoinBlock = (NextJoinBlock + 1) % 8; + + // If next block is greater than max block then randomly select the next + // block + if (block >= 8) + block = randr(0, 7); + + // Start search for next join channel at the selected block + for (i = 0; (i < 8) && (channel == -1); i++) { + uint8_t curBlock = (block + i) % 8; + uint8_t chMask; + + // Cycle through all blocks before using a previously used block + if (((JoinBlocksRemaining & (1 << curBlock)) != 0)) { + chMask = (ChannelsMaskRemaining[curBlock / 2] >> (curBlock & 1 ? 8 : 0)) & 0xff; + if (chMask != 0) { + channel = randr(0, 7); + for (uint8_t i = 0; (i < 8); i++) { + if ((chMask & (1 << channel)) != 0) { + uint16_t chMaskTmp = (1 << channel); + chMaskTmp = chMaskTmp << (curBlock & 1 ? 8 : 0); + channel = channel + (curBlock * 8); + JoinBlocksRemaining &= ~(1 << curBlock); + ChannelsMaskRemaining[curBlock / 2] &= ~chMaskTmp; + if ((JoinBlocksRemaining == 0)) { + JoinBlocksRemaining = 0xFF; + } + break; + } + else { + channel = (channel + 1) % 8; + } + } } - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - LoRaMacFlags.Bits.MacDone = 1; + } + } + + // No next channel case should never happen since ScheduleTx has already + // checked for at least one enabled channel and if none re-enabled all + // channels. + // But if we find ourselves without a channel then randomly select one + if (i >= 8) { + channel = randr(0, 63); } + } + // Use 500 KHz channel + else { + channel = randr(0, 7); + for (i = 0; i < 8; i++) { + uint8_t curChannel = (channel + i) % 8; + + if (((Join500KHzRemaining & (1 << curChannel)) != 0)) { + Join500KHzRemaining &= ~(1 << curChannel); + channel = 64 + curChannel; + if (Join500KHzRemaining == 0) { + Join500KHzRemaining = 0xFF; + } + break; + } + } + } + + for (i = 0; i < nbEnabledChannels; i++) { + if (enabledChannels[i] == channel) + break; + } + + if (i == nbEnabledChannels) { + channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + } + + LastJoinBlock = channel / 8; + + return channel; } - -static void OnRadioRxTimeout( void ) -{ - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); +#endif + +static bool SetNextChannel(TimerTime_t* time) { + 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*)ChannelsMask, 8); + } + if ((ChannelsDatarate >= DR_4) && + ((ChannelsMaskRemaining[4] & 0x00FF) == 0)) { // Make sure, that the channels are activated + ChannelsMaskRemaining[4] = ChannelsMask[4]; + } +#else + if (CountBits(ChannelsMask[0], 16) == 0) { + // Re-enable default channels, if no channel is enabled + ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3)); + } +#endif + + // Update Aggregated duty cycle + if (AggregatedTimeOff <= TimerGetElapsedTime(AggregatedLastTxDoneTime)) { + AggregatedTimeOff = 0; + + // Update bands Time OFF + for (uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++) { + if (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 { + nextTxDelay = 0; + 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 ((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 <= ChannelsDatarate) && + (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; + } + } + } + } + else { + delayTx++; + nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime(AggregatedLastTxDoneTime); + } + + if (nbEnabledChannels > 0) { +#if defined(USE_BAND_915) + if (IsLoRaMacNetworkJoined == false) { + Channel = GetNextJoinChannel(enabledChannels, nbEnabledChannels); + } + // Send first uplink on channel from same sub-band as the join + else if ((UpLinkCounter == 1) && (LastJoinBlock != -1)) { + uint8_t i; + uint8_t blockFirstChannel = LastJoinBlock * 8; + + Channel = randr(blockFirstChannel, blockFirstChannel + 7); + + // Check channel is enabled + for (i = 0; i < nbEnabledChannels; i++) { + if (Channel == enabledChannels[i]) + break; + } + + // If channel is not enabled fallback to selecting from the list of + // enabled channels + if (i == nbEnabledChannels) { + Channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; + } } else - { - OnRxWindow2TimerEvent( ); - } - - if( RxSlot == 1 ) - { - if( NodeAckRequested == true ) - { - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - } - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - LoRaMacFlags.Bits.MacDone = 1; - } -} - -static void OnMacStateCheckTimerEvent( void ) -{ - TimerStop( &MacStateCheckTimer ); - bool txTimeout = false; - bool txDone = false; - - if( LoRaMacFlags.Bits.MacDone == 1 ) - { - if( ( LoRaMacState & MAC_RX_ABORT ) == MAC_RX_ABORT ) - { - LoRaMacState &= ~MAC_RX_ABORT; - LoRaMacState &= ~MAC_TX_RUNNING; - } - - if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) - { - if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) || - ( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ) - { - // Stop transmit cycle due to tx timeout. - LoRaMacState &= ~MAC_TX_RUNNING; - McpsConfirm.NbRetries = AckTimeoutRetriesCounter; - McpsConfirm.AckReceived = false; - McpsConfirm.TxTimeOnAir = 0; - txTimeout = true; - } - } - - if( ( NodeAckRequested == false ) && ( txTimeout == false ) ) - { - if( LoRaMacFlags.Bits.MlmeReq == 1 ) - { - if( MlmeConfirm.MlmeRequest == MLME_JOIN ) - { - if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK ) - { - UpLinkCounter = 0; - } - // Join messages aren't repeated automatically - ChannelsNbRepCounter = ChannelsNbRep; - } - } - if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) - { - if( ( ChannelsNbRepCounter >= ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) ) - { - ChannelsNbRepCounter = 0; - - txDone = true; - LoRaMacState &= ~MAC_TX_RUNNING; - } - else - { - LoRaMacFlags.Bits.MacDone = 0; - // Sends the same frame again - ScheduleTx( ); - } - } - } - - if( LoRaMacFlags.Bits.McpsInd == 1 ) - { - if( ( McpsConfirm.AckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) ) - { - AckTimeoutRetry = false; - NodeAckRequested = false; - txDone = true; - McpsConfirm.NbRetries = AckTimeoutRetriesCounter; - - LoRaMacState &= ~MAC_TX_RUNNING; - } - } - - if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_TX_DELAYED ) == 0 ) ) - { - AckTimeoutRetry = false; - if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) ) - { - AckTimeoutRetriesCounter++; - - if( ( AckTimeoutRetriesCounter % 2 ) == 1 ) - { - ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE ); - // Check if new datarate is valid for the Payload length - if( ValidatePayloadLength( LoRaMacBufferPktLen - 13, ChannelsDatarate, 0 ) == false ) - { - // If invalid payload length, then revert to previous datarate - ChannelsDatarate++; - } - } - LoRaMacFlags.Bits.MacDone = 0; - // Sends the same frame again - ScheduleTx( ); - } - else - { -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - // Re-enable default channels LC1, LC2, LC3 - ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); -#elif !defined( USE_BAND_915 ) && !defined( USE_BAND_915_HYBRID ) - #error "Please define a frequency band in the compiler options." #endif - LoRaMacState &= ~MAC_TX_RUNNING; - - NodeAckRequested = false; - McpsConfirm.AckReceived = false; - McpsConfirm.NbRetries = AckTimeoutRetriesCounter; - txDone = true; - } - } - - // Update uplink counter - if( ( txDone == true ) && ( IsUpLinkCounterFixed == false ) ) - { - UpLinkCounter++; - - // Reset AdrAckCounter if downlink received - if( ( LoRaMacFlags.Bits.McpsInd == 1 ) || ( UpLinkCounter == 1 ) ) - { - AdrAckCounter = 0; - } - else - { - AdrAckCounter++; - } - } - } - // Handle reception for Class B and Class C - if( ( LoRaMacState & MAC_RX ) == MAC_RX ) - { - LoRaMacState &= ~MAC_RX; - } - - if( LoRaMacState == MAC_IDLE ) - { - if( LoRaMacFlags.Bits.McpsReq == 1 ) - { - LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm ); - LoRaMacFlags.Bits.McpsReq = 0; - } - - if( LoRaMacFlags.Bits.MlmeReq == 1 ) - { - LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm ); - LoRaMacFlags.Bits.MlmeReq = 0; - } - - LoRaMacFlags.Bits.MacDone = 0; - } - else - { - // Operation not finished restart timer - TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); - TimerStart( &MacStateCheckTimer ); - } - - if( LoRaMacFlags.Bits.McpsInd == 1 ) - { - LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); - LoRaMacFlags.Bits.McpsInd = 0; - } -} - -static void OnTxDelayedTimerEvent( void ) -{ - TimerStop( &TxDelayedTimer ); - LoRaMacState &= ~MAC_TX_DELAYED; - - ScheduleTx( ); -} - -static void OnRxWindow1TimerEvent( void ) -{ - uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0 - int8_t datarate = 0; - uint32_t bandwidth = 0; // LoRa 125 kHz - - TimerStop( &RxWindowTimer1 ); - RxSlot = 0; - - if( LoRaMacDeviceClass == CLASS_C ) - { - Radio.Standby( ); - } - -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - datarate = ChannelsDatarate - Rx1DrOffset; - if( datarate < 0 ) - { - datarate = DR_0; - } - - // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( ( datarate == DR_3 ) || ( datarate == DR_4 ) ) - { // DR_4, DR_3 - symbTimeout = 8; - } - else if( datarate == DR_5 ) - { - symbTimeout = 10; - } - else if( datarate == DR_6 ) - {// LoRa 250 kHz - bandwidth = 1; - symbTimeout = 14; - } - RxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false ); -#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - datarate = datarateOffsets[ChannelsDatarate][Rx1DrOffset]; - if( datarate < 0 ) - { - datarate = DR_0; - } - // For higher datarates, we increase the number of symbols generating a Rx Timeout - - - symbTimeout = 10; - // For low SF, we increase the number of symbols generating a Rx Timeout - switch ( datarate ) { - case DR_0: - case DR_8: - case DR_9: - case DR_10: - symbTimeout += 5; - break; - case DR_1: - case DR_11: - symbTimeout += 8; - break; - case DR_2: - case DR_4: - case DR_12: - symbTimeout += 9; - break; - case DR_3: - case DR_13: - symbTimeout += 10; - break; - default: - symbTimeout += 5; - break; - } - - if( datarate >= DR_4 ) - {// LoRa 500 kHz - bandwidth = 2; - } - RxWindowSetup( 923.3e6 + ( Channel % 8 ) * 600e3, datarate, bandwidth, symbTimeout, false ); -#else - #error "Please define a frequency band in the compiler options." -#endif -} - -static void OnRxWindow2TimerEvent( void ) -{ - uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0 - uint32_t bandwidth = 0; // LoRa 125 kHz - - TimerStop( &RxWindowTimer2 ); - RxSlot = 1; - -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - // For higher datarates, we increase the number of symbols generating a Rx Timeout - if( ( Rx2Channel.Datarate == DR_3 ) || ( Rx2Channel.Datarate == DR_4 ) ) - { // DR_4, DR_3 - symbTimeout = 8; - } - else if( Rx2Channel.Datarate == DR_5 ) - { - symbTimeout = 10; - } - else if( Rx2Channel.Datarate == DR_6 ) - {// LoRa 250 kHz - bandwidth = 1; - symbTimeout = 14; - } -#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - // For higher datarates, we increase the number of symbols generating a Rx Timeout - switch( Rx2Channel.Datarate ) - { - case DR_0: // SF10 - BW125 - symbTimeout = 5; - break; - - case DR_1: // SF9 - BW125 - case DR_2: // SF8 - BW125 - case DR_8: // SF12 - BW500 - case DR_9: // SF11 - BW500 - case DR_10: // SF10 - BW500 - symbTimeout = 8; - break; - - case DR_3: // SF7 - BW125 - case DR_11: // SF9 - BW500 - symbTimeout = 10; - break; - - case DR_4: // SF8 - BW500 - case DR_12: // SF8 - BW500 - symbTimeout = 14; - break; - - case DR_13: // SF7 - BW500 - symbTimeout = 16; - break; - default: - break; - } - if( Rx2Channel.Datarate >= DR_4 ) - {// LoRa 500 kHz - bandwidth = 2; - } -#else - #error "Please define a frequency band in the compiler options." -#endif - if( LoRaMacDeviceClass != CLASS_C ) - { - RxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false ); - } - else - { - RxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true ); - } -} - -static void OnAckTimeoutTimerEvent( void ) -{ - TimerStop( &AckTimeoutTimer ); - - if( NodeAckRequested == true ) - { - AckTimeoutRetry = true; - LoRaMacState &= ~MAC_ACK_REQ; - } - if( LoRaMacDeviceClass == CLASS_C ) - { - LoRaMacFlags.Bits.MacDone = 1; + Channel = enabledChannels[randr(0, nbEnabledChannels - 1)]; } -} - -#if defined( USE_BAND_915 ) -uint8_t GetNextJoinChannel( uint8_t* enabledChannels, uint8_t nbEnabledChannels ) -{ - int8_t channel = -1; - uint8_t block; - uint8_t i; - - // Use 125KHz channel - if( ChannelsDatarate < DR_4 ) - { - block = JoinBlock[NextJoinBlock]; - NextJoinBlock = (NextJoinBlock + 1) % 8; - - // If next block is greater than max block then randomly select the next block - if( block >= 8 ) - block = randr(0, 7); - - // Start search for next join channel at the selected block - for(i = 0; ( i < 8 ) && ( channel == -1 ); i++) - { - uint8_t curBlock = (block + i) % 8; - uint8_t chMask; - - // Cycle through all blocks before using a previously used block - if( ( ( JoinBlocksRemaining & ( 1 << curBlock ) ) != 0) ) - { - chMask = ( ChannelsMaskRemaining[curBlock/2] >> ( curBlock & 1 ? 8 : 0 ) ) & 0xff; - if( chMask != 0) - { - channel = randr(0, 7); - for(uint8_t i = 0; ( i < 8 ); i++) - { - if( ( chMask & ( 1 << channel ) ) != 0 ) - { - uint16_t chMaskTmp = ( 1 << channel ); - chMaskTmp = chMaskTmp << ( curBlock & 1 ? 8 : 0 ); - channel = channel + ( curBlock * 8 ); - JoinBlocksRemaining &= ~(1 << curBlock); - ChannelsMaskRemaining[curBlock/2] &= ~chMaskTmp; - if( ( JoinBlocksRemaining == 0 ) ) - { - JoinBlocksRemaining = 0xFF; - } - break; - } - else - { - channel = ( channel + 1 ) % 8; - } - } - } - } - } - - // No next channel case should never happen since ScheduleTx has already - // checked for at least one enabled channel and if none re-enabled all channels. - // But if we find ourselves without a channel then randomly select one - if ( i >= 8 ) - { - channel = randr( 0, 63 ); - } - } - // Use 500 KHz channel - else - { - channel = randr( 0, 7 ); - for(i = 0; i < 8; i++) - { - uint8_t curChannel = (channel + i) % 8; - - if( ( ( Join500KHzRemaining & ( 1 << curChannel ) ) != 0 ) ) - { - Join500KHzRemaining &= ~(1 << curChannel); - channel = 64 + curChannel; - if( Join500KHzRemaining == 0 ) - { - Join500KHzRemaining = 0xFF; - } - break; - } - } - } - - for( i = 0; i < nbEnabledChannels; i++ ) - { - if( enabledChannels[i] == channel ) - break; - } - - if( i == nbEnabledChannels ) - { - channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )]; - } - - LastJoinBlock = channel / 8; - - return channel; -} -#endif - -static bool SetNextChannel( TimerTime_t* time ) -{ - 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* ) ChannelsMask, 8 ); - } - if( ( ChannelsDatarate >= DR_4 ) && ( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 ) ) - { // Make sure, that the channels are activated - ChannelsMaskRemaining[4] = ChannelsMask[4]; - } -#else - if( CountBits( ChannelsMask[0], 16 ) == 0 ) - { - // Re-enable default channels, if no channel is enabled - ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); + +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + if (Channel < (LORA_MAX_NB_CHANNELS - 8)) { + DisableChannelInMask(Channel, ChannelsMaskRemaining); } #endif - - // Update Aggregated duty cycle - if( AggregatedTimeOff <= TimerGetElapsedTime( AggregatedLastTxDoneTime ) ) - { - AggregatedTimeOff = 0; - - // Update bands Time OFF - for( uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++ ) - { - if( 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 - { - nextTxDelay = 0; - 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( ( 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 <= ChannelsDatarate ) && - ( 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; - } - } - } - } - else - { - delayTx++; - nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime( AggregatedLastTxDoneTime ); + *time = 0; + return true; + } + else { + if (delayTx > 0) { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; } - - if( nbEnabledChannels > 0 ) - { -#if defined( USE_BAND_915 ) - if ( IsLoRaMacNetworkJoined == false ) - { - Channel = GetNextJoinChannel(enabledChannels, nbEnabledChannels); - } - // Send first uplink on channel from same sub-band as the join - else if( ( UpLinkCounter == 1 ) && ( LastJoinBlock != -1 ) ) - { - uint8_t i; - uint8_t blockFirstChannel = LastJoinBlock*8; - - Channel = randr( blockFirstChannel, blockFirstChannel + 7 ); - - // Check channel is enabled - for( i = 0; i < nbEnabledChannels; i++ ) - { - if( Channel == enabledChannels[i] ) - break; - } - - // If channel is not enabled fallback to selecting from the list of - // enabled channels - if (i == nbEnabledChannels) - { - Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )]; - } - } - else + // Datarate not supported by any channel + *time = 0; + return false; + } +} + +static void SetPublicNetwork(bool enable) { + PublicNetwork = enable; + Radio.SetModem(MODEM_LORA); + if (PublicNetwork == true) { + // Change LoRa modem SyncWord + Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD); + } + else { + // Change LoRa modem SyncWord + Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD); + } +} + +static void RxWindowSetup(uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, + bool rxContinuous) { + uint8_t downlinkDatarate = Datarates[datarate]; + RadioModems_t modem; + + if (Radio.GetStatus() == RF_IDLE) { + Radio.SetChannel(freq); + + // Store downlink datarate + McpsIndication.RxDatarate = (uint8_t)datarate; + +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + if (datarate == DR_7) { + modem = MODEM_FSK; + Radio.SetRxConfig(modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, + 0, false, rxContinuous); + } + else { + modem = MODEM_LORA; + Radio.SetRxConfig(modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, + true, rxContinuous); + } +#elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + modem = MODEM_LORA; + Radio.SetRxConfig(modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, + true, rxContinuous); #endif - { - Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )]; - } - -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( Channel < ( LORA_MAX_NB_CHANNELS - 8 ) ) - { - DisableChannelInMask( Channel, ChannelsMaskRemaining ); - } -#endif - *time = 0; - return true; + + if (RepeaterSupport == true) { + Radio.SetMaxPayloadLength( + modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD); + } + else { + Radio.SetMaxPayloadLength(modem, + MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD); + } + + if (rxContinuous == false) { + Radio.Rx(MaxRxWindow); + } + else { + Radio.Rx(0); // Continuous mode } - 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; - } + } } -static void SetPublicNetwork( bool enable ) -{ - PublicNetwork = enable; - Radio.SetModem( MODEM_LORA ); - if( PublicNetwork == true ) - { - // Change LoRa modem SyncWord - Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD ); - } - else - { - // Change LoRa modem SyncWord - Radio.Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD ); - } +static 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_915) || defined(USE_BAND_915_HYBRID)) + if ((Radio.CheckRfFrequency(freq) == true) && (freq >= LORAMAC_FIRST_RX2_CHANNEL) && + (freq <= LORAMAC_LAST_RX2_CHANNEL) && (((freq - (uint32_t)LORAMAC_FIRST_RX2_CHANNEL) % + (uint32_t)LORAMAC_STEPWIDTH_RX2_CHANNEL) == 0)) +#endif + { + return true; + } + return false; } -static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ) -{ - uint8_t downlinkDatarate = Datarates[datarate]; - RadioModems_t modem; - - if( Radio.GetStatus( ) == RF_IDLE ) - { - Radio.SetChannel( freq ); - - // Store downlink datarate - McpsIndication.RxDatarate = ( uint8_t ) datarate; - -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - if( datarate == DR_7 ) - { - modem = MODEM_FSK; - Radio.SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous ); - } - else - { - modem = MODEM_LORA; - Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); - } -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - modem = MODEM_LORA; - Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); -#endif - - if( RepeaterSupport == true ) - { - Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); - } - else - { - Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); - } - - if( rxContinuous == false ) - { - Radio.Rx( MaxRxWindow ); - } - else - { - Radio.Rx( 0 ); // Continuous mode - } +static bool ValidatePayloadLength(uint8_t lenN, int8_t datarate, uint8_t fOptsLen) { + uint16_t maxN = 0; + uint16_t payloadSize = 0; + + // Get the maximum payload length + if (RepeaterSupport == true) { + maxN = MaxPayloadOfDatarateRepeater[datarate]; + } + else { + maxN = MaxPayloadOfDatarate[datarate]; + } + + // Calculate the resulting payload size + payloadSize = (lenN + fOptsLen); + + // Validation of the application payload size + if ((payloadSize <= maxN) && (payloadSize <= LORAMAC_PHY_MAXPAYLOAD)) { + return true; + } + return false; +} + +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++; } -} - -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_915 ) || defined( USE_BAND_915_HYBRID ) ) - if( ( Radio.CheckRfFrequency( freq ) == true ) && - ( freq >= LORAMAC_FIRST_RX2_CHANNEL ) && - ( freq <= LORAMAC_LAST_RX2_CHANNEL ) && - ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX2_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX2_CHANNEL ) == 0 ) ) -#endif - { - return true; - } - return false; + } + return nbActiveBits; } - -static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ) -{ - uint16_t maxN = 0; - uint16_t payloadSize = 0; - - // Get the maximum payload length - if( RepeaterSupport == true ) - { - maxN = MaxPayloadOfDatarateRepeater[datarate]; - } - else - { - maxN = MaxPayloadOfDatarate[datarate]; - } - - // Calculate the resulting payload size - payloadSize = ( lenN + fOptsLen ); - - // Validation of the application payload size - if( ( payloadSize <= maxN ) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD ) ) - { - return true; - } - return false; +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) +static uint8_t CountNbEnabled125kHzChannels(uint16_t* channelsMask) { + uint8_t nb125kHzChannels = 0; + + for (uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++) { + nb125kHzChannels += CountBits(channelsMask[k], 16); + } + + return nb125kHzChannels; } -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++; - } +#if defined(USE_BAND_915_HYBRID) +static void ReenableChannels(uint16_t mask, uint16_t* channelMask) { + uint16_t blockMask = mask; + + for (uint8_t i = 0, j = 0; i < 4; i++, j += 2) { + channelMask[i] = 0; + if ((blockMask & (1 << j)) != 0) { + channelMask[i] |= 0x00FF; } - 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* channelMask ) -{ - uint16_t blockMask = mask; - - for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 ) - { - channelMask[i] = 0; - if( ( blockMask & ( 1 << j ) ) != 0 ) - { - channelMask[i] |= 0x00FF; - } - if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 ) - { - channelMask[i] |= 0xFF00; - } + if ((blockMask & (1 << (j + 1))) != 0) { + channelMask[i] |= 0xFF00; } - channelMask[4] = blockMask; - channelMask[5] = 0x0000; + } + channelMask[4] = blockMask; + channelMask[5] = 0x0000; } -static bool ValidateChannelMask( uint16_t* channelMask ) -{ - bool chanMaskState = false; - uint16_t block1 = 0; - uint16_t block2 = 0; - uint8_t index = 0; - - for( uint8_t i = 0; i < 4; i++ ) - { - block1 = channelMask[i] & 0x00FF; - block2 = channelMask[i] & 0xFF00; - - if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) ) - { - channelMask[i] &= block1; - channelMask[4] = 1 << ( i * 2 ); - chanMaskState = true; - index = i; - } - else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) ) - { - channelMask[i] &= block2; - channelMask[4] = 1 << ( i * 2 + 1 ); - chanMaskState = true; - index = i; - } +static bool ValidateChannelMask(uint16_t* channelMask) { + bool chanMaskState = false; + uint16_t block1 = 0; + uint16_t block2 = 0; + uint8_t index = 0; + + for (uint8_t i = 0; i < 4; i++) { + block1 = channelMask[i] & 0x00FF; + block2 = channelMask[i] & 0xFF00; + + if ((CountBits(block1, 16) > 5) && (chanMaskState == false)) { + channelMask[i] &= block1; + channelMask[4] = 1 << (i * 2); + chanMaskState = true; + index = i; } - - // Do only change the channel mask, if we have found a valid block. - if( chanMaskState == true ) - { - for( uint8_t i = 0; i < 4; i++ ) - { - if( i != index ) - { - channelMask[i] = 0; - } - } + else if ((CountBits(block2, 16) > 5) && (chanMaskState == false)) { + channelMask[i] &= block2; + channelMask[4] = 1 << (i * 2 + 1); + chanMaskState = true; + index = i; } - return chanMaskState; + } + + // Do only change the channel mask, if we have found a valid block. + if (chanMaskState == true) { + for (uint8_t i = 0; i < 4; i++) { + if (i != index) { + channelMask[i] = 0; + } + } + } + return chanMaskState; } #endif #endif -static int8_t LimitTxPower( int8_t txPower ) -{ - int8_t resultTxPower = MAX( txPower, TX_POWER_30_DBM ); - - return resultTxPower; +static int8_t LimitTxPower(int8_t txPower) { + int8_t resultTxPower = MAX(txPower, TX_POWER_30_DBM); + + 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 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 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 isTx, int8_t* datarateOut, int8_t* txpowerOut ) -{ - bool adrAckReq = false; - int8_t datarate = ChannelsDatarate; - int8_t txpower = ChannelsTxPower; - - if( adrEnabled == true ) - { - /* Request ADR Ack Request (including at lowest available datarate) */ - adrAckReq = AdrAckCounter >= ADR_ACK_LIMIT ? true : false; - - if( AdrAckCounter >= (ADR_ACK_LIMIT + ADR_ACK_DELAY) ) - { - // Step up power - txpower = LORAMAC_DEFAULT_TX_POWER; - - if( ( AdrAckCounter % ADR_ACK_DELAY ) == 0 ) - { -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - if( datarate > LORAMAC_TX_MIN_DATARATE ) - { - datarate--; - } - - if( datarate == LORAMAC_TX_MIN_DATARATE ) - { - if( isTx == true ) - { - // Re-enable default channels LC1, LC2, LC3 - ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); - } - } -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( datarate > LORAMAC_TX_MIN_DATARATE ) - { - if ( datarate == DR_8) - datarate = DR_4; - else - datarate--; - - } - else if( isTx == true ) - { -#if defined( USE_BAND_915 ) - // Re-enable default channels - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0x00FF; - ChannelsMask[5] = 0x0000; -#else // defined( USE_BAND_915_HYBRID ) - // Re-enable default channels - ChannelsMask[0] = 0x00FF; - ChannelsMask[1] = 0x0000; - ChannelsMask[2] = 0x0000; - ChannelsMask[3] = 0x0000; - ChannelsMask[4] = 0x0001; - ChannelsMask[5] = 0x0000; +static bool AdrNextDr(bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut) { + bool adrAckReq = false; + int8_t datarate = ChannelsDatarate; + int8_t txpower = ChannelsTxPower; + + if (adrEnabled == true) { + /* Request ADR Ack Request (including at lowest available datarate) */ + adrAckReq = AdrAckCounter >= ADR_ACK_LIMIT ? true : false; + + if (AdrAckCounter >= (ADR_ACK_LIMIT + ADR_ACK_DELAY)) { + // Step up power + txpower = LORAMAC_DEFAULT_TX_POWER; + + if ((AdrAckCounter % ADR_ACK_DELAY) == 0) { +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + if (datarate > LORAMAC_TX_MIN_DATARATE) { + datarate--; + } + + if (datarate == LORAMAC_TX_MIN_DATARATE) { + if (isTx == true) { + // Re-enable default channels LC1, LC2, LC3 + ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3)); + } + } +#elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + if (datarate > LORAMAC_TX_MIN_DATARATE) { + if (datarate == DR_8) + datarate = DR_4; + else + datarate--; + } + else if (isTx == true) { +#if defined(USE_BAND_915) + // Re-enable default channels + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0x00FF; + ChannelsMask[5] = 0x0000; +#else // defined( USE_BAND_915_HYBRID ) + // Re-enable default channels + ChannelsMask[0] = 0x00FF; + ChannelsMask[1] = 0x0000; + ChannelsMask[2] = 0x0000; + ChannelsMask[3] = 0x0000; + ChannelsMask[4] = 0x0001; + ChannelsMask[5] = 0x0000; #endif - } + } #else #error "Please define a frequency band in the compiler options." #endif - } - } + } } - - if(datarateOut != NULL) - *datarateOut = datarate; - - if(txpowerOut != NULL) - *txpowerOut = txpower; - - return adrAckReq; - + } + + if (datarateOut != NULL) + *datarateOut = datarate; + + if (txpowerOut != NULL) + *txpowerOut = txpower; + + return adrAckReq; } -static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 ) -{ - LoRaMacStatus_t status = LORAMAC_STATUS_BUSY; - // The maximum buffer length must take MAC commands to re-send into account. - uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex; - - switch( cmd ) - { - case MOTE_MAC_LINK_CHECK_REQ: - if( MacCommandsBufferIndex < bufLen ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // No payload for this command - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_LINK_ADR_ANS: - if( MacCommandsBufferIndex < ( bufLen - 1 ) ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // Margin - MacCommandsBuffer[MacCommandsBufferIndex++] = p1; - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_DUTY_CYCLE_ANS: - if( MacCommandsBufferIndex < bufLen ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // No payload for this answer - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_RX_PARAM_SETUP_ANS: - if( MacCommandsBufferIndex < ( bufLen - 1 ) ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // Status: Datarate ACK, Channel ACK - MacCommandsBuffer[MacCommandsBufferIndex++] = p1; - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_DEV_STATUS_ANS: - if( MacCommandsBufferIndex < ( bufLen - 2 ) ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // 1st byte Battery - // 2nd byte Margin - MacCommandsBuffer[MacCommandsBufferIndex++] = p1; - MacCommandsBuffer[MacCommandsBufferIndex++] = p2; - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_NEW_CHANNEL_ANS: - if( MacCommandsBufferIndex < ( bufLen - 1 ) ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // Status: Datarate range OK, Channel frequency OK - MacCommandsBuffer[MacCommandsBufferIndex++] = p1; - status = LORAMAC_STATUS_OK; - } - break; - case MOTE_MAC_RX_TIMING_SETUP_ANS: - if( MacCommandsBufferIndex < bufLen ) - { - MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; - // No payload for this answer - status = LORAMAC_STATUS_OK; - } - break; - default: - return LORAMAC_STATUS_SERVICE_UNKNOWN; +static LoRaMacStatus_t AddMacCommand(uint8_t cmd, uint8_t p1, uint8_t p2) { + LoRaMacStatus_t status = LORAMAC_STATUS_BUSY; + // The maximum buffer length must take MAC commands to re-send into account. + uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex; + + switch (cmd) { + case MOTE_MAC_LINK_CHECK_REQ: + if (MacCommandsBufferIndex < bufLen) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this command + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_LINK_ADR_ANS: + if (MacCommandsBufferIndex < (bufLen - 1)) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Margin + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_DUTY_CYCLE_ANS: + if (MacCommandsBufferIndex < bufLen) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this answer + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_RX_PARAM_SETUP_ANS: + if (MacCommandsBufferIndex < (bufLen - 1)) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Status: Datarate ACK, Channel ACK + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_DEV_STATUS_ANS: + if (MacCommandsBufferIndex < (bufLen - 2)) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // 1st byte Battery + // 2nd byte Margin + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + MacCommandsBuffer[MacCommandsBufferIndex++] = p2; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_NEW_CHANNEL_ANS: + if (MacCommandsBufferIndex < (bufLen - 1)) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Status: Datarate range OK, Channel frequency OK + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_RX_TIMING_SETUP_ANS: + if (MacCommandsBufferIndex < bufLen) { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this answer + status = LORAMAC_STATUS_OK; + } + break; + default: + return LORAMAC_STATUS_SERVICE_UNKNOWN; + } + if (status == LORAMAC_STATUS_OK) { + MacCommandsInNextTx = true; + } + return status; +} + +static uint8_t ParseMacCommandsToRepeat(uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut) { + uint8_t i = 0; + uint8_t cmdCount = 0; + + if ((cmdBufIn == NULL) || (cmdBufOut == NULL)) { + return 0; + } + + for (i = 0; i < length; i++) { + switch (cmdBufIn[i]) { + case MOTE_MAC_RX_PARAM_SETUP_ANS: { + cmdBufOut[cmdCount++] = cmdBufIn[i++]; + cmdBufOut[cmdCount++] = cmdBufIn[i++]; + cmdBufOut[cmdCount++] = cmdBufIn[i]; + break; + } + case MOTE_MAC_RX_TIMING_SETUP_ANS: { + cmdBufOut[cmdCount++] = cmdBufIn[i]; + break; + } + default: + break; } - if( status == LORAMAC_STATUS_OK ) - { - MacCommandsInNextTx = true; - } - return status; -} - -static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut ) -{ - uint8_t i = 0; - uint8_t cmdCount = 0; - - if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) ) - { - return 0; - } - - for( i = 0; i < length; i++ ) - { - switch( cmdBufIn[i] ) - { - case MOTE_MAC_RX_PARAM_SETUP_ANS: - { - cmdBufOut[cmdCount++] = cmdBufIn[i++]; - cmdBufOut[cmdCount++] = cmdBufIn[i++]; - cmdBufOut[cmdCount++] = cmdBufIn[i]; - break; - } - case MOTE_MAC_RX_TIMING_SETUP_ANS: - { - cmdBufOut[cmdCount++] = cmdBufIn[i]; - break; - } - default: - break; - } - } - - return cmdCount; + } + + return cmdCount; } -static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr ) -{ - uint8_t validLinkAdrCmds = 0; - int8_t txPower = 0; - int8_t datarate = 0; - uint8_t nbRep = 0; - uint16_t channelsMask[6] = {0,0,0,0,0,0}; - uint8_t LinkAdrMacCmdBufferIndex = 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++]; - break; - case SRV_MAC_LINK_ADR_REQ: - { - uint8_t chMaskCntl = 0; - uint8_t status = 0x07; - uint16_t chMask; - - datarate = payload[macIndex++]; - txPower = datarate & 0x0F; - datarate = ( datarate >> 4 ) & 0x0F; - - if( ( AdrCtrlOn == false ) && - ( ( ChannelsDatarate != datarate ) || ( ChannelsTxPower != txPower ) ) ) - { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower - // Answer the server with fail status - // 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; - } - else if ( validLinkAdrCmds++ == 0 ) - { - // Initialize local copy of the channels mask array - for(uint8_t i = 0; i < 6; i++ ) - { - channelsMask[i] = ChannelsMask[i]; - } - } - - - 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_915 ) || defined( USE_BAND_915_HYBRID ) - if( chMaskCntl < 4 ) - { - channelsMask[chMaskCntl] = chMask; - } - else if( chMaskCntl == 6 ) - { - // Enable all 125 kHz channels - for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ ) - { - for( uint8_t j = 0; j < 16; j++ ) - { - if( Channels[i + j].Frequency != 0 ) - { - channelsMask[k] |= 1 << j; - } - } - } - // channel mask applied to 500 kHz channels - channelsMask[4] = chMask; - } - else if( chMaskCntl == 7 ) - { - // Disable all 125 kHz channels - channelsMask[0] = 0x0000; - channelsMask[1] = 0x0000; - channelsMask[2] = 0x0000; - channelsMask[3] = 0x0000; - - // channel mask applied to 500 kHz channels - channelsMask[4] = chMask; - } - else - { - // RFU - status &= 0xFE; // Channel mask KO - } +static void ProcessMacCommands(uint8_t* payload, uint8_t macIndex, uint8_t commandsSize, + uint8_t snr) { + uint8_t validLinkAdrCmds = 0; + int8_t txPower = 0; + int8_t datarate = 0; + uint8_t nbRep = 0; + uint16_t channelsMask[6] = {0, 0, 0, 0, 0, 0}; + uint8_t LinkAdrMacCmdBufferIndex = 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++]; + break; + case SRV_MAC_LINK_ADR_REQ: { + uint8_t chMaskCntl = 0; + uint8_t status = 0x07; + uint16_t chMask; + + datarate = payload[macIndex++]; + txPower = datarate & 0x0F; + datarate = (datarate >> 4) & 0x0F; + + if ((AdrCtrlOn == false) && + ((ChannelsDatarate != datarate) || + (ChannelsTxPower != txPower))) { // ADR disabled don't handle ADR + // requests if server tries to + // change datarate or txpower + // Answer the server with fail status + // 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; + } + else if (validLinkAdrCmds++ == 0) { + // Initialize local copy of the channels mask array + for (uint8_t i = 0; i < 6; i++) { + channelsMask[i] = ChannelsMask[i]; + } + } + + 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_915) || defined(USE_BAND_915_HYBRID) + if (chMaskCntl < 4) { + channelsMask[chMaskCntl] = chMask; + } + else if (chMaskCntl == 6) { + // Enable all 125 kHz channels + for (uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++) { + for (uint8_t j = 0; j < 16; j++) { + if (Channels[i + j].Frequency != 0) { + channelsMask[k] |= 1 << j; + } + } + } + // channel mask applied to 500 kHz channels + channelsMask[4] = chMask; + } + else if (chMaskCntl == 7) { + // Disable all 125 kHz channels + channelsMask[0] = 0x0000; + channelsMask[1] = 0x0000; + channelsMask[2] = 0x0000; + channelsMask[3] = 0x0000; + + // channel mask applied to 500 kHz channels + channelsMask[4] = chMask; + } + else { + // RFU + status &= 0xFE; // Channel mask KO + } #else - #error "Please define a frequency band in the compiler options." +#error "Please define a frequency band in the compiler options." #endif - if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == 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 - } - - - // Save the mac command status location for possible channel mask KO later - LinkAdrMacCmdBufferIndex = MacCommandsBufferIndex; - - AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 ); - } - break; - case SRV_MAC_DUTY_CYCLE_REQ: - MaxDCycle = payload[macIndex++]; - AggregatedDCycle = 1 << MaxDCycle; - AddMacCommand( MOTE_MAC_DUTY_CYCLE_ANS, 0, 0 ); - break; - case SRV_MAC_RX_PARAM_SETUP_REQ: - { - 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; - 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 - } + if (ValueInRange(datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) == 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 + } + + // Save the mac command status location for possible channel mask KO + // later + LinkAdrMacCmdBufferIndex = MacCommandsBufferIndex; + + AddMacCommand(MOTE_MAC_LINK_ADR_ANS, status, 0); + } break; + case SRV_MAC_DUTY_CYCLE_REQ: + MaxDCycle = payload[macIndex++]; + AggregatedDCycle = 1 << MaxDCycle; + AddMacCommand(MOTE_MAC_DUTY_CYCLE_ANS, 0, 0); + break; + case SRV_MAC_RX_PARAM_SETUP_REQ: { + 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; + 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 - } - - if( ( status & 0x07 ) == 0x07 ) - { - Rx2Channel.Datarate = datarate; - Rx2Channel.Frequency = freq; - Rx1DrOffset = drOffset; - } - AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 ); - } - break; - case SRV_MAC_DEV_STATUS_REQ: - { - uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE; - if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) ) - { - batteryLevel = LoRaMacCallbacks->GetBatteryLevel( ); - } - AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr ); - break; - } - case SRV_MAC_NEW_CHANNEL_REQ: - { - uint8_t status = 0x03; - -#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - status &= 0xFC; // Channel frequency and datarate KO - macIndex += 5; + if (ValueInRange(drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET) == false) { + status &= 0xFB; // Rx1DrOffset range KO + } + + if ((status & 0x07) == 0x07) { + Rx2Channel.Datarate = datarate; + Rx2Channel.Frequency = freq; + Rx1DrOffset = drOffset; + } + AddMacCommand(MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0); + } break; + case SRV_MAC_DEV_STATUS_REQ: { + uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE; + if ((LoRaMacCallbacks != NULL) && (LoRaMacCallbacks->GetBatteryLevel != NULL)) { + batteryLevel = LoRaMacCallbacks->GetBatteryLevel(); + } + AddMacCommand(MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr); + break; + } + case SRV_MAC_NEW_CHANNEL_REQ: { + uint8_t status = 0x03; + +#if (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)) + status &= 0xFC; // Channel frequency and datarate KO + macIndex += 5; #else - int8_t channelIndex = 0; - ChannelParams_t chParam; - - channelIndex = payload[macIndex++]; - chParam.Frequency = ( uint32_t )payload[macIndex++]; - chParam.Frequency |= ( uint32_t )payload[macIndex++] << 8; - chParam.Frequency |= ( uint32_t )payload[macIndex++] << 16; - chParam.Frequency *= 100; - chParam.DrRange.Value = payload[macIndex++]; - - LoRaMacState |= MAC_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 &= ~MAC_TX_CONFIG; + int8_t channelIndex = 0; + ChannelParams_t chParam; + + channelIndex = payload[macIndex++]; + chParam.Frequency = (uint32_t)payload[macIndex++]; + chParam.Frequency |= (uint32_t)payload[macIndex++] << 8; + chParam.Frequency |= (uint32_t)payload[macIndex++] << 16; + chParam.Frequency *= 100; + chParam.DrRange.Value = payload[macIndex++]; + + LoRaMacState |= MAC_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 &= ~MAC_TX_CONFIG; #endif - AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 ); - } - break; - case SRV_MAC_RX_TIMING_SETUP_REQ: - { - uint8_t delay = payload[macIndex++] & 0x0F; - - if( delay == 0 ) - { - delay++; - } - ReceiveDelay1 = delay * 1e6; - ReceiveDelay2 = ReceiveDelay1 + 1e6; - AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 ); - } - break; - default: - // Unknown command. ABORT MAC commands processing - return; + AddMacCommand(MOTE_MAC_NEW_CHANNEL_ANS, status, 0); + } break; + case SRV_MAC_RX_TIMING_SETUP_REQ: { + uint8_t delay = payload[macIndex++] & 0x0F; + + if (delay == 0) { + delay++; } + ReceiveDelay1 = delay * 1e6; + ReceiveDelay2 = ReceiveDelay1 + 1e6; + AddMacCommand(MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0); + } break; + default: + // Unknown command. ABORT MAC commands processing + return; } - - // Process accumulated Link ADR channel mask changes - if( validLinkAdrCmds > 0 ) - { - uint8_t drOkCounter = 0; - uint8_t status = 0x07; - -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - for(uint8_t i=0; i< 6; i++) - { - for( uint8_t j = 0; j < 16; j++ ) - { - if( ( channelsMask[i] & ( 1 << j ) ) != 0 ) - { - if ( ( Channels[i * 16 + j].Frequency == 0 ) ) - { - status &= 0xFE; // Channel mask KO - break; - } - else if( ( datarate >= Channels[i * 16 + j].DrRange.Fields.Min ) && - ( datarate <= Channels[i * 16 + j].DrRange.Fields.Max ) ) - { - drOkCounter++; - } - } - } + } + + // Process accumulated Link ADR channel mask changes + if (validLinkAdrCmds > 0) { + uint8_t drOkCounter = 0; + uint8_t status = 0x07; + +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + for (uint8_t i = 0; i < 6; i++) { + for (uint8_t j = 0; j < 16; j++) { + if ((channelsMask[i] & (1 << j)) != 0) { + if ((Channels[i * 16 + j].Frequency == 0)) { + status &= 0xFE; // Channel mask KO + break; + } + else if ((datarate >= Channels[i * 16 + j].DrRange.Fields.Min) && + (datarate <= Channels[i * 16 + j].DrRange.Fields.Max)) { + drOkCounter++; + } } - - if ( drOkCounter == 0 ) - { - status &= 0xFD; // Datarate KO - } - - if( ( CountNbEnabled125kHzChannels( channelsMask ) > 0 ) && ( CountNbEnabled125kHzChannels( channelsMask ) < HYBRD_CHNLS_MIN ) ) - { - status &= 0xFE; // Channel mask KO - } - -#if defined( USE_BAND_915_HYBRID ) - if( ValidateChannelMask( channelsMask ) == false ) - { - status &= 0xFE; // Channel mask KO - } + } + } + + if (drOkCounter == 0) { + status &= 0xFD; // Datarate KO + } + + if ((CountNbEnabled125kHzChannels(channelsMask) > 0) && + (CountNbEnabled125kHzChannels(channelsMask) < HYBRD_CHNLS_MIN)) { + status &= 0xFE; // Channel mask KO + } + +#if defined(USE_BAND_915_HYBRID) + if (ValidateChannelMask(channelsMask) == false) { + status &= 0xFE; // Channel mask KO + } #endif #endif - if( ( status & 0x07 ) == 0x07 ) - { - ChannelsDatarate = datarate; - ChannelsDefaultDatarate = datarate; - ChannelsTxPower = txPower; - - ChannelsMask[0] = channelsMask[0]; - ChannelsMask[1] = channelsMask[1]; - ChannelsMask[2] = channelsMask[2]; - ChannelsMask[3] = channelsMask[3]; - ChannelsMask[4] = channelsMask[4]; - ChannelsMask[5] = channelsMask[5]; - - ChannelsNbRep = nbRep; - - // Clear remaining channels mask - memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask, 10 ); - } - // Channel Mask KO - else - { - // Update the last Link ADR status with channel mask KO - if( (LinkAdrMacCmdBufferIndex+1 ) < LORA_MAC_COMMAND_MAX_LENGTH ) - MacCommandsBuffer[LinkAdrMacCmdBufferIndex+1] &= status; - } - } -} - -LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) -{ - LoRaMacFrameCtrl_t fCtrl; - LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID; - - fCtrl.Value = 0; - fCtrl.Bits.FOptsLen = 0; - fCtrl.Bits.FPending = 0; - fCtrl.Bits.Ack = false; - fCtrl.Bits.AdrAckReq = false; - fCtrl.Bits.Adr = AdrCtrlOn; - - // Prepare the frame - status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize ); - - // Validate status - if( status != LORAMAC_STATUS_OK ) - { - return status; - } - - // Reset confirm parameters - McpsConfirm.NbRetries = 0; - McpsConfirm.AckReceived = false; - McpsConfirm.UpLinkCounter = UpLinkCounter; - - status = ScheduleTx( ); - - return status; -} - -static LoRaMacStatus_t ScheduleTx( ) -{ - TimerTime_t dutyCycleTimeOff = 0; - - // Check if the device is off - if( MaxDCycle == 255 ) - { - return LORAMAC_STATUS_DEVICE_OFF; - } - if( MaxDCycle == 0 ) - { - AggregatedTimeOff = 0; + if ((status & 0x07) == 0x07) { + ChannelsDatarate = datarate; + ChannelsDefaultDatarate = datarate; + ChannelsTxPower = txPower; + + ChannelsMask[0] = channelsMask[0]; + ChannelsMask[1] = channelsMask[1]; + ChannelsMask[2] = channelsMask[2]; + ChannelsMask[3] = channelsMask[3]; + ChannelsMask[4] = channelsMask[4]; + ChannelsMask[5] = channelsMask[5]; + + ChannelsNbRep = nbRep; + + // Clear remaining channels mask + memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, 10); } - - CalculateBackOff( LastTxChannel ); - - // Select channel - while( SetNextChannel( &dutyCycleTimeOff ) == false ) - { - // Set the default datarate - ChannelsDatarate = ChannelsDefaultDatarate; - -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - // Re-enable default channels LC1, LC2, LC3 - ChannelsMask[0] = ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); -#endif - } - - // Schedule transmission of frame - if( dutyCycleTimeOff == 0 ) - { - // Try to send now - return SendFrameOnChannel( Channels[Channel] ); - } - else - { - // Send later - prepare timer - LoRaMacState |= MAC_TX_DELAYED; - TimerSetValue( &TxDelayedTimer, dutyCycleTimeOff ); - TimerStart( &TxDelayedTimer ); - - return LORAMAC_STATUS_OK; - } -} - -static void CalculateBackOff( uint8_t channel ) -{ - uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle; - - if( IsLoRaMacNetworkJoined == false ) - { -#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) - dutyCycle = JOIN_DC; -#endif - } - - // Update Band Time OFF - if( DutyCycleOn == true ) - { - Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; - } - else - { - Bands[Channels[channel].Band].TimeOff = 0; - } - // Update Aggregated Time OFF - AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir ); -} - -LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) -{ - uint16_t i; - uint8_t pktHeaderLen = 0; - uint32_t mic = 0; - const void* payload = fBuffer; - uint8_t payloadSize = fBufferSize; - uint8_t framePort = fPort; - - LoRaMacBufferPktLen = 0; - - NodeAckRequested = false; - - if( fBuffer == NULL ) - { - fBufferSize = 0; + // Channel Mask KO + else { + // Update the last Link ADR status with channel mask KO + if ((LinkAdrMacCmdBufferIndex + 1) < LORA_MAC_COMMAND_MAX_LENGTH) + MacCommandsBuffer[LinkAdrMacCmdBufferIndex + 1] &= status; } - - LoRaMacBuffer[pktHeaderLen++] = macHdr->Value; - - switch( macHdr->Bits.MType ) - { - case FRAME_TYPE_JOIN_REQ: - RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME; - RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME; - - LoRaMacBufferPktLen = pktHeaderLen; - - memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 ); - LoRaMacBufferPktLen += 8; - memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8 ); - LoRaMacBufferPktLen += 8; - - LoRaMacDevNonce = Radio.Random( ); - - LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF; - - LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic ); - - LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF; - - break; - case FRAME_TYPE_DATA_CONFIRMED_UP: - NodeAckRequested = true; - //Intentional falltrough - case FRAME_TYPE_DATA_UNCONFIRMED_UP: - if( IsLoRaMacNetworkJoined == false ) - { - return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet - } - - fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &ChannelsDatarate, &ChannelsTxPower ); - - if( ValidatePayloadLength( fBufferSize, ChannelsDatarate, MacCommandsBufferIndex ) == false ) - { - return LORAMAC_STATUS_LENGTH_ERROR; - } - - RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME; - RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME; - - if( SrvAckRequested == true ) - { - SrvAckRequested = false; - fCtrl->Bits.Ack = 1; - } - - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF; - - LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value; - - LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF; - LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF; - - // Copy the MAC commands which must be re-send into the MAC command buffer - memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex ); - MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex; - - if( ( payload != NULL ) && ( payloadSize > 0 ) ) - { - if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) ) - { - fCtrl->Bits.FOptsLen += MacCommandsBufferIndex; - - // Update FCtrl field with new value of OptionsLength - LoRaMacBuffer[0x05] = fCtrl->Value; - for( i = 0; i < MacCommandsBufferIndex; i++ ) - { - LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i]; - } - } - } - else - { - if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) ) - { - payloadSize = MacCommandsBufferIndex; - payload = MacCommandsBuffer; - framePort = 0; - } - } - MacCommandsInNextTx = false; - // Store MAC commands which must be re-send in case the device does not receive a downlink anymore - MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat ); - if( MacCommandsBufferToRepeatIndex > 0 ) - { - MacCommandsInNextTx = true; - } - MacCommandsBufferIndex = 0; - - if( ( payload != NULL ) && ( payloadSize > 0 ) ) - { - LoRaMacBuffer[pktHeaderLen++] = framePort; - - if( framePort == 0 ) - { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload ); - } - else - { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload ); - } - memcpy1( LoRaMacBuffer + pktHeaderLen, LoRaMacPayload, payloadSize ); - } - LoRaMacBufferPktLen = pktHeaderLen + payloadSize; - - LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic ); - - LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF; - LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF; - - LoRaMacBufferPktLen += LORAMAC_MFR_LEN; - - break; - case FRAME_TYPE_PROPRIETARY: - if( ( fBuffer != NULL ) && ( fBufferSize > 0 ) ) - { - memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, fBufferSize ); - LoRaMacBufferPktLen = pktHeaderLen + fBufferSize; - } - break; - default: - return LORAMAC_STATUS_SERVICE_UNKNOWN; - } - - return LORAMAC_STATUS_OK; + } } -LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ) -{ - int8_t datarate = Datarates[ChannelsDatarate]; - int8_t txPowerIndex = 0; - int8_t txPower = 0; - - txPowerIndex = LimitTxPower( ChannelsTxPower ); - txPower = TxPowers[txPowerIndex]; - - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; - McpsConfirm.Datarate = ChannelsDatarate; - McpsConfirm.TxPower = txPowerIndex; - - Radio.SetChannel( channel.Frequency ); - -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - if( ChannelsDatarate == DR_7 ) - { // High Speed FSK channel - Radio.SetMaxPayloadLength( MODEM_FSK, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e6 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen ); - - } - else if( ChannelsDatarate == DR_6 ) - { // High speed LoRa channel - Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } - else - { // Normal LoRa channel - Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - if( ChannelsDatarate >= DR_4 ) - { // High speed LoRa channel BW500 kHz - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } - else - { // Normal LoRa channel - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); - TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); - } -#else - #error "Please define a frequency band in the compiler options." -#endif - - // Store the time on air - McpsConfirm.TxTimeOnAir = TxTimeOnAir; - MlmeConfirm.TxTimeOnAir = TxTimeOnAir; - - // Starts the MAC layer status check timer - TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); - TimerStart( &MacStateCheckTimer ); - - // Send now - Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen ); - - LoRaMacState |= MAC_TX_RUNNING; - - return LORAMAC_STATUS_OK; +LoRaMacStatus_t Send(LoRaMacHeader_t* macHdr, uint8_t fPort, void* fBuffer, uint16_t fBufferSize) { + LoRaMacFrameCtrl_t fCtrl; + LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID; + + fCtrl.Value = 0; + fCtrl.Bits.FOptsLen = 0; + fCtrl.Bits.FPending = 0; + fCtrl.Bits.Ack = false; + fCtrl.Bits.AdrAckReq = false; + fCtrl.Bits.Adr = AdrCtrlOn; + + // Prepare the frame + status = PrepareFrame(macHdr, &fCtrl, fPort, fBuffer, fBufferSize); + + // Validate status + if (status != LORAMAC_STATUS_OK) { + return status; + } + + // Reset confirm parameters + McpsConfirm.NbRetries = 0; + McpsConfirm.AckReceived = false; + McpsConfirm.UpLinkCounter = UpLinkCounter; + + status = ScheduleTx(); + + return status; } - -LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks ) -{ - if( primitives == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - if( ( primitives->MacMcpsConfirm == NULL ) || - ( primitives->MacMcpsIndication == NULL ) || - ( primitives->MacMlmeConfirm == NULL )) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - LoRaMacPrimitives = primitives; - LoRaMacCallbacks = callbacks; - - LoRaMacFlags.Value = 0; - - LoRaMacDeviceClass = CLASS_A; - - UpLinkCounter = 1; - DownLinkCounter = 0; - AdrAckCounter = 0; - - ChannelsNbRepCounter = 0; - - AckTimeoutRetries = 1; - AckTimeoutRetriesCounter = 1; - AckTimeoutRetry = false; - - MaxDCycle = 0; - AggregatedDCycle = 1; - - MacCommandsBufferIndex = 0; - MacCommandsBufferToRepeatIndex = 0; - - IsRxWindowsEnabled = true; - - RepeaterSupport = false; - IsRxWindowsEnabled = true; - IsLoRaMacNetworkJoined = false; - LoRaMacState = MAC_IDLE; - - NodeAckRequested = false; - SrvAckRequested = false; - MacCommandsInNextTx = false; - -#if defined( USE_BAND_433 ) - ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); -#elif defined( USE_BAND_780 ) - ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); -#elif defined( USE_BAND_868 ) - ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); -#elif defined( USE_BAND_915 ) - ChannelsMask[0] = 0xFFFF; - ChannelsMask[1] = 0xFFFF; - ChannelsMask[2] = 0xFFFF; - ChannelsMask[3] = 0xFFFF; - ChannelsMask[4] = 0x00FF; - ChannelsMask[5] = 0x0000; - - memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask, sizeof( ChannelsMask ) ); -#elif defined( USE_BAND_915_HYBRID ) - ChannelsMask[0] = 0x00FF; - ChannelsMask[1] = 0x0000; - ChannelsMask[2] = 0x0000; - ChannelsMask[3] = 0x0000; - ChannelsMask[4] = 0x0001; - ChannelsMask[5] = 0x0000; - - memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) ChannelsMask, sizeof( ChannelsMask ) ); -#else - #error "Please define a frequency band in the compiler options." -#endif - -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - // 125 kHz channels - for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ ) - { - 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; - } +static LoRaMacStatus_t ScheduleTx() { + TimerTime_t dutyCycleTimeOff = 0; + + // Check if the device is off + if (MaxDCycle == 255) { + return LORAMAC_STATUS_DEVICE_OFF; + } + if (MaxDCycle == 0) { + AggregatedTimeOff = 0; + } + + CalculateBackOff(LastTxChannel); + + // Select channel + while (SetNextChannel(&dutyCycleTimeOff) == false) { + // Set the default datarate + ChannelsDatarate = ChannelsDefaultDatarate; + +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + // Re-enable default channels LC1, LC2, LC3 + ChannelsMask[0] = ChannelsMask[0] | (LC(1) + LC(2) + LC(3)); #endif - - ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; - ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE; - ChannelsNbRep = 1; - ChannelsNbRepCounter = 0; - - Rx2Channel.Frequency = 923300000; - Rx2Channel.Datarate = DR_8; - Rx1DrOffset = 0; - - - MaxDCycle = 0; - AggregatedDCycle = 1; - AggregatedLastTxDoneTime = 0; - AggregatedTimeOff = 0; - -#if defined( USE_BAND_433 ) - DutyCycleOn = false; -#elif defined( USE_BAND_780 ) - DutyCycleOn = false; -#elif defined( USE_BAND_868 ) - DutyCycleOn = true; -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - DutyCycleOn = false; -#else - #error "Please define a frequency band in the compiler options." -#endif - - MaxRxWindow = MAX_RX_WINDOW; - ReceiveDelay1 = RECEIVE_DELAY1; - ReceiveDelay2 = RECEIVE_DELAY2; - JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1; - JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2; - -#if defined( USE_BAND_915 ) - NextJoinBlock = 0; - LastJoinBlock = -1; - JoinBlocksRemaining = 0xff; - Join500KHzRemaining = 0xff; -#endif - - LastJoinTxTime = 0; - JoinAggTimeOnAir = 0; - - TimerInit( &MacStateCheckTimer, OnMacStateCheckTimerEvent ); - TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); - - TimerInit( &TxDelayedTimer, OnTxDelayedTimerEvent ); - TimerInit( &RxWindowTimer1, OnRxWindow1TimerEvent ); - TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent ); - TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent ); - - // Initialize Radio driver - RadioEvents.TxDone = OnRadioTxDone; - RadioEvents.RxDone = OnRadioRxDone; - RadioEvents.RxError = OnRadioRxError; - RadioEvents.TxTimeout = OnRadioTxTimeout; - RadioEvents.RxTimeout = OnRadioRxTimeout; - Radio.Init( &RadioEvents ); - - // Random seed initialization - srand1( Radio.Random( ) ); - - // Initialize channel index. - Channel = LORA_MAX_NB_CHANNELS; - - PublicNetwork = true; - SetPublicNetwork( PublicNetwork ); - Radio.Sleep( ); - - return LORAMAC_STATUS_OK; -} - -LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo ) -{ - int8_t datarate = ChannelsDefaultDatarate; - uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex; - - if( txInfo == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - AdrNextDr( AdrCtrlOn, false, &datarate, NULL ); - - if( RepeaterSupport == true ) - { - txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate]; - } - else - { - txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate]; - } - - if( txInfo->CurrentPayloadSize >= fOptLen ) - { - txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen; - } - else - { - return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR; - } - - if( ValidatePayloadLength( size, datarate, 0 ) == false ) - { - return LORAMAC_STATUS_LENGTH_ERROR; - } - - if( ValidatePayloadLength( size, datarate, fOptLen ) == false ) - { - return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR; - } + } + + // Schedule transmission of frame + if (dutyCycleTimeOff == 0) { + // Try to send now + return SendFrameOnChannel(Channels[Channel]); + } + else { + // Send later - prepare timer + LoRaMacState |= MAC_TX_DELAYED; + TimerSetValue(&TxDelayedTimer, dutyCycleTimeOff); + TimerStart(&TxDelayedTimer); return LORAMAC_STATUS_OK; + } } -LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet ) -{ - LoRaMacStatus_t status = LORAMAC_STATUS_OK; - - if( mibGet == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - switch( mibGet->Type ) - { - case MIB_DEVICE_CLASS: - { - mibGet->Param.Class = LoRaMacDeviceClass; - break; - } - case MIB_NETWORK_JOINED: - { - mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined; - break; - } - case MIB_ADR: - { - mibGet->Param.AdrEnable = AdrCtrlOn; - break; - } - case MIB_NET_ID: - { - mibGet->Param.NetID = LoRaMacNetID; - break; - } - case MIB_DEV_ADDR: - { - mibGet->Param.DevAddr = LoRaMacDevAddr; - break; - } - case MIB_NWK_SKEY: - { - mibGet->Param.NwkSKey = LoRaMacNwkSKey; - break; - } - case MIB_APP_SKEY: - { - mibGet->Param.AppSKey = LoRaMacAppSKey; - break; - } - case MIB_PUBLIC_NETWORK: - { - mibGet->Param.EnablePublicNetwork = PublicNetwork; - break; - } - case MIB_REPEATER_SUPPORT: - { - mibGet->Param.EnableRepeaterSupport = RepeaterSupport; - break; - } - case MIB_CHANNELS: - { - mibGet->Param.ChannelList = Channels; - break; - } - case MIB_RX2_CHANNEL: - { - mibGet->Param.Rx2Channel = Rx2Channel; - break; - } - case MIB_CHANNELS_MASK: - { - mibGet->Param.ChannelsMask = ChannelsMask; - break; - } - case MIB_CHANNELS_NB_REP: - { - mibGet->Param.ChannelNbRep = ChannelsNbRep; - break; - } - case MIB_MAX_RX_WINDOW_DURATION: - { - mibGet->Param.MaxRxWindow = MaxRxWindow; - break; - } - case MIB_RECEIVE_DELAY_1: - { - mibGet->Param.ReceiveDelay1 = ReceiveDelay1; - break; - } - case MIB_RECEIVE_DELAY_2: - { - mibGet->Param.ReceiveDelay2 = ReceiveDelay2; - break; - } - case MIB_JOIN_ACCEPT_DELAY_1: - { - mibGet->Param.JoinAcceptDelay1 = JoinAcceptDelay1; - break; - } - case MIB_JOIN_ACCEPT_DELAY_2: - { - mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2; - break; - } - case MIB_CHANNELS_DEFAULT_DATARATE: - { - mibGet->Param.ChannelsDefaultDatarate = ChannelsDefaultDatarate; - break; +static void CalculateBackOff(uint8_t channel) { + uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle; + + if (IsLoRaMacNetworkJoined == false) { +#if defined(USE_BAND_868) || defined(USE_BAND_433) || defined(USE_BAND_780) + dutyCycle = JOIN_DC; +#endif + } + + // Update Band Time OFF + if (DutyCycleOn == true) { + Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; + } + else { + Bands[Channels[channel].Band].TimeOff = 0; + } + // Update Aggregated Time OFF + AggregatedTimeOff = AggregatedTimeOff + (TxTimeOnAir * AggregatedDCycle - TxTimeOnAir); +} + +LoRaMacStatus_t PrepareFrame(LoRaMacHeader_t* macHdr, LoRaMacFrameCtrl_t* fCtrl, uint8_t fPort, + void* fBuffer, uint16_t fBufferSize) { + uint16_t i; + uint8_t pktHeaderLen = 0; + uint32_t mic = 0; + const void* payload = fBuffer; + uint8_t payloadSize = fBufferSize; + uint8_t framePort = fPort; + + LoRaMacBufferPktLen = 0; + + NodeAckRequested = false; + + if (fBuffer == NULL) { + fBufferSize = 0; + } + + LoRaMacBuffer[pktHeaderLen++] = macHdr->Value; + + switch (macHdr->Bits.MType) { + case FRAME_TYPE_JOIN_REQ: + RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME; + RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME; + + LoRaMacBufferPktLen = pktHeaderLen; + + memcpyr(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8); + LoRaMacBufferPktLen += 8; + memcpyr(LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8); + LoRaMacBufferPktLen += 8; + + LoRaMacDevNonce = Radio.Random(); + + LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = (LoRaMacDevNonce >> 8) & 0xFF; + + LoRaMacJoinComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic); + + LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 8) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 16) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = (mic >> 24) & 0xFF; + + break; + case FRAME_TYPE_DATA_CONFIRMED_UP: + NodeAckRequested = true; + // Intentional falltrough + case FRAME_TYPE_DATA_UNCONFIRMED_UP: + if (IsLoRaMacNetworkJoined == false) { + return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined + // yet + } + + fCtrl->Bits.AdrAckReq = AdrNextDr(fCtrl->Bits.Adr, true, &ChannelsDatarate, &ChannelsTxPower); + + if (ValidatePayloadLength(fBufferSize, ChannelsDatarate, MacCommandsBufferIndex) == false) { + return LORAMAC_STATUS_LENGTH_ERROR; + } + + RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME; + RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME; + + if (SrvAckRequested == true) { + SrvAckRequested = false; + fCtrl->Bits.Ack = 1; + } + + LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr)&0xFF; + LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 8) & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 16) & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = (LoRaMacDevAddr >> 24) & 0xFF; + + LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value; + + LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = (UpLinkCounter >> 8) & 0xFF; + + // Copy the MAC commands which must be re-send into the MAC command buffer + memcpy1(&MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, + MacCommandsBufferToRepeatIndex); + MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex; + + if ((payload != NULL) && (payloadSize > 0)) { + if ((MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH) && + (MacCommandsInNextTx == true)) { + fCtrl->Bits.FOptsLen += MacCommandsBufferIndex; + + // Update FCtrl field with new value of OptionsLength + LoRaMacBuffer[0x05] = fCtrl->Value; + for (i = 0; i < MacCommandsBufferIndex; i++) { + LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i]; + } } - case MIB_CHANNELS_DATARATE: - { - mibGet->Param.ChannelsDatarate = ChannelsDatarate; - break; - } - case MIB_CHANNELS_TX_POWER: - { - mibGet->Param.ChannelsTxPower = ChannelsTxPower; - break; - } - case MIB_UPLINK_COUNTER: - { - mibGet->Param.UpLinkCounter = UpLinkCounter; - break; - } - case MIB_DOWNLINK_COUNTER: - { - mibGet->Param.DownLinkCounter = DownLinkCounter; - break; - } - case MIB_MULTICAST_CHANNEL: - { - mibGet->Param.MulticastList = MulticastChannels; - break; + } + else { + if ((MacCommandsBufferIndex > 0) && (MacCommandsInNextTx)) { + payloadSize = MacCommandsBufferIndex; + payload = MacCommandsBuffer; + framePort = 0; } - default: - status = LORAMAC_STATUS_SERVICE_UNKNOWN; - break; - } - - return status; -} - -LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet ) -{ - LoRaMacStatus_t status = LORAMAC_STATUS_OK; - - if( mibSet == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - return LORAMAC_STATUS_BUSY; - } - - switch( mibSet->Type ) - { - case MIB_DEVICE_CLASS: - { - LoRaMacDeviceClass = mibSet->Param.Class; - switch( LoRaMacDeviceClass ) - { - case CLASS_A: - { - // Set the radio into sleep to setup a defined state - Radio.Sleep( ); - break; - } - case CLASS_B: - { - break; - } - case CLASS_C: - { - // Set the NodeAckRequested indicator to default - NodeAckRequested = false; - OnRxWindow2TimerEvent( ); - break; - } - } - break; + } + MacCommandsInNextTx = false; + // Store MAC commands which must be re-send in case the device does not + // receive a downlink anymore + MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( + MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat); + if (MacCommandsBufferToRepeatIndex > 0) { + MacCommandsInNextTx = true; + } + MacCommandsBufferIndex = 0; + + if ((payload != NULL) && (payloadSize > 0)) { + LoRaMacBuffer[pktHeaderLen++] = framePort; + + if (framePort == 0) { + LoRaMacPayloadEncrypt((uint8_t*)payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr, + UP_LINK, UpLinkCounter, LoRaMacPayload); } - case MIB_NETWORK_JOINED: - { - IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( IsLoRaMacNetworkJoined == false ) - { - NextJoinBlock = 0; - JoinBlocksRemaining = 0xff; - Join500KHzRemaining = 0xff; - } -#endif - break; - } - case MIB_ADR: - { - AdrCtrlOn = mibSet->Param.AdrEnable; - break; - } - case MIB_NET_ID: - { - LoRaMacNetID = mibSet->Param.NetID; - break; - } - case MIB_DEV_ADDR: - { - LoRaMacDevAddr = mibSet->Param.DevAddr; - break; - } - case MIB_NWK_SKEY: - { - if( mibSet->Param.NwkSKey != NULL ) - { - memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey, - sizeof( LoRaMacNwkSKey ) ); - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; + else { + LoRaMacPayloadEncrypt((uint8_t*)payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr, + UP_LINK, UpLinkCounter, LoRaMacPayload); } - case MIB_APP_SKEY: - { - if( mibSet->Param.AppSKey != NULL ) - { - memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey, - sizeof( LoRaMacAppSKey ) ); - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_PUBLIC_NETWORK: - { - SetPublicNetwork( mibSet->Param.EnablePublicNetwork ); - break; - } - case MIB_REPEATER_SUPPORT: - { - RepeaterSupport = mibSet->Param.EnableRepeaterSupport; - break; - } - case MIB_RX2_CHANNEL: - { - Rx2Channel = mibSet->Param.Rx2Channel; - break; - } - case MIB_CHANNELS_MASK: - { - if( mibSet->Param.ChannelsMask ) - { -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - bool chanMaskState = true; - -#if defined( USE_BAND_915_HYBRID ) - chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask ); + memcpy1(LoRaMacBuffer + pktHeaderLen, LoRaMacPayload, payloadSize); + } + LoRaMacBufferPktLen = pktHeaderLen + payloadSize; + + LoRaMacComputeMic(LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, + UpLinkCounter, &mic); + + LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 1] = (mic >> 8) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 2] = (mic >> 16) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 3] = (mic >> 24) & 0xFF; + + LoRaMacBufferPktLen += LORAMAC_MFR_LEN; + + break; + case FRAME_TYPE_PROPRIETARY: + if ((fBuffer != NULL) && (fBufferSize > 0)) { + memcpy1(LoRaMacBuffer + pktHeaderLen, (uint8_t*)fBuffer, fBufferSize); + LoRaMacBufferPktLen = pktHeaderLen + fBufferSize; + } + break; + default: + return LORAMAC_STATUS_SERVICE_UNKNOWN; + } + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SendFrameOnChannel(ChannelParams_t channel) { + int8_t datarate = Datarates[ChannelsDatarate]; + int8_t txPowerIndex = 0; + int8_t txPower = 0; + + txPowerIndex = LimitTxPower(ChannelsTxPower); + txPower = TxPowers[txPowerIndex]; + + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + McpsConfirm.Datarate = ChannelsDatarate; + McpsConfirm.TxPower = txPowerIndex; + + Radio.SetChannel(channel.Frequency); + +// LOG("Radio TxPower=%u\r\n", txPower); +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + if (ChannelsDatarate == DR_7) { // High Speed FSK channel + Radio.SetMaxPayloadLength(MODEM_FSK, LoRaMacBufferPktLen); + Radio.SetTxConfig(MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, + 3e6); + TxTimeOnAir = Radio.TimeOnAir(MODEM_FSK, LoRaMacBufferPktLen); + } + else if (ChannelsDatarate == DR_6) { // High speed LoRa channel + Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen); + Radio.SetTxConfig(MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e6); + TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen); + } + else { // Normal LoRa channel + Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen); + Radio.SetTxConfig(MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6); + TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen); + } +#elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + Radio.SetMaxPayloadLength(MODEM_LORA, LoRaMacBufferPktLen); + if (ChannelsDatarate >= DR_4) { // High speed LoRa channel BW500 kHz + Radio.SetTxConfig(MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e6); + TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen); + } + else { // Normal LoRa channel + Radio.SetTxConfig(MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6); + TxTimeOnAir = Radio.TimeOnAir(MODEM_LORA, LoRaMacBufferPktLen); + } +#else +#error "Please define a frequency band in the compiler options." +#endif + + // Store the time on air + McpsConfirm.TxTimeOnAir = TxTimeOnAir; + MlmeConfirm.TxTimeOnAir = TxTimeOnAir; + + // Starts the MAC layer status check timer + TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT); + TimerStart(&MacStateCheckTimer); + + // Send now + Radio.Send(LoRaMacBuffer, LoRaMacBufferPktLen); + + LoRaMacState |= MAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacInitialization(LoRaMacPrimitives_t* primitives, + LoRaMacCallback_t* callbacks) { + if (primitives == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + if ((primitives->MacMcpsConfirm == NULL) || (primitives->MacMcpsIndication == NULL) || + (primitives->MacMlmeConfirm == NULL)) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + LoRaMacPrimitives = primitives; + LoRaMacCallbacks = callbacks; + + LoRaMacFlags.Value = 0; + + LoRaMacDeviceClass = CLASS_A; + + UpLinkCounter = 1; + DownLinkCounter = 0; + AdrAckCounter = 0; + + ChannelsNbRepCounter = 0; + + AckTimeoutRetries = 1; + AckTimeoutRetriesCounter = 1; + AckTimeoutRetry = false; + + MaxDCycle = 0; + AggregatedDCycle = 1; + + MacCommandsBufferIndex = 0; + MacCommandsBufferToRepeatIndex = 0; + + IsRxWindowsEnabled = true; + + RepeaterSupport = false; + IsRxWindowsEnabled = true; + IsLoRaMacNetworkJoined = false; + LoRaMacState = MAC_IDLE; + + NodeAckRequested = false; + SrvAckRequested = false; + MacCommandsInNextTx = false; + +#if defined(USE_BAND_433) + ChannelsMask[0] = LC(1) + LC(2) + LC(3); +#elif defined(USE_BAND_780) + ChannelsMask[0] = LC(1) + LC(2) + LC(3); +#elif defined(USE_BAND_868) + ChannelsMask[0] = LC(1) + LC(2) + LC(3); +#elif defined(USE_BAND_915) + ChannelsMask[0] = 0xFFFF; + ChannelsMask[1] = 0xFFFF; + ChannelsMask[2] = 0xFFFF; + ChannelsMask[3] = 0xFFFF; + ChannelsMask[4] = 0x00FF; + ChannelsMask[5] = 0x0000; + + memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, sizeof(ChannelsMask)); +#elif defined(USE_BAND_915_HYBRID) + ChannelsMask[0] = 0x00FF; + ChannelsMask[1] = 0x0000; + ChannelsMask[2] = 0x0000; + ChannelsMask[3] = 0x0000; + ChannelsMask[4] = 0x0001; + ChannelsMask[5] = 0x0000; + + memcpy1((uint8_t*)ChannelsMaskRemaining, (uint8_t*)ChannelsMask, sizeof(ChannelsMask)); +#else +#error "Please define a frequency band in the compiler options." +#endif + +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + // 125 kHz channels + for (uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++) { + Channels[i].Frequency = 902.3e6 + i * 200e3; + Channels[i].DrRange.Value = (DR_3 << 4) | DR_0; + Channels[i].Band = 0; + } + // 500 kHz channels + for (uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++) { + Channels[i].Frequency = 903.0e6 + (i - (LORA_MAX_NB_CHANNELS - 8)) * 1.6e6; + Channels[i].DrRange.Value = (DR_4 << 4) | DR_4; + Channels[i].Band = 0; + } +#endif + + ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; + ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE; + ChannelsNbRep = 1; + ChannelsNbRepCounter = 0; + + Rx2Channel.Frequency = 923300000; + Rx2Channel.Datarate = DR_8; + Rx1DrOffset = 0; + + MaxDCycle = 0; + AggregatedDCycle = 1; + AggregatedLastTxDoneTime = 0; + AggregatedTimeOff = 0; + +#if defined(USE_BAND_433) + DutyCycleOn = false; +#elif defined(USE_BAND_780) + DutyCycleOn = false; +#elif defined(USE_BAND_868) + DutyCycleOn = true; +#elif defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + DutyCycleOn = false; +#else +#error "Please define a frequency band in the compiler options." #endif - if( chanMaskState == true ) - { - if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < HYBRD_CHNLS_MIN ) && - ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - else - { - memcpy1( ( uint8_t* ) ChannelsMask, - ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) ); - for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ ) - { - // Disable channels which are no longer available - ChannelsMaskRemaining[i] &= ChannelsMask[i]; - } - } - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } -#else - memcpy1( ( uint8_t* ) ChannelsMask, - ( uint8_t* ) mibSet->Param.ChannelsMask, 2 ); + + MaxRxWindow = MAX_RX_WINDOW; + ReceiveDelay1 = RECEIVE_DELAY1; + ReceiveDelay2 = RECEIVE_DELAY2; + JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1; + JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2; + +#if defined(USE_BAND_915) + NextJoinBlock = 0; + LastJoinBlock = -1; + JoinBlocksRemaining = 0xff; + Join500KHzRemaining = 0xff; #endif - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_CHANNELS_NB_REP: - { - if( ( mibSet->Param.ChannelNbRep >= 1 ) && - ( mibSet->Param.ChannelNbRep <= 15 ) ) - { - ChannelsNbRep = mibSet->Param.ChannelNbRep; - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_MAX_RX_WINDOW_DURATION: - { - MaxRxWindow = mibSet->Param.MaxRxWindow; - break; - } - case MIB_RECEIVE_DELAY_1: - { - ReceiveDelay1 = mibSet->Param.ReceiveDelay1; - break; - } - case MIB_RECEIVE_DELAY_2: - { - ReceiveDelay2 = mibSet->Param.ReceiveDelay2; - break; - } - case MIB_JOIN_ACCEPT_DELAY_1: - { - JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1; - break; - } - case MIB_JOIN_ACCEPT_DELAY_2: - { - JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2; - break; + + LastJoinTxTime = 0; + JoinAggTimeOnAir = 0; + + TimerInit(&MacStateCheckTimer, OnMacStateCheckTimerEvent); + TimerSetValue(&MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT); + + TimerInit(&TxDelayedTimer, OnTxDelayedTimerEvent); + TimerInit(&RxWindowTimer1, OnRxWindow1TimerEvent); + TimerInit(&RxWindowTimer2, OnRxWindow2TimerEvent); + TimerInit(&AckTimeoutTimer, OnAckTimeoutTimerEvent); + + // Initialize Radio driver + RadioEvents.TxDone = OnRadioTxDone; + RadioEvents.RxDone = OnRadioRxDone; + RadioEvents.RxError = OnRadioRxError; + RadioEvents.TxTimeout = OnRadioTxTimeout; + RadioEvents.RxTimeout = OnRadioRxTimeout; + Radio.Init(&RadioEvents); + + // Random seed initialization + srand1(Radio.Random()); + + // Initialize channel index. + Channel = LORA_MAX_NB_CHANNELS; + + PublicNetwork = true; + SetPublicNetwork(PublicNetwork); + Radio.Sleep(); + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacQueryTxPossible(uint8_t size, LoRaMacTxInfo_t* txInfo) { + int8_t datarate = ChannelsDefaultDatarate; + uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex; + + if (txInfo == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + AdrNextDr(AdrCtrlOn, false, &datarate, NULL); + + if (RepeaterSupport == true) { + txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate]; + } + else { + txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate]; + } + + if (txInfo->CurrentPayloadSize >= fOptLen) { + txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen; + } + else { + return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR; + } + + if (ValidatePayloadLength(size, datarate, 0) == 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; + + if (mibGet == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + switch (mibGet->Type) { + case MIB_DEVICE_CLASS: { + mibGet->Param.Class = LoRaMacDeviceClass; + break; + } + case MIB_NETWORK_JOINED: { + mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined; + break; + } + case MIB_ADR: { + mibGet->Param.AdrEnable = AdrCtrlOn; + break; + } + case MIB_NET_ID: { + mibGet->Param.NetID = LoRaMacNetID; + break; + } + case MIB_DEV_ADDR: { + mibGet->Param.DevAddr = LoRaMacDevAddr; + break; + } + case MIB_NWK_SKEY: { + mibGet->Param.NwkSKey = LoRaMacNwkSKey; + break; + } + case MIB_APP_SKEY: { + mibGet->Param.AppSKey = LoRaMacAppSKey; + break; + } + case MIB_PUBLIC_NETWORK: { + mibGet->Param.EnablePublicNetwork = PublicNetwork; + break; + } + case MIB_REPEATER_SUPPORT: { + mibGet->Param.EnableRepeaterSupport = RepeaterSupport; + break; + } + case MIB_CHANNELS: { + mibGet->Param.ChannelList = Channels; + break; + } + case MIB_RX2_CHANNEL: { + mibGet->Param.Rx2Channel = Rx2Channel; + break; + } + case MIB_CHANNELS_MASK: { + mibGet->Param.ChannelsMask = ChannelsMask; + break; + } + case MIB_CHANNELS_NB_REP: { + mibGet->Param.ChannelNbRep = ChannelsNbRep; + break; + } + case MIB_MAX_RX_WINDOW_DURATION: { + mibGet->Param.MaxRxWindow = MaxRxWindow; + break; + } + case MIB_RECEIVE_DELAY_1: { + mibGet->Param.ReceiveDelay1 = ReceiveDelay1; + break; + } + case MIB_RECEIVE_DELAY_2: { + mibGet->Param.ReceiveDelay2 = ReceiveDelay2; + break; + } + case MIB_JOIN_ACCEPT_DELAY_1: { + mibGet->Param.JoinAcceptDelay1 = JoinAcceptDelay1; + break; + } + case MIB_JOIN_ACCEPT_DELAY_2: { + mibGet->Param.JoinAcceptDelay2 = JoinAcceptDelay2; + break; + } + case MIB_CHANNELS_DEFAULT_DATARATE: { + mibGet->Param.ChannelsDefaultDatarate = ChannelsDefaultDatarate; + break; + } + case MIB_CHANNELS_DATARATE: { + mibGet->Param.ChannelsDatarate = ChannelsDatarate; + break; + } + case MIB_CHANNELS_TX_POWER: { + mibGet->Param.ChannelsTxPower = ChannelsTxPower; + break; + } + case MIB_UPLINK_COUNTER: { + mibGet->Param.UpLinkCounter = UpLinkCounter; + break; + } + case MIB_DOWNLINK_COUNTER: { + mibGet->Param.DownLinkCounter = DownLinkCounter; + break; + } + case MIB_MULTICAST_CHANNEL: { + mibGet->Param.MulticastList = MulticastChannels; + break; + } + default: + status = LORAMAC_STATUS_SERVICE_UNKNOWN; + break; + } + + return status; +} + +LoRaMacStatus_t LoRaMacMibSetRequestConfirm(MibRequestConfirm_t* mibSet) { + LoRaMacStatus_t status = LORAMAC_STATUS_OK; + + if (mibSet == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + return LORAMAC_STATUS_BUSY; + } + + switch (mibSet->Type) { + 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 MIB_CHANNELS_DEFAULT_DATARATE: - { - if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, - LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) - { - ChannelsDefaultDatarate = mibSet->Param.ChannelsDefaultDatarate; - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; + case CLASS_B: { + break; } - case MIB_CHANNELS_DATARATE: - { - if( ValueInRange( mibSet->Param.ChannelsDatarate, - LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) - { - ChannelsDatarate = mibSet->Param.ChannelsDatarate; - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; + case CLASS_C: { + // Set the NodeAckRequested indicator to default + NodeAckRequested = false; + OnRxWindow2TimerEvent(); + break; } - case MIB_CHANNELS_TX_POWER: - { - if( ValueInRange( mibSet->Param.ChannelsTxPower, - LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) ) - { -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - int8_t txPower = LimitTxPower( mibSet->Param.ChannelsTxPower ); - if( txPower == mibSet->Param.ChannelsTxPower ) - { - ChannelsTxPower = mibSet->Param.ChannelsTxPower; - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } -#else - ChannelsTxPower = mibSet->Param.ChannelsTxPower; + } + break; + } + case MIB_NETWORK_JOINED: { + IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; +#if defined(USE_BAND_915) + if (IsLoRaMacNetworkJoined == false) { + NextJoinBlock = 0; + JoinBlocksRemaining = 0xff; + Join500KHzRemaining = 0xff; + } #endif - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; + break; + } + case MIB_ADR: { + AdrCtrlOn = mibSet->Param.AdrEnable; + break; + } + case MIB_NET_ID: { + LoRaMacNetID = mibSet->Param.NetID; + break; + } + case MIB_DEV_ADDR: { + LoRaMacDevAddr = mibSet->Param.DevAddr; + break; + } + case MIB_NWK_SKEY: { + if (mibSet->Param.NwkSKey != NULL) { + memcpy1(LoRaMacNwkSKey, mibSet->Param.NwkSKey, sizeof(LoRaMacNwkSKey)); + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_APP_SKEY: { + if (mibSet->Param.AppSKey != NULL) { + memcpy1(LoRaMacAppSKey, mibSet->Param.AppSKey, sizeof(LoRaMacAppSKey)); + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_PUBLIC_NETWORK: { + SetPublicNetwork(mibSet->Param.EnablePublicNetwork); + break; + } + case MIB_REPEATER_SUPPORT: { + RepeaterSupport = mibSet->Param.EnableRepeaterSupport; + break; + } + case MIB_RX2_CHANNEL: { + Rx2Channel = mibSet->Param.Rx2Channel; + break; + } + case MIB_CHANNELS_MASK: { + if (mibSet->Param.ChannelsMask) { +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + bool chanMaskState = true; + +#if defined(USE_BAND_915_HYBRID) + chanMaskState = ValidateChannelMask(mibSet->Param.ChannelsMask); +#endif + if (chanMaskState == true) { + if ((CountNbEnabled125kHzChannels(mibSet->Param.ChannelsMask) < HYBRD_CHNLS_MIN) && + (CountNbEnabled125kHzChannels(mibSet->Param.ChannelsMask) > 0)) { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + else { + memcpy1((uint8_t*)ChannelsMask, (uint8_t*)mibSet->Param.ChannelsMask, + sizeof(ChannelsMask)); + for (uint8_t i = 0; i < sizeof(ChannelsMask) / 2; i++) { + // Disable channels which are no longer available + ChannelsMaskRemaining[i] &= ChannelsMask[i]; } - break; + } } - case MIB_UPLINK_COUNTER: - { - UpLinkCounter = mibSet->Param.UpLinkCounter; - break; + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; } - case MIB_DOWNLINK_COUNTER: - { - DownLinkCounter = mibSet->Param.DownLinkCounter; - break; - } - default: - status = LORAMAC_STATUS_SERVICE_UNKNOWN; - break; +#else + memcpy1((uint8_t*)ChannelsMask, (uint8_t*)mibSet->Param.ChannelsMask, 2); +#endif + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_NB_REP: { + if ((mibSet->Param.ChannelNbRep >= 1) && (mibSet->Param.ChannelNbRep <= 15)) { + ChannelsNbRep = mibSet->Param.ChannelNbRep; + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_MAX_RX_WINDOW_DURATION: { + MaxRxWindow = mibSet->Param.MaxRxWindow; + break; + } + case MIB_RECEIVE_DELAY_1: { + ReceiveDelay1 = mibSet->Param.ReceiveDelay1; + break; + } + case MIB_RECEIVE_DELAY_2: { + ReceiveDelay2 = mibSet->Param.ReceiveDelay2; + break; + } + case MIB_JOIN_ACCEPT_DELAY_1: { + JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1; + break; + } + case MIB_JOIN_ACCEPT_DELAY_2: { + JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2; + break; } - - return status; -} - -LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params ) -{ -#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - return LORAMAC_STATUS_PARAMETER_INVALID; + case MIB_CHANNELS_DEFAULT_DATARATE: { + if (ValueInRange(mibSet->Param.ChannelsDefaultDatarate, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE)) { + ChannelsDefaultDatarate = mibSet->Param.ChannelsDefaultDatarate; + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_DATARATE: { + if (ValueInRange(mibSet->Param.ChannelsDatarate, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE)) { + ChannelsDatarate = mibSet->Param.ChannelsDatarate; + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_TX_POWER: { + if (ValueInRange(mibSet->Param.ChannelsTxPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER)) { +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) + int8_t txPower = LimitTxPower(mibSet->Param.ChannelsTxPower); + if (txPower == mibSet->Param.ChannelsTxPower) { + ChannelsTxPower = mibSet->Param.ChannelsTxPower; + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } #else - 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; + ChannelsTxPower = mibSet->Param.ChannelsTxPower; +#endif + } + else { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; } - // Validate if the MAC is in a correct state - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - if( ( LoRaMacState & MAC_TX_CONFIG ) != MAC_TX_CONFIG ) - { - return LORAMAC_STATUS_BUSY; - } + case MIB_UPLINK_COUNTER: { + UpLinkCounter = mibSet->Param.UpLinkCounter; + break; + } + case MIB_DOWNLINK_COUNTER: { + DownLinkCounter = mibSet->Param.DownLinkCounter; + break; } - // 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; + default: + status = LORAMAC_STATUS_SERVICE_UNKNOWN; + break; + } + + return status; +} + +LoRaMacStatus_t LoRaMacChannelAdd(uint8_t id, ChannelParams_t params) { +#if (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; + } + // Validate if the MAC is in a correct state + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + if ((LoRaMacState & MAC_TX_CONFIG) != MAC_TX_CONFIG) { + return LORAMAC_STATUS_BUSY; } - -#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 > ChannelsDefaultDatarate ) - { - datarateInvalid = true; - } - if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE ) == false ) - { - datarateInvalid = true; - } + } + // 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 > ChannelsDefaultDatarate) { + 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 >= 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 - - // Validate the frequency - if( ( Radio.CheckRfFrequency( params.Frequency ) == true ) && ( params.Frequency > 0 ) && ( frequencyInvalid == false ) ) - { -#if defined( USE_BAND_868 ) - 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; - ChannelsMask[0] |= ( 1 << id ); - - return LORAMAC_STATUS_OK; + } + 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; + ChannelsMask[0] |= (1 << id); + + return LORAMAC_STATUS_OK; #endif } -LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id ) -{ -#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - if( ( LoRaMacState & MAC_TX_CONFIG ) != MAC_TX_CONFIG ) - { - return LORAMAC_STATUS_BUSY; - } - } - - if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; +LoRaMacStatus_t LoRaMacChannelRemove(uint8_t id) { +#if defined(USE_BAND_433) || defined(USE_BAND_780) || defined(USE_BAND_868) + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + if ((LoRaMacState & MAC_TX_CONFIG) != MAC_TX_CONFIG) { + return LORAMAC_STATUS_BUSY; } - 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, ChannelsMask ) == false ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } + } + + if ((id < 3) || (id >= LORA_MAX_NB_CHANNELS)) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + else { + // Remove the channel from the list of channels + Channels[id] = (ChannelParams_t){0, {0}, 0}; + + // Disable the channel as it doesn't exist anymore + if (DisableChannelInMask(id, ChannelsMask) == false) { + return LORAMAC_STATUS_PARAMETER_INVALID; } - return LORAMAC_STATUS_OK; -#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - return LORAMAC_STATUS_PARAMETER_INVALID; + } + return LORAMAC_STATUS_OK; +#elif (defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID)) + return LORAMAC_STATUS_PARAMETER_INVALID; #endif } -LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam ) -{ - if( channelParam == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - return LORAMAC_STATUS_BUSY; - } - - // Reset downlink counter - channelParam->DownLinkCounter = 0; - - if( MulticastChannels == NULL ) - { - // New node is the fist element - MulticastChannels = channelParam; +LoRaMacStatus_t LoRaMacMulticastChannelLink(MulticastParams_t* channelParam) { + if (channelParam == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + return LORAMAC_STATUS_BUSY; + } + + // Reset downlink counter + channelParam->DownLinkCounter = 0; + + if (MulticastChannels == NULL) { + // New node is the fist element + MulticastChannels = channelParam; + } + else { + MulticastParams_t* cur = MulticastChannels; + + // Search the last node in the list + while (cur->Next != NULL) { + cur = cur->Next; } - else - { - MulticastParams_t *cur = MulticastChannels; - - // Search the last node in the list - while( cur->Next != NULL ) - { - cur = cur->Next; - } - // This function always finds the last node - cur->Next = channelParam; - } - - return LORAMAC_STATUS_OK; + // This function always finds the last node + cur->Next = channelParam; + } + + return LORAMAC_STATUS_OK; } -LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam ) -{ - if( channelParam == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - return LORAMAC_STATUS_BUSY; +LoRaMacStatus_t LoRaMacMulticastChannelUnlink(MulticastParams_t* channelParam) { + if (channelParam == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + return LORAMAC_STATUS_BUSY; + } + + if (MulticastChannels != NULL) { + if (MulticastChannels == channelParam) { + // First element + MulticastChannels = channelParam->Next; } - - if( MulticastChannels != NULL ) - { - if( MulticastChannels == channelParam ) - { - // First element - MulticastChannels = channelParam->Next; - } - else - { - MulticastParams_t *cur = MulticastChannels; - - // Search the node in the list - while( cur->Next && cur->Next != channelParam ) - { - cur = cur->Next; - } - // If we found the node, remove it - if( cur->Next ) - { - cur->Next = channelParam->Next; - } - } - channelParam->Next = NULL; + else { + MulticastParams_t* cur = MulticastChannels; + + // Search the node in the list + while (cur->Next && cur->Next != channelParam) { + cur = cur->Next; + } + // If we found the node, remove it + if (cur->Next) { + cur->Next = channelParam->Next; + } } - - return LORAMAC_STATUS_OK; + channelParam->Next = NULL; + } + + return LORAMAC_STATUS_OK; } -LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest ) -{ - LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; - LoRaMacHeader_t macHdr; - - if( mlmeRequest == NULL ) - { +LoRaMacStatus_t LoRaMacMlmeRequest(MlmeReq_t* mlmeRequest) { + LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; + LoRaMacHeader_t macHdr; + + if (mlmeRequest == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if ((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) { + return LORAMAC_STATUS_BUSY; + } + + memset1((uint8_t*)&MlmeConfirm, 0, sizeof(MlmeConfirm)); + + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + + switch (mlmeRequest->Type) { + case MLME_JOIN: { + if ((LoRaMacState & MAC_TX_DELAYED) == MAC_TX_DELAYED) { + return LORAMAC_STATUS_BUSY; + } + + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + + if ((mlmeRequest->Req.Join.DevEui == NULL) || (mlmeRequest->Req.Join.AppEui == NULL) || + (mlmeRequest->Req.Join.AppKey == NULL)) { return LORAMAC_STATUS_PARAMETER_INVALID; - } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) - { - return LORAMAC_STATUS_BUSY; - } - - memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) ); - - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; - - switch( mlmeRequest->Type ) - { - case MLME_JOIN: - { - if( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED ) - { - return LORAMAC_STATUS_BUSY; - } - - MlmeConfirm.MlmeRequest = mlmeRequest->Type; - - if( ( mlmeRequest->Req.Join.DevEui == NULL ) || - ( mlmeRequest->Req.Join.AppEui == NULL ) || - ( mlmeRequest->Req.Join.AppKey == NULL ) ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - - LoRaMacFlags.Bits.MlmeReq = 1; - - LoRaMacDevEui = mlmeRequest->Req.Join.DevEui; - LoRaMacAppEui = mlmeRequest->Req.Join.AppEui; - LoRaMacAppKey = mlmeRequest->Req.Join.AppKey; - -// Disable join retransmission dutycycle as it does not currently -// handle device reset + } + + LoRaMacFlags.Bits.MlmeReq = 1; + + LoRaMacDevEui = mlmeRequest->Req.Join.DevEui; + LoRaMacAppEui = mlmeRequest->Req.Join.AppEui; + LoRaMacAppKey = mlmeRequest->Req.Join.AppKey; + +// Disable join retransmission dutycycle as it does not currently +// handle device reset #if 0 if( LoRaMacCalcJoinBackOff( ) != 0 ) { @@ -4061,243 +3589,213 @@ } #endif - macHdr.Value = 0; - macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; - -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if ( IsLoRaMacNetworkJoined == true ) - { - NextJoinBlock = 0; - JoinBlocksRemaining = 0xff; - Join500KHzRemaining = 0xff; - IsLoRaMacNetworkJoined = false; - } + macHdr.Value = 0; + macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; + +#if defined(USE_BAND_915) + if (IsLoRaMacNetworkJoined == true) { + NextJoinBlock = 0; + JoinBlocksRemaining = 0xff; + Join500KHzRemaining = 0xff; + IsLoRaMacNetworkJoined = false; + } #endif -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) -#if defined( USE_BAND_915 ) - // Re-enable 500 kHz default channels - ChannelsMask[4] = 0x00FF; -#else // defined( USE_BAND_915_HYBRID ) - // Re-enable 500 kHz default channels - ChannelsMask[4] = 0x0001; +#if defined(USE_BAND_915) || defined(USE_BAND_915_HYBRID) +#if defined(USE_BAND_915) + // Re-enable 500 kHz default channels + ChannelsMask[4] = 0x00FF; +#else // defined( USE_BAND_915_HYBRID ) + // Re-enable 500 kHz default channels + ChannelsMask[4] = 0x0001; #endif - static uint8_t drSwitch = 0; - - if( ( ++drSwitch & 0x01 ) == 0x01 ) - { - ChannelsDatarate = DR_0; - } - else - { - ChannelsDatarate = DR_4; - } + static uint8_t drSwitch = 0; + + if ((++drSwitch & 0x01) == 0x01) { + ChannelsDatarate = DR_0; + } + else { + ChannelsDatarate = DR_4; + } #endif - status = Send( &macHdr, 0, NULL, 0 ); - break; - } - case MLME_LINK_CHECK: - { - LoRaMacFlags.Bits.MlmeReq = 1; - // LoRaMac will send this command piggy-pack - MlmeConfirm.MlmeRequest = mlmeRequest->Type; - - status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 ); - break; - } - default: - break; + status = Send(&macHdr, 0, NULL, 0); + break; } - - if( status != LORAMAC_STATUS_OK ) - { - NodeAckRequested = false; - LoRaMacFlags.Bits.MlmeReq = 0; + case MLME_LINK_CHECK: { + LoRaMacFlags.Bits.MlmeReq = 1; + // LoRaMac will send this command piggy-pack + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + + status = AddMacCommand(MOTE_MAC_LINK_CHECK_REQ, 0, 0); + break; } - - return status; + default: + break; + } + + if (status != LORAMAC_STATUS_OK) { + NodeAckRequested = false; + LoRaMacFlags.Bits.MlmeReq = 0; + } + + return status; } -LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest ) -{ - LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; - LoRaMacHeader_t macHdr; - uint8_t fPort = 0; - void *fBuffer; - uint16_t fBufferSize; - int8_t datarate; - bool readyToSend = false; - - if( mcpsRequest == NULL ) - { - return LORAMAC_STATUS_PARAMETER_INVALID; +LoRaMacStatus_t LoRaMacMcpsRequest(McpsReq_t* mcpsRequest) { + LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; + LoRaMacHeader_t macHdr; + uint8_t fPort = 0; + void* fBuffer; + uint16_t fBufferSize; + int8_t datarate; + bool readyToSend = false; + + if (mcpsRequest == NULL) { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if (((LoRaMacState & MAC_TX_RUNNING) == MAC_TX_RUNNING) || + ((LoRaMacState & MAC_TX_DELAYED) == MAC_TX_DELAYED)) { + return LORAMAC_STATUS_BUSY; + } + + macHdr.Value = 0; + memset1((uint8_t*)&McpsConfirm, 0, sizeof(McpsConfirm)); + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + + switch (mcpsRequest->Type) { + case MCPS_UNCONFIRMED: { + readyToSend = true; + AckTimeoutRetries = 1; + AckTimeoutRetriesCounter = 1; + + macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP; + fPort = mcpsRequest->Req.Unconfirmed.fPort; + fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer; + fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize; + datarate = mcpsRequest->Req.Unconfirmed.Datarate; + break; } - if( ( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) || - ( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED ) ) - { - return LORAMAC_STATUS_BUSY; + case MCPS_CONFIRMED: { + readyToSend = true; + AckTimeoutRetriesCounter = 1; + AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials; + + macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP; + fPort = mcpsRequest->Req.Confirmed.fPort; + fBuffer = mcpsRequest->Req.Confirmed.fBuffer; + fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize; + datarate = mcpsRequest->Req.Confirmed.Datarate; + break; } - - macHdr.Value = 0; - memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) ); - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; - - switch( mcpsRequest->Type ) - { - case MCPS_UNCONFIRMED: - { - readyToSend = true; - AckTimeoutRetries = 1; - AckTimeoutRetriesCounter = 1; - - macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP; - fPort = mcpsRequest->Req.Unconfirmed.fPort; - fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer; - fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize; - datarate = mcpsRequest->Req.Unconfirmed.Datarate; - break; - } - case MCPS_CONFIRMED: - { - readyToSend = true; - AckTimeoutRetriesCounter = 1; - AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials; - - macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP; - fPort = mcpsRequest->Req.Confirmed.fPort; - fBuffer = mcpsRequest->Req.Confirmed.fBuffer; - fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize; - datarate = mcpsRequest->Req.Confirmed.Datarate; - break; - } - case MCPS_PROPRIETARY: - { - readyToSend = true; - AckTimeoutRetries = 1; - - macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY; - fBuffer = mcpsRequest->Req.Proprietary.fBuffer; - fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize; - datarate = mcpsRequest->Req.Proprietary.Datarate; - break; - } - default: - break; + case MCPS_PROPRIETARY: { + readyToSend = true; + AckTimeoutRetries = 1; + + macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY; + fBuffer = mcpsRequest->Req.Proprietary.fBuffer; + fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize; + datarate = mcpsRequest->Req.Proprietary.Datarate; + break; } - - if( readyToSend == true ) - { - if( AdrCtrlOn == false ) - { - if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true ) - { - ChannelsDatarate = datarate; - } - else - { - return LORAMAC_STATUS_PARAMETER_INVALID; - } - } - - status = Send( &macHdr, fPort, fBuffer, fBufferSize ); - if( status == LORAMAC_STATUS_OK ) - { - McpsConfirm.McpsRequest = mcpsRequest->Type; - LoRaMacFlags.Bits.McpsReq = 1; - } - else - { - NodeAckRequested = false; - } + default: + break; + } + + if (readyToSend == true) { + if (AdrCtrlOn == false) { + if (ValueInRange(datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE) == true) { + ChannelsDatarate = datarate; + } + else { + return LORAMAC_STATUS_PARAMETER_INVALID; + } } - return status; + status = Send(&macHdr, fPort, fBuffer, fBufferSize); + if (status == LORAMAC_STATUS_OK) { + McpsConfirm.McpsRequest = mcpsRequest->Type; + LoRaMacFlags.Bits.McpsReq = 1; + } + else { + NodeAckRequested = false; + } + } + + return status; } -TimerTime_t LoRaMacCalcJoinBackOff( ) -{ - TimerTime_t timeOff = 0; - TimerTime_t uptime; - TimerTime_t currDCycleEndTime; - TimerTime_t prevDCycleEndTime; - TimerTime_t period; - TimerTime_t onAirTimeMax; - TimerTime_t lastJoinTime; - TimerTime_t elapsedTime; - uint8_t dcyclePeriod; - - // Check retransmit duty-cycle is enabled - if ( JOIN_NB_RETRANSMISSION_DCYCLES == 0 ) - return 0; - - // Normalize system time values to seconds - uptime = TimerGetCurrentTime( ) / 1e6; - lastJoinTime = LastJoinTxTime / 1e6; - - // Get dutycycle for current time - prevDCycleEndTime = 0; - currDCycleEndTime = 0; - for(dcyclePeriod = 0; dcyclePeriod < JOIN_NB_RETRANSMISSION_DCYCLES; dcyclePeriod++) - { - prevDCycleEndTime = currDCycleEndTime; - currDCycleEndTime += JoinReTransmitDCycle[dcyclePeriod].period; - - bool isCurrentPeriod = uptime < currDCycleEndTime; - - if( isCurrentPeriod || ( dcyclePeriod == ( JOIN_NB_RETRANSMISSION_DCYCLES-1 ) ) ) - { - period = JoinReTransmitDCycle[dcyclePeriod].period; - onAirTimeMax = JoinReTransmitDCycle[dcyclePeriod].onAirTimeMax; - if( isCurrentPeriod == true ) - break; - } +TimerTime_t LoRaMacCalcJoinBackOff() { + TimerTime_t timeOff = 0; + TimerTime_t uptime; + TimerTime_t currDCycleEndTime; + TimerTime_t prevDCycleEndTime; + TimerTime_t period; + TimerTime_t onAirTimeMax; + TimerTime_t lastJoinTime; + TimerTime_t elapsedTime; + uint8_t dcyclePeriod; + + // Check retransmit duty-cycle is enabled + if (JOIN_NB_RETRANSMISSION_DCYCLES == 0) + return 0; + + // Normalize system time values to seconds + uptime = TimerGetCurrentTime() / 1e6; + lastJoinTime = LastJoinTxTime / 1e6; + + // Get dutycycle for current time + prevDCycleEndTime = 0; + currDCycleEndTime = 0; + for (dcyclePeriod = 0; dcyclePeriod < JOIN_NB_RETRANSMISSION_DCYCLES; dcyclePeriod++) { + prevDCycleEndTime = currDCycleEndTime; + currDCycleEndTime += JoinReTransmitDCycle[dcyclePeriod].period; + + bool isCurrentPeriod = uptime < currDCycleEndTime; + + if (isCurrentPeriod || (dcyclePeriod == (JOIN_NB_RETRANSMISSION_DCYCLES - 1))) { + period = JoinReTransmitDCycle[dcyclePeriod].period; + onAirTimeMax = JoinReTransmitDCycle[dcyclePeriod].onAirTimeMax; + if (isCurrentPeriod == true) + break; } - - // Clear aggregate on air time if dutycycle period of last join has elapsed - if( lastJoinTime < prevDCycleEndTime ) - { + } + + // Clear aggregate on air time if dutycycle period of last join has elapsed + if (lastJoinTime < prevDCycleEndTime) { + JoinAggTimeOnAir = 0; + } + else { + elapsedTime = (uptime - prevDCycleEndTime) % period; + + if (dcyclePeriod == JOIN_NB_RETRANSMISSION_DCYCLES) { + if (((uptime - prevDCycleEndTime) / period) > ((lastJoinTime - prevDCycleEndTime) / period)) { JoinAggTimeOnAir = 0; - } - else - { - elapsedTime = ( uptime - prevDCycleEndTime ) % period; - - if( dcyclePeriod == JOIN_NB_RETRANSMISSION_DCYCLES ) - { - if( ( ( uptime - prevDCycleEndTime ) / period ) > ( ( lastJoinTime - prevDCycleEndTime ) / period ) ) - { - JoinAggTimeOnAir = 0; - } - } - } - - if ( JoinAggTimeOnAir >= onAirTimeMax ) - { - // time off is remaining time until beginning of next period - timeOff = ( period - elapsedTime ); + } } - - - if(timeOff > JOIN_RETRANSMISSION_DC_WAIT_MAX) - timeOff = JOIN_RETRANSMISSION_DC_WAIT_MAX; - - return ( timeOff * 1e6 ); -} - -void LoRaMacTestRxWindowsOn( bool enable ) -{ - IsRxWindowsEnabled = enable; + } + + if (JoinAggTimeOnAir >= onAirTimeMax) { + // time off is remaining time until beginning of next period + timeOff = (period - elapsedTime); + } + + if (timeOff > JOIN_RETRANSMISSION_DC_WAIT_MAX) + timeOff = JOIN_RETRANSMISSION_DC_WAIT_MAX; + + return (timeOff * 1e6); } -void LoRaMacTestSetMic( uint16_t txPacketCounter ) -{ - UpLinkCounter = txPacketCounter; - IsUpLinkCounterFixed = true; +void LoRaMacTestRxWindowsOn(bool enable) { + IsRxWindowsEnabled = enable; } -void LoRaMacTestSetDutyCycleOn( bool enable ) -{ - DutyCycleOn = enable; +void LoRaMacTestSetMic(uint16_t txPacketCounter) { + UpLinkCounter = txPacketCounter; + IsUpLinkCounterFixed = true; } + +void LoRaMacTestSetDutyCycleOn(bool enable) { + DutyCycleOn = enable; +}