How To Get Started with RUI3 API

KHM-033-00.png

This article aims to show you the basics to start creating your custom firmware with RUI3 API. A separate API documentation is available and example code can be found in the RUI3 BSP and in the GitHub repo.

In addition to that, here is an overview of the requirements to connect your RUI3 WisDuo or WisBlock Core to LoRaWAN.

LoRaWAN Credentials

Depending on the Join Mode your RUI3 node needs different credentials, DevEUI, AppEUI, AppKey for OTAA or AppSkey, NwSkey and Device Address for ABP. All of these can be set with simple function calls in RUI3:

To manage the credentials for OTAA Join mode:

api.lorawan.appeui api.lorawan.appkey api.lorawan.deui

To manage the credentials for ABP Join mode:

api.lorawan.daddr api.lorawan.appskey api.lorawan.nwkskey

These functions have both SET and GET calls, so you can not only set the values, but you can also read back the values.

Example for OTAA:

uint8_t node_device_eui[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x88};
  // OTAA Application EUI MSB
  uint8_t node_app_eui[8] = {0x0E, 0x0D, 0x0D, 0x01, 0x0E, 0x01, 0x02, 0x0E};
  // OTAA Application Key MSB
  uint8_t node_app_key[16] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3E};

  // Set App EUI
  if(!(ret = api.lorawan.appeui.set(node_app_eui, 8)))
  {
       Serial.printf("RUI3 - set device EUI failed! \r\n");
       return;
  }
  // Set App Key
  if(!(ret = api.lorawan.appkey.set(node_app_key, 16)))
  {
       Serial.printf("RUI3 - set application EUI failed! \r\n");
       return;
  }
  // Set Device EUI
  if(!(ret = api.lorawan.deui.set(node_device_eui, 8)))
  {
       Serial.printf("RUI3 - set application key failed! \r\n");
       return;
  }

Example for ABP:

uint8_t node_dev_addr[4] = {0x05, 0x05, 0x06, 0x06};
  // ABP Application Session Key
  uint8_t node_app_skey[16] = {0xB4, 0x91, 0xCC, 0x10, 0x17, 0x0E, 0x89, 0x04, 0x33, 0xCA, 0x5B, 0x13, 0x1E, 0x74, 0x20, 0x07};
  // ABP Network Session Key
  uint8_t node_nwk_skey[16] = {0xBF, 0x9B, 0x75, 0xBC, 0xD6, 0x08, 0x06, 0xDD, 0x80, 0xED, 0xB8, 0xE6, 0x83, 0x29, 0x9D, 0x22};

  // Set Device Address
  if (!api.lorawan.daddr.set(node_dev_addr, 4)) {
    Serial.printf("RUI3 - set device addr failed! \r\n");
    return;
  }
  // Set Application Session Key
  if (!api.lorawan.appskey.set(node_app_skey, 16)) {
    Serial.printf
    ("RUI3 - set application session key failed! \r\n");
    return;
  }
  // Set Network Session Key
  if (!api.lorawan.nwkskey.set(node_nwk_skey, 16)) {
    Serial.printf
    ("RUI3 - set network session key failed! \r\n");
    return;
  }

Network Parameter

In addition to the credentials, several network parameters must be defined, such as Region, Node Class, Join Mode, and for some regions and specific LoRaWAN servers, the Channel Mask.

All of these settings can be setup with the following API functions:

api.lorawan.band api.lorawan.deviceClass api.lorawan.njm api.lorawan.mask

These functions have both SET and GET calls, so you can not only set the values, but you can also read back the values.

api.lorawan.band

This call is used to set (or check) the Region (equal frequency settings) the device is using. Valid settings are as follows:

RAK_REGION_EU433 RAK_REGION_IN865 RAK_REGION_AU915 RAK_REGION_CN470 RAK_REGION_EU868 RAK_REGION_KR920 RAK_REGION_RU864 RAK_REGION_US915 RAK_REGION_AS923

Example

  if(!(ret = api.lorawan.band.set(RAK_REGION_EU868)))
  {
       Serial.printf("RUI3 - set band failed! \r\n");
       return;
  }

api.lorawan.deviceClass

LoRaWAN node devices are classified into three types.

  • Class A devices have the lowest power consumption. The device can only receive downlink messages from an LNS (LoRaWAN Network Server) after it has sent a data packet.
  • Class B devices open scheduled receive windows for downlink messages and thus consume more power.
  • Class C devices can receive downlink messages at any time. Because the LoRa transceiver must always be in receive mode, this class has the highest power consumption.

Valid settings are as follows:

RAK_LORA_CLASS_A RAK_LORA_CLASS_B RAK_LORA_CLASS_C

Example:

  if(!(ret = api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)))
  {
       Serial.printf("RUI3 - set device class failed! \r\n");
       return;
  }

api.lorawan.njm

As previously stated, there are two ways for a device to join the LoRaWAN network: OTAA and ABP.

In OTAA mode, the device has a DevEUI, an AppEUI, and an AppKey that are known by both the LNS and the device. During the join process, the device sends these credentials to the LNS. If the LNS recognizes the credentials, it generates a new random application and network session key and sends it to the device. These keys are then used to encrypt data messages in future communications.

In ABP mode, the device and the LNS are both aware of the application session key and the network session key. As a result, the Join procedure is only on the device to inform the LoRaWAN MAC stack about these keys.

Valid network join modes:

RAK_LORA_OTAA RAK_LORA_ABP

Example:

  // Set network join mode
  if(!(ret = api.lorawan.njm.set(RAK_LORA_OTAA)))
  {
       Serial.printf("RUI3 - set network join mode failed! \r\n");
       return;
  }

api.lorawan.mask

Some of the region's channel plans defined in the LoRaWAN regional parameters have a large number of channels (frequencies) that can be used to communicate between the device, gateway, and LNS. In these cases, the device must know which channels it is permitted to use for packet transmission. Typically, there are eight TX channels and one RX channel.

For example, the region US915 has defined 72 channels, but because most gateways only support eight channels, the eight available channels must be masked out of the 72. Because the Things Network uses channels 8 to 15 by default, the device must be configured to use only these eight channels. The channel masks are defined in groups of eight channels, as shown below:

Mask Number (for API call) Channel Mask Enabled Channels
ALL 0x0000 All enabled
1 0x0001 0 - 7
2 0x0002 8 – 15
3 0x0004 16 - 23
4 0x0008 24 - 31
5 0x0010 32 - 39
6 0x0020 40 – 47
10 0x0200 72 – 79
11 0x0400 80 – 87
12 0x0800 88 - 95

Example:

// Set the channel mask (only required for US915, AU915 and CN470)
  uint16_t maskBuff = 0x0002;
  if(!(ret = api.lorawan.njm.set(&maskBuff)))
  {
       Serial.printf("RUI3 - set channel mask failed! \r\n");
       return;
  }

Join the Network

After all of the above credentials and settings have been completed, the device is ready to join the network. Aside from the join function call, another function can be used to check the status of the join process.

  • The api.lorawan.join call returns only the success or failure of the join start. The join may fail if the device has already joined the network, for example.
  • The api.lorawan.njs call can be used to determine the status of the join sequence. If the device successfully joined, it will return TRUE; otherwise, it will return FALSE.

Example:

// Start to join the network
  if(!(ret = api.lorawan.join()))
  {
       Serial.printf("RUI3 - join fail! \r\n");
       return;
  }
  /**Wait for Join success */
  while (!api.lorawan.njs.get())
  {
    Serial.print("Waiting for Lorawan join...");
    api.lorawan.join();
    delay(10000);
  }

Summary

These few commands set up the device to successfully join the LoRaWAN network. Here's a complete simple example of a RUI3 network join sequence:

void setup()
{
    // OTAA Device EUI MSB
    uint8_t node_device_eui[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x88};
    // OTAA Application EUI MSB
    uint8_t node_app_eui[8] = {0x0E, 0x0D, 0x0D, 0x01, 0x0E, 0x01, 0x02, 0x0E};
    // OTAA Application Key MSB
    uint8_t node_app_key[16] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3E};

    // Set App EUI
    if (!(ret = api.lorawan.appeui.set(node_app_eui, 8)))
    {
        Serial.printf("RUI3 - set device EUI failed! \r\n");
        return;
    }
    // Set App Key
    if (!(ret = api.lorawan.appkey.set(node_app_key, 16)))
    {
        Serial.printf("RUI3 - set application EUI failed! \r\n");
        return;
    }
    // Set Device EUI
    if (!(ret = api.lorawan.deui.set(node_device_eui, 8)))
    {
            Serial.printf("RUI3 - set application key failed! \r\n");
        return;
    }
    // Set LoRaWAN Region
    if (!(ret = api.lorawan.band.set(RAK_REGION_EU868)))
    {
        Serial.printf("RUI3 - set band failed! \r\n");
        return;
    }
    // Set device class
    if (!(ret = api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)))
    {
        Serial.printf("RUI3 - set device class failed! \r\n");
        return;
    }
    // Set network join mode
    if (!(ret = api.lorawan.njm.set(RAK_LORA_OTAA)))
    {
        Serial.printf("RUI3 - set network join mode failed! \r\n");
        return;
    }
    // Start to join the network
    if(!(ret = api.lorawan.join()))
    {
        Serial.printf("RUI3 - join fail! \r\n");
        return;
    }
}

bool has_joined = false;

void loop()
{
    if (!has_joined)
    {
        if (api.lorawan.njs.get())
        {
            Serial.println("RUI3 - joined network");
            has_joined = true;
        }
    }
    else
    {
        // Read sensors, send the data
        // ...
        // We talk about this in the next post
    }
}
bernd-giesecke.png

Bernd Giesecke

Electronics Engineer, 23 years of experience in industrial and automotive HW and SW R&D. Supporting Arduino open-source community since 2014.

Updated