LoRaWAN end device MAC layer for SX1272 and SX1276. Supports LoRaWAN-1.0 and LoRaWAN-1.1

Dependencies:   sx12xx_hal

Dependents:   LoRaWAN-SanJose_Bootcamp LoRaWAN-grove-cayenne LoRaWAN-classC-demo LoRaWAN-grove-cayenne ... more

radio chip selection

Radio chip driver is not included, because two options are available.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

application project requirements

This library requires mbed TLS to be enabled.
The file mbed_app.json must be present in the project using this library:

{
    "macros": [ "MBEDTLS_CMAC_C" ]
}

regional PHY selection

All end device configuration is done in Commissioning.h, define desired radio frequency band of operation in this header file.
Commissioning.h is located in the application using this library.

end device provisioning

End device is provisioned by editing Commissioning.h in the application which is using this library
To use LoRaWAN-1.0 OTA: make sure LORAWAN_ROOT_APPKEY is undefined.
To use LoRaWAN-1.1 OTA, define LORAWAN_ROOT_APPKEY.
To select OTA operation, define LORAWAN_JOIN_EUI, then LORAWAN_DEVICE_EUI must be defined, along with root key(s).
To select ABP operation, undefine LORAWAN_JOIN_EUI: then define session keys

LoRaWAN 1.0 nameLoRaWAN 1.1 nameComissioning.h defnedescription
OTADevEUIDevEUILORAWAN_DEVICE_EUIuniquely identifies end device
OTAAppEUIJoinEUILORAWAN_JOIN_EUI
OTAAppKeyNwkKeyLORAWAN_ROOT_NWKKEYroot key for network server
OTA(note 1)AppKeyLORAWAN_ROOT_APPKEYroot key for application server
ABPNwkSKey(note 3)LORAWAN_FNwkSIntKeynetwork session key
ABP(note 2)SNwkSIntKeyLORAWAN_SNwkSIntKeymac layer network integrity key
ABP(note 2)NwkSEncKeyLORAWAN_NwkSEncKeynetwork session encryption key
ABP(note 2)FNwkSIntKeyLORAWAN_FNwkSIntKeyforwarding network session integrity key
ABPAppSKeyAppSKeyLORAWAN_APPSKEYapplication session encryption key

(note 1): LoRaWAN-1.0 OTA uses a single root key for both network server and application server.

In LoRaWAN-1.0 OTA: the single root AppKey is used to generate NwkSkey and AppSKey.
(note 2): In LoRaWAN-1.0 (both OTA and ABP) SNwkSIntKey, NwkSEncKey. FNwkSIntKey are of same value and are collectively known as NwkSKey.
(note 3): LoRaWAN-1.0 uses single network session key, LoRaWAN-1.1 uses 3 network session keys. Both use a unique application session key.


In LoRaWAN-1.1 OTA: the root NwkKey is used to generate SNwkSIntKey, NwkSEncKey, FNwkSIntKey
In LoRaWAN-1.1 OTA: the root AppKey is used to generate AppSKey


in ABP mode, the DevAddr, and session keys are fixed (never change), and frame counters never reset to zero.
ABP operation has no concept of: root keys, or DevEUI or JoinEUI/AppEUI.
in OTA mode, the DevAddr and session keys are assigned at join procedure, and frame counters reset at join.

eeprom

This library includes eeprom driver to support non-volatile storage required by LoRaWAN specification.
Currently eeprom is implemented for STM32L1 family and STM32L0 family.
Writing of values are wear-leveled to increase endurance; each write operation circulates across several memory locations. A read operation returns the highest value found. This simple method is used for sequence numbers which only increase.

value nameused in
DevNonceOTAfor Join request (note 1)
RJcount1OTAfor ReJoin Type 1 request
FCntUpABPuplink frame counter
NFCntDownABPdownlink frame counter
AFCntDownABPdownlink frame counter

AFCntDown is only used in LoRaWAN-1.1 when application payload is present in downlink and FPort > 0.
NFCntDown is used in LoRaWAN-1.1 when FPort is zero in downlink or application payload not present.
NFCntDown is the only downlink frame counter used in LoRaWAN-1.0
(note 1) OTA DevNonce is random number in LoRaWAN-1.0, therefore not stored in eeprom. DevNonce in LoRaWAN-1.1 is forever increasing (non-volatile) number upon each join request,.
RJcount0 is only stored in RAM because the value resets upon new session from JoinAccept, therefore not stored in eeprom.
Frame counters in OTA mode reset upon new session in join request, therefore are stored in RAM instead of eeprom for OTA.

radio driver support

When SX127x driver is used, both SX1272 and SX1276 are supported without defining at compile time. The chip is detected at start-up.
Supported radio platforms:


Alternately, when SX126x driver is imported, the SX126xDVK1xAS board is used.

low-speed clock oscillator selection

LoRaWAN uses 32768Hz crystal to permit low-power operation.
However, some mbed targets might revert to low-speed internal oscillator, which is not accurate enough for LoRaWAN operation.
An oscillator check is performed at initialization; program will not start if internal oscillator is used.
To force LSE watch crystal, add to mbed_app.json

{
    "macros": [ "MBEDTLS_CMAC_C" ],
    "target_overrides": {
        "<your-target>": {
            "target.lse_available": true
        }
    }
}
Committer:
Wayne Roberts
Date:
Mon Mar 05 16:49:15 2018 -0800
Revision:
3:eb174e10afbb
Parent:
0:6b3ac9c5a042
Child:
7:4b6f960dcca2
correct ADR_ACK_CNT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1 #include "board.h"
Wayne Roberts 0:6b3ac9c5a042 2 #if defined(USE_BAND_915_HYBRID) || defined(USE_BAND_915)
Wayne Roberts 0:6b3ac9c5a042 3 #include <stdint.h>
Wayne Roberts 0:6b3ac9c5a042 4 #include "LoRaMacPrivate.h"
Wayne Roberts 0:6b3ac9c5a042 5
Wayne Roberts 0:6b3ac9c5a042 6 ChannelParams_t Channels[LORA_MAX_NB_CHANNELS];
Wayne Roberts 0:6b3ac9c5a042 7 uint16_t ChannelsMaskRemaining[6];
Wayne Roberts 0:6b3ac9c5a042 8 const int8_t TxPowers[] = { 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10 };
Wayne Roberts 0:6b3ac9c5a042 9
Wayne Roberts 0:6b3ac9c5a042 10 // DR: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Wayne Roberts 0:6b3ac9c5a042 11 const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0};
Wayne Roberts 0:6b3ac9c5a042 12
Wayne Roberts 0:6b3ac9c5a042 13 const uint8_t MaxPayloadOfDatarate[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
Wayne Roberts 0:6b3ac9c5a042 14
Wayne Roberts 0:6b3ac9c5a042 15 bool DisableChannelInMask( uint8_t id, uint16_t* mask )
Wayne Roberts 0:6b3ac9c5a042 16 {
Wayne Roberts 0:6b3ac9c5a042 17 uint8_t index = 0;
Wayne Roberts 0:6b3ac9c5a042 18 index = id / 16;
Wayne Roberts 0:6b3ac9c5a042 19
Wayne Roberts 0:6b3ac9c5a042 20 if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
Wayne Roberts 0:6b3ac9c5a042 21 {
Wayne Roberts 0:6b3ac9c5a042 22 return false;
Wayne Roberts 0:6b3ac9c5a042 23 }
Wayne Roberts 0:6b3ac9c5a042 24
Wayne Roberts 0:6b3ac9c5a042 25 // Deactivate channel
Wayne Roberts 0:6b3ac9c5a042 26 mask[index] &= ~( 1 << ( id % 16 ) );
Wayne Roberts 0:6b3ac9c5a042 27
Wayne Roberts 0:6b3ac9c5a042 28 return true;
Wayne Roberts 0:6b3ac9c5a042 29 }
Wayne Roberts 0:6b3ac9c5a042 30
Wayne Roberts 0:6b3ac9c5a042 31 /*!
Wayne Roberts 0:6b3ac9c5a042 32 * Up/Down link data rates offset definition
Wayne Roberts 0:6b3ac9c5a042 33 */
Wayne Roberts 0:6b3ac9c5a042 34 const int8_t datarateOffsets[5][4] =
Wayne Roberts 0:6b3ac9c5a042 35 {
Wayne Roberts 0:6b3ac9c5a042 36 { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0
Wayne Roberts 0:6b3ac9c5a042 37 { DR_11, DR_10, DR_9 , DR_8 }, // DR_1
Wayne Roberts 0:6b3ac9c5a042 38 { DR_12, DR_11, DR_10, DR_9 }, // DR_2
Wayne Roberts 0:6b3ac9c5a042 39 { DR_13, DR_12, DR_11, DR_10 }, // DR_3
Wayne Roberts 0:6b3ac9c5a042 40 { DR_13, DR_13, DR_12, DR_11 }, // DR_4
Wayne Roberts 0:6b3ac9c5a042 41 };
Wayne Roberts 0:6b3ac9c5a042 42
Wayne Roberts 0:6b3ac9c5a042 43 uint32_t region_GetRxBandwidth( int8_t datarate )
Wayne Roberts 0:6b3ac9c5a042 44 {
Wayne Roberts 0:6b3ac9c5a042 45 if( datarate >= DR_4 )
Wayne Roberts 0:6b3ac9c5a042 46 {// LoRa 500 kHz
Wayne Roberts 0:6b3ac9c5a042 47 return 2;
Wayne Roberts 0:6b3ac9c5a042 48 }
Wayne Roberts 0:6b3ac9c5a042 49 return 0; // LoRa 125 kHz
Wayne Roberts 0:6b3ac9c5a042 50 }
Wayne Roberts 0:6b3ac9c5a042 51
Wayne Roberts 0:6b3ac9c5a042 52 uint16_t region_GetRxSymbolTimeout( int8_t datarate )
Wayne Roberts 0:6b3ac9c5a042 53 {
Wayne Roberts 0:6b3ac9c5a042 54 switch( datarate )
Wayne Roberts 0:6b3ac9c5a042 55 {
Wayne Roberts 0:6b3ac9c5a042 56 case DR_0: // SF10 - BW125
Wayne Roberts 0:6b3ac9c5a042 57 return 5;
Wayne Roberts 0:6b3ac9c5a042 58
Wayne Roberts 0:6b3ac9c5a042 59 case DR_1: // SF9 - BW125
Wayne Roberts 0:6b3ac9c5a042 60 case DR_2: // SF8 - BW125
Wayne Roberts 0:6b3ac9c5a042 61 case DR_8: // SF12 - BW500
Wayne Roberts 0:6b3ac9c5a042 62 case DR_9: // SF11 - BW500
Wayne Roberts 0:6b3ac9c5a042 63 case DR_10: // SF10 - BW500
Wayne Roberts 0:6b3ac9c5a042 64 return 8;
Wayne Roberts 0:6b3ac9c5a042 65
Wayne Roberts 0:6b3ac9c5a042 66 case DR_3: // SF7 - BW125
Wayne Roberts 0:6b3ac9c5a042 67 case DR_11: // SF9 - BW500
Wayne Roberts 0:6b3ac9c5a042 68 return 10;
Wayne Roberts 0:6b3ac9c5a042 69
Wayne Roberts 0:6b3ac9c5a042 70 case DR_4: // SF8 - BW500
Wayne Roberts 0:6b3ac9c5a042 71 case DR_12: // SF8 - BW500
Wayne Roberts 0:6b3ac9c5a042 72 return 14;
Wayne Roberts 0:6b3ac9c5a042 73
Wayne Roberts 0:6b3ac9c5a042 74 case DR_13: // SF7 - BW500
Wayne Roberts 0:6b3ac9c5a042 75 return 16;
Wayne Roberts 0:6b3ac9c5a042 76
Wayne Roberts 0:6b3ac9c5a042 77 default:
Wayne Roberts 0:6b3ac9c5a042 78 return 0; // LoRa 125 kHz
Wayne Roberts 0:6b3ac9c5a042 79 }
Wayne Roberts 0:6b3ac9c5a042 80 }
Wayne Roberts 0:6b3ac9c5a042 81
Wayne Roberts 0:6b3ac9c5a042 82 void region_rx1_setup(uint8_t ch)
Wayne Roberts 0:6b3ac9c5a042 83 {
Wayne Roberts 0:6b3ac9c5a042 84 int8_t datarate = datarateOffsets[LoRaMacParams.ChannelsDatarate][LoRaMacParams.Rx1DrOffset];
Wayne Roberts 0:6b3ac9c5a042 85 if( datarate < 0 )
Wayne Roberts 0:6b3ac9c5a042 86 {
Wayne Roberts 0:6b3ac9c5a042 87 datarate = DR_0;
Wayne Roberts 0:6b3ac9c5a042 88 }
Wayne Roberts 0:6b3ac9c5a042 89
Wayne Roberts 0:6b3ac9c5a042 90 RxWindowSetup(
Wayne Roberts 0:6b3ac9c5a042 91 LORAMAC_FIRST_RX1_CHANNEL + ( ch % 8 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL,
Wayne Roberts 0:6b3ac9c5a042 92 datarate,
Wayne Roberts 0:6b3ac9c5a042 93 region_GetRxBandwidth(datarate),
Wayne Roberts 0:6b3ac9c5a042 94 region_GetRxSymbolTimeout(datarate)
Wayne Roberts 0:6b3ac9c5a042 95 );
Wayne Roberts 0:6b3ac9c5a042 96 }
Wayne Roberts 0:6b3ac9c5a042 97
Wayne Roberts 0:6b3ac9c5a042 98 bool ValidateChannelMask( uint16_t* channelsMask )
Wayne Roberts 0:6b3ac9c5a042 99 {
Wayne Roberts 0:6b3ac9c5a042 100 bool chanMaskState = false;
Wayne Roberts 0:6b3ac9c5a042 101 uint16_t block1 = 0;
Wayne Roberts 0:6b3ac9c5a042 102 uint16_t block2 = 0;
Wayne Roberts 0:6b3ac9c5a042 103 uint8_t index = 0;
Wayne Roberts 0:6b3ac9c5a042 104
Wayne Roberts 0:6b3ac9c5a042 105 for( uint8_t i = 0; i < 4; i++ )
Wayne Roberts 0:6b3ac9c5a042 106 {
Wayne Roberts 0:6b3ac9c5a042 107 block1 = channelsMask[i] & 0x00FF;
Wayne Roberts 0:6b3ac9c5a042 108 block2 = channelsMask[i] & 0xFF00;
Wayne Roberts 0:6b3ac9c5a042 109
Wayne Roberts 0:6b3ac9c5a042 110 if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) )
Wayne Roberts 0:6b3ac9c5a042 111 {
Wayne Roberts 0:6b3ac9c5a042 112 channelsMask[i] &= block1;
Wayne Roberts 0:6b3ac9c5a042 113 channelsMask[4] = 1 << ( i * 2 );
Wayne Roberts 0:6b3ac9c5a042 114 chanMaskState = true;
Wayne Roberts 0:6b3ac9c5a042 115 index = i;
Wayne Roberts 0:6b3ac9c5a042 116 }
Wayne Roberts 0:6b3ac9c5a042 117 else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) )
Wayne Roberts 0:6b3ac9c5a042 118 {
Wayne Roberts 0:6b3ac9c5a042 119 channelsMask[i] &= block2;
Wayne Roberts 0:6b3ac9c5a042 120 channelsMask[4] = 1 << ( i * 2 + 1 );
Wayne Roberts 0:6b3ac9c5a042 121 chanMaskState = true;
Wayne Roberts 0:6b3ac9c5a042 122 index = i;
Wayne Roberts 0:6b3ac9c5a042 123 }
Wayne Roberts 0:6b3ac9c5a042 124 }
Wayne Roberts 0:6b3ac9c5a042 125
Wayne Roberts 0:6b3ac9c5a042 126 // Do only change the channel mask, if we have found a valid block.
Wayne Roberts 0:6b3ac9c5a042 127 if( chanMaskState == true )
Wayne Roberts 0:6b3ac9c5a042 128 {
Wayne Roberts 0:6b3ac9c5a042 129 for( uint8_t i = 0; i < 4; i++ )
Wayne Roberts 0:6b3ac9c5a042 130 {
Wayne Roberts 0:6b3ac9c5a042 131 if( i != index )
Wayne Roberts 0:6b3ac9c5a042 132 {
Wayne Roberts 0:6b3ac9c5a042 133 channelsMask[i] = 0;
Wayne Roberts 0:6b3ac9c5a042 134 }
Wayne Roberts 0:6b3ac9c5a042 135 }
Wayne Roberts 0:6b3ac9c5a042 136 }
Wayne Roberts 0:6b3ac9c5a042 137 return chanMaskState;
Wayne Roberts 0:6b3ac9c5a042 138 }
Wayne Roberts 0:6b3ac9c5a042 139
Wayne Roberts 0:6b3ac9c5a042 140 void region_adr_request(adr_t* adr)
Wayne Roberts 0:6b3ac9c5a042 141 {
Wayne Roberts 0:6b3ac9c5a042 142 if( adr->chMaskCntl == 6 )
Wayne Roberts 0:6b3ac9c5a042 143 {
Wayne Roberts 0:6b3ac9c5a042 144 // Enable all 125 kHz channels
Wayne Roberts 0:6b3ac9c5a042 145 adr->channelsMask[0] = 0xFFFF;
Wayne Roberts 0:6b3ac9c5a042 146 adr->channelsMask[1] = 0xFFFF;
Wayne Roberts 0:6b3ac9c5a042 147 adr->channelsMask[2] = 0xFFFF;
Wayne Roberts 0:6b3ac9c5a042 148 adr->channelsMask[3] = 0xFFFF;
Wayne Roberts 0:6b3ac9c5a042 149 // Apply chMask to channels 64 to 71
Wayne Roberts 0:6b3ac9c5a042 150 adr->channelsMask[4] = adr->chMask;
Wayne Roberts 0:6b3ac9c5a042 151 }
Wayne Roberts 0:6b3ac9c5a042 152 else if( adr->chMaskCntl == 7 )
Wayne Roberts 0:6b3ac9c5a042 153 {
Wayne Roberts 0:6b3ac9c5a042 154 // Disable all 125 kHz channels
Wayne Roberts 0:6b3ac9c5a042 155 adr->channelsMask[0] = 0x0000;
Wayne Roberts 0:6b3ac9c5a042 156 adr->channelsMask[1] = 0x0000;
Wayne Roberts 0:6b3ac9c5a042 157 adr->channelsMask[2] = 0x0000;
Wayne Roberts 0:6b3ac9c5a042 158 adr->channelsMask[3] = 0x0000;
Wayne Roberts 0:6b3ac9c5a042 159 // Apply chMask to channels 64 to 71
Wayne Roberts 0:6b3ac9c5a042 160 adr->channelsMask[4] = adr->chMask;
Wayne Roberts 0:6b3ac9c5a042 161 }
Wayne Roberts 0:6b3ac9c5a042 162 else if( adr->chMaskCntl == 5 )
Wayne Roberts 0:6b3ac9c5a042 163 {
Wayne Roberts 0:6b3ac9c5a042 164 // RFU
Wayne Roberts 0:6b3ac9c5a042 165 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 166 }
Wayne Roberts 0:6b3ac9c5a042 167 else
Wayne Roberts 0:6b3ac9c5a042 168 {
Wayne Roberts 0:6b3ac9c5a042 169 adr->channelsMask[adr->chMaskCntl] = adr->chMask;
Wayne Roberts 0:6b3ac9c5a042 170
Wayne Roberts 0:6b3ac9c5a042 171 // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
Wayne Roberts 0:6b3ac9c5a042 172 if( ( adr->datarate < DR_4 ) && ( CountNbEnabled125kHzChannels( adr->channelsMask ) < 2 ) )
Wayne Roberts 0:6b3ac9c5a042 173 {
Wayne Roberts 0:6b3ac9c5a042 174 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 175 }
Wayne Roberts 0:6b3ac9c5a042 176
Wayne Roberts 0:6b3ac9c5a042 177 #if defined( USE_BAND_915_HYBRID )
Wayne Roberts 0:6b3ac9c5a042 178 if( ValidateChannelMask( adr->channelsMask ) == false )
Wayne Roberts 0:6b3ac9c5a042 179 {
Wayne Roberts 0:6b3ac9c5a042 180 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 181 }
Wayne Roberts 0:6b3ac9c5a042 182 #endif
Wayne Roberts 0:6b3ac9c5a042 183 }
Wayne Roberts 0:6b3ac9c5a042 184
Wayne Roberts 0:6b3ac9c5a042 185
Wayne Roberts 0:6b3ac9c5a042 186 if ((adr->status & 0x07) == 0x07) {
Wayne Roberts 0:6b3ac9c5a042 187 // Reset ChannelsMaskRemaining to the new ChannelsMask
Wayne Roberts 0:6b3ac9c5a042 188 ChannelsMaskRemaining[0] &= adr->channelsMask[0];
Wayne Roberts 0:6b3ac9c5a042 189 ChannelsMaskRemaining[1] &= adr->channelsMask[1];
Wayne Roberts 0:6b3ac9c5a042 190 ChannelsMaskRemaining[2] &= adr->channelsMask[2];
Wayne Roberts 0:6b3ac9c5a042 191 ChannelsMaskRemaining[3] &= adr->channelsMask[3];
Wayne Roberts 0:6b3ac9c5a042 192 ChannelsMaskRemaining[4] = adr->channelsMask[4];
Wayne Roberts 0:6b3ac9c5a042 193 ChannelsMaskRemaining[5] = adr->channelsMask[5];
Wayne Roberts 0:6b3ac9c5a042 194 }
Wayne Roberts 0:6b3ac9c5a042 195 }
Wayne Roberts 0:6b3ac9c5a042 196
Wayne Roberts 3:eb174e10afbb 197 uint8_t region_CountNbEnabledChannels()
Wayne Roberts 0:6b3ac9c5a042 198 {
Wayne Roberts 3:eb174e10afbb 199 return CountNbEnabled125kHzChannels(LoRaMacParams.ChannelsMask) + CountBits(LoRaMacParams.ChannelsMask[4], 16);
Wayne Roberts 0:6b3ac9c5a042 200 }
Wayne Roberts 0:6b3ac9c5a042 201
Wayne Roberts 0:6b3ac9c5a042 202 uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask )
Wayne Roberts 0:6b3ac9c5a042 203 {
Wayne Roberts 0:6b3ac9c5a042 204 uint8_t nb125kHzChannels = 0;
Wayne Roberts 0:6b3ac9c5a042 205
Wayne Roberts 0:6b3ac9c5a042 206 for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ )
Wayne Roberts 0:6b3ac9c5a042 207 {
Wayne Roberts 0:6b3ac9c5a042 208 nb125kHzChannels += CountBits( channelsMask[k], 16 );
Wayne Roberts 0:6b3ac9c5a042 209 }
Wayne Roberts 0:6b3ac9c5a042 210
Wayne Roberts 0:6b3ac9c5a042 211 return nb125kHzChannels;
Wayne Roberts 0:6b3ac9c5a042 212 }
Wayne Roberts 0:6b3ac9c5a042 213
Wayne Roberts 0:6b3ac9c5a042 214 static bool SetNextChannel( )
Wayne Roberts 0:6b3ac9c5a042 215 {
Wayne Roberts 0:6b3ac9c5a042 216 uint8_t nbEnabledChannels = 0;
Wayne Roberts 0:6b3ac9c5a042 217 uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
Wayne Roberts 0:6b3ac9c5a042 218
Wayne Roberts 0:6b3ac9c5a042 219 memset( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
Wayne Roberts 0:6b3ac9c5a042 220
Wayne Roberts 0:6b3ac9c5a042 221 if( CountNbEnabled125kHzChannels( ChannelsMaskRemaining ) == 0 )
Wayne Roberts 0:6b3ac9c5a042 222 { // Restore default channels
Wayne Roberts 0:6b3ac9c5a042 223 memcpy( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParams.ChannelsMask, 8 );
Wayne Roberts 0:6b3ac9c5a042 224 }
Wayne Roberts 0:6b3ac9c5a042 225 if( ( LoRaMacParams.ChannelsDatarate >= DR_4 ) && ( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 226 { // Make sure, that the channels are activated
Wayne Roberts 0:6b3ac9c5a042 227 ChannelsMaskRemaining[4] = LoRaMacParams.ChannelsMask[4];
Wayne Roberts 0:6b3ac9c5a042 228 }
Wayne Roberts 0:6b3ac9c5a042 229
Wayne Roberts 0:6b3ac9c5a042 230 // Search how many channels are enabled
Wayne Roberts 0:6b3ac9c5a042 231 for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
Wayne Roberts 0:6b3ac9c5a042 232 {
Wayne Roberts 0:6b3ac9c5a042 233 for( uint8_t j = 0; j < 16; j++ )
Wayne Roberts 0:6b3ac9c5a042 234 {
Wayne Roberts 0:6b3ac9c5a042 235 if( ( ChannelsMaskRemaining[k] & ( 1 << j ) ) != 0 )
Wayne Roberts 0:6b3ac9c5a042 236 {
Wayne Roberts 0:6b3ac9c5a042 237 if( Channels[i + j].FreqHz == 0 )
Wayne Roberts 0:6b3ac9c5a042 238 { // Check if the channel is enabled
Wayne Roberts 0:6b3ac9c5a042 239 continue;
Wayne Roberts 0:6b3ac9c5a042 240 }
Wayne Roberts 0:6b3ac9c5a042 241 if( ( ( Channels[i + j].DrRange.Fields.Min <= LoRaMacParams.ChannelsDatarate ) &&
Wayne Roberts 0:6b3ac9c5a042 242 ( LoRaMacParams.ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
Wayne Roberts 0:6b3ac9c5a042 243 { // Check if the current channel selection supports the given datarate
Wayne Roberts 0:6b3ac9c5a042 244 continue;
Wayne Roberts 0:6b3ac9c5a042 245 }
Wayne Roberts 0:6b3ac9c5a042 246 enabledChannels[nbEnabledChannels++] = i + j;
Wayne Roberts 0:6b3ac9c5a042 247 }
Wayne Roberts 0:6b3ac9c5a042 248 }
Wayne Roberts 0:6b3ac9c5a042 249 }
Wayne Roberts 0:6b3ac9c5a042 250
Wayne Roberts 0:6b3ac9c5a042 251 if( nbEnabledChannels > 0 )
Wayne Roberts 0:6b3ac9c5a042 252 {
Wayne Roberts 0:6b3ac9c5a042 253 Channel = enabledChannels[random_at_most( nbEnabledChannels - 1 )];
Wayne Roberts 0:6b3ac9c5a042 254 if( Channel < ( LORA_MAX_NB_CHANNELS - 8 ) )
Wayne Roberts 0:6b3ac9c5a042 255 {
Wayne Roberts 0:6b3ac9c5a042 256 DisableChannelInMask( Channel, ChannelsMaskRemaining );
Wayne Roberts 0:6b3ac9c5a042 257 }
Wayne Roberts 0:6b3ac9c5a042 258 return true;
Wayne Roberts 0:6b3ac9c5a042 259 }
Wayne Roberts 0:6b3ac9c5a042 260 else
Wayne Roberts 0:6b3ac9c5a042 261 {
Wayne Roberts 0:6b3ac9c5a042 262 // Datarate not supported by any channel
Wayne Roberts 0:6b3ac9c5a042 263 return false;
Wayne Roberts 0:6b3ac9c5a042 264 }
Wayne Roberts 0:6b3ac9c5a042 265 }
Wayne Roberts 0:6b3ac9c5a042 266
Wayne Roberts 0:6b3ac9c5a042 267 void region_ScheduleTx( )
Wayne Roberts 0:6b3ac9c5a042 268 {
Wayne Roberts 0:6b3ac9c5a042 269 // Select channel
Wayne Roberts 0:6b3ac9c5a042 270 while( SetNextChannel() == false )
Wayne Roberts 0:6b3ac9c5a042 271 {
Wayne Roberts 0:6b3ac9c5a042 272 // Set the default datarate
Wayne Roberts 0:6b3ac9c5a042 273 LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 274 }
Wayne Roberts 0:6b3ac9c5a042 275
Wayne Roberts 0:6b3ac9c5a042 276 //MAC_PRINTF("ch%u ", Channel);
Wayne Roberts 0:6b3ac9c5a042 277 SendFrameOnChannel( Channel );
Wayne Roberts 0:6b3ac9c5a042 278 }
Wayne Roberts 0:6b3ac9c5a042 279
Wayne Roberts 0:6b3ac9c5a042 280 void region_tx_setup(int8_t dbm, uint8_t pktLen)
Wayne Roberts 0:6b3ac9c5a042 281 {
Wayne Roberts 0:6b3ac9c5a042 282 int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate];
Wayne Roberts 0:6b3ac9c5a042 283
Wayne Roberts 0:6b3ac9c5a042 284 //MAC_PRINTF("txsetup sf%d dr%u ", datarate, LoRaMacParams.ChannelsDatarate);
Wayne Roberts 0:6b3ac9c5a042 285
Wayne Roberts 0:6b3ac9c5a042 286 if( LoRaMacParams.ChannelsDatarate >= DR_4 )
Wayne Roberts 0:6b3ac9c5a042 287 { // High speed LoRa channel BW500 kHz
Wayne Roberts 0:6b3ac9c5a042 288 Radio::SetTxConfig( MODEM_LORA, dbm, 0, 2, datarate, 1, 8, false, true, false);
Wayne Roberts 0:6b3ac9c5a042 289 //TxTimeOnAir_us = Radio.TimeOnAir_us( MODEM_LORA, pktLen );
Wayne Roberts 0:6b3ac9c5a042 290 }
Wayne Roberts 0:6b3ac9c5a042 291 else
Wayne Roberts 0:6b3ac9c5a042 292 { // Normal LoRa channel
Wayne Roberts 0:6b3ac9c5a042 293 Radio::SetTxConfig( MODEM_LORA, dbm, 0, 0, datarate, 1, 8, false, true, false);
Wayne Roberts 0:6b3ac9c5a042 294 //TxTimeOnAir_us = Radio.TimeOnAir_us( MODEM_LORA, pktLen );
Wayne Roberts 0:6b3ac9c5a042 295 }
Wayne Roberts 0:6b3ac9c5a042 296 }
Wayne Roberts 0:6b3ac9c5a042 297
Wayne Roberts 3:eb174e10afbb 298 #define RECEIVE_DELAY2_us 2000000
Wayne Roberts 3:eb174e10afbb 299 #define JOIN_ACCEPT_DELAY1_us 5000000
Wayne Roberts 3:eb174e10afbb 300 #define JOIN_ACCEPT_DELAY2_us 6000000
Wayne Roberts 3:eb174e10afbb 301 const LoRaMacParams_t LoRaMacParamsDefaults = {
Wayne Roberts 3:eb174e10afbb 302 /* int8_t ChannelsTxPower; */ LORAMAC_DEFAULT_TX_POWER,
Wayne Roberts 3:eb174e10afbb 303 /* int8_t ChannelsDatarate;*/ LORAMAC_DEFAULT_DATARATE,
Wayne Roberts 3:eb174e10afbb 304 /* uint32_t MaxRxWindow_us;*/ MAX_RX_WINDOW_us,
Wayne Roberts 3:eb174e10afbb 305 /* uint32_t ReceiveDelay1_us;*/ RECEIVE_DELAY1_us,
Wayne Roberts 3:eb174e10afbb 306 /* uint32_t ReceiveDelay2_us;*/ RECEIVE_DELAY2_us,
Wayne Roberts 3:eb174e10afbb 307 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 3:eb174e10afbb 308 /* uint32_t JoinAcceptDelay1_us;*/ JOIN_ACCEPT_DELAY1_us,
Wayne Roberts 3:eb174e10afbb 309 /* uint32_t JoinAcceptDelay2_us;*/ JOIN_ACCEPT_DELAY2_us,
Wayne Roberts 3:eb174e10afbb 310 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 311 /* uint8_t NbTrans;*/ 1,
Wayne Roberts 3:eb174e10afbb 312 /* uint8_t Rx1DrOffset;*/ 0,
Wayne Roberts 3:eb174e10afbb 313 /* Rx2ChannelParams_t Rx2Channel;*/ RX_WND_2_CHANNEL,
Wayne Roberts 3:eb174e10afbb 314 #if defined( USE_BAND_915 )
Wayne Roberts 3:eb174e10afbb 315 /* uint16_t ChannelsMask[6];*/ { 0xffff, 0xffff, 0xffff, 0xffff, 0x00ff, 0x0000},
Wayne Roberts 3:eb174e10afbb 316 /* uint8_t NbEnabledChannels;*/ 72,
Wayne Roberts 3:eb174e10afbb 317 #elif defined( USE_BAND_915_HYBRID )
Wayne Roberts 3:eb174e10afbb 318 /* uint16_t ChannelsMask[6];*/ { 0x00ff, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000},
Wayne Roberts 3:eb174e10afbb 319 /* uint8_t NbEnabledChannels;*/ 9
Wayne Roberts 3:eb174e10afbb 320 #endif
Wayne Roberts 3:eb174e10afbb 321 };
Wayne Roberts 3:eb174e10afbb 322
Wayne Roberts 0:6b3ac9c5a042 323 void region_mac_init()
Wayne Roberts 0:6b3ac9c5a042 324 {
Wayne Roberts 0:6b3ac9c5a042 325 // 125 kHz channels
Wayne Roberts 0:6b3ac9c5a042 326 for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ )
Wayne Roberts 0:6b3ac9c5a042 327 {
Wayne Roberts 0:6b3ac9c5a042 328 Channels[i].FreqHz = 902.3e6 + i * 200e3;
Wayne Roberts 0:6b3ac9c5a042 329 Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
Wayne Roberts 0:6b3ac9c5a042 330 Channels[i].Band = 0;
Wayne Roberts 0:6b3ac9c5a042 331 }
Wayne Roberts 0:6b3ac9c5a042 332 // 500 kHz channels
Wayne Roberts 0:6b3ac9c5a042 333 for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ )
Wayne Roberts 0:6b3ac9c5a042 334 {
Wayne Roberts 0:6b3ac9c5a042 335 Channels[i].FreqHz = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6;
Wayne Roberts 0:6b3ac9c5a042 336 Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
Wayne Roberts 0:6b3ac9c5a042 337 Channels[i].Band = 0;
Wayne Roberts 0:6b3ac9c5a042 338 }
Wayne Roberts 0:6b3ac9c5a042 339 }
Wayne Roberts 0:6b3ac9c5a042 340
Wayne Roberts 3:eb174e10afbb 341 int8_t
Wayne Roberts 3:eb174e10afbb 342 region_LimitTxPower( int8_t txPower )
Wayne Roberts 3:eb174e10afbb 343 {
Wayne Roberts 3:eb174e10afbb 344 int8_t resultTxPower = txPower;
Wayne Roberts 3:eb174e10afbb 345
Wayne Roberts 3:eb174e10afbb 346 if( ( LoRaMacParams.ChannelsDatarate == DR_4 ) ||
Wayne Roberts 3:eb174e10afbb 347 ( ( LoRaMacParams.ChannelsDatarate >= DR_8 ) && ( LoRaMacParams.ChannelsDatarate <= DR_13 ) ) )
Wayne Roberts 3:eb174e10afbb 348 {// Limit tx power to max 26dBm
Wayne Roberts 3:eb174e10afbb 349 resultTxPower = MAX( txPower, TX_POWER_26_DBM );
Wayne Roberts 3:eb174e10afbb 350 }
Wayne Roberts 3:eb174e10afbb 351 else
Wayne Roberts 3:eb174e10afbb 352 {
Wayne Roberts 3:eb174e10afbb 353 if( CountNbEnabled125kHzChannels( LoRaMacParams.ChannelsMask ) < 50 )
Wayne Roberts 3:eb174e10afbb 354 {// Limit tx power to max 21dBm
Wayne Roberts 3:eb174e10afbb 355 resultTxPower = MAX( txPower, TX_POWER_20_DBM );
Wayne Roberts 3:eb174e10afbb 356 }
Wayne Roberts 3:eb174e10afbb 357 }
Wayne Roberts 3:eb174e10afbb 358 return resultTxPower;
Wayne Roberts 3:eb174e10afbb 359 }
Wayne Roberts 3:eb174e10afbb 360
Wayne Roberts 3:eb174e10afbb 361 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 3:eb174e10afbb 362 int8_t
Wayne Roberts 3:eb174e10afbb 363 region_AlternateDatarate( uint16_t nbTrials )
Wayne Roberts 3:eb174e10afbb 364 {
Wayne Roberts 3:eb174e10afbb 365 if (region_CountNbEnabledChannels() < LoRaMacParamsDefaults.NbEnabledChannels) {
Wayne Roberts 3:eb174e10afbb 366 memcpy(LoRaMacParams.ChannelsMask, LoRaMacParamsDefaults.ChannelsMask, sizeof(LoRaMacParams.ChannelsMask));
Wayne Roberts 3:eb174e10afbb 367 LoRaMacParams.NbEnabledChannels = LoRaMacParamsDefaults.NbEnabledChannels;
Wayne Roberts 3:eb174e10afbb 368 }
Wayne Roberts 3:eb174e10afbb 369
Wayne Roberts 3:eb174e10afbb 370 if( ( nbTrials & 0x01 ) == 0x01 )
Wayne Roberts 3:eb174e10afbb 371 {
Wayne Roberts 3:eb174e10afbb 372 return DR_4;
Wayne Roberts 3:eb174e10afbb 373 }
Wayne Roberts 3:eb174e10afbb 374 else
Wayne Roberts 3:eb174e10afbb 375 {
Wayne Roberts 3:eb174e10afbb 376 return DR_0;
Wayne Roberts 3:eb174e10afbb 377 }
Wayne Roberts 3:eb174e10afbb 378 }
Wayne Roberts 3:eb174e10afbb 379 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 380
Wayne Roberts 0:6b3ac9c5a042 381 void region_session_start(LoRaMacEventInfoStatus_t status) { }
Wayne Roberts 0:6b3ac9c5a042 382
Wayne Roberts 0:6b3ac9c5a042 383 #endif /* USE_BAND_915_HYBRID || USE_BAND_915 */