Sending fragmented messages - the middle one is lost

Hello!

I am developing an app that requires me to save a “geoFence” on my heltec device and then retrieve it when needed. I tried a fragmentation method and first two messages go through smoothly, but the third message is always lost. If there are more than three messages to be sent then the rest (4th one) will be send and received normaly. In my serial output I can see, that all of the messages are being sent, but on the chirpstack I can’t see the 3rd one. All messages are 51 bytes in length, but last one - it can be smaller. I tried adding padding to last message and it didn’t work too. What is the best way to send fragmented messages? What should I check for when sending them?

If you set them, why do you need to retrieve them?

How far apart at the messages in seconds?

Where are you, aka what regional settings are you using?

What is the SF that the device is using?

Plus, are you using Heltec’s LoRaWAN_APP.h or some other library?

I got this code from some other developer and when I was trying to install libraries that he used none worked. I found some working one on github (I think he did the same looking at his previous work), but honestly I have no idea whether it was the original one. Is that the one from an ArduinoIDE? Can you give me a link to the one I should use? I will try to adjust the code to make it run.

If you can show us what you got, we can advice you on what to do next - maybe you’re close and there’s just a small detail to fix. Or maybe it’s very sub-optimal, in which case we can advice something else. But please, bring to the table whatever you have!

#define MAX_FRAGMENTS_PER_BATCH 2

#define MAX_PAYLOAD_SIZE 51  

#define GEO_PORT 3  

uint8_t currentFragment = 0;

uint8_t totalFragments = 0;

String geofenceDataString = "";

bool isSendingGeofenceData = false;

bool geofenceTransmissionInProgress = false;

void prepareGeofenceDataString() {

    geofenceDataString = "";

    for (size_t i = 0; i < geoFence.vertices.size(); i++) {

        String lat = String(geoFence.vertices[i].y, 6);

        String lng = String(geoFence.vertices[i].x, 6);

        geofenceDataString += lat + "," + lng;

        if (i < geoFence.vertices.size() - 1) {

            geofenceDataString += ";";

        }

    }

    totalFragments = (geofenceDataString.length() + MAX_PAYLOAD_SIZE - 1) / MAX_PAYLOAD_SIZE;

}

void resetGeofenceTransmissionState() {

    currentFragment = 0;  

    isSendingGeofenceData = false;  

    geofenceTransmissionInProgress = false;  // Reset flag when transmission is done

}

void sendGeofenceFragment() {

    if (currentFragment < totalFragments) {

        uint8_t fragmentPayload[MAX_PAYLOAD_SIZE] = {0};

        uint8_t startIdx = currentFragment * MAX_PAYLOAD_SIZE;

        uint8_t fragmentSize = min(static_cast<unsigned int>(MAX_PAYLOAD_SIZE), geofenceDataString.length() - startIdx);

        String fragment = geofenceDataString.substring(startIdx, startIdx + fragmentSize);

        fragment.getBytes(fragmentPayload, fragmentSize + 1);  

        Serial.printf("Preparing to send fragment %d of %d\n", currentFragment + 1, totalFragments);

        for (int i = 0; i < fragmentSize; i++) {

            Serial.printf("%02X ", fragmentPayload[i]);

        }

        Serial.println();

        prepareTxFrame(fragmentPayload, fragmentSize, GEO_PORT);

        LoRaWAN.send();

        currentFragment++;

        Serial.printf("Sent fragment %d of %d\n", currentFragment, totalFragments);

        delay(3000);  

        if (currentFragment >= totalFragments) {

            Serial.println("All fragments sent successfully.");

            resetGeofenceTransmissionState();  

            deviceState = DEVICE_STATE_CYCLE;  

        } else {

            deviceState = DEVICE_STATE_CYCLE;  

        }

    } else {

        Serial.println("No more fragments to send or all fragments sent.");

    }

}

void sendAllGeofenceFragments() {

    Serial.println("Starting sendAllGeofenceFragments...");

    geofenceTransmissionInProgress = true;  // Set flag to indicate geofence transmission is in progress

    prepareGeofenceDataString();

    currentFragment = 0;

    isSendingGeofenceData = true;

    sendGeofenceFragment();

}

void sendGeofenceUplink() {

    switch (deviceState) {

        case DEVICE_STATE_INIT: {

            Serial.println("Initializing LoRaWAN...");

            LoRaWAN.init(loraWanClass, loraWanRegion);

            deviceState = DEVICE_STATE_JOIN;

            break;

        }

        case DEVICE_STATE_JOIN: {

            Serial.println("Joining LoRaWAN network...");

            LoRaWAN.join();

            break;

        }

        case DEVICE_STATE_SEND: {

            if (!isSendingGeofenceData) {

                sendAllGeofenceFragments();  

            } else {

                sendGeofenceFragment();  

            }

            break;

        }

        case DEVICE_STATE_CYCLE: {

            Serial.println("Cycling before continuing with the next fragment...");

            txDutyCycleTime = 3000;  

            LoRaWAN.cycle(txDutyCycleTime);

            deviceState = DEVICE_STATE_SEND;  

            break;

        }

        case DEVICE_STATE_SLEEP: {

            Serial.println("Entering sleep mode...");

            LoRaWAN.sleep();

            break;

        }

        default: {

            deviceState = DEVICE_STATE_INIT;

            break;

        }

    }

}

Then in my loop I have:

if (isSendingGeofenceData) {
sendGeofenceUplink(); // Continue sending geofence fragments
} else {}

I know that at this point my code is very overcomplicated, but I’ve been trying everything now. Thank you for your help!

You’ll be surprised how much help you can get if you give us the info we need! :wink:

Sadly, I have another Q for you - what server / backend / LNS are you using - because a 3 second gap is a bit ambitious in a world where the Rx1 window is 5 seconds …