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 Jun 11 14:09:16 2018 -0700
Revision:
9:fe8e08792ae9
Parent:
0:6b3ac9c5a042
sx126x: update xfer() calls

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1
Wayne Roberts 0:6b3ac9c5a042 2 #include "board.h"
Wayne Roberts 0:6b3ac9c5a042 3 #include "radio.h"
Wayne Roberts 0:6b3ac9c5a042 4
Wayne Roberts 0:6b3ac9c5a042 5 #define RADIO_RESET PC_2 //NorAm_Mote Reset_sx
Wayne Roberts 0:6b3ac9c5a042 6 #define RADIO_MOSI PB_15 //NorAm_Mote SPI2 Mosi
Wayne Roberts 0:6b3ac9c5a042 7 #define RADIO_MISO PB_14 //NorAm_Mote SPI2 Miso
Wayne Roberts 0:6b3ac9c5a042 8 #define RADIO_SCLK PB_13 //NorAm_Mote SPI2 Clk
Wayne Roberts 0:6b3ac9c5a042 9 #define RADIO_NSS PB_12 //NorAm_Mote SPI2 Nss
Wayne Roberts 0:6b3ac9c5a042 10
Wayne Roberts 0:6b3ac9c5a042 11 #define RADIO_DIO_0 PC_6 //NorAm_Mote DIO0
Wayne Roberts 0:6b3ac9c5a042 12 #define RADIO_DIO_1 PC_10 //NorAm_Mote DIO1
Wayne Roberts 0:6b3ac9c5a042 13 #define RADIO_DIO_2 PC_8 //NorAm_Mote DIO2
Wayne Roberts 0:6b3ac9c5a042 14 #define RADIO_DIO_3 PB_4 //NorAm_Mote DIO3
Wayne Roberts 0:6b3ac9c5a042 15 #define RADIO_DIO_4 PB_5 //NorAm_Mote DIO4
Wayne Roberts 0:6b3ac9c5a042 16 #define RADIO_DIO_5 PB_6 //NorAm_Mote DIO5
Wayne Roberts 0:6b3ac9c5a042 17
Wayne Roberts 0:6b3ac9c5a042 18 #define RFSW1 PC_4 //NorAm_Mote RFSwitch_CNTR_1
Wayne Roberts 0:6b3ac9c5a042 19 #define RFSW2 PC_13 //NorAm_Mote RFSwitch_CNTR_2
Wayne Roberts 0:6b3ac9c5a042 20
Wayne Roberts 0:6b3ac9c5a042 21 // txpow: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Wayne Roberts 0:6b3ac9c5a042 22 const uint8_t PaBTable[20] = { 0, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15 };
Wayne Roberts 0:6b3ac9c5a042 23
Wayne Roberts 0:6b3ac9c5a042 24 // txpow: 20 21 22 23 24 25 26 27 28 29 30
Wayne Roberts 0:6b3ac9c5a042 25 const uint8_t RfoTable[11] = { 1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 9 };
Wayne Roberts 0:6b3ac9c5a042 26
Wayne Roberts 0:6b3ac9c5a042 27 SPI spi(RADIO_MOSI, RADIO_MISO, RADIO_SCLK); // mosi, miso, sclk
Wayne Roberts 0:6b3ac9c5a042 28 // dio0, dio1, nss, spi, rst
Wayne Roberts 0:6b3ac9c5a042 29 SX127x Radio::radio(RADIO_DIO_0, RADIO_DIO_1, RADIO_NSS, spi, RADIO_RESET); // sx1276 arduino shield
Wayne Roberts 0:6b3ac9c5a042 30 SX127x_lora Radio::lora(radio);
Wayne Roberts 0:6b3ac9c5a042 31 SX127x_fsk Radio::fsk(radio);
Wayne Roberts 0:6b3ac9c5a042 32
Wayne Roberts 0:6b3ac9c5a042 33 DigitalOut rfsw1(RFSW1);
Wayne Roberts 0:6b3ac9c5a042 34 DigitalOut rfsw2(RFSW2);
Wayne Roberts 0:6b3ac9c5a042 35
Wayne Roberts 0:6b3ac9c5a042 36 InterruptIn Radio::dio0(RADIO_DIO_0);
Wayne Roberts 0:6b3ac9c5a042 37 InterruptIn Radio::dio1(RADIO_DIO_1);
Wayne Roberts 0:6b3ac9c5a042 38
Wayne Roberts 0:6b3ac9c5a042 39 DigitalOut red(LED1);
Wayne Roberts 0:6b3ac9c5a042 40 DigitalOut yellow(LED3);
Wayne Roberts 0:6b3ac9c5a042 41 #define LED_OFF 1
Wayne Roberts 0:6b3ac9c5a042 42 #define LED_ON 0
Wayne Roberts 0:6b3ac9c5a042 43
Wayne Roberts 0:6b3ac9c5a042 44 void Radio::rfsw_callback()
Wayne Roberts 0:6b3ac9c5a042 45 {
Wayne Roberts 0:6b3ac9c5a042 46 if (radio.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) { // start of transmission
Wayne Roberts 0:6b3ac9c5a042 47 red = LED_ON;
Wayne Roberts 0:6b3ac9c5a042 48 yellow = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 49 if (radio.HF) {
Wayne Roberts 0:6b3ac9c5a042 50 if (radio.RegPaConfig.bits.PaSelect) { // if PA_BOOST
Wayne Roberts 0:6b3ac9c5a042 51 rfsw2 = 0;
Wayne Roberts 0:6b3ac9c5a042 52 rfsw1 = 1;
Wayne Roberts 0:6b3ac9c5a042 53 } else { // RFO to power amp
Wayne Roberts 0:6b3ac9c5a042 54 rfsw2 = 1;
Wayne Roberts 0:6b3ac9c5a042 55 rfsw1 = 0;
Wayne Roberts 0:6b3ac9c5a042 56 }
Wayne Roberts 0:6b3ac9c5a042 57 } else {
Wayne Roberts 0:6b3ac9c5a042 58 // todo: sx1276
Wayne Roberts 0:6b3ac9c5a042 59 }
Wayne Roberts 0:6b3ac9c5a042 60 //hdr_fem_csd = 1; //debug
Wayne Roberts 0:6b3ac9c5a042 61 } else if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE || radio.RegOpMode.bits.Mode == RF_OPMODE_CAD) { // start of reception
Wayne Roberts 0:6b3ac9c5a042 62 red = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 63 yellow = LED_ON;
Wayne Roberts 0:6b3ac9c5a042 64 if (radio.HF) {
Wayne Roberts 0:6b3ac9c5a042 65 rfsw2 = 1;
Wayne Roberts 0:6b3ac9c5a042 66 rfsw1 = 1;
Wayne Roberts 0:6b3ac9c5a042 67 } else {
Wayne Roberts 0:6b3ac9c5a042 68 // todo: sx1276
Wayne Roberts 0:6b3ac9c5a042 69 }
Wayne Roberts 0:6b3ac9c5a042 70 } else { // RF switch shutdown
Wayne Roberts 0:6b3ac9c5a042 71 yellow = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 72 red = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 73 rfsw2 = 0;
Wayne Roberts 0:6b3ac9c5a042 74 rfsw1 = 0;
Wayne Roberts 0:6b3ac9c5a042 75 }
Wayne Roberts 0:6b3ac9c5a042 76 }
Wayne Roberts 0:6b3ac9c5a042 77
Wayne Roberts 0:6b3ac9c5a042 78 void
Wayne Roberts 0:6b3ac9c5a042 79 Radio::set_tx_dbm(int8_t dbm)
Wayne Roberts 0:6b3ac9c5a042 80 {
Wayne Roberts 0:6b3ac9c5a042 81 //int i = dbm;
Wayne Roberts 0:6b3ac9c5a042 82 RegPdsTrim1_t pds_trim;
Wayne Roberts 0:6b3ac9c5a042 83 uint8_t adr;
Wayne Roberts 0:6b3ac9c5a042 84
Wayne Roberts 0:6b3ac9c5a042 85 radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
Wayne Roberts 0:6b3ac9c5a042 86
Wayne Roberts 0:6b3ac9c5a042 87 if (dbm < 20) {
Wayne Roberts 0:6b3ac9c5a042 88 radio.RegPaConfig.bits.PaSelect = 1;
Wayne Roberts 0:6b3ac9c5a042 89 if (dbm < 0)
Wayne Roberts 0:6b3ac9c5a042 90 dbm = 0;
Wayne Roberts 0:6b3ac9c5a042 91 radio.RegPaConfig.bits.OutputPower = PaBTable[dbm];
Wayne Roberts 0:6b3ac9c5a042 92 } else {
Wayne Roberts 0:6b3ac9c5a042 93 radio.RegPaConfig.bits.PaSelect = 0;
Wayne Roberts 0:6b3ac9c5a042 94 if (dbm > 30)
Wayne Roberts 0:6b3ac9c5a042 95 dbm = 30;
Wayne Roberts 0:6b3ac9c5a042 96 radio.RegPaConfig.bits.OutputPower = RfoTable[dbm-20];
Wayne Roberts 0:6b3ac9c5a042 97 }
Wayne Roberts 0:6b3ac9c5a042 98
Wayne Roberts 0:6b3ac9c5a042 99 if (radio.type == SX1276)
Wayne Roberts 0:6b3ac9c5a042 100 adr = REG_PDSTRIM1_SX1276;
Wayne Roberts 0:6b3ac9c5a042 101 else
Wayne Roberts 0:6b3ac9c5a042 102 adr = REG_PDSTRIM1_SX1272;
Wayne Roberts 0:6b3ac9c5a042 103
Wayne Roberts 0:6b3ac9c5a042 104 pds_trim.octet = radio.read_reg(adr);
Wayne Roberts 0:6b3ac9c5a042 105
Wayne Roberts 0:6b3ac9c5a042 106 if (radio.RegPaConfig.bits.PaSelect) {
Wayne Roberts 0:6b3ac9c5a042 107 /* PABOOST used: +2dbm to +17, or +20 */
Wayne Roberts 0:6b3ac9c5a042 108 if (dbm == 20) {
Wayne Roberts 0:6b3ac9c5a042 109 dbm -= 3;
Wayne Roberts 0:6b3ac9c5a042 110 pds_trim.bits.prog_txdac = 7;
Wayne Roberts 0:6b3ac9c5a042 111 radio.write_reg(adr, pds_trim.octet);
Wayne Roberts 0:6b3ac9c5a042 112 ocp(150);
Wayne Roberts 0:6b3ac9c5a042 113 } else if (dbm < 18) {
Wayne Roberts 0:6b3ac9c5a042 114 pds_trim.bits.prog_txdac = 5;
Wayne Roberts 0:6b3ac9c5a042 115 radio.write_reg(adr, pds_trim.octet);
Wayne Roberts 0:6b3ac9c5a042 116 ocp(120);
Wayne Roberts 0:6b3ac9c5a042 117 }
Wayne Roberts 0:6b3ac9c5a042 118 } else
Wayne Roberts 0:6b3ac9c5a042 119 ocp(80);
Wayne Roberts 0:6b3ac9c5a042 120
Wayne Roberts 0:6b3ac9c5a042 121 radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
Wayne Roberts 0:6b3ac9c5a042 122 } // ..set_tx_dbm()
Wayne Roberts 0:6b3ac9c5a042 123
Wayne Roberts 0:6b3ac9c5a042 124 void Radio::boardInit()
Wayne Roberts 0:6b3ac9c5a042 125 {
Wayne Roberts 0:6b3ac9c5a042 126 red = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 127 yellow = LED_OFF;
Wayne Roberts 0:6b3ac9c5a042 128 }
Wayne Roberts 0:6b3ac9c5a042 129