Reputation: 31
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
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