cbluetooth-lowenergyraspberry-pi-picobtstack

How to send large (>2KB) packets using [BTstack] BLE


I am writing a C application on a raspberry pico W which utilizes the BTstack library. I have a characteristic that points to a 2 kB buffer of data. When a client device signals to ready this data, I am currently only getting several hundred bytes to be send to the client. Based on all the examples I can find, this is the code I have that gets triggered whenever a read happens:

uint16_t att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size) {
    UNUSED(connection_handle);

    if (att_handle == ATT_CHARACTERISTIC_ORG_QT_CHARACTERISTIC_HEARTBEAT_COVERAGE_01_VALUE_HANDLE) {
        
        return att_read_callback_handle_blob((const uint8_t *)&coverage_buffer, sizeof(coverage_buffer), offset, buffer, buffer_size);
    }
    return 0;
}

I've added some print statements just before calling the att_read_callback_handle_blob() and I can see that the att_read_callback is invoked numerous times as BTstack attempts to send the whole packet. However instead of sending all 2000 bytes I am only receiving around 750 bytes.


Solution

  • As Martijn van Welie mentioned, there is only a limited number of bytes that you can send per BLE read, and in order to read the whole remote characteristic value, this should be done over several read attempts. From the code you shared, there is this offset parameter that specifies the beginning of the data that you want to read. Depending on the amount of data that you are reading per operation (e.g. each read operation returns 240 bytes of data), you need to perform multiple reads in order to read the full 2kB of data (i.e. for your second read attempt, the offset should be 241, then for the third read attempt, the offset neds to be 482, and so on).

    Please note that you cannot/shouldn't read data in quick succession. For all read attempts, you have to first wait for the completion of the previous read attempt before you make a new one. In your case, this means that you need to wait for the handler to kick in (att_read_callback()) before making a new read attempt.