Wisblock RAK19007 and RAK7240CV2 Gateway

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.

Added my gateway and the RAK10706 on TTN (but using AS923-3) and it works without any issues.

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?

As shown in our Documentation Center for RUI3 API:
api.lorawan.join(0,0,30,10);

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:

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:

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.