Simplified LoRaWAN library.
Fork of LoRaWAN-lib-v1_0_1 by
Diff: LoRaMac.cpp
- Revision:
- 1:91e4e6c60d1e
- Parent:
- 0:91d1a7783bb9
- Child:
- 2:14a5d6ad92d5
diff -r 91d1a7783bb9 -r 91e4e6c60d1e LoRaMac.cpp --- 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 {