Fork of Semtech LoRaWAN stack
Fork of LoRaWAN-lib by
Diff: LoRaMac.cpp.orig
- Branch:
- SenetNetTool
- Revision:
- 49:8b9e6442a02a
- Parent:
- 36:fc9baa35ae1a
diff -r fc9baa35ae1a -r 8b9e6442a02a LoRaMac.cpp.orig --- a/LoRaMac.cpp.orig Tue Aug 08 11:21:18 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4309 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech - ___ _____ _ ___ _ _____ ___ ___ ___ ___ -/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| -\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| -|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| -embedded.connectivity.solutions=============== - -Description: LoRa MAC layer implementation - -License: Revised BSD License, see LICENSE.TXT file include in the project - -Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) -*/ -#include "board.h" - -#include "LoRaMacCrypto.h" -#include "LoRaMac.h" -#include "LoRaMacTest.h" - -/*! - * Maximum PHY layer payload size - */ -#define LORAMAC_PHY_MAXPAYLOAD 255 - -/*! - * Maximum MAC commands buffer size - */ -#define LORA_MAC_COMMAND_MAX_LENGTH 15 - -/*! - * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength - * in RxWindowSetup function. - * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD - */ -#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) - -/*! - * Minimum number of available channels in Frequency Hopping Mode - */ -#define FRQ_HOP_CHNLS_MIN 50 - -/*! - * Minimum number of available channels in Hybrid Mode - */ -#define HYBRD_CHNLS_MIN 4 - - -/*! - * Device IEEE EUI - */ -static uint8_t *LoRaMacDevEui; - -/*! - * Application IEEE EUI - */ -static uint8_t *LoRaMacAppEui; - -/*! - * AES encryption/decryption cipher application key - */ -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 -}; - -/*! - * 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 -}; - -/*! - * Device nonce is a random value extracted by issuing a sequence of RSSI - * measurements - */ -static uint16_t LoRaMacDevNonce; - -/*! - * Network ID ( 3 bytes ) - */ -static uint32_t LoRaMacNetID; - -/*! - * Mote Address - */ -static uint32_t LoRaMacDevAddr; - -/*! - * Multicast channels linked list - */ -static MulticastParams_t *MulticastChannels = NULL; - -/*! - * Actual device class - */ -static DeviceClass_t LoRaMacDeviceClass; - -/*! - * Indicates if the node is connected to a private or public network - */ -static bool PublicNetwork; - -/*! - * Indicates if the node supports repeaters - */ -static bool RepeaterSupport; - -/*! - * Buffer containing the data to be sent or received. - */ -static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD]; - -/*! - * Length of packet in LoRaMacBuffer - */ -static uint16_t LoRaMacBufferPktLen = 0; - -/*! - * Buffer containing the upper layer data. - */ -static uint8_t LoRaMacPayload[LORAMAC_PHY_MAXPAYLOAD]; -static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD]; - -/*! - * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. - * Only the 16 LSB bits are sent - */ -static uint32_t UpLinkCounter = 1; - -/*! - * 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; - -/*! - * IsPacketCounterFixed enables the MIC field tests by fixing the - * UpLinkCounter value - */ -static bool IsUpLinkCounterFixed = false; - -/*! - * Used for test purposes. Disables the opening of the reception windows. - */ -static bool IsRxWindowsEnabled = true; - -/*! - * Indicates if the MAC layer has already joined a network. - */ -static bool IsLoRaMacNetworkJoined = false; - -/*! - * LoRaMac ADR control status - */ -static bool AdrCtrlOn = true; - -/*! - * Counts the number of missed ADR acknowledgements - */ -static uint32_t AdrAckCounter = 0; - -/*! - * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates - * if the nodes needs to manage the server acknowledgement. - */ -static bool NodeAckRequested = false; - -/*! - * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates - * if the ACK bit must be set for the next transmission - */ -static bool SrvAckRequested = false; - -/*! - * Indicates if the MAC layer wants to send MAC commands - */ -static bool MacCommandsInNextTx = false; - -/*! - * Contains the current MacCommandsBuffer index - */ -static uint8_t MacCommandsBufferIndex = 0; - -/*! - * Contains the current MacCommandsBuffer index for MAC commands to repeat - */ -static uint8_t MacCommandsBufferToRepeatIndex = 0; - -/*! - * Buffer containing the MAC layer commands - */ -static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH]; - -/*! - * Buffer containing the MAC layer commands which must be repeated - */ -static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH]; - -#if defined( USE_BAND_433 ) -/*! - * Data rates table definition - */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -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 }; - -/*! - * LoRaMac bands - */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, -}; - -/*! - * LoRaMAC channels - */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = -{ - LC1, - LC2, - LC3, -}; -#elif defined( USE_BAND_780 ) -/*! - * Data rates table definition - */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -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 }; - -/*! - * LoRaMac bands - */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, -}; - -/*! - * LoRaMAC channels - */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = -{ - LC1, - LC2, - LC3, -}; -#elif defined( USE_BAND_868 ) -/*! - * Data rates table definition - */ -const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; - -/*! - * Maximum payload with respect to the datarate index. Cannot operate with repeater. - */ -const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; - -/*! - * Maximum payload with respect to the datarate index. Can operate with repeater. - */ -const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; - -/*! - * Tx output powers table definition - */ -const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; - -/*! - * LoRaMac bands - */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, - BAND1, - BAND2, - BAND3, - BAND4, -}; - -/*! - * LoRaMAC channels - */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = -{ - LC1, - LC2, - LC3, -}; -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) -/*! - * Data rates table definition - */ -const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; - -/*! - * Up/Down link data rates offset definition - */ -const 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. - */ -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. - */ -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 }; - -/*! - * LoRaMac bands - */ -static Band_t Bands[LORA_MAX_NB_BANDS] = -{ - BAND0, -}; - -/*! - * LoRaMAC channels - */ -static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; - -/*! - * Contains the channels which remain to be applied. - */ -static uint16_t ChannelsMaskRemaining[6]; - -#if defined( USE_BAND_915 ) -/*! - * Last join request sub-band - */ -static int8_t LastJoinBlock; - -/*! - * Next join sub-band block - */ -static uint8_t NextJoinBlock; - -/*! - * Mask of 125 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; - -#ifndef JOIN_BLOCK_ORDER -#define JOIN_BLOCK_ORDER { -1, -1, -1, -1, -1, -1, -1, -1 } -#endif - -/*! - * join sub-band block order - */ -static int8_t JoinBlock[8] = JOIN_BLOCK_ORDER; - -#endif - -/*! - * Defines the first channel for RX window 2 for US band - */ -#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 ) - -/*! - * Defines the step width of the channels for RX window 2 - */ -#define LORAMAC_STEPWIDTH_RX2_CHANNEL ( (uint32_t) 600e3 ) - - -#else - #error "Please define a frequency band in the compiler options." -#endif - -/*! - * LoRaMAC 2nd reception window settings - */ -static Rx2ChannelParams_t Rx2Channel = RX_WND_2_CHANNEL; - -/*! - * Datarate offset between uplink and downlink on first window - */ -static uint8_t Rx1DrOffset = 0; - -/*! - * Mask indicating which channels are enabled - */ -static uint16_t ChannelsMask[6]; - -/*! - * Channels Tx output power - */ -static int8_t ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; - -/*! - * Channels datarate - */ -static int8_t ChannelsDatarate = LORAMAC_DEFAULT_DATARATE; - -/*! - * Channels default datarate - */ -static int8_t ChannelsDefaultDatarate = LORAMAC_DEFAULT_DATARATE; - -/*! - * Number of uplink messages repetitions [1:15] (unconfirmed messages only) - */ -static uint8_t ChannelsNbRep = 1; - -/*! - * Uplink messages repetitions counter - */ -static uint8_t ChannelsNbRepCounter = 0; - -/*! - * Maximum duty cycle - * \remark Possibility to shutdown the device. - */ -static uint8_t MaxDCycle = 0; - -/*! - * Aggregated duty cycle management - */ -static uint16_t AggregatedDCycle; -static TimerTime_t AggregatedLastTxDoneTime; -static TimerTime_t AggregatedTimeOff; - -/*! - * Enables/Disables duty cycle management (Test only) - */ -static bool DutyCycleOn; - -/*! - * Current channel index - */ -static uint8_t Channel; - -static uint8_t LastTxChannel; - -/*! - * 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, -}; - -/*! - * LoRaMac internal state - */ -uint32_t LoRaMacState = MAC_IDLE; - -/*! - * LoRaMac timer used to check the LoRaMacState (runs every second) - */ -static TimerEvent_t MacStateCheckTimer; - -/*! - * LoRaMac upper layer event functions - */ -static LoRaMacPrimitives_t *LoRaMacPrimitives; - -/*! - * LoRaMac upper layer callback functions - */ -static LoRaMacCallback_t *LoRaMacCallbacks; - -/*! - * Radio events function pointer - */ -static RadioEvents_t RadioEvents; - -/*! - * LoRaMac duty cycle delayed Tx timer - */ -static TimerEvent_t TxDelayedTimer; - -/*! - * LoRaMac reception windows timers - */ -static TimerEvent_t RxWindowTimer1; -static TimerEvent_t RxWindowTimer2; - -/*! - * LoRaMac reception windows delay from end of Tx - */ -static uint32_t ReceiveDelay1; -static uint32_t ReceiveDelay2; -static uint32_t JoinAcceptDelay1; -static uint32_t JoinAcceptDelay2; - -/*! - * LoRaMac reception windows delay - * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME - * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME - */ -static uint32_t RxWindow1Delay; -static uint32_t RxWindow2Delay; - -/*! - * LoRaMac maximum time a reception window stays open - */ -static uint32_t MaxRxWindow; - -/*! - * Acknowledge timeout timer. Used for packet retransmissions. - */ -static TimerEvent_t AckTimeoutTimer; - -/*! - * Number of trials to get a frame acknowledged - */ -static uint8_t AckTimeoutRetries = 1; - -/*! - * Number of trials to get a frame acknowledged - */ -static uint8_t AckTimeoutRetriesCounter = 1; - -/*! - * Indicates if the AckTimeout timer has expired or not - */ -static bool AckTimeoutRetry = false; - -/*! - * Last transmission time on air - */ -TimerTime_t TxTimeOnAir = 0; - -/*! - * Structure to hold an MCPS indication data. - */ -static McpsIndication_t McpsIndication; - -/*! - * Structure to hold MCPS confirm data. - */ -static McpsConfirm_t McpsConfirm; - -/*! - * Structure to hold MLME confirm data. - */ -static MlmeConfirm_t MlmeConfirm; - -/*! - * Holds the current rx window slot - */ -static uint8_t RxSlot = 0; - -/*! - * LoRaMac tx/rx operation state - */ -LoRaMacFlags_t LoRaMacFlags; - -/*! - * Join Retransmission back-off configuration - */ -LoRaMacRetransmissionDCycle_t JoinReTransmitDCycle[JOIN_NB_RETRANSMISSION_DCYCLES] = -{ - JOIN_RETRANSMISSION_DCYCLE1, - JOIN_RETRANSMISSION_DCYCLE2, - JOIN_RETRANSMISSION_DCYCLE3 -}; - -/*! - * Uptime of the last sent join request - */ -static TimerTime_t LastJoinTxTime; - -/*! - * Aggregated join request time on air - */ -static TimerTime_t JoinAggTimeOnAir; - - -/*! - * \brief Function to be executed on Radio Tx Done event - */ -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 ); - -/*! - * \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 ); - -/*! - * \brief Function executed on Radio Tx Timeout event - */ -static void OnRadioTxTimeout( void ); - -/*! - * \brief Function executed on Radio Rx error event - */ -static void OnRadioRxError( void ); - -/*! - * \brief Function executed on Radio Rx Timeout event - */ -static void OnRadioRxTimeout( void ); - -/*! - * \brief Function executed on Resend Frame timer event. - */ -static void OnMacStateCheckTimerEvent( void ); - -/*! - * \brief Function executed on duty cycle delayed Tx timer event - */ -static void OnTxDelayedTimerEvent( void ); - -/*! - * \brief Function executed on first Rx window timer event - */ -static void OnRxWindow1TimerEvent( void ); - -/*! - * \brief Function executed on second Rx window timer event - */ -static void OnRxWindow2TimerEvent( void ); - -/*! - * \brief Function executed on AckTimeout timer event - */ -static void OnAckTimeoutTimerEvent( void ); - -/*! - * \brief Searches and set the next random available channel - * - * \param [OUT] Time to wait for the next transmission according to the duty - * cycle. - * - * \retval status Function status [1: OK, 0: Unable to find a channel on the - * current datarate] - */ -static bool SetNextChannel( TimerTime_t* time ); - -/*! - * \brief Sets the network to public or private. Updates the sync byte. - * - * \param [IN] enable if true, it enables a public network - */ -static void SetPublicNetwork( bool enable ); - -/*! - * \brief Initializes and opens the reception window - * - * \param [IN] freq window channel frequency - * \param [IN] datarate window channel datarate - * \param [IN] bandwidth window channel bandwidth - * \param [IN] timeout window channel timeout - */ -static 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 - * - * \param [IN] freq window channel frequency - * - * \retval status Function status [1: OK, 0: Frequency not applicable] - */ -static bool Rx2FreqInRange( uint32_t freq ); - - -/*! - * \brief Adds a new MAC command to be sent. - * - * \Remark MAC layer internal function - * - * \param [in] cmd MAC command to be added - * [MOTE_MAC_LINK_CHECK_REQ, - * MOTE_MAC_LINK_ADR_ANS, - * MOTE_MAC_DUTY_CYCLE_ANS, - * MOTE_MAC_RX2_PARAM_SET_ANS, - * MOTE_MAC_DEV_STATUS_ANS - * MOTE_MAC_NEW_CHANNEL_ANS] - * \param [in] p1 1st parameter ( optional depends on the command ) - * \param [in] p2 2nd parameter ( optional depends on the command ) - * - * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full] - */ -static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 ); - -/*! - * \brief Parses the MAC commands which must be repeated. - * - * \Remark MAC layer internal function - * - * \param [IN] cmdBufIn Buffer which stores the MAC commands to send - * \param [IN] length Length of the input buffer to parse - * \param [OUT] cmdBufOut Buffer which stores the MAC commands which must be - * repeated. - * - * \retval Size of the MAC commands to repeat. - */ -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 - * into account. - * - * \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0 - * - * \param lenN Length of the application payload. The length depends on the - * datarate and is region specific - * - * \param datarate Current datarate - * - * \param fOptsLen Length of the fOpts field - * - * \retval [false: payload does not fit into the frame, true: payload fits into - * the frame] - */ -static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ); - -/*! - * \brief Counts the number of bits in a mask. - * - * \param [IN] mask A mask from which the function counts the active bits. - * \param [IN] nbBits The number of bits to check. - * - * \retval Number of enabled bits in the mask. - */ -static uint8_t CountBits( uint16_t mask, uint8_t nbBits ); - -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) -/*! - * \brief Counts the number of enabled 125 kHz channels in the channel mask. - * This function can only be applied to US915 band. - * - * \param [IN] channelsMask Pointer to the first element of the channel mask - * - * \retval Number of enabled channels in the channel mask - */ -static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ); - -#if defined( USE_BAND_915_HYBRID ) -/*! - * \brief Validates the correctness of the channel mask for US915, hybrid mode. - * - * \param [IN] mask Block definition to set. - * \param [OUT] channelsMask Pointer to the first element of the channel mask - */ -static void ReenableChannels( uint16_t mask, uint16_t* channelMask ); - -/*! - * \brief Validates the correctness of the channel mask for US915, hybrid mode. - * - * \param [IN] channelsMask Pointer to the first element of the channel mask - * - * \retval [true: channel mask correct, false: channel mask not correct] - */ -static bool ValidateChannelMask( uint16_t* channelMask ); -#endif - -#endif - -/*! - * \brief Limits the Tx power according to the number of enabled channels - * - * \retval Returns the maximum valid tx power - */ -static int8_t LimitTxPower( int8_t txPower ); - -/*! - * \brief Verifies, if a value is in a given range. - * - * \param value Value to verify, if it is in range - * - * \param min Minimum possible value - * - * \param max Maximum possible value - * - * \retval Returns the maximum valid tx power - */ -static bool ValueInRange( int8_t value, int8_t min, int8_t max ); - -/*! - * \brief Calculates the next datarate to set, when ADR is on or off - * - * \param [IN] adrEnabled Specify whether ADR is on or off - * - * \param [IN] isTx Set to true if called by transmit, set to false if a dry run - * - * \param [OUT] datarateOut Reports the datarate which will be used next - * - * \param [OUT] txpowerOut Reports the tx power which will be used next - * - * \retval Returns the state of ADR ack request - */ -static bool AdrNextDr( bool adrEnabled, bool isTx, int8_t* datarateOut, int8_t* txpowerOut ); - -/*! - * \brief Disables channel in a specified channel mask - * - * \param [IN] id - Id of the channel - * - * \param [IN] mask - Pointer to the channel mask to edit - * - * \retval [true, if disable was successful, false if not] - */ -static bool DisableChannelInMask( uint8_t id, uint16_t* mask ); - -/*! - * \brief Decodes MAC commands in the fOpts field and in the payload - */ -static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr ); - -/*! - * \brief LoRaMAC layer generic send frame - * - * \param [IN] macHdr MAC header field - * \param [IN] fPort MAC payload port - * \param [IN] fBuffer MAC data buffer to be sent - * \param [IN] fBufferSize MAC data buffer size - * \retval status Status of the operation. - */ -LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); - -/*! - * \brief LoRaMAC layer frame buffer initialization - * - * \param [IN] macHdr MAC header field - * \param [IN] fCtrl MAC frame control field - * \param [IN] fOpts MAC commands buffer - * \param [IN] fPort MAC payload port - * \param [IN] fBuffer MAC data buffer to be sent - * \param [IN] fBufferSize MAC data buffer size - * \retval status Status of the operation. - */ -LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); - -/* - * \brief Schedules the frame according to the duty cycle - * - * \retval Status of the operation - */ -static LoRaMacStatus_t ScheduleTx( void ); - -/* - * \brief Calculates the back-off time for the band of a channel. - * - * \param [IN] channel The last Tx channel index - */ -static void CalculateBackOff( uint8_t channel ); - -/*! - * \brief LoRaMAC layer prepared frame buffer transmission with channel specification - * - * \remark PrepareFrame must be called at least once before calling this - * function. - * - * \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( ); - } - 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; - - AdrAckCounter = 0; - 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( ( 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; - } - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; - LoRaMacFlags.Bits.MacDone = 1; - } -} - -static void OnRadioRxTimeout( void ) -{ - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); - } - else - { - OnRxWindow2TimerEvent( ); - } - - if( RxSlot == 1 ) - { - if( NodeAckRequested == true ) - { - McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - } - MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; - LoRaMacFlags.Bits.MacDone = 1; - } -} - -static void OnMacStateCheckTimerEvent( void ) -{ - TimerStop( &MacStateCheckTimer ); - bool txTimeout = false; - - if( LoRaMacFlags.Bits.MacDone == 1 ) - { - if( ( 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; - - AdrAckCounter++; - if( IsUpLinkCounterFixed == false ) - { - UpLinkCounter++; - } - - LoRaMacState &= ~MAC_TX_RUNNING; - } - else - { - LoRaMacFlags.Bits.MacDone = 0; - // Sends the same frame again - ScheduleTx( ); - } - } - } - - if( LoRaMacFlags.Bits.McpsInd == 1 ) - { - if( ( McpsConfirm.AckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) ) - { - AckTimeoutRetry = false; - NodeAckRequested = false; - if( IsUpLinkCounterFixed == false ) - { - UpLinkCounter++; - } - McpsConfirm.NbRetries = AckTimeoutRetriesCounter; - - LoRaMacState &= ~MAC_TX_RUNNING; - } - } - - if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_TX_DELAYED ) == 0 ) ) - { - AckTimeoutRetry = false; - if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) ) - { - AckTimeoutRetriesCounter++; - - if( ( AckTimeoutRetriesCounter % 2 ) == 1 ) - { - ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_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; - if( IsUpLinkCounterFixed == false ) - { - UpLinkCounter++; - } - } - } - } - // Handle reception for Class B and Class C - if( ( LoRaMacState & MAC_RX ) == MAC_RX ) - { - LoRaMacState &= ~MAC_RX; - } - if( LoRaMacState == MAC_IDLE ) - { - if( LoRaMacFlags.Bits.McpsReq == 1 ) - { - LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm ); - LoRaMacFlags.Bits.McpsReq = 0; - } - - if( LoRaMacFlags.Bits.MlmeReq == 1 ) - { - LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm ); - LoRaMacFlags.Bits.MlmeReq = 0; - } - - LoRaMacFlags.Bits.MacDone = 0; - } - else - { - // Operation not finished restart timer - 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 - switch( datarate ) - { - case DR_0: // SF10 - BW125 - symbTimeout = 5; - break; - - case DR_1: // SF9 - BW125 - case DR_2: // SF8 - BW125 - case DR_8: // SF12 - BW500 - case DR_9: // SF11 - BW500 - case DR_10: // SF10 - BW500 - symbTimeout = 8; - break; - - case DR_3: // SF7 - BW125 - case DR_11: // SF9 - BW500 - symbTimeout = 10; - break; - - case DR_4: // SF8 - BW500 - case DR_12: // SF8 - BW500 - symbTimeout = 14; - break; - - case DR_13: // SF7 - BW500 - symbTimeout = 16; - break; - default: - break; - } - if( datarate >= DR_4 ) - {// LoRa 500 kHz - 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; - } - } - } - } - } - - // 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 ) ); - } -#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 -#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; - } - 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 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 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 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++; - } - } - 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; - } - } - channelMask[4] = blockMask; - channelMask[5] = 0x0000; -} - -static bool ValidateChannelMask( uint16_t* channelMask ) -{ - bool chanMaskState = false; - uint16_t block1 = 0; - uint16_t block2 = 0; - uint8_t index = 0; - - for( uint8_t i = 0; i < 4; i++ ) - { - block1 = channelMask[i] & 0x00FF; - block2 = channelMask[i] & 0xFF00; - - if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) ) - { - channelMask[i] &= block1; - channelMask[4] = 1 << ( i * 2 ); - chanMaskState = true; - index = i; - } - else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) ) - { - channelMask[i] &= block2; - channelMask[4] = 1 << ( i * 2 + 1 ); - chanMaskState = true; - index = i; - } - } - - // Do only change the channel mask, if we have found a valid block. - if( chanMaskState == true ) - { - for( uint8_t i = 0; i < 4; i++ ) - { - if( i != index ) - { - channelMask[i] = 0; - } - } - } - return chanMaskState; -} -#endif -#endif - -static int8_t LimitTxPower( int8_t txPower ) -{ - int8_t resultTxPower = txPower; -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - if( ( ChannelsDatarate == DR_4 ) || - ( ( ChannelsDatarate >= DR_8 ) && ( ChannelsDatarate <= DR_13 ) ) ) - {// Limit tx power to max 26dBm - resultTxPower = MAX( txPower, TX_POWER_26_DBM ); - } - else - { - if( CountNbEnabled125kHzChannels( ChannelsMask ) < FRQ_HOP_CHNLS_MIN ) - {// Limit tx power to max 21dBm - resultTxPower = MAX( txPower, TX_POWER_20_DBM ); - } - } -#endif - return resultTxPower; -} - -static bool ValueInRange( int8_t value, int8_t min, int8_t max ) -{ - if( ( value >= min ) && ( value <= max ) ) - { - return true; - } - return false; -} - -static bool DisableChannelInMask( uint8_t id, uint16_t* mask ) -{ - uint8_t index = 0; - index = id / 16; - - if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) ) - { - return false; - } - - // Deactivate channel - mask[index] &= ~( 1 << ( id % 16 ) ); - - return true; -} - -static bool AdrNextDr( bool adrEnabled, bool 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; - -} - -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; - } - } - - 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 - } -#else - #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 - } -#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; -#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; -#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; - } - } - - // 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 - } -#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; - } - - 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; - } - - 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 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 - - 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; - } - - 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 CLASS_B: - { - break; - } - case CLASS_C: - { - // Set the NodeAckRequested indicator to default - NodeAckRequested = false; - OnRxWindow2TimerEvent( ); - break; - } - } - break; - } - case MIB_NETWORK_JOINED: - { - IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; -#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; - } - 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]; - } - } - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } -#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; - } - 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 - ChannelsTxPower = mibSet->Param.ChannelsTxPower; -#endif - } - else - { - status = LORAMAC_STATUS_PARAMETER_INVALID; - } - break; - } - case MIB_UPLINK_COUNTER: - { - UpLinkCounter = mibSet->Param.UpLinkCounter; - break; - } - case MIB_DOWNLINK_COUNTER: - { - DownLinkCounter = mibSet->Param.DownLinkCounter; - break; - } - default: - status = LORAMAC_STATUS_SERVICE_UNKNOWN; - break; - } - - 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; - } - } - // 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 - } - 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; - } - 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; -#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; - } - 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; -} - -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; - } - 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; - } - - return LORAMAC_STATUS_OK; -} - -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; - } - - 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 ) - { - return LORAMAC_STATUS_TX_DCYCLE_EXCEEDED; - } -#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; - } -#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; -#endif - - static uint8_t drSwitch = 0; - - if( ( ++drSwitch & 0x01 ) == 0x01 ) - { - ChannelsDatarate = DR_0; - } - else - { - ChannelsDatarate = DR_4; - } -#endif - - status = Send( &macHdr, 0, NULL, 0 ); - break; - } - case MLME_LINK_CHECK: - { - LoRaMacFlags.Bits.MlmeReq = 1; - // LoRaMac will send this command piggy-pack - MlmeConfirm.MlmeRequest = mlmeRequest->Type; - - status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 ); - break; - } - default: - break; - } - - if( status != LORAMAC_STATUS_OK ) - { - NodeAckRequested = false; - LoRaMacFlags.Bits.MlmeReq = 0; - } - - return status; -} - -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; - - 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; - } - - 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; - } - } - - 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; - } - } - - // 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; - } - } - } - - 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; -} - -void LoRaMacTestSetMic( uint16_t txPacketCounter ) -{ - UpLinkCounter = txPacketCounter; - IsUpLinkCounterFixed = true; -} - -void LoRaMacTestSetDutyCycleOn( bool enable ) -{ - DutyCycleOn = enable; -}