Demonstration of Class-A LoRaWAN device using NAMote-72

Dependencies:   LoRaWAN-lib mbed lib_mpl3115a2 lib_mma8451q lib_gps SX1272Lib

Dependents:   LoRaWAN-NAMote72-BVS-confirmed-tester-0-7v1_copy

LoRaWAN-NAMote72 Application Demo is a Class-A device example project using LoRaWAN-lib and SX1272Lib libraries.

This project is compliant with LoRaWAN V1.0.1 specification.

Comissioning.h (LoRaWAN Network Configuration)

The end-device can be activated in one of the two ways:

Over the Air (OTA) activation can be enabled as shown in the figure below. /media/uploads/ubhat/ota_enable.png

The end-device must be configured with the following parameters:

  • LORAWAN_DEVICE_EUI (8 Bytes) : Fist 3 Bytes is the Organizationally Unique Identifier (OUI) followed by 5 bytes of unique ID. If not defined by user, then the firmware automatically assigns one to the end-device
  • LORAWAN_APPLICATION_EUI (8 Bytes)
  • LORAWAN_APPLICATION_KEY (or DEVKEY) (16 Bytes)

/media/uploads/ubhat/ota_eui.png

Activation by Personalization (ABP) can be enabled as shown in the figure below. /media/uploads/ubhat/abp_enable.png

The end-device must be configured with the following parameters:

  • LORAWAN_DEVICE_ADDRESS (4 Bytes) : If not defined by user, then the firmware automatically assigns one to the end-device
  • LORAWAN_NWKSKEY (16 Bytes)
  • LORAWAN_APPSKEY (16 Bytes)

/media/uploads/ubhat/abp_key.png

Config.h (LoRaWAN Communication Parameters)

  • Mode of Operation : Hybrid If the end-device needs to be configured to operate over 8-channels, then Hybrid Mode needs to be enabled /media/uploads/ubhat/hybridenable.png
  • Mode of Operation : Frequency Hop If the end-device needs to be configured to operate over 64-channels, then Hybrid Mode needs to be disabled
  • Delay between successive JOIN REQUESTs : The delay between successive Join Requests (until the end-device joins the network) can be configured using the parameter OVER_THE_AIR_ACTIVATION_DUTYCYCLE
  • Inter-Frame Delay : One can change the delay between each frame transmission using APP_TX_DUTYCYCLE It is advisable that APP_TX_DUTYCYCLE is greater than or equal to 3sec.
  • Data Rate : The data rate can be configured as per LoRaWAN specification using the paramter LORAWAN_DEFAULT_DATARATE. The range of values are DR_0, DR_1, DR_2, DR_3 and DR_4
  • Confirmed/Unconfirmed Messages : The uplink message or payload can be chosen to be confirmed or unconfirmed using the parameter LORAWAN_CONFIRMED_MSG_ON. When set to 1, the transmitted messages need to be confirmed with an ACK by the network server in the subsequent RX window. When set to 0, no ACK is requested.
  • ADR ON/OFF : The ADR can be enabled or disabled using the parameter LORAWAN_ADR_ON. When set to 1, ADR is enabled and disabled when set to 0.
  • Application Port : The application port can be set using parameter LORAWAN_APP_PORT.
  • Payload Length : The lenght of the payload (in bytes) to be transmitted can be configured using LORAWAN_APP_DATA_SIZE
  • Transmit Power : The transmit power can be configured using LORAWAN_TX_POWER (LoRaMAC verifies if the set power is compliant with the LoRaWAN spec and FCC guidelines)

/media/uploads/ubhat/loraconfig.png

Main.cpp (Device State Machine)

The end-device state machine is defined.

  • Initial State : Device is initialized.
  • Join State : For OTA, Join Request is transmitted to the network until Join Accept is received by the end-device. Join event function is called that sets Red LED ON.
  • Send State : Transmit payload frame is prepared. Tx event is called that blinks the Red LED indicating uplink transmission.
  • Cycle State : Next packet transmission is scheduled

LoRaEventProc.cpp (Events and On-board Application)

Define events during Join, Tx & Rx. Prepare TX packet by appending with appropriate application data.

/media/uploads/ubhat/lora_events.png

  • PrepareLoRaFrame(uint8_t port ) : Prepare LoRa payload frame with on-board application data such as GPS, Temperature, Battery, etc. LoRa.ApplicationCall(AppType ) calls application AppType defined in LoRaApp.cpp. AppType is defined in LoRaApp.h

/media/uploads/ubhat/lora_app.png

LoRaApp.cpp

User-defined applications such as GPS, Temp, Accelerometer, LED indications etc. Event based actions such as LED blink on Tx, LED toggle on downlink etc /media/uploads/ubhat/apptype.png

LoRaDeviceStateProc.cpp

Process function calls corresponding to different Device states /media/uploads/ubhat/device_state.png

LoRaMacLayerService.cpp

Define MAC Layer Services: MLME & MCPS

Serial Terminal Display

By using a serial port connection using applications such as teraterm or putty, one can view the status of the End-Device. Once the End-Device Joins the network, transmission parameters such as payload data, application port, message type etc. are displayed on the terminal.

/media/uploads/ubhat/serial.png

Default Application Payload

This application defaults to sending uplink data to logical port 5. The application payload consists of: /media/uploads/jknapp_smtc/payload.png

Sample Application Payload Calculation for Longitude/Latitude

Payload => 00 19 F6 352BBA A94C20 FFFF

Temperature Calculation

19H => 2510

Temp = 25/2 = 12.5 oC

Battery Level

FFH => 100 %

F6H => 96.5 %

Longitude Calculation

longitude = A94C20H => 1109507210

longitudinal coordinate = -360 + (longitude10 x 180/(223))

longitudinal coordinate = -121.93

Latitude Calculation

latitude = 352BBAH = 348460210

latitude coordinate = (latitude10 x 90/(223-1))

latitude coordinate = 37.39

Committer:
ubhat
Date:
Tue May 17 00:21:55 2016 +0000
Revision:
0:69f2e28d12c1
Child:
18:18408c3c2d0c
Project for LoRa Bootcamp

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ubhat 0:69f2e28d12c1 1 /*
ubhat 0:69f2e28d12c1 2 / _____) _ | |
ubhat 0:69f2e28d12c1 3 ( (____ _____ ____ _| |_ _____ ____| |__
ubhat 0:69f2e28d12c1 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
ubhat 0:69f2e28d12c1 5 _____) ) ____| | | || |_| ____( (___| | | |
ubhat 0:69f2e28d12c1 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
ubhat 0:69f2e28d12c1 7 (C)2015 Semtech
ubhat 0:69f2e28d12c1 8
ubhat 0:69f2e28d12c1 9 Description: Process function calls from various Device states
ubhat 0:69f2e28d12c1 10
ubhat 0:69f2e28d12c1 11 License: Revised BSD License, see LICENSE.TXT file include in the project
ubhat 0:69f2e28d12c1 12
ubhat 0:69f2e28d12c1 13 Maintainer: Uttam Bhat
ubhat 0:69f2e28d12c1 14 */
ubhat 0:69f2e28d12c1 15
ubhat 0:69f2e28d12c1 16 #include "LoRaDeviceStateProc.h"
ubhat 0:69f2e28d12c1 17 #include "LoRaMacLayerService.h"
ubhat 0:69f2e28d12c1 18
ubhat 0:69f2e28d12c1 19 eDevicState DeviceState;
ubhat 0:69f2e28d12c1 20
ubhat 0:69f2e28d12c1 21 sLoRaMacUplinkStatus LoRaMacUplinkStatus;
ubhat 0:69f2e28d12c1 22
ubhat 0:69f2e28d12c1 23 sLoRaMacDownlinkStatus LoRaMacDownlinkStatus;
ubhat 0:69f2e28d12c1 24
ubhat 0:69f2e28d12c1 25 LoRaMacPrimitives_t LoRaPrimitives;
ubhat 0:69f2e28d12c1 26
ubhat 0:69f2e28d12c1 27 LoRaMacCallback_t LoRaCallbacks;
ubhat 0:69f2e28d12c1 28
ubhat 0:69f2e28d12c1 29 MibRequestConfirm_t LoRaMibReq;
ubhat 0:69f2e28d12c1 30
ubhat 0:69f2e28d12c1 31 MlmeReq_t mlmeReq;
ubhat 0:69f2e28d12c1 32
ubhat 0:69f2e28d12c1 33
ubhat 0:69f2e28d12c1 34 /*!
ubhat 0:69f2e28d12c1 35 * \brief Function executed on TxNextPacket Timeout event
ubhat 0:69f2e28d12c1 36 */
ubhat 0:69f2e28d12c1 37 static void OnTxNextPacketTimerEvent( void )
ubhat 0:69f2e28d12c1 38 {
ubhat 0:69f2e28d12c1 39 MibRequestConfirm_t mibReq;
ubhat 0:69f2e28d12c1 40 LoRaMacStatus_t status;
ubhat 0:69f2e28d12c1 41
ubhat 0:69f2e28d12c1 42 TimerStop( &TxNextPacketTimer );
ubhat 0:69f2e28d12c1 43
ubhat 0:69f2e28d12c1 44 mibReq.Type = MIB_NETWORK_JOINED;
ubhat 0:69f2e28d12c1 45 status = LoRaMacMibGetRequestConfirm( &mibReq );
ubhat 0:69f2e28d12c1 46
ubhat 0:69f2e28d12c1 47 if( status == LORAMAC_STATUS_OK )
ubhat 0:69f2e28d12c1 48 {
ubhat 0:69f2e28d12c1 49 if( mibReq.Param.IsNetworkJoined == true )
ubhat 0:69f2e28d12c1 50 {
ubhat 0:69f2e28d12c1 51 DeviceState = DEVICE_STATE_SEND;
ubhat 0:69f2e28d12c1 52 }
ubhat 0:69f2e28d12c1 53 else
ubhat 0:69f2e28d12c1 54 {
ubhat 0:69f2e28d12c1 55 DeviceState = DEVICE_STATE_JOIN;
ubhat 0:69f2e28d12c1 56 }
ubhat 0:69f2e28d12c1 57 NextTx = true;
ubhat 0:69f2e28d12c1 58 }
ubhat 0:69f2e28d12c1 59 }
ubhat 0:69f2e28d12c1 60
ubhat 0:69f2e28d12c1 61 void DeviceInit( void )
ubhat 0:69f2e28d12c1 62 {
ubhat 0:69f2e28d12c1 63 LoRaPrimitives.MacMcpsConfirm = McpsConfirm;
ubhat 0:69f2e28d12c1 64 LoRaPrimitives.MacMcpsIndication = McpsIndication;
ubhat 0:69f2e28d12c1 65 LoRaPrimitives.MacMlmeConfirm = MlmeConfirm;
ubhat 0:69f2e28d12c1 66 LoRaCallbacks.GetBatteryLevel = BoardGetBatteryLevel;
ubhat 0:69f2e28d12c1 67 LoRaMacInitialization( &LoRaPrimitives, &LoRaCallbacks );
ubhat 0:69f2e28d12c1 68
ubhat 0:69f2e28d12c1 69 TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
ubhat 0:69f2e28d12c1 70
ubhat 0:69f2e28d12c1 71 LoRaMibReq.Type = MIB_ADR;
ubhat 0:69f2e28d12c1 72 LoRaMibReq.Param.AdrEnable = LORAWAN_ADR_ON;
ubhat 0:69f2e28d12c1 73 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 74
ubhat 0:69f2e28d12c1 75 LoRaMibReq.Type = MIB_PUBLIC_NETWORK;
ubhat 0:69f2e28d12c1 76 LoRaMibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
ubhat 0:69f2e28d12c1 77 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 78
ubhat 0:69f2e28d12c1 79 LoRaMibReq.Type = MIB_CHANNELS_TX_POWER;
ubhat 0:69f2e28d12c1 80 LoRaMibReq.Param.ChannelsTxPower = LORAWAN_TX_POWER;
ubhat 0:69f2e28d12c1 81 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 82
ubhat 0:69f2e28d12c1 83 LoRaMacDownlinkStatus.DownlinkCounter = 0;
ubhat 0:69f2e28d12c1 84 }
ubhat 0:69f2e28d12c1 85
ubhat 0:69f2e28d12c1 86 void DeviceJoinUpdate( void )
ubhat 0:69f2e28d12c1 87 {
ubhat 0:69f2e28d12c1 88 LoRaMibReq.Type = MIB_NETWORK_JOINED;
ubhat 0:69f2e28d12c1 89 LoRaMacMibGetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 90 }
ubhat 0:69f2e28d12c1 91
ubhat 0:69f2e28d12c1 92 void DeviceJoin( void )
ubhat 0:69f2e28d12c1 93 {
ubhat 0:69f2e28d12c1 94 #if( OVER_THE_AIR_ACTIVATION != 0 )
ubhat 0:69f2e28d12c1 95
ubhat 0:69f2e28d12c1 96 mlmeReq.Type = MLME_JOIN;
ubhat 0:69f2e28d12c1 97
ubhat 0:69f2e28d12c1 98 mlmeReq.Req.Join.DevEui = DevEui;
ubhat 0:69f2e28d12c1 99 mlmeReq.Req.Join.AppEui = AppEui;
ubhat 0:69f2e28d12c1 100 mlmeReq.Req.Join.AppKey = AppKey;
ubhat 0:69f2e28d12c1 101
ubhat 0:69f2e28d12c1 102 if( NextTx == true )
ubhat 0:69f2e28d12c1 103 {
ubhat 0:69f2e28d12c1 104 LoRaMacMlmeRequest( &mlmeReq );
ubhat 0:69f2e28d12c1 105 }
ubhat 0:69f2e28d12c1 106
ubhat 0:69f2e28d12c1 107 #else
ubhat 0:69f2e28d12c1 108 // Choose a random device address if not already defined in Config.h
ubhat 0:69f2e28d12c1 109 if( DevAddr == 0 )
ubhat 0:69f2e28d12c1 110 {
ubhat 0:69f2e28d12c1 111 // Random seed initialization
ubhat 0:69f2e28d12c1 112 srand1( BoardGetRandomSeed( ) );
ubhat 0:69f2e28d12c1 113 DevAddr = randr( 0, 0x01FFFFFF );
ubhat 0:69f2e28d12c1 114 }
ubhat 0:69f2e28d12c1 115
ubhat 0:69f2e28d12c1 116 LoRaMibReq.Type = MIB_NET_ID;
ubhat 0:69f2e28d12c1 117 LoRaMibReq.Param.NetID = LORAWAN_NETWORK_ID;
ubhat 0:69f2e28d12c1 118 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 119
ubhat 0:69f2e28d12c1 120 LoRaMibReq.Type = MIB_DEV_ADDR;
ubhat 0:69f2e28d12c1 121 LoRaMibReq.Param.DevAddr = DevAddr;
ubhat 0:69f2e28d12c1 122 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 123
ubhat 0:69f2e28d12c1 124 LoRaMibReq.Type = MIB_NWK_SKEY;
ubhat 0:69f2e28d12c1 125 LoRaMibReq.Param.NwkSKey = NwkSKey;
ubhat 0:69f2e28d12c1 126 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 127
ubhat 0:69f2e28d12c1 128 LoRaMibReq.Type = MIB_APP_SKEY;
ubhat 0:69f2e28d12c1 129 LoRaMibReq.Param.AppSKey = AppSKey;
ubhat 0:69f2e28d12c1 130 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 131
ubhat 0:69f2e28d12c1 132 LoRaMibReq.Type = MIB_NETWORK_JOINED;
ubhat 0:69f2e28d12c1 133 LoRaMibReq.Param.IsNetworkJoined = true;
ubhat 0:69f2e28d12c1 134 LoRaMacMibSetRequestConfirm( &LoRaMibReq );
ubhat 0:69f2e28d12c1 135
ubhat 0:69f2e28d12c1 136 #endif
ubhat 0:69f2e28d12c1 137 }
ubhat 0:69f2e28d12c1 138
ubhat 0:69f2e28d12c1 139 /*!
ubhat 0:69f2e28d12c1 140 * \brief Prepares the payload of the frame
ubhat 0:69f2e28d12c1 141 */
ubhat 0:69f2e28d12c1 142 void PrepareTxFrame( uint8_t port )
ubhat 0:69f2e28d12c1 143 {
ubhat 0:69f2e28d12c1 144 MibRequestConfirm_t mibReq;
ubhat 0:69f2e28d12c1 145
ubhat 0:69f2e28d12c1 146 if( BoardGetBatteryVoltage( ) < LOW_BAT_THRESHOLD )
ubhat 0:69f2e28d12c1 147 {
ubhat 0:69f2e28d12c1 148 mibReq.Type = MIB_CHANNELS_TX_POWER;
ubhat 0:69f2e28d12c1 149 LoRaMacMibGetRequestConfirm( &mibReq );
ubhat 0:69f2e28d12c1 150 // TX_POWER_30_DBM = 0, TX_POWER_28_DBM = 1, ..., TX_POWER_20_DBM = 5, ..., TX_POWER_10_DBM = 10
ubhat 0:69f2e28d12c1 151 // The if condition is then "less than" to check if the power is greater than 20 dBm
ubhat 0:69f2e28d12c1 152 if( mibReq.Param.ChannelsTxPower < TX_POWER_20_DBM )
ubhat 0:69f2e28d12c1 153 {
ubhat 0:69f2e28d12c1 154 mibReq.Param.ChannelsTxPower = TX_POWER_20_DBM;
ubhat 0:69f2e28d12c1 155 LoRaMacMibSetRequestConfirm( &mibReq );
ubhat 0:69f2e28d12c1 156 }
ubhat 0:69f2e28d12c1 157 }
ubhat 0:69f2e28d12c1 158
ubhat 0:69f2e28d12c1 159 if( port == 224 )
ubhat 0:69f2e28d12c1 160 {
ubhat 0:69f2e28d12c1 161 RunComplianceTest( );
ubhat 0:69f2e28d12c1 162 }
ubhat 0:69f2e28d12c1 163 else
ubhat 0:69f2e28d12c1 164 {
ubhat 0:69f2e28d12c1 165 PrepareLoRaFrame( port );
ubhat 0:69f2e28d12c1 166 }
ubhat 0:69f2e28d12c1 167 }
ubhat 0:69f2e28d12c1 168
ubhat 0:69f2e28d12c1 169 /*!
ubhat 0:69f2e28d12c1 170 * \brief Prepares the payload of the frame
ubhat 0:69f2e28d12c1 171 *
ubhat 0:69f2e28d12c1 172 * \retval [0: frame could be send, 1: error]
ubhat 0:69f2e28d12c1 173 */
ubhat 0:69f2e28d12c1 174 bool SendFrame( void )
ubhat 0:69f2e28d12c1 175 {
ubhat 0:69f2e28d12c1 176 McpsReq_t mcpsReq;
ubhat 0:69f2e28d12c1 177 LoRaMacTxInfo_t txInfo;
ubhat 0:69f2e28d12c1 178
ubhat 0:69f2e28d12c1 179 if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK )
ubhat 0:69f2e28d12c1 180 {
ubhat 0:69f2e28d12c1 181 // Send empty frame in order to flush MAC commands
ubhat 0:69f2e28d12c1 182 mcpsReq.Type = MCPS_UNCONFIRMED;
ubhat 0:69f2e28d12c1 183 mcpsReq.Req.Unconfirmed.fBuffer = NULL;
ubhat 0:69f2e28d12c1 184 mcpsReq.Req.Unconfirmed.fBufferSize = 0;
ubhat 0:69f2e28d12c1 185 mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
ubhat 0:69f2e28d12c1 186
ubhat 0:69f2e28d12c1 187 LoRaMacUplinkStatus.Acked = false;
ubhat 0:69f2e28d12c1 188 LoRaMacUplinkStatus.Port = 0;
ubhat 0:69f2e28d12c1 189 LoRaMacUplinkStatus.Buffer = NULL;
ubhat 0:69f2e28d12c1 190 LoRaMacUplinkStatus.BufferSize = 0;
ubhat 0:69f2e28d12c1 191 }
ubhat 0:69f2e28d12c1 192 else
ubhat 0:69f2e28d12c1 193 {
ubhat 0:69f2e28d12c1 194 LoRaMacUplinkStatus.Acked = false;
ubhat 0:69f2e28d12c1 195 LoRaMacUplinkStatus.Port = AppPort;
ubhat 0:69f2e28d12c1 196 LoRaMacUplinkStatus.Buffer = AppData;
ubhat 0:69f2e28d12c1 197 LoRaMacUplinkStatus.BufferSize = AppDataSize;
ubhat 0:69f2e28d12c1 198
ubhat 0:69f2e28d12c1 199 if( ( IsTxConfirmed == false ) || ( LoRaMacUplinkStatus.UplinkCounter == 0 ) )
ubhat 0:69f2e28d12c1 200 {
ubhat 0:69f2e28d12c1 201 mcpsReq.Type = MCPS_UNCONFIRMED;
ubhat 0:69f2e28d12c1 202 mcpsReq.Req.Unconfirmed.fPort = AppPort;
ubhat 0:69f2e28d12c1 203 mcpsReq.Req.Unconfirmed.fBuffer = AppData;
ubhat 0:69f2e28d12c1 204 mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
ubhat 0:69f2e28d12c1 205 mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
ubhat 0:69f2e28d12c1 206 }
ubhat 0:69f2e28d12c1 207 else
ubhat 0:69f2e28d12c1 208 {
ubhat 0:69f2e28d12c1 209 mcpsReq.Type = MCPS_CONFIRMED;
ubhat 0:69f2e28d12c1 210 mcpsReq.Req.Confirmed.fPort = AppPort;
ubhat 0:69f2e28d12c1 211 mcpsReq.Req.Confirmed.fBuffer = AppData;
ubhat 0:69f2e28d12c1 212 mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
ubhat 0:69f2e28d12c1 213 mcpsReq.Req.Confirmed.NbTrials = 8;
ubhat 0:69f2e28d12c1 214 mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
ubhat 0:69f2e28d12c1 215 }
ubhat 0:69f2e28d12c1 216 }
ubhat 0:69f2e28d12c1 217
ubhat 0:69f2e28d12c1 218 LoRaMacUplinkStatus.Type = mcpsReq.Type;
ubhat 0:69f2e28d12c1 219
ubhat 0:69f2e28d12c1 220 if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
ubhat 0:69f2e28d12c1 221 {
ubhat 0:69f2e28d12c1 222 return false;
ubhat 0:69f2e28d12c1 223 }
ubhat 0:69f2e28d12c1 224 return true;
ubhat 0:69f2e28d12c1 225 }