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:
4:e4bfe9183f94
correct ADR_ACK_CNT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 0:6b3ac9c5a042 1 #include "sx127x_lora.h"
Wayne Roberts 0:6b3ac9c5a042 2 #include "sx127x_fsk.h"
Wayne Roberts 0:6b3ac9c5a042 3
Wayne Roberts 0:6b3ac9c5a042 4 #define RADIO_OSC_STARTUP_us 1000 // [ms]
Wayne Roberts 0:6b3ac9c5a042 5 #define RADIO_SLEEP_TO_RX_us 2000 // [ms]
Wayne Roberts 0:6b3ac9c5a042 6 #define RADIO_WAKEUP_TIME_us ( RADIO_OSC_STARTUP_us + RADIO_SLEEP_TO_RX_us )
Wayne Roberts 0:6b3ac9c5a042 7
Wayne Roberts 0:6b3ac9c5a042 8 typedef enum
Wayne Roberts 0:6b3ac9c5a042 9 {
Wayne Roberts 0:6b3ac9c5a042 10 MODEM_FSK = 0,
Wayne Roberts 0:6b3ac9c5a042 11 MODEM_LORA,
Wayne Roberts 0:6b3ac9c5a042 12 } RadioModems_t;
Wayne Roberts 0:6b3ac9c5a042 13
Wayne Roberts 0:6b3ac9c5a042 14 typedef enum
Wayne Roberts 0:6b3ac9c5a042 15 {
Wayne Roberts 0:6b3ac9c5a042 16 RF_IDLE = 0,
Wayne Roberts 0:6b3ac9c5a042 17 RF_RX_RUNNING,
Wayne Roberts 0:6b3ac9c5a042 18 RF_TX_RUNNING,
Wayne Roberts 0:6b3ac9c5a042 19 RF_CAD,
Wayne Roberts 0:6b3ac9c5a042 20 } RadioState_t;
Wayne Roberts 0:6b3ac9c5a042 21
Wayne Roberts 0:6b3ac9c5a042 22 /*!
Wayne Roberts 0:6b3ac9c5a042 23 * \brief Radio driver callback functions
Wayne Roberts 0:6b3ac9c5a042 24 */
Wayne Roberts 0:6b3ac9c5a042 25 typedef struct
Wayne Roberts 0:6b3ac9c5a042 26 {
Wayne Roberts 0:6b3ac9c5a042 27 void (*Dio0_top_half)(us_timestamp_t curTime);
Wayne Roberts 0:6b3ac9c5a042 28 /*!
Wayne Roberts 0:6b3ac9c5a042 29 * \brief Tx Done callback prototype.
Wayne Roberts 0:6b3ac9c5a042 30 */
Wayne Roberts 0:6b3ac9c5a042 31 void ( *TxDone )(us_timestamp_t curTime);
Wayne Roberts 0:6b3ac9c5a042 32 /*!
Wayne Roberts 0:6b3ac9c5a042 33 * \brief Tx Timeout callback prototype.
Wayne Roberts 0:6b3ac9c5a042 34 */
Wayne Roberts 0:6b3ac9c5a042 35 void ( *TxTimeout )( void );
Wayne Roberts 0:6b3ac9c5a042 36 /*!
Wayne Roberts 0:6b3ac9c5a042 37 * \brief Rx Done callback prototype.
Wayne Roberts 0:6b3ac9c5a042 38 *
Wayne Roberts 0:6b3ac9c5a042 39 * \param [IN] payload Received buffer pointer
Wayne Roberts 0:6b3ac9c5a042 40 * \param [IN] size Received buffer size
Wayne Roberts 0:6b3ac9c5a042 41 * \param [IN] rssi RSSI value computed while receiving the frame [dBm]
Wayne Roberts 0:6b3ac9c5a042 42 * \param [IN] snr Raw SNR value given by the radio hardware
Wayne Roberts 0:6b3ac9c5a042 43 * FSK : N/A ( set to 0 )
Wayne Roberts 0:6b3ac9c5a042 44 * LoRa: SNR value in dB
Wayne Roberts 0:6b3ac9c5a042 45 * \param [IN] curTime captured time at RxDone event occurance
Wayne Roberts 0:6b3ac9c5a042 46 */
Wayne Roberts 0:6b3ac9c5a042 47 void ( *RxDone )( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, us_timestamp_t curTime);
Wayne Roberts 0:6b3ac9c5a042 48 /*!
Wayne Roberts 0:6b3ac9c5a042 49 * \brief Rx Timeout callback prototype.
Wayne Roberts 0:6b3ac9c5a042 50 */
Wayne Roberts 0:6b3ac9c5a042 51 void ( *RxTimeout )( void );
Wayne Roberts 0:6b3ac9c5a042 52 /*!
Wayne Roberts 0:6b3ac9c5a042 53 * \brief Rx Error callback prototype.
Wayne Roberts 0:6b3ac9c5a042 54 */
Wayne Roberts 0:6b3ac9c5a042 55 void ( *RxError )( void );
Wayne Roberts 0:6b3ac9c5a042 56 /*!
Wayne Roberts 0:6b3ac9c5a042 57 * \brief FHSS Change Channel callback prototype.
Wayne Roberts 0:6b3ac9c5a042 58 *
Wayne Roberts 0:6b3ac9c5a042 59 * \param [IN] currentChannel Index number of the current channel
Wayne Roberts 0:6b3ac9c5a042 60 */
Wayne Roberts 0:6b3ac9c5a042 61 void ( *FhssChangeChannel )( uint8_t currentChannel );
Wayne Roberts 0:6b3ac9c5a042 62
Wayne Roberts 0:6b3ac9c5a042 63 /*!
Wayne Roberts 0:6b3ac9c5a042 64 * \brief CAD Done callback prototype.
Wayne Roberts 0:6b3ac9c5a042 65 *
Wayne Roberts 0:6b3ac9c5a042 66 * \param [IN] channelDetected Channel Activity detected during the CAD
Wayne Roberts 0:6b3ac9c5a042 67 */
Wayne Roberts 0:6b3ac9c5a042 68 void ( *CadDone ) ( bool channelActivityDetected );
Wayne Roberts 0:6b3ac9c5a042 69 } RadioEvents_t;
Wayne Roberts 0:6b3ac9c5a042 70
Wayne Roberts 0:6b3ac9c5a042 71 class Radio {
Wayne Roberts 0:6b3ac9c5a042 72 public:
Wayne Roberts 0:6b3ac9c5a042 73 static void SetTxContinuousWave(unsigned hz, int8_t txPower, unsigned timeout);
Wayne Roberts 0:6b3ac9c5a042 74 static uint32_t Random(void);
Wayne Roberts 0:6b3ac9c5a042 75 static void SetPublicNetwork(bool);
Wayne Roberts 0:6b3ac9c5a042 76 static void Sleep(void);
Wayne Roberts 0:6b3ac9c5a042 77 //static RadioState_t GetStatus(void);
Wayne Roberts 0:6b3ac9c5a042 78 static void SetChannel(unsigned hz);
Wayne Roberts 0:6b3ac9c5a042 79 static void SetRxMaxPayloadLength(RadioModems_t, uint8_t);
Wayne Roberts 0:6b3ac9c5a042 80 static void Rx(unsigned timeout);
Wayne Roberts 0:6b3ac9c5a042 81 static void Standby(void);
Wayne Roberts 0:6b3ac9c5a042 82 static bool CheckRfFrequency(unsigned hz);
Wayne Roberts 0:6b3ac9c5a042 83 static void Init(const RadioEvents_t*);
Wayne Roberts 0:6b3ac9c5a042 84 static void Send(uint8_t size);
Wayne Roberts 0:6b3ac9c5a042 85 static void PrintStatus(void);
Wayne Roberts 0:6b3ac9c5a042 86 #ifdef DUTY_ENABLE
Wayne Roberts 0:6b3ac9c5a042 87 static us_timestamp_t TimeOnAir(RadioModems_t, uint8_t);
Wayne Roberts 0:6b3ac9c5a042 88 #endif /* DUTY_ENABLE */
Wayne Roberts 0:6b3ac9c5a042 89
Wayne Roberts 0:6b3ac9c5a042 90 static void SetRxConfig(
Wayne Roberts 0:6b3ac9c5a042 91 RadioModems_t modem,
Wayne Roberts 0:6b3ac9c5a042 92 uint32_t bandwidth,
Wayne Roberts 0:6b3ac9c5a042 93 uint32_t datarate,
Wayne Roberts 0:6b3ac9c5a042 94 uint8_t coderate,
Wayne Roberts 0:6b3ac9c5a042 95 uint32_t bandwidthAfc,
Wayne Roberts 0:6b3ac9c5a042 96 uint16_t preambleLen,
Wayne Roberts 0:6b3ac9c5a042 97 uint16_t symbTimeout,
Wayne Roberts 0:6b3ac9c5a042 98 bool fixLen,
Wayne Roberts 0:6b3ac9c5a042 99 uint8_t payloadLen,
Wayne Roberts 0:6b3ac9c5a042 100 bool crcOn,
Wayne Roberts 0:6b3ac9c5a042 101 bool iqInverted
Wayne Roberts 0:6b3ac9c5a042 102 );
Wayne Roberts 0:6b3ac9c5a042 103
Wayne Roberts 0:6b3ac9c5a042 104
Wayne Roberts 0:6b3ac9c5a042 105 static void SetTxConfig(
Wayne Roberts 0:6b3ac9c5a042 106 RadioModems_t modem,
Wayne Roberts 0:6b3ac9c5a042 107 int8_t power,
Wayne Roberts 0:6b3ac9c5a042 108 uint32_t fdev,
Wayne Roberts 0:6b3ac9c5a042 109 uint32_t bandwidth,
Wayne Roberts 0:6b3ac9c5a042 110 uint32_t datarate,
Wayne Roberts 0:6b3ac9c5a042 111 uint8_t coderate,
Wayne Roberts 0:6b3ac9c5a042 112 uint16_t preambleLen,
Wayne Roberts 0:6b3ac9c5a042 113 bool fixLen,
Wayne Roberts 0:6b3ac9c5a042 114 bool crcOn,
Wayne Roberts 0:6b3ac9c5a042 115 bool iqInverted
Wayne Roberts 0:6b3ac9c5a042 116 );
Wayne Roberts 0:6b3ac9c5a042 117
Wayne Roberts 0:6b3ac9c5a042 118 static LowPowerTimer lpt;
Wayne Roberts 0:6b3ac9c5a042 119 static SX127x radio;
Wayne Roberts 0:6b3ac9c5a042 120
Wayne Roberts 0:6b3ac9c5a042 121 private:
Wayne Roberts 0:6b3ac9c5a042 122 static void LoRaConfig(uint32_t bandwidth, uint8_t datarate, uint8_t coderate, uint16_t preambleLen, bool fixLen, bool crcOn);
Wayne Roberts 0:6b3ac9c5a042 123 static void dio0callback(void);
Wayne Roberts 0:6b3ac9c5a042 124 static void dio1callback(void);
Wayne Roberts 0:6b3ac9c5a042 125 static void boardInit(void);
Wayne Roberts 0:6b3ac9c5a042 126 static SX127x_lora lora;
Wayne Roberts 0:6b3ac9c5a042 127 static SX127x_fsk fsk;
Wayne Roberts 0:6b3ac9c5a042 128 static void rfsw_callback(void);
Wayne Roberts 0:6b3ac9c5a042 129 static InterruptIn dio0;
Wayne Roberts 0:6b3ac9c5a042 130 static InterruptIn dio1;
Wayne Roberts 0:6b3ac9c5a042 131 static void set_tx_dbm(int8_t dbm);
Wayne Roberts 0:6b3ac9c5a042 132 static void ocp(uint8_t ma);
Wayne Roberts 0:6b3ac9c5a042 133
Wayne Roberts 0:6b3ac9c5a042 134 };
Wayne Roberts 0:6b3ac9c5a042 135
Wayne Roberts 0:6b3ac9c5a042 136