1use bt_hci::cmd::le::{
4 LeConnUpdate, LeConnectionRateRequest, LeFrameSpaceUpdate, LeReadLocalSupportedFeatures, LeReadPhy,
5 LeSetDataLength, LeSetPhy,
6};
7use bt_hci::cmd::status::ReadRssi;
8use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
9use bt_hci::param::{
10 AllPhys, ConnHandle, DisconnectReason, FilterDuplicates, FrameSpaceInitiator, LeConnRole, PhyKind, PhyMask,
11 PhyOptions, SpacingTypes, Status,
12};
13#[cfg(feature = "connection-params-update")]
14use bt_hci::{
15 cmd::le::{LeRemoteConnectionParameterRequestNegativeReply, LeRemoteConnectionParameterRequestReply},
16 param::RemoteConnectionParamsRejectReason,
17};
18#[cfg(feature = "gatt")]
19use embassy_sync::blocking_mutex::raw::RawMutex;
20use embassy_time::Duration;
21
22use crate::connection_manager::ConnectionManager;
23#[cfg(feature = "connection-metrics")]
24pub use crate::connection_manager::Metrics as ConnectionMetrics;
25use crate::pdu::Pdu;
26#[cfg(feature = "gatt")]
27use crate::prelude::{AttributeServer, GattConnection};
28#[cfg(feature = "security")]
29use crate::security_manager::{BondInformation, PassKey};
30use crate::types::l2cap::ConnParamUpdateRes;
31use crate::{bt_hci_duration, Address, BleHostError, Error, Identity, PacketPool, Stack};
32
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum SecurityLevel {
41 NoEncryption,
43 Encrypted,
45 EncryptedAuthenticated,
47}
48
49impl SecurityLevel {
50 pub fn encrypted(&self) -> bool {
52 !matches!(self, SecurityLevel::NoEncryption)
53 }
54
55 pub fn authenticated(&self) -> bool {
57 matches!(self, SecurityLevel::EncryptedAuthenticated)
58 }
59}
60
61pub struct ConnectConfig<'d> {
63 pub scan_config: ScanConfig<'d>,
65 pub connect_params: RequestedConnParams,
67}
68
69pub struct ScanConfig<'d> {
71 pub active: bool,
73 pub filter_accept_list: &'d [Address],
75 pub phys: PhySet,
77 pub interval: Duration,
79 pub window: Duration,
81 pub timeout: Duration,
83 pub filter_duplicates: FilterDuplicates,
85}
86
87impl Default for ScanConfig<'_> {
88 fn default() -> Self {
89 Self {
90 active: true,
91 filter_accept_list: &[],
92 phys: PhySet::M1,
93 interval: Duration::from_secs(1),
94 window: Duration::from_secs(1),
95 timeout: Duration::from_secs(0),
96 filter_duplicates: FilterDuplicates::Disabled,
97 }
98 }
99}
100
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103#[derive(Eq, PartialEq, Copy, Clone)]
104#[repr(u8)]
105pub enum PhySet {
106 M1 = 1,
108 M2 = 2,
110 M1M2 = 3,
112 Coded = 4,
114 M1Coded = 5,
116 M2Coded = 6,
118 M1M2Coded = 7,
120}
121
122#[derive(Debug, Clone, PartialEq)]
124#[cfg_attr(feature = "defmt", derive(defmt::Format))]
125pub struct RequestedConnParams {
126 pub min_connection_interval: Duration,
128 pub max_connection_interval: Duration,
130 pub max_latency: u16,
132 pub min_event_length: Duration,
134 pub max_event_length: Duration,
136 pub supervision_timeout: Duration,
138}
139
140impl RequestedConnParams {
141 pub fn is_valid(&self) -> bool {
143 self.min_connection_interval <= self.max_connection_interval
144 && self.min_connection_interval >= Duration::from_micros(7_500)
145 && self.max_connection_interval <= Duration::from_secs(4)
146 && self.max_latency < 500
147 && self.min_event_length <= self.max_event_length
148 && self.supervision_timeout >= Duration::from_millis(100)
149 && self.supervision_timeout <= Duration::from_millis(32_000)
150 && self.supervision_timeout.as_micros()
151 > 2 * u64::from(self.max_latency + 1) * self.max_connection_interval.as_micros()
152 }
153}
154
155#[derive(Default, Debug, Clone, Copy)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158pub struct ConnParams {
159 pub conn_interval: Duration,
161 pub peripheral_latency: u16,
163 pub supervision_timeout: Duration,
165}
166
167#[derive(Debug, Clone, PartialEq)]
169#[cfg_attr(feature = "defmt", derive(defmt::Format))]
170pub struct ConnectRateParams {
171 pub min_connection_interval: Duration,
173 pub max_connection_interval: Duration,
175 pub subrate_min: u16,
177 pub subrate_max: u16,
179 pub max_latency: u16,
181 pub continuation_number: u16,
183 pub supervision_timeout: Duration,
185 pub min_ce_length: Duration,
187 pub max_ce_length: Duration,
189}
190
191#[derive(Debug)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194pub enum ConnectionEvent {
195 Disconnected {
197 reason: Status,
199 },
200 PhyUpdated {
202 tx_phy: PhyKind,
204 rx_phy: PhyKind,
206 },
207 ConnectionParamsUpdated {
209 conn_interval: Duration,
211 peripheral_latency: u16,
213 supervision_timeout: Duration,
215 },
216 DataLengthUpdated {
218 max_tx_octets: u16,
220 max_tx_time: u16,
222 max_rx_octets: u16,
224 max_rx_time: u16,
226 },
227 FrameSpaceUpdated {
229 frame_space: Duration,
231 initiator: FrameSpaceInitiator,
233 phys: PhyMask,
235 spacing_types: SpacingTypes,
237 },
238 ConnectionRateChanged {
240 conn_interval: Duration,
242 subrate_factor: u16,
244 peripheral_latency: u16,
246 continuation_number: u16,
248 supervision_timeout: Duration,
250 },
251 RequestConnectionParams(ConnectionParamsRequest),
256 #[cfg(feature = "security")]
257 PassKeyDisplay(PassKey),
259 #[cfg(feature = "security")]
260 PassKeyConfirm(PassKey),
262 #[cfg(feature = "security")]
263 PassKeyInput,
265 #[cfg(feature = "security")]
266 PairingComplete {
268 security_level: SecurityLevel,
270 bond: Option<BondInformation>,
272 },
273 #[cfg(feature = "security")]
274 PairingFailed(Error),
276 #[cfg(feature = "security")]
277 BondLost,
279 #[cfg(feature = "security")]
280 Encrypted {
284 security_level: SecurityLevel,
286 bond: Option<BondInformation>,
288 },
289 #[cfg(feature = "security")]
290 OobRequest,
292}
293
294#[derive(Debug)]
296#[cfg_attr(feature = "defmt", derive(defmt::Format))]
297pub struct ConnectionParamsRequest {
298 params: RequestedConnParams,
299 handle: ConnHandle,
300 responded: bool,
301 #[cfg(feature = "connection-params-update")]
302 l2cap: bool,
303}
304
305impl ConnectionParamsRequest {
306 pub(crate) fn new(
307 params: RequestedConnParams,
308 handle: ConnHandle,
309 #[cfg(feature = "connection-params-update")] l2cap: bool,
310 ) -> Self {
311 Self {
312 params,
313 handle,
314 responded: false,
315 #[cfg(feature = "connection-params-update")]
316 l2cap,
317 }
318 }
319
320 pub fn params(&self) -> &RequestedConnParams {
322 &self.params
323 }
324}
325
326#[cfg(not(feature = "connection-params-update"))]
327impl ConnectionParamsRequest {
328 pub async fn accept<C, P: PacketPool>(
332 mut self,
333 params: Option<&RequestedConnParams>,
334 stack: &Stack<'_, C, P>,
335 ) -> Result<(), BleHostError<C::Error>>
336 where
337 C: crate::Controller,
338 {
339 self.responded = true;
340
341 let params = params.unwrap_or(&self.params);
342 if !params.is_valid() {
343 return self.reject(stack).await;
344 }
345
346 match stack.host.async_command(into_le_conn_update(self.handle, params)).await {
347 Ok(()) => {
348 let param = ConnParamUpdateRes { result: 0 };
349 stack.host.send_conn_param_update_res(self.handle, ¶m).await
350 }
351 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
352 Err(crate::Error::Disconnected.into())
353 }
354 Err(e) => {
355 info!("Connection parameters request procedure failed");
356 if let Err(e) = self.reject(stack).await {
357 warn!("Failed to reject ConnParamRequest after failure");
358 }
359 Err(e)
360 }
361 }
362 }
363
364 pub async fn reject<C, P: PacketPool>(mut self, stack: &Stack<'_, C, P>) -> Result<(), BleHostError<C::Error>>
366 where
367 C: crate::Controller,
368 {
369 self.responded = true;
370 let param = ConnParamUpdateRes { result: 1 };
371 stack.host.send_conn_param_update_res(self.handle, ¶m).await
372 }
373}
374
375#[cfg(feature = "connection-params-update")]
376impl ConnectionParamsRequest {
377 pub async fn accept<C, P: PacketPool>(
381 mut self,
382 params: Option<&RequestedConnParams>,
383 stack: &Stack<'_, C, P>,
384 ) -> Result<(), BleHostError<C::Error>>
385 where
386 C: crate::Controller
387 + ControllerCmdAsync<LeRemoteConnectionParameterRequestReply>
388 + ControllerCmdAsync<LeRemoteConnectionParameterRequestNegativeReply>,
389 {
390 self.responded = true;
391
392 let params = params.unwrap_or(&self.params);
393 if !params.is_valid() {
394 return self.reject(stack).await;
395 }
396
397 match stack.host.async_command(into_le_conn_update(self.handle, params)).await {
398 Ok(()) => {
399 if self.l2cap {
400 let param = ConnParamUpdateRes { result: 0 };
402 stack.host.send_conn_param_update_res(self.handle, ¶m).await
403 } else {
404 let interval_min: bt_hci::param::Duration<1_250> = bt_hci_duration(params.min_connection_interval);
405 let interval_max: bt_hci::param::Duration<1_250> = bt_hci_duration(params.max_connection_interval);
406 let timeout: bt_hci::param::Duration<10_000> = bt_hci_duration(params.supervision_timeout);
407 stack
408 .host
409 .async_command(LeRemoteConnectionParameterRequestReply::new(
410 self.handle,
411 interval_min,
412 interval_max,
413 params.max_latency,
414 timeout,
415 bt_hci_duration(params.min_event_length),
416 bt_hci_duration(params.max_event_length),
417 ))
418 .await
419 }
420 }
421 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
422 Err(crate::Error::Disconnected.into())
423 }
424 Err(e) => {
425 info!("Connection parameters request procedure failed");
426 if let Err(e) = self.reject(stack).await {
427 warn!("Failed to reject ConnParamRequest after failure");
428 }
429 Err(e)
430 }
431 }
432 }
433
434 pub async fn reject<C, P: PacketPool>(mut self, stack: &Stack<'_, C, P>) -> Result<(), BleHostError<C::Error>>
436 where
437 C: crate::Controller + ControllerCmdAsync<LeRemoteConnectionParameterRequestNegativeReply>,
438 {
439 self.responded = true;
440 if self.l2cap {
441 let param = ConnParamUpdateRes { result: 1 };
442 stack.host.send_conn_param_update_res(self.handle, ¶m).await
443 } else {
444 stack
445 .host
446 .async_command(LeRemoteConnectionParameterRequestNegativeReply::new(
447 self.handle,
448 RemoteConnectionParamsRejectReason::UnacceptableConnParameters,
449 ))
450 .await
451 }
452 }
453}
454
455impl Drop for ConnectionParamsRequest {
456 fn drop(&mut self) {
457 if !self.responded {
458 error!("ConnParamRequest dropped without being acccepted/rejected");
459 }
460 }
461}
462
463impl Default for RequestedConnParams {
464 fn default() -> Self {
465 Self {
466 min_connection_interval: Duration::from_millis(80),
467 max_connection_interval: Duration::from_millis(80),
468 max_latency: 0,
469 min_event_length: Duration::from_secs(0),
470 max_event_length: Duration::from_secs(0),
471 supervision_timeout: Duration::from_secs(8),
472 }
473 }
474}
475
476impl ConnParams {
477 pub(crate) const fn new() -> Self {
478 Self {
479 conn_interval: Duration::from_ticks(0),
480 peripheral_latency: 0,
481 supervision_timeout: Duration::from_ticks(0),
482 }
483 }
484}
485
486pub struct Connection<'stack, P: PacketPool> {
490 index: u8,
491 manager: &'stack ConnectionManager<'stack, P>,
492}
493
494impl<P: PacketPool> Clone for Connection<'_, P> {
495 fn clone(&self) -> Self {
496 self.manager.inc_ref(self.index);
497 Connection::new(self.index, self.manager)
498 }
499}
500
501impl<P: PacketPool> Drop for Connection<'_, P> {
502 fn drop(&mut self) {
503 self.manager.dec_ref(self.index);
504 }
505}
506
507impl<'stack, P: PacketPool> Connection<'stack, P> {
508 pub(crate) fn new(index: u8, manager: &'stack ConnectionManager<'stack, P>) -> Self {
509 Self { index, manager }
510 }
511
512 pub(crate) fn set_att_mtu(&self, mtu: u16) {
513 self.manager.set_att_mtu(self.index, mtu);
514 }
515
516 pub(crate) fn get_att_mtu(&self) -> u16 {
517 self.manager.get_att_mtu(self.index)
518 }
519
520 pub(crate) fn set_l2cap_listening(&self, listening: bool) {
521 self.manager.set_l2cap_listening(self.index, listening);
522 }
523
524 pub(crate) async fn send(&self, pdu: Pdu<P::Packet>) {
525 self.manager.send(self.index, pdu).await
526 }
527
528 pub(crate) fn try_send(&self, pdu: Pdu<P::Packet>) -> Result<(), Error> {
529 self.manager.try_send(self.index, pdu)
530 }
531
532 pub(crate) async fn post_event(&self, event: ConnectionEvent) {
533 self.manager.post_event(self.index, event).await
534 }
535
536 pub async fn next(&self) -> ConnectionEvent {
538 self.manager.next(self.index).await
539 }
540
541 #[cfg(feature = "gatt")]
542 pub(crate) async fn next_gatt(&self) -> Pdu<P::Packet> {
543 self.manager.next_gatt(self.index).await
544 }
545
546 #[cfg(feature = "gatt")]
547 pub(crate) async fn next_gatt_client(&self) -> Option<Pdu<P::Packet>> {
548 self.manager.next_gatt_client(self.index).await
549 }
550
551 #[cfg(feature = "gatt")]
552 pub(crate) async fn acquire_indication_slot(&self) -> Result<(), Error> {
553 self.manager.acquire_indication_slot(self.index).await
554 }
555
556 #[cfg(feature = "gatt")]
557 pub(crate) fn release_indication_slot(&self) {
558 self.manager.release_indication_slot(self.index)
559 }
560
561 #[cfg(feature = "gatt")]
562 pub(crate) async fn wait_indication_confirmation(&self) -> Result<(), Error> {
563 self.manager.wait_indication_confirmation(self.index).await
564 }
565
566 pub fn is_connected(&self) -> bool {
568 self.manager.is_connected(self.index)
569 }
570
571 pub fn handle(&self) -> ConnHandle {
573 self.manager.handle(self.index)
574 }
575
576 pub fn att_mtu(&self) -> u16 {
578 self.get_att_mtu()
579 }
580
581 pub fn role(&self) -> LeConnRole {
583 self.manager.role(self.index)
584 }
585
586 pub fn peer_address(&self) -> Address {
588 self.manager.peer_address(self.index)
589 }
590
591 pub fn peer_identity(&self) -> Identity {
593 self.manager.peer_identity(self.index)
594 }
595
596 pub fn params(&self) -> ConnParams {
598 self.manager.params(self.index)
599 }
600
601 pub fn request_security(&self) -> Result<(), Error> {
609 self.manager.request_security(self.index, true)
610 }
611
612 #[cfg(feature = "security")]
614 pub fn is_bonded_peer(&self) -> bool {
615 self.manager.is_bonded_peer(self.index)
616 }
617
618 #[cfg(feature = "security")]
620 pub(crate) async fn try_enable_encryption(&self) -> Result<(), Error> {
621 self.manager.try_enable_encryption(self.index).await
622 }
623
624 pub fn security_level(&self) -> Result<SecurityLevel, Error> {
626 self.manager.get_security_level(self.index)
627 }
628
629 #[cfg(feature = "legacy-pairing")]
631 pub fn encryption_key_len(&self) -> Result<u8, Error> {
632 self.manager.get_encryption_key_len(self.index)
633 }
634
635 pub fn bondable(&self) -> Result<bool, Error> {
639 self.manager.get_bondable(self.index)
640 }
641
642 pub fn set_bondable(&self, bondable: bool) -> Result<(), Error> {
657 self.manager.set_bondable(self.index, bondable)
658 }
659
660 pub fn pass_key_confirm(&self) -> Result<(), Error> {
662 self.manager.pass_key_confirm(self.index, true)
663 }
664
665 pub fn pass_key_cancel(&self) -> Result<(), Error> {
667 self.manager.pass_key_confirm(self.index, false)
668 }
669
670 pub fn pass_key_input(&self, pass_key: u32) -> Result<(), Error> {
672 self.manager.pass_key_input(self.index, pass_key)
673 }
674
675 #[cfg(feature = "security")]
682 pub fn set_oob_available(&self, available: bool) -> Result<(), Error> {
683 self.manager.set_oob_available(self.index, available)
684 }
685
686 #[cfg(feature = "security")]
691 pub fn provide_oob_data(
692 &self,
693 local_oob: crate::security_manager::OobData,
694 peer_oob: crate::security_manager::OobData,
695 ) -> Result<(), Error> {
696 self.manager.provide_oob_data(self.index, local_oob, peer_oob)
697 }
698
699 pub fn disconnect(&self) {
701 self.manager
702 .request_disconnect(self.index, DisconnectReason::RemoteUserTerminatedConn);
703 }
704
705 #[cfg(feature = "connection-metrics")]
707 pub fn metrics<F: FnOnce(&ConnectionMetrics) -> R, R>(&self, f: F) -> R {
708 self.manager.metrics(self.index, f)
709 }
710
711 #[cfg(feature = "att-queued-writes")]
712 pub(crate) fn prepare_write(&self, handle: u16, offset: u16, value: &[u8]) -> Result<(), crate::att::AttErrorCode> {
713 self.manager.prepare_write(self.index, handle, offset, value)
714 }
715
716 #[cfg(feature = "att-queued-writes")]
717 pub(crate) fn with_prepare_write<F, R>(&self, f: F) -> R
718 where
719 F: FnOnce(&crate::connection_manager::PrepareWriteState) -> R,
720 {
721 self.manager.with_prepare_write(self.index, f)
722 }
723
724 #[cfg(feature = "att-queued-writes")]
725 pub(crate) fn clear_prepare_write(&self) {
726 self.manager.clear_prepare_write(self.index)
727 }
728
729 pub async fn rssi<T>(&self, stack: &Stack<'_, T, P>) -> Result<i8, BleHostError<T::Error>>
731 where
732 T: ControllerCmdSync<ReadRssi>,
733 {
734 let handle = self.handle();
735 let ret = stack.host.command(ReadRssi::new(handle)).await?;
736 Ok(ret.rssi)
737 }
738
739 pub async fn set_phy<T>(&self, stack: &Stack<'_, T, P>, phy: PhyKind) -> Result<(), BleHostError<T::Error>>
744 where
745 T: ControllerCmdAsync<LeSetPhy>,
746 {
747 let all_phys = AllPhys::new()
748 .set_has_no_rx_phy_preference(false)
749 .set_has_no_tx_phy_preference(false);
750 let mut mask = PhyMask::new()
751 .set_le_coded_phy(false)
752 .set_le_1m_phy(false)
753 .set_le_2m_phy(false);
754 let mut options = PhyOptions::default();
755 match phy {
756 PhyKind::Le2M => {
757 mask = mask.set_le_2m_phy(true);
758 }
759 PhyKind::Le1M => {
760 mask = mask.set_le_1m_phy(true);
761 }
762 PhyKind::LeCoded => {
763 mask = mask.set_le_coded_phy(true);
764 options = PhyOptions::S8CodingPreferred;
765 }
766 PhyKind::LeCodedS2 => {
767 mask = mask.set_le_coded_phy(true);
768 options = PhyOptions::S2CodingPreferred;
769 }
770 }
771 stack
772 .host
773 .async_command(LeSetPhy::new(self.handle(), all_phys, mask, mask, options))
774 .await?;
775 Ok(())
776 }
777
778 pub async fn read_phy<T>(&self, stack: &Stack<'_, T, P>) -> Result<(PhyKind, PhyKind), BleHostError<T::Error>>
780 where
781 T: ControllerCmdSync<LeReadPhy>,
782 {
783 let res = stack.host.command(LeReadPhy::new(self.handle())).await?;
784 Ok((res.tx_phy, res.rx_phy))
785 }
786
787 pub async fn update_data_length<T>(
789 &self,
790 stack: &Stack<'_, T, P>,
791 length: u16,
792 time_us: u16,
793 ) -> Result<(), BleHostError<T::Error>>
794 where
795 T: ControllerCmdSync<LeSetDataLength> + ControllerCmdSync<LeReadLocalSupportedFeatures>,
796 {
797 let handle = self.handle();
798 let features = stack.host.command(LeReadLocalSupportedFeatures::new()).await?;
800 if length <= 27 || features.supports_le_data_packet_length_extension() {
801 match stack.host.command(LeSetDataLength::new(handle, length, time_us)).await {
802 Ok(_) => Ok(()),
803 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
804 Err(crate::Error::Disconnected.into())
805 }
806 Err(e) => Err(e),
807 }
808 } else {
809 Err(BleHostError::BleHost(Error::InvalidValue))
810 }
811 }
812
813 pub async fn update_connection_params<T>(
815 &self,
816 stack: &Stack<'_, T, P>,
817 params: &RequestedConnParams,
818 ) -> Result<(), BleHostError<T::Error>>
819 where
820 T: ControllerCmdAsync<LeConnUpdate> + ControllerCmdSync<LeReadLocalSupportedFeatures>,
821 {
822 let handle = self.handle();
823 let features = stack.host.command(LeReadLocalSupportedFeatures::new()).await?;
825 if features.supports_conn_parameters_request_procedure() || self.role() == LeConnRole::Central {
826 match stack.host.async_command(into_le_conn_update(handle, params)).await {
827 Ok(_) => return Ok(()),
828 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
829 return Err(crate::Error::Disconnected.into());
830 }
831 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNSUPPORTED_REMOTE_FEATURE))) => {
832 }
837 Err(e) => return Err(e),
838 }
839 }
840
841 if self.role() == LeConnRole::Peripheral || cfg!(feature = "connection-params-update") {
842 use crate::types::l2cap::ConnParamUpdateReq;
843 info!(
845 "Connection parameters request procedure not supported, use l2cap connection parameter update req instead"
846 );
847 let interval_min: bt_hci::param::Duration<1_250> = bt_hci_duration(params.min_connection_interval);
848 let interval_max: bt_hci::param::Duration<1_250> = bt_hci_duration(params.max_connection_interval);
849 let timeout: bt_hci::param::Duration<10_000> = bt_hci_duration(params.supervision_timeout);
850 let param = ConnParamUpdateReq {
851 interval_min: interval_min.as_u16(),
852 interval_max: interval_max.as_u16(),
853 latency: params.max_latency,
854 timeout: timeout.as_u16(),
855 };
856 stack.host.send_conn_param_update_req(handle, ¶m).await?;
857 }
858 Ok(())
859 }
860
861 pub async fn update_frame_space<T>(
863 &self,
864 stack: &Stack<'_, T, P>,
865 frame_space_min: Duration,
866 frame_space_max: Duration,
867 phys: PhyMask,
868 spacing_types: SpacingTypes,
869 ) -> Result<(), BleHostError<T::Error>>
870 where
871 T: ControllerCmdSync<LeFrameSpaceUpdate>,
872 {
873 let handle = self.handle();
874 let frame_space_min_dur = bt_hci_duration(frame_space_min);
875 let frame_space_max_dur = bt_hci_duration(frame_space_max);
876 match stack
877 .host
878 .command(LeFrameSpaceUpdate::new(
879 handle,
880 frame_space_min_dur,
881 frame_space_max_dur,
882 phys,
883 spacing_types,
884 ))
885 .await
886 {
887 Ok(_) => Ok(()),
888 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
889 Err(crate::Error::Disconnected.into())
890 }
891 Err(e) => Err(e),
892 }
893 }
894
895 pub async fn request_connection_rate<T>(
897 &self,
898 stack: &Stack<'_, T, P>,
899 conn_rate_params: &ConnectRateParams,
900 ) -> Result<(), BleHostError<T::Error>>
901 where
902 T: ControllerCmdSync<LeConnectionRateRequest>,
903 {
904 let handle = self.handle();
905 let min_interval = bt_hci_duration(conn_rate_params.min_connection_interval);
906 let max_interval = bt_hci_duration(conn_rate_params.max_connection_interval);
907 let timeout = bt_hci_duration(conn_rate_params.supervision_timeout);
908 let min_ce = bt_hci_duration(conn_rate_params.min_ce_length);
909 let max_ce = bt_hci_duration(conn_rate_params.max_ce_length);
910 match stack
911 .host
912 .command(LeConnectionRateRequest::new(
913 handle,
914 min_interval,
915 max_interval,
916 conn_rate_params.subrate_min,
917 conn_rate_params.subrate_max,
918 conn_rate_params.max_latency,
919 conn_rate_params.continuation_number,
920 timeout,
921 min_ce,
922 max_ce,
923 ))
924 .await
925 {
926 Ok(_) => Ok(()),
927 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
928 Err(crate::Error::Disconnected.into())
929 }
930 Err(e) => Err(e),
931 }
932 }
933
934 #[cfg(feature = "gatt")]
936 pub fn with_attribute_server<'values, 'server, M: RawMutex, const ATT_MAX: usize, const CONN_MAX: usize>(
937 self,
938 server: &'server AttributeServer<'values, M, P, ATT_MAX, CONN_MAX>,
939 ) -> Result<GattConnection<'stack, 'server, P>, Error> {
940 GattConnection::try_new(self, server)
941 }
942}
943
944fn into_le_conn_update(handle: ConnHandle, params: &RequestedConnParams) -> LeConnUpdate {
945 LeConnUpdate::new(
946 handle,
947 bt_hci_duration(params.min_connection_interval),
948 bt_hci_duration(params.max_connection_interval),
949 params.max_latency,
950 bt_hci_duration(params.supervision_timeout),
951 bt_hci_duration(params.min_event_length),
952 bt_hci_duration(params.max_event_length),
953 )
954}