Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of LoRaWAN_Semtech_stack_v4.1 by
Diff: mac/LoRaMac.cpp
- Revision:
- 1:2be292bd43f9
- Parent:
- 0:c58229885f95
- Child:
- 4:0aa5d153c316
--- a/mac/LoRaMac.cpp Wed Dec 16 14:25:16 2015 +0000
+++ b/mac/LoRaMac.cpp Tue Mar 15 23:27:24 2016 +0000
@@ -5,25 +5,35 @@
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(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 and Gregory Cristian
+Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
*/
-
#include "mbed.h"
+
#include "LoRaMacCrypto.h"
#include "LoRaMac.h"
+#include "LoRaMacTest.h"
+#include "LoRaMac-board.h"
+
#include "sx1272.h"
#include "sx1272Regs-LoRa.h"
-#include "utilities.h"
#include "sx1272-hal.h"
-#define USE_BAND_868
+
/*!
* Maximum PHY layer payload size
*/
#define LORAMAC_PHY_MAXPAYLOAD 255
-typedef uint64_t TimerTime_t;
+/*!
+ * Maximum MAC commands buffer size
+ */
+#define LORA_MAC_COMMAND_MAX_LENGTH 15
/*!
* Device IEEE EUI
@@ -75,7 +85,7 @@
static uint32_t LoRaMacDevAddr;
/*!
- * Mutlicast channels linked list
+ * Multicast channels linked list
*/
static MulticastParams_t *MulticastChannels = NULL;
@@ -173,7 +183,7 @@
/*!
* Buffer containing the MAC layer commands
*/
-static uint8_t MacCommandsBuffer[15];
+static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
#if defined( USE_BAND_433 )
/*!
@@ -292,12 +302,6 @@
LC1,
LC2,
LC3,
- LC4,
- LC5,
- LC6,
- LC7,
- LC8,
- LC9,
};
#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
/*!
@@ -308,7 +312,7 @@
/*!
* Up/Down link data rates offset definition
*/
-const int8_t datarateOffsets[16][4] =
+const int8_t datarateOffsets[16][4] =
{
{ DR_10, DR_9 , DR_8 , DR_8 }, // DR_0
{ DR_11, DR_10, DR_9 , DR_8 }, // DR_1
@@ -356,6 +360,11 @@
*/
static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
+/*!
+ * Contains the channels which remain to be applied.
+ */
+static uint16_t ChannelsMaskRemaining[6];
+
#else
#error "Please define a frequency band in the compiler options."
#endif
@@ -407,7 +416,7 @@
static uint8_t MaxDCycle = 0;
/*!
- * Agregated duty cycle management
+ * Aggregated duty cycle management
*/
static uint16_t AggregatedDCycle;
static TimerTime_t AggregatedLastTxDoneTime;
@@ -426,14 +435,15 @@
/*!
* LoRaMac internal states
*/
-enum LoRaMacState_e
+enum eLoRaMacState
{
MAC_IDLE = 0x00000000,
MAC_TX_RUNNING = 0x00000001,
MAC_RX = 0x00000002,
MAC_ACK_REQ = 0x00000004,
MAC_ACK_RETRY = 0x00000008,
- MAC_CHANNEL_CHECK = 0x00000010,
+ MAC_TX_DELAYED = 0x00000010,
+ MAC_TX_CONFIG = 0x00000020,
};
/*!
@@ -442,35 +452,35 @@
uint32_t LoRaMacState = MAC_IDLE;
/*!
- * LoRaMac upper layer event functions
+ * LoRaMac timer used to check the LoRaMacState (runs every second)
*/
-static LoRaMacCallbacks_t *LoRaMacCallbacks;
+static Timeout MacStateCheckTimer;
/*!
- * LoRaMac notification event flags
+ * LoRaMac upper layer event functions
*/
-LoRaMacEventFlags_t LoRaMacEventFlags;
+static LoRaMacPrimitives_t *LoRaMacPrimitives;
/*!
- * LoRaMac notification event info
+ * LoRaMac upper layer callback functions
*/
-LoRaMacEventInfo_t LoRaMacEventInfo;
+static LoRaMacCallback_t *LoRaMacCallbacks;
/*!
- * LoRaMac channel check timer
+ * Radio events function pointer
*/
-//static Timeout ChannelCheckTimer;
+//static RadioEvents_t RadioEvents;
/*!
* LoRaMac duty cycle delayed Tx timer
*/
-//static Timeout TxDelayedTimer;
+static Timeout TxDelayedTimer;
/*!
* LoRaMac reception windows timers
*/
-//static RtosTimer RxWindowTimer1;
-//static RtosTimer RxWindowTimer2;
+static Timeout RxWindowTimer1;
+static Timeout RxWindowTimer2;
/*!
* LoRaMac reception windows delay from end of Tx
@@ -496,7 +506,7 @@
/*!
* Acknowledge timeout timer. Used for packet retransmissions.
*/
-
+static Timeout AckTimeoutTimer;
/*!
* Number of trials to get a frame acknowledged
@@ -519,104 +529,134 @@
TimerTime_t TxTimeOnAir = 0;
/*!
- * Function to be executed on Radio Tx Done event
+ * 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;
+
+/*!
+ * \brief Function to be executed on Radio Tx Done event
*/
static void OnRadioTxDone( void );
/*!
- * Function to be executed on Radio Rx Done event
+ * \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 );
/*!
- * Function executed on Radio Tx Timeout event
+ * \brief Function executed on Radio Tx Timeout event
*/
static void OnRadioTxTimeout( void );
/*!
- * Function executed on Radio Rx error event
+ * \brief Function executed on Radio Rx error event
*/
static void OnRadioRxError( void );
/*!
- * Function executed on Radio Rx Timeout event
+ * \brief Function executed on Radio Rx Timeout event
*/
static void OnRadioRxTimeout( void );
/*!
- * Function executed on Resend Frame timer event.
+ * \brief Function executed on Resend Frame timer event.
*/
-static void OnMacStateCheckTimerEvent(void);
+static void OnMacStateCheckTimerEvent( void );
/*!
- * Function executed on duty cycle delayed Tx timer event
+ * \brief Function executed on duty cycle delayed Tx timer event
*/
static void OnTxDelayedTimerEvent( void );
/*!
- * Function executed on channel check timer event
+ * \brief Function executed on first Rx window timer event
*/
-static void OnChannelCheckTimerEvent( void );
+static void OnRxWindow1TimerEvent( void );
/*!
- * Function executed on first Rx window timer event
+ * \brief Function executed on second Rx window timer event
*/
-static void OnRxWindow1TimerEvent(void);
+static void OnRxWindow2TimerEvent( void );
/*!
- * Function executed on second Rx window timer event
+ * \brief Function executed on AckTimeout timer event
*/
-static void OnRxWindow2TimerEvent(void);
+static void OnAckTimeoutTimerEvent( void );
/*!
- * Function executed on AckTimeout timer event
+ * \brief Searches and set the next random available channel
+ *
+ * \retval status Function status [0: OK, 1: Unable to find a free channel]
*/
-static void OnAckTimeoutTimerEvent(void);
-
-/*!
- * Radio events function pointer
- */
-//RadioEvents_t RadioEvents;
-
-//Radio *radio;
+static TimerTime_t SetNextChannel( void );
+
+static Timer timerGeneralPurpose;
SX1272BRD radio( OnRadioTxDone, OnRadioTxTimeout, OnRadioRxDone, OnRadioRxTimeout, OnRadioRxError, NULL, NULL,
RF_SPI_MOSI, RF_SPI_MISO, RF_SPI_SCK, RF_SPI_CS,
RF_RESET, RF_DIO0, RF_DIO1, RF_DIO2, RF_DIO3, RF_DIO4, RF_DIO5, RF_RXTX_SW );
-static Timeout AckTimeoutTimer;
-static Timeout MacStateCheckTimer;
-static Timeout TxDelayedTimer;
-static Timeout ChannelCheckTimer;
-static Timeout RxWindowTimer1;
-static Timeout RxWindowTimer2;
-
-//static RtosTimer AckTimeoutTimer(OnAckTimeoutTimerEvent, osTimerOnce);
+/*!
+ * \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 );
+
/*!
- * LoRaMac timer used to check the LoRaMacState (runs every second)
+ * \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 RtosTimer MacStateCheckTimer(OnMacStateCheckTimerEvent, osTimerPeriodic);
+static void RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous );
/*!
- * LoRaMac channel check timer
- */
-//static RtosTimer TxDelayedTimer(OnTxDelayedTimerEvent, osTimerOnce);
-
-/*!
- * LoRaMac duty cycle delayed Tx timer
+ * \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 RtosTimer ChannelCheckTimer(OnChannelCheckTimerEvent, osTimerOnce);
-
-/*!
- * LoRaMac reception windows timers
- */
-//static RtosTimer RxWindowTimer1(OnRxWindow1TimerEvent, osTimerOnce);
-//static RtosTimer RxWindowTimer2(OnRxWindow2TimerEvent, osTimerOnce);
-
-/*
-* General purpose timer - time since startup
-*/
-static Timer timerGeneralPurpose;
+static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 );
/*!
* \brief Validates if the payload fits into the frame, taking the datarate
@@ -629,10 +669,12 @@
*
* \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 );
+static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
/*!
@@ -653,213 +695,92 @@
*/
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] updateChannelMask Set to true, if the channel masks shall be updated
+ *
+ * \param [OUT] datarateOut Reports the datarate which will be used next
+ *
+ * \retval Returns the state of ADR ack request
+ */
+static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut );
+
+/*!
+ * \brief Disables channel in a specified channel mask
+ *
+ * \param [IN] id - Id of the channel
+ *
+ * \param [IN] mask - Pointer to the channel mask to edit
+ *
+ * \retval [true, if disable was successful, false if not]
+ */
+static bool DisableChannelInMask( uint8_t id, uint16_t* mask );
+
+/*!
+ * \brief Decodes MAC commands in the fOpts field and in the payload
+ */
+static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
/*!
- * Searches and set the next random available channel
+ * \brief LoRaMAC layer generic send frame
*
- * \retval status Function status [0: OK, 1: Unable to find a free channel]
+ * \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.
*/
-static uint8_t LoRaMacSetNextChannel( void )
-{
- uint8_t i = 0;
- uint8_t j = 0;
- uint8_t k = 0;
- uint8_t nbEnabledChannels = 0;
- uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
- //TimerTime_t curTime = TimerGetCurrentTime( );
- TimerTime_t curTime = timerGeneralPurpose.read_us();
-
- //printf("LoRaMacSetNextChannel %llu \r\n", curTime);
-
- memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
-
- // Update Aggregated duty cycle
- if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) )
- {
- AggregatedTimeOff = 0;
- }
-
- // Update bands Time OFF
- TimerTime_t minTime = ( TimerTime_t )( -1 );
- for( i = 0; i < LORA_MAX_NB_BANDS; i++ )
- {
- if( DutyCycleOn == true )
- {
- if( Bands[i].TimeOff < ( curTime - Bands[i].LastTxDoneTime ) )
- {
- //printf("DutyCycleOn 1\r\n");
- Bands[i].TimeOff = 0;
- }
- if( Bands[i].TimeOff != 0 )
- {
- minTime = MIN( Bands[i].TimeOff, minTime );
- //printf("DutyCycleOn 2 %llu\r\n", minTime);
- }
- }
- else
- {
- printf("DutyCycleOn off\r\n");
- minTime = 0;
- Bands[i].TimeOff = 0;
- }
- }
-
- // Search how many channels are enabled
- for( i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
- {
- for( j = 0; j < 16; j++ )
- {
- if( ( ChannelsMask[k] & ( 1 << j ) ) != 0 )
- {
- if( Channels[i + j].Frequency == 0 )
- { // Check if the channel is enabled
- //printf("DutyCycleOn Check if the channel is enabled\r\n");
- continue;
- }
- 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
- //printf("DutyCycleOn Check if the current channel selection supports the given datarate\r\n");
- continue;
- }
- if( Bands[Channels[i + j].Band].TimeOff > 0 )
- { // Check if the band is available for transmission
- //printf("DutyCycleOn CCheck if the band is available for transmission\r\n");
- continue;
- }
- if( AggregatedTimeOff > 0 )
- { // Check if there is time available for transmission
- //printf("DutyCycleOn Check if there is time available for transmission\r\n");
- continue;
- }
- enabledChannels[nbEnabledChannels++] = i + j;
- printf("Enabled channels %i\r\n", enabledChannels[nbEnabledChannels-1]);
- }
- }
- }
- if( nbEnabledChannels > 0 )
- {
- Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
- LoRaMacState &= ~MAC_CHANNEL_CHECK;
- //TimerStop( &ChannelCheckTimer );
- //ChannelCheckTimer.stop();
- ChannelCheckTimer.detach();
-// printf("LoRaMacSetNextChannel return 0, channel %i \r\n", Channel);
- return 0;
- }
- // No free channel found.
- // Check again
- if( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 )
- {
- //TimerSetValue( &ChannelCheckTimer, minTime );
- //TimerStart( &ChannelCheckTimer );
- //ChannelCheckTimer.start(minTime/1000);
- ChannelCheckTimer.attach_us(OnChannelCheckTimerEvent, minTime);
- LoRaMacState |= MAC_CHANNEL_CHECK;
- }
- //printf("LoRaMacSetNextChannel return 1 \r\n");
- return 1;
-}
+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 );
/*
- * TODO: Add documentation
+ * \brief Schedules the frame according to the duty cycle
+ *
+ * \retval Status of the operation
*/
-void OnChannelCheckTimerEvent( void )
-{
- //TimerStop( &ChannelCheckTimer );
- //ChannelCheckTimer.stop();
- ChannelCheckTimer.detach();
-
- LoRaMacState &= ~MAC_CHANNEL_CHECK;
- if( LoRaMacSetNextChannel( ) == 0 )
- {
- if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
- {
- LoRaMacSendFrameOnChannel( Channels[Channel] );
- }
- }
-}
+static LoRaMacStatus_t ScheduleTx( void );
/*!
- * Adds a new MAC command to be sent.
- *
- * \Remark MAC layer internal function
+ * \brief LoRaMAC layer prepared frame buffer transmission with channel specification
*
- * \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 )
+ * \remark PrepareFrame must be called at least once before calling this
+ * function.
*
- * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full]
+ * \param [IN] channel Channel parameters
+ * \retval status Status of the operation.
*/
-static uint8_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
-{
- if( MacCommandsBufferIndex > 15 )
- {
- return 2;
- }
-
- MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
- switch( cmd )
- {
- case MOTE_MAC_LINK_CHECK_REQ:
- // No payload for this command
- break;
- case MOTE_MAC_LINK_ADR_ANS:
- // Margin
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
- break;
- case MOTE_MAC_DUTY_CYCLE_ANS:
- // No payload for this answer
- break;
- case MOTE_MAC_RX_PARAM_SETUP_ANS:
- // Status: Datarate ACK, Channel ACK
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
- break;
- case MOTE_MAC_DEV_STATUS_ANS:
- // 1st byte Battery
- // 2nd byte Margin
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
- MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
- break;
- case MOTE_MAC_NEW_CHANNEL_ANS:
- // Status: Datarate range OK, Channel frequency OK
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
- break;
- case MOTE_MAC_RX_TIMING_SETUP_ANS:
- // No payload for this answer
- break;
- default:
- return 1;
- }
- if( MacCommandsBufferIndex <= 15 )
- {
- MacCommandsInNextTx = true;
- return 0;
- }
- else
- {
- return 2;
- }
-}
-
-// TODO: Add Documentation
-static void LoRaMacNotify( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
-{
- if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->MacEvent != NULL ) )
- {
- LoRaMacCallbacks->MacEvent( flags, info );
- }
- flags->Value = 0;
-}
+LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel );
+
static unsigned char randbuf[16];
-// get random seed from wideband noise rssi
void radio_init( void )
{
//hal_disableIRQs( );
@@ -901,651 +822,1218 @@
__enable_irq();
}
-void LoRaMacInit( LoRaMacCallbacks_t *callbacks )
+static void OnRadioTxDone( void )
{
- // start general purpose timer
- timerGeneralPurpose.start();
-
- LoRaMacCallbacks = callbacks;
-
- LoRaMacEventFlags.Value = 0;
-
- LoRaMacEventInfo.TxAckReceived = false;
- LoRaMacEventInfo.TxNbRetries = 0;
- LoRaMacEventInfo.TxDatarate = 7;
- LoRaMacEventInfo.RxPort = 1;
- LoRaMacEventInfo.RxBuffer = NULL;
- LoRaMacEventInfo.RxBufferSize = 0;
- LoRaMacEventInfo.RxRssi = 0;
- LoRaMacEventInfo.RxSnr = 0;
- LoRaMacEventInfo.Energy = 0;
- LoRaMacEventInfo.DemodMargin = 0;
- LoRaMacEventInfo.NbGateways = 0;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-
- LoRaMacDeviceClass = CLASS_A;
-
- UpLinkCounter = 1;
- DownLinkCounter = 0;
-
- IsLoRaMacNetworkJoined = false;
- LoRaMacState = MAC_IDLE;
-
-#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;
-#elif defined( USE_BAND_915_HYBRID )
- ChannelsMask[0] = 0x00FF;
- ChannelsMask[1] = 0x0000;
- ChannelsMask[2] = 0x0000;
- ChannelsMask[3] = 0x0000;
- ChannelsMask[4] = 0x0001;
- ChannelsMask[5] = 0x0000;
-#else
- #error "Please define a frequency band in the compiler options."
-#endif
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- // 125 kHz channels
- for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ )
- {
- Channels[i].Frequency = 902.3e6 + i * 200e3;
- Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
- Channels[i].Band = 0;
- }
- // 500 kHz channels
- for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ )
- {
- Channels[i].Frequency = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6;
- Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
- Channels[i].Band = 0;
- }
-#endif
-
- ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER;
- ChannelsDefaultDatarate = ChannelsDatarate = LORAMAC_DEFAULT_DATARATE;
- ChannelsNbRep = 1;
- ChannelsNbRepCounter = 0;
+ TimerTime_t curTime = timerGeneralPurpose.read_us( );
- 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;
-
- //TimerInit( &MacStateCheckTimer, OnMacStateCheckTimerEvent );
- //TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT );
-
- //TimerInit( &ChannelCheckTimer, OnChannelCheckTimerEvent );
- //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;
- */
- /*
- oid ( *txDone )( ), void ( *txTimeout ) ( ), void ( *rxDone ) ( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ),
- void ( *rxTimeout ) ( ), void ( *rxError ) ( ), void ( *fhssChangeChannel ) ( uint8_t channelIndex ), void ( *cadDone ) ( bool channelActivityDetected ),
- PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset,
- PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5 )*/
-
- // initialize radio driver
- //radio = new SX1276MB1xAS( &RadioEvents, RF_SPI_MOSI, RF_SPI_MISO, RF_SPI_SCK, RF_SPI_CS, RF_RESET, RF_DIO0, RF_DIO1, RF_DIO2, RF_DIO3, RF_DIO4, RF_DIO5, RF_RXTX_SW );
- #warning check if this should be somewhere removed...
-
- radio_init();
- //radio.Init( &RadioEvents );
-
- // Random seed initialization
- srand1( radio.Random( ) );
-
- // Initialize channel index.
- Channel = LORA_MAX_NB_CHANNELS;
-
- PublicNetwork = true;
- LoRaMacSetPublicNetwork( PublicNetwork );
- radio.Sleep( );
-}
-
-void LoRaMacSetAdrOn( bool enable )
-{
- AdrCtrlOn = enable;
-}
-
-void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey )
-{
- LoRaMacNetID = netID;
- LoRaMacDevAddr = devAddr;
- LoRaMacMemCpy( nwkSKey, LoRaMacNwkSKey, 16 );
- LoRaMacMemCpy( appSKey, LoRaMacAppSKey, 16 );
-
- IsLoRaMacNetworkJoined = true;
-}
-
-void LoRaMacMulticastChannelAdd( MulticastParams_t *channelParam )
-{
- // Reset downlink counter
- channelParam->DownLinkCounter = 0;
-
- if( MulticastChannels == NULL )
+ if( LoRaMacDeviceClass != CLASS_C )
{
- MulticastChannels = channelParam;
+ radio.Sleep( );
}
else
{
- MulticastParams_t *cur = MulticastChannels;
- while( cur->Next != NULL )
- {
- cur = cur->Next;
- }
- cur->Next = channelParam;
+ OnRxWindow2TimerEvent( );
}
-}
-
-void LoRaMacMulticastChannelRemove( MulticastParams_t *channelParam )
-{
- MulticastParams_t *cur = NULL;
-
- // Remove the front element
- if( MulticastChannels == channelParam )
+
+ // Update Band Time OFF
+ Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
+ if( DutyCycleOn == true )
+ {
+ Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
+ }
+ else
{
- if( MulticastChannels != NULL )
- {
- cur = MulticastChannels;
- MulticastChannels = MulticastChannels->Next;
- cur->Next = NULL;
- // Last node in the list
- if( cur == MulticastChannels )
- {
- MulticastChannels = NULL;
- }
- }
- return;
+ Bands[Channels[Channel].Band].TimeOff = 0;
}
-
- // Remove last element
- if( channelParam->Next == NULL )
+ // Update Aggregated Time OFF
+ AggregatedLastTxDoneTime = curTime;
+ AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
+
+ if( IsRxWindowsEnabled == true )
{
- if( MulticastChannels != NULL )
+ RxWindowTimer1.attach_us(OnRxWindow1TimerEvent, RxWindow1Delay);
+
+ if( LoRaMacDeviceClass != CLASS_C )
{
- cur = MulticastChannels;
- MulticastParams_t *last = NULL;
- while( cur->Next != NULL )
- {
- last = cur;
- cur = cur->Next;
- }
- if( last != NULL )
- {
- last->Next = NULL;
- }
- // Last node in the list
- if( cur == last )
- {
- MulticastChannels = NULL;
- }
- }
- return;
- }
-
- // Remove a middle element
- cur = MulticastChannels;
- while( cur != NULL )
- {
- if( cur->Next == channelParam )
- {
- break;
+ RxWindowTimer2.attach_us(OnRxWindow2TimerEvent, RxWindow2Delay);
}
- cur = cur->Next;
- }
- if( cur != NULL )
- {
- MulticastParams_t *tmp = cur ->Next;
- cur->Next = tmp->Next;
- tmp->Next = NULL;
- }
-}
-
-uint8_t LoRaMacJoinReq( uint8_t *devEui, uint8_t *appEui, uint8_t *appKey )
-{
- LoRaMacHeader_t macHdr;
-
- LoRaMacDevEui = devEui;
- LoRaMacAppEui = appEui;
- LoRaMacAppKey = appKey;
-
- macHdr.Value = 0;
- macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
-
- IsLoRaMacNetworkJoined = false;
-
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- static uint8_t drSwitch = 0;
-
- if( ( ++drSwitch & 0x01 ) == 0x01 )
- {
- ChannelsDatarate = DR_0;
+ if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
+ {
+ AckTimeoutTimer.attach_us(OnAckTimeoutTimerEvent,
+ RxWindow2Delay + ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ));
+ }
}
else
{
- ChannelsDatarate = DR_4;
+ 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;
}
-#endif
- return LoRaMacSend( &macHdr, NULL, 0, NULL, 0 );
-}
-
-uint8_t LoRaMacLinkCheckReq( void )
-{
- return AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 );
+
+ if( NodeAckRequested == false )
+ {
+ McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+ ChannelsNbRepCounter++;
+ }
}
-uint8_t LoRaMacSendFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+static void PrepareRxDoneAbort( void )
{
- LoRaMacHeader_t macHdr;
-
- macHdr.Value = 0;
-
- macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP;
- return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
+ LoRaMacState &= ~MAC_TX_RUNNING;
+
+ 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
+ MacStateCheckTimer.attach_us(OnMacStateCheckTimerEvent, 1000);
}
-uint8_t LoRaMacSendConfirmedFrame( uint8_t fPort, void *fBuffer, uint16_t fBufferSize, uint8_t retries )
+static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
LoRaMacHeader_t macHdr;
-
- if( AdrCtrlOn == false )
+ LoRaMacFrameCtrl_t fCtrl;
+
+ 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 )
{
- ChannelsDatarate = ChannelsDefaultDatarate;
- }
- AckTimeoutRetries = retries;
- AckTimeoutRetriesCounter = 1;
-
- macHdr.Value = 0;
-
- macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP;
- return LoRaMacSend( &macHdr, NULL, fPort, fBuffer, fBufferSize );
-}
-
-uint8_t LoRaMacSend( LoRaMacHeader_t *macHdr, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
- LoRaMacFrameCtrl_t fCtrl;
-
- fCtrl.Value = 0;
-
- fCtrl.Bits.FOptsLen = 0;
- fCtrl.Bits.FPending = 0;
- fCtrl.Bits.Ack = false;
- fCtrl.Bits.AdrAckReq = false;
- fCtrl.Bits.Adr = AdrCtrlOn;
-
- if( LoRaMacSetNextChannel( ) == 0 )
- {
- printf("LoRaMacSend\r\n");
- return LoRaMacSendOnChannel( Channels[Channel], macHdr, &fCtrl, fOpts, fPort, fBuffer, fBufferSize );
- }
- return 5;
-}
-
-uint8_t LoRaMacPrepareFrame( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
-{
- uint16_t i;
- uint8_t pktHeaderLen = 0;
- uint32_t mic = 0;
-
- LoRaMacBufferPktLen = 0;
-
- NodeAckRequested = false;
-
- if( fBuffer == NULL )
- {
- fBufferSize = 0;
- }
- else
- {
- if( ValidatePayloadLength( fBufferSize, ChannelsDatarate ) == false )
- {
- return 3;
- }
+ radio.Sleep( );
}
-
- LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
-
- switch( macHdr->Bits.MType )
+ RxWindowTimer2.detach();
+
+ macHdr.Value = payload[pktHeaderLen++];
+
+ switch( macHdr.Bits.MType )
{
- case FRAME_TYPE_JOIN_REQ:
- RxWindow1Delay = JoinAcceptDelay1 - RADIO_WAKEUP_TIME;
- RxWindow2Delay = JoinAcceptDelay2 - RADIO_WAKEUP_TIME;
-
- LoRaMacBufferPktLen = pktHeaderLen;
-
- LoRaMacMemCpy( LoRaMacAppEui, LoRaMacBuffer + LoRaMacBufferPktLen, 8 );
- LoRaMacBufferPktLen += 8;
- LoRaMacMemCpy( LoRaMacDevEui, LoRaMacBuffer + LoRaMacBufferPktLen, 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;
-
+ 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;
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+ /*
+ * WARNING: To be removed once Semtech server implementation
+ * is corrected.
+ */
+ if( Rx2Channel.Datarate == DR_3 )
+ {
+ Rx2Channel.Datarate = DR_8;
+ }
+#endif
+ // 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;
+ ChannelsDatarate = ChannelsDefaultDatarate;
+ }
+ else
+ {
+ MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
+ }
break;
- case FRAME_TYPE_DATA_CONFIRMED_UP:
- NodeAckRequested = true;
- //Intentional falltrough
- case FRAME_TYPE_DATA_UNCONFIRMED_UP:
- if( IsLoRaMacNetworkJoined == false )
- {
- return 2; // No network has been joined yet
- }
-
- RxWindow1Delay = ReceiveDelay1 - RADIO_WAKEUP_TIME;
- RxWindow2Delay = ReceiveDelay2 - RADIO_WAKEUP_TIME;
-
- if( fOpts == NULL )
+ case FRAME_TYPE_DATA_CONFIRMED_DOWN:
+ case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
{
- fCtrl->Bits.FOptsLen = 0;
- }
-
- if( SrvAckRequested == true )
- {
- SrvAckRequested = false;
- fCtrl->Bits.Ack = 1;
- }
-
- if( fCtrl->Bits.Adr == true )
- {
- if( ChannelsDatarate == LORAMAC_MIN_DATARATE )
+ address = payload[pktHeaderLen++];
+ address |= ( (uint32_t)payload[pktHeaderLen++] << 8 );
+ address |= ( (uint32_t)payload[pktHeaderLen++] << 16 );
+ address |= ( (uint32_t)payload[pktHeaderLen++] << 24 );
+
+ if( address != LoRaMacDevAddr )
{
- AdrAckCounter = 0;
- fCtrl->Bits.AdrAckReq = false;
+ 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
{
- if( AdrAckCounter > ADR_ACK_LIMIT )
+ 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 )
{
- fCtrl->Bits.AdrAckReq = true;
+ isMicOk = true;
+ downLinkCounter = downLinkCounterTmp;
+ }
+ }
+
+ 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;
+
+ // 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;
+ }
+ 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;
+ }
+
+ // 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.
+ AckTimeoutTimer.detach();
}
else
{
- fCtrl->Bits.AdrAckReq = false;
+ McpsConfirm.AckReceived = false;
+
+ if( AckTimeoutRetriesCounter > AckTimeoutRetries )
+ {
+ // Stop the AckTimeout timer as no more retransmissions
+ // are needed.
+ AckTimeoutTimer.detach();
+ }
}
- if( AdrAckCounter > ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
+
+ if( fCtrl.Bits.FOptsLen > 0 )
+ {
+ // Decode Options field MAC commands
+ ProcessMacCommands( payload, 8, appPayloadStartIndex, snr );
+ }
+ if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
{
- AdrAckCounter = 0;
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
- if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
+ port = payload[appPayloadStartIndex++];
+ frameLen = ( size - 4 ) - appPayloadStartIndex;
+
+ McpsIndication.Port = port;
+
+ if( port == 0 )
{
- ChannelsDatarate--;
+ LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
+ frameLen,
+ nwkSKey,
+ address,
+ DOWN_LINK,
+ downLinkCounter,
+ LoRaMacRxPayload );
+
+ // Decode frame payload MAC commands
+ ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr );
}
else
{
- // 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( ( ChannelsDatarate > LORAMAC_MIN_DATARATE ) && ( ChannelsDatarate == DR_8 ) )
- {
- ChannelsDatarate = DR_4;
- }
- if( ChannelsDatarate > LORAMAC_MIN_DATARATE )
- {
- ChannelsDatarate--;
+ LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
+ frameLen,
+ appSKey,
+ address,
+ DOWN_LINK,
+ downLinkCounter,
+ LoRaMacRxPayload );
+
+ McpsIndication.Buffer = LoRaMacRxPayload;
+ McpsIndication.BufferSize = frameLen;
+ McpsIndication.RxData = true;
}
- else
- {
-#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
- }
+ }
+ 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;
+}
+
+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 )
+{
+ MacStateCheckTimer.detach();
+ bool txTimeout = false;
+
+ if( LoRaMacFlags.Bits.MacDone == 1 )
+ {
+ 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_MIN_DATARATE );
+ }
+ 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 )
+ // Re-enable default channels
+ ChannelsMask[0] = 0xFFFF;
+ ChannelsMask[1] = 0xFFFF;
+ ChannelsMask[2] = 0xFFFF;
+ ChannelsMask[3] = 0xFFFF;
+ ChannelsMask[4] = 0x00FF;
+ ChannelsMask[5] = 0x0000;
+#elif defined( USE_BAND_915_HYBRID )
+ // Re-enable default channels
+ ChannelsMask[0] = 0x00FF;
+ ChannelsMask[1] = 0x0000;
+ ChannelsMask[2] = 0x0000;
+ ChannelsMask[3] = 0x0000;
+ ChannelsMask[4] = 0x0001;
+ ChannelsMask[5] = 0x0000;
#else
#error "Please define a frequency band in the compiler options."
#endif
- }
- }
- }
-
- 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;
-
- if( fOpts != NULL )
- {
- for( i = 0; i < fCtrl->Bits.FOptsLen; i++ )
+ LoRaMacState &= ~MAC_TX_RUNNING;
+
+ NodeAckRequested = false;
+ McpsConfirm.AckReceived = false;
+ McpsConfirm.NbRetries = AckTimeoutRetriesCounter;
+ if( IsUpLinkCounterFixed == false )
{
- LoRaMacBuffer[pktHeaderLen++] = fOpts[i];
- }
- }
- if( ( MacCommandsBufferIndex + fCtrl->Bits.FOptsLen ) <= 15 )
- {
- if( MacCommandsInNextTx == true )
- {
- fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
-
- // Update FCtrl field with new value of OptionsLength
- LoRaMacBuffer[0x05] = fCtrl->Value;
- for( i = 0; i < MacCommandsBufferIndex; i++ )
- {
- LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
- }
+ UpLinkCounter++;
}
}
- MacCommandsInNextTx = false;
- MacCommandsBufferIndex = 0;
-
- if( ( pktHeaderLen + fBufferSize ) > LORAMAC_PHY_MAXPAYLOAD )
- {
- return 3;
- }
-
- if( fBuffer != NULL )
- {
- LoRaMacBuffer[pktHeaderLen++] = fPort;
-
- if( fPort == 0 )
- {
- LoRaMacPayloadEncrypt( ( uint8_t* )fBuffer, fBufferSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
- }
- else
- {
- LoRaMacPayloadEncrypt( ( uint8_t* )fBuffer, fBufferSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
- }
- LoRaMacMemCpy( LoRaMacPayload, LoRaMacBuffer + pktHeaderLen, fBufferSize );
- }
- LoRaMacBufferPktLen = pktHeaderLen + fBufferSize;
-
- LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic );
-
- if( ( LoRaMacBufferPktLen + LORAMAC_MFR_LEN ) > LORAMAC_PHY_MAXPAYLOAD )
- {
- return 3;
- }
- 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;
- default:
- return 4;
+ }
+ }
+ // Handle reception for Class B and Class C
+ if( ( LoRaMacState & MAC_RX ) == MAC_RX )
+ {
+ LoRaMacState &= ~MAC_RX;
}
-
- return 0;
-}
-
-uint8_t LoRaMacSendFrameOnChannel( ChannelParams_t channel )
-{
- printf("LoRaMacSendFrameOnChannel channel \r\n");
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
- LoRaMacEventInfo.TxDatarate = ChannelsDatarate;
-
- ChannelsTxPower = LimitTxPower( ChannelsTxPower );
-
- radio.SetChannel( channel.Frequency );
- radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen );
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
- if( ChannelsDatarate == DR_7 )
- { // High Speed FSK channel
- radio.SetTxConfig( MODEM_FSK, TxPowers[ChannelsTxPower], 25e3, 0, Datarates[ChannelsDatarate] * 1e3, 0, 5, false, true, 0, 0, false, 3e6 );
- TxTimeOnAir = radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen );
- }
- else if( ChannelsDatarate == DR_6 )
+ if( LoRaMacState == MAC_IDLE )
{
- printf("LoRaMacSendFrameOnChannel channel DR_6\r\n" );
- // High speed LoRa channel
- radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 1, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
- TxTimeOnAir = radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
+ 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
{
- printf("LoRaMacSendFrameOnChannel channel other\r\n");
- // Normal LoRa channel
- radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
- TxTimeOnAir = radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
+ // Operation not finished restart timer
+ MacStateCheckTimer.attach_us(OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT);
+ }
+
+ if( LoRaMacFlags.Bits.McpsInd == 1 )
+ {
+ LoRaMacPrimitives->MacMcpsIndication( &McpsIndication );
+ LoRaMacFlags.Bits.McpsInd = 0;
+ }
+}
+
+static void OnTxDelayedTimerEvent( void )
+{
+ TxDelayedTimer.detach();
+ 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
+
+ RxWindowTimer1.detach();
+ 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 )
+ { // DR_6, DR_5, DR_4, DR_3
+ symbTimeout = 8;
+ }
+ if( datarate == DR_6 )
+ {// LoRa 250 kHz
+ bandwidth = 1;
}
-#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- if( ChannelsDatarate >= DR_4 )
- { // High speed LoRa channel BW500 kHz
- radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 2, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
- TxTimeOnAir = radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
+ 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
+ if( datarate > DR_0 )
+ { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
+ symbTimeout = 8;
+ }
+ if( datarate >= DR_4 )
+ {// LoRa 500 kHz
+ bandwidth = 2;
}
- else
- { // Normal LoRa channel
- radio.SetTxConfig( MODEM_LORA, TxPowers[ChannelsTxPower], 0, 0, Datarates[ChannelsDatarate], 1, 8, false, true, 0, 0, false, 3e6 );
- TxTimeOnAir = radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen );
+ 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
+
+ RxWindowTimer2.detach();
+ 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 )
+ { // DR_6, DR_5, DR_4, DR_3
+ symbTimeout = 8;
+ }
+ if( Rx2Channel.Datarate == DR_6 )
+ {// LoRa 250 kHz
+ bandwidth = 1;
+ }
+#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
+ // For higher datarates, we increase the number of symbols generating a Rx Timeout
+ if( Rx2Channel.Datarate > DR_0 )
+ { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
+ symbTimeout = 8;
+ }
+ if( Rx2Channel.Datarate >= DR_4 )
+ {// LoRa 500 kHz
+ bandwidth = 2;
}
#else
#error "Please define a frequency band in the compiler options."
#endif
-
- if( MaxDCycle == 255 )
+ 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 )
+{
+ AckTimeoutTimer.detach();
+
+ if( NodeAckRequested == true )
+ {
+ AckTimeoutRetry = true;
+ LoRaMacState &= ~MAC_ACK_REQ;
+ }
+ if( LoRaMacDeviceClass == CLASS_C )
{
- return 6;
+ LoRaMacFlags.Bits.MacDone = 1;
+ }
+}
+
+static bool SetNextChannel( TimerTime_t* time )
+{
+ uint8_t nbEnabledChannels = 0;
+ uint8_t delayTx = 0;
+ uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
+ TimerTime_t curTime = timerGeneralPurpose.read_us( );
+ 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( MaxDCycle == 0 )
+ if( ( ChannelsDatarate >= DR_4 ) && ( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 ) )
+ { // Make sure, that the channels are activated
+ ChannelsMaskRemaining[4] = ChannelsMask[4];
+ }
+#else
+ uint8_t chanCnt = 0;
+ for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
+ {
+ if( ChannelsMask[k] != 0 )
+ {
+ chanCnt++;
+ break;
+ }
+ }
+ if( chanCnt == 0 )
+ {
+ // 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 < ( curTime - 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 < ( curTime - Bands[i].LastTxDoneTime ) )
+ {
+ Bands[i].TimeOff = 0;
+ }
+ if( Bands[i].TimeOff != 0 )
+ {
+ nextTxDelay = MIN( Bands[i].TimeOff -
+ ( curTime - 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( ( ( 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;
+ }
+ }
+ }
}
-
- LoRaMacState |= MAC_TX_RUNNING;
- // Starts the MAC layer status check timer
- //TimerStart( &MacStateCheckTimer );
- //MacStateCheckTimer.start(MAC_STATE_CHECK_TIMEOUT/1000);
- MacStateCheckTimer.attach_us(OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT);
-
- //if( MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) > ( TimerGetCurrentTime( ) ) )
- if( MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) > ( timerGeneralPurpose.read_us( ) ) )
+ else
+ {
+ delayTx++;
+ nextTxDelay = AggregatedTimeOff - ( curTime - AggregatedLastTxDoneTime );
+ }
+
+ if( nbEnabledChannels > 0 )
+ {
+ Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+ if( Channel < ( LORA_MAX_NB_CHANNELS - 8 ) )
+ {
+ DisableChannelInMask( Channel, ChannelsMaskRemaining );
+ }
+#endif
+ *time = 0;
+ return true;
+ }
+ else
+ {
+ if( delayTx > 0 )
+ {
+ // Delay transmission due to AggregatedTimeOff or to a band time off
+ *time = nextTxDelay;
+ return true;
+ }
+ // Datarate not supported by any channel
+ *time = 0;
+ return false;
+ }
+}
+
+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
{
- // Schedule transmission
- //TimerSetValue( &TxDelayedTimer, MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ) );
- //TimerStart( &TxDelayedTimer );
- //TxDelayedTimer.start(MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff )/1000 );
-
- TxDelayedTimer.attach_us(OnTxDelayedTimerEvent, MAX( Bands[channel.Band].TimeOff, AggregatedTimeOff ));
-
+ // 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];
+ ModemType modem;
+
+ if( radio.GetState( ) == 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] );
+ }
+ else
+ {
+ radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] );
+ }
+
+ if( rxContinuous == false )
+ {
+ radio.Rx( MaxRxWindow );
+ }
+ else
+ {
+ radio.Rx( 0 ); // Continuous mode
+ }
+ }
+}
+
+static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
+{
+ uint16_t maxN = 0;
+ uint16_t payloadSize = 0;
+
+ // Get the maximum payload length
+ if( RepeaterSupport == true )
+ {
+ maxN = MaxPayloadOfDatarateRepeater[datarate];
}
else
{
- // Send now
- radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
+ 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 0;
+ return false;
+}
+
+#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
+static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask )
+{
+ uint8_t nb125kHzChannels = 0;
+
+ for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ )
+ {
+ for( uint8_t j = 0; j < 16; j++ )
+ {// Verify if the channel is active
+ if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) )
+ {
+ nb125kHzChannels++;
+ }
+ }
+ }
+
+ return nb125kHzChannels;
}
-
-
-void OnTxDelayedTimerEvent( void )
+#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 ) < 50 )
+ {// Limit tx power to max 21dBm
+ resultTxPower = MAX( txPower, TX_POWER_20_DBM );
+ }
+ }
+#endif
+ return resultTxPower;
+}
+
+static bool ValueInRange( int8_t value, int8_t min, int8_t max )
{
- TxDelayedTimer.detach();
- //TimerStop( &TxDelayedTimer );
- //TxDelayedTimer.stop();
- radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
+ if( ( value >= min ) && ( value <= max ) )
+ {
+ return true;
+ }
+ return false;
}
-uint8_t LoRaMacSendOnChannel( ChannelParams_t channel, LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t *fOpts, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
+static bool DisableChannelInMask( uint8_t id, uint16_t* mask )
+{
+ uint8_t index = 0;
+ index = id / 16;
+
+ if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
+ {
+ return false;
+ }
+
+ // Deactivate channel
+ mask[index] &= ~( 1 << ( id % 16 ) );
+
+ return true;
+}
+
+static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut )
{
- uint8_t status = 0;
-
- if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
- {
- printf("LoRaMacSendOnChannel MAC is busy\r\n");
- return 1; // MAC is busy transmitting a previous frame
- }
-
- status = LoRaMacPrepareFrame( channel, macHdr, fCtrl, fOpts, fPort, fBuffer, fBufferSize );
- if( status != 0 )
+ bool adrAckReq = false;
+ int8_t datarate = ChannelsDatarate;
+
+ if( adrEnabled == true )
{
- return status;
+ if( datarate == LORAMAC_MIN_DATARATE )
+ {
+ AdrAckCounter = 0;
+ adrAckReq = false;
+ }
+ else
+ {
+ if( AdrAckCounter >= ADR_ACK_LIMIT )
+ {
+ adrAckReq = true;
+ }
+ else
+ {
+ adrAckReq = false;
+ }
+ if( AdrAckCounter >= ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) )
+ {
+ if( ( ( AdrAckCounter - ADR_ACK_DELAY ) % ADR_ACK_LIMIT ) == 0 )
+ {
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+ if( datarate > LORAMAC_MIN_DATARATE )
+ {
+ datarate--;
+ }
+ if( datarate == LORAMAC_MIN_DATARATE )
+ {
+ if( updateChannelMask == 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_MIN_DATARATE ) && ( datarate == DR_8 ) )
+ {
+ datarate = DR_4;
+ }
+ else if( datarate > LORAMAC_MIN_DATARATE )
+ {
+ datarate--;
+ }
+ if( datarate == LORAMAC_MIN_DATARATE )
+ {
+ if( updateChannelMask == 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
+ }
+ }
+ }
}
- LoRaMacEventInfo.TxNbRetries = 0;
- LoRaMacEventInfo.TxAckReceived = false;
-
- return LoRaMacSendFrameOnChannel( channel );
+ *datarateOut = datarate;
+
+ return adrAckReq;
}
-static void LoRaMacProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize )
+static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
+{
+ LoRaMacStatus_t status = LORAMAC_STATUS_BUSY;
+
+ switch( cmd )
+ {
+ case MOTE_MAC_LINK_CHECK_REQ:
+ if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // No payload for this command
+ status = LORAMAC_STATUS_OK;
+ }
+ break;
+ case MOTE_MAC_LINK_ADR_ANS:
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 1 ) )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // Margin
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ status = LORAMAC_STATUS_OK;
+ }
+ break;
+ case MOTE_MAC_DUTY_CYCLE_ANS:
+ if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // No payload for this answer
+ status = LORAMAC_STATUS_OK;
+ }
+ break;
+ case MOTE_MAC_RX_PARAM_SETUP_ANS:
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 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 < ( LORA_MAC_COMMAND_MAX_LENGTH - 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 < ( LORA_MAC_COMMAND_MAX_LENGTH - 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 < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ 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 void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr )
{
while( macIndex < commandsSize )
{
@@ -1553,12 +2041,13 @@
switch( payload[macIndex++] )
{
case SRV_MAC_LINK_CHECK_ANS:
- LoRaMacEventFlags.Bits.LinkCheck = 1;
- LoRaMacEventInfo.DemodMargin = payload[macIndex++];
- LoRaMacEventInfo.NbGateways = payload[macIndex++];
+ MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+ MlmeConfirm.DemodMargin = payload[macIndex++];
+ MlmeConfirm.NbGateways = payload[macIndex++];
break;
case SRV_MAC_LINK_ADR_REQ:
{
+ uint8_t i;
uint8_t status = 0x07;
uint16_t chMask;
int8_t txPower = 0;
@@ -1566,9 +2055,9 @@
uint8_t nbRep = 0;
uint8_t chMaskCntl = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
-
+
// Initialize local copy of the channels mask array
- for( uint8_t i = 0; i < 6; i++ )
+ for( i = 0; i < 6; i++ )
{
channelsMask[i] = ChannelsMask[i];
}
@@ -1576,7 +2065,7 @@
txPower = datarate & 0x0F;
datarate = ( datarate >> 4 ) & 0x0F;
- if( ( AdrCtrlOn == false ) &&
+ 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
@@ -1602,14 +2091,15 @@
{
status &= 0xFE; // Channel mask KO
}
- else if( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 ) )
+ else if( ( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 )) ||
+ ( chMaskCntl >= 7 ) )
{
// RFU
status &= 0xFE; // Channel mask KO
}
else
{
- for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
+ for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
{
if( chMaskCntl == 6 )
{
@@ -1668,7 +2158,7 @@
}
}
channelsMask[chMaskCntl] = chMask;
-
+
if( CountNbEnabled125kHzChannels( channelsMask ) < 6 )
{
status &= 0xFE; // Channel mask KO
@@ -1677,8 +2167,7 @@
#else
#error "Please define a frequency band in the compiler options."
#endif
- if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
- ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
+ if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
@@ -1686,8 +2175,7 @@
//
// Remark MaxTxPower = 0 and MinTxPower = 5
//
- if( ( ( LORAMAC_MAX_TX_POWER <= txPower ) &&
- ( txPower <= LORAMAC_MIN_TX_POWER ) ) == false )
+ if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
{
status &= 0xFB; // TxPower KO
}
@@ -1726,32 +2214,37 @@
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++];
freq |= ( uint32_t )payload[macIndex++] << 8;
freq |= ( uint32_t )payload[macIndex++] << 16;
freq *= 100;
-
+
if( radio.CheckRfFrequency( freq ) == false )
{
status &= 0xFE; // Channel frequency KO
}
-
- if( ( ( datarate < LORAMAC_MIN_DATARATE ) ||
- ( datarate > LORAMAC_MAX_DATARATE ) ) == true )
+
+ if( ValueInRange( datarate, LORAMAC_MIN_DATARATE, LORAMAC_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
-
- if( ( ( drOffset < LORAMAC_MIN_RX1_DR_OFFSET ) ||
- ( drOffset > LORAMAC_MAX_RX1_DR_OFFSET ) ) == true )
+#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;
@@ -1768,51 +2261,80 @@
{
batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
}
- AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, LoRaMacEventInfo.RxSnr );
+ AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr );
+ break;
}
- 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++];
-
- if( ( channelIndex < 3 ) || ( channelIndex > LORA_MAX_NB_CHANNELS ) )
+
+ LoRaMacState |= MAC_TX_CONFIG;
+ if( chParam.Frequency == 0 )
{
- status &= 0xFE; // Channel frequency KO
- }
-
- if( radio.CheckRfFrequency( chParam.Frequency ) == false )
- {
- status &= 0xFE; // Channel frequency KO
+ if( channelIndex < 3 )
+ {
+ status &= 0xFC;
+ }
+ else
+ {
+ if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK )
+ {
+ status &= 0xFC;
+ }
+ }
}
-
- if( ( chParam.DrRange.Fields.Min > chParam.DrRange.Fields.Max ) ||
- ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Min ) &&
- ( chParam.DrRange.Fields.Min <= LORAMAC_MAX_DATARATE ) ) == false ) ||
- ( ( ( LORAMAC_MIN_DATARATE <= chParam.DrRange.Fields.Max ) &&
- ( chParam.DrRange.Fields.Max <= LORAMAC_MAX_DATARATE ) ) == false ) )
+ else
{
- status &= 0xFD; // Datarate range KO
+ 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;
+ }
+ }
}
- if( ( status & 0x03 ) == 0x03 )
- {
- LoRaMacSetChannel( channelIndex, chParam );
- }
+ 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++;
@@ -1829,1075 +2351,1220 @@
}
}
-/*!
- * Function to be executed on Tx Done event
- */
-static void OnRadioTxDone( void )
+LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
{
- //TimerTime_t curTime = TimerGetCurrentTime( );
- TimerTime_t curTime = timerGeneralPurpose.read_us( );
-
- if( LoRaMacDeviceClass != CLASS_C )
- {
- radio.Sleep( );
- }
- else
- {
- OnRxWindow2TimerEvent();
- }
-
- // Update Band Time OFF
- Bands[Channels[Channel].Band].LastTxDoneTime = curTime;
- if( DutyCycleOn == true )
- {
- Bands[Channels[Channel].Band].TimeOff = TxTimeOnAir * Bands[Channels[Channel].Band].DCycle - TxTimeOnAir;
- }
- else
- {
- Bands[Channels[Channel].Band].TimeOff = 0;
- }
- // Update Agregated Time OFF
- AggregatedLastTxDoneTime = curTime;
- AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir );
-
- if( IsRxWindowsEnabled == true )
+ 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 )
{
- //TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
- //TimerStart( &RxWindowTimer1 );
- //RxWindowTimer1.attach_us(&OnRxWindow1TimerEvent, RxWindow1Delay);
- //RxWindowTimer1.start(RxWindow1Delay/1000);
- RxWindowTimer1.attach_us(OnRxWindow1TimerEvent, RxWindow1Delay);
-
- if( LoRaMacDeviceClass != CLASS_C )
- {
- //TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
- //TimerStart( &RxWindowTimer2 );
- //RxWindowTimer2.attach_us(&OnRxWindow2TimerEvent, RxWindow2Delay);
- //RxWindowTimer2.start(RxWindow2Delay/1000);
- RxWindowTimer2.attach_us(OnRxWindow2TimerEvent, RxWindow2Delay);
- }
+ return status;
}
- else
- {
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
- }
-
- if( NodeAckRequested == false )
- {
- ChannelsNbRepCounter++;
- }
+
+ // Reset confirm parameters
+ McpsConfirm.NbRetries = 0;
+ McpsConfirm.AckReceived = false;
+ McpsConfirm.UpLinkCounter = UpLinkCounter;
+
+ status = ScheduleTx( );
+
+ return status;
}
-/*!
- * Function to be executed on Rx Done event
- */
-static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
+static LoRaMacStatus_t ScheduleTx( )
{
- printf("OnRadioRxDone\r\n");
- LoRaMacHeader_t macHdr;
- LoRaMacFrameCtrl_t fCtrl;
-
- 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;
-
- bool isMicOk = false;
-
- if( LoRaMacDeviceClass != CLASS_C )
+ TimerTime_t dutyCycleTimeOff = 0;
+
+ // Check if the device is off
+ if( MaxDCycle == 255 )
+ {
+ return LORAMAC_STATUS_DEVICE_OFF;
+ }
+ if( MaxDCycle == 0 )
+ {
+ AggregatedTimeOff = 0;
+ }
+
+ // Select channel
+ while( SetNextChannel( &dutyCycleTimeOff ) == false )
{
- radio.Sleep( );
+ // 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
{
- if( LoRaMacEventFlags.Bits.RxSlot == 0 )
- {
- OnRxWindow2TimerEvent();
- }
+ // Send later - prepare timer
+ LoRaMacState |= MAC_TX_DELAYED;
+ TxDelayedTimer.attach_us(OnTxDelayedTimerEvent, dutyCycleTimeOff);
+
+ return LORAMAC_STATUS_OK;
}
- //TimerStop( &RxWindowTimer2 );
- //RxWindowTimer2.stop();
- RxWindowTimer2.detach();
-
- macHdr.Value = payload[pktHeaderLen++];
-
- switch( macHdr.Bits.MType )
+}
+
+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_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 )
+ 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 )
{
- LoRaMacEventFlags.Bits.Rx = 1;
- LoRaMacEventInfo.RxSnr = snr;
- LoRaMacEventInfo.RxRssi = rssi;
-
- 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;
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- /*
- * WARNING: To be removed once Semtech server implementation
- * is corrected.
- */
- if( Rx2Channel.Datarate == DR_3 )
+ return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet
+ }
+
+ fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &ChannelsDatarate );
+
+ 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;
+
+ if( ( payload != NULL ) && ( payloadSize > 0 ) )
+ {
+ if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) )
{
- Rx2Channel.Datarate = DR_8;
- }
-#endif
- // 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;
-
- for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 )
+ fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
+
+ // Update FCtrl field with new value of OptionsLength
+ LoRaMacBuffer[0x05] = fCtrl->Value;
+ for( i = 0; i < MacCommandsBufferIndex; i++ )
{
- param.Frequency = ( ( uint32_t )LoRaMacRxPayload[13 + j] | ( ( uint32_t )LoRaMacRxPayload[14 + j] << 8 ) | ( ( uint32_t )LoRaMacRxPayload[15 + j] << 16 ) ) * 100;
- LoRaMacSetChannel( i, param );
+ LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
}
}
-#endif
- LoRaMacEventFlags.Bits.JoinAccept = 1;
- IsLoRaMacNetworkJoined = true;
- ChannelsDatarate = ChannelsDefaultDatarate;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
}
else
{
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
- }
-
- LoRaMacEventFlags.Bits.Tx = 1;
- 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 )
+ if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) )
{
- curMulticastParams = MulticastChannels;
- while( curMulticastParams != NULL )
- {
- if( address == curMulticastParams->Address )
- {
- LoRaMacEventFlags.Bits.Multicast = 1;
- nwkSKey = curMulticastParams->NwkSKey;
- appSKey = curMulticastParams->AppSKey;
- downLinkCounter = curMulticastParams->DownLinkCounter;
- break;
- }
- curMulticastParams = curMulticastParams->Next;
- }
- if( LoRaMacEventFlags.Bits.Multicast == 0 )
- {
- // We are not the destination of this frame.
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
- LoRaMacState &= ~MAC_TX_RUNNING;
- return;
- }
+ payloadSize = MacCommandsBufferIndex;
+ payload = MacCommandsBuffer;
+ framePort = 0;
}
- else
- {
- LoRaMacEventFlags.Bits.Multicast = 0;
- nwkSKey = LoRaMacNwkSKey;
- appSKey = LoRaMacAppSKey;
- downLinkCounter = DownLinkCounter;
- }
-
- if( LoRaMacDeviceClass != CLASS_A )
+ }
+ MacCommandsInNextTx = false;
+ MacCommandsBufferIndex = 0;
+
+ if( ( payload != NULL ) && ( payloadSize > 0 ) )
+ {
+ LoRaMacBuffer[pktHeaderLen++] = framePort;
+
+ if( framePort == 0 )
{
- LoRaMacState |= MAC_RX;
- // Starts the MAC layer status check timer
- //TimerStart( &MacStateCheckTimer );
- //MacStateCheckTimer.start(MAC_STATE_CHECK_TIMEOUT/1000);
- }
- 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;
- }
+ LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
}
else
{
- // check for downlink counter 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;
- }
+ LoRaMacPayloadEncrypt( (uint8_t* ) payload, payloadSize, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, LoRaMacPayload );
}
-
- if( isMicOk == true )
- {
- LoRaMacEventFlags.Bits.Rx = 1;
- LoRaMacEventInfo.RxSnr = snr;
- LoRaMacEventInfo.RxRssi = rssi;
- LoRaMacEventInfo.RxBufferSize = 0;
- AdrAckCounter = 0;
-
- // Update 32 bits downlink counter
- if( LoRaMacEventFlags.Bits.Multicast == 1 )
- {
- curMulticastParams->DownLinkCounter = downLinkCounter;
- }
- else
- {
- DownLinkCounter = downLinkCounter;
- }
-
- if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
- {
- SrvAckRequested = true;
- }
- else
- {
- SrvAckRequested = false;
- }
- // Check if the frame is an acknowledgement
- if( fCtrl.Bits.Ack == 1 )
- {
- LoRaMacEventInfo.TxAckReceived = true;
-
- // Stop the AckTimeout timer as no more retransmissions
- // are needed.
- //TimerStop( &AckTimeoutTimer );
- //AckTimeoutTimer.stop();
- AckTimeoutTimer.detach();
- }
- else
- {
- LoRaMacEventInfo.TxAckReceived = false;
- if( AckTimeoutRetriesCounter > AckTimeoutRetries )
- {
- // Stop the AckTimeout timer as no more retransmissions
- // are needed.
- //TimerStop( &AckTimeoutTimer );
- //AckTimeoutTimer.stop();
- AckTimeoutTimer.detach();
- }
- }
-
- if( fCtrl.Bits.FOptsLen > 0 )
- {
- // Decode Options field MAC commands
- LoRaMacProcessMacCommands( payload, 8, appPayloadStartIndex );
- }
-
- if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 )
- {
- port = payload[appPayloadStartIndex++];
- frameLen = ( size - 4 ) - appPayloadStartIndex;
-
- if( port == 0 )
- {
- LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
- frameLen,
- nwkSKey,
- address,
- DOWN_LINK,
- downLinkCounter,
- LoRaMacRxPayload );
-
- // Decode frame payload MAC commands
- LoRaMacProcessMacCommands( LoRaMacRxPayload, 0, frameLen );
- }
- else
- {
- LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
- frameLen,
- appSKey,
- address,
- DOWN_LINK,
- downLinkCounter,
- LoRaMacRxPayload );
-
- LoRaMacEventFlags.Bits.RxData = 1;
- LoRaMacEventInfo.RxPort = port;
- LoRaMacEventInfo.RxBuffer = LoRaMacRxPayload;
- LoRaMacEventInfo.RxBufferSize = frameLen;
- }
- }
-
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
- }
- else
- {
- LoRaMacEventInfo.TxAckReceived = false;
-
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
- LoRaMacState &= ~MAC_TX_RUNNING;
- }
+ 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;
- case FRAME_TYPE_PROPRIETARY:
- //Intentional falltrough
default:
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
- LoRaMacState &= ~MAC_TX_RUNNING;
- break;
+ return LORAMAC_STATUS_SERVICE_UNKNOWN;
}
+
+ return LORAMAC_STATUS_OK;
}
-/*!
- * Function executed on Radio Tx Timeout event
- */
-static void OnRadioTxTimeout( void )
+LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel )
{
- if( LoRaMacDeviceClass != CLASS_C )
- {
- radio.Sleep( );
+ int8_t datarate = Datarates[ChannelsDatarate];
+ int8_t txPower = 0;
+
+ ChannelsTxPower = LimitTxPower( ChannelsTxPower );
+ txPower = TxPowers[ChannelsTxPower];
+
+ MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+ McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+ McpsConfirm.Datarate = ChannelsDatarate;
+ McpsConfirm.TxPower = ChannelsTxPower;
+
+ 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
- {
- OnRxWindow2TimerEvent();
- }
-
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT;
-}
-
-/*!
- * Function executed on Radio Rx Timeout event
- */
-static void OnRadioRxTimeout( void )
-{
- printf("OnRadioRxTimeout \r\n");
- if( LoRaMacDeviceClass != CLASS_C )
- {
- radio.Sleep( );
- }
- if( LoRaMacEventFlags.Bits.RxSlot == 1 )
- {
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
- }
-}
-
-/*!
- * Function executed on Radio Rx Error event
- */
-static void OnRadioRxError( void )
-{
- if( LoRaMacDeviceClass != CLASS_C )
- {
- radio.Sleep( );
- }
- if( LoRaMacEventFlags.Bits.RxSlot == 1 )
- {
- LoRaMacEventFlags.Bits.Tx = 1;
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR;
- }
-}
-
-/*!
- * 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
- */
-void LoRaMacRxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
-{
- uint8_t downlinkDatarate = Datarates[datarate];
- //RadioModems_t modem;
- ModemType modem;
-
- if( radio.GetState( ) == IDLE )
- {
- radio.SetChannel( freq );
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
- if( datarate == DR_7 )
- {
- modem = MODEM_FSK;
- radio.SetRxConfig( MODEM_FSK, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
- }
- else
- {
- modem = MODEM_LORA;
- radio.SetRxConfig( MODEM_LORA, 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_LORA, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
-#endif
- if( RepeaterSupport == true )
- {
- radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] );
- }
- else
- {
- radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] );
- }
-
- if( rxContinuous == false )
- {
- radio.Rx( MaxRxWindow );
- }
- else
- {
- radio.Rx( 0 ); // Continuous mode
- }
+ { // 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 );
}
-}
-
-/*!
- * Function executed on first Rx window timer event
- */
-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 );
- //RxWindowTimer1.stop();
- RxWindowTimer1.detach();
- LoRaMacEventFlags.Bits.RxSlot = 0;
-
-#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 )
- { // DR_6, DR_5, DR_4, DR_3
- symbTimeout = 8;
- }
- if( datarate == DR_6 )
- {// LoRa 250 kHz
- bandwidth = 1;
- }
- LoRaMacRxWindowSetup( 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
- if( datarate > DR_0 )
- { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
- symbTimeout = 8;
+#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 );
}
- if( datarate >= DR_4 )
- {// LoRa 500 kHz
- bandwidth = 2;
- }
- LoRaMacRxWindowSetup( 923.3e6 + ( Channel % 8 ) * 600e3, datarate, bandwidth, symbTimeout, false );
-#else
- #error "Please define a frequency band in the compiler options."
-#endif
-}
-
-/*!
- * Function executed on second Rx window timer event
- */
-static void OnRxWindow2TimerEvent(void)
-{
- uint16_t symbTimeout = 5; // DR_2, DR_1, DR_0
- uint32_t bandwidth = 0; // LoRa 125 kHz
-
- RxWindowTimer2.detach();
- //TimerStop( &RxWindowTimer2 );
- //RxWindowTimer2.stop();
- LoRaMacEventFlags.Bits.RxSlot = 1;
-
- if( NodeAckRequested == true )
- {
- //TimerSetValue( &AckTimeoutTimer, ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
- //TimerStart( &AckTimeoutTimer );
- //AckTimeoutTimer.start((ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ))/1000);
- AckTimeoutTimer.attach_us(OnAckTimeoutTimerEvent, ACK_TIMEOUT + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ));
- }
-
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
- // For higher datarates, we increase the number of symbols generating a Rx Timeout
- if( Rx2Channel.Datarate >= DR_3 )
- { // DR_6, DR_5, DR_4, DR_3
- symbTimeout = 8;
- }
- if( Rx2Channel.Datarate == DR_6 )
- {// LoRa 250 kHz
- bandwidth = 1;
- }
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
- // For higher datarates, we increase the number of symbols generating a Rx Timeout
- if( Rx2Channel.Datarate > DR_0 )
- { // DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13
- symbTimeout = 8;
- }
- if( Rx2Channel.Datarate >= DR_4 )
- {// LoRa 500 kHz
- bandwidth = 2;
+ 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
- if( LoRaMacDeviceClass != CLASS_C )
+
+ // Store the time on air
+ McpsConfirm.TxTimeOnAir = TxTimeOnAir;
+ MlmeConfirm.TxTimeOnAir = TxTimeOnAir;
+
+ // Starts the MAC layer status check timer
+ MacStateCheckTimer.attach_us(OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT);
+
+ // Send now
+ radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen );
+
+ LoRaMacState |= MAC_TX_RUNNING;
+
+ return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks )
+{
+ // start general purpose timer
+ timerGeneralPurpose.start();
+
+ 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;
+
+ RepeaterSupport = false;
+ IsRxWindowsEnabled = true;
+ IsLoRaMacNetworkJoined = false;
+ LoRaMacState = MAC_IDLE;
+
+#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++ )
{
- LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, false );
+ 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;
+
+ 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;
+
+ //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 );
+
+ radio_init();
+
+ // 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;
+
+ if( txInfo == NULL )
+ {
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+
+ AdrNextDr( AdrCtrlOn, false, &datarate );
+
+ if( RepeaterSupport == true )
+ {
+ txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate];
+ }
+ else
+ {
+ txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate];
+ }
+
+ if( txInfo->CurrentPayloadSize >= MacCommandsBufferIndex )
+ {
+ txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - MacCommandsBufferIndex;
}
else
{
- LoRaMacRxWindowSetup( Rx2Channel.Frequency, Rx2Channel.Datarate, bandwidth, symbTimeout, true );
+ return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
+ }
+
+ if( ValidatePayloadLength( size, datarate, 0 ) == false )
+ {
+ return LORAMAC_STATUS_LENGTH_ERROR;
}
+
+ if( ValidatePayloadLength( size, datarate, MacCommandsBufferIndex ) == false )
+ {
+ return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR;
+ }
+
+ return LORAMAC_STATUS_OK;
}
-/*!
- * Function executed on MacStateCheck timer event
- */
-static void OnMacStateCheckTimerEvent( void )
+LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
{
- printf("OnMacStateCheckTimerEvent \r\n");
- //TimerStop( &MacStateCheckTimer );
- //MacStateCheckTimer.stop();
- MacStateCheckTimer.detach();
-
- if( LoRaMacEventFlags.Bits.Tx == 1 )
+ LoRaMacStatus_t status = LORAMAC_STATUS_OK;
+
+ if( mibGet == NULL )
+ {
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+
+ switch( mibGet->Type )
{
- if( NodeAckRequested == false )
+ 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:
{
- if( LoRaMacEventFlags.Bits.JoinAccept == true )
+ 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_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 )
{
- // Join messages aren't repeated automatically
- ChannelsNbRepCounter = ChannelsNbRep;
- UpLinkCounter = 0;
- }
- if( ChannelsNbRepCounter >= ChannelsNbRep )
- {
- ChannelsNbRepCounter = 0;
-
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
-
- AdrAckCounter++;
- if( IsUpLinkCounterFixed == false )
+ case CLASS_A:
+ {
+ // Set the radio into sleep to setup a defined state
+ radio.Sleep( );
+ break;
+ }
+ case CLASS_B:
{
- UpLinkCounter++;
+ break;
}
-
- LoRaMacState &= ~MAC_TX_RUNNING;
- }
- else
- {
- LoRaMacEventFlags.Bits.Tx = 0;
- // Sends the same frame again
- if( LoRaMacSetNextChannel( ) == 0 )
+ case CLASS_C:
{
- LoRaMacSendFrameOnChannel( Channels[Channel] );
+ // Set the NodeAckRequested indicator to default
+ NodeAckRequested = false;
+ OnRxWindow2TimerEvent( );
+ break;
}
}
+ break;
}
- else
+ case MIB_NETWORK_JOINED:
+ {
+ IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined;
+ break;
+ }
+ case MIB_ADR:
{
- /*
- * For confirmed uplinks, ignore MIC and address errors and keep retrying.
- */
- if( ( LoRaMacEventInfo.Status == LORAMAC_EVENT_INFO_STATUS_MIC_FAIL ) ||
- ( LoRaMacEventInfo.Status == LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL ) )
- {
- AckTimeoutRetry = true;
- }
+ AdrCtrlOn = mibSet->Param.AdrEnable;
+ break;
+ }
+ case MIB_NET_ID:
+ {
+ LoRaMacNetID = mibSet->Param.NetID;
+ break;
}
-
- if( LoRaMacEventFlags.Bits.Rx == 1 )
+ case MIB_DEV_ADDR:
{
- if( ( LoRaMacEventInfo.TxAckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) )
+ LoRaMacDevAddr = mibSet->Param.DevAddr;
+ break;
+ }
+ case MIB_NWK_SKEY:
+ {
+ if( mibSet->Param.NwkSKey != NULL )
{
- AckTimeoutRetry = false;
- if( IsUpLinkCounterFixed == false )
- {
- UpLinkCounter++;
- }
- LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
-
- LoRaMacState &= ~MAC_TX_RUNNING;
- }
- }
-
- if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & MAC_CHANNEL_CHECK ) == 0 ) )
- {
- AckTimeoutRetry = false;
- if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) )
- {
- AckTimeoutRetriesCounter++;
-
- if( ( AckTimeoutRetriesCounter % 2 ) == 1 )
- {
- ChannelsDatarate = MAX( ChannelsDatarate - 1, LORAMAC_MIN_DATARATE );
- }
- LoRaMacEventFlags.Bits.Tx = 0;
- // Sends the same frame again
- if( LoRaMacSetNextChannel( ) == 0 )
- {
- LoRaMacSendFrameOnChannel( Channels[Channel] );
- }
+ memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey,
+ sizeof( LoRaMacNwkSKey ) );
}
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 )
- // Re-enable default channels
- ChannelsMask[0] = 0xFFFF;
- ChannelsMask[1] = 0xFFFF;
- ChannelsMask[2] = 0xFFFF;
- ChannelsMask[3] = 0xFFFF;
- ChannelsMask[4] = 0x00FF;
- ChannelsMask[5] = 0x0000;
-#elif defined( USE_BAND_915_HYBRID )
- // Re-enable default channels
- ChannelsMask[0] = 0x00FF;
- ChannelsMask[1] = 0x0000;
- ChannelsMask[2] = 0x0000;
- ChannelsMask[3] = 0x0000;
- ChannelsMask[4] = 0x0001;
- ChannelsMask[5] = 0x0000;
+ 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 )
+ if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 6 ) &&
+ ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) )
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ else
+ {
+ memcpy1( ( uint8_t* ) ChannelsMask,
+ ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( ChannelsMask ) );
+ for ( uint8_t i = 0; i < sizeof( ChannelsMask ) / 2; i++ )
+ {
+ ChannelsMaskRemaining[i] &= ChannelsMask[i];
+ }
+ }
#else
- #error "Please define a frequency band in the compiler options."
+ memcpy1( ( uint8_t* ) ChannelsMask,
+ ( uint8_t* ) mibSet->Param.ChannelsMask, 2 );
#endif
- LoRaMacState &= ~MAC_TX_RUNNING;
-
- LoRaMacEventInfo.TxAckReceived = false;
- LoRaMacEventInfo.TxNbRetries = AckTimeoutRetriesCounter;
- if( IsUpLinkCounterFixed == false )
+ }
+ 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_DATARATE:
+ {
+ if( ValueInRange( mibSet->Param.ChannelsDatarate,
+ LORAMAC_MIN_DATARATE, LORAMAC_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 )
{
- UpLinkCounter++;
+ ChannelsTxPower = mibSet->Param.ChannelsTxPower;
+ }
+ else
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
}
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
+#else
+ ChannelsTxPower = mibSet->Param.ChannelsTxPower;
+#endif
+ }
+ else
+ {
+ status = LORAMAC_STATUS_PARAMETER_INVALID;
}
+ 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;
}
}
- // Handle reception for Class B and Class C
- if( ( LoRaMacState & MAC_RX ) == MAC_RX )
- {
- LoRaMacState &= ~MAC_RX;
- }
- if( LoRaMacState == MAC_IDLE )
+ // Validate the datarate
+ if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) ||
+ ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_MIN_DATARATE,
+ LORAMAC_MAX_DATARATE ) == false ) ||
+ ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_MIN_DATARATE,
+ LORAMAC_MAX_DATARATE ) == false ) )
{
- LoRaMacNotify( &LoRaMacEventFlags, &LoRaMacEventInfo );
- }
- else
- {
- // Operation not finished restart timer
- MacStateCheckTimer.attach_us(OnMacStateCheckTimerEvent, MAC_STATE_CHECK_TIMEOUT);
- //TimerStart( &MacStateCheckTimer );
- //MacStateCheckTimer.start(MAC_STATE_CHECK_TIMEOUT/1000);
+ datarateInvalid = true;
}
-}
-
-static void OnAckTimeoutTimerEvent(void)
-{
- AckTimeoutTimer.detach();
- //TimerStop( &AckTimeoutTimer );
- //AckTimeoutTimer.stop();
-
- AckTimeoutRetry = true;
- LoRaMacState &= ~MAC_ACK_REQ;
-}
-
-/*!
- * ============================================================================
- * = LoRaMac utility functions =
- * ============================================================================
- */
-static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate )
-{
- bool payloadSizeOk = false;
- uint8_t maxN = 0;
-
- // Get the maximum payload length
- if( RepeaterSupport == true )
- {
- maxN = MaxPayloadOfDatarateRepeater[datarate];
- }
- else
+
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+ if( id < 3 )
{
- maxN = MaxPayloadOfDatarate[datarate];
- }
-
- // Validation of the application payload size
- if( lenN <= maxN )
- {
- payloadSizeOk = true;
- }
-
- return payloadSizeOk;
-}
-
-#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++ )
- {
- for( uint8_t j = 0; j < 16; j++ )
- {// Verify if the channel is active
- if( ( channelsMask[k] & ( 1 << j ) ) == ( 1 << j ) )
- {
- nb125kHzChannels++;
- }
+ if( params.Frequency != Channels[id].Frequency )
+ {
+ frequencyInvalid = true;
}
- }
-
- return nb125kHzChannels;
-}
-#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 ) < 50 )
- {// Limit tx power to max 21dBm
- resultTxPower = MAX( txPower, TX_POWER_20_DBM );
+
+ if( params.DrRange.Fields.Min > LORAMAC_DEFAULT_DATARATE )
+ {
+ datarateInvalid = true;
+ }
+ if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_MAX_DATARATE ) == false )
+ {
+ datarateInvalid = true;
}
}
#endif
- return resultTxPower;
-}
-
-void LoRaMacChannelRemove( uint8_t id )
-{
- if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+
+ // Validate the frequency
+ if( ( radio.CheckRfFrequency( params.Frequency ) == true ) && ( params.Frequency > 0 ) && ( frequencyInvalid == false ) )
{
- return;
- }
-#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
- if( id < 64 )
- {
- if( CountNbEnabled125kHzChannels( ChannelsMask ) <= 6 )
+#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 ) )
{
- return;
+ band = BAND_G1_2;
+ }
+ else if( ( params.Frequency >= 869400000 ) && ( params.Frequency <= 869650000 ) )
+ {
+ band = BAND_G1_3;
}
- }
-#else
- if( id < 3 )
- {
- return;
- }
+ else if( ( params.Frequency >= 869700000 ) && ( params.Frequency <= 870000000 ) )
+ {
+ band = BAND_G1_4;
+ }
+ else
+ {
+ frequencyInvalid = true;
+ }
#endif
-
- uint8_t index = 0;
- index = id / 16;
-
- if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
- {
- return;
- }
-
- // Deactivate channel
- ChannelsMask[index] &= ~( 1 << ( id % 16 ) );
-
- return;
-}
-
-/*!
- * ============================================================================
- * = LoRaMac setup functions =
- * ============================================================================
- */
-void LoRaMacSetDeviceClass( DeviceClass_t deviceClass )
-{
- LoRaMacDeviceClass = deviceClass;
-}
-
-void LoRaMacSetPublicNetwork( 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 );
+ 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
}
-void LoRaMacSetChannel( uint8_t id, ChannelParams_t params )
+LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
{
- params.Band = 0;
- Channels[id] = params;
- // Activate the newly created channel
- if( id < 16 )
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
+ if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
{
- ChannelsMask[0] |= 1 << id;
+ if( ( LoRaMacState & MAC_TX_CONFIG ) != MAC_TX_CONFIG )
+ {
+ return LORAMAC_STATUS_BUSY;
+ }
}
- else if( id < 32 )
+
+ if( id < 3 )
{
- ChannelsMask[1] |= 1 << ( id - 16 );
+ return LORAMAC_STATUS_PARAMETER_INVALID;
}
- else if( id < 48 )
+ else
{
- ChannelsMask[2] |= 1 << ( id - 32 );
+ // 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;
+ }
}
- else if( id < 64 )
+ 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 )
{
- ChannelsMask[3] |= 1 << ( id - 48 );
+ return LORAMAC_STATUS_PARAMETER_INVALID;
}
- else if( id < 72 )
+ if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
{
- ChannelsMask[4] |= 1 << ( id - 64 );
+ return LORAMAC_STATUS_BUSY;
+ }
+
+ // Reset downlink counter
+ channelParam->DownLinkCounter = 0;
+
+ if( MulticastChannels == NULL )
+ {
+ // New node is the fist element
+ MulticastChannels = channelParam;
}
else
{
- // Don't activate the channel
+ 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;
}
-#if defined( USE_BAND_433 ) || defined( USE_BAND_780 )
- Channels[id].Band = 0; // 1% duty cycle on EU433 and CN780 bands
-#elif defined( USE_BAND_868 )
- if( ( Channels[id].Frequency >= 865000000 ) && ( Channels[id].Frequency <= 868000000 ) )
+
+ return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam )
+{
+ if( channelParam == NULL )
{
- if( Channels[id].Band != BAND_G1_0 )
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+ {
+ return LORAMAC_STATUS_BUSY;
+ }
+
+ if( MulticastChannels != NULL )
+ {
+ if( MulticastChannels == channelParam )
{
- Channels[id].Band = BAND_G1_0;
+ // First element
+ MulticastChannels = channelParam->Next;
}
+ else
+ {
+ MulticastParams_t *cur = MulticastChannels;
+
+ // Search the node in the list
+ while( cur->Next && cur->Next != channelParam )
+ {
+ cur = cur->Next;
+ }
+ // If we found the node, remove it
+ if( cur->Next )
+ {
+ cur->Next = channelParam->Next;
+ }
+ }
+ channelParam->Next = NULL;
}
- else if( ( Channels[id].Frequency > 868000000 ) && ( Channels[id].Frequency <= 868600000 ) )
+
+ return LORAMAC_STATUS_OK;
+}
+
+LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
+{
+ LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
+ LoRaMacHeader_t macHdr;
+
+ if( mlmeRequest == NULL )
{
- if( Channels[id].Band != BAND_G1_1 )
- {
- Channels[id].Band = BAND_G1_1;
- }
+ return LORAMAC_STATUS_PARAMETER_INVALID;
+ }
+ if( ( LoRaMacState & MAC_TX_RUNNING ) == MAC_TX_RUNNING )
+ {
+ return LORAMAC_STATUS_BUSY;
}
- else if( ( Channels[id].Frequency >= 868700000 ) && ( Channels[id].Frequency <= 869200000 ) )
+
+ memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) );
+
+ MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+
+ switch( mlmeRequest->Type )
{
- if( Channels[id].Band != BAND_G1_2 )
+ case MLME_JOIN:
{
- Channels[id].Band = BAND_G1_2;
+ if( ( LoRaMacState & MAC_TX_DELAYED ) == MAC_TX_DELAYED )
+ {
+ status = 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;
+
+ macHdr.Value = 0;
+ macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ;
+
+ IsLoRaMacNetworkJoined = false;
+
+#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;
}
- else if( ( Channels[id].Frequency >= 869400000 ) && ( Channels[id].Frequency <= 869650000 ) )
+
+ if( status != LORAMAC_STATUS_OK )
{
- if( Channels[id].Band != BAND_G1_3 )
- {
- Channels[id].Band = BAND_G1_3;
- }
+ 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;
}
- else if( ( Channels[id].Frequency >= 869700000 ) && ( Channels[id].Frequency <= 870000000 ) )
+
+ macHdr.Value = 0;
+ memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) );
+ McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
+
+ switch( mcpsRequest->Type )
{
- if( Channels[id].Band != BAND_G1_4 )
+ 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:
{
- Channels[id].Band = BAND_G1_4;
+ 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_MIN_DATARATE, LORAMAC_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;
}
}
- else
- {
- Channels[id].Frequency = 0;
- Channels[id].DrRange.Value = 0;
- }
-#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) )
- Channels[id].Band = 0; // No duty cycle on US915 band
-#else
- #error "Please define a frequency band in the compiler options."
-#endif
- // Check if it is a valid channel
- if( Channels[id].Frequency == 0 )
- {
- LoRaMacChannelRemove( id );
- }
-}
-
-void LoRaMacSetRx2Channel( Rx2ChannelParams_t param )
-{
- Rx2Channel = param;
-}
-
-void LoRaMacSetChannelsTxPower( int8_t txPower )
-{
- if( ( txPower >= LORAMAC_MAX_TX_POWER ) &&
- ( txPower <= LORAMAC_MIN_TX_POWER ) )
- {
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- int8_t txPwr = LimitTxPower( txPower );
- if( txPwr == txPower )
- {
- ChannelsTxPower = txPower;
- }
-#else
- ChannelsTxPower = txPower;
-#endif
- }
-}
-
-void LoRaMacSetChannelsDatarate( int8_t datarate )
-{
- ChannelsDefaultDatarate = ChannelsDatarate = datarate;
-}
-
-void LoRaMacSetChannelsMask( uint16_t *mask )
-{
-#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
- if( ( CountNbEnabled125kHzChannels( mask ) < 6 ) &&
- ( CountNbEnabled125kHzChannels( mask ) > 0 ) )
- {
-
- }
- else
- {
- LoRaMacMemCpy( (uint8_t* ) mask,
- ( uint8_t* ) ChannelsMask, 10 );
- }
-#else
- if( ( mask[0] & 0x0007 ) != 0x0007 )
- {
- }
- else
- {
- LoRaMacMemCpy( ( uint8_t* ) mask,
- ( uint8_t* ) ChannelsMask, 2 );
- }
-#endif
-}
-
-void LoRaMacSetChannelsNbRep( uint8_t nbRep )
-{
- if( nbRep < 1 )
- {
- nbRep = 1;
- }
- if( nbRep > 15 )
- {
- nbRep = 15;
- }
- ChannelsNbRep = nbRep;
-}
-
-void LoRaMacSetMaxRxWindow( uint32_t delay )
-{
- MaxRxWindow = delay;
-}
-
-void LoRaMacSetReceiveDelay1( uint32_t delay )
-{
- ReceiveDelay1 = delay;
-}
-
-void LoRaMacSetReceiveDelay2( uint32_t delay )
-{
- ReceiveDelay2 = delay;
-}
-
-void LoRaMacSetJoinAcceptDelay1( uint32_t delay )
-{
- JoinAcceptDelay1 = delay;
-}
-
-void LoRaMacSetJoinAcceptDelay2( uint32_t delay )
-{
- JoinAcceptDelay2 = delay;
-}
-
-uint32_t LoRaMacGetUpLinkCounter( void )
-{
- return UpLinkCounter;
-}
-
-uint32_t LoRaMacGetDownLinkCounter( void )
-{
- return DownLinkCounter;
-}
-
-/*!
- * ============================================================================
- * = LoRaMac test functions =
- * ============================================================================
- */
-void LoRaMacTestSetDutyCycleOn( bool enable )
-{
- DutyCycleOn = enable;
+
+ return status;
}
void LoRaMacTestRxWindowsOn( bool enable )
@@ -2905,8 +3572,13 @@
IsRxWindowsEnabled = enable;
}
-void LoRaMacTestSetMic( uint16_t upLinkCounter )
+void LoRaMacTestSetMic( uint16_t txPacketCounter )
{
- UpLinkCounter = upLinkCounter;
+ UpLinkCounter = txPacketCounter;
IsUpLinkCounterFixed = true;
}
+
+void LoRaMacTestSetDutyCycleOn( bool enable )
+{
+ DutyCycleOn = enable;
+}
\ No newline at end of file
