Sending interval doesn't work

Hello,

I am trying to make a small lora gps tracker using the adafruit feather m0 rfm915. I have the following code, which works and sends what it should, but transmission runs only once (see serial monitor at the bottom), not in a loop at specified interval. I need to make TX send fom 30 to 30 seconds. Any ideea what i am doing wrong? Thanks in advance.

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


osjob_t sendTTNjob;
const unsigned long TX_INTERVAL = 30;
TinyGPSPlus gps;


const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},
    .rxtx_rx_active = 0,
    .rssi_cal = 8,              // LBT cal for the Adafruit Feather M0 LoRa, in dB
    .spi_freq = 8000000,
};

// 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]={ };
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]={ };
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] = {};
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}


uint8_t coords[9];
uint32_t LatitudeBinary, LongitudeBinary;
uint16_t altitudeGps;
uint8_t hdopGps;
static osjob_t sendjob;



void get_coords () {

  for (unsigned long start = millis(); millis() - start < 1000;) {
    while (Serial1.available()) {
      char c = Serial1.read();
      Serial.write(c); 
      gps.encode(c);
    }
  }

  if (gps.location.isValid()) {

    LatitudeBinary = ((gps.location.lat() + 90) / 180.0) * 16777215;
    LongitudeBinary = ((gps.location.lng() + 180) / 360.0) * 16777215;

    coords[0] = ( LatitudeBinary >> 16 ) & 0xFF;
    coords[1] = ( LatitudeBinary >> 8 ) & 0xFF;
    coords[2] = LatitudeBinary & 0xFF;

    coords[3] = ( LongitudeBinary >> 16 ) & 0xFF;
    coords[4] = ( LongitudeBinary >> 8 ) & 0xFF;
    coords[5] = LongitudeBinary & 0xFF;

    altitudeGps = gps.altitude.meters();
    coords[6] = ( altitudeGps >> 8 ) & 0xFF;
    coords[7] = altitudeGps & 0xFF;

    hdopGps = gps.hdop.value() / 10;
    coords[8] = hdopGps & 0xFF;
  }
}

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.
    get_coords();
    LMIC_setTxData2(1, (uint8_t*) coords, sizeof(coords), 0);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

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"));
      // Start sending data to TTN
      os_setCallback(&sendTTNjob, do_send);
      LMIC_setLinkCheckMode(0);
      break;
    case EV_JOIN_FAILED:
      Serial.println(F("EV_JOIN_FAILED"));
      break;
    case EV_REJOIN_FAILED:
      Serial.println(F("EV_REJOIN_FAILED"));
      break;

    case EV_TXCOMPLETE:
      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
      digitalWrite(LED_BUILTIN, LOW); 
      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"));
      }
          os_setTimedCallback(&sendTTNjob, 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;
    case EV_TXSTART:
      Serial.println(F("EV_TXSTART"));
      break;
    default:
      Serial.println(F("Unknown event"));
      break;
  }
}


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

  Serial1.begin(9600);
  delay(5000);
  Serial1.print("$PMTK301,2*2E\r\n");  // Select SBAS as DGPS source (RTCM)
  Serial1.print("$PMTK313,1*2E\r\n");  // Enable to search a SBAS satellite
  Serial1.print("$PMTK513,1*28\r\n");

  // LMIC init
  os_init();

  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();
  LMIC_setClockError(MAX_CLOCK_ERROR * 5 / 100);
    LMIC_setLinkCheckMode(0);
    LMIC_setDrTxpow(DR_SF7,14);
    LMIC_setAdrMode(0);
do_send(&sendTTNjob);
}

void loop() {
 os_runloop_once();
}

And the serial monitor output:

07:37:59.860 -> $GPGSV,3,1,11,02,33,049,15,05,24,105,,11,20,044,,12,25,121,*73
07:37:59.907 -> $GPGSV,3,2,11,18,34,199,,20,25,067,,22,00,256,,25,66,125,*73
07:38:00.000 -> $GPGSV,3,3,11,26,16,306,17,29,76,321,,31,42,283,*4E
07:38:00.046 -> $GPGLL,,,,,043757.00,V,N*48
07:38:00.140 -> Packet queued
07:38:00.140 -> 376205: EV_JOINING
07:38:08.020 -> 866599: EV_TXSTART
07:38:13.124 -> 1187829: EV_JOINED
07:38:13.124 -> 1188012: EV_TXSTART
07:38:13.124 -> OP_TXRXPEND, not sending
07:38:14.262 -> 1257189: EV_TXCOMPLETE (includes waiting for RX windows)
07:38:18.782 -> 1540938: EV_TXSTART

Yes you are sending interval is to frequent, please read FUP and TTN you need to only use max 30 sec a day airtime.

And you are also most probably breaking the law.

GPS trackers are not a good fit for a TTN application.

It seems logical that you dont know where the device being tracked is so you need to assume it can be at a long distance from a Gateway, thus you should further assume it may be using spreading factor 12 mode for maximum range.

You can get a location payload in a packet that has an air time of circa 1.2 seconds @ SF12.

Thus the TTN fair access limit useage is 30 / 1.2 = 25 packets a day or one location transmission per hour.

And equally, you can’t assume it is even in range of a gateway - which makes it entirely useless:

“Yes officer, I tracked it as it left the city and then it was in an area with no gateway coverage”

“So where is it now?”

“I don’t know”