This is my first time working on BLE and Nordic, so this might sound strange.
I am trying to update data on the fly when the central requests char data.
I have been setting the is_defered_read bit in the char config so I get the event BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST and it works well.
I have then inserted code in on_rw_authorize_request() with something like:
else if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_READ)
NRF_LOG_INFO("Constructing configuration data");
protobufFormatCB_t formatter = GetCfgServiceFormatter();
uint8_t formatResult = 0;
memset(data, 0, sizeof(data));
size_t len = 0;
if (p_parameter_service->conn_handle != BLE_CONN_HANDLE_INVALID)
formatResult = formatter.cb(
params.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
params.params.read.gatt_status = formatResult
params.params.read.update = 1;
params.params.read.offset = p_auth_req->request.read.offset;
params.params.read.len = (int16_t)len;
//params.params.read.len = 20; //Passed 20 bytes, receiving NRF_ERROR_INVALID_PARAM
params.params.read.p_data = data;
uint32_t error_code = sd_ble_gatts_rw_authorize_reply(p_parameter_service->conn_handle, ¶ms);
NRF_LOG_ERROR("Error constructing data: %i", error_code);
It seems that whenever the lenght is greater than 20 bytes, sd_ble_gatts_rw_authorize_reply returns 7 (invalid params).
This seems tied to the MTU somehow, but I haven't found where yet.
What is strange is that I am able the send the whole (110bytes) message via sd_ble_gatts_value_set(...) or sd_ble_gatts_hvx(...), but would rather compute it on the fly with the central request.
I'm sure this is an easy fix, please enlighten me.. :)
It is a bit strange that sd_ble_gatts_hvx() works with 110 bytes, but not read. And this is on the same attribute? I need to look into this. Which SoftDevice and SDK version are you using? Did you use any of the examples in the SDK as a starting point?
I started from blinky, and mofified to include the BMS.
I am using nRF5_SDK_14.0.0_3bcc1f7 with the included SD s140_nrf52840_5.0.0-2.alpha_softdevice.hex
You doubts made me re-test with set() and hvx() and you are right, passed 20 bytes, I have an error as well. I did those tests with a shorter protobuf message, for which size depends on difference from default values...
So if I understand correctly, it is my job to split the message in MTU units? is there a way to send a longer message and have the SDK or SD do the slicing process?
The default ATT MTU is 23 bytes and the default LL payload is 27 bytes. So you can have 20 bytes of data in each packet. You can increase the ATT MTU, then the data will be fragmented into multiple LL packets and reassembled on the other side of the link. If you in addition increase the LL payload size you can send larger pieces of data without fragmentation. One typically increases both. For example and ATT MTU of 247, and a LL payload of 251 (this is max).
See this for how to increase the ATT MTU.
See this for how to increase the LL payload.
You may also find the ble_app_att_mtu_throughput example in the SDK useful.
Ok this all makes a lot of sense. Changing at least MTU helped me send the whole message, thanks!