Commit downlink tx_interval to memory RAK4630

Hi, I have a working sketch for a pressure transducer, which includes the ability to modify the tx_interval via downlink. I also use a reset after a certain number of uplinks. The problem I encounter is when I manually reset the device or it resets via the count, the tx_interval resets to the original timing…
Is it possible to commit this interval to memory so it calls that instead? Here’s the sketch…

#include <Arduino.h>

#include <SPI.h>

#include <LoRaWan-RAK4630.h>

#include <nrf_nvic.h>

/* Time the device is sleeping in milliseconds = 2 minutes * 60 seconds * 1000 milliseconds */

uint32_t tx_interval_start = 60000;

int tx_interval = 7200000;

int change_tx_after = 10;

int tx_reset_count = 2500;

int current_sensor_payload;

TimerEvent_t appTimer;

static uint32_t timers_init(void);

static uint32_t count = 1;

//Battery Voltage************************************************************************

#define PIN_VBAT WB_A0

uint32_t vbat_pin = PIN_VBAT;

#define VBAT_MV_PER_LSB (0.73242188F)  // 3.0V ADC range and 12 - bit ADC resolution = 3000mV / 4096

#define VBAT_DIVIDER_COMP (1.73)       // Compensation factor for the VBAT divider, depend on the board

#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)

/** DIO1 GPIO pin for RAK4631 */

#define PIN_LORA_DIO_1 47

//Battery Voltage************************************************************************

// LoRaWan stuff

int8_t initLoRaWan(void);

bool sendLoRaFrame(void);

extern SemaphoreHandle_t loraEvent;

// Main loop stuff

void periodicWakeup(TimerHandle_t unused);

extern SemaphoreHandle_t taskEvent;

extern uint8_t rcvdLoRaData[];

extern uint8_t rcvdDataLen;

extern uint8_t eventType;

extern SoftwareTimer taskWakeupTimer;

/** Semaphore used by events to wake up loop task */

SemaphoreHandle_t taskEvent = NULL;

/** Timer to wakeup task frequently and send message */

SoftwareTimer taskWakeupTimer;

/** Buffer for received LoRaWan data */

uint8_t rcvdLoRaData[256];

/** Length of received data */

uint8_t rcvdDataLen = 0;

uint8_t eventType = -1;

/**

 * @brief Timer event that wakes up the loop task frequently

 *

 * @param unused

 */

void periodicWakeup(TimerHandle_t unused) {

  // Switch off blue LED to save power during sleep

  digitalWrite(LED_CONN, LOW);

  eventType = 1;

  // Give the semaphore, so the loop task will wake up

  xSemaphoreGiveFromISR(taskEvent, pdFALSE);

}

/** Max size of the data to be transmitted. */

#define LORAWAN_APP_DATA_BUFF_SIZE 64

/** Number of trials for the join request. */

#define JOINREQ_NBTRIALS 8

/** Lora application data buffer. */

static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];

/** Lora application data structure. */

static lmh_app_data_t m_lora_app_data = { m_lora_app_data_buffer, 0, 0, 0, 0 };

// LoRaWan event handlers

/** LoRaWan callback when join network finished */

static void lorawan_has_joined_handler(void);

/** LoRaWan callback when join failed */

static void lorawan_join_failed_handler(void);

/** LoRaWan callback when data arrived */

static void lorawan_rx_handler(lmh_app_data_t *app_data);

/** LoRaWan callback after class change request finished */

static void lorawan_confirm_class_handler(DeviceClass_t Class);

/** LoRaWan Function to send a package */

bool sendLoRaFrame(void);

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()

 *

 * Set structure members to

 * LORAWAN_ADR_ON or LORAWAN_ADR_OFF to enable or disable adaptive data rate

 * LORAWAN_DEFAULT_DATARATE OR DR_0 ... DR_5 for default data rate or specific data rate selection

 * LORAWAN_PUBLIC_NETWORK or LORAWAN_PRIVATE_NETWORK to select the use of a public or private network

 * JOINREQ_NBTRIALS or a specific number to set the number of trials to join the network

 * LORAWAN_DEFAULT_TX_POWER or a specific number to set the TX power used

 * LORAWAN_DUTYCYCLE_ON or LORAWAN_DUTYCYCLE_OFF to enable or disable duty cycles

 *                   Please note that ETSI mandates duty cycled transmissions.

 */

static lmh_param_t lora_param_init = { LORAWAN_ADR_ON, DR_0, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_DEFAULT_TX_POWER, LORAWAN_DUTYCYCLE_OFF };

/** Structure containing LoRaWan callback functions, needed for lmh_init() */

static lmh_callback_t lora_callbacks = { BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,

                                         lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler };

//  !!!! KEYS ARE MSB !!!!

/** Device EUI required for OTAA network join */

uint8_t nodeDeviceEUI[8] = {  };

/** Application EUI required for network join */

uint8_t nodeAppEUI[8] = {  };

/** Application key required for network join */

uint8_t nodeAppKey[16] = {  };

/** Device address required for ABP network join */

uint32_t nodeDevAddr = 0x26021FB6;

/** Network session key required for ABP network join */

uint8_t nodeNwsKey[16] = {  };

/** Application session key required for ABP network join */

uint8_t nodeAppsKey[16] = {  };

/** Flag whether to use OTAA or ABP network join method */

bool doOTAA = true;

DeviceClass_t gCurrentClass = CLASS_A;                 /* class definition*/

LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_AU915; /* Region:EU868*/

/**

 * @brief Initialize LoRa HW and LoRaWan MAC layer

 *

 * @return int8_t result

 *  0 => OK

 * -1 => SX126x HW init failure

 * -2 => LoRaWan MAC initialization failure

 * -3 => Subband selection failure

 * -4 => LoRaWan handler task start failure

 */

int8_t initLoRaWan(void) {

  Serial.printf("<<>> lora_rak4630_init called at %dms\n", millis());

  // Initialize LoRa chip.

  if (lora_rak4630_init() != 0) {

    return -1;

  }

  Serial.printf("<<>> lora_rak4630_init finished at %dms\n", millis());

  delay(100);

  // Setup the EUIs and Keys

  if (doOTAA) {

    lmh_setDevEui(nodeDeviceEUI);

    lmh_setAppEui(nodeAppEUI);

    lmh_setAppKey(nodeAppKey);

  } else {

    lmh_setNwkSKey(nodeNwsKey);

    lmh_setAppSKey(nodeAppsKey);

    lmh_setDevAddr(nodeDevAddr);

  }

  Serial.printf("<<>> lmh_init called at %dms\n", millis());

  // Initialize LoRaWan

  if (lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion) != 0) {

    return -2;

  }

  Serial.printf("<<>> lmh_init finished at %dms\n", millis());

  delay(100);

  // For some regions we might need to define the sub band the gateway is listening to

  // This must be called AFTER lmh_init()

  if (!lmh_setSubBandChannels(2)) {

    return -3;

  }

  // Start Join procedure

#ifndef MAX_SAVE

  Serial.printf("<<>> lmh_join called at %dms\n", millis());

#endif

  lmh_join();

  Serial.printf("<<>> lmh_join finished at %dms\n", millis());

  delay(100);

  return 0;

}

/**

 * @brief LoRa function for handling HasJoined event.

 */

static void lorawan_has_joined_handler(void) {

  Serial.printf("<<>> lorawan_has_joined_handler called at %dms\n", millis());

  delay(100);

  if (doOTAA) {

    uint32_t otaaDevAddr = lmh_getDevAddr();

#ifndef MAX_SAVE

    Serial.printf("OTAA joined and got dev address %08X\n", otaaDevAddr);

#endif

  } else {

#ifndef MAX_SAVE

    Serial.println("ABP joined");

#endif

  }

  // Default is Class A, where the SX1262 transceiver is in sleep mode unless a package is sent

  // If switched to Class C the power consumption is higher because the SX1262 chip remains in RX mode

  // lmh_class_request(CLASS_C);

  digitalWrite(LED_CONN, LOW);

  // Now we are connected, start the timer that will wakeup the loop frequently

  taskWakeupTimer.begin(tx_interval_start, periodicWakeup);

  taskWakeupTimer.start();

  eventType = 1;

  // Notify task about the event

  if (taskEvent != NULL) {

    Serial.printf("<<>> Waking up task at %dms\n", millis());

    xSemaphoreGive(taskEvent);

  }

}

/**@brief LoRa function for handling OTAA join failed

*/

static void lorawan_join_failed_handler(void) {

  Serial.println("OVER_THE_AIR_ACTIVATION failed!");

  Serial.println("Check your EUI's and Keys's!");

  Serial.println("Check if a Gateway is in range!");

}

/**

 * @brief Function for handling LoRaWan received data from Gateway

 *

 * @param app_data  Pointer to rx data

 */

static void lorawan_rx_handler(lmh_app_data_t *app_data) {

#ifndef MAX_SAVE

  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d\n",

                app_data->port, app_data->buffsize, app_data->rssi, app_data->snr);

#endif

  switch (app_data->port) {

    case 3:

      // Port 3 switches the class

      if (app_data->buffsize == 1) {

        switch (app_data->buffer[0]) {

          case 0:

            lmh_class_request(CLASS_A);

#ifndef MAX_SAVE

            Serial.println("Request to switch to class A");

#endif

            break;

          case 1:

            lmh_class_request(CLASS_B);

#ifndef MAX_SAVE

            Serial.println("Request to switch to class B");

#endif

            break;

          case 2:

            lmh_class_request(CLASS_C);

#ifndef MAX_SAVE

            Serial.println("Request to switch to class C");

#endif

            break;

          default:

            break;

        }

      }

      break;

    case LORAWAN_APP_PORT:

      // Copy the data into loop data buffer

      memcpy(rcvdLoRaData, app_data->buffer, app_data->buffsize);

      rcvdDataLen = app_data->buffsize;

      eventType = 0;

      // Assuming the new time is encoded as 3 bytes. e.g. 30=> 0x00, 0x00, 0x1F

      // Downlink must be sent on Port 2

      // Downlink is in seconds

      uint32_t new_time = app_data->buffer[0] << 16;

      new_time |= app_data->buffer[1] << 8;

      new_time |= app_data->buffer[2];

      tx_interval = new_time * 1000;

      Serial.print("New Time Set ");

      Serial.println(new_time);

      Serial.print("Sleep Time ");

      Serial.println(tx_interval);

      taskWakeupTimer.stop();

      taskWakeupTimer.setPeriod(tx_interval_start);

      taskWakeupTimer.start();

      // Notify task about the event

      if (taskEvent != NULL) {

#ifndef MAX_SAVE

        Serial.println("Waking up loop task");

#endif

        xSemaphoreGive(taskEvent);

      }

  }

}

/**

 * @brief Callback for class switch confirmation

 *

 * @param Class The new class

 */

static void lorawan_confirm_class_handler(DeviceClass_t Class) {

#ifndef MAX_SAVE

  Serial.printf("switch to class %c done\n", "ABC"[Class]);

#endif

  // Informs the server that switch has occurred ASAP

  m_lora_app_data.buffsize = 0;

  m_lora_app_data.port = LORAWAN_APP_PORT;

  lmh_send(&m_lora_app_data, LMH_UNCONFIRMED_MSG);

}

/**

 * @brief Send a LoRaWan package

 *

 * @return result of send request

 */

bool sendLoRaFrame(void) {

  if (lmh_join_status_get() != LMH_SET) {

    //Not joined, try again later

#ifndef MAX_SAVE

    Serial.println("Did not join network, skip sending frame");

#endif

    return false;

  }

  //Battery Voltage**********************************************************************************

  // Get a raw ADC reading

  analogReference(AR_INTERNAL_3_0);

  delay(50);

  int vbat_mv = readVBAT();

  int vbat_VOLT = (vbat_mv / 10) - 300;

  analogReference(AR_INTERNAL);  //This takes it back to default (3.6V), so wind direction has full resistance

  // Convert from raw mv to percentage (based on LIPO chemistry)

  uint8_t vbat_per = mvToPercent(vbat_mv);

  m_lora_app_data.port = LORAWAN_APP_PORT;

  /* WisBLOCK 5801 Power On*/

  pinMode(WB_IO1, OUTPUT);

  digitalWrite(WB_IO1, HIGH);

  delay(1000);

  /* WisBLOCK 5801 Power On*/

  int i;

  int sensor_pin = A1;  // select the input pin for the potentiometer

  int mcu_ain_value = 0;

  int pressure;  //KPa as unit

  int average_value;

  float voltage_ain;

  float current_sensor;  // variable to store the value coming from the sensor

  for (i = 0; i < 10; i++) {

    mcu_ain_value += analogRead(sensor_pin);

  }

  /* WisBLOCK 5801 Power Off*/

  digitalWrite(WB_IO1, LOW);

  /* WisBLOCK 5801 Power Off*/

  average_value = mcu_ain_value / i;

  voltage_ain = average_value * 3.6 / 1024;     //raef 3.6v / 10bit ADC

  current_sensor = voltage_ain / 149.9 * 1000;  //WisBlock RAK5801 I=U/149.9\*1000 (mA)

  current_sensor_payload = current_sensor * 1000;

  //  Serial.printf("-------average_value------- =  %d\n", average_value);

  //  Serial.printf("-------current_sensor------ =  %f\n", current_sensor);

  //  Serial.printf("--current_sensor_payload--- =  %d\n", current_sensor_payload);

  //  Serial.printf("----------Voltage (mV)----- =  %d\n", vbat_mv);

  uint32_t buffSize = 0;

  m_lora_app_data_buffer[buffSize++] = highByte(current_sensor_payload);

  m_lora_app_data_buffer[buffSize++] = lowByte(current_sensor_payload);

  m_lora_app_data_buffer[buffSize++] = vbat_mv / 20;

  //  m_lora_app_data_buffer[buffSize++] = 'l';

  //  m_lora_app_data_buffer[buffSize++] = 'o';

  m_lora_app_data.buffsize = buffSize;

  lmh_error_status error = lmh_send(&m_lora_app_data, LMH_UNCONFIRMED_MSG);

  return (error == 0);

}

void setup(void) {

  pinMode(17, OUTPUT);

  digitalWrite(17, HIGH);

  //Battery Voltage*****************************************************************

  // Set the analog reference to 3.0V (default = 3.6V)

  // analogReference(AR_INTERNAL_3_0);

  // Let the ADC settle

  delay(1);

  // Get a single ADC sample and throw it away

  float readVBAT();

  //******************************************************************************

  // Create the LoRaWan event semaphore

  taskEvent = xSemaphoreCreateBinary();

  // Initialize semaphore

  xSemaphoreGive(taskEvent);

  // Initialize the built in LED

  pinMode(LED_BUILTIN, OUTPUT);

  digitalWrite(LED_BUILTIN, LOW);

  // Initialize the connection status LED

  pinMode(LED_CONN, OUTPUT);

  digitalWrite(LED_CONN, LOW);

#ifndef MAX_SAVE

  // Initialize Serial for debug output

  Serial.begin(115200);

  time_t timeout = millis();

  // On nRF52840 the USB serial is not available immediately

  while (!Serial) {

    if ((millis() - timeout) < 5000) {

      delay(100);

      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));

    } else {

      break;

    }

  }

#endif

  digitalWrite(LED_BUILTIN, LOW);

#ifndef MAX_SAVE

#endif

  // Initialize LoRaWan and start join request

  int8_t loraInitResult = initLoRaWan();

#ifndef MAX_SAVE

  if (loraInitResult != 0) {

    switch (loraInitResult) {

      case -1:

        Serial.println("SX126x init failed");

        break;

      case -2:

        Serial.println("LoRaWan init failed");

        break;

      case -3:

        Serial.println("Subband init error");

        break;

      case -4:

        Serial.println("LoRa Task init error");

        break;

      default:

        Serial.println("LoRa init unknown error");

        break;

    }

    // Without working LoRa we just stop here

    while (1) {

      Serial.println("Nothing I can do, just loving you");

      delay(5000);

    }

  }

  Serial.println("LoRaWan init success");

#endif

  // Take the semaphore so the loop will go to sleep until an event happens

  xSemaphoreTake(taskEvent, 10);

}

/**

 * @brief Arduino loop task. Called in a loop from the FreeRTOS task handler

 *

 */

void loop(void) {

  // Switch off blue LED to show we go to sleep

  //  digitalWrite(LED_BUILTIN, LOW);

  // Sleep until we are woken up by an event

  if (xSemaphoreTake(taskEvent, portMAX_DELAY) == pdTRUE) {

    // Switch on blue LED to show we are awake

    digitalWrite(LED_BUILTIN, HIGH);

    delay(500);  // Only so we can see the blue LED

    // Check the wake up reason

    switch (eventType) {

      case 0:  // Wakeup reason is package downlink arrived

#ifndef MAX_SAVE

        Serial.println("Received package over LoRaWan");

#endif

        if (rcvdLoRaData[0] > 0x1F) {

#ifndef MAX_SAVE

          Serial.printf("%s\n", (char *)rcvdLoRaData);

#endif

        } else {

#ifndef MAX_SAVE

          for (int idx = 0; idx < rcvdDataLen; idx++) {

            Serial.printf("%X ", rcvdLoRaData[idx]);

          }

          Serial.println("");

#endif

        }

        break;

      case 1:  // Wakeup reason is timer

#ifndef MAX_SAVE

        Serial.println("Timer wakeup");

#endif

        /// \todo read sensor or whatever you need to do frequently

        // Send the data package

        if (sendLoRaFrame()) {

#ifndef MAX_SAVE

          Serial.println("LoRaWan package sent successfully");

          count++;

          Serial.printf("lmh_send ok count %d\n", count - 1);

          if (count > change_tx_after) {

            tx_interval_start = tx_interval;

            Serial.printf("Frame count over set limit - interval now set to %d\n", tx_interval);

            taskWakeupTimer.stop();

            taskWakeupTimer.setPeriod(tx_interval_start);

            taskWakeupTimer.start();

          }

          if (count > tx_reset_count) {

            sd_nvic_SystemReset();

            Serial.printf("Frame count over set due for restart - number of counts = %d\n", tx_reset_count);

            taskWakeupTimer.stop();

            taskWakeupTimer.setPeriod(tx_interval_start);

            taskWakeupTimer.start();

          }

#endif

        } else {

#ifndef MAX_SAVE

          Serial.println("LoRaWan package send failed");

          /// \todo maybe you need to retry here?

#endif

        }

        break;

      default:

#ifndef MAX_SAVE

        Serial.println("This should never happen ;-)");

#endif

        break;

    }

    // Go back to sleep

    Serial.println("Going back to sleep ;-)");

    digitalWrite(LED_BUILTIN, LOW);

    xSemaphoreTake(taskEvent, 10);

  }

}

float readVBAT(void) {

  float raw;

  // Get the raw 12-bit, 0..3000mV ADC value

  analogReadResolution(12);

  raw = analogRead(vbat_pin);

  delay(50);

  analogReadResolution(10);

  return raw * REAL_VBAT_MV_PER_LSB;

}

uint8_t mvToPercent(float mvolts) {

  if (mvolts < 3300)

    return 0;

  if (mvolts < 3600) {

    mvolts -= 3300;

    return mvolts / 30;

  }

  mvolts -= 3600;

  return 10 + (mvolts * 0.15F);  // thats mvolts /6.66666666

}

/**

   @brief get LoRaWan Battery value

   @param mvolts

      Raw Battery Voltage

*/

uint8_t mvToLoRaWanBattVal(float mvolts) {

  if (mvolts < 3300)

    return 0;

  if (mvolts < 3600) {

    mvolts -= 3300;

    return mvolts / 30 * 2.55;

  }

  mvolts -= 3600;

  return (10 + (mvolts * 0.15F)) * 2.55;

}

//***************************************************************************************

Hi Andy,

On the open source Arduino BSP
You can use the file system of the nRF52 to save the value and read it back after reset.
I have an example (not uplink time, but can be converted) in my WisBlock-Sensor-For-LoRaWAN code.

On RUI3
You can use the Flash API as I am doing in my RUI3-Modular code.
Get values:

api.system.flash.get(offset, buf, len)

Write values

api.system.flash.set(offset, buf, len)

Excellent, thanks @beegee, I’ll check it out.
Happy New Year!

Happy New Year!
Let me know if you have any other questions.

Getting close I feel, but getting a compile error, any thoughts?

Compilation error: expected unqualified-id before ‘if’

The error is pointing to line 25. Here’s copied portions of the relevant changes I have made to an existing sketch…happy to include whole sketch if required…

#include <Arduino.h>
#include <SPI.h>
#include <LoRaWan-RAK4630.h>
#include <nrf_nvic.h>
#ifdef NRF52_SERIES
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
/** Filename to save TX interval setting /
static const char tx_int_filename[] = “TX_INTERVAL”;
File tx_int_file(InternalFS);
#endif
/
Time the device is sleeping in milliseconds = 2 minutes * 60 seconds * 1000 milliseconds */
uint32_t tx_interval_start = 60000;
int tx_interval = 7200000; // Default value, possibly overridden by file value
int change_tx_after = 10;
int tx_reset_count = 2500;
int current_sensor_payload;
bool tx_int_loaded = false;
uint8_t tx_file_data[3];
#ifdef NRF52_SERIES
if (InternalFS.exists(tx_int_filename))
{
tx_int_file.open(tx_int_filename, FILE_O_READ);
// int read (void *buf, uint16_t nbyte);
tx_int_file.read(tx_file_data, 3);
tx_int_file.close();
tx_int_loaded = true;
}
#endif
if(tx_int_loaded)
{
uint32_t new_tx_int = tx_file_data[0] << 16;
new_tx_int |= tx_file_data[1] << 8;
new_tx_int |= tx_file_data[2];
tx_interval = new_tx_int * 1000;
}

and the downlink section is as follows…

case LORAWAN_APP_PORT:
// Copy the data into loop data buffer
memcpy(rcvdLoRaData, app_data->buffer, app_data->buffsize);
rcvdDataLen = app_data->buffsize;
eventType = 0;
// Assuming the new time is encoded as 3 bytes. e.g. 30=> 0x00, 0x00, 0x1F
// Downlink must be sent on Port 2
// Downlink is in seconds
uint32_t new_time = app_data->buffer[0] << 16;
new_time |= app_data->buffer[1] << 8;
new_time |= app_data->buffer[2];
tx_interval = new_time * 1000;
#ifdef NRF52_SERIES
InternalFS.remove(tx_int_filename);
tx_int_file.open(tx_int_filename, FILE_O_WRITE);
tx_int_file.write(app_data->buffer, 3);
tx_int_file.close();
#endif

In line 10 you have commented out the tx_int_filename[] but in line 22 you try to use it. That cannot work.

And your commenting out lines is strange.
A comment starts either with // and nothing at the end of the line or starts with /** and a */ at the end.

And then you have an unclosed #ifdef NRF52_SERIES

Try to use commenting like this and see if it compiles:

#include <Arduino.h>
#include <SPI.h>
#include <LoRaWan-RAK4630.h>
#include <nrf_nvic.h>
#ifdef NRF52_SERIES
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
/** Filename to save TX interval setting */
static const char tx_int_filename[] = “TX_INTERVAL”;
File tx_int_file(InternalFS);
#endif
/** Time the device is sleeping in milliseconds = 2 minutes * 60 seconds * 1000 milliseconds */
uint32_t tx_interval_start = 60000;
int tx_interval = 7200000; // Default value, possibly overridden by file value
int change_tx_after = 10;
int tx_reset_count = 2500;
int current_sensor_payload;
bool tx_int_loaded = false;
uint8_t tx_file_data[3];
#ifdef NRF52_SERIES
if (InternalFS.exists(tx_int_filename))
{
	tx_int_file.open(tx_int_filename, FILE_O_READ);
	// int read (void *buf, uint16_t nbyte);
	tx_int_file.read(tx_file_data, 3);
	tx_int_file.close();
	tx_int_loaded = true;
}
#endif

Apologies @beegee, that is how I had it, my editing when posting must have messed up…Here’s a screenshot of what it looks like…and getting the same error obviously…

Below is the complete error message if it’s helpful?

E:\arduino- 2.0.0\portable\sketchbook\1.Wisblock\LoraWan_Deepsleep_Pressure Transducers\wis-New save downlink to memory singletab-downlink-deepsleep_copy_20230109183453\wis-New save downlink to memory singletab-downlink-deepsleep_copy_20230109183453.ino:22:3: error: expected unqualified-id before ‘if’
22 | bool tx_int_loaded = false;
| ^~
E:\arduino- 2.0.0\portable\sketchbook\1.Wisblock\LoraWan_Deepsleep_Pressure Transducers\wis-New save downlink to memory singletab-downlink-deepsleep_copy_20230109183453\wis-New save downlink to memory singletab-downlink-deepsleep_copy_20230109183453.ino:31:1: error: expected unqualified-id before ‘if’
31 | tx_int_loaded = true;
| ^

exit status 1

Compilation error: expected unqualified-id before ‘if’

Sometimes I am blind.

This part:

#ifdef NRF52_SERIES
if (InternalFS.exists(tx_int_filename))
{
	tx_int_file.open(tx_int_filename, FILE_O_READ);
	// int read (void *buf, uint16_t nbyte);
	tx_int_file.read(tx_file_data, 3);
	tx_int_file.close();
	tx_int_loaded = true;
}
#endif

is outside of any function. That is the problem. It should be within an function like the setup() or any function you call when you start to access the flash FS.

Thanks @beegee, I now have the sketch compiling ok, but when sent to board, no action whatsoever. When I comment out the changes, it works…here’s the changes I made…

Under global I have…

#ifdef NRF52_SERIES
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
/** Filename to save TX interval setting */
static const char tx_int_filename[] = “TX_INTERVAL”;
File tx_int_file(InternalFS);
#endif

Under Setup I have the following lines…

#ifdef NRF52_SERIES
if (InternalFS.exists(tx_int_filename))
{
tx_int_file.open(tx_int_filename, FILE_O_READ);
// int read (void *buf, uint16_t nbyte);
tx_int_file.read(tx_file_data, 3);
tx_int_file.close();
tx_int_loaded = true;
}
#endif
if(tx_int_loaded)
{
uint32_t new_tx_int = tx_file_data[0] << 16;
new_tx_int |= tx_file_data[1] << 8;
new_tx_int |= tx_file_data[2];
tx_interval = new_tx_int * 1000;

}

And on the downlink section I have…

  #ifdef NRF52_SERIES
    InternalFS.remove(tx_int_filename);
    tx_int_file.open(tx_int_filename, FILE_O_WRITE);
    tx_int_file.write(app_data->buffer, 3);
    tx_int_file.close();
  #endif

Hi Andy,

if there is no output at all on the log, then most likely the app crashes somewhere at an early stage.

Could you share your complete code, I can have a look into it.

Thanks @beegee, I hope it’s not something too idiotic…! :pensive:

#include <Arduino.h>
#include <SPI.h>
#include <LoRaWan-RAK4630.h>
#include <nrf_nvic.h>

/* Time the device is sleeping in milliseconds = 2 minutes * 60 seconds * 1000 milliseconds */
uint32_t tx_interval_start = 20000;
int tx_interval = 20000; // Default value, possibly overridden by file value
int change_tx_after = 10;
int tx_reset_count = 2500;
int current_sensor_payload;
bool tx_int_loaded = false;
uint8_t tx_file_data[3];

#ifdef NRF52_SERIES
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
/** Filename to save TX interval setting */
static const char tx_int_filename[] = "TX_INTERVAL";
File tx_int_file(InternalFS);
#endif



TimerEvent_t appTimer;
static uint32_t timers_init(void);
static uint32_t count = 1;

//Battery Voltage************************************************************************
#define PIN_VBAT WB_A0
uint32_t vbat_pin = PIN_VBAT;

#define VBAT_MV_PER_LSB (0.73242188F)  // 3.0V ADC range and 12 - bit ADC resolution = 3000mV / 4096
#define VBAT_DIVIDER_COMP (1.73)       // Compensation factor for the VBAT divider, depend on the board
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
/** DIO1 GPIO pin for RAK4631 */
#define PIN_LORA_DIO_1 47

//Battery Voltage************************************************************************

// LoRaWan stuff
int8_t initLoRaWan(void);
bool sendLoRaFrame(void);
extern SemaphoreHandle_t loraEvent;

// Main loop stuff
void periodicWakeup(TimerHandle_t unused);
extern SemaphoreHandle_t taskEvent;
extern uint8_t rcvdLoRaData[];
extern uint8_t rcvdDataLen;
extern uint8_t eventType;
extern SoftwareTimer taskWakeupTimer;

/** Semaphore used by events to wake up loop task */
SemaphoreHandle_t taskEvent = NULL;

/** Timer to wakeup task frequently and send message */
SoftwareTimer taskWakeupTimer;

/** Buffer for received LoRaWan data */
uint8_t rcvdLoRaData[256];
/** Length of received data */
uint8_t rcvdDataLen = 0;

uint8_t eventType = -1;

/**
 * @brief Timer event that wakes up the loop task frequently
 * 
 * @param unused 
 */
void periodicWakeup(TimerHandle_t unused) {
  // Switch off blue LED to save power during sleep
  digitalWrite(LED_CONN, LOW);
  eventType = 1;
  // Give the semaphore, so the loop task will wake up
  xSemaphoreGiveFromISR(taskEvent, pdFALSE);
}

/** Max size of the data to be transmitted. */
#define LORAWAN_APP_DATA_BUFF_SIZE 64
/** Number of trials for the join request. */
#define JOINREQ_NBTRIALS 8

/** Lora application data buffer. */
static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];
/** Lora application data structure. */
static lmh_app_data_t m_lora_app_data = { m_lora_app_data_buffer, 0, 0, 0, 0 };

// LoRaWan event handlers
/** LoRaWan callback when join network finished */
static void lorawan_has_joined_handler(void);
/** LoRaWan callback when join failed */
static void lorawan_join_failed_handler(void);
/** LoRaWan callback when data arrived */
static void lorawan_rx_handler(lmh_app_data_t *app_data);
/** LoRaWan callback after class change request finished */
static void lorawan_confirm_class_handler(DeviceClass_t Class);
/** LoRaWan Function to send a package */
bool sendLoRaFrame(void);

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
 * 
 * Set structure members to
 * LORAWAN_ADR_ON or LORAWAN_ADR_OFF to enable or disable adaptive data rate
 * LORAWAN_DEFAULT_DATARATE OR DR_0 ... DR_5 for default data rate or specific data rate selection
 * LORAWAN_PUBLIC_NETWORK or LORAWAN_PRIVATE_NETWORK to select the use of a public or private network
 * JOINREQ_NBTRIALS or a specific number to set the number of trials to join the network
 * LORAWAN_DEFAULT_TX_POWER or a specific number to set the TX power used
 * LORAWAN_DUTYCYCLE_ON or LORAWAN_DUTYCYCLE_OFF to enable or disable duty cycles
 *                   Please note that ETSI mandates duty cycled transmissions. 
 */
static lmh_param_t lora_param_init = { LORAWAN_ADR_ON, DR_0, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_DEFAULT_TX_POWER, LORAWAN_DUTYCYCLE_OFF };

/** Structure containing LoRaWan callback functions, needed for lmh_init() */
static lmh_callback_t lora_callbacks = { BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                         lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler };
//  !!!! KEYS ARE MSB !!!!
/** Device EUI required for OTAA network join */
uint8_t nodeDeviceEUI[8] = { };
/** Application EUI required for network join */
uint8_t nodeAppEUI[8] = {  };
/** Application key required for network join */
uint8_t nodeAppKey[16] = {  };
/** Device address required for ABP network join */
uint32_t nodeDevAddr = 0x26021FB6;
/** Network session key required for ABP network join */
uint8_t nodeNwsKey[16] = {  };
/** Application session key required for ABP network join */
uint8_t nodeAppsKey[16] = {  };

/** Flag whether to use OTAA or ABP network join method */
bool doOTAA = true;

DeviceClass_t gCurrentClass = CLASS_A;                 /* class definition*/
LoRaMacRegion_t gCurrentRegion = LORAMAC_REGION_AU915; /* Region:EU868*/

/**
 * @brief Initialize LoRa HW and LoRaWan MAC layer
 * 
 * @return int8_t result
 *  0 => OK
 * -1 => SX126x HW init failure
 * -2 => LoRaWan MAC initialization failure
 * -3 => Subband selection failure
 * -4 => LoRaWan handler task start failure
 */

int8_t initLoRaWan(void) {
  Serial.printf("<<>> lora_rak4630_init called at %dms\n", millis());
  // Initialize LoRa chip.
  if (lora_rak4630_init() != 0) {
    return -1;
  }
  Serial.printf("<<>> lora_rak4630_init finished at %dms\n", millis());
  delay(100);

  // Setup the EUIs and Keys
  if (doOTAA) {
    lmh_setDevEui(nodeDeviceEUI);
    lmh_setAppEui(nodeAppEUI);
    lmh_setAppKey(nodeAppKey);

  } else {
    lmh_setNwkSKey(nodeNwsKey);
    lmh_setAppSKey(nodeAppsKey);
    lmh_setDevAddr(nodeDevAddr);
  }

  Serial.printf("<<>> lmh_init called at %dms\n", millis());
  // Initialize LoRaWan
  if (lmh_init(&lora_callbacks, lora_param_init, doOTAA, gCurrentClass, gCurrentRegion) != 0) {
    return -2;
  }
  Serial.printf("<<>> lmh_init finished at %dms\n", millis());
  delay(100);

  // For some regions we might need to define the sub band the gateway is listening to
  // This must be called AFTER lmh_init()
  if (!lmh_setSubBandChannels(2)) {
    return -3;
  }

  // Start Join procedure
#ifndef MAX_SAVE
  Serial.printf("<<>> lmh_join called at %dms\n", millis());
#endif
  lmh_join();
  Serial.printf("<<>> lmh_join finished at %dms\n", millis());
  delay(100);

  return 0;
}

/**
 * @brief LoRa function for handling HasJoined event.
 */
static void lorawan_has_joined_handler(void) {
  Serial.printf("<<>> lorawan_has_joined_handler called at %dms\n", millis());
  delay(100);
  if (doOTAA) {
    uint32_t otaaDevAddr = lmh_getDevAddr();
#ifndef MAX_SAVE
    Serial.printf("OTAA joined and got dev address %08X\n", otaaDevAddr);
#endif
  } else {
#ifndef MAX_SAVE
    Serial.println("ABP joined");
#endif
  }

  // Default is Class A, where the SX1262 transceiver is in sleep mode unless a package is sent
  // If switched to Class C the power consumption is higher because the SX1262 chip remains in RX mode

  // lmh_class_request(CLASS_C);

  digitalWrite(LED_CONN, LOW);

  // Now we are connected, start the timer that will wakeup the loop frequently
  taskWakeupTimer.begin(tx_interval_start, periodicWakeup);
  taskWakeupTimer.start();

  eventType = 1;
  // Notify task about the event
  if (taskEvent != NULL) {
    Serial.printf("<<>> Waking up task at %dms\n", millis());
    xSemaphoreGive(taskEvent);
  }
}

/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void) {
  Serial.println("OVER_THE_AIR_ACTIVATION failed!");
  Serial.println("Check your EUI's and Keys's!");
  Serial.println("Check if a Gateway is in range!");
}
/**
 * @brief Function for handling LoRaWan received data from Gateway
 *
 * @param app_data  Pointer to rx data
 */
static void lorawan_rx_handler(lmh_app_data_t *app_data) {




#ifndef MAX_SAVE
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d\n",
                app_data->port, app_data->buffsize, app_data->rssi, app_data->snr);
#endif
  switch (app_data->port) {
    case 3:
      // Port 3 switches the class
      if (app_data->buffsize == 1) {
        switch (app_data->buffer[0]) {
          case 0:
            lmh_class_request(CLASS_A);
#ifndef MAX_SAVE
            Serial.println("Request to switch to class A");
#endif
            break;

          case 1:
            lmh_class_request(CLASS_B);
#ifndef MAX_SAVE
            Serial.println("Request to switch to class B");
#endif
            break;

          case 2:
            lmh_class_request(CLASS_C);
#ifndef MAX_SAVE
            Serial.println("Request to switch to class C");
#endif
            break;

          default:
            break;
        }
      }

      break;
    case LORAWAN_APP_PORT:
      // Copy the data into loop data buffer
      memcpy(rcvdLoRaData, app_data->buffer, app_data->buffsize);
      rcvdDataLen = app_data->buffsize;
      eventType = 0;

      // Assuming the new time is encoded as 3 bytes. e.g. 30=> 0x00, 0x00, 0x1F
      // Downlink must be sent on Port 2
      // Downlink is in seconds
      uint32_t new_time = app_data->buffer[0] << 16;
      new_time |= app_data->buffer[1] << 8;
      new_time |= app_data->buffer[2];

      tx_interval = new_time * 1000;
      #ifdef NRF52_SERIES
        InternalFS.remove(tx_int_filename);
        tx_int_file.open(tx_int_filename, FILE_O_WRITE);
        tx_int_file.write(app_data->buffer, 3);
        tx_int_file.close();
      #endif
      Serial.print("New Time Set ");
      Serial.println(new_time);
      Serial.print("Sleep Time ");
      Serial.println(tx_interval);

      taskWakeupTimer.stop();
      taskWakeupTimer.setPeriod(tx_interval_start);
      taskWakeupTimer.start();

      // Notify task about the event
      if (taskEvent != NULL) {
#ifndef MAX_SAVE
        Serial.println("Waking up loop task");
#endif
        xSemaphoreGive(taskEvent);
      }
  }
}

/**
 * @brief Callback for class switch confirmation
 * 
 * @param Class The new class
 */
static void lorawan_confirm_class_handler(DeviceClass_t Class) {
#ifndef MAX_SAVE
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
#endif

  // Informs the server that switch has occurred ASAP
  m_lora_app_data.buffsize = 0;
  m_lora_app_data.port = LORAWAN_APP_PORT;
  lmh_send(&m_lora_app_data, LMH_UNCONFIRMED_MSG);
}

/**
 * @brief Send a LoRaWan package
 * 
 * @return result of send request
 */

bool sendLoRaFrame(void) {
  if (lmh_join_status_get() != LMH_SET) {
    //Not joined, try again later
#ifndef MAX_SAVE
    Serial.println("Did not join network, skip sending frame");
#endif
    return false;
  }

  //Battery Voltage**********************************************************************************
  // Get a raw ADC reading
  analogReference(AR_INTERNAL_3_0);
  delay(50);
  int vbat_mv = readVBAT();
  int vbat_VOLT = (vbat_mv / 10) - 300;

  analogReference(AR_INTERNAL);  //This takes it back to default (3.6V), so wind direction has full resistance

  // Convert from raw mv to percentage (based on LIPO chemistry)
  uint8_t vbat_per = mvToPercent(vbat_mv);

  m_lora_app_data.port = LORAWAN_APP_PORT;

  /* WisBLOCK 5801 Power On*/
  pinMode(WB_IO1, OUTPUT);
  digitalWrite(WB_IO1, HIGH);
  delay(1000);
  /* WisBLOCK 5801 Power On*/


  int i;
  int sensor_pin = A1;  // select the input pin for the potentiometer
  int mcu_ain_value = 0;
  int pressure;  //KPa as unit
  int average_value;
  float voltage_ain;
  float current_sensor;  // variable to store the value coming from the sensor

  for (i = 0; i < 10; i++) {

    mcu_ain_value += analogRead(sensor_pin);
  }

  /* WisBLOCK 5801 Power Off*/
  digitalWrite(WB_IO1, LOW);
  /* WisBLOCK 5801 Power Off*/

  average_value = mcu_ain_value / i;
  voltage_ain = average_value * 3.6 / 1024;     //raef 3.6v / 10bit ADC
  current_sensor = voltage_ain / 149.9 * 1000;  //WisBlock RAK5801 I=U/149.9\*1000 (mA)
  current_sensor_payload = current_sensor * 1000;

  //  Serial.printf("-------average_value------- =  %d\n", average_value);
  //  Serial.printf("-------current_sensor------ =  %f\n", current_sensor);
  //  Serial.printf("--current_sensor_payload--- =  %d\n", current_sensor_payload);
  //  Serial.printf("----------Voltage (mV)----- =  %d\n", vbat_mv);

  uint32_t buffSize = 0;
  m_lora_app_data_buffer[buffSize++] = highByte(current_sensor_payload);
  m_lora_app_data_buffer[buffSize++] = lowByte(current_sensor_payload);
  m_lora_app_data_buffer[buffSize++] = vbat_mv / 20;
  //  m_lora_app_data_buffer[buffSize++] = 'l';
  //  m_lora_app_data_buffer[buffSize++] = 'o';

  m_lora_app_data.buffsize = buffSize;

  lmh_error_status error = lmh_send(&m_lora_app_data, LMH_UNCONFIRMED_MSG);

  return (error == 0);
}

void setup(void) {
  pinMode(17, OUTPUT);
  digitalWrite(17, HIGH);



  #ifdef NRF52_SERIES
		if (InternalFS.exists(tx_int_filename))
    {
			tx_int_file.open(tx_int_filename, FILE_O_READ);
			// int read (void *buf, uint16_t nbyte);
			tx_int_file.read(tx_file_data, 3);
			tx_int_file.close();
      tx_int_loaded = true;
		}
#endif

if(tx_int_loaded)
{
  uint32_t new_tx_int = tx_file_data[0] << 16;
  new_tx_int |= tx_file_data[1] << 8;
  new_tx_int |= tx_file_data[2];

  tx_interval = new_tx_int * 1000;
}

  //Battery Voltage*****************************************************************

  // Set the analog reference to 3.0V (default = 3.6V)
  // analogReference(AR_INTERNAL_3_0);

  // Let the ADC settle
  delay(1);

  // Get a single ADC sample and throw it away
  float readVBAT();
  //******************************************************************************

  // Create the LoRaWan event semaphore
  taskEvent = xSemaphoreCreateBinary();
  // Initialize semaphore
  xSemaphoreGive(taskEvent);

  // Initialize the built in LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Initialize the connection status LED
  pinMode(LED_CONN, OUTPUT);
  digitalWrite(LED_CONN, LOW);

#ifndef MAX_SAVE
  // Initialize Serial for debug output
  Serial.begin(115200);

  time_t timeout = millis();
  // On nRF52840 the USB serial is not available immediately
  while (!Serial) {
    if ((millis() - timeout) < 5000) {
      delay(100);
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    } else {
      break;
    }
  }
#endif

  digitalWrite(LED_BUILTIN, LOW);

#ifndef MAX_SAVE

#endif

  // Initialize LoRaWan and start join request
  int8_t loraInitResult = initLoRaWan();

#ifndef MAX_SAVE
  if (loraInitResult != 0) {
    switch (loraInitResult) {
      case -1:
        Serial.println("SX126x init failed");
        break;
      case -2:
        Serial.println("LoRaWan init failed");
        break;
      case -3:
        Serial.println("Subband init error");
        break;
      case -4:
        Serial.println("LoRa Task init error");
        break;
      default:
        Serial.println("LoRa init unknown error");
        break;
    }

    // Without working LoRa we just stop here
    while (1) {
      Serial.println("Nothing I can do, just loving you");
      delay(5000);
    }
  }
  Serial.println("LoRaWan init success");
#endif

  // Take the semaphore so the loop will go to sleep until an event happens
  xSemaphoreTake(taskEvent, 10);
}

/**
 * @brief Arduino loop task. Called in a loop from the FreeRTOS task handler
 * 
 */
void loop(void) {
  // Switch off blue LED to show we go to sleep
  //	digitalWrite(LED_BUILTIN, LOW);

  // Sleep until we are woken up by an event
  if (xSemaphoreTake(taskEvent, portMAX_DELAY) == pdTRUE) {
    // Switch on blue LED to show we are awake
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);  // Only so we can see the blue LED

    // Check the wake up reason
    switch (eventType) {
      case 0:  // Wakeup reason is package downlink arrived
#ifndef MAX_SAVE
        Serial.println("Received package over LoRaWan");
#endif
        if (rcvdLoRaData[0] > 0x1F) {
#ifndef MAX_SAVE
          Serial.printf("%s\n", (char *)rcvdLoRaData);
#endif
        } else {
#ifndef MAX_SAVE
          for (int idx = 0; idx < rcvdDataLen; idx++) {
            Serial.printf("%X ", rcvdLoRaData[idx]);
          }
          Serial.println("");
#endif
        }

        break;
      case 1:  // Wakeup reason is timer
#ifndef MAX_SAVE
        Serial.println("Timer wakeup");
#endif
        /// \todo read sensor or whatever you need to do frequently

        // Send the data package
        if (sendLoRaFrame()) {
#ifndef MAX_SAVE
          Serial.println("LoRaWan package sent successfully");

          count++;
          Serial.printf("lmh_send ok count %d\n", count - 1);
          if (count > change_tx_after) {
            tx_interval_start = tx_interval;
            Serial.printf("Frame count over set limit - interval now set to %d\n", tx_interval);
            taskWakeupTimer.stop();
            taskWakeupTimer.setPeriod(tx_interval_start);
            taskWakeupTimer.start();
          }

          if (count > tx_reset_count) {
            sd_nvic_SystemReset();
            Serial.printf("Frame count over set due for restart - number of counts = %d\n", tx_reset_count);
            taskWakeupTimer.stop();
            taskWakeupTimer.setPeriod(tx_interval_start);
            taskWakeupTimer.start();
          }

#endif
        } else {
#ifndef MAX_SAVE
          Serial.println("LoRaWan package send failed");
          /// \todo maybe you need to retry here?
#endif
        }

        break;
      default:
#ifndef MAX_SAVE
        Serial.println("This should never happen ;-)");
#endif
        break;
    }
    // Go back to sleep
    Serial.println("Going back to sleep ;-)");
    digitalWrite(LED_BUILTIN, LOW);
    xSemaphoreTake(taskEvent, 10);
  }
}
float readVBAT(void) {
  float raw;

  // Get the raw 12-bit, 0..3000mV ADC value
  analogReadResolution(12);
  raw = analogRead(vbat_pin);
  delay(50);
  analogReadResolution(10);

  return raw * REAL_VBAT_MV_PER_LSB;
}
uint8_t mvToPercent(float mvolts) {
  if (mvolts < 3300)
    return 0;
  if (mvolts < 3600) {
    mvolts -= 3300;
    return mvolts / 30;
  }
  mvolts -= 3600;
  return 10 + (mvolts * 0.15F);  // thats mvolts /6.66666666
}
/**
   @brief get LoRaWan Battery value
   @param mvolts
      Raw Battery Voltage
*/
uint8_t mvToLoRaWanBattVal(float mvolts) {
  if (mvolts < 3300)
    return 0;
  if (mvolts < 3600) {
    mvolts -= 3300;
    return mvolts / 30 * 2.55;
  }
  mvolts -= 3600;
  return (10 + (mvolts * 0.15F)) * 2.55;
}

//***************************************************************************************

A few points to improve and it should work.

  1. Your LoRaWAN credentials are empty, so the device will never join the network and therefor the timer will never be started. You need to fill these values with the DevEUI, AppEUI and AppKey you have used to setup the device in the LoRaWAN server:
/** Device EUI required for OTAA network join */
uint8_t nodeDeviceEUI[8] = {};
/** Application EUI required for network join */
uint8_t nodeAppEUI[8] = {};
/** Application key required for network join */
uint8_t nodeAppKey[16] = {};
  1. The file system of the nRF52 needs a begin() call before you can use it.
    Change the code part where you check if the file exists to:|
#ifdef NRF52_SERIES
  InternalFS.begin();
  if (InternalFS.exists(tx_int_filename))
  {
    tx_int_file.open(tx_int_filename, FILE_O_READ);
    // int read (void *buf, uint16_t nbyte);
    tx_int_file.read(tx_file_data, 3);
    tx_int_file.close();
    tx_int_loaded = true;
  }
#endif

Perfect!, thanks once again @beegee, it was the InternalFS.begin(); I was missing. I intentionally removed all keys purely as a matter of good practice.
Thanks so much for the assistance, I have tested and it works perfectly.

Hi Andy,

Glad it is solved.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.