Sending text with lorawan towards the things network

This is a writeup describing how I programmed the NUCLEO-L152RE microcontroller to ship off some ascii text to our lora gateway. Our gateway is connected to the things network. Our address space is 02:03:10:xx, which we have claimed on the TTN wiki.

STM32 Nucleo board
STM32 Nucleo board

To connect the lora radio chip, we use the Seeed Grove Shield V2 expansion board.

 As an expansion board, Base Shield v2 has many Grove connectors, making it convenient for you to use Grove products together
As an expansion board, Base Shield v2 has many Grove connectors, making it convenient for you to use Grove products together

To communicate to the lora gateway we use the SX1276MB1xAS transceiver.

The SX1276MB1MAS and SX1276LB1LAS are both fitted with the SX1276 transceiver which, added to a high-performance FSK / OOK RF transceiver modem, features the LoRa™ long range modem.
The SX1276MB1MAS and SX1276LB1LAS are both fitted with the SX1276 transceiver which, added to a high-performance FSK / OOK RF transceiver modem, features the LoRa™ long range modem.

The three devices all connected looks like this:

IMG_20160114_140004

Producing the binary

To create binaries from code I used the compiler from developer.mbed.org. It is a web IDE that simplifies and speeds up the creation and deployment of devices based on ARM microcontrollers. To create a program I imported the LoRaWAN_send_text repository from a user called tamberg.

The first change I do in the code is to set the device address:

#define LORAWAN_DEV_ADDR (uint32_t) 0x02031002

First I hit compile and a binary LoRaWAN_send_text_NUCLEO_L152RE.bin is downloaded to my local storage.

Next I plug the Nucleo into my machine using micro-USB cable. This presents a USB mass storage device to my machine. To upload the binary I conveniently move the file over and the microcontroller is flashed immediately after.

mv -v LoRaWAN_send_text_2_NUCLEO_L152RE.bin /media/d/NODE_L152RE/

Shortly after, the LD1 LED blinks furiously indicating that new binary is flashed onto device.

A few seconds later the data has arrived to TTN and is exposed on their HTTP API. Here is the data:

{
  "data_raw": "gAIQAwKAAAADNTFQd4kvk4XcLgU++F/zahI=",
  "gateway_eui": "AA555A0008060353",
  "node_eui": "02031002",
  "frequency": 868.1,
  "data_plain": "YO Trondheim ",
  "time": "2016-01-14T13:43:08.175Z",
  "rssi": -96,
  "snr": 9.0,
  "datarate": "SF12BW125",
  "data": "WU8gVHJvbmRoZWltIA=="
}

The "gateway_eui": "AA555A0008060353" is our lora gateway located on the rooftop at olavskvartalet in Trondheim. We also have deployed a gateway at the rooftop on Samfundet. Its eui is AA555A0008060352

The full code

// License: Revised BSD License, see LICENSE.TXT, (c)2015 Semtech

#include "mbed.h"
#include "lmic.h"
#include "debug.h"

#define LORAWAN_NET_ID (uint32_t) 0x00000000
// TODO: enter device address below, for TTN just set ???
#define LORAWAN_DEV_ADDR (uint32_t) 0x02031002
#define LORAWAN_ADR_ON 1
#define LORAWAN_CONFIRMED_MSG_ON 1
#define LORAWAN_APP_PORT 3//15

static uint8_t NwkSKey[] = {
    // TODO: enter network, or use TTN default
    // e.g. for 2B7E151628AED2A6ABF7158809CF4F3C =>
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

static uint8_t ArtSKey[] = {
    // TODO: enter application key, or use TTN default
    // e.g. for 2B7E151628AED2A6ABF7158809CF4F3C =>
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

osjob_t initjob;
osjob_t sendFrameJob;
u1_t n = 0;

void os_getArtEui (uint8_t *buf) {} // ignore
void os_getDevEui (uint8_t *buf) {} // ignore
void os_getDevKey (uint8_t *buf) {} // ignore

void onSendFrame (osjob_t* j) {
    const char* message = "YO Trondheim "; // ASCII only
    int frameLength = strlen(message); // keep it < 32
    for (int i = 0; i < frameLength; i++) {
        LMIC.frame[i] = message[i];
    }
    int result = LMIC_setTxData2(LORAWAN_APP_PORT, LMIC.frame, 
        frameLength, LORAWAN_CONFIRMED_MSG_ON); // calls onEvent()
}

void onInit (osjob_t* j) {
    LMIC_reset();
    LMIC_setAdrMode(LORAWAN_ADR_ON);
    LMIC_setDrTxpow(DR_SF12, 14);
    LMIC_setSession(LORAWAN_NET_ID, LORAWAN_DEV_ADDR, NwkSKey, ArtSKey);
    onSendFrame(NULL);
}

void onEvent (ev_t ev) { // called by lmic.cpp, see also oslmic.h
    debug_event(ev);
    if (ev == EV_TXCOMPLETE) {
        os_setCallback(&sendFrameJob, onSendFrame);
    }
}

int main (void) {
    debug_str("main\r\n");
    os_init();
    os_setCallback(&initjob, onInit);
    os_runloop(); // blocking
}

This OS-like code is the IBM LoRaWAN C-library (LMiC) portable implementation of the LoRaTM MAC specification for the C programming language. It drives the SEMTECH SX1272 radio.

The LMiC library can be accessed via a set of API functions, run-time functions, callback functions, and a global LMIC data structure.

The LMiC library offers a simple event-based programming model where all protocol events are dispatched to the application’s onEvent() callback function. In order to free the application of details like timings or interrupts, the library has a built-in run-time environment to take care of timer queues and job management.