Fork of Semtech LoRaWAN stack
Fork of LoRaWAN-lib by
Diff: LoRaMac.cpp
- Revision:
- 32:26002607de9c
- Parent:
- 7:c16969e0f70f
- Child:
- 33:db4900d60c37
diff -r c16969e0f70f -r 26002607de9c LoRaMac.cpp --- a/LoRaMac.cpp Tue Jul 05 13:24:54 2016 +0000 +++ b/LoRaMac.cpp Mon Apr 24 09:42:37 2017 +0000 @@ -17,6 +17,7 @@ Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) */ +#include <math.h> #include "board.h" #include "LoRaMacCrypto.h" @@ -41,6 +42,21 @@ #define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) /*! + * LoRaMac duty cycle for the back-off procedure during the first hour. + */ +#define BACKOFF_DC_1_HOUR 100 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 10 hours. + */ +#define BACKOFF_DC_10_HOURS 1000 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 24 hours. + */ +#define BACKOFF_DC_24_HOURS 10000 + +/*! * Device IEEE EUI */ static uint8_t *LoRaMacDevEui; @@ -120,16 +136,20 @@ static uint16_t LoRaMacBufferPktLen = 0; /*! + * Length of the payload in LoRaMacBuffer + */ +static uint8_t LoRaMacTxPayloadLen = 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; +static uint32_t UpLinkCounter = 0; /*! * LoRaMAC frame counter. Each time a packet is received the counter is incremented. @@ -207,19 +227,24 @@ const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; /*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; +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[] = { 59, 59, 59, 123, 230, 230, 230, 230 }; +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; /*! * Tx output powers table definition */ -const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; +const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 }; /*! * LoRaMac bands @@ -238,6 +263,61 @@ LC2, LC3, }; +#elif defined( USE_BAND_470 ) + +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 222, 222 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 17, 16, 14, 12, 10, 7, 5, 2 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; + +/*! + * Defines the first channel for RX window 1 for CN470 band + */ +#define LORAMAC_FIRST_RX1_CHANNEL ( (uint32_t) 500.3e6 ) + +/*! + * Defines the last channel for RX window 1 for CN470 band + */ +#define LORAMAC_LAST_RX1_CHANNEL ( (uint32_t) 509.7e6 ) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define LORAMAC_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 200e3 ) + #elif defined( USE_BAND_780 ) /*! * Data rates table definition @@ -245,19 +325,24 @@ const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; /*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ -const uint8_t MaxPayloadOfDatarate[] = { 59, 59, 59, 123, 250, 250, 250, 250 }; +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[] = { 59, 59, 59, 123, 230, 230, 230, 230 }; +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; /*! * Tx output powers table definition */ -const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; +const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 }; /*! * LoRaMac bands @@ -283,6 +368,11 @@ const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; /*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! * Maximum payload with respect to the datarate index. Cannot operate with repeater. */ const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; @@ -325,9 +415,14 @@ const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; /*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 500e3, 0, 0, 0, 500e3, 500e3, 500e3, 500e3, 500e3, 500e3, 0, 0 }; + +/*! * Up/Down link data rates offset definition */ -const int8_t datarateOffsets[16][4] = +const int8_t DatarateOffsets[5][4] = { { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0 { DR_11, DR_10, DR_9 , DR_8 }, // DR_1 @@ -370,19 +465,19 @@ static uint16_t ChannelsMaskRemaining[6]; /*! - * Defines the first channel for RX window 2 for US band + * Defines the first channel for RX window 1 for US band */ -#define LORAMAC_FIRST_RX2_CHANNEL ( (uint32_t) 923.3e6 ) +#define LORAMAC_FIRST_RX1_CHANNEL ( (uint32_t) 923.3e6 ) /*! - * Defines the last channel for RX window 2 for US band + * Defines the last channel for RX window 1 for US band */ -#define LORAMAC_LAST_RX2_CHANNEL ( (uint32_t) 927.5e6 ) +#define LORAMAC_LAST_RX1_CHANNEL ( (uint32_t) 927.5e6 ) /*! - * Defines the step width of the channels for RX window 2 + * Defines the step width of the channels for RX window 1 */ -#define LORAMAC_STEPWIDTH_RX2_CHANNEL ( (uint32_t) 600e3 ) +#define LORAMAC_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600e3 ) #else #error "Please define a frequency band in the compiler options." @@ -427,29 +522,31 @@ static uint8_t Channel; /*! - * Channel index of the last transmission + * Stores the time at LoRaMac initialization. + * + * \remark Used for the BACKOFF_DC computation. */ -static uint8_t LastTxChannel; +static TimerTime_t LoRaMacInitializationTime = 0; /*! * 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_IDLE = 0x00000000, + LORAMAC_TX_RUNNING = 0x00000001, + LORAMAC_RX = 0x00000002, + LORAMAC_ACK_REQ = 0x00000004, + LORAMAC_ACK_RETRY = 0x00000008, + LORAMAC_TX_DELAYED = 0x00000010, + LORAMAC_TX_CONFIG = 0x00000020, + LORAMAC_RX_ABORT = 0x00000040, }; /*! * LoRaMac internal state */ -uint32_t LoRaMacState = MAC_IDLE; +uint32_t LoRaMacState = LORAMAC_IDLE; /*! * LoRaMac timer used to check the LoRaMacState (runs every second) @@ -491,6 +588,22 @@ static uint32_t RxWindow2Delay; /*! + * Rx window parameters + */ +typedef struct +{ + int8_t Datarate; + uint8_t Bandwidth; + uint32_t RxWindowTimeout; + int32_t RxOffset; +}RxConfigParams_t; + +/*! + * Rx windows params + */ +static RxConfigParams_t RxWindowsParams[2]; + +/*! * Acknowledge timeout timer. Used for packet retransmissions. */ static TimerEvent_t AckTimeoutTimer; @@ -518,7 +631,12 @@ /*! * Number of trials for the Join Request */ -static uint16_t JoinRequestTrials; +static uint8_t JoinRequestTrials; + +/*! + * Maximum number of trials for the Join Request + */ +static uint8_t MaxJoinRequestTrials; /*! * Structure to hold an MCPS indication data. @@ -613,21 +731,16 @@ 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 + * + * \retval status Operation status [true: Success, false: Fail] */ -static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ); +static bool 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 @@ -717,7 +830,7 @@ * \param [IN] mask Block definition to set. * \param [OUT] channelsMask Pointer to the first element of the channel mask */ -static void ReenableChannels( uint16_t mask, uint16_t* channelMask ); +static void ReenableChannels( uint16_t mask, uint16_t* channelsMask ); /*! * \brief Validates the correctness of the channel mask for US915, hybrid mode. @@ -726,17 +839,30 @@ * * \retval [true: channel mask correct, false: channel mask not correct] */ -static bool ValidateChannelMask( uint16_t* channelMask ); +static bool ValidateChannelMask( uint16_t* channelsMask ); #endif #endif /*! + * \brief Validates the correctness of the datarate against the enable channels. + * + * \param [IN] datarate Datarate to be check + * \param [IN] channelsMask Pointer to the first element of the channel mask + * + * \retval [true: datarate can be used, false: datarate can not be used] + */ +static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask ); + +/*! * \brief Limits the Tx power according to the number of enabled channels * + * \param [IN] txPower txPower to limit + * \param [IN] maxBandTxPower Maximum band allowed TxPower + * * \retval Returns the maximum valid tx power */ -static int8_t LimitTxPower( int8_t txPower ); +static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower ); /*! * \brief Verifies, if a value is in a given range. @@ -812,11 +938,11 @@ static LoRaMacStatus_t ScheduleTx( void ); /* - * \brief Sets the duty cycle for retransmissions + * \brief Sets the duty cycle for the join procedure. * * \retval Duty cycle */ -static uint16_t RetransmissionDutyCylce( void ); +static uint16_t JoinDutyCycle( void ); /* * \brief Calculates the back-off time for the band of a channel. @@ -845,13 +971,86 @@ LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ); /*! + * \brief Sets the radio in continuous transmission mode + * + * \remark Uses the radio parameters set on the previous transmission. + * + * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode + * \retval status Status of the operation. + */ +LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout ); + +/*! + * \brief Sets the radio in continuous transmission mode + * + * \remark Uses the radio parameters set on the previous transmission. + * + * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode + * \param [IN] frequency RF frequency to be set. + * \param [IN] power RF ouptput power to be set. + * \retval status Status of the operation. + */ +LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ); + +/*! * \brief Resets MAC specific parameters to default */ static void ResetMacParameters( void ); +/* + * Rx window precise timing + * + * For more details please consult the following document, chapter 3.1.2. + * http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf + * or + * http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf + * + * Downlink start: T = Tx + 1s (+/- 20 us) + * | + * TRxEarly | TRxLate + * | | | + * | | +---+---+---+---+---+---+---+---+ + * | | | Latest Rx window | + * | | +---+---+---+---+---+---+---+---+ + * | | | + * +---+---+---+---+---+---+---+---+ + * | Earliest Rx window | + * +---+---+---+---+---+---+---+---+ + * | + * +---+---+---+---+---+---+---+---+ + *Downlink preamble 8 symbols | | | | | | | | | + * +---+---+---+---+---+---+---+---+ + * + * Worst case Rx window timings + * + * TRxLate = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME + * TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME + * + * TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR + * + * RxOffset = ( TRxLate + TRxEarly ) / 2 + * + * RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR + * RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME + * + * Minimal value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol + */ +/*! + * Computes the Rx window parameters. + * + * \param [IN] datarate Rx window datarate to be used + * \param [IN] rxError Maximum timing error of the receiver. in milliseconds + * The receiver will turn on in a [-rxError : +rxError] ms + * interval around RxOffset + * + * \retval rxConfigParams Returns a RxConfigParams_t structure. + */ +static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ); + static void OnRadioTxDone( void ) { TimerTime_t curTime = TimerGetCurrentTime( ); + if( LoRaMacDeviceClass != CLASS_C ) { Radio.Sleep( ); @@ -861,13 +1060,7 @@ 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; - + // Setup timers if( IsRxWindowsEnabled == true ) { TimerSetValue( &RxWindowTimer1, RxWindow1Delay ); @@ -896,6 +1089,13 @@ LoRaMacFlags.Bits.MacDone = 1; } + // Update last tx done time for the current channel + Bands[Channels[Channel].Band].LastTxDoneTime = curTime; + // Update Aggregated last tx done time + AggregatedLastTxDoneTime = curTime; + // Update Backoff + CalculateBackOff( Channel ); + if( NodeAckRequested == false ) { McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; @@ -905,23 +1105,18 @@ static void PrepareRxDoneAbort( void ) { - LoRaMacState |= MAC_RX_ABORT; + LoRaMacState |= LORAMAC_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 ); + TimerSetValue( &MacStateCheckTimer, 1 ); TimerStart( &MacStateCheckTimer ); } @@ -966,10 +1161,7 @@ McpsIndication.DownLinkCounter = 0; McpsIndication.McpsIndication = MCPS_UNCONFIRMED; - if( LoRaMacDeviceClass != CLASS_C ) - { - Radio.Sleep( ); - } + Radio.Sleep( ); TimerStop( &RxWindowTimer2 ); macHdr.Value = payload[pktHeaderLen++]; @@ -979,7 +1171,9 @@ case FRAME_TYPE_JOIN_ACCEPT: if( IsLoRaMacNetworkJoined == true ) { - break; + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + PrepareRxDoneAbort( ); + return; } LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 ); @@ -1008,24 +1202,15 @@ // DLSettings LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07; LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F; -#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) - /* - * WARNING: To be removed once Semtech server implementation - * is corrected. - */ - if( LoRaMacParams.Rx2Channel.Datarate == DR_3 ) - { - LoRaMacParams.Rx2Channel.Datarate = DR_8; - } -#endif + // RxDelay LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F ); if( LoRaMacParams.ReceiveDelay1 == 0 ) { LoRaMacParams.ReceiveDelay1 = 1; } - LoRaMacParams.ReceiveDelay1 *= 1e6; - LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e6; + LoRaMacParams.ReceiveDelay1 *= 1e3; + LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3; #if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) //CFList @@ -1034,13 +1219,20 @@ ChannelParams_t param; param.DrRange.Value = ( DR_5 << 4 ) | DR_0; - LoRaMacState |= MAC_TX_CONFIG; + LoRaMacState |= LORAMAC_TX_CONFIG; for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 ) { param.Frequency = ( ( uint32_t )LoRaMacRxPayload[13 + j] | ( ( uint32_t )LoRaMacRxPayload[14 + j] << 8 ) | ( ( uint32_t )LoRaMacRxPayload[15 + j] << 16 ) ) * 100; - LoRaMacChannelAdd( i, param ); + if( param.Frequency != 0 ) + { + LoRaMacChannelAdd( i, param ); + } + else + { + LoRaMacChannelRemove( i ); + } } - LoRaMacState &= ~MAC_TX_CONFIG; + LoRaMacState &= ~LORAMAC_TX_CONFIG; } #endif MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; @@ -1176,6 +1368,10 @@ ( DownLinkCounter != 0 ) ) { // Duplicated confirmed downlink. Skip indication. + // In this case, the MAC layer shall accept the MAC commands + // which are included in the downlink retransmission. + // It should not provide the same frame to the application + // layer again. skipIndication = true; } } @@ -1196,28 +1392,23 @@ DownLinkCounter = downLinkCounter; } - // Check if the frame is an acknowledgement - if( fCtrl.Bits.Ack == 1 ) + // This must be done before parsing the payload and the MAC commands. + // We need to reset the MacCommandsBufferIndex here, since we need + // to take retransmissions and repititions into account. Error cases + // will be handled in function OnMacStateCheckTimerEvent. + if( McpsConfirm.McpsRequest == MCPS_CONFIRMED ) { - McpsConfirm.AckReceived = true; - McpsIndication.AckReceived = true; - - // Stop the AckTimeout timer as no more retransmissions - // are needed. - TimerStop( &AckTimeoutTimer ); + if( fCtrl.Bits.Ack == 1 ) + {// Reset MacCommandsBufferIndex when we have received an ACK. + MacCommandsBufferIndex = 0; + } } else - { - McpsConfirm.AckReceived = false; - - if( AckTimeoutRetriesCounter > AckTimeoutRetries ) - { - // Stop the AckTimeout timer as no more retransmissions - // are needed. - TimerStop( &AckTimeoutTimer ); - } + {// Reset the variable if we have received any valid frame. + MacCommandsBufferIndex = 0; } + // Process payload and MAC commands if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 ) { port = payload[appPayloadStartIndex++]; @@ -1227,6 +1418,7 @@ if( port == 0 ) { + // Only allow frames which do not have fOpts if( fCtrl.Bits.FOptsLen == 0 ) { LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, @@ -1280,8 +1472,32 @@ if( skipIndication == false ) { - LoRaMacFlags.Bits.McpsInd = 1; + // 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 ); + } + } } + // Provide always an indication, skip the callback to the user application, + // in case of a confirmed downlink retransmission. + LoRaMacFlags.Bits.McpsInd = 1; + LoRaMacFlags.Bits.McpsIndSkip = skipIndication; } else { @@ -1309,15 +1525,10 @@ PrepareRxDoneAbort( ); break; } - - if( ( RxSlot == 0 ) && ( LoRaMacDeviceClass == CLASS_C ) ) - { - OnRxWindow2TimerEvent( ); - } LoRaMacFlags.Bits.MacDone = 1; // Trig OnMacCheckTimerEvent call as soon as possible - TimerSetValue( &MacStateCheckTimer, 1000 ); + TimerSetValue( &MacStateCheckTimer, 1 ); TimerStart( &MacStateCheckTimer ); } @@ -1348,7 +1559,20 @@ OnRxWindow2TimerEvent( ); } - if( RxSlot == 1 ) + if( RxSlot == 0 ) + { + if( NodeAckRequested == true ) + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + } + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + + if( TimerGetElapsedTime( AggregatedLastTxDoneTime ) >= RxWindow2Delay ) + { + LoRaMacFlags.Bits.MacDone = 1; + } + } + else { if( NodeAckRequested == true ) { @@ -1388,10 +1612,10 @@ if( LoRaMacFlags.Bits.MacDone == 1 ) { - if( ( LoRaMacState & MAC_RX_ABORT ) == MAC_RX_ABORT ) + if( ( LoRaMacState & LORAMAC_RX_ABORT ) == LORAMAC_RX_ABORT ) { - LoRaMacState &= ~MAC_RX_ABORT; - LoRaMacState &= ~MAC_TX_RUNNING; + LoRaMacState &= ~LORAMAC_RX_ABORT; + LoRaMacState &= ~LORAMAC_TX_RUNNING; } if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) @@ -1400,7 +1624,8 @@ ( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ) { // Stop transmit cycle due to tx timeout. - LoRaMacState &= ~MAC_TX_RUNNING; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + MacCommandsBufferIndex = 0; McpsConfirm.NbRetries = AckTimeoutRetriesCounter; McpsConfirm.AckReceived = false; McpsConfirm.TxTimeOnAir = 0; @@ -1410,46 +1635,64 @@ if( ( NodeAckRequested == false ) && ( txTimeout == false ) ) { - if( LoRaMacFlags.Bits.MlmeReq == 1 ) - { - if( MlmeConfirm.MlmeRequest == MLME_JOIN ) - { - // Retransmit only if the answer is not OK - ChannelsNbRepCounter = 0; - - if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK ) - { - // Stop retransmission - ChannelsNbRepCounter = LoRaMacParams.ChannelsNbRep; - UpLinkCounter = 0; - } - } - } if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) { - if( ( ChannelsNbRepCounter >= LoRaMacParams.ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) ) - { - ChannelsNbRepCounter = 0; - - AdrAckCounter++; - if( IsUpLinkCounterFixed == false ) + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) ) + {// Procedure for the join request + MlmeConfirm.NbRetries = JoinRequestTrials; + + if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK ) + {// Node joined successfully + UpLinkCounter = 0; + ChannelsNbRepCounter = 0; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else { - UpLinkCounter++; + if( JoinRequestTrials >= MaxJoinRequestTrials ) + { + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else + { + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + OnTxDelayedTimerEvent( ); + } } - - LoRaMacState &= ~MAC_TX_RUNNING; } else - { - LoRaMacFlags.Bits.MacDone = 0; - // Sends the same frame again - ScheduleTx( ); + {// Procedure for all other frames + if( ( ChannelsNbRepCounter >= LoRaMacParams.ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) ) + { + if( LoRaMacFlags.Bits.McpsInd == 0 ) + { // Maximum repititions without downlink. Reset MacCommandsBufferIndex. Increase ADR Ack counter. + // Only process the case when the MAC did not receive a downlink. + MacCommandsBufferIndex = 0; + AdrAckCounter++; + } + + ChannelsNbRepCounter = 0; + + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else + { + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + OnTxDelayedTimerEvent( ); + } } } } if( LoRaMacFlags.Bits.McpsInd == 1 ) - { + {// Procedure if we received a frame if( ( McpsConfirm.AckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) ) { AckTimeoutRetry = false; @@ -1460,12 +1703,12 @@ } McpsConfirm.NbRetries = AckTimeoutRetriesCounter; - LoRaMacState &= ~MAC_TX_RUNNING; + LoRaMacState &= ~LORAMAC_TX_RUNNING; } } - if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_TX_DELAYED ) == 0 ) ) - { + if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & LORAMAC_TX_DELAYED ) == 0 ) ) + {// Retransmissions procedure for confirmed uplinks AckTimeoutRetry = false; if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) ) { @@ -1475,31 +1718,48 @@ { LoRaMacParams.ChannelsDatarate = MAX( LoRaMacParams.ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE ); } - LoRaMacFlags.Bits.MacDone = 0; - // Sends the same frame again - ScheduleTx( ); + // Try to send the frame again + if( ScheduleTx( ) == LORAMAC_STATUS_OK ) + { + LoRaMacFlags.Bits.MacDone = 0; + } + else + { + // The DR is not applicable for the payload size + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; + + MacCommandsBufferIndex = 0; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + NodeAckRequested = false; + McpsConfirm.AckReceived = false; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate; + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + } } else { #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) // Re-enable default channels LC1, LC2, LC3 LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); +#elif defined( USE_BAND_470 ) + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); #elif defined( USE_BAND_915 ) // Re-enable default channels - LoRaMacParams.ChannelsMask[0] = 0xFFFF; - LoRaMacParams.ChannelsMask[1] = 0xFFFF; - LoRaMacParams.ChannelsMask[2] = 0xFFFF; - LoRaMacParams.ChannelsMask[3] = 0xFFFF; - LoRaMacParams.ChannelsMask[4] = 0x00FF; - LoRaMacParams.ChannelsMask[5] = 0x0000; + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); #elif defined( USE_BAND_915_HYBRID ) // Re-enable default channels - ReenableChannels( LoRaMacParams.ChannelsMask[4], LoRaMacParams.ChannelsMask ); + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); #else #error "Please define a frequency band in the compiler options." #endif - LoRaMacState &= ~MAC_TX_RUNNING; - + LoRaMacState &= ~LORAMAC_TX_RUNNING; + + MacCommandsBufferIndex = 0; NodeAckRequested = false; McpsConfirm.AckReceived = false; McpsConfirm.NbRetries = AckTimeoutRetriesCounter; @@ -1511,11 +1771,11 @@ } } // Handle reception for Class B and Class C - if( ( LoRaMacState & MAC_RX ) == MAC_RX ) + if( ( LoRaMacState & LORAMAC_RX ) == LORAMAC_RX ) { - LoRaMacState &= ~MAC_RX; + LoRaMacState &= ~LORAMAC_RX; } - if( LoRaMacState == MAC_IDLE ) + if( LoRaMacState == LORAMAC_IDLE ) { if( LoRaMacFlags.Bits.McpsReq == 1 ) { @@ -1529,6 +1789,7 @@ LoRaMacFlags.Bits.MlmeReq = 0; } + // Procedure done. Reset variables. LoRaMacFlags.Bits.MacDone = 0; } else @@ -1540,7 +1801,15 @@ if( LoRaMacFlags.Bits.McpsInd == 1 ) { - LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); + if( LoRaMacDeviceClass == CLASS_C ) + {// Activate RX2 window for Class C + OnRxWindow2TimerEvent( ); + } + if( LoRaMacFlags.Bits.McpsIndSkip == 0 ) + { + LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); + } + LoRaMacFlags.Bits.McpsIndSkip = 0; LoRaMacFlags.Bits.McpsInd = 0; } } @@ -1551,17 +1820,21 @@ LoRaMacFrameCtrl_t fCtrl; TimerStop( &TxDelayedTimer ); - LoRaMacState &= ~MAC_TX_DELAYED; + LoRaMacState &= ~LORAMAC_TX_DELAYED; if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) ) { + ResetMacParameters( ); + // Add a +1, since we start to count from 0 + LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 ); + macHdr.Value = 0; macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; fCtrl.Value = 0; fCtrl.Bits.Adr = AdrCtrlOn; - /* In case of a join request retransmission, the stack must prepare + /* In case of join request retransmissions, the stack must prepare * the frame again, because the network server keeps track of the random * LoRaMacDevNonce values to prevent reply attacks. */ PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 ); @@ -1572,10 +1845,6 @@ 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; @@ -1585,69 +1854,11 @@ } #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) - datarate = LoRaMacParams.ChannelsDatarate - LoRaMacParams.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 ); + RxWindowSetup( Channels[Channel].Frequency, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); +#elif defined( USE_BAND_470 ) + RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); #elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) - datarate = datarateOffsets[LoRaMacParams.ChannelsDatarate][LoRaMacParams.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( LORAMAC_FIRST_RX2_CHANNEL + ( Channel % 8 ) * LORAMAC_STEPWIDTH_RX2_CHANNEL, datarate, bandwidth, symbTimeout, false ); + RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 8 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); #else #error "Please define a frequency band in the compiler options." #endif @@ -1655,73 +1866,17 @@ static void OnRxWindow2TimerEvent( void ) { - uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0 - uint32_t bandwidth = 0; // LoRa 125 kHz + bool rxContinuousMode = false; 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( ( LoRaMacParams.Rx2Channel.Datarate == DR_3 ) || ( LoRaMacParams.Rx2Channel.Datarate == DR_4 ) ) - { // DR_4, DR_3 - symbTimeout = 8; - } - else if( LoRaMacParams.Rx2Channel.Datarate == DR_5 ) - { - symbTimeout = 10; - } - else if( LoRaMacParams.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( LoRaMacParams.Rx2Channel.Datarate ) + + if( LoRaMacDeviceClass == CLASS_C ) { - 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; + rxContinuousMode = true; } - if( LoRaMacParams.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 ) + if( RxWindowSetup( LoRaMacParams.Rx2Channel.Frequency, RxWindowsParams[1].Datarate, RxWindowsParams[1].Bandwidth, RxWindowsParams[1].RxWindowTimeout, rxContinuousMode ) == true ) { - RxWindowSetup( LoRaMacParams.Rx2Channel.Frequency, LoRaMacParams.Rx2Channel.Datarate, bandwidth, symbTimeout, false ); - } - else - { - RxWindowSetup( LoRaMacParams.Rx2Channel.Frequency, LoRaMacParams.Rx2Channel.Datarate, bandwidth, symbTimeout, true ); + RxSlot = 1; } } @@ -1732,7 +1887,7 @@ if( NodeAckRequested == true ) { AckTimeoutRetry = true; - LoRaMacState &= ~MAC_ACK_REQ; + LoRaMacState &= ~LORAMAC_ACK_REQ; } if( LoRaMacDeviceClass == CLASS_C ) { @@ -1758,6 +1913,16 @@ { // Make sure, that the channels are activated ChannelsMaskRemaining[4] = LoRaMacParams.ChannelsMask[4]; } +#elif defined( USE_BAND_470 ) + if( ( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[1], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[2], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[3], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[4], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[5], 16 ) == 0 ) ) + { + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + } #else if( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 ) { @@ -1774,7 +1939,7 @@ // Update bands Time OFF for( uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++ ) { - if( DutyCycleOn == true ) + if( ( IsLoRaMacNetworkJoined == false ) || ( DutyCycleOn == true ) ) { if( Bands[i].TimeOff <= TimerGetElapsedTime( Bands[i].LastTxDoneTime ) ) { @@ -1782,15 +1947,15 @@ } if( Bands[i].TimeOff != 0 ) { - nextTxDelay = MIN( Bands[i].TimeOff - - TimerGetElapsedTime( Bands[i].LastTxDoneTime ), - nextTxDelay ); + nextTxDelay = MIN( Bands[i].TimeOff - TimerGetElapsedTime( Bands[i].LastTxDoneTime ), nextTxDelay ); } } else { - nextTxDelay = 0; - Bands[i].TimeOff = 0; + if( DutyCycleOn == false ) + { + Bands[i].TimeOff = 0; + } } } @@ -1865,23 +2030,7 @@ } } -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 ) +static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ) { uint8_t downlinkDatarate = Datarates[datarate]; RadioModems_t modem; @@ -1897,14 +2046,14 @@ 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 ); + Radio.SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, timeout, false, 0, true, 0, 0, false, rxContinuous ); } else { modem = MODEM_LORA; Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); } -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +#elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) modem = MODEM_LORA; Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); #endif @@ -1926,18 +2075,20 @@ { Radio.Rx( 0 ); // Continuous mode } + return true; } + return false; } static bool Rx2FreqInRange( uint32_t freq ) { #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) if( Radio.CheckRfFrequency( freq ) == true ) -#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) +#elif defined( USE_BAND_470 ) || 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 ) ) + ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) && + ( freq <= LORAMAC_LAST_RX1_CHANNEL ) && + ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) ) #endif { return true; @@ -1999,27 +2150,27 @@ } #if defined( USE_BAND_915_HYBRID ) -static void ReenableChannels( uint16_t mask, uint16_t* channelMask ) +static void ReenableChannels( uint16_t mask, uint16_t* channelsMask ) { uint16_t blockMask = mask; for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 ) { - channelMask[i] = 0; + channelsMask[i] = 0; if( ( blockMask & ( 1 << j ) ) != 0 ) { - channelMask[i] |= 0x00FF; + channelsMask[i] |= 0x00FF; } if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 ) { - channelMask[i] |= 0xFF00; + channelsMask[i] |= 0xFF00; } } - channelMask[4] = blockMask; - channelMask[5] = 0x0000; + channelsMask[4] = blockMask; + channelsMask[5] = 0x0000; } -static bool ValidateChannelMask( uint16_t* channelMask ) +static bool ValidateChannelMask( uint16_t* channelsMask ) { bool chanMaskState = false; uint16_t block1 = 0; @@ -2028,20 +2179,20 @@ for( uint8_t i = 0; i < 4; i++ ) { - block1 = channelMask[i] & 0x00FF; - block2 = channelMask[i] & 0xFF00; + block1 = channelsMask[i] & 0x00FF; + block2 = channelsMask[i] & 0xFF00; if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) ) { - channelMask[i] &= block1; - channelMask[4] = 1 << ( i * 2 ); + channelsMask[i] &= block1; + channelsMask[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 ); + channelsMask[i] &= block2; + channelsMask[4] = 1 << ( i * 2 + 1 ); chanMaskState = true; index = i; } @@ -2054,7 +2205,7 @@ { if( i != index ) { - channelMask[i] = 0; + channelsMask[i] = 0; } } } @@ -2063,9 +2214,36 @@ #endif #endif -static int8_t LimitTxPower( int8_t txPower ) +static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask ) +{ + if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false ) + { + return false; + } + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) + { + for( uint8_t j = 0; j < 16; j++ ) + { + if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) ) + {// Check datarate validity for enabled channels + if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true ) + { + // At least 1 channel has been found we can return OK. + return true; + } + } + } + } + return false; +} + +static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower ) { int8_t resultTxPower = txPower; + + // Limit tx power to the band max + resultTxPower = MAX( txPower, maxBandTxPower ); + #if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) if( ( LoRaMacParams.ChannelsDatarate == DR_4 ) || ( ( LoRaMacParams.ChannelsDatarate >= DR_8 ) && ( LoRaMacParams.ChannelsDatarate <= DR_13 ) ) ) @@ -2125,6 +2303,7 @@ if( AdrAckCounter >= ADR_ACK_LIMIT ) { adrAckReq = true; + LoRaMacParams.ChannelsTxPower = LORAMAC_MAX_TX_POWER; } else { @@ -2132,7 +2311,7 @@ } if( AdrAckCounter >= ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) ) { - if( ( AdrAckCounter % ADR_ACK_DELAY ) == 0 ) + if( ( AdrAckCounter % ADR_ACK_DELAY ) == 1 ) { #if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) if( datarate > LORAMAC_TX_MIN_DATARATE ) @@ -2147,6 +2326,19 @@ LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); } } +#elif defined( USE_BAND_470 ) + if( datarate > LORAMAC_TX_MIN_DATARATE ) + { + datarate--; + } + if( datarate == LORAMAC_TX_MIN_DATARATE ) + { + if( updateChannelMask == true ) + { + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + } + } #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) if( ( datarate > LORAMAC_TX_MIN_DATARATE ) && ( datarate == DR_8 ) ) { @@ -2162,15 +2354,10 @@ { #if defined( USE_BAND_915 ) // Re-enable default channels - LoRaMacParams.ChannelsMask[0] = 0xFFFF; - LoRaMacParams.ChannelsMask[1] = 0xFFFF; - LoRaMacParams.ChannelsMask[2] = 0xFFFF; - LoRaMacParams.ChannelsMask[3] = 0xFFFF; - LoRaMacParams.ChannelsMask[4] = 0x00FF; - LoRaMacParams.ChannelsMask[5] = 0x0000; + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); #else // defined( USE_BAND_915_HYBRID ) // Re-enable default channels - ReenableChannels( LoRaMacParams.ChannelsMask[4], LoRaMacParams.ChannelsMask ); + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); #endif } } @@ -2281,10 +2468,10 @@ { switch( cmdBufIn[i] ) { + // STICKY case MOTE_MAC_RX_PARAM_SETUP_ANS: { cmdBufOut[cmdCount++] = cmdBufIn[i++]; - cmdBufOut[cmdCount++] = cmdBufIn[i++]; cmdBufOut[cmdCount++] = cmdBufIn[i]; break; } @@ -2293,6 +2480,23 @@ cmdBufOut[cmdCount++] = cmdBufIn[i]; break; } + // NON-STICKY + case MOTE_MAC_DEV_STATUS_ANS: + { // 2 bytes payload + i += 2; + break; + } + case MOTE_MAC_LINK_ADR_ANS: + case MOTE_MAC_NEW_CHANNEL_ANS: + { // 1 byte payload + i++; + break; + } + case MOTE_MAC_DUTY_CYCLE_ANS: + case MOTE_MAC_LINK_CHECK_REQ: + { // 0 byte payload + break; + } default: break; } @@ -2387,11 +2591,11 @@ } channelsMask[0] = chMask; } -#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +#elif defined( USE_BAND_470 ) if( chMaskCntl == 6 ) { // Enable all 125 kHz channels - for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ ) + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) { for( uint8_t j = 0; j < 16; j++ ) { @@ -2404,15 +2608,6 @@ } else if( chMaskCntl == 7 ) { - // Disable all 125 kHz channels - channelsMask[0] = 0x0000; - channelsMask[1] = 0x0000; - channelsMask[2] = 0x0000; - channelsMask[3] = 0x0000; - } - else if( chMaskCntl == 5 ) - { - // RFU status &= 0xFE; // Channel mask KO } else @@ -2426,8 +2621,39 @@ } } channelsMask[chMaskCntl] = chMask; - - if( CountNbEnabled125kHzChannels( channelsMask ) < 6 ) + } +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( chMaskCntl == 6 ) + { + // Enable all 125 kHz channels + channelsMask[0] = 0xFFFF; + channelsMask[1] = 0xFFFF; + channelsMask[2] = 0xFFFF; + channelsMask[3] = 0xFFFF; + // Apply chMask to channels 64 to 71 + channelsMask[4] = chMask; + } + else if( chMaskCntl == 7 ) + { + // Disable all 125 kHz channels + channelsMask[0] = 0x0000; + channelsMask[1] = 0x0000; + channelsMask[2] = 0x0000; + channelsMask[3] = 0x0000; + // Apply chMask to channels 64 to 71 + channelsMask[4] = chMask; + } + else if( chMaskCntl == 5 ) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + channelsMask[chMaskCntl] = chMask; + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if( ( datarate < DR_4 ) && ( CountNbEnabled125kHzChannels( channelsMask ) < 2 ) ) { status &= 0xFE; // Channel mask KO } @@ -2442,7 +2668,7 @@ #else #error "Please define a frequency band in the compiler options." #endif - if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false ) + if( ValidateDatarate( datarate, channelsMask ) == false ) { status &= 0xFD; // Datarate KO } @@ -2459,14 +2685,18 @@ LoRaMacParams.ChannelsDatarate = datarate; LoRaMacParams.ChannelsTxPower = txPower; - LoRaMacParams.ChannelsMask[0] = channelsMask[0]; - LoRaMacParams.ChannelsMask[1] = channelsMask[1]; - LoRaMacParams.ChannelsMask[2] = channelsMask[2]; - LoRaMacParams.ChannelsMask[3] = channelsMask[3]; - LoRaMacParams.ChannelsMask[4] = channelsMask[4]; - LoRaMacParams.ChannelsMask[5] = channelsMask[5]; + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )channelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); LoRaMacParams.ChannelsNbRep = nbRep; +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + // Reset ChannelsMaskRemaining to the new ChannelsMask + ChannelsMaskRemaining[0] &= channelsMask[0]; + ChannelsMaskRemaining[1] &= channelsMask[1]; + ChannelsMaskRemaining[2] &= channelsMask[2]; + ChannelsMaskRemaining[3] &= channelsMask[3]; + ChannelsMaskRemaining[4] = channelsMask[4]; + ChannelsMaskRemaining[5] = channelsMask[5]; +#endif } AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 ); } @@ -2536,7 +2766,7 @@ { uint8_t status = 0x03; -#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) +#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) status &= 0xFC; // Channel frequency and datarate KO macIndex += 5; #else @@ -2550,7 +2780,7 @@ chParam.Frequency *= 100; chParam.DrRange.Value = payload[macIndex++]; - LoRaMacState |= MAC_TX_CONFIG; + LoRaMacState |= LORAMAC_TX_CONFIG; if( chParam.Frequency == 0 ) { if( channelIndex < 3 ) @@ -2595,7 +2825,7 @@ } } } - LoRaMacState &= ~MAC_TX_CONFIG; + LoRaMacState &= ~LORAMAC_TX_CONFIG; #endif AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 ); } @@ -2608,8 +2838,8 @@ { delay++; } - LoRaMacParams.ReceiveDelay1 = delay * 1e6; - LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e6; + LoRaMacParams.ReceiveDelay1 = delay * 1e3; + LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3; AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 ); } break; @@ -2651,7 +2881,7 @@ return status; } -static LoRaMacStatus_t ScheduleTx( ) +static LoRaMacStatus_t ScheduleTx( void ) { TimerTime_t dutyCycleTimeOff = 0; @@ -2665,8 +2895,6 @@ AggregatedTimeOff = 0; } - CalculateBackOff( LastTxChannel ); - // Select channel while( SetNextChannel( &dutyCycleTimeOff ) == false ) { @@ -2679,6 +2907,30 @@ #endif } + // Compute Rx1 windows parameters +#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + RxWindowsParams[0] = ComputeRxWindowParameters( DatarateOffsets[LoRaMacParams.ChannelsDatarate][LoRaMacParams.Rx1DrOffset], LoRaMacParams.SystemMaxRxError ); +#else + RxWindowsParams[0] = ComputeRxWindowParameters( MAX( DR_0, LoRaMacParams.ChannelsDatarate - LoRaMacParams.Rx1DrOffset ), LoRaMacParams.SystemMaxRxError ); +#endif + // Compute Rx2 windows parameters + RxWindowsParams[1] = ComputeRxWindowParameters( LoRaMacParams.Rx2Channel.Datarate, LoRaMacParams.SystemMaxRxError ); + + if( IsLoRaMacNetworkJoined == false ) + { + RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 + RxWindowsParams[0].RxOffset; + RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 + RxWindowsParams[1].RxOffset; + } + else + { + if( ValidatePayloadLength( LoRaMacTxPayloadLen, LoRaMacParams.ChannelsDatarate, MacCommandsBufferIndex ) == false ) + { + return LORAMAC_STATUS_LENGTH_ERROR; + } + RxWindow1Delay = LoRaMacParams.ReceiveDelay1 + RxWindowsParams[0].RxOffset; + RxWindow2Delay = LoRaMacParams.ReceiveDelay2 + RxWindowsParams[1].RxOffset; + } + // Schedule transmission of frame if( dutyCycleTimeOff == 0 ) { @@ -2688,7 +2940,7 @@ else { // Send later - prepare timer - LoRaMacState |= MAC_TX_DELAYED; + LoRaMacState |= LORAMAC_TX_DELAYED; TimerSetValue( &TxDelayedTimer, dutyCycleTimeOff ); TimerStart( &TxDelayedTimer ); @@ -2696,18 +2948,16 @@ } } -static uint16_t RetransmissionDutyCylce( void ) +static uint16_t JoinDutyCycle( void ) { uint16_t dutyCycle = 0; - -#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) - TimerTime_t timeElapsed = TimerGetElapsedTime( 0 ); - - if( timeElapsed < 3600000000 ) + TimerTime_t timeElapsed = TimerGetElapsedTime( LoRaMacInitializationTime ); + + if( timeElapsed < 3600e3 ) { dutyCycle = BACKOFF_DC_1_HOUR; } - else if( timeElapsed < ( 3600000000 + 36000000000 ) ) + else if( timeElapsed < ( 3600e3 + 36000e3 ) ) { dutyCycle = BACKOFF_DC_10_HOURS; } @@ -2715,7 +2965,6 @@ { dutyCycle = BACKOFF_DC_24_HOURS; } -#endif return dutyCycle; } @@ -2723,34 +2972,25 @@ { uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle; uint16_t joinDutyCycle = 0; - bool rndTimeOff = false; + + // Reset time-off to initial value. + Bands[Channels[channel].Band].TimeOff = 0; if( IsLoRaMacNetworkJoined == false ) { - joinDutyCycle = RetransmissionDutyCylce( ); + // The node has not joined yet. Apply join duty cycle to all regions. + joinDutyCycle = JoinDutyCycle( ); dutyCycle = MAX( dutyCycle, joinDutyCycle ); - // Make sure to not apply the random back-off to the first TX - if( TxTimeOnAir > 0 ) - { - rndTimeOff = true; - } - } - - // Update Band Time OFF - if( DutyCycleOn == true ) - { + // Update Band time-off. Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; } else { - Bands[Channels[channel].Band].TimeOff = 0; - } - - if( rndTimeOff == true ) - { - Bands[Channels[channel].Band].TimeOff = randr( Bands[Channels[channel].Band].TimeOff, - Bands[Channels[channel].Band].TimeOff + BACKOFF_RND_OFFSET ); + if( DutyCycleOn == true ) + { + Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; + } } // Update Aggregated Time OFF @@ -2766,7 +3006,7 @@ LoRaMacParams.ChannelsMask[4] = 0x00FF; #else // defined( USE_BAND_915_HYBRID ) // Re-enable 500 kHz default channels - ReenableChannels( LoRaMacParams.ChannelsMask[4], LoRaMacParams.ChannelsMask ); + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); #endif if( ( nbTrials & 0x01 ) == 0x01 ) @@ -2775,7 +3015,7 @@ } else { - datarate = DR_1; + datarate = DR_0; } #else if( ( nbTrials % 48 ) == 0 ) @@ -2811,7 +3051,7 @@ IsLoRaMacNetworkJoined = false; // Counters - UpLinkCounter = 1; + UpLinkCounter = 0; DownLinkCounter = 0; AdrAckCounter = 0; @@ -2832,15 +3072,7 @@ LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower; LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate; - LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow; - LoRaMacParams.ReceiveDelay1 = LoRaMacParamsDefaults.ReceiveDelay1; - LoRaMacParams.ReceiveDelay2 = LoRaMacParamsDefaults.ReceiveDelay2; - LoRaMacParams.JoinAcceptDelay1 = LoRaMacParamsDefaults.JoinAcceptDelay1; - LoRaMacParams.JoinAcceptDelay2 = LoRaMacParamsDefaults.JoinAcceptDelay2; - LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset; - LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep; - LoRaMacParams.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel; memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); @@ -2872,7 +3104,6 @@ uint8_t pktHeaderLen = 0; uint32_t mic = 0; const void* payload = fBuffer; - uint8_t payloadSize = fBufferSize; uint8_t framePort = fPort; LoRaMacBufferPktLen = 0; @@ -2884,14 +3115,13 @@ fBufferSize = 0; } + LoRaMacTxPayloadLen = fBufferSize; + LoRaMacBuffer[pktHeaderLen++] = macHdr->Value; switch( macHdr->Bits.MType ) { case FRAME_TYPE_JOIN_REQ: - RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 - RADIO_WAKEUP_TIME; - RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 - RADIO_WAKEUP_TIME; - LoRaMacBufferPktLen = pktHeaderLen; memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 ); @@ -2914,7 +3144,7 @@ break; case FRAME_TYPE_DATA_CONFIRMED_UP: NodeAckRequested = true; - //Intentional falltrough + //Intentional fallthrough case FRAME_TYPE_DATA_UNCONFIRMED_UP: if( IsLoRaMacNetworkJoined == false ) { @@ -2923,14 +3153,6 @@ fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &LoRaMacParams.ChannelsDatarate ); - if( ValidatePayloadLength( fBufferSize, LoRaMacParams.ChannelsDatarate, MacCommandsBufferIndex ) == false ) - { - return LORAMAC_STATUS_LENGTH_ERROR; - } - - RxWindow1Delay = LoRaMacParams.ReceiveDelay1 - RADIO_WAKEUP_TIME; - RxWindow2Delay = LoRaMacParams.ReceiveDelay2 - RADIO_WAKEUP_TIME; - if( SrvAckRequested == true ) { SrvAckRequested = false; @@ -2951,7 +3173,7 @@ memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex ); MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex; - if( ( payload != NULL ) && ( payloadSize > 0 ) ) + if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) { if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) ) { @@ -2969,7 +3191,7 @@ { if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) ) { - payloadSize = MacCommandsBufferIndex; + LoRaMacTxPayloadLen = MacCommandsBufferIndex; payload = MacCommandsBuffer; framePort = 0; } @@ -2981,23 +3203,21 @@ { MacCommandsInNextTx = true; } - MacCommandsBufferIndex = 0; - - if( ( payload != NULL ) && ( payloadSize > 0 ) ) + + if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) { LoRaMacBuffer[pktHeaderLen++] = framePort; if( framePort == 0 ) { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload ); + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); } else { - LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload ); + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); } - memcpy1( LoRaMacBuffer + pktHeaderLen, LoRaMacPayload, payloadSize ); } - LoRaMacBufferPktLen = pktHeaderLen + payloadSize; + LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic ); @@ -3010,10 +3230,10 @@ break; case FRAME_TYPE_PROPRIETARY: - if( ( fBuffer != NULL ) && ( fBufferSize > 0 ) ) + if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) { - memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, fBufferSize ); - LoRaMacBufferPktLen = pktHeaderLen + fBufferSize; + memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen ); + LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; } break; default: @@ -3029,13 +3249,14 @@ int8_t txPowerIndex = 0; int8_t txPower = 0; - txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower ); + txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[channel.Band].TxMaxPower ); txPower = TxPowers[txPowerIndex]; MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate; McpsConfirm.TxPower = txPowerIndex; + McpsConfirm.UpLinkFrequency = channel.Frequency; Radio.SetChannel( channel.Frequency ); @@ -3043,34 +3264,38 @@ if( LoRaMacParams.ChannelsDatarate == DR_7 ) { // High Speed FSK channel Radio.SetMaxPayloadLength( MODEM_FSK, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e6 ); + Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e3 ); TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen ); } else if( LoRaMacParams.ChannelsDatarate == DR_6 ) { // High speed LoRa channel Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); } else { // Normal LoRa channel Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); } #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); if( LoRaMacParams.ChannelsDatarate >= DR_4 ) { // High speed LoRa channel BW500 kHz - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); } else { // Normal LoRa channel - Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e6 ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); } +#elif defined( USE_BAND_470 ) + Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); #else #error "Please define a frequency band in the compiler options." #endif @@ -3083,10 +3308,47 @@ TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); TimerStart( &MacStateCheckTimer ); + if( IsLoRaMacNetworkJoined == false ) + { + JoinRequestTrials++; + } + // Send now Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen ); - LoRaMacState |= MAC_TX_RUNNING; + LoRaMacState |= LORAMAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout ) +{ + int8_t txPowerIndex = 0; + int8_t txPower = 0; + + txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[Channels[Channel].Band].TxMaxPower ); + txPower = TxPowers[txPowerIndex]; + + // Starts the MAC layer status check timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + + Radio.SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout ); + + LoRaMacState |= LORAMAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ) +{ + Radio.SetTxContinuousWave( frequency, power, timeout ); + + // Starts the MAC layer status check timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + + LoRaMacState |= LORAMAC_TX_RUNNING; return LORAMAC_STATUS_OK; } @@ -3100,7 +3362,7 @@ if( ( primitives->MacMcpsConfirm == NULL ) || ( primitives->MacMcpsIndication == NULL ) || - ( primitives->MacMlmeConfirm == NULL )) + ( primitives->MacMlmeConfirm == NULL ) ) { return LORAMAC_STATUS_PARAMETER_INVALID; } @@ -3111,9 +3373,10 @@ LoRaMacFlags.Value = 0; LoRaMacDeviceClass = CLASS_A; - LoRaMacState = MAC_IDLE; + LoRaMacState = LORAMAC_IDLE; JoinRequestTrials = 0; + MaxJoinRequestTrials = 1; RepeaterSupport = false; // Reset duty cycle times @@ -3122,9 +3385,11 @@ // Duty cycle #if defined( USE_BAND_433 ) + DutyCycleOn = true; +#elif defined( USE_BAND_470 ) DutyCycleOn = false; #elif defined( USE_BAND_780 ) - DutyCycleOn = false; + DutyCycleOn = true; #elif defined( USE_BAND_868 ) DutyCycleOn = true; #elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) @@ -3137,6 +3402,8 @@ LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; LoRaMacParamsDefaults.ChannelsDatarate = LORAMAC_DEFAULT_DATARATE; + LoRaMacParamsDefaults.SystemMaxRxError = 10; + LoRaMacParamsDefaults.MinRxSymbols = 6; LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW; LoRaMacParamsDefaults.ReceiveDelay1 = RECEIVE_DELAY1; LoRaMacParamsDefaults.ReceiveDelay2 = RECEIVE_DELAY2; @@ -3151,6 +3418,13 @@ // Channel mask #if defined( USE_BAND_433 ) LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); +#elif defined ( USE_BAND_470 ) + LoRaMacParamsDefaults.ChannelsMask[0] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[1] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[2] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[3] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[4] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[5] = 0xFFFF; #elif defined( USE_BAND_780 ) LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); #elif defined( USE_BAND_868 ) @@ -3188,8 +3462,26 @@ Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4; Channels[i].Band = 0; } +#elif defined( USE_BAND_470 ) + // 125 kHz channels + for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ ) + { + Channels[i].Frequency = 470.3e6 + i * 200e3; + Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0; + Channels[i].Band = 0; + } #endif + // Init parameters which are not set in function ResetMacParameters + LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError; + LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols; + LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow; + LoRaMacParams.ReceiveDelay1 = LoRaMacParamsDefaults.ReceiveDelay1; + LoRaMacParams.ReceiveDelay2 = LoRaMacParamsDefaults.ReceiveDelay2; + LoRaMacParams.JoinAcceptDelay1 = LoRaMacParamsDefaults.JoinAcceptDelay1; + LoRaMacParams.JoinAcceptDelay2 = LoRaMacParamsDefaults.JoinAcceptDelay2; + LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep; + ResetMacParameters( ); // Initialize timers @@ -3201,6 +3493,9 @@ TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent ); TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent ); + // Store the current initialization time + LoRaMacInitializationTime = TimerGetCurrentTime( ); + // Initialize Radio driver RadioEvents.TxDone = OnRadioTxDone; RadioEvents.RxDone = OnRadioRxDone; @@ -3213,7 +3508,7 @@ srand1( Radio.Random( ) ); PublicNetwork = true; - SetPublicNetwork( PublicNetwork ); + Radio.SetPublicNetwork( PublicNetwork ); Radio.Sleep( ); return LORAMAC_STATUS_OK; @@ -3328,6 +3623,16 @@ mibGet->Param.Rx2Channel = LoRaMacParams.Rx2Channel; break; } + case MIB_RX2_DEFAULT_CHANNEL: + { + mibGet->Param.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel; + break; + } + case MIB_CHANNELS_DEFAULT_MASK: + { + mibGet->Param.ChannelsDefaultMask = LoRaMacParamsDefaults.ChannelsMask; + break; + } case MIB_CHANNELS_MASK: { mibGet->Param.ChannelsMask = LoRaMacParams.ChannelsMask; @@ -3373,6 +3678,11 @@ mibGet->Param.ChannelsDatarate = LoRaMacParams.ChannelsDatarate; break; } + case MIB_CHANNELS_DEFAULT_TX_POWER: + { + mibGet->Param.ChannelsDefaultTxPower = LoRaMacParamsDefaults.ChannelsTxPower; + break; + } case MIB_CHANNELS_TX_POWER: { mibGet->Param.ChannelsTxPower = LoRaMacParams.ChannelsTxPower; @@ -3393,6 +3703,16 @@ mibGet->Param.MulticastList = MulticastChannels; break; } + case MIB_SYSTEM_MAX_RX_ERROR: + { + mibGet->Param.SystemMaxRxError = LoRaMacParams.SystemMaxRxError; + break; + } + case MIB_MIN_RX_SYMBOLS: + { + mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols; + break; + } default: status = LORAMAC_STATUS_SERVICE_UNKNOWN; break; @@ -3409,7 +3729,7 @@ { return LORAMAC_STATUS_PARAMETER_INVALID; } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { return LORAMAC_STATUS_BUSY; } @@ -3489,7 +3809,8 @@ } case MIB_PUBLIC_NETWORK: { - SetPublicNetwork( mibSet->Param.EnablePublicNetwork ); + PublicNetwork = mibSet->Param.EnablePublicNetwork; + Radio.SetPublicNetwork( PublicNetwork ); break; } case MIB_REPEATER_SUPPORT: @@ -3502,6 +3823,57 @@ LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel; break; } + case MIB_RX2_DEFAULT_CHANNEL: + { + LoRaMacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel; + break; + } + case MIB_CHANNELS_DEFAULT_MASK: + { + if( mibSet->Param.ChannelsDefaultMask ) + { +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + bool chanMaskState = true; + +#if defined( USE_BAND_915_HYBRID ) + chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsDefaultMask ); +#endif + if( chanMaskState == true ) + { + if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) && + ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + else + { + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) ); + for ( uint8_t i = 0; i < sizeof( LoRaMacParamsDefaults.ChannelsMask ) / 2; i++ ) + { + // Disable channels which are no longer available + ChannelsMaskRemaining[i] &= LoRaMacParamsDefaults.ChannelsMask[i]; + } + } + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } +#elif defined( USE_BAND_470 ) + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) ); +#else + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, 2 ); +#endif + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } case MIB_CHANNELS_MASK: { if( mibSet->Param.ChannelsMask ) @@ -3514,7 +3886,7 @@ #endif if( chanMaskState == true ) { - if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) && + if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) && ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) { status = LORAMAC_STATUS_PARAMETER_INVALID; @@ -3534,6 +3906,9 @@ { status = LORAMAC_STATUS_PARAMETER_INVALID; } +#elif defined( USE_BAND_470 ) + memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); #else memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) mibSet->Param.ChannelsMask, 2 ); @@ -3585,11 +3960,19 @@ } case MIB_CHANNELS_DEFAULT_DATARATE: { +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, + DR_0, DR_5 ) ) + { + LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate; + } +#else if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) { LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate; } +#endif else { status = LORAMAC_STATUS_PARAMETER_INVALID; @@ -3609,6 +3992,19 @@ } break; } + case MIB_CHANNELS_DEFAULT_TX_POWER: + { + if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower, + LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) ) + { + LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } case MIB_CHANNELS_TX_POWER: { if( ValueInRange( mibSet->Param.ChannelsTxPower, @@ -3632,6 +4028,16 @@ DownLinkCounter = mibSet->Param.DownLinkCounter; break; } + case MIB_SYSTEM_MAX_RX_ERROR: + { + LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError; + break; + } + case MIB_MIN_RX_SYMBOLS: + { + LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols; + break; + } default: status = LORAMAC_STATUS_SERVICE_UNKNOWN; break; @@ -3642,7 +4048,7 @@ LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params ) { -#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) +#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) return LORAMAC_STATUS_PARAMETER_INVALID; #else bool datarateInvalid = false; @@ -3655,9 +4061,9 @@ return LORAMAC_STATUS_PARAMETER_INVALID; } // Validate if the MAC is in a correct state - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { - if( ( LoRaMacState & MAC_TX_CONFIG ) != MAC_TX_CONFIG ) + if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG ) { return LORAMAC_STATUS_BUSY; } @@ -3680,7 +4086,7 @@ frequencyInvalid = true; } - if( params.DrRange.Fields.Min > LoRaMacParamsDefaults.ChannelsDatarate ) + if( params.DrRange.Fields.Min > DR_0 ) { datarateInvalid = true; } @@ -3695,7 +4101,11 @@ if( ( Radio.CheckRfFrequency( params.Frequency ) == true ) && ( params.Frequency > 0 ) && ( frequencyInvalid == false ) ) { #if defined( USE_BAND_868 ) - if( ( params.Frequency >= 865000000 ) && ( params.Frequency <= 868000000 ) ) + if( ( params.Frequency >= 863000000 ) && ( params.Frequency < 865000000 ) ) + { + band = BAND_G1_2; + } + else if( ( params.Frequency >= 865000000 ) && ( params.Frequency <= 868000000 ) ) { band = BAND_G1_0; } @@ -3751,9 +4161,9 @@ 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 & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { - if( ( LoRaMacState & MAC_TX_CONFIG ) != MAC_TX_CONFIG ) + if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG ) { return LORAMAC_STATUS_BUSY; } @@ -3775,7 +4185,7 @@ } } return LORAMAC_STATUS_OK; -#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) +#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) || defined( USE_BAND_470 ) ) return LORAMAC_STATUS_PARAMETER_INVALID; #endif } @@ -3786,7 +4196,7 @@ { return LORAMAC_STATUS_PARAMETER_INVALID; } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { return LORAMAC_STATUS_BUSY; } @@ -3821,7 +4231,7 @@ { return LORAMAC_STATUS_PARAMETER_INVALID; } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { return LORAMAC_STATUS_BUSY; } @@ -3863,7 +4273,7 @@ { return LORAMAC_STATUS_PARAMETER_INVALID; } - if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) { return LORAMAC_STATUS_BUSY; } @@ -3876,33 +4286,52 @@ { case MLME_JOIN: { - if( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED ) + if( ( LoRaMacState & LORAMAC_TX_DELAYED ) == LORAMAC_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 ) ) + ( mlmeRequest->Req.Join.AppKey == NULL ) || + ( mlmeRequest->Req.Join.NbTrials == 0 ) ) { return LORAMAC_STATUS_PARAMETER_INVALID; } +#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + // Enables at least the usage of the 2 datarates. + if( mlmeRequest->Req.Join.NbTrials < 2 ) + { + mlmeRequest->Req.Join.NbTrials = 2; + } +#else + // Enables at least the usage of all datarates. + if( mlmeRequest->Req.Join.NbTrials < 48 ) + { + mlmeRequest->Req.Join.NbTrials = 48; + } +#endif + LoRaMacFlags.Bits.MlmeReq = 1; + MlmeConfirm.MlmeRequest = mlmeRequest->Type; LoRaMacDevEui = mlmeRequest->Req.Join.DevEui; LoRaMacAppEui = mlmeRequest->Req.Join.AppEui; LoRaMacAppKey = mlmeRequest->Req.Join.AppKey; - + MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials; + + // Reset variable JoinRequestTrials + JoinRequestTrials = 0; + + // Setup header information macHdr.Value = 0; macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; ResetMacParameters( ); - JoinRequestTrials++; - LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials ); + // Add a +1, since we start to count from 0 + LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 ); status = Send( &macHdr, 0, NULL, 0 ); break; @@ -3916,6 +4345,20 @@ status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 ); break; } + case MLME_TXCW: + { + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + LoRaMacFlags.Bits.MlmeReq = 1; + status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout ); + break; + } + case MLME_TXCW_1: + { + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + LoRaMacFlags.Bits.MlmeReq = 1; + status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power ); + break; + } default: break; } @@ -3943,8 +4386,8 @@ { return LORAMAC_STATUS_PARAMETER_INVALID; } - if( ( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING ) || - ( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED ) ) + if( ( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) || + ( ( LoRaMacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED ) ) { return LORAMAC_STATUS_BUSY; } @@ -4037,5 +4480,52 @@ void LoRaMacTestSetDutyCycleOn( bool enable ) { +#if ( defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) ) DutyCycleOn = enable; +#else + DutyCycleOn = false; +#endif } + +void LoRaMacTestSetChannel( uint8_t channel ) +{ + Channel = channel; +} + +static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ) +{ + RxConfigParams_t rxConfigParams = { 0, 0, 0, 0 }; + double tSymbol = 0.0; + + rxConfigParams.Datarate = datarate; + switch( Bandwidths[datarate] ) + { + default: + case 125000: + rxConfigParams.Bandwidth = 0; + break; + case 250000: + rxConfigParams.Bandwidth = 1; + break; + case 500000: + rxConfigParams.Bandwidth = 2; + break; + } + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( datarate == DR_7 ) + { // FSK + tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte + } + else +#endif + { // LoRa + tSymbol = ( ( double )( 1 << Datarates[datarate] ) / ( double )Bandwidths[datarate] ) * 1e3; + } + + rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols + + rxConfigParams.RxOffset = ( int32_t )ceil( ( 4.0 * tSymbol ) - ( ( rxConfigParams.RxWindowTimeout * tSymbol ) / 2.0 ) - RADIO_WAKEUP_TIME ); + + return rxConfigParams; +}