diff --git a/components/ble/peer_manager/gatt_cache_manager.c b/components/ble/peer_manager/gatt_cache_manager.c index 140b4dbd..79a808b6 100644 --- a/components/ble/peer_manager/gatt_cache_manager.c +++ b/components/ble/peer_manager/gatt_cache_manager.c @@ -284,6 +284,48 @@ static bool local_db_update_in_evt(uint16_t conn_handle) } #if PM_SERVICE_CHANGED_ENABLED + + +/**@brief Function for getting the value of the CCCD for the service changed characteristic. + * + * @details This function will search all system handles consecutively. + * + * @param[in] conn_handle The connection to check. + * @param[out] p_cccd The CCCD value of the service changed characteristic for this link. + * + * @return Any error from @ref sd_ble_gatts_value_get or @ref sd_ble_gatts_attr_get. + */ +static ret_code_t service_changed_cccd(uint16_t conn_handle, uint16_t * p_cccd) +{ + bool sc_found = false; + uint16_t end_handle; + + ret_code_t err_code = sd_ble_gatts_initial_user_handle_get(&end_handle); + ASSERT(err_code == NRF_SUCCESS); + + for (uint16_t handle = 1; handle < end_handle; handle++) + { + ble_uuid_t uuid; + ble_gatts_value_t value = {.p_value = (uint8_t *)&uuid.uuid, .len = 2, .offset = 0}; + + err_code = sd_ble_gatts_attr_get(handle, &uuid, NULL); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + else if (!sc_found && (uuid.uuid == BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED)) + { + sc_found = true; + } + else if (sc_found && (uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)) + { + value.p_value = (uint8_t *)p_cccd; + return sd_ble_gatts_value_get(conn_handle, handle, &value); + } + } + return NRF_ERROR_NOT_FOUND; +} + /**@brief Function for sending a service changed indication in an event context, where no return * code can be given. * @@ -319,8 +361,26 @@ static void service_changed_send_in_evt(uint16_t conn_handle) break; case NRF_ERROR_INVALID_STATE: - // CCCDs not enabled. Drop indication. - // Fallthrough. + { + uint16_t cccd; + err_code = service_changed_cccd(conn_handle, &cccd); + if ((err_code == NRF_SUCCESS) && cccd) + { + // Possible ATT_MTU exchange ongoing. + // Do nothing, treat as busy. + break; + } + else + { + if (err_code != NRF_SUCCESS) + { + NRF_LOG_DEBUG("Unexpected error when looking for service changed CCCD: %s", + nrf_strerror_get(err_code)); + } + // CCCDs not enabled or an error happened. Drop indication. + // Fallthrough. + } + } case NRF_ERROR_NOT_SUPPORTED: // Service changed not supported. Drop indication.