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
Committer:
mluis
Date:
Thu Nov 26 17:17:08 2015 +0000
Revision:
4:85b2b647cb64
Parent:
1:d3b7bde3995c
Merged branches

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mluis 0:62d1edcc13d1 1 /*******************************************************************************
mluis 1:d3b7bde3995c 2 * Copyright (c) 2014-2015 IBM Corporation.
mluis 0:62d1edcc13d1 3 * All rights reserved. This program and the accompanying materials
mluis 0:62d1edcc13d1 4 * are made available under the terms of the Eclipse Public License v1.0
mluis 0:62d1edcc13d1 5 * which accompanies this distribution, and is available at
mluis 0:62d1edcc13d1 6 * http://www.eclipse.org/legal/epl-v10.html
mluis 0:62d1edcc13d1 7 *
mluis 0:62d1edcc13d1 8 * Contributors:
mluis 0:62d1edcc13d1 9 * IBM Zurich Research Lab - initial API, implementation and documentation
mluis 0:62d1edcc13d1 10 *******************************************************************************/
mluis 0:62d1edcc13d1 11
mluis 0:62d1edcc13d1 12 #include "lmic.h"
mluis 0:62d1edcc13d1 13
mluis 0:62d1edcc13d1 14 // RUNTIME STATE
mluis 0:62d1edcc13d1 15 static struct {
mluis 0:62d1edcc13d1 16 osjob_t* scheduledjobs;
mluis 0:62d1edcc13d1 17 osjob_t* runnablejobs;
mluis 0:62d1edcc13d1 18 } OS;
mluis 0:62d1edcc13d1 19
mluis 1:d3b7bde3995c 20 void os_init () {
mluis 0:62d1edcc13d1 21 memset(&OS, 0x00, sizeof(OS));
mluis 0:62d1edcc13d1 22 hal_init();
mluis 0:62d1edcc13d1 23 radio_init();
mluis 0:62d1edcc13d1 24 LMIC_init();
mluis 0:62d1edcc13d1 25 }
mluis 0:62d1edcc13d1 26
mluis 1:d3b7bde3995c 27 ostime_t os_getTime () {
mluis 0:62d1edcc13d1 28 return hal_ticks();
mluis 0:62d1edcc13d1 29 }
mluis 0:62d1edcc13d1 30
mluis 0:62d1edcc13d1 31 static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) {
mluis 0:62d1edcc13d1 32 for( ; *pnext; pnext = &((*pnext)->next)) {
mluis 0:62d1edcc13d1 33 if(*pnext == job) { // unlink
mluis 0:62d1edcc13d1 34 *pnext = job->next;
mluis 0:62d1edcc13d1 35 return 1;
mluis 0:62d1edcc13d1 36 }
mluis 0:62d1edcc13d1 37 }
mluis 0:62d1edcc13d1 38 return 0;
mluis 0:62d1edcc13d1 39 }
mluis 0:62d1edcc13d1 40
mluis 0:62d1edcc13d1 41 // clear scheduled job
mluis 0:62d1edcc13d1 42 void os_clearCallback (osjob_t* job) {
mluis 0:62d1edcc13d1 43 hal_disableIRQs();
mluis 0:62d1edcc13d1 44 unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job);
mluis 0:62d1edcc13d1 45 hal_enableIRQs();
mluis 0:62d1edcc13d1 46 }
mluis 0:62d1edcc13d1 47
mluis 0:62d1edcc13d1 48 // schedule immediately runnable job
mluis 0:62d1edcc13d1 49 void os_setCallback (osjob_t* job, osjobcb_t cb) {
mluis 0:62d1edcc13d1 50 osjob_t** pnext;
mluis 0:62d1edcc13d1 51 hal_disableIRQs();
mluis 0:62d1edcc13d1 52 // remove if job was already queued
mluis 0:62d1edcc13d1 53 os_clearCallback(job);
mluis 0:62d1edcc13d1 54 // fill-in job
mluis 0:62d1edcc13d1 55 job->func = cb;
mluis 0:62d1edcc13d1 56 job->next = NULL;
mluis 0:62d1edcc13d1 57 // add to end of run queue
mluis 0:62d1edcc13d1 58 for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
mluis 0:62d1edcc13d1 59 *pnext = job;
mluis 0:62d1edcc13d1 60 hal_enableIRQs();
mluis 0:62d1edcc13d1 61 }
mluis 0:62d1edcc13d1 62
mluis 0:62d1edcc13d1 63 // schedule timed job
mluis 0:62d1edcc13d1 64 void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
mluis 0:62d1edcc13d1 65 osjob_t** pnext;
mluis 0:62d1edcc13d1 66 hal_disableIRQs();
mluis 0:62d1edcc13d1 67 // remove if job was already queued
mluis 0:62d1edcc13d1 68 os_clearCallback(job);
mluis 0:62d1edcc13d1 69 // fill-in job
mluis 0:62d1edcc13d1 70 job->deadline = time;
mluis 0:62d1edcc13d1 71 job->func = cb;
mluis 0:62d1edcc13d1 72 job->next = NULL;
mluis 0:62d1edcc13d1 73 // insert into schedule
mluis 0:62d1edcc13d1 74 for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
mluis 1:d3b7bde3995c 75 if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
mluis 0:62d1edcc13d1 76 // enqueue before next element and stop
mluis 0:62d1edcc13d1 77 job->next = *pnext;
mluis 0:62d1edcc13d1 78 break;
mluis 0:62d1edcc13d1 79 }
mluis 0:62d1edcc13d1 80 }
mluis 0:62d1edcc13d1 81 *pnext = job;
mluis 0:62d1edcc13d1 82 hal_enableIRQs();
mluis 0:62d1edcc13d1 83 }
mluis 0:62d1edcc13d1 84
mluis 0:62d1edcc13d1 85 // execute jobs from timer and from run queue
mluis 1:d3b7bde3995c 86 void os_runloop () {
mluis 0:62d1edcc13d1 87 while(1) {
mluis 0:62d1edcc13d1 88 osjob_t* j = NULL;
mluis 0:62d1edcc13d1 89 hal_disableIRQs();
mluis 1:d3b7bde3995c 90 // check for runnable jobs
mluis 1:d3b7bde3995c 91 if(OS.runnablejobs) {
mluis 0:62d1edcc13d1 92 j = OS.runnablejobs;
mluis 0:62d1edcc13d1 93 OS.runnablejobs = j->next;
mluis 1:d3b7bde3995c 94 } else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs
mluis 0:62d1edcc13d1 95 j = OS.scheduledjobs;
mluis 0:62d1edcc13d1 96 OS.scheduledjobs = j->next;
mluis 0:62d1edcc13d1 97 } else { // nothing pending
mluis 0:62d1edcc13d1 98 hal_sleep(); // wake by irq (timer already restarted)
mluis 0:62d1edcc13d1 99 }
mluis 0:62d1edcc13d1 100 hal_enableIRQs();
mluis 0:62d1edcc13d1 101 if(j) { // run job callback
mluis 1:d3b7bde3995c 102 j->func(j);
mluis 0:62d1edcc13d1 103 }
mluis 0:62d1edcc13d1 104 }
mluis 0:62d1edcc13d1 105 }