Hello everyone,
I'm developing an application for boards with NRF52832, Softdevice S132 3.00 and SDK 12.3.0.
The network architecture consists of:
- one peripheral board (slave) with NUS and BAS services
- one central plus peripheral board (master) with central plus peripheral NUS and BAS services
- an android device which would connect to the central device (master)
The peripheral/slave application is working properly, has been tried directly connecting to the android device. It's based on the UART peripheral example of the SDK.
The central/master application is based on the ble_central_and_peripheral ble_app_hrs_rscs_relay example. I changed the HRS and RSCS services for NUS service and set it up for only one peripheral link. When connected to the Android device and a peripheral device with only NUS, it works properly. But when I added the BAS service to the slave, the error appeared on the master.
And thus, when the master device discovers the two UUIDs of NUS and BAS services in the advertising data, it tries to enable the notification and register the CCCD with the softdevice. This works for the first service (BAS in this case), but the second time it doesn't work because the softdevice returns NRF_ERROR_BUSY.
As I've learned, this is normal when I don't give enough time to the softdevice to do the ATT write request to the peer (as in this diagram). I've seen some other threads in the devzone with the same problem, but I can't find a workaround.
What I've tried so far is to create a flag which waits for the softdevice to answer with a BLE_GATTC_EVT_WRITE_RSP event after I register the first service. Then, I wait for the flag to be activated until try to register the second service. But the problem is that the while I write to wait for the flag turns out to be an endless loop. Could it be a problem of interrupt priorities?
This is the relevant code I added to the application:
Flag declaration:
static volatile uint8_t sd_gattc_write_rsp_rx = 1;
BLE_GATTC_EVT_WRITE_RSP in on_ble_central_evt function:
case BLE_GATTC_EVT_WRITE_RSP: // Response from SD NRF_LOG_DEBUG("**** GATT Client Write Response.\r\n"); sd_gattc_write_rsp_rx = 1; break; // BLE_GATTC_EVT_WRITE_RSP
db_disc_handler function:
static void db_disc_handler(ble_db_discovery_evt_t * p_evt) { while(!sd_gattc_write_rsp_rx) { // The program stays here forever ret_code_t err_code = sd_app_evt_wait(); APP_ERROR_CHECK(err_code); }; sd_gattc_write_rsp_rx = 0; ble_bas_on_db_disc_evt(&m_ble_bas_c, p_evt); ble_nus_c_on_db_disc_evt(&m_ble_nus_c, p_evt); }
Here is where the program crashes if I don't wait for the softdevice response:
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, const ble_nus_c_evt_t * p_ble_nus_evt) { uint32_t err_code; switch (p_ble_nus_evt->evt_type) { case BLE_NUS_C_EVT_DISCOVERY_COMPLETE: err_code = ble_nus_c_handles_assign(p_ble_nus_c, p_ble_nus_evt->conn_handle, &p_ble_nus_evt->handles); APP_ERROR_CHECK(err_code); err_code = ble_nus_c_rx_notif_enable(p_ble_nus_c); APP_ERROR_CHECK(err_code); // ERROR 0x11 (17 - NRF_ERROR_BUSY) NRF_LOG_INFO("Nordic UART service discovered on conn_handle 0x%x\r\n", p_ble_nus_evt->conn_handle); break; case BLE_NUS_C_EVT_NUS_RX_EVT: // Handle data break; case BLE_NUS_C_EVT_DISCONNECTED: NRF_LOG_INFO("Nordic UART service disconnected\r\n"); scan_start(); break; } }
How should I properly manage the BLE_GATTC_EVT_WRITE_RSP of the softdevice?
Anyone has an example of a central device connecting to a peripheral device with two services?
Thank you very much in advance.