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-lib by
Diff: LoRaMac.cpp
- Revision:
- 1:91e4e6c60d1e
- Parent:
- 0:91d1a7783bb9
- Child:
- 2:14a5d6ad92d5
--- a/LoRaMac.cpp Tue Oct 20 13:21:26 2015 +0000
+++ b/LoRaMac.cpp Mon Nov 23 10:09:43 2015 +0000
@@ -12,10 +12,7 @@
Maintainer: Miguel Luis and Gregory Cristian
*/
-#include "mbed.h"
#include "board.h"
-#include "utilities.h"
-#include "sx1276-hal.h"
#include "LoRaMacCrypto.h"
#include "LoRaMac.h"
@@ -23,7 +20,12 @@
/*!
* Maximum PHY layer payload size
*/
-#define LORAMAC_PHY_MAXPAYLOAD 250
+#define LORAMAC_PHY_MAXPAYLOAD 255
+
+/*!
+ * Maximum MAC commands buffer size
+ */
+#define LORA_MAC_COMMAND_MAX_LENGTH 15
/*!
* Device IEEE EUI
@@ -173,7 +175,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 )
/*!
@@ -449,7 +451,7 @@
/*!
* LoRaMac upper layer event functions
*/
-static LoRaMacEvent_t *LoRaMacEvents;
+static LoRaMacCallbacks_t *LoRaMacCallbacks;
/*!
* LoRaMac notification event flags
@@ -581,8 +583,7 @@
/*!
* Radio events function pointer
*/
-//static RadioEvents_t RadioEvents;
-SX1276MB1xAS Radio( OnRadioTxDone, OnRadioTxTimeout, OnRadioRxDone, OnRadioRxTimeout, OnRadioRxError, NULL, NULL );
+static RadioEvents_t RadioEvents;
/*!
* \brief Validates if the payload fits into the frame, taking the datarate
@@ -633,7 +634,7 @@
uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
TimerTime_t curTime = TimerGetCurrentTime( );
- memset( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
+ memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
// Update Aggregated duty cycle
if( AggregatedTimeOff < ( curTime - AggregatedLastTxDoneTime ) )
@@ -741,70 +742,99 @@
* \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]
+ * \retval status Function status [0: OK, 1: Unknown command, 2: Busy]
*/
static uint8_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 )
{
- MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ uint8_t status = 2; // Busy
+
switch( cmd )
{
case MOTE_MAC_LINK_CHECK_REQ:
- // No payload for this command
+ if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // No payload for this command
+ status = 0; // OK
+ }
break;
case MOTE_MAC_LINK_ADR_ANS:
- // Margin
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 1 ) )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // Margin
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ status = 0; // OK
+ }
break;
case MOTE_MAC_DUTY_CYCLE_ANS:
- // No payload for this answer
+ if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // No payload for this answer
+ status = 0; // OK
+ }
break;
case MOTE_MAC_RX_PARAM_SETUP_ANS:
- // Status: Datarate ACK, Channel ACK
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 1 ) )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // Status: Datarate ACK, Channel ACK
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ status = 0; // OK
+ }
break;
case MOTE_MAC_DEV_STATUS_ANS:
- // 1st byte Battery
- // 2nd byte Margin
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
- MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 2 ) )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // 1st byte Battery
+ // 2nd byte Margin
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p2;
+ status = 0; // OK
+ }
break;
case MOTE_MAC_NEW_CHANNEL_ANS:
- // Status: Datarate range OK, Channel frequency OK
- MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ if( MacCommandsBufferIndex < ( LORA_MAC_COMMAND_MAX_LENGTH - 1 ) )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // Status: Datarate range OK, Channel frequency OK
+ MacCommandsBuffer[MacCommandsBufferIndex++] = p1;
+ status = 0; // OK
+ }
break;
case MOTE_MAC_RX_TIMING_SETUP_ANS:
- // No payload for this answer
+ if( MacCommandsBufferIndex < LORA_MAC_COMMAND_MAX_LENGTH )
+ {
+ MacCommandsBuffer[MacCommandsBufferIndex++] = cmd;
+ // No payload for this answer
+ status = 0; // OK
+ }
break;
default:
- return 1;
+ return 1; // Unknown command
}
- if( MacCommandsBufferIndex <= 15 )
+ if( status == 0 )
{
MacCommandsInNextTx = true;
- return 0;
}
- else
- {
- return 2;
- }
+ return status;
}
// TODO: Add Documentation
static void LoRaMacNotify( LoRaMacEventFlags_t *flags, LoRaMacEventInfo_t *info )
{
- if( ( LoRaMacEvents != NULL ) && ( LoRaMacEvents->MacEvent != NULL ) )
+ if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->MacEvent != NULL ) )
{
- LoRaMacEvents->MacEvent( flags, info );
+ LoRaMacCallbacks->MacEvent( flags, info );
}
flags->Value = 0;
}
-typedef uint8_t ( *GetBatteryLevel )( );
-GetBatteryLevel LoRaMacGetBatteryLevel;
-
-void LoRaMacInit( LoRaMacEvent_t *events, uint8_t ( *getBatteryLevel )( ) )
+void LoRaMacInit( LoRaMacCallbacks_t *callbacks )
{
- LoRaMacEvents = events;
+ LoRaMacCallbacks = callbacks;
LoRaMacEventFlags.Value = 0;
@@ -821,8 +851,6 @@
LoRaMacEventInfo.NbGateways = 0;
LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
- LoRaMacGetBatteryLevel = getBatteryLevel;
-
LoRaMacDeviceClass = CLASS_A;
UpLinkCounter = 1;
@@ -908,9 +936,17 @@
TimerInit( &RxWindowTimer1, OnRxWindow1TimerEvent );
TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent );
TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent );
+
+ // Initialize Radio driver
+ RadioEvents.TxDone = OnRadioTxDone;
+ RadioEvents.RxDone = OnRadioRxDone;
+ RadioEvents.RxError = OnRadioRxError;
+ RadioEvents.TxTimeout = OnRadioTxTimeout;
+ RadioEvents.RxTimeout = OnRadioRxTimeout;
+ Radio.Init( &RadioEvents );
// Random seed initialization
- srand( Radio.Random( ) );
+ srand1( Radio.Random( ) );
// Initialize channel index.
Channel = LORA_MAX_NB_CHANNELS;
@@ -1035,7 +1071,7 @@
#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID )
static uint8_t drSwitch = 0;
- if( drSwitch == 0 )
+ if( ( ++drSwitch & 0x01 ) == 0x01 )
{
ChannelsDatarate = DR_0;
}
@@ -1043,7 +1079,6 @@
{
ChannelsDatarate = DR_4;
}
- drSwitch = ( drSwitch + 1 ) % 2;
#endif
return LoRaMacSend( &macHdr, NULL, 0, NULL, 0 );
}
@@ -1268,9 +1303,9 @@
LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
}
}
- MacCommandsInNextTx = false;
- MacCommandsBufferIndex = 0;
}
+ MacCommandsInNextTx = false;
+ MacCommandsBufferIndex = 0;
if( ( pktHeaderLen + fBufferSize ) > LORAMAC_PHY_MAXPAYLOAD )
{
@@ -1448,10 +1483,11 @@
// Data rate ACK = 0
// Channel mask = 0
AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
+ macIndex += 3; // Skip over the remaining bytes of the request
break;
}
- chMask = payload[macIndex++];
- chMask |= payload[macIndex++] << 8;
+ chMask = ( uint16_t )payload[macIndex++];
+ chMask |= ( uint16_t )payload[macIndex++] << 8;
nbRep = payload[macIndex++];
chMaskCntl = ( nbRep >> 4 ) & 0x07;
@@ -1590,10 +1626,9 @@
int8_t drOffset = 0;
uint32_t freq = 0;
- drOffset = payload[macIndex++];
- datarate = drOffset & 0x0F;
- drOffset = ( drOffset >> 4 ) & 0x0F;
-
+ drOffset = ( payload[macIndex] >> 4 ) & 0x07;
+ datarate = payload[macIndex] & 0x0F;
+ macIndex++;
freq = ( uint32_t )payload[macIndex++];
freq |= ( uint32_t )payload[macIndex++] << 8;
freq |= ( uint32_t )payload[macIndex++] << 16;
@@ -1610,7 +1645,8 @@
status &= 0xFD; // Datarate KO
}
- if( ( ( drOffset < 0 ) || ( drOffset > 5 ) ) == true )
+ if( ( ( drOffset < LORAMAC_MIN_RX1_DR_OFFSET ) ||
+ ( drOffset > LORAMAC_MAX_RX1_DR_OFFSET ) ) == true )
{
status &= 0xFB; // Rx1DrOffset range KO
}
@@ -1625,7 +1661,14 @@
}
break;
case SRV_MAC_DEV_STATUS_REQ:
- AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, LoRaMacGetBatteryLevel( ), LoRaMacEventInfo.RxSnr );
+ {
+ uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE;
+ if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) )
+ {
+ batteryLevel = LoRaMacCallbacks->GetBatteryLevel( );
+ }
+ AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, LoRaMacEventInfo.RxSnr );
+ }
break;
case SRV_MAC_NEW_CHANNEL_REQ:
{
@@ -1723,6 +1766,12 @@
TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
TimerStart( &RxWindowTimer2 );
}
+ if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
+ {
+ TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT +
+ randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) );
+ TimerStart( &AckTimeoutTimer );
+ }
}
else
{
@@ -1732,6 +1781,7 @@
if( NodeAckRequested == false )
{
+ LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
ChannelsNbRepCounter++;
}
}
@@ -1746,18 +1796,20 @@
uint8_t pktHeaderLen = 0;
uint32_t address = 0;
- uint16_t sequenceCounter = 0;
- int32_t sequence = 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;
- uint32_t downLinkCounter = 0;
bool isMicOk = false;
@@ -1814,7 +1866,16 @@
// 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 )
@@ -1847,8 +1908,6 @@
{
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:
@@ -1898,8 +1957,8 @@
}
fCtrl.Value = payload[pktHeaderLen++];
- sequenceCounter |= ( uint32_t )payload[pktHeaderLen++];
- sequenceCounter |= ( uint32_t )payload[pktHeaderLen++] << 8;
+ sequenceCounter = ( uint16_t )payload[pktHeaderLen++];
+ sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8;
appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
@@ -1908,45 +1967,39 @@
micRx |= ( (uint32_t)payload[size - LORAMAC_MFR_LEN + 2] << 16 );
micRx |= ( (uint32_t)payload[size - LORAMAC_MFR_LEN + 3] << 24 );
- sequence = ( int32_t )sequenceCounter - ( int32_t )( downLinkCounter & 0xFFFF );
- if( sequence < 0 )
+ sequenceCounterPrev = ( uint16_t )downLinkCounter;
+ sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
+
+ if( sequenceCounterDiff < ( 1 << 15 ) )
{
- // sequence reset or roll over happened
- downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | ( sequenceCounter + ( uint32_t )0x10000 );
+ downLinkCounter += sequenceCounterDiff;
LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
if( micRx == mic )
{
isMicOk = true;
}
- else
- {
- isMicOk = false;
- // sequence reset
- if( LoRaMacEventFlags.Bits.Multicast == 1 )
- {
- curMulticastParams->DownLinkCounter = downLinkCounter = sequenceCounter;
- }
- else
- {
- DownLinkCounter = downLinkCounter = sequenceCounter;
- }
- LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
- }
}
else
{
- downLinkCounter = ( downLinkCounter & 0xFFFF0000 ) | sequenceCounter;
- LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
+ // 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;
+ }
}
- if( ( isMicOk == true ) ||
- ( micRx == mic ) )
+ 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;
@@ -2025,27 +2078,29 @@
}
}
- 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;
+ if( NodeAckRequested == true )
+ {
+ OnAckTimeoutTimerEvent( );
+ }
}
}
break;
case FRAME_TYPE_PROPRIETARY:
//Intentional falltrough
default:
- LoRaMacEventFlags.Bits.Tx = 1;
LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
LoRaMacState &= ~MAC_TX_RUNNING;
break;
}
+ LoRaMacEventFlags.Bits.Tx = 1;
}
/*!
@@ -2075,6 +2130,10 @@
{
Radio.Sleep( );
}
+ else
+ {
+ OnRxWindow2TimerEvent( );
+ }
if( LoRaMacEventFlags.Bits.RxSlot == 1 )
{
LoRaMacEventFlags.Bits.Tx = 1;
@@ -2091,6 +2150,10 @@
{
Radio.Sleep( );
}
+ else
+ {
+ OnRxWindow2TimerEvent( );
+ }
if( LoRaMacEventFlags.Bits.RxSlot == 1 )
{
LoRaMacEventFlags.Bits.Tx = 1;
@@ -2108,17 +2171,36 @@
*/
void LoRaMacRxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous )
{
- if( Radio.GetStatus( ) == IDLE )
+ uint8_t downlinkDatarate = Datarates[datarate];
+ RadioModems_t modem;
+
+ if( Radio.GetStatus( ) == RF_IDLE )
{
Radio.SetChannel( freq );
+#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 )
if( datarate == DR_7 )
{
- Radio.SetRxConfig( MODEM_FSK, 50e3, Datarates[datarate] * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
+ modem = MODEM_FSK;
+ Radio.SetRxConfig( MODEM_FSK, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, 0, false, 0, true, 0, 0, false, rxContinuous );
}
else
{
- Radio.SetRxConfig( MODEM_LORA, bandwidth, Datarates[datarate], 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous );
+ 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 );
@@ -2142,6 +2224,10 @@
TimerStop( &RxWindowTimer1 );
LoRaMacEventFlags.Bits.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 )
@@ -2174,7 +2260,6 @@
{// LoRa 500 kHz
bandwidth = 2;
}
- //LoRaMacRxWindowSetup( Channels[Channel].Frequency, datarate, bandwidth, symbTimeout, false );
LoRaMacRxWindowSetup( 923.3e6 + ( Channel % 8 ) * 600e3, datarate, bandwidth, symbTimeout, false );
#else
#error "Please define a frequency band in the compiler options."
@@ -2338,7 +2423,6 @@
{
UpLinkCounter++;
}
- LoRaMacEventInfo.Status = LORAMAC_EVENT_INFO_STATUS_OK;
}
}
}
@@ -2350,6 +2434,7 @@
if( LoRaMacState == MAC_IDLE )
{
LoRaMacNotify( &LoRaMacEventFlags, &LoRaMacEventInfo );
+ LoRaMacEventFlags.Bits.Tx = 0;
}
else
{
