IBM LoRa MAC in C (LMiC) mbed library port

Dependents:   lora-temperature LoRaWAN-lmic-app_HS LoRaWAN-lmic-app_huynh

LoRa WAN in C for sx1276 shield

Currently version 1.5


LoRaWAN network configuration for end-device

The following three pieces of information uniquely identifies end-device to network to allow over-the-air activation. These are stored in the end-device prior to join procedure.

AppEUI

Uniquely identifies application provider of end-device.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t APPEUI[8]  = { 0x01, 0x00, 0x01, 0x00, 0x00, 0x0C, 0x25, 0x00 };

This is copied into LMIC by os_getArtEui() callback function in application.

DevEUI

End-device ID, unique to each end-node.

Least-significant byte first, 8 bytes, use reverse memcpy() to keep same order as shown on lora server.

example C code

static const u1_t DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x0C, 0x25, 0x00 }; 

This is copied into LMIC by os_getDevEui() callback function in application.

AppKey (aka DevKey)

128-bit (16byte) AES key.

example C code

static const u1_t DEVKEY[16] = { 0xe4, 0x72, 0x71, 0xc5, 0xf5, 0x30, 0xa9, 0x9f, 0xcf, 0xc4, 0x0e, 0xab, 0xea, 0xd7, 0x19, 0x42 };

This is copied into LMIC by os_getDevKey() callback function in application.

Using over-the air activation, the end-device (LMIC) performs a join procedure every time it starts for first time, or has lost session context information. When join procedure has successfully completed, the end-device will have a network session key (NwkSKey) and an application session key (AppSKey), which are used for encryption and message integrity check.


US915 configuration with http://us01-iot.semtech.com/

  • log in to server
  • click on Applications
  • find your application and click it
  • go to configure motes
  • to create a mote, you may enter a new DevEUI
    • you may copy-paste the 16byte application key from an already existing mote, if you desire.
CHNL_HYBRID125KHz500KHz
defined valuechannelschannel
00 to 764
18 to 1565
216 to 2366
324 to 3167
432 to 3968
540 to 4769
648 to 5570
756 to 6371
undef0 to 6364 to 71
Revision:
1:d3b7bde3995c
Parent:
0:62d1edcc13d1
Child:
2:974cafbfb159
Child:
3:519c71d29a06
--- a/lmic.h	Thu Jan 22 12:50:49 2015 +0000
+++ b/lmic.h	Tue Mar 31 13:36:56 2015 +0000
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014 IBM Corporation.
+ * Copyright (c) 2014-2015 IBM Corporation.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,32 +9,39 @@
  *    IBM Zurich Research Lab - initial API, implementation and documentation
  *******************************************************************************/
 
-#define NEW_CHNL 1
+//! @file
+//! @brief LMIC API
 
 #ifndef _lmic_h_
 #define _lmic_h_
 
-#define CFG_DEBUG    1
-#define CFG_eu868    1
-//#define CFG_us915    0
+// MBED compiler options
+#define CFG_eu868                                   1
+//#define CFG_us915                                   0
 
-#define USE_SMTC_RADIO_DRIVER 1
+#define USE_SMTC_RADIO_DRIVER                       1
 
-//#define CFG_sx1272_radio    0
-#define CFG_sx1276_radio    1
+//#define CFG_sx1272_radio                            0
+#define CFG_sx1276_radio                            1
+// End MBED compiler options
 
-#include "mbed.h"
 #include "oslmic.h"
 #include "lorabase.h"
 
-enum { MAX_FRAME_LEN      =  64 };   // Library cap on max frame length
-enum { TXCONF_ATTEMPTS    =   8 };   // transmit attempts for confirmed frames
+// LMIC version
+#define LMIC_VERSION_MAJOR 1
+#define LMIC_VERSION_MINOR 4
+#define LMIC_VERSION_BUILD 1426605786
+
+enum { MAX_FRAME_LEN      =  64 };   //!< Library cap on max frame length
+enum { TXCONF_ATTEMPTS    =   8 };   //!< Transmit attempts for confirmed frames
 enum { MAX_MISSED_BCNS    =  20 };   // threshold for triggering rejoin requests
 enum { MAX_RXSYMS         = 100 };   // stop tracking beacon beyond this
 
-enum { LINK_CHECK_CONT    =   6 };   // continue with this after reported dead link
-enum { LINK_CHECK_DEAD    =  12 };   // after this UP frames and no response from NWK assume link is dead
-enum { LINK_CHECK_INIT    = -12 };   // UP frame count until we inc datarate
+enum { LINK_CHECK_CONT    =   6 ,    // continue with this after reported dead link
+       LINK_CHECK_DEAD    =  12 ,    // after this UP frames and no response from NWK assume link is dead
+       LINK_CHECK_INIT    = -12 ,    // UP frame count until we inc datarate
+       LINK_CHECK_OFF     =-128 };   // link check disabled
 
 enum { TIME_RESYNC        = 6*128 }; // secs
 enum { TXRX_GUARD_ms      =  6000 };  // msecs - don't start TX-RX transaction before beacon
@@ -42,20 +49,22 @@
 enum { TXRX_BCNEXT_secs   =     2 };  // secs - earliest start after beacon time
 enum { RETRY_PERIOD_secs  =     3 };  // secs - random period for retrying a confirmed send
 
-#if CFG_eu868 // EU868 spectrum ====================================================
+#if defined(CFG_eu868) // EU868 spectrum ====================================================
 
-enum { MAX_CHANNELS = 8 };      // library may not support all 16 channels
-enum { MAX_BANDS    = 4 };
+enum { MAX_CHANNELS = 16 };      //!< Max supported channels
+enum { MAX_BANDS    =  4 };
 
 enum { LIMIT_CHANNELS = (1<<4) };   // EU868 will never have more channels
+//! \internal
 struct band_t {
-    u2_t     txcap;  // duty cycle limitation: 1/txcap
-    s1_t     txpow;  // maximum TX power
-    ostime_t avail;  // channel is blocked until this time
+    u2_t     txcap;     // duty cycle limitation: 1/txcap
+    s1_t     txpow;     // maximum TX power
+    u1_t     lastchnl;  // last used channel
+    ostime_t avail;     // channel is blocked until this time
 };
-TYPEDEF_xref2band_t;
+TYPEDEF_xref2band_t; //!< \internal
 
-#elif CFG_us915  // US915 spectrum =================================================
+#elif defined(CFG_us915)  // US915 spectrum =================================================
 
 enum { MAX_XCHANNELS = 2 };      // extra channels in RAM, channels 0-71 are immutable 
 enum { MAX_TXPOW_125kHz = 30 };
@@ -67,6 +76,7 @@
 enum { KEEP_TXPOW = -128 };
 
 
+//! \internal
 struct rxsched_t {
     u1_t     dr;
     u1_t     intvExp;   // 0..7
@@ -76,30 +86,32 @@
     ostime_t rxtime;    // start of next spot
     u4_t     freq;
 };
-TYPEDEF_xref2rxsched_t;
+TYPEDEF_xref2rxsched_t;  //!< \internal
 
 
-// Information extracted from (last) beacon
-enum { BCN_NONE    = 0x00,
-       BCN_PARTIAL = 0x01,
-       BCN_FULL    = 0x02,
-       BCN_NODRIFT = 0x04,    // no drift value measured
-       BCN_NODDIFF = 0x08 };  // no differential drift measured yet
+//! Parsing and tracking states of beacons.
+enum { BCN_NONE    = 0x00,   //!< No beacon received
+       BCN_PARTIAL = 0x01,   //!< Only first (common) part could be decoded (info,lat,lon invalid/previous)
+       BCN_FULL    = 0x02,   //!< Full beacon decoded
+       BCN_NODRIFT = 0x04,   //!< No drift value measured yet
+       BCN_NODDIFF = 0x08 }; //!< No differential drift measured yet
+//! Information about the last and previous beacons.
 struct bcninfo_t {
-    rxqu_t   rxq;
-    ostime_t txtime;  // time when beacon was sent
-    u1_t     flags;
-    u4_t     time;    // GPS time in seconds
-    // This part is valid only if flags==BCN_FULL
-    u1_t     info;    // info field
-    s4_t     lat;
-    s4_t     lon;
+    ostime_t txtime;  //!< Time when the beacon was sent
+    s1_t     rssi;    //!< Adjusted RSSI value of last received beacon
+    s1_t     snr;     //!< Scaled SNR value of last received beacon
+    u1_t     flags;   //!< Last beacon reception and tracking states. See BCN_* values.
+    u4_t     time;    //!< GPS time in seconds of last beacon (received or surrogate)
+    //
+    u1_t     info;    //!< Info field of last beacon (valid only if BCN_FULL set)
+    s4_t     lat;     //!< Lat field of last beacon (valid only if BCN_FULL set)
+    s4_t     lon;     //!< Lon field of last beacon (valid only if BCN_FULL set)
 };
 
 // purpose of receive window - lmic_t.rxState
 enum { RADIO_RST=0, RADIO_TX=1, RADIO_RX=2, RADIO_RXON=3 };
 // Netid values /  lmic_t.netid
-enum { NETID_NONE=(int)~0U, NETID_MASK=0xFFFFFF };
+enum { NETID_NONE=(int)~0U, NETID_MASK=(int)0xFFFFFF };
 // MAC operation modes (lmic_t.opmode).
 enum { OP_NONE     = 0x0000,
        OP_SCAN     = 0x0001, // radio scan to find a beacon
@@ -115,21 +127,22 @@
        OP_PINGABLE = 0x0400, // we're pingable
        OP_NEXTCHNL = 0x0800, // find a new channel
        OP_LINKDEAD = 0x1000, // link was reported as dead
-       OP_OTA      = 0x2000, // Over the Air Activation in use
+       OP_TESTMODE = 0x2000, // developer test mode
 };
 // TX-RX transaction flags - report back to user
 enum { TXRX_ACK    = 0x80,   // confirmed UP frame was acked
        TXRX_NACK   = 0x40,   // confirmed UP frame was not acked
        TXRX_NOPORT = 0x20,   // set if a frame with a port was RXed, clr if no frame/no port
+       TXRX_PORT   = 0x10,   // set if a frame with a port was RXed, LMIC.frame[LMIC.dataBeg-1] => port
        TXRX_DNW1   = 0x01,   // received in 1st DN slot
        TXRX_DNW2   = 0x02,   // received in 2dn DN slot
        TXRX_PING   = 0x04 }; // received in a scheduled RX slot
 // Event types for event callback
 enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND,
-         EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING,
-         EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED,
-         EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET,
-         EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE };
+             EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING,
+             EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED,
+             EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET,
+             EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE };
 typedef enum _ev_t ev_t;
 
 
@@ -137,25 +150,27 @@
     // Radio settings TX/RX (also accessed by HAL)
     ostime_t    txend;
     ostime_t    rxtime;
-    rxqu_t      rxq;
     u4_t        freq;
+    s1_t        rssi;
+    s1_t        snr;
     rps_t       rps;
     u1_t        rxsyms;
+    u1_t        dndr;
     s1_t        txpow;     // dBm
 
     osjob_t     osjob;
 
     // Channel scheduling
-#if CFG_eu868
+#if defined(CFG_eu868)
     band_t      bands[MAX_BANDS];
     u4_t        channelFreq[MAX_CHANNELS];
-    u1_t        channelDrs[MAX_CHANNELS];
+    u2_t        channelDrMap[MAX_CHANNELS];
     u2_t        channelMap;
-#elif CFG_us915
-    u4_t        xchFreq[MAX_XCHANNELS];  // extra channel frequencies (if device is behind a repeater)
-    u1_t        xchDrs[MAX_XCHANNELS];   // extra channel datarate ranges  ---XXX: ditto
+#elif defined(CFG_us915)
+    u4_t        xchFreq[MAX_XCHANNELS];    // extra channel frequencies (if device is behind a repeater)
+    u2_t        xchDrMap[MAX_XCHANNELS];   // extra channel datarate ranges  ---XXX: ditto
     u2_t        channelMap[(72+MAX_XCHANNELS+15)/16];  // enabled bits
-    u1_t        chRnd;        // channel randomizer
+    u2_t        chRnd;        // channel randomizer
 #endif
     u1_t        txChnl;          // channel for next TX
     u1_t        globalDutyRate;  // max rate: 1/2^k
@@ -218,8 +233,18 @@
     ostime_t    bcnRxtime;
     bcninfo_t   bcninfo;      // Last received beacon info
 };
-DECLARE_LMIC;
+//! \var struct lmic_t LMIC
+//! The state of LMIC MAC layer is encapsulated in this variable.
+DECLARE_LMIC; //!< \internal
 
+//! Construct a bit map of allowed datarates from drlo to drhi (both included). 
+#define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi))))
+#if defined(CFG_eu868)
+enum { BAND_MILLI=0, BAND_CENTI=1, BAND_DECI=2, BAND_AUX=3 };
+bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap);
+#endif
+bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band);
+void  LMIC_disableChannel (u1_t channel);
 
 void  LMIC_setDrTxpow   (dr_t dr, s1_t txpow);  // set default/start DR/txpow
 void  LMIC_setAdrMode   (bit_t enabled);        // set ADR mode (if mobile turn off)
@@ -239,6 +264,11 @@
 void  LMIC_stopPingable  (void);
 void  LMIC_setPingable   (u1_t intvExp);
 void  LMIC_tryRejoin     (void);
-void  LMIC_startABP      (u4_t netid, devaddr_t devaddr, u1_t* nwkKey, u1_t* artKey);
+
+void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
+void LMIC_setLinkCheckMode (bit_t enabled);
+
+// Special APIs - for development or testing
+// !!!See implementation for caveats!!!
 
 #endif // _lmic_h_