Uplinks drop after a few packets

Hi,

I’m running a LoRaWAN node in AU915 on TTN (fsb 2). The hardware is an ESP32 and an SX1276 module using radiolib (7.2.1).
On boot, joining works fine. I adapted the session restore example in the radiolib-persistence repo for ESP-IDF, and that seems to work fine.

The problem is, that uplinks work initially for about 5-10 uplinks (spaced over 30 mins) then the node goes “silent”. Nothing in the gateway live data. Nothing in the node live data. On my node, it keeps happily reporting success, with either radiolib code 0 or 1.

My gateway has a 12db omni antenna and is about 20m away from the node (with walls in between), so I don’t think it being too close should be an issue, and certainly not too far. RSSI is around -75 and SNR 13.

I tried disabling ADR and using SF7 and SF9. It looks like some packets go through, perhaps more than with ADR, but they still kind of just peter out after a while.

I also tried disabling the dutycycle temporarily (although if im not mistaken, Australia does not enforce duty cycle?) but this did not solve the problem.

If anyone has any ideas or could help further diagnose this issue, it would be greatly appreciated.

Nikolai

Code:

I have cut out a lot of the app-specific code for making the node actually collect the data, so sorry if there are parts missing.

#define SLEEP_INTERVAL_US (30ULL * 60ULL * 1000000ULL)

#define RADIOLIB_LORAWAN_JOIN_EUI REDACTED
#define RADIOLIB_LORAWAN_DEV_EUI REDACTED
#define RADIOLIB_LORAWAN_APP_KEY REDACTED
#define RADIOLIB_LORAWAN_NWK_KEY REDACTED

#define RADIOLIB_LORAWAN_REGION AU915
#define RADIOLIB_LORAWAN_SUB_BAND 2

#define LORAWAN_SAVE_BOOTCOUNT 10

int radioLibState;

extern RTC_DATA_ATTR uint8_t LWsession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE]; // from lorawan_storage.cpp

uint64_t joinEUI = RADIOLIB_LORAWAN_JOIN_EUI;
uint64_t devEUI = RADIOLIB_LORAWAN_DEV_EUI;
uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY };
uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY };

EspHal *hal = new EspHal(SPI_SCK_PIN, SPI_MISO_PIN, SPI_MOSI_PIN);

const LoRaWANBand_t Region = RADIOLIB_LORAWAN_REGION;
const uint8_t subBand = RADIOLIB_LORAWAN_SUB_BAND;

SX1276 radio = new Module(
	hal,
	SX1276_CS_PIN,
	SX1276_IRQ_PIN,
	SX1276_RST_PIN,
	SX1276_BUSY_PIN);

LoRaWANNode node(&radio, &Region, subBand);

RTC_DATA_ATTR int bootCount = 0;

static const char *TAG = "main";

extern "C" void app_main(void)
{
	bootCount++;
	ESP_LOGI(TAG, "Boot count: %d", bootCount);

	// initialise NVS
	esp_err_t err = nvs_flash_init();
	if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
	    err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
		ESP_ERROR_CHECK(nvs_flash_erase());
		ESP_ERROR_CHECK(nvs_flash_init());
	}

	// Initializ
se radio and join LoRaWAN network
	ESP_LOGI(TAG, "[SX1276] Initialising radio...");
	radioLibState = radio.begin();
	if (radioLibState != RADIOLIB_ERR_NONE) {
		ESP_LOGE(TAG, "Failed to initialise radio: %d", radioLibState);
		return;
	}
	ESP_LOGI(TAG, "[LoRaWAN] Initialising node...");
	radioLibState = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);
	if (radioLibState != RADIOLIB_ERR_NONE) {
		ESP_LOGE(TAG, "Failed to initialise LoRaWAN node: %d", radioLibState);
		return;
	}

	radioLibState = lwActivate(node);

        // device-specific logic for collecting data omitted for brevity

	size_t uplink_len = 0;

	if (uplink_len > 0) {
		ESP_LOGI(TAG, "Built uplink payload with %zu bytes", uplink_len);
		radioLibState = node.sendReceive(uplink_payload, uplink_len);
		ESP_LOGI(TAG, "Radiolib code: %d, FCntUp now %" PRIu32, radioLibState, node.getFCntUp());
		memcpy(LWsession, node.getBufferSession(), RADIOLIB_LORAWAN_SESSION_BUF_SIZE);
	} else {
		ESP_LOGW(TAG, "Nothing to send (payload %zu bytes)",uplink_len);
	}

	esp_sleep_enable_timer_wakeup(SLEEP_INTERVAL_US);
	ESP_LOGI(TAG, "Entering deep sleep for %u seconds…", (unsigned)(SLEEP_INTERVAL_US / 1000000ULL));
	esp_deep_sleep_start();
}

And the lwActivate() function:

#define MIN(a, b) (((a) < (b)) ? (a) : (b))

extern RTC_DATA_ATTR int bootCount;
RTC_DATA_ATTR static int bootCountSinceUnsuccessfulJoin = 0;
RTC_DATA_ATTR uint8_t LWsession[RADIOLIB_LORAWAN_SESSION_BUF_SIZE];

int lwActivate(LoRaWANNode& node)
{
	int state = RADIOLIB_ERR_UNKNOWN;
	nvs_handle_t handle;

	ESP_LOGI(TAG, "Recalling nonces and session...");

	if (nvs_open(LORAWAN_NAMESPACE, NVS_READONLY, &handle) == ESP_OK) {
		size_t len = RADIOLIB_LORAWAN_NONCES_BUF_SIZE;
		uint8_t buffer[RADIOLIB_LORAWAN_NONCES_BUF_SIZE];
		if (nvs_get_blob(handle, LORAWAN_KEY_NONCES, buffer, &len) == ESP_OK) {
			state = node.setBufferNonces(buffer);
			if (state != RADIOLIB_ERR_NONE)
				ESP_LOGE(TAG, "Failed to set nonces buffer: %d", state);
			else
				ESP_LOGI(TAG, "Nonces buffer restored successfully.");
		}
		state = node.setBufferSession(LWsession);
		if (state != RADIOLIB_ERR_NONE && bootCount > 1)
			ESP_LOGE(TAG, "Restoring session buffer failed (code: %d, bootCount: %d)",
				 state, bootCount);
		else
			ESP_LOGI(TAG, "Session buffer restored successfully.");
		nvs_close(handle);
		if (state == RADIOLIB_ERR_NONE) {
			ESP_LOGI(TAG, "Session restored successfully. Attempting to join...");
			state = node.activateOTAA(3);
			if (state != RADIOLIB_LORAWAN_SESSION_RESTORED)
				ESP_LOGE(TAG, "Failed to restore session: %d", state);
			else
				ESP_LOGI(TAG, "Session restored successfully.");
			return state;
		}
	} else {
		ESP_LOGI(TAG, "No nonces found in NVS, starting new session...");
	}

	state = RADIOLIB_ERR_NETWORK_NOT_JOINED;

	while (state != RADIOLIB_LORAWAN_NEW_SESSION) {
		ESP_LOGI(TAG, "Attempting to join network...");
		state = node.activateOTAA();

		ESP_LOGI(TAG, "Saving nonces to flash...");
		if (nvs_open(LORAWAN_NAMESPACE, NVS_READWRITE, &handle) == ESP_OK) {
			const uint8_t *persist = node.getBufferNonces();
			if (nvs_set_blob(handle, LORAWAN_KEY_NONCES,
					 persist, RADIOLIB_LORAWAN_NONCES_BUF_SIZE) == ESP_OK) {
				nvs_commit(handle);
				ESP_LOGI(TAG, "Nonces saved successfully.");
			} else {
				ESP_LOGE(TAG, "Failed to save nonces to flash.");
			}
			nvs_close(handle);
		}

		if (state != RADIOLIB_LORAWAN_NEW_SESSION) {
			ESP_LOGI(TAG, "Join failed: %d", state);
			int sleepForSeconds = MIN((bootCountSinceUnsuccessfulJoin + 1) * 60, 180);
			bootCountSinceUnsuccessfulJoin++;
			ESP_LOGI(TAG, "Boots since last successful join: %d",
				 bootCountSinceUnsuccessfulJoin);
			ESP_LOGI(TAG, "Retrying in %d seconds...", sleepForSeconds);
			esp_sleep_enable_timer_wakeup(uint64_t(sleepForSeconds) * 1000000ULL);
			esp_deep_sleep_start();
		}
	}

	ESP_LOGI(TAG, "Join successful!");
	bootCountSinceUnsuccessfulJoin = 0;
	vTaskDelay(1000 / portTICK_PERIOD_MS);
	return state;
}

Hi @artichoke,

To find out whether this something with your device or on the TTN side, you can try investigating the device & gateway logs.
To get device logs, you can enable the DEBUG_PROTOCOL flag in BuildOptUser.h in the RadioLib source folder. Do you have access to gateway logs as well?

If you can share here what you see in both their logs, I’m sure we’ll be able to help.