h2zero/NimBLE-Arduino

Characteristic callback disconnected when value size is greater than 20 bytes

Closed this issue · 7 comments

I'm trying to add multiple sensors data into one characteristic value, like "v1,v2,v3" rather creating characteristic for each sensor. The issue I am encountering is that when this value goes beyond 20 length, the onRead callback is disconnected.

I've override in local nimconfig.h for CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH set to 64, but it seems the value doesn't apply at runtime.

After the override, I've cleaned the project so all the files are compiled again. I've tried to set it to other values as well, like 48, 40 and even 128. But as soon as the length goes over 20, the callback is disconnected.

Here's samples code:

class MyBleCallbacks : public NimBLECharacteristicCallbacks
{
    void onRead(NimBLECharacteristic *pCharacteristic, NimBLEConnInfo &connInfo)
    {
        std::string uuid = pCharacteristic->getUUID();

        // old value
        Serial.println("MyBleCallbacks-onRead: " + String(pCharacteristic->getValue().c_str()));

        if(uuid == UUID_DATA1)
        {
                // update value
                pCharacteristic->setValue<String>("123,345,123,456,567,123,567,679,456,978,234,423");
        }
    }
}

If the value is more than 20 bytes then the client device needs to use a long read command or trigger an MTU exchange to negotiate a larger amount.

Thanks for your response,

The default MTU is 255, the value I want to set is under 48 characters string.

I've implemented firmware OTA for with 255 MTU and 244 bytes data packets, where client is writing characteristic value. It works perfectly. But in reading the value back from ESP32 to client, I'm facing this 20 character limit issue.

I've tried with changing the value length define, and also by setting the desired size when creating the characteristic, but it doesn't apply.

h2zero commented

The value length that you are setting is for the max characteristic size, if left at default it will be 512 bytes, so that is not the issue.

Does the client actually exchange MTU? There is a server callback onMTUChange that you should use to find out. If that is not called then it's not going to read more than 20 bytes unless a long read is used.

Not sure what the client is but if it is a custom app or device you should check what is happening there.

Thanks for the reply,

The client is an Android mobile phone with LightBlue app for testing this.

After BLE connection is established, I debug print the negotiated MTU, which is by default 255.

I will go through my code once more and update here if I got it working with changing MTU. My guess is the max length set from CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH or when creating characteristic is not being applied.

h2zero commented

I will go through my code once more and update here if I got it working with changing MTU. My guess is the max length set from CONFIG_NIMBLE_CPP_ATT_VALUE_INIT_LENGTH or when creating characteristic is not being applied.

This has nothing to do with your issue, the value container dynamically adjusts to the data size, your data is all there.

Use a different app (nRFConnect) or another esp32 as a client and you will see your data and callback called.

Thanks for clarification. I am definitely going to try with other clients. Also, after connecting, updating the connection parameters from server with setMTU to larger value.

@h2zero you've correctly pointed out that this was not an issue with the NimBLE server side, rather client side issue. I've tried both LightBlue and nRFConnect apps, and they both seem to have this issue, even when updating the MTU from server after connection.

I tested it with own Flutter based Android app which will work with ESP32 I'm programming, and it worked without this issue.

I am going to leave feedback to both LightBlue and nRFConnect apps to fix the issue in the app.

Thanks again for your help. Highly appreciated.