frabbit
frabbit

Reputation: 31

Class C loraWan implementation

Good morning! I am trying to create code for message exchange via LoRaWAN using a Raspberry Pi Pico with an SX1262 hat link. Initially, the project only involved sending messages at regular intervals without the idea of receiving them. For this, while studying the classes, I had opted for a Class A as mentioned on the website thethingsnetwork:

A Class A device can send an uplink message at any time. Once the uplink transmission is completed, the device opens two short receive windows for receiving downlink messages from the network.

I registered the device on TTN with the European frequency (863-870 MHz) and LoRaWAN specification 1.0.2, registering it as Class A only. I've found some code in C++ to send data via lorawan, but later the idea evolved to include receiving messages. So, the node should not only be able to send a message at a specific time interval but also remain constantly on the lookout for incoming messages. In this case, based on the Class specifications, I read that it would be better to use Class C.

Class C devices extend Class A capabilities by keeping the receive windows open unless transmitting an uplink, as shown in the figure below. Therefore, Class C devices can receive downlink messages at almost any time, thus having very low latency for downlinks.

So, I am trying to modify the code to have a Class C device. Do you have any advice on how to create this class through code or where I can find useful code for Class C? I searched a bit on the web but without finding anything that could satisfy me. On TTN, when registering a new device, after registering the specifications and clicking on "show advanced activation," in LoRaWAN capabilities, I select Class C and then proceed with the registration as I would for any other device. Is this correct, or is there anything else to manage that differs from Class B or A?

I've taken the code from the demo of waveshare git link By modifying only the LoRaWAN Node Region and OTAA settings in config.h, but this is a code designed for Class A, meaning it receives a downlink only when a message is sent. What I would like is for it to remain always listening.

#include <stdio.h>
#include <string.h>

#include "pico/stdlib.h"
#include "pico/lorawan.h"
#include "tusb.h"

// edit with LoRaWAN Node Region and OTAA settings 
#include "config.h"

// pin configuration for SX1276 radio module
const struct lorawan_sx1276_settings sx1276_settings = {
    .spi = {
        .inst = PICO_DEFAULT_SPI_INSTANCE,
        .mosi = PICO_DEFAULT_SPI_TX_PIN,
        .miso = PICO_DEFAULT_SPI_RX_PIN,
        .sck  = PICO_DEFAULT_SPI_SCK_PIN,
        .nss  = 8
    },
    .reset = 9,
    .dio0  = 7,
    .dio1  = 10
};

// OTAA settings
const struct lorawan_otaa_settings otaa_settings = {
    .device_eui   = LORAWAN_DEVICE_EUI,
    .app_eui      = LORAWAN_APP_EUI,
    .app_key      = LORAWAN_APP_KEY,
    .channel_mask = LORAWAN_CHANNEL_MASK
};

// variables for receiving data
int receive_length = 0;
uint8_t receive_buffer[242];
uint8_t receive_port = 0;

int main( void )
{
    // initialize stdio and wait for USB CDC connect
    stdio_init_all();

    while (!tud_cdc_connected()) {
        tight_loop_contents();
    }
    
    printf("Pico LoRaWAN - Hello OTAA\n\n");

    // uncomment next line to enable debug
    // lorawan_debug(true);

    // initialize the LoRaWAN stack
    printf("Initilizating LoRaWAN ... ");
    if (lorawan_init_otaa(&sx1276_settings, LORAWAN_REGION, &otaa_settings) < 0) {
        printf("failed!!!\n");
        while (1) {
            tight_loop_contents();
        }
    } else {
        printf("success!\n");
    }

    // Start the join process and wait
    printf("Joining LoRaWAN network ... ");
    lorawan_join();

    while (!lorawan_is_joined()) {
        lorawan_process();
    }
    printf("joined successfully!\n");

    uint32_t last_message_time = 0;

    // loop forever
    while (1) {
        // let the lorwan library process pending events
        lorawan_process();

        // get the current time and see if 5 seconds have passed
        // since the last message was sent
        uint32_t now = to_ms_since_boot(get_absolute_time());

        if ((now - last_message_time) > 5000) {
            const char* message = "hello world!";

            // try to send an unconfirmed uplink message
            printf("sending unconfirmed message '%s' ... ", message);
            if (lorawan_send_unconfirmed(message, strlen(message), 2) < 0) {
                printf("failed!!!\n");
            } else {
                printf("success!\n");
            }

            last_message_time = now;
        }

        // check if a downlink message was received
        receive_length = lorawan_receive(receive_buffer, sizeof(receive_buffer), &receive_port);
        if (receive_length > -1) {
            printf("received a %d byte message on port %d: ", receive_length, receive_port);

            for (int i = 0; i < receive_length; i++) {
                printf("%02x", receive_buffer[i]);
            }
            printf("\n");
        }
    }

    return 0;
}

I tried to implement some checks in order to send data only when necessary within the while(true) loop and have a continuous lorawan_receive running, but it doesn't receive messages unless a message is sent. I was only able to extend the receive window, making it Class B, but nothing more than that. I'm now relying on those who may know more about this.

Upvotes: 3

Views: 99

Answers (1)

dda
dda

Reputation: 6213

Class A or C doesn't change the code much. I haven't used a hat for this, but I have done plenty of two-way communication with LoRaWAN devices. Water meters, monitoring devices, etc.

The library I use is event-driven. When a downlink comes in, a handler functiin is called. Class A or C doesn't matter. It's just that in Class A you have very small windows of opportunity. So you send an uplink regularly to trigger any pending downlinks.

Inbyour code, you'll have to determine whether it can provide event-driven functions that would wotk the same way. If not you'll have to watch for the incoming messages.

And if you stick to Class A, just arrange for a heartsbeat to be sent regularly, and then you can watch for messages.

Upvotes: 0

Related Questions