Fork of Semtech LoRaWAN stack
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
{
