Issue with Frame Counter Rejection and Dragino DLOS8

Hello,

I’m trying to pair the RAK4631 with Dragino’s DLOS8, so far I’ve been able to get data to appear to be received by the gateway, but for some reason the gateway rejects it, citing an invalid fcnt every time. I’m using ABP mode with the gateway’s ABP decryption function (local network server).

Data appearing on gateway:

Mon Oct  4 21:49:43 2021 daemon.info lora_pkt_fwd[2661]: RXTX~ {"rxpk":[{"tmst":1027488172,"time":"2021-10-04T21:49:46.434830Z","tmms":4434,"chan":3,"rfch":0,"freq":902.900000,"stat":1,"modu":"LORA","datr":"SF8BW125","codr":"4/5","lsnr":12.5,"rssi":-78,"size":33,"data":"gDU0MzKAAAACaoCirlQyU4FKWw0TeeZ2vnpEM4obVZiq"}]}

Sketch that sends data:

#include <Arduino.h>
#include <LoRaWan-RAK4630.h> //http://librarymanager/All#SX126x
#include <SPI.h>

// RAK4630 supply two LED
#ifndef LED_BUILTIN
#define LED_BUILTIN 35
#endif

#ifndef LED_BUILTIN2
#define LED_BUILTIN2 36
#endif

bool doOTAA = false;   // OTAA is used by default.
#define SCHED_MAX_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 60                      /**< Maximum number of events in the scheduler queue. */
#define LORAWAN_DATERATE DR_3                   /*LoRaMac datarates definition, from DR_0 to DR_5*/
#define LORAWAN_TX_POWER TX_POWER_5             /*LoRaMac tx power definition, from TX_POWER_0 to TX_POWER_15*/
#define JOINREQ_NBTRIALS 0                      /**< Number of trials for the join request. */
DeviceClass_t g_CurrentClass = CLASS_A;         /* class definition*/
LoRaMacRegion_t g_CurrentRegion = LORAMAC_REGION_US915;    /* Region:EU868*/
lmh_confirm g_CurrentConfirm = LMH_CONFIRMED_MSG;         /* confirm/unconfirm packet definition*/
uint8_t gAppPort = LORAWAN_APP_PORT;                      /* data port*/

/**@brief Structure containing LoRaWan parameters, needed for lmh_init()
*/
static lmh_param_t g_lora_param_init = {LORAWAN_ADR_ON, LORAWAN_DATERATE, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS, LORAWAN_TX_POWER, LORAWAN_DUTYCYCLE_OFF};

// Foward declaration
static void lorawan_has_joined_handler(void);
static void lorawan_join_failed_handler(void);
static void lorawan_rx_handler(lmh_app_data_t *app_data);
static void lorawan_confirm_class_handler(DeviceClass_t Class);
static void send_lora_frame(void);

/**@brief Structure containing LoRaWan callback functions, needed for lmh_init()
*/
static lmh_callback_t g_lora_callbacks = {BoardGetBatteryLevel, BoardGetUniqueId, BoardGetRandomSeed,
                                          lorawan_rx_handler, lorawan_has_joined_handler, lorawan_confirm_class_handler, lorawan_join_failed_handler
                                         };
//OTAA keys !!!! KEYS ARE MSB !!!!
uint8_t nodeDeviceEUI[8] = {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x33, 0x33};
uint8_t nodeAppEUI[8] = {0xB8, 0x27, 0xEB, 0xFF, 0xFE, 0x39, 0x00, 0x00};
uint8_t nodeAppKey[16] = {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88};

// ABP keys
uint32_t nodeDevAddr = 0x32333435;
uint8_t nodeNwsKey[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x12, 0x13, 0x14, 0x14, 0x15, 0x16};
uint8_t nodeAppsKey[16] = {0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31, 0x32};

// Private defination
#define LORAWAN_APP_DATA_BUFF_SIZE 21                    /**< buffer size of the data to be transmitted. */
#define LORAWAN_APP_INTERVAL 30000                        /**< Defines for user timer, the application data transmission interval. 20s, value in [ms]. */
static uint8_t m_lora_app_data_buffer[LORAWAN_APP_DATA_BUFF_SIZE];            //< Lora user application data buffer.
static lmh_app_data_t m_lora_app_data = {m_lora_app_data_buffer, 0, 0, 0, 0}; //< Lora user application data structure.

TimerEvent_t appTimer;
static uint32_t timers_init(void);
static uint32_t count = 0;
static uint32_t count_fail = 0;

unsigned int thingNum = 1130;
byte appNum = 69;
byte mac[] = {0x26, 0x01, 0x16, 0xF9, 0xFF, 0xFF};
unsigned long time = 1632942051000;
float flo = 2.31;
int in = -1500;
byte bs = 0b01010101;

byte Lpacket[20];

union Union
{
  float flt;
  unsigned char flBytes[4];
};

void setup() {
  // put your setup code here, to run once:

  preparePacket();
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Initialize LoRa chip.
  lora_rak4630_init();

  // Initialize Serial for debug output
  time_t timeout = millis();
  Serial.begin(115200);
  while (!Serial)
  {
    if ((millis() - timeout) < 5000)
    {
      delay(100);
    }
    else
    {
      break;
    }
  }
  Serial.println("=====================================");
  Serial.println("Welcome to RAK4630 LoRaWan!!!");
  if (doOTAA)
  {
    Serial.println("Type: OTAA");
  }
  else
  {
    Serial.println("Type: ABP");
  }

  switch (g_CurrentRegion)
  {
    case LORAMAC_REGION_AS923:
      Serial.println("Region: AS923");
      break;
    case LORAMAC_REGION_AU915:
      Serial.println("Region: AU915");
      break;
    case LORAMAC_REGION_CN470:
      Serial.println("Region: CN470");
      break;
    case LORAMAC_REGION_EU433:
      Serial.println("Region: EU433");
      break;
    case LORAMAC_REGION_IN865:
      Serial.println("Region: IN865");
      break;
    case LORAMAC_REGION_EU868:
      Serial.println("Region: EU868");
      break;
    case LORAMAC_REGION_KR920:
      Serial.println("Region: KR920");
      break;
    case LORAMAC_REGION_US915:
      Serial.println("Region: US915");
      break;
  }
  Serial.println("=====================================");

  //creat a user timer to send data to server period
  uint32_t err_code;
  err_code = timers_init();
  if (err_code != 0)
  {
    Serial.printf("timers_init failed - %d\n", err_code);
    return;
  }

  // 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);
  }
  // Initialize LoRaWan
  err_code = lmh_init(&g_lora_callbacks, g_lora_param_init, doOTAA, g_CurrentClass, g_CurrentRegion);
  lmh_setSubBandChannels(1);

  if (err_code != 0)
  {
    Serial.printf("lmh_init failed - %d\n", err_code);
    return;
  }


  // Start Join procedure
  lmh_join();

}

void loop() {
  // put your main code here, to run repeatedly:

}

void preparePacket() {
  Union a;
  a.flt = flo;
  Union b;
  b.flt = flo;
  int i = 0;
  Lpacket[i++] = highByte(thingNum);
  Lpacket[i++] = lowByte(thingNum);
  Lpacket[i++] = appNum;
  Lpacket[i++] = mac[0];
  Lpacket[i++] = mac[1];
  Lpacket[i++] = mac[2];
  Lpacket[i++] = mac[3];
  Lpacket[i++] = mac[4];
  Lpacket[i++] = mac[5];
  Lpacket[i++] = a.flBytes[0];
  Lpacket[i++] = a.flBytes[1];
  Lpacket[i++] = a.flBytes[2];
  Lpacket[i++] = a.flBytes[3];
  Lpacket[i++] = b.flBytes[0];
  Lpacket[i++] = b.flBytes[1];
  Lpacket[i++] = b.flBytes[2];
  Lpacket[i++] = b.flBytes[3];
  Lpacket[i++] = highByte(in);
  Lpacket[i++] = lowByte(in);
  Lpacket[i++] = bs;
}

void lorawan_has_joined_handler(void)
{
  Serial.println("OTAA Mode, Network Joined!");

  lmh_error_status ret = lmh_class_request(g_CurrentClass);
  if (ret == LMH_SUCCESS)
  {
    delay(1000);
    TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
    TimerStart(&appTimer);
  }
}
/**@brief LoRa function for handling OTAA join failed
*/
static void lorawan_join_failed_handler(void)
{
  Serial.println("OTAA join 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[in] app_data  Pointer to rx data
*/
void lorawan_rx_handler(lmh_app_data_t *app_data)
{
  Serial.printf("LoRa Packet received on port %d, size:%d, rssi:%d, snr:%d, data:%s\n",
                app_data->port, app_data->buffsize, app_data->rssi, app_data->snr, app_data->buffer);
}

void lorawan_confirm_class_handler(DeviceClass_t Class)
{
  Serial.printf("switch to class %c done\n", "ABC"[Class]);
  // Informs the server that switch has occurred ASAP
  m_lora_app_data.buffsize = 0;
  m_lora_app_data.port = gAppPort;
  lmh_send(&m_lora_app_data, g_CurrentConfirm);
}

void send_lora_frame(void)
{
  if (lmh_join_status_get() != LMH_SET)
  {
    //Not joined, try again later
    return;
  }

  Union a;
  a.flt = flo;
  Union b;
  b.flt = flo;
  uint32_t i = 0;
  memset(m_lora_app_data.buffer, 0, LORAWAN_APP_DATA_BUFF_SIZE);
  m_lora_app_data.port = gAppPort;
  m_lora_app_data.buffer[i++] = highByte(thingNum);
  m_lora_app_data.buffer[i++] = lowByte(thingNum);
  m_lora_app_data.buffer[i++] = appNum;
  m_lora_app_data.buffer[i++] = mac[0];
  m_lora_app_data.buffer[i++] = mac[1];
  m_lora_app_data.buffer[i++] = mac[2];
  m_lora_app_data.buffer[i++] = mac[3];
  m_lora_app_data.buffer[i++] = mac[4];
  m_lora_app_data.buffer[i++] = mac[5];
  m_lora_app_data.buffer[i++] = a.flBytes[0];
  m_lora_app_data.buffer[i++] = a.flBytes[1];
  m_lora_app_data.buffer[i++] = a.flBytes[2];
  m_lora_app_data.buffer[i++] = a.flBytes[3];
  m_lora_app_data.buffer[i++] = b.flBytes[0];
  m_lora_app_data.buffer[i++] = b.flBytes[1];
  m_lora_app_data.buffer[i++] = b.flBytes[2];
  m_lora_app_data.buffer[i++] = b.flBytes[3];
  m_lora_app_data.buffer[i++] = highByte(in);
  m_lora_app_data.buffer[i++] = lowByte(in);
  m_lora_app_data.buffer[i++] = bs;
  m_lora_app_data.buffsize = i;

  lmh_error_status error = lmh_send(&m_lora_app_data, g_CurrentConfirm);
  if (error == LMH_SUCCESS)
  {
    count++;
    Serial.printf("lmh_send ok count %d\n", count);
  }
  else
  {
    count_fail++;
    Serial.printf("lmh_send fail count %d\n", count_fail);
  }
}

/**@brief Function for handling user timerout event.
*/
void tx_lora_periodic_handler(void)
{
  TimerSetValue(&appTimer, LORAWAN_APP_INTERVAL);
  TimerStart(&appTimer);
  Serial.println("Sending frame now...");
  send_lora_frame();
}

/**@brief Function for the Timer initialization.

   @details Initializes the timer module. This creates and starts application timers.
*/
uint32_t timers_init(void)
{
  TimerInit(&appTimer, tx_lora_periodic_handler);
  return 0;
}

I’ve tried changing the devaddr, nwskey, and appskey on both the node and gateway side to try to get the two sides to sync frame counters but to no avail. Any ideas?

Hello Charles,

I do not know the Dragino DLOS8, does it have a built-in LoRaWAN server?
The gateway itself is just a packet forwarder. It does not check the fCnt or anything else in the packet. What LoRaWAN server do you use?

It would be helpful to get a bit more familiar with how LoRaWAN works, eg, “pair” is a bluetooth term that doesn’t really apply here, and the other end of the conversation is the network server NOT the gateway.

The manual for your gateway says it can “Decrypt” ABP packet but doesn’t really say it has its own internal network server.

I ran it through the online decoder at https://lorawan-packet-decoder-0ta6puiniaut.runkit.sh/ and the packet you quoted in your post is a valid LoRaWAN packet for the keys quoted in your post, so you may have to pursue the error declared by the gateway’s decoding software with the company who sold you the gateway. You might want to first rule out simple transcription errors, etc - note you have “14” in your network key twice.

Hello All,

It does indeed have its own network server, as you said if the correct device address and keys are within its ABP decode database, the gateway is capable of decoding the payload and placing the contents into a file within the openWRT’s linux file system. I’ve successfully been able to do this in the past with an Arduino MKR1310 on a different project, but was really hoping to use the RAK4631 for this.

In this case, the gateway itself is not just a packet forwarder, it acts as the network server, and I’ve also included some smarts in it for it to be able to forward on received payloads via MQTT.

I’ll double check that things look ok from my side in the meantime, as good eye, you saw that I repeated a number twice, possibly throwing things off. Any additional help here would be appreciated as well in the meantime.

Your packet is (in isolation) valid for your given device address and network key, so the issue is either with the additional rather “unique” software running on the gateway, or your transcription of the device records between the firmware and that box.

That said, if Dragino’s software is correctly tracking past frame counts, any time you reset the node and it starts over from zero, the LoRaWAN spec says that its packets must be rejected until they exceed the last previously used frame count. If you keep restarting the node, you may need to find a way to zero the Dragino software’s expected frame count (at an extreme by deleting and recreating its knowledge of the device).

Really in LoRaWAN deployed nodes aren’t supposed to ever restart from scratch. Even using OTAA only partially works around that, since the device’s nonce in the join request isn’t allowed to repeat either. In practice, just about everyone cheats and does cold restarts without retained data, but that means you have to tell whatever is validating packets about the restart.

I see, it’s good to know that the node is doing what it’s supposed to be doing in any case. However, I’ve already tried deleting and re-entering multiple times, changing up the devaddr and keys each time to make it think it’s a new node in hopes of resetting the internal frame counter. No dice though

If Dragino’s software is rejecting valid packets on a correct device record with no previous frame count history, that’s an issue you’re going to have to take up with Dragino.

Update: the device record was incorrectly entered into the Dragino box

Hm, there is one thing that I noticed is different, the MIC. I understand I may have to ask this elsewhere (already asked Dragino support, waiting to hear back).

The gateway reports conflicting values for MIC, so I’m unsure. This is the packet I get from reading the log:

Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: PKT_FWD~ DATA_CONF_UP-> {"DevAddr": "F2333435", "FCtrl": ["ADR": 1, "ADRACKReq": 0, "ACK": 0, "RFU" : "RFU", "FOptsLen": 0], "FCnt": 0, "FPort": 2, "MIC": "974660B3"}

So MIC = 974660B3, which as you said agrees with the online lorawan decoder I used, albeit in reverse byte order:

However, the log goes on to demonstrate (I believe), what the MIC should have been at different frame counters taking into account overflow, none of which match an MIC of 974660B3 in any byte order.

Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=52A28CC6, MIC=974660B3, fcnt=0, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=CADD1935, MIC=974660B3, fcnt=65536, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=7ABE52E5, MIC=974660B3, fcnt=131072, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=FAAEBC3B, MIC=974660B3, fcnt=196608, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=7B2694D3, MIC=97466                                                                    0B3, fcnt=262144, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=435DDB47, MIC=974660B3, fcnt=327680, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=070EAF7F, MIC=97466                                                                    0B3, fcnt=393216, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=597AA495, MIC=97466                                                                    0B3, fcnt=458752, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] mic=6CB482BA, MIC=974660B3, fcnt=524288, FCNT=0
Tue Oct  5 15:36:03 2021 daemon.info lora_pkt_fwd[14893]: INFO~ [MIC] Invalid fcnt(=0) for de                                                                    vaddr:F2333435

Maybe there’s something here?

Their software seems to be a mess, starting with incorrectly parsing the packet, or at least incorrectly reporting it.

The devaddr actually sent in your quoted “gDU0MzKAAAACaoCirlQyU4FKWw0TeeZ2vnpEM4obVZiq” packet was 0x32333435 as in your code.

Dragino’s software really isn’t on topic here, you’re going to need to pursue that with them.

Dumb mistake, I figured it out… I swapped the network and app keys when I was entering in the UI…

Thank you all for your help!

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