That is my code and I am sure I am not changing any of the credentials in my code.
The code relies 100% on a setup through AT commands.
Thanks. This issue is very strange then. With your unmodified code I am getting this issue of changing credentials. Also after I do the first step here (adafruit-nrfutil.exe --verbose dfu serial --package rui3_nrf52840_bootloader_latest.zip --port COM<insert correct number here based on Windows + X > Device Manager > Ports> -b 115200 --singlebank --touch 1200) I cannot see anything via AT commands in RAK serial monitor or Arduino IDE serial monitor.
I’ve tried now with a second WisBlock and I get the same problems
I realize I shouldn’t have to, but in my case because of this strange issue is there a way to hardcode the DevEUI, AppEUI, and AppKey explicitly in this .ino file? I have been trying a few different methods to try to deal with this issue, but I am still getting random outputs
If you set the credentials with AT commands, that is already hard-coded. The values submitted with AT commands are saved in flash and the LoRaWAN stack is reading them during startup and using them for the Join request.
If you think it helps, have a look into the LoRaWan_OTAA.ino example code.
It is setting the credentials with API calls.
Code extracts:
#define OTAA_BAND (RAK_REGION_EU868)
#define OTAA_DEVEUI {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x88}
#define OTAA_APPEUI {0x0E, 0x0D, 0x0D, 0x01, 0x0E, 0x01, 0x02, 0x0E}
#define OTAA_APPKEY {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3E}
...
if (!api.lorawan.appeui.set(node_app_eui, 8)) {
Serial.printf("LoRaWan OTAA - set application EUI is incorrect! \r\n");
return;
}
if (!api.lorawan.appkey.set(node_app_key, 16)) {
Serial.printf("LoRaWan OTAA - set application key is incorrect! \r\n");
return;
}
if (!api.lorawan.deui.set(node_device_eui, 8)) {
Serial.printf("LoRaWan OTAA - set device EUI is incorrect! \r\n");
return;
}
if (!api.lorawan.band.set(OTAA_BAND)) {
Serial.printf("LoRaWan OTAA - set band is incorrect! \r\n");
return;
}
But make sure you disable automatic join first with AT+JOIN=0:0.
If automatic join is enabled, these commands will fail. Join will start after bootup and the commands will fail because during a join sequence, the credentials cannot be changed.
Thank you. Because nothing is showing up via serial monitor, am I able to do this part inside the .ino code too instead of inside the serial monitor?
I tried to integrate all of those suggestions and I ended up with this code:
/**
* @file RUI3-Signal-Meter-P2P-LPWAN.ino
* @author Bernd Giesecke ([email protected])
* @brief Simple signal meter for LoRa P2P and LoRaWAN
* @version 0.1
* @date 2023-11-23
*
* @copyright Copyright (c) 2023
*
*/
#include "app.h"
#define OTAA_BAND (RAK_REGION_US915)
uint8_t OTAA_DEVEUI[8] = { 0xAC,0x1F,0x09,0xFF,0xFE,0x1C,0xCE,0xE4 };
uint8_t OTAA_APPEUI[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t OTAA_APPKEY[16] = {
0x3F,0x00,0x9C,0x60, 0x61,0xEE,0x0F,0x38,
0xFB,0x29,0x27,0xCD, 0x4E,0xFC,0xEE,0x95
};
/** Last RX SNR level*/
volatile int8_t last_snr = 0;
/** Last RX RSSI level*/
volatile int16_t last_rssi = 0;
/** Link check result */
volatile uint8_t link_check_state;
/** Demodulation margin */
volatile uint8_t link_check_demod_margin;
/** Number of gateways */
volatile uint8_t link_check_gateways;
/** Sent packet counter */
volatile int32_t packet_num = 0;
/** Lost packet counter (only LPW mode)*/
volatile int32_t packet_lost = 0;
/** Last RX data rate */
volatile uint8_t last_dr = 0;
/** TX fail reason (only LPW mode)*/
volatile int32_t tx_fail_status;
/** LoRa mode */
bool lorawan_mode = true;
/** Flag if confirmed packets or LinkCheck should be used */
bool use_link_check = true;
/** Flag if OLED was found */
bool has_oled = false;
/** Buffer for OLED output */
char line_str[256];
/** Flag for display handler */
uint8_t display_reason;
/**
* @brief Send a LoRaWAN packet
*
* @param data unused
*/
void send_packet(void *data)
{
if (api.lorawan.njs.get())
{
MYLOG("APP", "Send packet");
uint8_t payload[4] = {0x01, 0x02, 0x03, 0x04};
// Always send confirmed packet to make sure a reply is received
api.lorawan.send(4, payload, 2, true, 8);
// if (use_link_check)
// {
// // Linkcheck is enabled, send an unconfirmed packet
// api.lorawan.send(4, payload, 2, false);
// }
// else
// {
// // Linkcheck is disabled, send a confirmed packet
// api.lorawan.send(4, payload, 2, true, 8);
// }
}
else
{
MYLOG("APP", "Not joined, don't send packet");
}
}
/**
* @brief Display handler
*
* @param reason 1 = RX packet display
* 2 = TX failed display (only LPW mode)
* 3 = Join failed (only LPW mode)
* 4 = Linkcheck result display (only LPW LinkCheck mode)
* 5 = Join success (only LPW mode)
*/
void handle_display(void *reason)
{
/** Update header and battery value */
if (has_oled)
{
rak1921_clear();
sprintf(line_str, "RAK Signal Meter - B %.2fV", api.system.bat.get());
rak1921_write_header(line_str);
}
// Get the wakeup reason
uint8_t *disp_reason = (uint8_t *)reason;
// Check if we have a reason
if (disp_reason == NULL)
{
Serial.println("Bug in code!");
}
else if (disp_reason[0] == 1)
{
// MYLOG("APP", "RX_EVENT %d\n", disp_reason[0]);
// RX event display
if (g_custom_parameters.test_mode == 1)
{
if (has_oled)
{
sprintf(line_str, "LPW CFM mode");
rak1921_write_line(0, 0, line_str);
sprintf(line_str, "Sent %d", packet_num);
rak1921_write_line(1, 0, line_str);
sprintf(line_str, "Lost %d", packet_lost);
rak1921_write_line(1, 64, line_str);
sprintf(line_str, "DR %d", last_dr);
rak1921_write_line(2, 0, line_str);
sprintf(line_str, "RSSI %d", last_rssi);
rak1921_write_line(3, 0, line_str);
sprintf(line_str, "SNR %d", last_snr);
rak1921_write_line(3, 64, line_str);
sprintf(line_str, "----------");
rak1921_write_line(4, 0, line_str);
rak1921_display();
}
Serial.println("LPW CFM mode");
Serial.printf("Packet # %d RSSI %d SNR %d\n", packet_num, last_rssi, last_snr);
Serial.printf("DR %d\n", last_dr);
}
else
{
if (has_oled)
{
sprintf(line_str, "LoRa P2P mode");
rak1921_write_line(0, 0, line_str);
sprintf(line_str, "Received packets %d", packet_num);
rak1921_write_line(1, 0, line_str);
sprintf(line_str, "F %.3f", (api.lora.pfreq.get() / 1000000.0));
rak1921_write_line(2, 0, line_str);
sprintf(line_str, "SF %d", api.lora.psf.get());
rak1921_write_line(3, 0, line_str);
sprintf(line_str, "BW %d", (api.lora.pbw.get() + 1) * 125);
rak1921_write_line(3, 64, line_str);
sprintf(line_str, "RSSI %d", last_rssi);
rak1921_write_line(4, 0, line_str);
sprintf(line_str, "SNR %d", last_snr);
rak1921_write_line(4, 64, line_str);
rak1921_display();
}
Serial.println("LPW P2P mode");
Serial.printf("Packet # %d RSSI %d SNR %d\n", packet_num, last_rssi, last_snr);
Serial.printf("F %.3f SF %d BW %d\n",
(float)api.lora.pfreq.get() / 1000000.0,
api.lora.psf.get(),
(api.lora.pbw.get() + 1) * 125);
}
}
else if (disp_reason[0] == 2)
{
// MYLOG("APP", "TX_ERROR %d\n", disp_reason[0]);
digitalWrite(LED_BLUE, HIGH);
if (has_oled)
{
sprintf(line_str, "LPW CFM mode");
rak1921_write_line(0, 0, line_str);
sprintf(line_str, "Sent %d", packet_num);
rak1921_write_line(1, 0, line_str);
sprintf(line_str, "Lost %d", packet_num, packet_lost);
rak1921_write_line(1, 64, line_str);
sprintf(line_str, "TX failed with status %d", tx_fail_status);
rak1921_write_line(2, 0, line_str);
}
Serial.println("LPW CFM mode");
Serial.printf("Packet %d\n", packet_num);
Serial.printf("TX failed with status %d\n", tx_fail_status);
switch (tx_fail_status)
{
case RAK_LORAMAC_STATUS_ERROR:
sprintf(line_str, "Service error");
break;
case RAK_LORAMAC_STATUS_TX_TIMEOUT:
sprintf(line_str, "TX timeout");
break;
case RAK_LORAMAC_STATUS_RX1_TIMEOUT:
sprintf(line_str, "RX1 timeout");
break;
case RAK_LORAMAC_STATUS_RX2_TIMEOUT:
sprintf(line_str, "RX2 timeout");
break;
case RAK_LORAMAC_STATUS_RX1_ERROR:
sprintf(line_str, "RX1 error");
break;
case RAK_LORAMAC_STATUS_RX2_ERROR:
sprintf(line_str, "RX2 error");
break;
case RAK_LORAMAC_STATUS_JOIN_FAIL:
sprintf(line_str, "Join failed");
break;
case RAK_LORAMAC_STATUS_DOWNLINK_REPEATED:
sprintf(line_str, "Dowlink frame error");
break;
case RAK_LORAMAC_STATUS_TX_DR_PAYLOAD_SIZE_ERROR:
sprintf(line_str, "Payload size error");
break;
case RAK_LORAMAC_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS:
sprintf(line_str, "Fcnt loss error");
break;
case RAK_LORAMAC_STATUS_ADDRESS_FAIL:
sprintf(line_str, "Adress error");
break;
case RAK_LORAMAC_STATUS_MIC_FAIL:
sprintf(line_str, "MIC error");
break;
case RAK_LORAMAC_STATUS_MULTICAST_FAIL:
sprintf(line_str, "Multicast error");
break;
case RAK_LORAMAC_STATUS_BEACON_LOCKED:
sprintf(line_str, "Beacon locked");
break;
case RAK_LORAMAC_STATUS_BEACON_LOST:
sprintf(line_str, "Beacon lost");
break;
case RAK_LORAMAC_STATUS_BEACON_NOT_FOUND:
sprintf(line_str, "Beacon not found");
break;
default:
sprintf(line_str, "Unknown error");
break;
}
Serial.printf("%s\n", line_str);
Serial.printf("Lost %d packets\n", packet_lost);
if (has_oled)
{
rak1921_write_line(3, 0, line_str);
sprintf(line_str, "----------");
rak1921_write_line(4, 0, line_str);
rak1921_display();
}
}
else if (disp_reason[0] == 3)
{
// MYLOG("APP", "JOIN_ERROR %d\n", disp_reason[0]);
if (has_oled)
{
sprintf(line_str, "LPW mode");
rak1921_write_line(0, 0, line_str);
rak1921_write_line(1, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
rak1921_write_line(2, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
sprintf(line_str, "Join failed");
rak1921_write_line(3, 0, line_str);
rak1921_write_line(4, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
rak1921_display();
}
}
else if (disp_reason[0] == 5)
{
// MYLOG("APP", "JOIN_SUCCESS %d\n", disp_reason[0]);
if (has_oled)
{
sprintf(line_str, "LPW mode");
rak1921_write_line(0, 0, line_str);
rak1921_write_line(1, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
rak1921_write_line(2, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
sprintf(line_str, "Device joined network");
rak1921_write_line(3, 0, line_str);
rak1921_write_line(4, 0, (char *)"!!!!!!!!!!!!!!!!!!!");
rak1921_display();
}
}
else if (disp_reason[0] == 4)
{
// MYLOG("APP", "LINK_CHECK %d\n", disp_reason[0]);
// LinkCheck result event display
if (has_oled)
{
sprintf(line_str, "LPW LinkCheck %s", link_check_state == 0 ? "OK" : "NOK");
rak1921_write_line(0, 0, line_str);
if (link_check_state == 0)
{
sprintf(line_str, "Demod Margin %d", link_check_demod_margin);
rak1921_write_line(1, 0, line_str);
sprintf(line_str, "Sent %d", packet_num);
rak1921_write_line(2, 0, line_str);
sprintf(line_str, "Lost %d", packet_lost);
rak1921_write_line(2, 64, line_str);
sprintf(line_str, "%d GW(s)", link_check_gateways);
rak1921_write_line(3, 0, line_str);
sprintf(line_str, "DR %d", api.lorawan.dr.get());
rak1921_write_line(3, 64, line_str);
sprintf(line_str, "RSSI %d", last_rssi);
rak1921_write_line(4, 0, line_str);
sprintf(line_str, "SNR %d", last_snr);
rak1921_write_line(4, 64, line_str);
}
else
{
sprintf(line_str, "Sent %d", packet_num);
rak1921_write_line(1, 0, line_str);
sprintf(line_str, "Lost %d", packet_lost);
rak1921_write_line(1, 64, line_str);
sprintf(line_str, "LinkCheck result %d ", link_check_state);
rak1921_write_line(2, 0, line_str);
switch (link_check_state)
{
case RAK_LORAMAC_STATUS_ERROR:
sprintf(line_str, "Service error");
break;
case RAK_LORAMAC_STATUS_TX_TIMEOUT:
sprintf(line_str, "TX timeout");
break;
case RAK_LORAMAC_STATUS_RX1_TIMEOUT:
sprintf(line_str, "RX1 timeout");
break;
case RAK_LORAMAC_STATUS_RX2_TIMEOUT:
sprintf(line_str, "RX2 timeout");
break;
case RAK_LORAMAC_STATUS_RX1_ERROR:
sprintf(line_str, "RX1 error");
break;
case RAK_LORAMAC_STATUS_RX2_ERROR:
sprintf(line_str, "RX2 error");
break;
case RAK_LORAMAC_STATUS_JOIN_FAIL:
sprintf(line_str, "Join failed");
break;
case RAK_LORAMAC_STATUS_DOWNLINK_REPEATED:
sprintf(line_str, "Dowlink frame error");
break;
case RAK_LORAMAC_STATUS_TX_DR_PAYLOAD_SIZE_ERROR:
sprintf(line_str, "Payload size error");
break;
case RAK_LORAMAC_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS:
sprintf(line_str, "Fcnt loss error");
break;
case RAK_LORAMAC_STATUS_ADDRESS_FAIL:
sprintf(line_str, "Adress error");
break;
case RAK_LORAMAC_STATUS_MIC_FAIL:
sprintf(line_str, "MIC error");
break;
case RAK_LORAMAC_STATUS_MULTICAST_FAIL:
sprintf(line_str, "Multicast error");
break;
case RAK_LORAMAC_STATUS_BEACON_LOCKED:
sprintf(line_str, "Beacon locked");
break;
case RAK_LORAMAC_STATUS_BEACON_LOST:
sprintf(line_str, "Beacon lost");
break;
case RAK_LORAMAC_STATUS_BEACON_NOT_FOUND:
sprintf(line_str, "Beacon not found");
break;
default:
sprintf(line_str, "Unknown error");
break;
}
rak1921_write_line(3, 0, line_str);
}
rak1921_display();
}
Serial.printf("LinkCheck %s\n", link_check_state == 0 ? "OK" : "NOK");
Serial.printf("Packet # %d RSSI %d SNR %d\n", packet_num, last_rssi, last_snr);
Serial.printf("GW # %d Demod Margin %d\n", link_check_gateways, link_check_demod_margin);
}
digitalWrite(LED_GREEN, LOW);
}
/**
* @brief Join network callback
*
* @param status status of join request
*/
void join_cb_lpw(int32_t status)
{
if (status != 0)
{
display_reason = 3;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
else
{
display_reason = 5;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
}
/**
* @brief Receive callback for LoRa P2P mode
*
* @param data structure with RX packet information
*/
void recv_cb_p2p(rui_lora_p2p_recv_t data)
{
digitalWrite(LED_GREEN, HIGH);
last_rssi = data.Rssi;
last_snr = data.Snr;
packet_num++;
display_reason = 1;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
/**
* @brief Receive callback for LoRaWAN mode
*
* @param data structure with RX packet information
*/
void recv_cb_lpw(SERVICE_LORA_RECEIVE_T *data)
{
digitalWrite(LED_GREEN, HIGH);
last_rssi = data->Rssi;
last_snr = data->Snr;
last_dr = data->RxDatarate;
packet_num++;
if (!use_link_check)
{
display_reason = 1;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
}
/**
* @brief Send finished callback for LoRaWAN mode
*
* @param status
*/
void send_cb_lpw(int32_t status)
{
if (status != RAK_LORAMAC_STATUS_OK)
{
MYLOG("APP", "LMC status %d\n", RAK_LORAMAC_STATUS_OK);
tx_fail_status = status;
if (!use_link_check)
{
packet_lost++;
display_reason = 2;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
}
}
/**
* @brief Linkcheck callback
*
* @param data structure with the result of the Linkcheck
*/
void linkcheck_cb_lpw(SERVICE_LORA_LINKCHECK_T *data)
{
// MYLOG("APP", "linkcheck_cb_lpw\n");
last_snr = data->Snr;
last_rssi = data->Rssi;
link_check_state = data->State;
link_check_demod_margin = data->DemodMargin;
link_check_gateways = data->NbGateways;
if (data->State != 0)
{
packet_lost++;
}
display_reason = 4;
api.system.timer.start(RAK_TIMER_1, 250, &display_reason);
}
/**
* @brief Setup routine
*
*/
void setup(void)
{
api.lorawan.join(0, 0, 0, 0);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
Serial.begin(115200);
if (!api.lorawan.appeui.set((uint8_t *)OTAA_APPEUI, 8)) {
Serial.println("Failed to set AppEUI");
return;
}
if (!api.lorawan.appkey.set((uint8_t *)OTAA_APPKEY, 16)) {
Serial.println("Failed to set AppKey");
return;
}
if (!api.lorawan.deui.set((uint8_t *)OTAA_DEVEUI, 8)) {
Serial.println("Failed to set DevEUI");
return;
}
if (!api.lorawan.band.set(OTAA_BAND)) {
Serial.printf("LoRaWan OTAA - set band is incorrect! \r\n");
return;
}
sprintf(line_str, "RUI3_Tester_V%d.%d.%d", SW_VERSION_0, SW_VERSION_1, SW_VERSION_2);
api.system.firmwareVersion.set(line_str);
// Check if OLED is available
Wire.begin();
has_oled = init_rak1921();
if (has_oled)
{
sprintf(line_str, "RAK Signal Meter - B %.2fV", api.system.bat.get());
rak1921_write_header(line_str);
}
digitalWrite(LED_GREEN, HIGH);
#ifndef RAK3172
time_t serial_timeout = millis();
// On nRF52840 the USB serial is not available immediately
while (!Serial.available())
{
if ((millis() - serial_timeout) < 5000)
{
delay(100);
digitalWrite(LED_GREEN, !digitalRead(LED_GREEN));
}
else
{
break;
}
}
#else
digitalWrite(LED_GREEN, HIGH);
delay(5000);
#endif
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_BLUE, LOW);
if (!has_oled)
{
MYLOG("APP", "No OLED found");
}
// Initialize custom AT commands
if (!init_status_at())
{
MYLOG("APP", "Failed to initialize Status AT command");
}
if (!init_interval_at())
{
MYLOG("APP", "Failed to initialize Send Interval AT command");
}
if (!init_test_mode_at())
{
MYLOG("APP", "Failed to initialize Test Mode AT command");
}
// Get saved custom settings
if (!get_at_setting())
{
MYLOG("APP", "Failed to read saved custom settings");
}
// Setup callbacks and timers depending on test mode
switch (g_custom_parameters.test_mode)
{
default:
Serial.println("Invalid test mode, use LinkCheck");
if (has_oled)
{
sprintf(line_str, "Invalid test mode");
rak1921_write_line(0, 0, line_str);
sprintf(line_str, "Using LinkCheck");
rak1921_write_line(1, 0, line_str);
rak1921_display();
}
case MODE_LINKCHECK:
set_linkcheck();
break;
case MODE_CFM:
set_cfm();
break;
case MODE_P2P:
set_p2p();
break;
}
if (lorawan_mode)
{
api.system.timer.create(RAK_TIMER_0, send_packet, RAK_TIMER_PERIODIC);
if (g_custom_parameters.send_interval != 0)
{
api.system.timer.start(RAK_TIMER_0, g_custom_parameters.send_interval, NULL);
}
api.system.timer.create(RAK_TIMER_1, handle_display, RAK_TIMER_ONESHOT);
}
else
{
api.system.timer.create(RAK_TIMER_1, handle_display, RAK_TIMER_ONESHOT);
}
// If LoRaWAN, start join if required
if (lorawan_mode)
{
if (!api.lorawan.njs.get())
{
api.lorawan.join();
}
}
MYLOG("APP", "Start testing");
// Enable low power mode
api.system.lpm.set(1);
}
/**
* @brief Loop (unused)
*
*/
void loop(void)
{
api.system.sleep.all();
}
/**
* @brief Set the module for LoRaWAN Confirmed Packet testing
*
*/
void set_cfm(void)
{
MYLOG("APP", "Found CFM Mode");
use_link_check = false;
lorawan_mode = true;
// Force LoRaWAN mode (might cause restart)
api.lorawan.nwm.set();
// Register callbacks
api.lorawan.registerRecvCallback(recv_cb_lpw);
api.lorawan.registerSendCallback(send_cb_lpw);
api.lorawan.registerJoinCallback(join_cb_lpw);
// Set confirmed packet mode
api.lorawan.cfm.set(true);
// Disable LinkCheck
api.lorawan.linkcheck.set(0);
if (!api.lorawan.join(1, 1, 10, 50))
{
MYLOG("APP", "Failed to start JOIN");
}
}
/**
* @brief Set the module for LoRaWAN LinkCheck testing
*
*/
void set_linkcheck(void)
{
MYLOG("APP", "Found LinkCheck Mode");
use_link_check = true;
lorawan_mode = true;
// Force LoRaWAN mode (might cause restart)
api.lorawan.nwm.set();
// Register callbacks
api.lorawan.registerRecvCallback(recv_cb_lpw);
api.lorawan.registerSendCallback(send_cb_lpw);
api.lorawan.registerJoinCallback(join_cb_lpw);
api.lorawan.registerLinkCheckCallback(linkcheck_cb_lpw);
// Set unconfirmed packet mode
api.lorawan.cfm.set(false);
// Disable LinkCheck
api.lorawan.linkcheck.set(2);
if (!api.lorawan.join(1, 1, 10, 50))
{
MYLOG("APP", "Failed to start JOIN");
}
}
/**
* @brief Set the module for LoRa P2P testing
*
*/
void set_p2p(void)
{
MYLOG("APP", "Found P2P Mode");
lorawan_mode = false;
if (!api.lorawan.join(0, 0, 10, 50))
{
MYLOG("APP", "Failed to stop JOIN");
}
if (!api.lora.precv(0))
{
MYLOG("APP", "Failed to stop P2P RX");
}
// Force LoRa P2P mode (might cause restart)
if (!api.lora.nwm.set())
{
MYLOG("APP", "Failed to set P2P Mode");
}
// Register callbacks
api.lora.registerPRecvCallback(recv_cb_p2p);
// Enable RX mode
api.lora.precv(65533);
}
However I still get random DevEUI and AppEUIs being generated:
Unfortunately last day this season to do the field test is tomorrow morning (in 12 hours from now for my time zone). I will catch you up on everything I tried to see if we can figure this out. I greatly appreciate your help!
So I started with another, brand new Wisblock RAK4631/RAK19007 (with LoRa antenna, bluetooth antenna, and 3.7V 5000mAh lithium polymer rechargeable battery). Out of the box I tried to do AT commands to get or set the AppEUI, but it didn’t react to commands in RAK serial monitor or Arduino IDE serial monitor. I would type the command, press enter, and the command would disappear and nothing would change in the serial monitor output. The Arduino IDE serial monitor output looked like this:
e[0me[32mINFO e[0m| ??:??:?? 121 [DeviceTelemetry] e[32mSend: air_util_tx=0.000000, channel_utilization=0.000000, battery_level=101, voltage=4.185000, uptime=121
e[0me[34mDEBUG e[0m| ??:??:?? 121 [DeviceTelemetry] e[34mPartially randomized packet id 3481816558
e[0me[34mDEBUG e[0m| ??:??:?? 121 [DeviceTelemetry] e[34mupdateTelemetry LOCAL
e[0me[34mDEBUG e[0m| ??:??:?? 121 [DeviceTelemetry] e[34mNode status update: 1 online, 1 total
e[0me[32mINFO e[0m| ??:??:?? 121 [DeviceTelemetry] e[32mSend packet to phone
e[0me[32mINFO e[0m| ??:??:?? 121 [DeviceTelemetry] e[32mSending local stats: uptime=121, channel_utilization=0.000000, air_util_tx=0.000000, num_online_nodes=1, num_total_nodes=1
e[0me[32mINFO e[0m| ??:??:?? 121 [DeviceTelemetry] e[32mnum_packets_tx=0, num_packets_rx=0, num_packets_rx_bad=0
e[0me[34mDEBUG e[0m| ??:??:?? 121 [DeviceTelemetry] e[34mPartially randomized packet id 2289684975
e[0m
Then I did the following:
- Download & unzip these files into the folder:
- adafruit-nrfutil.exe
- rui3_nrf52840_bootloader
- Connect RAK4631-R via USB
- Double click reset button on device
- Check COM port via Device Manager (Windows + X > Device Manager > Ports).
- If not detected, double-click the reset button on the WisBlock Base.
- Open Command Prompt as Administrator.
- Navigate to the folder:
cd C:\RAK4631 Bootloader to RUI v3\
- Run this command (replace <COM#> with your actual port number):
adafruit-nrfutil.exe --verbose dfu serial --package rui3_nrf52840_bootloader_latest.zip --port COM<COM#> -b 115200 --singlebank --touch 1200
I then tried AT commands in Arduino IDE and RAK serial monitor again at that stage. It didn’t react at all and there was no output in the Arduino IDE serial monitor.
I then did this:
- After upgrade, note the new COM port number (e.g., COM31 to COM32).
- Download Firmware Files
- Download & place these files in the same folder:
- nrfutil.exe
- rui3_rak4631_latest
- In Command Prompt (Administrator), navigate to the folder:
- cd C:\RAK4631 Bootloader to RUI v3\
- Run this command (replace <COM#> with your actual port number):
- nrfutil.exe dfu serial -pkg rui3_rak4631_latest.zip -p COM<COM#>
- Download and unzip the .ino repo:
- Rename unzipped folder to “RUI3-Signal-Meter-P2P-LPWAN” (to match .ino file name). (Besides renaming the folder I did not modify anything at all, including not modifying anything in the .ino file)
- In Arduino IDE:
- Install libraries:
- RUI3-Arduino-Library
- nRF_SSD1306
- File > Open > Navigate to the downloaded .ino file.
- Double-click the restart button on the board.
- Tools > Board > WisBlock Boards > Connect the correct COM port for RAK4631.
- Upload the script.
- Install libraries:
- In Wisgate:
- Overview > Packet Monitor > Download Session
- Read JSON file to see new DevEUI and JoinEUI that were assigned
At that point I noticed that it was randomly assigning new DevEUI and JoinEUIs at each join request
So I tried to implement your suggestions for modifying the .ino file but DevEUI/JoinEUIs were still random. I tried making a super basic script based on your script:
#include "app.h"
#define OTAA_BAND (RAK_REGION_US915)
// Your hardcoded credentials
static const uint8_t OTAA_DEVEUI[8] = { 0xAC, 0x1F, 0x09, 0xFF, 0xFE, 0x1C, 0xCE, 0xE4 };
static const uint8_t OTAA_APPEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t OTAA_APPKEY[16] = {
0x3F, 0x00, 0x9C, 0x60, 0x61, 0xEE, 0x0F, 0x38,
0xFB, 0x29, 0x27, 0xCD, 0x4E, 0xFC, 0xEE, 0x95
};
void join_cb(int32_t status)
{
if (status == 0)
Serial.println("Join successful!");
else
Serial.printf("Join failed. Status: %ld\n", status);
}
void setup()
{
Serial.begin(115200);
delay(2000);
Serial.println("Starting minimal LoRaWAN sketch...");
// Kill auto-join
api.lorawan.join(0, 0, 0, 0);
api.lorawan.nwm.set();
api.lorawan.njm.set(RAK_LORA_OTAA);
api.lorawan.band.set(OTAA_BAND);
// Set credentials MULTIPLE times just to be sure
for (int i = 0; i < 3; i++) {
api.lorawan.deui.set((uint8_t *)OTAA_DEVEUI, 8);
api.lorawan.appeui.set((uint8_t *)OTAA_APPEUI, 8);
api.lorawan.appkey.set((uint8_t *)OTAA_APPKEY, 16);
}
// Print back the credentials to confirm
uint8_t buf[16];
api.lorawan.deui.get(buf, 8);
Serial.print("DevEUI: ");
for (int i = 0; i < 8; i++) Serial.printf("%02X", buf[i]);
Serial.println();
api.lorawan.appeui.get(buf, 8);
Serial.print("AppEUI: ");
for (int i = 0; i < 8; i++) Serial.printf("%02X", buf[i]);
Serial.println();
api.lorawan.appkey.get(buf, 16);
Serial.print("AppKey: ");
for (int i = 0; i < 16; i++) Serial.printf("%02X", buf[i]);
Serial.println();
// Register join callback
api.lorawan.registerJoinCallback(join_cb);
// Start join process
if (!api.lorawan.join())
{
Serial.println("Join request failed to start.");
}
else
{
Serial.println("Join request sent...");
}
}
void loop()
{
api.system.sleep.all();
}
But that did not work either so I am unsure what to try next
I am lost, the device does not generate DevEUI’s by itself. It uses whatever is set with AT+DEVEUI or api.lorawan.deui.set(). There must be something happening on the Gateway or in the LoRaWAN server.
This kind of debug output is generated by Meshtastic firmware. It has nothing to do with LoRaWAN:
e[0me[34mDEBUG e[0m| ??:??:?? 121 [DeviceTelemetry] e[34mPartially randomized packet id 3481816558
Hello. Thank you for trying. I downloaded Wisblock Toolbox desktop app to see if that help
Hello,
I have been thinking some more. Even though the packets are being rejected on the gateway, when I have my field gateway within line of sight of the Ethernet gateway, is there a chance I would see some change when I review the live feeds on TTN due to the join requests alone?
A gateway is not “rejecting” any packets if they come in on the selected frequencies and data rates.
It is just forwarding them to the LoRaWAN server.
Of course it makes more sense to check the log in TTN, but I am thinking the packets are never arriving there.
Oh yeah, I guess I wasn’t clear in my language
If I have my RAK4631 attempting to join using your script next to my non-internet connected gateway, but I am within line of sight of the Ethernet-connected gateway, is there any chance that even though TTN is rejecting the join requests would I see any changes to the TTN log (like that my non-internet connected gateway was connected) when I return back to my WiFi connection?
If the join request reaches the second gateway (with Ethernet connection), TTN should see the join request and process it.
Thank you, even if the join request is rejected (which it will be because of the random DevEUI and AppEUIs)? Will I see the join requests in the packet capture of the Ethernet-connected gateway or what should I look for?
I was thinking maybe I would see the last connected value change on TTN?
Your screenshot only tells me that the gateway never sent any uplinks to TTN.
Here is my gateway on TTN.
You are connected with Basic Station protocol? :// SEMTECHWS/LBSLNS
In General Settings of the gateway in TTN, are you sure you have selected the correct Frequency plan?
Thank you, yeah it is set to the correct frequency:
Should I switch from basics station to packet forwarder for the field gateway and/or the Ethernet-connected gateway?
Would I see this populate with rejected join requests for my Ethernet-gateway if it was able to connect to my field gateway via line of sight, with the RAK4631 next to the field gateway?
Oh wow, I feel silly but I just noticed something. I am still getting rejected random join requests when my RAK4631 is off and even when I remove the battery. So the join requests were not coming from my RAK4631
Hi @CLehnen ,
I have other idea that might cause the issue. Since you are using US915 and the default band on TTN, the missing join uplinks can be possibly attributed to the unset sub-band channels.
TTN US915 default uses sub-band 2.
You can quickly try to configured this via AT command on your WisDuo module by sending AT+MASK=0002.






