1use bt_hci::cmd::le::{LeConnUpdate, LeReadLocalSupportedFeatures, LeReadPhy, LeSetDataLength, LeSetPhy};
4use bt_hci::cmd::status::ReadRssi;
5use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
6use bt_hci::param::{
7 AddrKind, AllPhys, BdAddr, ConnHandle, DisconnectReason, LeConnRole, PhyKind, PhyMask, PhyOptions, Status,
8};
9#[cfg(feature = "connection-params-update")]
10use bt_hci::{
11 cmd::le::{LeRemoteConnectionParameterRequestNegativeReply, LeRemoteConnectionParameterRequestReply},
12 param::RemoteConnectionParamsRejectReason,
13};
14#[cfg(feature = "gatt")]
15use embassy_sync::blocking_mutex::raw::RawMutex;
16use embassy_time::Duration;
17
18use crate::connection_manager::ConnectionManager;
19#[cfg(feature = "connection-metrics")]
20pub use crate::connection_manager::Metrics as ConnectionMetrics;
21use crate::pdu::Pdu;
22#[cfg(feature = "gatt")]
23use crate::prelude::{AttributeServer, GattConnection};
24#[cfg(feature = "security")]
25use crate::security_manager::{BondInformation, PassKey};
26use crate::types::l2cap::ConnParamUpdateRes;
27use crate::{bt_hci_duration, BleHostError, Error, Identity, PacketPool, Stack};
28
29#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum SecurityLevel {
36 NoEncryption,
38 Encrypted,
40 EncryptedAuthenticated,
42}
43
44impl SecurityLevel {
45 pub fn encrypted(&self) -> bool {
47 !matches!(self, SecurityLevel::NoEncryption)
48 }
49
50 pub fn authenticated(&self) -> bool {
52 matches!(self, SecurityLevel::EncryptedAuthenticated)
53 }
54}
55
56pub struct ConnectConfig<'d> {
58 pub scan_config: ScanConfig<'d>,
60 pub connect_params: RequestedConnParams,
62}
63
64pub struct ScanConfig<'d> {
66 pub active: bool,
68 pub filter_accept_list: &'d [(AddrKind, &'d BdAddr)],
70 pub phys: PhySet,
72 pub interval: Duration,
74 pub window: Duration,
76 pub timeout: Duration,
78}
79
80impl Default for ScanConfig<'_> {
81 fn default() -> Self {
82 Self {
83 active: true,
84 filter_accept_list: &[],
85 phys: PhySet::M1,
86 interval: Duration::from_secs(1),
87 window: Duration::from_secs(1),
88 timeout: Duration::from_secs(0),
89 }
90 }
91}
92
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95#[derive(Eq, PartialEq, Copy, Clone)]
96#[repr(u8)]
97pub enum PhySet {
98 M1 = 1,
100 M2 = 2,
102 M1M2 = 3,
104 Coded = 4,
106 M1Coded = 5,
108 M2Coded = 6,
110 M1M2Coded = 7,
112}
113
114#[derive(Debug, Clone, PartialEq)]
116#[cfg_attr(feature = "defmt", derive(defmt::Format))]
117pub struct RequestedConnParams {
118 pub min_connection_interval: Duration,
120 pub max_connection_interval: Duration,
122 pub max_latency: u16,
124 pub min_event_length: Duration,
126 pub max_event_length: Duration,
128 pub supervision_timeout: Duration,
130}
131
132impl RequestedConnParams {
133 pub fn is_valid(&self) -> bool {
135 self.min_connection_interval <= self.max_connection_interval
136 && self.min_connection_interval >= Duration::from_micros(7_500)
137 && self.max_connection_interval <= Duration::from_secs(4)
138 && self.max_latency < 500
139 && self.min_event_length <= self.max_event_length
140 && self.supervision_timeout >= Duration::from_millis(100)
141 && self.supervision_timeout <= Duration::from_millis(32_000)
142 && self.supervision_timeout.as_micros()
143 > 2 * u64::from(self.max_latency + 1) * self.max_connection_interval.as_micros()
144 }
145}
146
147#[derive(Default, Debug, Clone, Copy)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub struct ConnParams {
151 pub conn_interval: Duration,
153 pub peripheral_latency: u16,
155 pub supervision_timeout: Duration,
157}
158
159#[derive(Debug)]
161#[cfg_attr(feature = "defmt", derive(defmt::Format))]
162pub enum ConnectionEvent {
163 Disconnected {
165 reason: Status,
167 },
168 PhyUpdated {
170 tx_phy: PhyKind,
172 rx_phy: PhyKind,
174 },
175 ConnectionParamsUpdated {
177 conn_interval: Duration,
179 peripheral_latency: u16,
181 supervision_timeout: Duration,
183 },
184 DataLengthUpdated {
186 max_tx_octets: u16,
188 max_tx_time: u16,
190 max_rx_octets: u16,
192 max_rx_time: u16,
194 },
195 RequestConnectionParams(ConnectionParamsRequest),
200 #[cfg(feature = "security")]
201 PassKeyDisplay(PassKey),
203 #[cfg(feature = "security")]
204 PassKeyConfirm(PassKey),
206 #[cfg(feature = "security")]
207 PassKeyInput,
209 #[cfg(feature = "security")]
210 PairingComplete {
212 security_level: SecurityLevel,
214 bond: Option<BondInformation>,
216 },
217 #[cfg(feature = "security")]
218 PairingFailed(Error),
220}
221
222#[derive(Debug)]
224#[cfg_attr(feature = "defmt", derive(defmt::Format))]
225pub struct ConnectionParamsRequest {
226 params: RequestedConnParams,
227 handle: ConnHandle,
228 responded: bool,
229 #[cfg(feature = "connection-params-update")]
230 l2cap: bool,
231}
232
233impl ConnectionParamsRequest {
234 pub(crate) fn new(
235 params: RequestedConnParams,
236 handle: ConnHandle,
237 #[cfg(feature = "connection-params-update")] l2cap: bool,
238 ) -> Self {
239 Self {
240 params,
241 handle,
242 responded: false,
243 #[cfg(feature = "connection-params-update")]
244 l2cap,
245 }
246 }
247
248 pub fn params(&self) -> &RequestedConnParams {
250 &self.params
251 }
252}
253
254#[cfg(not(feature = "connection-params-update"))]
255impl ConnectionParamsRequest {
256 pub async fn accept<C, P: PacketPool>(
260 mut self,
261 params: Option<&RequestedConnParams>,
262 stack: &Stack<'_, C, P>,
263 ) -> Result<(), BleHostError<C::Error>>
264 where
265 C: crate::Controller,
266 {
267 self.responded = true;
268
269 let params = params.unwrap_or(&self.params);
270 if !params.is_valid() {
271 return self.reject(stack).await;
272 }
273
274 match stack.host.async_command(into_le_conn_update(self.handle, params)).await {
275 Ok(()) => {
276 let param = ConnParamUpdateRes { result: 0 };
277 stack.host.send_conn_param_update_res(self.handle, ¶m).await
278 }
279 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
280 Err(crate::Error::Disconnected.into())
281 }
282 Err(e) => {
283 info!("Connection parameters request procedure failed");
284 if let Err(e) = self.reject(stack).await {
285 warn!("Failed to reject ConnParamRequest after failure");
286 }
287 Err(e)
288 }
289 }
290 }
291
292 pub async fn reject<C, P: PacketPool>(mut self, stack: &Stack<'_, C, P>) -> Result<(), BleHostError<C::Error>>
294 where
295 C: crate::Controller,
296 {
297 self.responded = true;
298 let param = ConnParamUpdateRes { result: 1 };
299 stack.host.send_conn_param_update_res(self.handle, ¶m).await
300 }
301}
302
303#[cfg(feature = "connection-params-update")]
304impl ConnectionParamsRequest {
305 pub async fn accept<C, P: PacketPool>(
309 mut self,
310 params: Option<&RequestedConnParams>,
311 stack: &Stack<'_, C, P>,
312 ) -> Result<(), BleHostError<C::Error>>
313 where
314 C: crate::Controller
315 + ControllerCmdAsync<LeRemoteConnectionParameterRequestReply>
316 + ControllerCmdAsync<LeRemoteConnectionParameterRequestNegativeReply>,
317 {
318 self.responded = true;
319
320 let params = params.unwrap_or(&self.params);
321 if !params.is_valid() {
322 return self.reject(stack).await;
323 }
324
325 match stack.host.async_command(into_le_conn_update(self.handle, params)).await {
326 Ok(()) => {
327 if self.l2cap {
328 let param = ConnParamUpdateRes { result: 0 };
330 stack.host.send_conn_param_update_res(self.handle, ¶m).await
331 } else {
332 let interval_min: bt_hci::param::Duration<1_250> = bt_hci_duration(params.min_connection_interval);
333 let interval_max: bt_hci::param::Duration<1_250> = bt_hci_duration(params.max_connection_interval);
334 let timeout: bt_hci::param::Duration<10_000> = bt_hci_duration(params.supervision_timeout);
335 stack
336 .host
337 .async_command(LeRemoteConnectionParameterRequestReply::new(
338 self.handle,
339 interval_min,
340 interval_max,
341 params.max_latency,
342 timeout,
343 bt_hci_duration(params.min_event_length),
344 bt_hci_duration(params.max_event_length),
345 ))
346 .await
347 }
348 }
349 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
350 Err(crate::Error::Disconnected.into())
351 }
352 Err(e) => {
353 info!("Connection parameters request procedure failed");
354 if let Err(e) = self.reject(stack).await {
355 warn!("Failed to reject ConnParamRequest after failure");
356 }
357 Err(e)
358 }
359 }
360 }
361
362 pub async fn reject<C, P: PacketPool>(mut self, stack: &Stack<'_, C, P>) -> Result<(), BleHostError<C::Error>>
364 where
365 C: crate::Controller + ControllerCmdAsync<LeRemoteConnectionParameterRequestNegativeReply>,
366 {
367 self.responded = true;
368 if self.l2cap {
369 let param = ConnParamUpdateRes { result: 1 };
370 stack.host.send_conn_param_update_res(self.handle, ¶m).await
371 } else {
372 stack
373 .host
374 .async_command(LeRemoteConnectionParameterRequestNegativeReply::new(
375 self.handle,
376 RemoteConnectionParamsRejectReason::UnacceptableConnParameters,
377 ))
378 .await
379 }
380 }
381}
382
383impl Drop for ConnectionParamsRequest {
384 fn drop(&mut self) {
385 if !self.responded {
386 error!("ConnParamRequest dropped without being acccepted/rejected");
387 }
388 }
389}
390
391impl Default for RequestedConnParams {
392 fn default() -> Self {
393 Self {
394 min_connection_interval: Duration::from_millis(80),
395 max_connection_interval: Duration::from_millis(80),
396 max_latency: 0,
397 min_event_length: Duration::from_secs(0),
398 max_event_length: Duration::from_secs(0),
399 supervision_timeout: Duration::from_secs(8),
400 }
401 }
402}
403
404impl ConnParams {
405 pub(crate) const fn new() -> Self {
406 Self {
407 conn_interval: Duration::from_ticks(0),
408 peripheral_latency: 0,
409 supervision_timeout: Duration::from_ticks(0),
410 }
411 }
412}
413
414pub struct Connection<'stack, P: PacketPool> {
418 index: u8,
419 manager: &'stack ConnectionManager<'stack, P>,
420}
421
422impl<P: PacketPool> Clone for Connection<'_, P> {
423 fn clone(&self) -> Self {
424 self.manager.inc_ref(self.index);
425 Connection::new(self.index, self.manager)
426 }
427}
428
429impl<P: PacketPool> Drop for Connection<'_, P> {
430 fn drop(&mut self) {
431 self.manager.dec_ref(self.index);
432 }
433}
434
435impl<'stack, P: PacketPool> Connection<'stack, P> {
436 pub(crate) fn new(index: u8, manager: &'stack ConnectionManager<'stack, P>) -> Self {
437 Self { index, manager }
438 }
439
440 pub(crate) fn set_att_mtu(&self, mtu: u16) {
441 self.manager.set_att_mtu(self.index, mtu);
442 }
443
444 pub(crate) fn get_att_mtu(&self) -> u16 {
445 self.manager.get_att_mtu(self.index)
446 }
447
448 pub(crate) async fn send(&self, pdu: Pdu<P::Packet>) {
449 self.manager.send(self.index, pdu).await
450 }
451
452 pub(crate) fn try_send(&self, pdu: Pdu<P::Packet>) -> Result<(), Error> {
453 self.manager.try_send(self.index, pdu)
454 }
455
456 pub(crate) async fn post_event(&self, event: ConnectionEvent) {
457 self.manager.post_event(self.index, event).await
458 }
459
460 pub async fn next(&self) -> ConnectionEvent {
462 self.manager.next(self.index).await
463 }
464
465 #[cfg(feature = "gatt")]
466 pub(crate) async fn next_gatt(&self) -> Pdu<P::Packet> {
467 self.manager.next_gatt(self.index).await
468 }
469
470 #[cfg(feature = "gatt")]
471 pub(crate) async fn next_gatt_client(&self) -> Pdu<P::Packet> {
472 self.manager.next_gatt_client(self.index).await
473 }
474
475 pub fn is_connected(&self) -> bool {
477 self.manager.is_connected(self.index)
478 }
479
480 pub fn handle(&self) -> ConnHandle {
482 self.manager.handle(self.index)
483 }
484
485 pub fn att_mtu(&self) -> u16 {
487 self.get_att_mtu()
488 }
489
490 pub fn role(&self) -> LeConnRole {
492 self.manager.role(self.index)
493 }
494
495 pub fn peer_addr_kind(&self) -> AddrKind {
497 self.manager.peer_addr_kind(self.index)
498 }
499
500 pub fn peer_address(&self) -> BdAddr {
502 self.manager.peer_address(self.index)
503 }
504
505 pub fn peer_identity(&self) -> Identity {
507 self.manager.peer_identity(self.index)
508 }
509
510 pub fn params(&self) -> ConnParams {
512 self.manager.params(self.index)
513 }
514
515 pub fn request_security(&self) -> Result<(), Error> {
523 self.manager.request_security(self.index)
524 }
525
526 pub fn security_level(&self) -> Result<SecurityLevel, Error> {
528 self.manager.get_security_level(self.index)
529 }
530
531 pub fn bondable(&self) -> Result<bool, Error> {
535 self.manager.get_bondable(self.index)
536 }
537
538 pub fn set_bondable(&self, bondable: bool) -> Result<(), Error> {
553 self.manager.set_bondable(self.index, bondable)
554 }
555
556 pub fn pass_key_confirm(&self) -> Result<(), Error> {
558 self.manager.pass_key_confirm(self.index, true)
559 }
560
561 pub fn pass_key_cancel(&self) -> Result<(), Error> {
563 self.manager.pass_key_confirm(self.index, false)
564 }
565
566 pub fn pass_key_input(&self, pass_key: u32) -> Result<(), Error> {
568 self.manager.pass_key_input(self.index, pass_key)
569 }
570
571 pub fn disconnect(&self) {
573 self.manager
574 .request_disconnect(self.index, DisconnectReason::RemoteUserTerminatedConn);
575 }
576
577 #[cfg(feature = "connection-metrics")]
579 pub fn metrics<F: FnOnce(&ConnectionMetrics) -> R, R>(&self, f: F) -> R {
580 self.manager.metrics(self.index, f)
581 }
582
583 pub async fn rssi<T>(&self, stack: &Stack<'_, T, P>) -> Result<i8, BleHostError<T::Error>>
585 where
586 T: ControllerCmdSync<ReadRssi>,
587 {
588 let handle = self.handle();
589 let ret = stack.host.command(ReadRssi::new(handle)).await?;
590 Ok(ret.rssi)
591 }
592
593 pub async fn set_phy<T>(&self, stack: &Stack<'_, T, P>, phy: PhyKind) -> Result<(), BleHostError<T::Error>>
598 where
599 T: ControllerCmdAsync<LeSetPhy>,
600 {
601 let all_phys = AllPhys::new()
602 .set_has_no_rx_phy_preference(false)
603 .set_has_no_tx_phy_preference(false);
604 let mut mask = PhyMask::new()
605 .set_le_coded_phy(false)
606 .set_le_1m_phy(false)
607 .set_le_2m_phy(false);
608 let mut options = PhyOptions::default();
609 match phy {
610 PhyKind::Le2M => {
611 mask = mask.set_le_2m_phy(true);
612 }
613 PhyKind::Le1M => {
614 mask = mask.set_le_1m_phy(true);
615 }
616 PhyKind::LeCoded => {
617 mask = mask.set_le_coded_phy(true);
618 options = PhyOptions::S8CodingPreferred;
619 }
620 PhyKind::LeCodedS2 => {
621 mask = mask.set_le_coded_phy(true);
622 options = PhyOptions::S2CodingPreferred;
623 }
624 }
625 stack
626 .host
627 .async_command(LeSetPhy::new(self.handle(), all_phys, mask, mask, options))
628 .await?;
629 Ok(())
630 }
631
632 pub async fn read_phy<T>(&self, stack: &Stack<'_, T, P>) -> Result<(PhyKind, PhyKind), BleHostError<T::Error>>
634 where
635 T: ControllerCmdSync<LeReadPhy>,
636 {
637 let res = stack.host.command(LeReadPhy::new(self.handle())).await?;
638 Ok((res.tx_phy, res.rx_phy))
639 }
640
641 pub async fn update_data_length<T>(
643 &self,
644 stack: &Stack<'_, T, P>,
645 length: u16,
646 time_us: u16,
647 ) -> Result<(), BleHostError<T::Error>>
648 where
649 T: ControllerCmdSync<LeSetDataLength> + ControllerCmdSync<LeReadLocalSupportedFeatures>,
650 {
651 let handle = self.handle();
652 let features = stack.host.command(LeReadLocalSupportedFeatures::new()).await?;
654 if length <= 27 || features.supports_le_data_packet_length_extension() {
655 match stack.host.command(LeSetDataLength::new(handle, length, time_us)).await {
656 Ok(_) => Ok(()),
657 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
658 Err(crate::Error::Disconnected.into())
659 }
660 Err(e) => Err(e),
661 }
662 } else {
663 Err(BleHostError::BleHost(Error::InvalidValue))
664 }
665 }
666
667 pub async fn update_connection_params<T>(
669 &self,
670 stack: &Stack<'_, T, P>,
671 params: &RequestedConnParams,
672 ) -> Result<(), BleHostError<T::Error>>
673 where
674 T: ControllerCmdAsync<LeConnUpdate> + ControllerCmdSync<LeReadLocalSupportedFeatures>,
675 {
676 let handle = self.handle();
677 let features = stack.host.command(LeReadLocalSupportedFeatures::new()).await?;
679 if features.supports_conn_parameters_request_procedure() || self.role() == LeConnRole::Central {
680 match stack.host.async_command(into_le_conn_update(handle, params)).await {
681 Ok(_) => return Ok(()),
682 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
683 return Err(crate::Error::Disconnected.into());
684 }
685 Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNSUPPORTED_REMOTE_FEATURE))) => {
686 }
691 Err(e) => return Err(e),
692 }
693 }
694
695 if self.role() == LeConnRole::Peripheral || cfg!(feature = "connection-params-update") {
696 use crate::types::l2cap::ConnParamUpdateReq;
697 info!(
699 "Connection parameters request procedure not supported, use l2cap connection parameter update req instead"
700 );
701 let interval_min: bt_hci::param::Duration<1_250> = bt_hci_duration(params.min_connection_interval);
702 let interval_max: bt_hci::param::Duration<1_250> = bt_hci_duration(params.max_connection_interval);
703 let timeout: bt_hci::param::Duration<10_000> = bt_hci_duration(params.supervision_timeout);
704 let param = ConnParamUpdateReq {
705 interval_min: interval_min.as_u16(),
706 interval_max: interval_max.as_u16(),
707 latency: params.max_latency,
708 timeout: timeout.as_u16(),
709 };
710 stack.host.send_conn_param_update_req(handle, ¶m).await?;
711 }
712 Ok(())
713 }
714
715 #[cfg(feature = "gatt")]
717 pub fn with_attribute_server<
718 'values,
719 'server,
720 M: RawMutex,
721 const ATT_MAX: usize,
722 const CCCD_MAX: usize,
723 const CONN_MAX: usize,
724 >(
725 self,
726 server: &'server AttributeServer<'values, M, P, ATT_MAX, CCCD_MAX, CONN_MAX>,
727 ) -> Result<GattConnection<'stack, 'server, P>, Error> {
728 GattConnection::try_new(self, server)
729 }
730}
731
732fn into_le_conn_update(handle: ConnHandle, params: &RequestedConnParams) -> LeConnUpdate {
733 LeConnUpdate::new(
734 handle,
735 bt_hci_duration(params.min_connection_interval),
736 bt_hci_duration(params.max_connection_interval),
737 params.max_latency,
738 bt_hci_duration(params.supervision_timeout),
739 bt_hci_duration(params.min_event_length),
740 bt_hci_duration(params.max_event_length),
741 )
742}