LMIC.h ACK question

Hi everyone,
I’ve been using the LMIC library for a week trying to use my RF95 to TTN through a multitech conduit gateway. After have a few problems with the library due to its complexity I’ve finally make it work, or, at least, that’s what I though untill I saw this:
Captura_foro
Those many message, at the gateway/traffic console, what are they? Is this normal? Is this allowed?
The debug messages in the COM Port are in the next picture:
Captura_2_foro
I think there is something wrong with the ACK messages. Hope you can help me.
Thanks in advance.
Regards.

I see your node joined the network - 16.07.13
and have device adress 26 01 28 28 (that’s you ) and transmitted 3 frames.
a little bit to fast imho

what’s the problem ?

https://www.thethingsnetwork.org/docs/
ack

The problem is that I don´t know why it is sending 3 messages when I just want to send one but acknowledge. It only happends when I write, in the code, this line: “LMIC_setTxData2(1, mydata, 2, 1);”. The last “1” means that the transmission must be confirmed with an ACK. As you see here:
Captura_retry
When I sent the message, TTN try to confirm many times untill my node recieve the ACK. Those attempts to send the ACK generates those many messages and I don’t know if that is a standard TTN behavior or it is my foult.
The code is exactly the ttn-otaa example in Lmic library but changing that line code.
LMIC_setTxData2(1, mydata, 2, 1); instead of LMIC_setTxData2(1, mydata, 2, 0);
That’s it.
Thank you,
Regards

It’s sending retry messages because it’s not receiving the ACK, though TTN told a gateway to send one.

As you’re using OTAA, you know downlinks work, as it received the OTAA Join Accept. Still then, see also LMiC’s MAX_CLOCK_ERROR.

As an aside: your payload 48656c6c6f2c20776f726c6421 is the text “Hello, world!”, while you somehow show some temperature too. Also, LMIC_setTxData2(1, mydata, 2, 1) suggests you’re only sending 2 bytes. Messy example sketch? I’d clean that up first.

Ok, so I clened the code ( I use a code line from another sketch, sorry about that). I add the “LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);” line and change “LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);” into “LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 1);”. Also chage the payload format at TTN to not show the temperature variable.
That’s the code:

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

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void os_getArtEui (u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void os_getDevEui (u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] ={ 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };
void os_getDevKey (u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
  .nss = 6,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = 5,
  .dio = {2, 3, 4},
};

void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.print(": ");
  switch (ev) {
    case EV_SCAN_TIMEOUT:
      Serial.println(F("EV_SCAN_TIMEOUT"));
      break;
    case EV_BEACON_FOUND:
      Serial.println(F("EV_BEACON_FOUND"));
      break;
    case EV_BEACON_MISSED:
      Serial.println(F("EV_BEACON_MISSED"));
      break;
    case EV_BEACON_TRACKED:
      Serial.println(F("EV_BEACON_TRACKED"));
      break;
    case EV_JOINING:
      Serial.println(F("EV_JOINING"));
      break;
    case EV_JOINED:
      Serial.println(F("EV_JOINED"));

      // Disable link check validation (automatically enabled
      // during join, but not supported by TTN at this time).
      LMIC_setLinkCheckMode(0);
      break;
    case EV_RFU1:
      Serial.println(F("EV_RFU1"));
      break;
    case EV_JOIN_FAILED:
      Serial.println(F("EV_JOIN_FAILED"));
      break;
    case EV_REJOIN_FAILED:
      Serial.println(F("EV_REJOIN_FAILED"));
      break;
      break;
    case EV_TXCOMPLETE:
      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
      if (LMIC.txrxFlags & TXRX_ACK)
        Serial.println(F("Received ack"));
      if (LMIC.dataLen) {
        Serial.println(F("Received "));
        Serial.println(LMIC.dataLen);
        Serial.println(F(" bytes of payload"));
      }
      // Schedule next transmission
      os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
      break;
    case EV_LOST_TSYNC:
      Serial.println(F("EV_LOST_TSYNC"));
      break;
    case EV_RESET:
      Serial.println(F("EV_RESET"));
      break;
    case EV_RXCOMPLETE:
      // data received in ping slot
      Serial.println(F("EV_RXCOMPLETE"));
      break;
    case EV_LINK_DEAD:
      Serial.println(F("EV_LINK_DEAD"));
      break;
    case EV_LINK_ALIVE:
      Serial.println(F("EV_LINK_ALIVE"));
      break;
    default:
      Serial.println(F("Unknown event"));
      break;
  }
}

void do_send(osjob_t* j) {
  // Check if there is not a current TX/RX job running
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    // Prepare upstream data transmission at the next possible time.
    LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 1);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
  Serial.begin(9600);
  Serial.println(F("Starting"));

#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
  // Start job (sending automatically starts OTAA too)
  do_send(&sendjob);
}

Those are the TTN gateway data:
TTN_gateway
Those are the TTN aplication/device data:
TTN_aplication
COM port data:
COM

I hope there is no mistake now and you could help me. As you see, even if I place the ClockError line it still needs like 2 attempts to receive the ACK.

Regards.

Please don’t post images for what is just text (the COM port data).

In both screenshots of the node’s output you see that eventually it got a successful “Received downlink”, which is the ACK. For the earlier attempts, the node did not receive the downlink that the gateway (should have) transmitted. That’s all we can tell.

Both screenshots of TTN Console seem to indicate that the OTAA Join is not successful right away all the time either? An OTAA Join will fail if the node does not receive the OTAA Join Accept that TTN has told a gateway to transmit. That’s also a downlink, just like the ACK is a downlink.

Check your gateway’s logs to see if it indeed got a downlink, and got it in time. (Any chance the uplinks are received by multiple gateways? Click the uplink in TTN Console to see that information.) Increase the allowed clock error. Make sure there at least a few meters between gateway and node. Try with another node. There’s not much else we can advise.

(As an aside: when no longer testing, the don’t send text. That’s a waste of bandwidth. Also, you cannot send every uplink as a confirmed uplink, so to continue testing/developing consider using unconfirmed uplinks.)

Thanks for the response. I will keep on testing.