how to do long write or reliable write from Android to nrf?

I'm close but this is not working for me yet. I'm trying to send a few hundred bytes from android to my nrf device.  So I tried to implement long write where you set prepare and execute flags.  But in Android I could never get the flags to send no matter what approach I tried. And since I"m out of gas I thought I'd ask here.  I can send data to this characteristic just fine, but without the flags it just falls out.  Is there a way to make this work or do I need to rearchitect and do it manually?

On the android side I've tried reliablewrite approach, just sending with writecharacteristic, and many others.  Thanks for any advice.

This is my nordic side code:

static ssize_t write_long_characteristic(struct bt_conn *conn,
                                         const struct bt_gatt_attr *attr,
                                         const void *buf,
                                         uint16_t len,
                                         uint16_t offset,
                                         uint8_t flags) {
    // Automatically reset the buffer if this is the first Prepare Write of a new file
    if (offset == 0 && (flags & BT_GATT_WRITE_FLAG_PREPARE)) {
        reset_long_write_buffer();  // Reset the buffer for new file transfer
        printk("Reset Buffer");
    }

    // Check for Prepare Write phase
    if (flags & BT_GATT_WRITE_FLAG_PREPARE) {
        printk("Prepare Write received: offset=%u, len=%u\n", offset, len);

        // Ensure we don't exceed the buffer size
        if (offset + len > sizeof(long_write_buffer)) {
            printk("Error: Buffer overflow\n");
            return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);  // Return an error code
        }

        // Copy the incoming data to the buffer at the specified offset
        memcpy(long_write_buffer + offset, buf, len);
        long_write_len = offset + len;  // Update the total length

        return len;  // Return the number of bytes written
    }

    // Check for Execute Write phase
    if (flags & BT_GATT_WRITE_FLAG_EXECUTE) {
        printk("Execute Write received, total length: %zu\n", long_write_len);

        // Process the buffered data
        //process_long_write_data(long_write_buffer, long_write_len);

        // Reset the buffer for the next long write operation
        long_write_len = 0;

        return len;
    }

    printk("We don't like what you're selling\n");
    return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);  // Handle unexpected cases
}

Parents
  • Hello,

    Can I ask what caused you to try "long write"? As far as I can tell, you are trying to write only to one characteristic, right?

    The name is a bit deceiving. This is intended in the cases where you want to update multiple characteristics at the same time. Not in the cases where you want to update the same characteristic multiple times (to write a longer message). If you want to write a long message, you should either increase the MTU and data length, or simply just split the message up to smaller chunks and send them one after another. 

    So how long is the message that you are trying to send? And how often do you send this message? (is throughput an issue?)

    Best regards,

    Edvin

Reply
  • Hello,

    Can I ask what caused you to try "long write"? As far as I can tell, you are trying to write only to one characteristic, right?

    The name is a bit deceiving. This is intended in the cases where you want to update multiple characteristics at the same time. Not in the cases where you want to update the same characteristic multiple times (to write a longer message). If you want to write a long message, you should either increase the MTU and data length, or simply just split the message up to smaller chunks and send them one after another. 

    So how long is the message that you are trying to send? And how often do you send this message? (is throughput an issue?)

    Best regards,

    Edvin

Children
  • so 500b to 1000b, message is rarely sent and then only to one characteristic.  I was just learning and wasn't sure if I could always adjust the MTU size (like maybe one android version would restrict me or I'd run into some other problem).

  • e_engineer said:
    like maybe one android version would restrict me or I'd run into some other problem

    That is true, and I am not really sure exactly how to do it from the Android side. It is possible to request it from the nRF side, and it probably gives a callback in the Android application when it has changed. 

    It depends on how long MTU the phone gives you. Typically, really old phones only support the standard 23 bytes. but most newer phones will give you between 180 and the maximum of 247 (some even gives higher, around 500, but in this case the message is split up on the air either way, so there is really little benefits of going over 247, from a time and power perspective).

    So I suggest that either your android app or the nRF tries to request a higher MTU. And depending on what the resulting MTU will be, you can use this message length, and just send them back to back. They will appear on the nRF in the same order that you sent them. BLE is "lossless" meaning as long as you don't disconnect, all packets will be retransmitted until they are ACKed correctly.

    Best regards,

    Edvin

Related