LMIC 1.5 + Arduino UNO/LoRa HAT Class B beacon code

Hi there.
I’ve up and running a installation with

  • LoRaServer Application Server
  • LoRaServer Network Server
  • IMST LoRa Lite Gateway (raspberry pi + ic880A SX1301 module) with attached GPS module / PPS-Pin connected

So far, class A devices are working as expected, uplink and downlink.
Tried and checked with an Arduino UNO R3 + Dragino LoRa HAT + LMIC 1.5 (LMIC-Arduino Library with ttn-abp.ino Example, see at the end of this post):

Now, i want to make class B working to be able to conduct measurements i need for my university thesis.

Regarding the Gateway side, everything seems fine now:
I compiled the latest packet_forwarder from semtech (Lora-Net) directly on the raspberry pi.
GPS seems to work, die coordinates are displayed correctly in LoRa Appserver for the Gateway.
Also Beacons are sent out regularly as configured (checked with a HackRF One SDR).

Regarding the node, i’,m a little lost.
Since i want to use Arduino with RFM95 / SX1276 transceiver chip, i am going with the LMIC library.
Consulting the LMIC Examples (LMiC-v1.5.pdf) i am not sure what beacon frequency to set and how to register that beacon frequency in the LMiC.

How to align the frequency setup, so that LMIC looks for the beacons on the right frequency, configured in global_conf.json for the packet-forwarder?

On the LoraServer Side:
Do i have to do some configuration in the LoraAppServer for the Gateway or the Network Server?

Anyone who has done already class B with LMIC devices and could provide some help?
Or maybe some hints where to dig deeper?

Thank you very much.

End-Device Class-A (ABP, sending and receiving in RX Windows) LMIC Code (working so far, without the Beacon thing…):
> /*******************************************************************************
> * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
> *
> * Permission is hereby granted, free of charge, to anyone
> * obtaining a copy of this document and accompanying files,
> * to do whatever they want with them without any restriction,
> * including, but not limited to, copying, modification and redistribution.
> * NO WARRANTY OF ANY KIND IS PROVIDED.
> *
> * This example sends a valid LoRaWAN packet with payload “Hello,
> * world!”, using frequency and encryption settings matching those of
> * the (early prototype version of) The Things Network.
> *
> * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1,
> * 0.1% in g2).
> *
> * Change DEVADDR to a unique address!
> * See http://thethingsnetwork.org/wiki/AddressSpace
> *
> * Do not forget to define the radio type correctly in config.h.
> *
> ***************************************************************************/
>
> #include <lmic.h>
> #include <hal/hal.h>
> #include <SPI.h>
>
> // LoRaWAN NwkSKey, network session key
>
> //static const PROGMEM u1_t NWKSKEY[16] = { 0xFE, 0x25, 0xB1, 0x06, 0x3D, 0x8D, 0x60, 0x10, 0x67, 0xE5, 0x47, 0x13, 0x06, 0xC2, 0xDA, 0x61 };
>
> // f3 ed 1f 47 44 fb b4 da 98 c5 9e f8 f3 41 ef 10
> static const PROGMEM u1_t NWKSKEY[16] = { 0xF3, 0xED, 0x1F, 0x47, 0x44, 0xFB, 0xB4, 0xDA, 0x98, 0xC5, 0x9E, 0xF8, 0xF3, 0x41, 0xEF, 0x10 };
>
> // LoRaWAN AppSKey, application session key
> static const u1_t PROGMEM APPSKEY[16] = { 0xC5, 0xDB, 0x30, 0x48, 0x70, 0xA1, 0xC2, 0x4D, 0x33, 0x22, 0x89, 0x24, 0x9B, 0x21, 0xF2, 0x40 };
>
> // LoRaWAN end-device address (DevAddr)
> static const u4_t DEVADDR = 0xfceb3e8f ;
>
> // These callbacks are only used in over-the-air activation, so they are
> // left empty here (we cannot leave them out completely unless
> // DISABLE_JOIN is set in config.h, otherwise the linker will complain).
> void os_getArtEui (u1_t
buf) { }
> void os_getDevEui (u1_t
buf) { }
> void os_getDevKey (u1_t
buf) { }
>
> static uint8_t mydata[] = “Hello, world!”;
> static osjob_t sendjob;
>
> // Schedule TX every this many seconds (might become longer due to duty
> // cycle limitations).
> const unsigned TX_INTERVAL = 60;
>
> // Pin mapping
> const lmic_pinmap lmic_pins = {
> .nss = 10,
> .rxtx = LMIC_UNUSED_PIN,
> .rst = 9,
> .dio = {2, 6, 7},
> };
>
> void onEvent (ev_t ev) {
> Serial.print(os_getTime());
> Serial.print(“: “);
> switch(ev) {
> case EV_SCAN_TIMEOUT:
> Serial.println(F(“EV_SCAN_TIMEOUT”));
> break;
> case EV_BEACON_FOUND:
> Serial.println(F(“EV_BEACON_FOUND”));
> Serial.println(”---- found beacon ----”);
> break;
> case EV_BEACON_MISSED:
> Serial.println(F(“EV_BEACON_MISSED”));
> Serial.println(“Beacon missed at expected time”);
> break;
> case EV_BEACON_TRACKED:
> Serial.println(F(“EV_BEACON_TRACKED”));
> Serial.print("GPS time = ");Serial.print(LMIC.bcninfo.time);
> Serial.println(“Beacon tracked at expected time”);
> break;
> case EV_JOINING:
> Serial.println(F(“EV_JOINING”));
> break;
> case EV_JOINED:
> Serial.println(F(“EV_JOINED”));
> LMIC_enableTracking(0);
> Serial.println(“SCANNING…\r\n”);
> break;
> case EV_RFU1:
> Serial.println(F(“EV_RFU1”));
> break;
> case EV_JOIN_FAILED:
> Serial.println(F(“EV_JOIN_FAILED”));
> break;
> case EV_REJOIN_FAILED:
> Serial.println(F(“EV_REJOIN_FAILED”));
> break;
> break;
> case EV_TXCOMPLETE:
> Serial.println(F(“EV_TXCOMPLETE (includes waiting for RX windows)”));
> if(LMIC.dataLen) {
> // data received in rx slot after tx
> Serial.print(F("Data Received: "));
> Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);
> Serial.println();
> }
> // Schedule next transmission
> os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
> break;
> case EV_LOST_TSYNC:
> Serial.println(F(“EV_LOST_TSYNC”));
> break;
> case EV_RESET:
> Serial.println(F(“EV_RESET”));
> break;
> case EV_RXCOMPLETE:
> // data received in ping slot
> Serial.println(F(“EV_RXCOMPLETE”));
> break;
> case EV_LINK_DEAD:
> Serial.println(F(“EV_LINK_DEAD”));
> break;
> case EV_LINK_ALIVE:
> Serial.println(F(“EV_LINK_ALIVE”));
> break;
> default:
> Serial.println(F(“Unknown event”));
> break;
> }
> }
>
> void do_send(osjob_t
j){
> // Check if there is not a current TX/RX job running
> if (LMIC.opmode & OP_TXRXPEND) {
> Serial.println(F(“OP_TXRXPEND, not sending”));
> } else {
> // Prepare upstream data transmission at the next possible time.
> LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
> Serial.println(F(“Packet queued”));
> }
> // Next TX is scheduled after TX_COMPLETE event.
> }
>
> void setup() {
> Serial.begin(57600);
> Serial.println(F(“Starting”));
>
> // LMIC init
> os_init();
> // Reset the MAC state. Session and pending data transfers will be discarded.
> LMIC_reset();
>
> // Set static session parameters. Instead of dynamically establishing a session
> // by joining the network, precomputed session parameters are be provided.
> #ifdef PROGMEM
> // On AVR, these values are stored in flash and only copied to RAM
> // once. Copy them to a temporary buffer here, LMIC_setSession will
> // copy them into a buffer of its own again.
> uint8_t appskey[sizeof(APPSKEY)];
> uint8_t nwkskey[sizeof(NWKSKEY)];
> memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
> memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
> LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
> #else
> // If not running an AVR with PROGMEM, just use the arrays directly
> LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
> #endif
>
> // Set up the channels used by the Things Network, which corresponds
> // to the defaults of most gateways. Without this, only three base
> // channels from the LoRaWAN specification are used, which certainly
> // works, so it is good for debugging, but can overload those
> // frequencies, so be sure to configure the full frequency range of
> // your network here (unless your network autoconfigures them).
> // Setting up channels should happen after LMIC_setSession, as that
> // configures the minimal channel set.
> LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
> LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
> LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band
> // TTN defines an additional channel at 869.525Mhz using SF9 for class B
> // devices’ ping slots. LMIC does not have an easy way to define set this
> // frequency and support for class B is spotty and untested, so this
> // frequency is not configured here.
>
> // Disable link check validation
> LMIC_setLinkCheckMode(0);
>
> // Set data rate and transmit power (note: txpow seems to be ignored by the library)
> LMIC_setDrTxpow(DR_SF7,14);
>
> LMIC_enableTracking(0);
> Serial.println(“SCANNING…\r\n”);
>
> // Start job
> do_send(&sendjob);
> }
>
> void loop() {
> os_runloop_once();
> }

My current global_conf.json used with the semtech packet forwarder:

{
“SX1301_conf”: {
“lorawan_public”: true,
“clksrc”: 1, /* radio_1 provides clock to concentrator /
“antenna_gain”: 0, /
antenna gain, in dBi /
“radio_0”: {
“enable”: true,
“type”: “SX1257”,
“freq”: 867500000,
“rssi_offset”: -166.0,
“tx_enable”: true,
“tx_freq_min”: 863000000,
“tx_freq_max”: 870000000
},
“radio_1”: {
“enable”: true,
“type”: “SX1257”,
“freq”: 868500000,
“rssi_offset”: -166.0,
“tx_enable”: false
},
“chan_multiSF_0”: {
/
Lora MAC channel, 125kHz, all SF, 868.1 MHz /
“enable”: true,
“radio”: 1,
“if”: -400000
},
“chan_multiSF_1”: {
/
Lora MAC channel, 125kHz, all SF, 868.3 MHz /
“enable”: true,
“radio”: 1,
“if”: -200000
},
“chan_multiSF_2”: {
/
Lora MAC channel, 125kHz, all SF, 868.5 MHz /
“enable”: true,
“radio”: 1,
“if”: 0
},
“chan_multiSF_3”: {
/
Lora MAC channel, 125kHz, all SF, 867.1 MHz /
“enable”: true,
“radio”: 0,
“if”: -400000
},
“chan_multiSF_4”: {
/
Lora MAC channel, 125kHz, all SF, 867.3 MHz /
“enable”: true,
“radio”: 0,
“if”: -200000
},
“chan_multiSF_5”: {
/
Lora MAC channel, 125kHz, all SF, 867.5 MHz /
“enable”: true,
“radio”: 0,
“if”: 0
},
“chan_multiSF_6”: {
/
Lora MAC channel, 125kHz, all SF, 867.7 MHz /
“enable”: true,
“radio”: 0,
“if”: 200000
},
“chan_multiSF_7”: {
/
Lora MAC channel, 125kHz, all SF, 867.9 MHz /
“enable”: true,
“radio”: 0,
“if”: 400000
},
“chan_Lora_std”: {
/
Lora MAC channel, 250kHz, SF7, 868.3 MHz /
“enable”: true,
“radio”: 1,
“if”: -200000,
“bandwidth”: 250000,
“spread_factor”: 7
},
“chan_FSK”: {
/
FSK 50kbps channel, 868.8 MHz /
“enable”: true,
“radio”: 1,
“if”: 300000,
“bandwidth”: 125000,
“datarate”: 50000
},
“tx_lut_0”: {
/
TX gain table, index 0 /
“pa_gain”: 0,
“mix_gain”: 8,
“rf_power”: -6,
“dig_gain”: 0
},
“tx_lut_1”: {
/
TX gain table, index 1 /
“pa_gain”: 0,
“mix_gain”: 10,
“rf_power”: -3,
“dig_gain”: 0
},
“tx_lut_2”: {
/
TX gain table, index 2 /
“pa_gain”: 0,
“mix_gain”: 12,
“rf_power”: 0,
“dig_gain”: 0
},
“tx_lut_3”: {
/
TX gain table, index 3 /
“pa_gain”: 1,
“mix_gain”: 8,
“rf_power”: 3,
“dig_gain”: 0
},
“tx_lut_4”: {
/
TX gain table, index 4 /
“pa_gain”: 1,
“mix_gain”: 10,
“rf_power”: 6,
“dig_gain”: 0
},
“tx_lut_5”: {
/
TX gain table, index 5 /
“pa_gain”: 1,
“mix_gain”: 12,
“rf_power”: 10,
“dig_gain”: 0
},
“tx_lut_6”: {
/
TX gain table, index 6 /
“pa_gain”: 1,
“mix_gain”: 13,
“rf_power”: 11,
“dig_gain”: 0
},
“tx_lut_7”: {
/
TX gain table, index 7 /
“pa_gain”: 2,
“mix_gain”: 9,
“rf_power”: 12,
“dig_gain”: 0
},
“tx_lut_8”: {
/
TX gain table, index 8 /
“pa_gain”: 1,
“mix_gain”: 15,
“rf_power”: 13,
“dig_gain”: 0
},
“tx_lut_9”: {
/
TX gain table, index 9 /
“pa_gain”: 2,
“mix_gain”: 10,
“rf_power”: 14,
“dig_gain”: 0
},
“tx_lut_10”: {
/
TX gain table, index 10 /
“pa_gain”: 2,
“mix_gain”: 11,
“rf_power”: 16,
“dig_gain”: 0
},
“tx_lut_11”: {
/
TX gain table, index 11 /
“pa_gain”: 3,
“mix_gain”: 9,
“rf_power”: 20,
“dig_gain”: 0
},
“tx_lut_12”: {
/
TX gain table, index 12 /
“pa_gain”: 3,
“mix_gain”: 10,
“rf_power”: 23,
“dig_gain”: 0
},
“tx_lut_13”: {
/
TX gain table, index 13 /
“pa_gain”: 3,
“mix_gain”: 11,
“rf_power”: 25,
“dig_gain”: 0
},
“tx_lut_14”: {
/
TX gain table, index 14 /
“pa_gain”: 3,
“mix_gain”: 12,
“rf_power”: 26,
“dig_gain”: 0
},
“tx_lut_15”: {
/
TX gain table, index 15 /
“pa_gain”: 3,
“mix_gain”: 14,
“rf_power”: 27,
“dig_gain”: 0
}
},
“gateway_conf”: {
“gateway_ID”: “b827ebFFFE4c09b0”,
/
change with default server address/ports, or overwrite in local_conf.json /
“server_address”: “localhost”,
“serv_port_up”: 1700,
“serv_port_down”: 1700,
/
adjust the following parameters for your network /
“keepalive_interval”: 30,
“stat_interval”: 30,
“push_timeout_ms”: 100,
/
forward only valid packets /
“forward_crc_valid”: true,
“forward_crc_error”: false,
“forward_crc_disabled”: false,
/
GPS configuration /
“gps”:true,
“fake_gps”:false,
contact_email":"test@example.com”,
“gps_tty_path”: “/dev/ttyAMA0”,
/
GPS reference coordinates /
“ref_latitude”: 0.0,
“ref_longitude”: 0.0,
“ref_altitude”: 10,
/
Beaconing parameters */
“beacon_period”: 64,
“beacon_freq_hz” : 869525000,
“beacon_datarate”: 9,
“beacon_bw_hz”: 125000,
“beacon_power”: 14,
“beacon_infodesc”: 0
}
}

I don’t think that LMIC has Class-B support which aligns with the LoRaWAN 1.0.3 / LoRaWAN 1.1.x specification.

Oh really? Despite its claims to be Class-B compatible? okay, this if from 2015, LoRaWAN 1.1.x was not even on the horizon there…But maybe someone has tried this?

Do you know of any implementations for SX1272/SX1276/RFM95 Radio modules (and optimally the Arduino Plattform, may be another mcu than the Atmel AVRs though), that works with current Class B, at least compliant to LoRaWAN 1.0.3 spec?

A lot has changed since 2015 :wink: Please see https://github.com/Lora-net/LoRaMac-node

:wink: Any recommendations for beginners? I have a SAML21 Xplained Pro board lying around here, but it seems quite overwhelming, considering i can’t use all the arduino libraries…

Is there, to your knowledge, any board that runs with Arduino that supports LoRaWAN Class B Stack?

Or is there even a “full-Stack” chip with Class B support readliy available? I looked but did not find any with these capabilities.

Thank you very much!
Best Regards

Long time ago, since you entered that issue. Did you solve it? I’m stuck at the same point. I use mcci LMIC, which is new version. How can I tell LMIC to listen to the beacon frequency (channel).

thanks
Thomas

Hi ,
Did you had any luck LoRa HAT Class B beacon code]. Broocar said that the
https://github.com/Lora-net/LoRaMac-node/ was the place to search. The
https://github.com/Lora-net/LoRaMac-node/tree/feature/5.0.0 reports:

This project also provides SX1272/73, SX1276/77/78/79 and SX1261/2 radio drivers.

For each currently supported platform example applications are provided.

  • LoRaMac/classA : ClassA end-device example application.
  • LoRaMac/classB : ClassB end-device example application.

Have you tried this ?

1 Like