Hi,
I am trying to understand one thing about the att_mtu_throughput example.
What it does in the char_notification_send() function, which is shown below, is that if it has not sent 1Mbits yet, it tries to send some random data, and increments the counter until for a NRF_ERROR_RESOURCES event is returned, in other words until the queue is full. When the NRF_ERROR_RESOURCES is returned, it sets the busy= true and exits the while loop.
static void char_notification_send(nrf_ble_amts_t * p_ctx)
{
uint8_t data[256];
uint16_t payload_len = p_ctx->max_payload_len;
nrf_ble_amts_evt_t evt;
if (p_ctx->bytes_sent >= AMT_BYTE_TRANSFER_CNT)
{
evt.bytes_transfered_cnt = p_ctx->bytes_sent;
evt.evt_type = NRF_BLE_AMTS_EVT_TRANSFER_FINISHED;
p_ctx->evt_handler(evt);
p_ctx->busy = false;
p_ctx->bytes_sent = 0;
p_ctx->kbytes_sent = 0;
return;
}
ble_gatts_hvx_params_t const hvx_param =
{
.type = BLE_GATT_HVX_NOTIFICATION,
.handle = p_ctx->amts_char_handles.value_handle,
.p_data = data,
.p_len = &payload_len,
};
uint32_t err_code = NRF_SUCCESS;
while (err_code == NRF_SUCCESS)
{
(void)uint32_encode(p_ctx->bytes_sent, data);
err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_param);
if (err_code == NRF_ERROR_RESOURCES)
{
// Wait for BLE_GATTS_EVT_HVN_TX_COMPLETE.
p_ctx->busy = true;
break;
}
else if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("sd_ble_gatts_hvx() failed: 0x%x", err_code);
}
p_ctx->bytes_sent += payload_len;
if (p_ctx->kbytes_sent != (p_ctx->bytes_sent / 1024))
{
p_ctx->kbytes_sent = (p_ctx->bytes_sent / 1024);
evt.evt_type = NRF_BLE_AMTS_EVT_TRANSFER_1KB;
evt.bytes_transfered_cnt = p_ctx->bytes_sent;
p_ctx->evt_handler(evt);
}
}
}
Now it is expected to go to wait for a BLE_GATTS_EVT_HVN_TX_COMPLETE event, which means there is available space in the queue. And the switch case again calls char_notification_send() in the on_tx_complete() function after setting the busy=false. The same procedure loops around until 1Mbit is sent.
void nrf_ble_amts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
nrf_ble_amts_t * p_ctx = (nrf_ble_amts_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_ctx, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_ctx, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_ctx, p_ble_evt);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_tx_complete(p_ctx);
break;
default:
break;
}
}
static void on_tx_complete(nrf_ble_amts_t * p_ctx)
{
if (p_ctx->busy)
{
p_ctx->busy = false;
char_notification_send(p_ctx);
}
}
The thing I do not get is, when NRF_ERROR_RESOURCES is returned and the program exits the while loop, how come and where does it wait for a BLE_GATTS_EVT_HVN_TX_COMPLETE event? When NRF_ERROR_RESOURCES is returned, I expect the program to go back to where char_notification_send() is initially called. However it does not. Is there something the code does in the background that I did not notice?