matthijskooijman / arduino-lmic

:warning: This library is deprecated, see the README for alternatives.
711 stars 653 forks source link

How to determine if your no longer joined? #150

Open trlafleur opened 6 years ago

trlafleur commented 6 years ago

I have been doing some testing to determine when I'm no longer connected to a gateway... The goal is to determine when I need to try a rejoin??

I start off with an active GW, I do join the network, I see traffic at TTN. My sends ask for an ACK, so it should fail if I'm no longer connected to the network... I TX into a dummy load so, very low TX energy is sent... No other GW within 10mi

But, when I disconnect the GW, My messages still get an: Event EV_TXCOMPLETE, time: 481, this is very odd but after about 25 tries, I get an: Event EV_LINK_DEAD, time: 1743

So my question is, why do I get TXCOMPLETE back from the stack when Its NOT connected to any GW???? if its asking for an ACK back from the GW??

I have a keep-alive task sending a REJOIN every 120 sec...

My test code is at the end.... its based on the standard example code, but some change as needed for my testing. ARDUINO 1.8.5 LMic Arduino-2 Mods for SPI speed were made to LMiC code Keys have been changed


 ** LMiC Starting on a ESP32 **
ESP32 Chip ID = E0AA4CA4AE30
 ** LMiC Test 1.1e
 ** /Users/lafleur/Desktop/MySensor-Arduino-development/Arduino_fork/thethingsnetwork-send-v1e-ESP32/thethingsnetwork-send-v1e-ESP32.ino 
 ** Mar 16 2018, 12:45:18 

***  LMiC os_init 
***  LMIC_reset 
Event EV_JOINING, time: 2 
Event EV_JOIN_FAILED, time: 62 

***  Keep-Alive-Time: 122 
***  Sending ReJoin Request
Event EV_JOIN_FAILED, time: 132 
Event EV_JOIN_FAILED, time: 204 
Event EV_JOINED, time: 231 

***  Keep-Alive-Time: 242 
***  Sending ReJoin Request

***  Joined  <------------------ a flag I set to tell me we have joined
Time: 242
Send, txCnhl: 71 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_REJOIN_FAILED, time: 248 

***  Joined
Time: 272
Send, txCnhl: 71 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 299 

***  Joined
Time: 302
Send, txCnhl: 7 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 303 

***  Joined
Time: 332
Send, txCnhl: 8 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 349 

***  Keep-Alive-Time: 362 
***  Sending ReJoin Request

***  Joined
Time: 362
Send, txCnhl: 14 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_REJOIN_FAILED, time: 368 

***  Joined
Time: 392
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 422 

***  Joined       <------------------------------------- this is where I disconnected the GW
Time: 422
Send, txCnhl: 14 
Opmode check: it's ok to send--

***  Joined
Time: 452
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 481   <-----------------  As you can see, LMiC still get a complete

***  Keep-Alive-Time: 482 
***  Sending ReJoin Request

***  Joined
Time: 482
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_REJOIN_FAILED, time: 490 

***  Joined
Time: 512
Send, txCnhl: 13 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 542    <-----------------  As you can see, LMiC still get a complete

***  Joined
Time: 542
Send, txCnhl: 12 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 571    <-----------------  As you can see, LMiC still get a complete

***  Joined
Time: 572
Send, txCnhl: 12 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 601    <-----------------  As you can see, LMiC still get a complete

***  Keep-Alive-Time: 602 
***  Sending ReJoin Request

***  Joined
Time: 602
Send, txCnhl: 13 
Opmode check: it's ok to send--
Event EV_REJOIN_FAILED, time: 609 

***  Joined
Time: 632
Send, txCnhl: 12 
Opmode check: it's ok to send--

***  Joined
Time: 662
Send, txCnhl: 11 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 690 

***  Joined
Time: 692
Send, txCnhl: 10 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 721 

***  Keep-Alive-Time: 722 
***  Sending ReJoin Request

***  Joined
Time: 722
Send, txCnhl: 11 
Opmode check: it's ok to send--
Event EV_REJOIN_FAILED, time: 730 

***  Joined
Time: 752
Send, txCnhl: 10 
Opmode check: it's ok to send--

***  Joined
Time: 782
Send, txCnhl: 8 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 812 

***  Joined
Time: 812
Send, txCnhl: 15 
Opmode check: it's ok to send--

***  Keep-Alive-Time: 842 
***  Sending ReJoin Request

***  Joined
Time: 842
Send, txCnhl: 15 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 843 
Event EV_REJOIN_FAILED, time: 852 

***  Joined
Time: 872
Send, txCnhl: 8 
Opmode check: it's ok to send--

***  Joined
Time: 902
Send, txCnhl: 8 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 904 

***  Joined
Time: 932
Send, txCnhl: 8 
Opmode check: it's ok to send--

***  Keep-Alive-Time: 962 
***  Sending ReJoin Request
Event EV_TXCOMPLETE, time: 962 

***  Joined
Time: 962
Send, txCnhl: 9 
Opmode check: it's ok to send--
Event EV_REJOIN_FAILED, time: 970 

***  Joined
Time: 992
Send, txCnhl: 15 
Opmode check: it's ok to send--

***  Joined
Time: 1022
Send, txCnhl: 14 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1025 

***  Joined
Time: 1052
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1079 

***  Keep-Alive-Time: 1082 
***  Sending ReJoin Request

***  Joined
Time: 1082
Send, txCnhl: 15 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_REJOIN_FAILED, time: 1089 

***  Joined
Time: 1112
Send, txCnhl: 15 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1140 

***  Joined
Time: 1142
Send, txCnhl: 15 
Opmode check: it's ok to send--

***  Joined
Time: 1172
Send, txCnhl: 15 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1202 

***  Keep-Alive-Time: 1202 
***  Sending ReJoin Request

***  Joined
Time: 1202
Send, txCnhl: 15 
Opmode check: it's ok to send--
Event EV_REJOIN_FAILED, time: 1210 

***  Joined
Time: 1232
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1262 

***  Joined
Time: 1262
Send, txCnhl: 13 
Opmode check: it's ok to send--

***  Joined
Time: 1292
Send, txCnhl: 13 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1293 

***  Keep-Alive-Time: 1322 
***  Sending ReJoin Request

***  Joined
Time: 1322
Send, txCnhl: 14 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_REJOIN_FAILED, time: 1329 

***  Joined
Time: 1352
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1381 

***  Joined
Time: 1382
Send, txCnhl: 14 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1410 

***  Joined
Time: 1412
Send, txCnhl: 14 
Opmode check: it's ok to send--

***  Keep-Alive-Time: 1442 
***  Sending ReJoin Request

***  Joined
Time: 1442
Send, txCnhl: 14 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1445 
Event EV_REJOIN_FAILED, time: 1454 

***  Joined
Time: 1472
Send, txCnhl: 15 
Opmode check: it's ok to send--

***  Joined
Time: 1502
Send, txCnhl: 15 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1503 

***  Joined
Time: 1532
Send, txCnhl: 15 
Opmode check: it's ok to send--

***  Keep-Alive-Time: 1562 
***  Sending ReJoin Request

***  Joined
Time: 1562
Send, txCnhl: 15 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1563 
Event EV_REJOIN_FAILED, time: 1571 

***  Joined
Time: 1592
Send, txCnhl: 8 
Opmode check: it's ok to send--

***  Joined
Time: 1622
Send, txCnhl: 8 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1624 

***  Joined
Time: 1652
Send, txCnhl: 8 
Opmode check: it's ok to send--
Event EV_TXCOMPLETE, time: 1681 

***  Keep-Alive-Time: 1682 
***  Sending ReJoin Request

***  Joined
Time: 1682
Send, txCnhl: 9 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_REJOIN_FAILED, time: 1689 

***  Joined
Time: 1712
Send, txCnhl: 9 
Opmode check: it's ok to send--

***  Joined
Time: 1742
Send, txCnhl: 9 
Opmode check: OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent
Event EV_TXCOMPLETE, time: 1743
Event EV_LINK_DEAD, time: 1743    <--------------------------- Now we get a Link Dead
Event EV_REJOIN_FAILED, time: 1752 

Test Code:

*
 * TRL  ver 1.1e   16 Mar 2018
 *  added: ESP32 + OLED Display 3 Mar 2018
 * 
 * 
 *  Test Code running on these processors:
 *    TTGO ESP32
 *    Rocketscream ARM M0 RFM95 LoRa board
 *    MoteinoMega LoRa
 * 
 * */

 /* *******************************************************************************
 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 *
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and redistribution.
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 *
 * This example sends a valid LoRaWAN packet with payload "Hello, world!", that
 * will be processed by The Things Network server.
 *
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1, 
*  0.1% in g2). <--- Not in US
 *
 * Change DEVADDR to a unique address! 
 * See http://thethingsnetwork.org/wiki/AddressSpace
 *
 * Do not forget to define the radio type correctly in config.h, default is:
 *   #define CFG_sx1272_radio 1
 * for SX1272 and RFM92, but change to:
 *   #define CFG_sx1276_radio 1
 * for SX1276 and RFM95.
 *
 *******************************************************************************/

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <stdarg.h>

#include <Wire.h>         // http://arduino.cc/en/Reference/Wire ??

/* ************************************************************************************** */
// User defines
//#define OLED              // If we are using OLED display

#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))

/* ************************************************************************************** */
#ifdef __AVR_ATmega1284P__      // MoteinoMega LoRa
// Pin mapping
const lmic_pinmap lmic_pins = 
{
  .nss  = 4,
  .rxtx = LMIC_UNUSED_PIN,    // Not connected on RFM92/RFM95
  .rst  = 3,                  // Needed on RFM92/RFM95 ??
  .dio  = {2, 22, 21},
};
#define myLED 15
#define MyFlashCS 23
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)

/* ************************************************************************************** */
#elif __SAMD21G18A__            // RocketScream
#define Serial SerialUSB
// Pin mapping
const lmic_pinmap lmic_pins = 
{
  .nss  = 5,
  .rxtx = LMIC_UNUSED_PIN,    // Not connected on RFM92/RFM95
  .rst  = 3,                  // Needed on RFM92/RFM95 ??
  .dio  = {2, 6, LMIC_UNUSED_PIN},
};

#define myLED 13              // Is 13 on M0
#define MyFlashCS 4
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)

/* ************************************************************************************** */
#elif ARDUINO_ARCH_ESP32
// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 18,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,   // was 14
    .dio = {26, 33, 32}     // Pins for the Heltec ESP32 Lora board/ TTGO Lora32 with 3D metal antenna
};

#define myLED           2   // Is 2 on ESP32 TTGO

/* ************************************************************************************** */
#else
#error Wrong Processor defined
#endif
/* ************************************************************************************** */

#ifdef OLED
  // If using 128x64 OLED display
  // OLED display lines are: 0, 8, 16, 24, 32, 40, 48, ~56
  unsigned int counter = 0;
  char TTN_response[30];
  #define OLED_I2C_ADDR   0x3C
  #define OLED_RESET      16
  #define OLED_SDA        4
  #define OLED_SCL        15
  #include <SSD1306.h>        // Using OLED Display on board
  SSD1306 display (OLED_I2C_ADDR, OLED_SDA, OLED_SCL);
#endif

/* ************************************************************************************** */
/*  Enable debug prints to serial monitor on port 0 */
#define MY_DEBUG            // used for debug 
#define MY_DEBUG1           // used in this program, level 1 debug
#define MY_DEBUG2           // used in this program, level 2 debug

#define SKETCHNAME "LMiC Test"
#define SKETCHVERSION "1.1e"

/* ************************************************************************************** 
 *            TTN Key's in OTAA Mode
 *          
 *   DEVEUI   Unique ID for each device, we supply per device  64bits   
 *   APPEUI   Unique Application ID, as we registered our application with TTN 64bits 
 *   APPKEY   Unique to our Application, TTN use's it to derived --> NwkSKey and AppSKey
 *   NwkSKey  Network Session Key, Generated by TTN per session     
 *   AppSKey  Application Session Key, Generated by TTN per session      
 *   DEVADDR  Device Address, Assigned to us when we join the network by TTN
 *          
 * ************************************************************************************** */

/* ************************************************************************************** */
// LoRaWAN DevEUI, unique device ID (LSBF)
//static const u1_t DEVEUI[8]  = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u1_t DEVEUI[8]  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };

/* ************************************************************************************** */
// LoRaWAN Application identifier (AppEUI) --> (ArtEui in LMiC)
//static const u1_t APPEUI[8]  = { 0x40, 0x1e, 0x00, 0xf0, 0x7e, 0xd5, 0xf3, 0x70 };
static const u1_t APPEUI[8]  = { 0x70, 0xf3, 0xd5, 0x7e, 0xf0, 0x00, 0x1e, 0x40 };

/* ************************************************************************************** */
// LoRaWAN NwkSKey, network session key (NwkSKey) --> (DEVKEY)
// Use this key for The Things Network, supplied by TTN
static const u1_t DEVKEY[16] = {0xCB, 0xA3, 0x5C, 0x8D, 0xA6, 0x9E, 0x93, 0xAE, 0x0B, 0xA6, 0x42, 0x93, 0xA4, 0xCD, 0x02, 0xE9 };  // <--- Your key here

// **********************************************************
// Function to do a byte swap in a byte array
void RevBytes(unsigned char* b, size_t c)
{
  u1_t i;
  for (i = 0; i < c / 2; i++)
  {
     unsigned char t = b[i];
    b[i] = b[c - 1 - i];
    b[c - 1 - i] = t;
  }
}

//////////////////////////////////////////////////
// APPLICATION CALLBACKS
//////////////////////////////////////////////////

/* ************************************************************************************** */
// provide device ID (8 bytes, LSBF)
void os_getDevEui (u1_t* buf) {
    memcpy(buf, DEVEUI, 8);
    RevBytes(buf, 8);      // TTN requires it in LSB First order, so lets swap byte's
}

/* ************************************************************************************** */
// provide application router ID (APPEUI) (8 bytes, LSBF)
void os_getArtEui (u1_t* buf) {
    memcpy(buf, APPEUI, 8);
    RevBytes(buf, 8);      // TTN requires it in LSB First order, so lets swap byte's
}

/* ************************************************************************************** */
// provide device key (16 bytes)
void os_getDevKey (u1_t* buf) {
    memcpy(buf, DEVKEY, 16);
}

/* ************************************************************************************** */
uint8_t mydata[] = "Hello, World!";
static osjob_t sendjob;
static osjob_t keepalivejob;
bool JoinedFlag = false;

/* ************************************************************************************** */
#ifdef MY_DEBUG
void hwDebugPrint(const char *fmt, ... ) 
{
  char fmtBuffer[300];
  va_list args;
  va_start (args, fmt );
  va_end (args);

#ifdef __SAMD21G18A__            // RocketScream
  vsnprintf(fmtBuffer, 299, fmt, args); 
#elif ARDUINO_ARCH_ESP32
  vsnprintf(fmtBuffer, 299, fmt, args);
#else   
  vsnprintf_P(fmtBuffer, 299, fmt, args);
#endif 
  va_end (args);
  Serial.print(fmtBuffer);    // <---------------------
  Serial.flush();
}

#endif

/* ************************************************************************************** */
/* These are use for local debug of code, hwDebugPrint is defined in MyHwATMega328.cpp */
#ifdef MY_DEBUG
#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__)
#else
#define debug(x,...)
#endif

#ifdef MY_DEBUG1
#define debug1(x,...) hwDebugPrint(x, ##__VA_ARGS__)
#else
#define debug1(x,...)
#endif

#ifdef MY_DEBUG2
#define debug2(x,...) hwDebugPrint(x, ##__VA_ARGS__)
#else
#define debug2(x,...)
#endif

/* ************************************************************************************** */
void onEvent (ev_t ev) 
{
    //debug_event(ev);

    switch(ev) 
    {
/* ************************************************************************************** */      
      // scheduled data sent (optionally data received)
      // note: this includes the receive window!
      case EV_TXCOMPLETE:
          // use this event to keep track of actual transmissions
          debug(PSTR("Event EV_TXCOMPLETE, time: %u \n"), millis() / 1000);
          JoinedFlag = true;
#ifdef OLED
          display.clear();
          display.drawString (0, 0, "EV_TXCOMPLETE event!");
          display.display();
#endif
          digitalWrite(myLED, 0);

          if(LMIC.dataLen) 
          { // data received in rx slot after tx
           //debug_buf(LMIC.frame+LMIC.dataBeg, LMIC.dataLen); <---------------------------
           debug(PSTR("Data Received! \n"));
           Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);  // <-----------------
#ifdef OLED           
          int i = 0;
          display.drawString (0, 9, "Received DATA.");
          for ( i = 0 ; i < LMIC.dataLen ; i++ )
          {
              TTN_response[i] = LMIC.frame[LMIC.dataBeg+i];
          }
              TTN_response[i] = 0;
              display.drawString (0, 24, String(TTN_response));
              display.drawString (0, 32, String(LMIC.rssi));
              display.drawString (64,32, String(LMIC.snr));
              display.display();
#endif
          }
          break;

/* ************************************************************************************** */
       case EV_JOIN_FAILED:
          debug(PSTR("Event EV_JOIN_FAILED, time: %u \n"), millis() / 1000);
          JoinedFlag = false;
          LMIC_startJoining();    // lest try again...
#ifdef OLED
          display.drawString(0, 32, "EV_JOIN_FAILED....");
          display.display();
#endif
          break;

/* ************************************************************************************** */
       case EV_RXCOMPLETE:
          debug(PSTR("Event EV_RXCOMPLETE, time: %u \n"), millis() / 1000);
          JoinedFlag = true;
          break;

/* ************************************************************************************** */
       case EV_LINK_DEAD:
          debug(PSTR("Event EV_LINK_DEAD, time: %u \n"), millis() / 1000);
          JoinedFlag = false;
          break;

/* ************************************************************************************** */
       case EV_RESET:
          debug(PSTR("Event EV_RESET, time: %u \n"), millis() / 1000);
          JoinedFlag = false;
          break;

/* ************************************************************************************** */
       case EV_JOINING:
          debug(PSTR("Event EV_JOINING, time: %u \n"), millis() / 1000);
          JoinedFlag = false;
#ifdef OLED          
          display.drawString(0, 16, "OTTA joining....");
          display.display();
#endif          
          break;

/* ************************************************************************************** */
       case EV_REJOIN_FAILED:
          debug(PSTR("Event EV_REJOIN_FAILED, time: %u \n"), millis() / 1000);
          //JoinedFlag = false;
          break;

/* ************************************************************************************** */
       case EV_JOINED:
          debug(PSTR("Event EV_JOINED, time: %u \n"), millis() / 1000);
          JoinedFlag = true;
#ifdef OLED          
          display.clear();
          display.drawString(0 , 0 ,  "Joined!...");
          display.display();
#endif          
          break;

/* ************************************************************************************** */
       case EV_BEACON_FOUND:
          debug(PSTR("Event EV_BEACON_FOUND, time: %u \n"), millis() / 1000);
          break;

/* ************************************************************************************** */
       case EV_SCAN_TIMEOUT:
          debug(PSTR("Event EV_SCAN_TIMEOUT, time: %u \n"), millis() / 1000);
          break;

/* ************************************************************************************** */
       case EV_LOST_TSYNC:
          debug(PSTR("Event EV_LOST_TSYNC, time: %u \n"), millis() / 1000);
          break;

/* ************************************************************************************** */
       case EV_BEACON_TRACKED:
          debug(PSTR("Event EV_BEACON_TRACKED, time: %u \n"), millis() / 1000);
          break;

/* ************************************************************************************** */
       case EV_BEACON_MISSED:
          debug(PSTR("Event EV_BEACON_MISSED, time: %u \n"), millis() / 1000);
          break;

/* ************************************************************************************** */
       default:
          debug(PSTR("Event EV_OTHER, time: %u \n"), millis() / 1000);
          break;
    }
}

/* ************************************************************************************** */
#define KeepAliveTime   120                  // time is sec to restart this task
void do_keepalive(osjob_t* k)
{
      debug(PSTR("\n***  Keep-Alive-Time: %u \n***  Sending ReJoin Request\n"), millis() / 1000);
      //if ( JoinedFlag == false) LMIC_tryRejoin();   // <------------------------------------------------------------------------------------- added to test rejoin
      LMIC_tryRejoin();
 // Re-Schedule a timed job to run this task again at the given timestamp (absolute system time)
      os_setTimedCallback(k, os_getTime()+sec2osticks(KeepAliveTime), do_keepalive); 
} 

/* ************************************************************************************** */
void do_send(osjob_t* j)
{
  if ( JoinedFlag == true) 
    {
      debug(PSTR("\n***  Joined\n"));
      debug(PSTR("Time: %u\nSend, txCnhl: %u \n"), millis() / 1000, LMIC.txChnl);
      debug(PSTR("Opmode check: "));

      // Check if there is not a current TX/RX job running and we are ok to TX
      if (LMIC.opmode & (1 << 7))                  // TXRX-Pending bit 
        {
          debug(PSTR("OP_TXRXPEND, <-- TX/RX was Busy, last msg not yet sent\n"));
        } 
      else 
        {
          debug(PSTR("it's ok to send--\n"));
          // Prepare upstream data transmission at the next possible time.
          LMIC.pendTxConf = true;
          LMIC_setTxData2(1, mydata, sizeof(mydata)-1, true);  // <-------------- ask for confirm 

      //      digitalWrite(myLED, HIGH);
    #ifdef OLED        
            display.clear();
            display.drawString (0, 0, "Sending uplink packet...");    
            display.drawString (0, 48, String (++counter));
            display.display ();
    #endif           
        }

    }
    //LMIC_startJoining();
    // Schedule a timed job to run this task again at the given timestamp (absolute system time)
    os_setTimedCallback(j, os_getTime()+sec2osticks(30), do_send);       // <------------------------- time to send
}

/* ************************************************************************************** */
void setup() 
{

/* ************************************************************************************** */
#ifdef __AVR_ATmega1284P__      // use for Moteino Mega
  Serial.begin(115200);
  delay (2500);

  debug(PSTR("\n ** LMiC Starting on a MoteinoMega **\n") );
    // de-select Flash 
  pinMode(MyFlashCS, OUTPUT);
  digitalWrite(MyFlashCS, HIGH);
    // set the LED digital pin as output:
  pinMode(myLED, OUTPUT);
  digitalWrite(myLED, 0);

/* ************************************************************************************** */
#elif __SAMD21G18A__            // RocketScream
  Serial.begin(115200);
  while (!Serial);    // wait for USB serial port

  debug(PSTR("\n ** LMiC Starting on a RocketScream M0 **\n") );
    // de-select Flash 
  pinMode(MyFlashCS, OUTPUT);
  digitalWrite(MyFlashCS, HIGH);
    // set the LED digital pin as output:
  pinMode(myLED, OUTPUT);
  digitalWrite(myLED, 0);

/* ************************************************************************************** */  
#elif ARDUINO_ARCH_ESP32
  Serial.begin(115200);
  delay (2500);

  debug(PSTR("\n ** LMiC Starting on a ESP32 **\n") );
  SPI.begin(5,19,27,18);
  uint64_t chipid;  
  chipid=ESP.getEfuseMac();                                         //The chip ID is essentially its MAC address(length: 6 bytes).  <---- need to fix
  Serial.printf("ESP32 Chip ID = %04X",(uint16_t)(chipid>>32));     //print High 2 bytes
  Serial.printf("%08X\n",(uint32_t)chipid);                         //print Low 4bytes.
  pinMode(myLED, OUTPUT);
  digitalWrite(myLED, 0);

#endif

/* ************************************************************************************** */ 
#ifdef OLED
//Set up and reset the OLED display
    pinMode(OLED_RESET, OUTPUT);
    digitalWrite(OLED_RESET, LOW);
    delay(50);
    digitalWrite(OLED_RESET, HIGH);

    display.init ();
   // display.flipScreenVertically ();
    display.setFont (ArialMT_Plain_10);
    display.setTextAlignment (TEXT_ALIGN_LEFT);

    display.drawString (0, 0, "Starting....");
    display.display ();
#endif

/* ************************************************************************************** */ 
  const char compile_file[]  = __FILE__ ;
  debug(PSTR(" ** %s %s\n"), SKETCHNAME, SKETCHVERSION);
  debug(PSTR(" ** %s \n"), compile_file);
  const char compile_date[]  = __DATE__ ", " __TIME__;
  debug(PSTR(" ** %s \n\n"), compile_date);

 /* ************************************************************************************** */  
  // LMIC init
  debug(PSTR("***  LMiC os_init \n"));
  os_init();

  // Reset the MAC state. Session and pending data transfers will be discarded.
  debug(PSTR("***  LMIC_reset \n"));
  LMIC_reset();

  // Open up clock tolarence
  LMIC_setClockError(MAX_CLOCK_ERROR * 2 / 100);

// Set static session parameters. Instead of OTAA dynamically establishing a session 
// by joining the network, precomputed session parameters are provided.
// debug(PSTR("***  LMIC_setSession \n"));
//  LMIC_setSession (0x1, DEVADDR, (uint8_t*)DEVKEY, (uint8_t*)ARTKEY);

// Disable data rate adaptation
//  debug(PSTR("***  LMIC_setAdrMode \n"));
//  LMIC_setAdrMode(false);

// Disable link check validation
//  debug(PSTR("***  LMIC_setLinkCheckMode \n"));
//  LMIC_setLinkCheckMode(true);

// Disable beacon tracking
//  debug(PSTR("***  LMIC_disableTracking \n"));
//  LMIC_disableTracking ();  // <-------------------will not run if set on ARM M0

// Stop listening for downstream data (periodical reception)
//  debug(PSTR("***  LMIC_stopPingable \n"));
//  LMIC_stopPingable();

// Set data rate and transmit power (note: txpow seems to be ignored by the library)
//  debug(PSTR("***  LMIC_setDrTxpow \n"));
//  LMIC_setDrTxpow(DR_SF7,20);

// for now only TX on ch 0->15 , disable all others
//  debug(PSTR("***  LMIC_disableChannel, Using Ch = 0 \n"));

//int i = 16;   // Max channel number to use
//  for( u1_t i; i<71; i++ ) 
//    {
//      LMIC_disableChannel(i);
//    }

    LMIC_startJoining();
    JoinedFlag = false;

 // do these once, they will re schedule themselves
    do_send(&sendjob);
    //do_keepalive(&keepalivejob);
    os_setTimedCallback(&keepalivejob, os_getTime()+sec2osticks(KeepAliveTime), do_keepalive); // <---------------------------------------
}
/* ************************************************************************************** */

/* ************************************************************************************** */
void loop() 
{

    os_runloop_once();      // run the LMIC scheduler

 }
/* ************************************************************************************** */
flograsso commented 6 years ago

Hi, have you solved this problem? I have the same issue in my code

utkarshshah007 commented 6 years ago

I don't think a failure to receive an ack on a confirmed uplink is supposed to immediately result in an EV_LINK_DEAD.

Based on this and this EV_LINK_DEAD is triggered if the gateway doesn't ack for the preset LINK_CHECK_DEAD number of uplinks.

As you can see here, that number is set to 24 by default.

Therefore, it makes sense that you get an EV_LINK_DEAD after 25 attempts. If you'd like to change the number of attempts before an EV_LINK_DEAD, you should set LINK_CHECK_DEAD to a custom value.