Downlink not working: Dragino LG01 Gateway + TTGO LoRa V1 with LMIC

Hi! I wanted to tell you about a problem I am having with my LoRa network. The network is made up of a Dragino LG01 gateway and a TTGO LoRa v1 module with the LMIC library.

Everything about UPLINK is working fine. Upload the data with SF8 BW125 on the 904.6MHz frequency. The problem is in the DOWNLINK that I can’t make it work and I don’t know where else to check. According to TTN, it sends the data through SF12 BW500 and in the frequency of 923.3MHz, but I have this configured in the gateway (capture attached) and I think I am correct in the module but it does not work when I send a data with the console’s downlink by TTN. On the gateway I use the " simple_pkt_forwarder_v004".

Any ideas? I checked the LMIC.dn2Freq parameter and it is correctly at 923300000.

I attach other photos of the configuration and the implemented code.
Thanks!!

Captura de pantalla 2021-04-26 a las 16.55.20 p. m. Captura de pantalla 2021-04-26 a las 16.Captura de pantalla 2021-04-26 a las 16.55.20 p. m.|735x1000 Captura de pantalla 2021-04-26 a las 16.Captura de pantalla 2021-04-26 a las 16.55.20 p. m.|735x1000 Captura de pantalla 2021-04-26 a las 16.57.02 p. m.|999x444 test_ttgo.pdf|attachment (28.2 KB) 57.02 p. m.|999x444 57.02 p. m.

This is the implemented code:

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

//Libreria usada para el DHT22
#include <SimpleDHT.h>
// DHT digital pin
#define DHTPIN 25
SimpleDHT22 dht22;

#ifdef COMPILE_REGRESSION_TEST

define FILLMEIN 0

#else

warning “You must replace the values marked FILLMEIN with real values from the TTN control panel!”

define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)

#endif

static const PROGMEM u1_t NWKSKEY[16] = { /This is private/ };
// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = { /This is private/ };
//Device Address
#ifndef COMPILE_REGRESSION_TEST
static const u4_t DEVADDR = 0x/This is private/ ;
#else
static const u4_t DEVADDR = 0;
#endif

// payload to send to TTN gateway
static uint8_t payload[5];
static osjob_t sendjob;

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

// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in arduino-lmic/project_config/lmic_project_config.h,
// otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

//Pin mapping
//For TTGO LoRa32 V1 use:
const lmic_pinmap lmic_pins = {
.nss = 18,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
//If DIO2 is not connected use:
.dio = {/dio0/ 26, /dio1/ 33, /dio2/ LMIC_UNUSED_PIN}
//If DIO2 is connected use:
//.dio = {/dio0/ 26, /dio1/ 33, /dio2/ 32}
};

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”));
break;
/*
|| This event is defined but not used in the code. No
|| point in wasting codespace on it.
||
|| 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;
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;
/

|| This event is defined but not used in the code. No
|| point in wasting codespace on it.
||
|| case EV_SCAN_FOUND:
|| Serial.println(F(“EV_SCAN_FOUND”));
|| break;
/
case EV_TXSTART:
Serial.println(F(“EV_TXSTART”));
break;
case EV_TXCANCELED:
Serial.println(F(“EV_TXCANCELED”));
break;
case EV_RXSTART:
/
do not print anything – it wrecks timing */
Serial.println(F(“EV_RXSTART”));
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F(“EV_JOIN_TXCOMPLETE: no JoinAccept”));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned) ev);
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 {
float temperatura = 58;
float humedad = 45;
//Lectura de la temperatura y humedad del DHT22
//dht22.read2(25, &temperatura, &humedad, NULL);
int centTemperatura=temperatura100.0;
int centHumedad=humedad
100.0;

    payload[0] =(byte)(centTemperatura/100);
    payload[1] = (byte)(centTemperatura%100);
    payload[2] = (byte)(centHumedad/100);
    payload[3] = (byte)(centHumedad%100);

    // prepare upstream data transmission at the next possible time.
    // transmit on port 1 (the first parameter); you can use any value from 1 to 223 (others are reserved).
    // don't request an ack (the last parameter, if not zero, requests an ack from the network).
    // Remember, acks consume a lot of network resources; don't ask for an ack unless you really need it.
    LMIC_setTxData2(1, payload, sizeof(payload)-1, 0);
    Serial.println(F("Packet queued"));
    
    //For test     
    Serial.print(F("LMIC.dndr = "));
    Serial.println(LMIC.dndr); // Datarate TX
    Serial.print(F("LMIC.freq = "));
    Serial.println(LMIC.freq);

    Serial.print(F("LMIC.dn2Freq = "));
    Serial.println(LMIC.dn2Freq);

    Serial.print(F("LMIC.dn2Dr = "));
    Serial.println(LMIC.dn2Dr);

}
// Next TX is scheduled after TX_COMPLETE event.

}

void setup() {
delay(1000);
while (!Serial);
Serial.begin(115200);
delay(100);
Serial.println(F(“Starting”));

// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();

// Set static session parameters. Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
// On AVR, these values are stored in flash and only copied to RAM
// once. Copy them to a temporary buffer here, LMIC_setSession will
// copy them into a buffer of its own again.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x13, DEVADDR, nwkskey, appskey);

// Let LMIC offset for +/- 1% clock error
LMIC_setClockError (MAX_CLOCK_ERROR * 10/100);

// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = 8;

for (int c = 0; c < 72; c++){
  LMIC_disableChannel(c);
}

LMIC_enableChannel(65); //Gateway RX-frequency (904.6MHz)

// Disable link check validation
LMIC_setLinkCheckMode(0);

// Set data rate and transmit power for uplink
LMIC_setDrTxpow(DR_SF8,14);

// Start job
do_send(&sendjob);

}

void loop() {
os_runloop_once();
}

  1. Disconnect your LG01 Single Channel Packet Forwarder from the TTN it is not supported and is disruptive to other users.
  2. Use Forum search(*) to understand why we do not support these LoRa (note NOT LoRaWAN) devices
  3. Treat yourself to a LoRaWAN Gateway (Dragino also provide proper GW’s)

(*) Terms like LG01, LG02, SCPF, DCPF, single/dual channel packet forwarder etc.

1 Like