mcci-catena / arduino-lorawan

User-friendly library for using arduino-lmic with The Things Network and other LoRaWAN® networks
MIT License
274 stars 54 forks source link

Preconditions for calling myLoRaWAN.SendBuffer()? #209

Open matthias-bs opened 1 year ago

matthias-bs commented 1 year ago

Hi,

My sketch is based on the example simple_sensor_bme280.ino I am using a modified version of doUplink(void) which works just fine. Then I have added a receive callback function named ReceiveCb with SetReceiveBufferBufferCb(ReceiveCb) to handle downlink messages - this works as expected, too. Finally I would like to add another function to call SendBuffer() for an uplink of status data (if requested by a command in a downlink message).

I have tried a similar approach as in doUplink() to check if SendBuffer() can be called:

// if busy uplinking, just skip
if (this->m_fBusy)
    return;
// if LMIC is busy, just skip
if (LMIC.opmode & (OP_POLL | OP_TXDATA | OP_TXRXPEND))
    return;

The first condition is clear, but I'm not sure how to handle the second one.

Why are there 3 different flags checked in LMIC.opmode? What is the difference between this and just calling GetTxReady()?

With my current trials, I either get no uplink at all (if I compare LMIC.opmode as above) or the uplink is reported to have zero payload and an undefined port [how is that possible?] (if I ignore LMIC.opmode and just check the status flag of doUplink()).

Thanks in advance for your help!

Best regards, Matthias

matthias-bs commented 1 year ago

Here is my code. doCfgUplink() is called from the Arduino execution loop if the flag uplinkReq was set [by the downlink callback function].

void
cMyLoRaWAN::doCfgUplink(void) {
    // if busy uplinking, just skip
    if (this->m_fBusy || mySensor.isBusy()) {
        return;
    }
    // if LMIC is busy, just skip
    //if (LMIC.opmode & (OP_POLL | OP_TXDATA | OP_TXRXPEND)) {
    //    log_v("LMIC.opmode: 0x%02X", LMIC.opmode);
    //    return;
    //}

    log_d("--- Uplink Configuration/Status ---");

    uint8_t uplink_payload[5];
    uint8_t port;

    // Encode data as byte array for LoRaWAN transmission
    LoraEncoder encoder(uplink_payload);

    if (uplinkReq == CMD_GET_DATETIME) {
        log_d("Date/Time");
        port = 2;
        time_t t_now = rtc.getLocalEpoch();
        encoder.writeUint8((t_now >> 24) & 0xff);
        encoder.writeUint8((t_now >> 16) & 0xff);
        encoder.writeUint8((t_now >>  8) & 0xff);
        encoder.writeUint8( t_now        & 0xff);
        log_v("Size: %d", encoder.getLength());
    } else {
      log_v("");
        return;
    }

    this->m_fBusy = true;

    // Schedule transmission
    if (! myLoRaWAN.SendBuffer(
        uplink_payload, encoder.getLength(),
        // this is the completion function:
        [](void *pClientData, bool fSucccess) -> void {
            auto const pThis = (cMyLoRaWAN *)pClientData;
            pThis->m_fBusy = false;
            uplinkReq = 0;
        },
        (void *)this,
        /* confirmed */ true,
        /* port */ port
        )) {
        // sending failed; callback has not been called and will not
        // be called. Reset busy flag.
        this->m_fBusy = false;
        uplinkReq = 0;
    }
}
matthias-bs commented 1 year ago

Some more insights - I added checking of GetTxReady() at the beginning and a little debug output:

    this->m_fBusy = true;
    log_v("Trying SendBuffer: port=%d, size=%d", port, encoder.getLength());

    // Schedule transmission
    if (! myLoRaWAN.SendBuffer(
        uplink_payload, encoder.getLength(),
        // this is the completion function:
        [](void *pClientData, bool fSucccess) -> void {
            auto const pThis = (cMyLoRaWAN *)pClientData;
            pThis->m_fBusy = false;
            uplinkReq = 0;
            log_v("Sending successful");
        },
        (void *)this,
        /* confirmed */ true,
        /* port */ port
        )) {
        // sending failed; callback has not been called and will not
        // be called. Reset busy flag.
        this->m_fBusy = false;
        uplinkReq = 0;
        log_v("Sending failed");
    }
}

Resulting in:

20:58:34.622 -> [132258][V][BresserWeatherSensorTTN.ino:1126] doCfgUplink(): Trying SendBuffer: port=2, size=5
20:58:34.622 -> [132267][V][BresserWeatherSensorTTN.ino:1136] operator()(): Sending successful
20:58:34.622 -> [132274][V][BresserWeatherSensorTTN.ino:1146] doCfgUplink(): Sending failed
  1. Port and payload size are as expected
  2. The completion function is called
  3. SendBuffer() returns false (which may be o.k. or not if I understand the comments in https://github.com/mcci-catena/arduino-lorawan/blob/master/src/lib/SendBuffer.cpp correctly)

The contents of uplink_payload are as expected.