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:
Fri May 04 11:00:06 2018 -0700
Revision:
7:4b6f960dcca2
Parent:
3:eb174e10afbb
Child:
10:9a7a8b8d0ac2
Add class-C support, and LBT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1 //#include "Commissioning.h"
Wayne Roberts 0:6b3ac9c5a042 2 #include "board.h"
Wayne Roberts 0:6b3ac9c5a042 3 #if defined(USE_BAND_ARIB_8CH)
Wayne Roberts 0:6b3ac9c5a042 4 #include <stdint.h>
Wayne Roberts 0:6b3ac9c5a042 5 #include "LoRaMacPrivate.h"
Wayne Roberts 0:6b3ac9c5a042 6
Wayne Roberts 0:6b3ac9c5a042 7 const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
Wayne Roberts 0:6b3ac9c5a042 8 const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
Wayne Roberts 0:6b3ac9c5a042 9 const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 };
Wayne Roberts 0:6b3ac9c5a042 10
Wayne Roberts 0:6b3ac9c5a042 11 ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] =
Wayne Roberts 0:6b3ac9c5a042 12 {
Wayne Roberts 0:6b3ac9c5a042 13 LC1,
Wayne Roberts 0:6b3ac9c5a042 14 LC2
Wayne Roberts 0:6b3ac9c5a042 15 /* other channels given by mac command */
Wayne Roberts 0:6b3ac9c5a042 16 };
Wayne Roberts 0:6b3ac9c5a042 17
Wayne Roberts 0:6b3ac9c5a042 18 uint32_t region_GetRxBandwidth( int8_t datarate )
Wayne Roberts 0:6b3ac9c5a042 19 {
Wayne Roberts 0:6b3ac9c5a042 20 if( datarate == DR_6 )
Wayne Roberts 0:6b3ac9c5a042 21 {// LoRa 250 kHz
Wayne Roberts 0:6b3ac9c5a042 22 return 1;
Wayne Roberts 0:6b3ac9c5a042 23 }
Wayne Roberts 0:6b3ac9c5a042 24 return 0; // LoRa 125 kHz
Wayne Roberts 0:6b3ac9c5a042 25 }
Wayne Roberts 0:6b3ac9c5a042 26
Wayne Roberts 0:6b3ac9c5a042 27 uint16_t region_GetRxSymbolTimeout( int8_t datarate )
Wayne Roberts 0:6b3ac9c5a042 28 {
Wayne Roberts 0:6b3ac9c5a042 29 if( ( datarate == DR_3 ) || ( datarate == DR_4 ) )
Wayne Roberts 0:6b3ac9c5a042 30 { // DR_4, DR_3
Wayne Roberts 0:6b3ac9c5a042 31 return 8;
Wayne Roberts 0:6b3ac9c5a042 32 }
Wayne Roberts 0:6b3ac9c5a042 33 else if( datarate == DR_5 )
Wayne Roberts 0:6b3ac9c5a042 34 {
Wayne Roberts 0:6b3ac9c5a042 35 return 10;
Wayne Roberts 0:6b3ac9c5a042 36 }
Wayne Roberts 0:6b3ac9c5a042 37 else if( datarate == DR_6 )
Wayne Roberts 0:6b3ac9c5a042 38 {
Wayne Roberts 0:6b3ac9c5a042 39 return 14;
Wayne Roberts 0:6b3ac9c5a042 40 }
Wayne Roberts 0:6b3ac9c5a042 41 return 5; // DR_2, DR_1, DR_0
Wayne Roberts 0:6b3ac9c5a042 42 }
Wayne Roberts 0:6b3ac9c5a042 43
Wayne Roberts 0:6b3ac9c5a042 44 void region_rx1_setup(uint8_t chan)
Wayne Roberts 0:6b3ac9c5a042 45 {
Wayne Roberts 0:6b3ac9c5a042 46 int8_t datarate = LoRaMacParams.ChannelsDatarate - LoRaMacParams.Rx1DrOffset;
Wayne Roberts 0:6b3ac9c5a042 47 if( datarate < 0 )
Wayne Roberts 0:6b3ac9c5a042 48 {
Wayne Roberts 0:6b3ac9c5a042 49 datarate = DR_0;
Wayne Roberts 0:6b3ac9c5a042 50 }
Wayne Roberts 0:6b3ac9c5a042 51
Wayne Roberts 0:6b3ac9c5a042 52 RxWindowSetup(
Wayne Roberts 0:6b3ac9c5a042 53 Channels[chan].FreqHz,
Wayne Roberts 0:6b3ac9c5a042 54 datarate,
Wayne Roberts 0:6b3ac9c5a042 55 region_GetRxBandwidth(datarate),
Wayne Roberts 0:6b3ac9c5a042 56 region_GetRxSymbolTimeout(datarate)
Wayne Roberts 0:6b3ac9c5a042 57 );
Wayne Roberts 0:6b3ac9c5a042 58 }
Wayne Roberts 0:6b3ac9c5a042 59
Wayne Roberts 0:6b3ac9c5a042 60 static bool SetNextChannel(LoRaMacStatus_t* status)
Wayne Roberts 0:6b3ac9c5a042 61 {
Wayne Roberts 0:6b3ac9c5a042 62 uint8_t nbEnabledChannels = 0;
Wayne Roberts 0:6b3ac9c5a042 63 uint8_t enabledChannels[LORA_MAX_NB_CHANNELS];
Wayne Roberts 0:6b3ac9c5a042 64
Wayne Roberts 0:6b3ac9c5a042 65 memset( enabledChannels, 0, LORA_MAX_NB_CHANNELS );
Wayne Roberts 0:6b3ac9c5a042 66
Wayne Roberts 0:6b3ac9c5a042 67 *status = LORAMAC_STATUS_SERVICE_UNKNOWN;
Wayne Roberts 0:6b3ac9c5a042 68 if( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 )
Wayne Roberts 0:6b3ac9c5a042 69 {
Wayne Roberts 0:6b3ac9c5a042 70 // Re-enable default channels, if no channel is enabled
Wayne Roberts 0:6b3ac9c5a042 71 LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) );
Wayne Roberts 0:6b3ac9c5a042 72 }
Wayne Roberts 0:6b3ac9c5a042 73
Wayne Roberts 0:6b3ac9c5a042 74 // Search how many channels are enabled
Wayne Roberts 0:6b3ac9c5a042 75 for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
Wayne Roberts 0:6b3ac9c5a042 76 {
Wayne Roberts 0:6b3ac9c5a042 77 for( uint8_t j = 0; j < 16; j++ )
Wayne Roberts 0:6b3ac9c5a042 78 {
Wayne Roberts 0:6b3ac9c5a042 79 if( ( LoRaMacParams.ChannelsMask[k] & ( 1 << j ) ) != 0 )
Wayne Roberts 0:6b3ac9c5a042 80 {
Wayne Roberts 0:6b3ac9c5a042 81 if( Channels[i + j].FreqHz == 0 )
Wayne Roberts 0:6b3ac9c5a042 82 { // Check if the channel is enabled
Wayne Roberts 0:6b3ac9c5a042 83 continue;
Wayne Roberts 0:6b3ac9c5a042 84 }
Wayne Roberts 0:6b3ac9c5a042 85 #ifdef OVER_THE_AIR_ACTIVATION
Wayne Roberts 0:6b3ac9c5a042 86 if (!flags.IsLoRaMacNetworkJoined)
Wayne Roberts 0:6b3ac9c5a042 87 {
Wayne Roberts 0:6b3ac9c5a042 88 if( ( JOIN_CHANNELS & ( 1 << j ) ) == 0 )
Wayne Roberts 0:6b3ac9c5a042 89 {
Wayne Roberts 0:6b3ac9c5a042 90 continue;
Wayne Roberts 0:6b3ac9c5a042 91 }
Wayne Roberts 0:6b3ac9c5a042 92 }
Wayne Roberts 0:6b3ac9c5a042 93 #endif /* OVER_THE_AIR_ACTIVATION */
Wayne Roberts 0:6b3ac9c5a042 94 if( ( ( Channels[i + j].DrRange.Fields.Min <= LoRaMacParams.ChannelsDatarate ) &&
Wayne Roberts 0:6b3ac9c5a042 95 ( LoRaMacParams.ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false )
Wayne Roberts 0:6b3ac9c5a042 96 { // Check if the current channel selection supports the given datarate
Wayne Roberts 0:6b3ac9c5a042 97 *status = LORAMAC_STATUS_DATARATE_INVALID;
Wayne Roberts 0:6b3ac9c5a042 98 continue;
Wayne Roberts 0:6b3ac9c5a042 99 }
Wayne Roberts 0:6b3ac9c5a042 100 enabledChannels[nbEnabledChannels++] = i + j;
Wayne Roberts 0:6b3ac9c5a042 101 }
Wayne Roberts 0:6b3ac9c5a042 102 }
Wayne Roberts 0:6b3ac9c5a042 103 }
Wayne Roberts 0:6b3ac9c5a042 104
Wayne Roberts 0:6b3ac9c5a042 105 if( nbEnabledChannels > 0 )
Wayne Roberts 0:6b3ac9c5a042 106 {
Wayne Roberts 0:6b3ac9c5a042 107 Channel = enabledChannels[random_at_most(nbEnabledChannels - 1)];
Wayne Roberts 0:6b3ac9c5a042 108 *status = LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 109 return true;
Wayne Roberts 0:6b3ac9c5a042 110 }
Wayne Roberts 0:6b3ac9c5a042 111 else
Wayne Roberts 0:6b3ac9c5a042 112 {
Wayne Roberts 0:6b3ac9c5a042 113 // Datarate not supported by any channel
Wayne Roberts 0:6b3ac9c5a042 114 return false;
Wayne Roberts 0:6b3ac9c5a042 115 }
Wayne Roberts 0:6b3ac9c5a042 116 }
Wayne Roberts 0:6b3ac9c5a042 117
Wayne Roberts 0:6b3ac9c5a042 118
Wayne Roberts 0:6b3ac9c5a042 119 static us_timestamp_t defer_uplink_us;
Wayne Roberts 0:6b3ac9c5a042 120
Wayne Roberts 0:6b3ac9c5a042 121 void region_ScheduleTx( )
Wayne Roberts 0:6b3ac9c5a042 122 {
Wayne Roberts 0:6b3ac9c5a042 123 LoRaMacStatus_t ret;
Wayne Roberts 0:6b3ac9c5a042 124
Wayne Roberts 0:6b3ac9c5a042 125 if (defer_uplink_us > 0) {
Wayne Roberts 7:4b6f960dcca2 126 TxDelayedEvent.attach_us(OnTxDelayedIsr, defer_uplink_us);
Wayne Roberts 0:6b3ac9c5a042 127 defer_uplink_us = 0;
Wayne Roberts 0:6b3ac9c5a042 128 return;
Wayne Roberts 0:6b3ac9c5a042 129 }
Wayne Roberts 0:6b3ac9c5a042 130
Wayne Roberts 7:4b6f960dcca2 131 if (LoRaMacDeviceClass == CLASS_C) {
Wayne Roberts 7:4b6f960dcca2 132 Radio::Standby();
Wayne Roberts 7:4b6f960dcca2 133 }
Wayne Roberts 7:4b6f960dcca2 134
Wayne Roberts 0:6b3ac9c5a042 135 // Select channel
Wayne Roberts 0:6b3ac9c5a042 136 if (!SetNextChannel(&ret))
Wayne Roberts 0:6b3ac9c5a042 137 {
Wayne Roberts 0:6b3ac9c5a042 138 // Set the default datarate
Wayne Roberts 0:6b3ac9c5a042 139 LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
Wayne Roberts 0:6b3ac9c5a042 140 // re-enable default channels
Wayne Roberts 0:6b3ac9c5a042 141 LoRaMacParams.ChannelsMask[0] = LoRaMacParamsDefaults.ChannelsMask[0];
Wayne Roberts 0:6b3ac9c5a042 142 if (!SetNextChannel(&ret))
Wayne Roberts 0:6b3ac9c5a042 143 return;
Wayne Roberts 0:6b3ac9c5a042 144 }
Wayne Roberts 0:6b3ac9c5a042 145
Wayne Roberts 0:6b3ac9c5a042 146 // Schedule transmission of frame
Wayne Roberts 0:6b3ac9c5a042 147 // Try to send now
Wayne Roberts 0:6b3ac9c5a042 148 SendFrameOnChannel( Channel );
Wayne Roberts 0:6b3ac9c5a042 149 }
Wayne Roberts 0:6b3ac9c5a042 150
Wayne Roberts 3:eb174e10afbb 151 #define RECEIVE_DELAY2_us 2000000
Wayne Roberts 3:eb174e10afbb 152 #define JOIN_ACCEPT_DELAY1_us 5000000
Wayne Roberts 3:eb174e10afbb 153 #define JOIN_ACCEPT_DELAY2_us 6000000
Wayne Roberts 3:eb174e10afbb 154 const LoRaMacParams_t LoRaMacParamsDefaults = {
Wayne Roberts 7:4b6f960dcca2 155 /* int8_t ChannelsTxPower */ LORAMAC_DEFAULT_TX_POWER,
Wayne Roberts 7:4b6f960dcca2 156 /* int8_t ChannelsDatarate */ LORAMAC_DEFAULT_DATARATE,
Wayne Roberts 7:4b6f960dcca2 157 /* uint32_t MaxRxWindow_us */ MAX_RX_WINDOW_us,
Wayne Roberts 7:4b6f960dcca2 158 /* uint32_t ReceiveDelay1_us */ RECEIVE_DELAY1_us,
Wayne Roberts 7:4b6f960dcca2 159 /* uint32_t ReceiveDelay2_us */ RECEIVE_DELAY2_us,
Wayne Roberts 3:eb174e10afbb 160 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 7:4b6f960dcca2 161 /* uint32_t JoinAcceptDelay1_us */ JOIN_ACCEPT_DELAY1_us,
Wayne Roberts 7:4b6f960dcca2 162 /* uint32_t JoinAcceptDelay2_us */ JOIN_ACCEPT_DELAY2_us,
Wayne Roberts 3:eb174e10afbb 163 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 7:4b6f960dcca2 164 /* uint8_t NbTrans */ 1,
Wayne Roberts 7:4b6f960dcca2 165 /* uint8_t Rx1DrOffset */ 0,
Wayne Roberts 7:4b6f960dcca2 166 /* Rx2ChannelParams_t Rx2Channel */ RX_WND_2_CHANNEL,
Wayne Roberts 7:4b6f960dcca2 167 /* uint16_t ChannelsMask[6] */ { (LC(1)+LC(2)), 0, 0, 0, 0, 0},/* only boot channels enabled */
Wayne Roberts 7:4b6f960dcca2 168 /* uint8_t NbEnabledChannels */ 2,
Wayne Roberts 7:4b6f960dcca2 169 /* us_timestamp_t MaxListenTime */ 4000000
Wayne Roberts 3:eb174e10afbb 170 };
Wayne Roberts 3:eb174e10afbb 171
Wayne Roberts 0:6b3ac9c5a042 172 void region_mac_init()
Wayne Roberts 0:6b3ac9c5a042 173 {
Wayne Roberts 0:6b3ac9c5a042 174 }
Wayne Roberts 0:6b3ac9c5a042 175
Wayne Roberts 0:6b3ac9c5a042 176 void region_adr_request(adr_t* adr)
Wayne Roberts 0:6b3ac9c5a042 177 {
Wayne Roberts 0:6b3ac9c5a042 178 uint8_t i;
Wayne Roberts 0:6b3ac9c5a042 179
Wayne Roberts 0:6b3ac9c5a042 180 if( ( adr->chMaskCntl == 0 ) && ( adr->chMask == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 181 {
Wayne Roberts 0:6b3ac9c5a042 182 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 183 }
Wayne Roberts 0:6b3ac9c5a042 184 else if( ( ( adr->chMaskCntl >= 1 ) && ( adr->chMaskCntl <= 5 )) ||
Wayne Roberts 0:6b3ac9c5a042 185 ( adr->chMaskCntl >= 7 ) )
Wayne Roberts 0:6b3ac9c5a042 186 {
Wayne Roberts 0:6b3ac9c5a042 187 // RFU
Wayne Roberts 0:6b3ac9c5a042 188 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 189 }
Wayne Roberts 0:6b3ac9c5a042 190 else
Wayne Roberts 0:6b3ac9c5a042 191 {
Wayne Roberts 0:6b3ac9c5a042 192 for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ )
Wayne Roberts 0:6b3ac9c5a042 193 {
Wayne Roberts 0:6b3ac9c5a042 194 if( adr->chMaskCntl == 6 )
Wayne Roberts 0:6b3ac9c5a042 195 {
Wayne Roberts 0:6b3ac9c5a042 196 if( Channels[i].FreqHz != 0 )
Wayne Roberts 0:6b3ac9c5a042 197 {
Wayne Roberts 0:6b3ac9c5a042 198 adr->chMask |= 1 << i;
Wayne Roberts 0:6b3ac9c5a042 199 }
Wayne Roberts 0:6b3ac9c5a042 200 }
Wayne Roberts 0:6b3ac9c5a042 201 else
Wayne Roberts 0:6b3ac9c5a042 202 {
Wayne Roberts 0:6b3ac9c5a042 203 if( ( ( adr->chMask & ( 1 << i ) ) != 0 ) &&
Wayne Roberts 0:6b3ac9c5a042 204 ( Channels[i].FreqHz == 0 ) )
Wayne Roberts 0:6b3ac9c5a042 205 {// Trying to enable an undefined channel
Wayne Roberts 0:6b3ac9c5a042 206 adr->status &= 0xFE; // Channel mask KO
Wayne Roberts 0:6b3ac9c5a042 207 }
Wayne Roberts 0:6b3ac9c5a042 208 }
Wayne Roberts 0:6b3ac9c5a042 209 }
Wayne Roberts 0:6b3ac9c5a042 210 adr->channelsMask[0] = adr->chMask;
Wayne Roberts 0:6b3ac9c5a042 211 MAC_PRINTF("arib set channelsMask:%04x ", adr->channelsMask[0]);
Wayne Roberts 0:6b3ac9c5a042 212 }
Wayne Roberts 0:6b3ac9c5a042 213 }
Wayne Roberts 0:6b3ac9c5a042 214
Wayne Roberts 0:6b3ac9c5a042 215 void region_tx_setup(int8_t txPower, uint8_t pktLen)
Wayne Roberts 0:6b3ac9c5a042 216 {
Wayne Roberts 0:6b3ac9c5a042 217 int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate];
Wayne Roberts 0:6b3ac9c5a042 218
Wayne Roberts 0:6b3ac9c5a042 219 if( LoRaMacParams.ChannelsDatarate == DR_7 )
Wayne Roberts 0:6b3ac9c5a042 220 { // High Speed FSK channel
Wayne Roberts 0:6b3ac9c5a042 221 Radio::SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, false);
Wayne Roberts 0:6b3ac9c5a042 222 //TxTimeOnAir_us = Radio.TimeOnAir_us( MODEM_FSK, LoRaMacBufferPktLen );
Wayne Roberts 0:6b3ac9c5a042 223
Wayne Roberts 0:6b3ac9c5a042 224 }
Wayne Roberts 0:6b3ac9c5a042 225 else if( LoRaMacParams.ChannelsDatarate == DR_6 )
Wayne Roberts 0:6b3ac9c5a042 226 { // High speed LoRa channel
Wayne Roberts 0:6b3ac9c5a042 227 Radio::SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, false);
Wayne Roberts 0:6b3ac9c5a042 228 //TxTimeOnAir_us = Radio.TimeOnAir_us( MODEM_LORA, LoRaMacBufferPktLen );
Wayne Roberts 0:6b3ac9c5a042 229 }
Wayne Roberts 0:6b3ac9c5a042 230 else
Wayne Roberts 0:6b3ac9c5a042 231 { // Normal LoRa channel
Wayne Roberts 0:6b3ac9c5a042 232 Radio::SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, false);
Wayne Roberts 0:6b3ac9c5a042 233 //TxTimeOnAir_us = Radio.TimeOnAir_us( MODEM_LORA, LoRaMacBufferPktLen );
Wayne Roberts 0:6b3ac9c5a042 234 }
Wayne Roberts 0:6b3ac9c5a042 235 }
Wayne Roberts 0:6b3ac9c5a042 236
Wayne Roberts 0:6b3ac9c5a042 237 static bool DisableChannelInMask( uint8_t id, uint16_t* mask )
Wayne Roberts 0:6b3ac9c5a042 238 {
Wayne Roberts 0:6b3ac9c5a042 239 uint8_t index = 0;
Wayne Roberts 0:6b3ac9c5a042 240 index = id / 16;
Wayne Roberts 0:6b3ac9c5a042 241
Wayne Roberts 0:6b3ac9c5a042 242 if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
Wayne Roberts 0:6b3ac9c5a042 243 {
Wayne Roberts 0:6b3ac9c5a042 244 return false;
Wayne Roberts 0:6b3ac9c5a042 245 }
Wayne Roberts 0:6b3ac9c5a042 246
Wayne Roberts 0:6b3ac9c5a042 247 // Deactivate channel
Wayne Roberts 0:6b3ac9c5a042 248 mask[index] &= ~( 1 << ( id % 16 ) );
Wayne Roberts 0:6b3ac9c5a042 249
Wayne Roberts 0:6b3ac9c5a042 250 return true;
Wayne Roberts 0:6b3ac9c5a042 251 }
Wayne Roberts 0:6b3ac9c5a042 252
Wayne Roberts 0:6b3ac9c5a042 253 LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id )
Wayne Roberts 0:6b3ac9c5a042 254 {
Wayne Roberts 0:6b3ac9c5a042 255 /*if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING )
Wayne Roberts 0:6b3ac9c5a042 256 {
Wayne Roberts 0:6b3ac9c5a042 257 if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG )
Wayne Roberts 0:6b3ac9c5a042 258 {
Wayne Roberts 0:6b3ac9c5a042 259 return LORAMAC_STATUS_BUSY;
Wayne Roberts 0:6b3ac9c5a042 260 }
Wayne Roberts 0:6b3ac9c5a042 261 }*/
Wayne Roberts 0:6b3ac9c5a042 262
Wayne Roberts 0:6b3ac9c5a042 263 if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) )
Wayne Roberts 0:6b3ac9c5a042 264 {
Wayne Roberts 0:6b3ac9c5a042 265 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 266 }
Wayne Roberts 0:6b3ac9c5a042 267 else
Wayne Roberts 0:6b3ac9c5a042 268 {
Wayne Roberts 0:6b3ac9c5a042 269 // Remove the channel from the list of channels
Wayne Roberts 0:6b3ac9c5a042 270 Channels[id] = ( ChannelParams_t ){ 0, { 0 }, 0 };
Wayne Roberts 0:6b3ac9c5a042 271
Wayne Roberts 0:6b3ac9c5a042 272 // Disable the channel as it doesn't exist anymore
Wayne Roberts 0:6b3ac9c5a042 273 if( DisableChannelInMask( id, LoRaMacParams.ChannelsMask ) == false )
Wayne Roberts 0:6b3ac9c5a042 274 {
Wayne Roberts 0:6b3ac9c5a042 275 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 276 }
Wayne Roberts 0:6b3ac9c5a042 277 }
Wayne Roberts 0:6b3ac9c5a042 278 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 279 }
Wayne Roberts 0:6b3ac9c5a042 280
Wayne Roberts 0:6b3ac9c5a042 281 static bool ValidateDrRange( DrRange_t drRange, int8_t min, int8_t max )
Wayne Roberts 0:6b3ac9c5a042 282 {
Wayne Roberts 0:6b3ac9c5a042 283 int8_t drMin = drRange.Fields.Min & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 284 int8_t drMax = drRange.Fields.Max & 0x0F;
Wayne Roberts 0:6b3ac9c5a042 285
Wayne Roberts 0:6b3ac9c5a042 286 if( drMin > drMax )
Wayne Roberts 0:6b3ac9c5a042 287 {
Wayne Roberts 0:6b3ac9c5a042 288 return false;
Wayne Roberts 0:6b3ac9c5a042 289 }
Wayne Roberts 0:6b3ac9c5a042 290 if( ValueInRange( drMin, min, max ) == false )
Wayne Roberts 0:6b3ac9c5a042 291 {
Wayne Roberts 0:6b3ac9c5a042 292 return false;
Wayne Roberts 0:6b3ac9c5a042 293 }
Wayne Roberts 0:6b3ac9c5a042 294 if( ValueInRange( drMax, min, max ) == false )
Wayne Roberts 0:6b3ac9c5a042 295 {
Wayne Roberts 0:6b3ac9c5a042 296 return false;
Wayne Roberts 0:6b3ac9c5a042 297 }
Wayne Roberts 0:6b3ac9c5a042 298 return true;
Wayne Roberts 0:6b3ac9c5a042 299 }
Wayne Roberts 0:6b3ac9c5a042 300
Wayne Roberts 0:6b3ac9c5a042 301 LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params )
Wayne Roberts 0:6b3ac9c5a042 302 {
Wayne Roberts 0:6b3ac9c5a042 303 bool datarateInvalid = false;
Wayne Roberts 0:6b3ac9c5a042 304 bool frequencyInvalid = false;
Wayne Roberts 0:6b3ac9c5a042 305 uint8_t band = 0;
Wayne Roberts 0:6b3ac9c5a042 306
Wayne Roberts 0:6b3ac9c5a042 307 //MAC_PRINTF("channelAdd(%u,%u)\r\n", id, params.Frequency);
Wayne Roberts 0:6b3ac9c5a042 308 // The id must not exceed LORA_MAX_NB_CHANNELS
Wayne Roberts 0:6b3ac9c5a042 309 if( id >= LORA_MAX_NB_CHANNELS )
Wayne Roberts 0:6b3ac9c5a042 310 {
Wayne Roberts 0:6b3ac9c5a042 311 return LORAMAC_STATUS_PARAMETER_INVALID;
Wayne Roberts 0:6b3ac9c5a042 312 }
Wayne Roberts 0:6b3ac9c5a042 313
Wayne Roberts 0:6b3ac9c5a042 314 // Validate the datarate
Wayne Roberts 0:6b3ac9c5a042 315 if( ValidateDrRange( params.DrRange, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false )
Wayne Roberts 0:6b3ac9c5a042 316 {
Wayne Roberts 0:6b3ac9c5a042 317 datarateInvalid = true;
Wayne Roberts 0:6b3ac9c5a042 318 }
Wayne Roberts 0:6b3ac9c5a042 319
Wayne Roberts 0:6b3ac9c5a042 320 // Validate the frequency
Wayne Roberts 0:6b3ac9c5a042 321 if( ( Radio::CheckRfFrequency( params.FreqHz ) == true ) && ( params.FreqHz > 0 ) && ( frequencyInvalid == false ) )
Wayne Roberts 0:6b3ac9c5a042 322 {
Wayne Roberts 0:6b3ac9c5a042 323 frequencyInvalid = false;
Wayne Roberts 0:6b3ac9c5a042 324 }
Wayne Roberts 0:6b3ac9c5a042 325 else
Wayne Roberts 0:6b3ac9c5a042 326 {
Wayne Roberts 0:6b3ac9c5a042 327 frequencyInvalid = true;
Wayne Roberts 0:6b3ac9c5a042 328 }
Wayne Roberts 0:6b3ac9c5a042 329
Wayne Roberts 0:6b3ac9c5a042 330 if( ( datarateInvalid == true ) && ( frequencyInvalid == true ) )
Wayne Roberts 0:6b3ac9c5a042 331 {
Wayne Roberts 0:6b3ac9c5a042 332 return LORAMAC_STATUS_FREQ_AND_DR_INVALID;
Wayne Roberts 0:6b3ac9c5a042 333 }
Wayne Roberts 0:6b3ac9c5a042 334 if( datarateInvalid == true )
Wayne Roberts 0:6b3ac9c5a042 335 {
Wayne Roberts 0:6b3ac9c5a042 336 return LORAMAC_STATUS_DATARATE_INVALID;
Wayne Roberts 0:6b3ac9c5a042 337 }
Wayne Roberts 0:6b3ac9c5a042 338 if( frequencyInvalid == true )
Wayne Roberts 0:6b3ac9c5a042 339 {
Wayne Roberts 0:6b3ac9c5a042 340 return LORAMAC_STATUS_FREQUENCY_INVALID;
Wayne Roberts 0:6b3ac9c5a042 341 }
Wayne Roberts 0:6b3ac9c5a042 342
Wayne Roberts 0:6b3ac9c5a042 343 // Every parameter is valid, activate the channel
Wayne Roberts 0:6b3ac9c5a042 344 Channels[id] = params;
Wayne Roberts 0:6b3ac9c5a042 345 Channels[id].Band = band;
Wayne Roberts 0:6b3ac9c5a042 346 LoRaMacParams.ChannelsMask[0] |= ( 1 << id );
Wayne Roberts 0:6b3ac9c5a042 347
Wayne Roberts 0:6b3ac9c5a042 348 return LORAMAC_STATUS_OK;
Wayne Roberts 0:6b3ac9c5a042 349 }
Wayne Roberts 0:6b3ac9c5a042 350
Wayne Roberts 0:6b3ac9c5a042 351 void
Wayne Roberts 0:6b3ac9c5a042 352 region_session_start(LoRaMacEventInfoStatus_t status)
Wayne Roberts 0:6b3ac9c5a042 353 {
Wayne Roberts 0:6b3ac9c5a042 354 McpsReq_t mcpsReq;
Wayne Roberts 0:6b3ac9c5a042 355
Wayne Roberts 0:6b3ac9c5a042 356 if (LoRaMacParams.ChannelsMask[0] == 0x003c) {
Wayne Roberts 0:6b3ac9c5a042 357 return;
Wayne Roberts 0:6b3ac9c5a042 358 }
Wayne Roberts 0:6b3ac9c5a042 359 /* send mac commands until desired channel mask */
Wayne Roberts 0:6b3ac9c5a042 360
Wayne Roberts 0:6b3ac9c5a042 361 mcpsReq.Type = MCPS_UNCONFIRMED;
Wayne Roberts 0:6b3ac9c5a042 362 mcpsReq.Req.fPort = 1;
Wayne Roberts 0:6b3ac9c5a042 363 mcpsReq.Req.fBuffer = NULL;
Wayne Roberts 0:6b3ac9c5a042 364 mcpsReq.Req.fBufferSize = 0;
Wayne Roberts 0:6b3ac9c5a042 365 mcpsReq.Req.Datarate = DR_3;
Wayne Roberts 0:6b3ac9c5a042 366
Wayne Roberts 0:6b3ac9c5a042 367 defer_uplink_us = 2000000 + random_at_most(2000000);
Wayne Roberts 0:6b3ac9c5a042 368 LoRaMacMcpsRequest( &mcpsReq );
Wayne Roberts 0:6b3ac9c5a042 369 }
Wayne Roberts 0:6b3ac9c5a042 370
Wayne Roberts 3:eb174e10afbb 371 int8_t region_LimitTxPower( int8_t txPower )
Wayne Roberts 3:eb174e10afbb 372 {
Wayne Roberts 3:eb174e10afbb 373 return txPower;
Wayne Roberts 3:eb174e10afbb 374 }
Wayne Roberts 3:eb174e10afbb 375
Wayne Roberts 3:eb174e10afbb 376 uint8_t region_CountNbEnabledChannels()
Wayne Roberts 3:eb174e10afbb 377 {
Wayne Roberts 3:eb174e10afbb 378 return CountBits(LoRaMacParams.ChannelsMask[4], 16);
Wayne Roberts 3:eb174e10afbb 379 }
Wayne Roberts 3:eb174e10afbb 380
Wayne Roberts 3:eb174e10afbb 381 #ifdef LORAWAN_JOIN_EUI
Wayne Roberts 3:eb174e10afbb 382 int8_t
Wayne Roberts 3:eb174e10afbb 383 region_AlternateDatarate( uint16_t nbTrials )
Wayne Roberts 3:eb174e10afbb 384 {
Wayne Roberts 3:eb174e10afbb 385 if( ( nbTrials % 48 ) == 0 )
Wayne Roberts 3:eb174e10afbb 386 {
Wayne Roberts 3:eb174e10afbb 387 return DR_0;
Wayne Roberts 3:eb174e10afbb 388 }
Wayne Roberts 3:eb174e10afbb 389 else if( ( nbTrials % 32 ) == 0 )
Wayne Roberts 3:eb174e10afbb 390 {
Wayne Roberts 3:eb174e10afbb 391 return DR_1;
Wayne Roberts 3:eb174e10afbb 392 }
Wayne Roberts 3:eb174e10afbb 393 else if( ( nbTrials % 24 ) == 0 )
Wayne Roberts 3:eb174e10afbb 394 {
Wayne Roberts 3:eb174e10afbb 395 return DR_2;
Wayne Roberts 3:eb174e10afbb 396 }
Wayne Roberts 3:eb174e10afbb 397 else if( ( nbTrials % 16 ) == 0 )
Wayne Roberts 3:eb174e10afbb 398 {
Wayne Roberts 3:eb174e10afbb 399 return DR_3;
Wayne Roberts 3:eb174e10afbb 400 }
Wayne Roberts 3:eb174e10afbb 401 else if( ( nbTrials % 8 ) == 0 )
Wayne Roberts 3:eb174e10afbb 402 {
Wayne Roberts 3:eb174e10afbb 403 return DR_4;
Wayne Roberts 3:eb174e10afbb 404 }
Wayne Roberts 3:eb174e10afbb 405 else
Wayne Roberts 3:eb174e10afbb 406 {
Wayne Roberts 3:eb174e10afbb 407 return DR_5;
Wayne Roberts 3:eb174e10afbb 408 }
Wayne Roberts 3:eb174e10afbb 409 }
Wayne Roberts 3:eb174e10afbb 410 #endif /* LORAWAN_JOIN_EUI */
Wayne Roberts 3:eb174e10afbb 411
Wayne Roberts 0:6b3ac9c5a042 412 #endif /* USE_BAND_ARIB_8CH */
Wayne Roberts 0:6b3ac9c5a042 413