Hi everyone,
I'm setting up 02 peripheral devices (nRF53832 Dev KIT) that connect to a central device (nRF52840 Dev KIT). In the past few days, I've tested its throughput using only 1 peripheral device to send data to the central one at 250 samples/sec with 16 bytes data packet (15-byte data packet + 1 byte index to check if any data packet loss) as shown in the following figure. I'm using SDK17.02 and NUS service for both peripheral device and central device. I'm using 2M PHY, DLE enabled and ATT MTU 247 bytes.
The following code is the ble_nus_data_send function being used to send data to the central device.
uint32_t ble_nus_data_send(ble_nus_t * p_nus, uint8_t * p_data, uint16_t p_length, uint16_t conn_handle) { ret_code_t err_code; ble_gatts_hvx_params_t hvx_params; ble_nus_client_context_t * p_client; //ble_evt_t const * p_ble_evt; ble_nus_evt_t * p_evt; VERIFY_PARAM_NOT_NULL(p_nus); err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client); VERIFY_SUCCESS(err_code); if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL)) { return NRF_ERROR_NOT_FOUND; } if (!p_client->is_notification_enabled) { return NRF_ERROR_INVALID_STATE; } if (p_length > BLE_NUS_MAX_DATA_LEN) { return NRF_ERROR_INVALID_PARAM; } memset(&hvx_params, 0, sizeof(hvx_params)); hvx_params.handle = p_nus->tx_handles.value_handle; hvx_params.p_data = p_data; hvx_params.p_len = &p_length; hvx_params.type = BLE_GATT_HVX_NOTIFICATION; err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); return err_code; }
I put this function in while (1) loop along with my sensor data saved in array as one of parameters (uint8_t* p_data) in the main.c to keep sending data. The error I got from this function: sd_ble_gatts_hvx() is NRF_ERROR_RESOURCES. Following some suggestions on other posts like this [1, 2], there are two approaches I used:
Approach #1: Once I receive NRF_ERROR_RESOURCES, I resend the data packet till the error goes away. I keep printing the err_code and it showed NRF_SUCCESS; however, I checked on the terminal debug of the central device, I'm still seeing some data packet loss. I noticed some data packets were resent several times. The following illustrates what I'm saying. P/s: I checked on the index number (16th byte) of each data packet and printed out on the central side.
Approach #2: It's slightly similar to the first one, but once I received the NRF_ERROR_RESOURCES, I wait till the BLE_GATTS_EVT_HVN_TX_COMPLETE event happened. This event was triggered at the ble_nus_on_ble_evt function:
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
if ((p_context == NULL) || (p_ble_evt == NULL))
{
return;
}
ble_nus_t * p_nus = (ble_nus_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_hvx_tx_complete(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
So whenever BLE_GATTS_EVT_HVN_TX_COMPLETE event happened, it called the following function, and I used BLE_NUS_EVT_TX_RDY as an event to see if Service is ready to accept new data to be transmitted. I create a bool variable (as a flag) and whenever BLE_NUS_EVT_TX_RDY is called, the flag is TRUE. Thus when sending data to over BLE, if NRF_ERROR_RESOURCES happened, I wait for the flag is TRUE before calling the BLE sending function. However, the data packet loss still happened.
static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_nus_client_context_t * p_client;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gatts_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gatts_evt.conn_handle);
return;
}
if ((p_client->is_notification_enabled) && (p_nus->data_handler != NULL))
{
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.type = BLE_NUS_EVT_TX_RDY;
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
evt.p_link_ctx = p_client;
p_nus->data_handler(&evt);
}
}
Please advise on if I need to update/modify the above approaches to solve data loss problem. Thanks!