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?