diff --git a/host/src/channel_manager.rs b/host/src/channel_manager.rs index e2a24d75..5a1d7555 100644 --- a/host/src/channel_manager.rs +++ b/host/src/channel_manager.rs @@ -726,6 +726,17 @@ impl<'d, P: PacketPool> ChannelManager<'d, P> { Ok(()) } + pub(crate) async fn send_conn_param_update_req( + &self, + handle: ConnHandle, + host: &BleHost<'d, T, P>, + param: &ConnParamUpdateReq, + ) -> Result<(), BleHostError> { + let identifier = self.next_request_id(); + let mut tx = [0; 16]; + host.l2cap_signal(handle, identifier, param, &mut tx[..]).await + } + fn connected_channel_params(&self, index: ChannelIndex) -> Result<(ConnHandle, u16, u16, u16), Error> { let state = self.state.borrow(); let chan = &state.channels[index.0 as usize]; diff --git a/host/src/connection.rs b/host/src/connection.rs index a47e2e7f..289c06d4 100644 --- a/host/src/connection.rs +++ b/host/src/connection.rs @@ -1,6 +1,6 @@ //! BLE connection. -use bt_hci::cmd::le::{LeConnUpdate, LeReadPhy, LeSetPhy}; +use bt_hci::cmd::le::{LeConnUpdate, LeReadLocalSupportedFeatures, LeReadPhy, LeSetPhy}; use bt_hci::cmd::status::ReadRssi; use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync}; use bt_hci::param::{ @@ -18,6 +18,7 @@ use crate::pdu::Pdu; use crate::prelude::{AttributeServer, GattConnection}; #[cfg(feature = "security")] use crate::security_manager::BondInformation; +use crate::types::l2cap::ConnParamUpdateReq; use crate::{BleHostError, Error, Identity, PacketPool, Stack}; /// Connection configuration. @@ -304,27 +305,44 @@ impl<'stack, P: PacketPool> Connection<'stack, P> { params: &ConnectParams, ) -> Result<(), BleHostError> where - T: ControllerCmdAsync, + T: ControllerCmdAsync + ControllerCmdSync, { let handle = self.handle(); - match stack - .host - .async_command(LeConnUpdate::new( - handle, - params.min_connection_interval.into(), - params.max_connection_interval.into(), - params.max_latency, - params.supervision_timeout.into(), - params.event_length.into(), - params.event_length.into(), - )) - .await - { - Ok(_) => Ok(()), - Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => { - Err(crate::Error::Disconnected.into()) + // First, check the local supported features to ensure that the connection update is supported. + let features = stack.host.command(LeReadLocalSupportedFeatures::new()).await?; + if features.supports_conn_parameters_request_procedure() || self.role() == LeConnRole::Central { + match stack + .host + .async_command(LeConnUpdate::new( + handle, + params.min_connection_interval.into(), + params.max_connection_interval.into(), + params.max_latency, + params.supervision_timeout.into(), + params.event_length.into(), + params.event_length.into(), + )) + .await + { + Ok(_) => Ok(()), + Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => { + Err(crate::Error::Disconnected.into()) + } + Err(e) => Err(e), } - Err(e) => Err(e), + } else { + // Use L2CAP signaling to update connection parameters + info!("Connection parameters request procedure not supported, use l2cap connection parameter update req instead"); + let interval_min: bt_hci::param::Duration<1_250> = params.min_connection_interval.into(); + let interva_max: bt_hci::param::Duration<1_250> = params.max_connection_interval.into(); + let timeout: bt_hci::param::Duration<10_000> = params.supervision_timeout.into(); + let param = ConnParamUpdateReq { + interval_min: interval_min.as_u16(), + interval_max: interva_max.as_u16(), + latency: params.max_latency, + timeout: timeout.as_u16(), + }; + stack.host.send_conn_param_update_req(handle, ¶m).await } } diff --git a/host/src/host.rs b/host/src/host.rs index c5da3205..7d8bf379 100644 --- a/host/src/host.rs +++ b/host/src/host.rs @@ -45,8 +45,8 @@ use crate::pdu::Pdu; #[cfg(feature = "security")] use crate::security_manager::SecurityEventData; use crate::types::l2cap::{ - L2capHeader, L2capSignal, L2capSignalHeader, L2CAP_CID_ATT, L2CAP_CID_DYN_START, L2CAP_CID_LE_U_SECURITY_MANAGER, - L2CAP_CID_LE_U_SIGNAL, + ConnParamUpdateReq, L2capHeader, L2capSignal, L2capSignalHeader, L2CAP_CID_ATT, L2CAP_CID_DYN_START, + L2CAP_CID_LE_U_SECURITY_MANAGER, L2CAP_CID_LE_U_SIGNAL, }; use crate::{att, Address, BleHostError, Error, PacketPool, Stack}; @@ -578,6 +578,14 @@ where }) } + pub(crate) async fn send_conn_param_update_req( + &self, + handle: ConnHandle, + param: &ConnParamUpdateReq, + ) -> Result<(), BleHostError> { + self.channels.send_conn_param_update_req(handle, self, param).await + } + /// Read current host metrics pub(crate) fn metrics R, R>(&self, f: F) -> R { let m = self.metrics.borrow();