1use bt_hci::cmd::le::{LeConnUpdate, LeReadPhy, 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 = "gatt")]
10use embassy_sync::blocking_mutex::raw::RawMutex;
11use embassy_time::Duration;
12
13use crate::connection_manager::ConnectionManager;
14#[cfg(feature = "connection-metrics")]
15pub use crate::connection_manager::Metrics as ConnectionMetrics;
16use crate::pdu::Pdu;
17#[cfg(feature = "gatt")]
18use crate::prelude::{AttributeServer, GattConnection};
19#[cfg(feature = "security")]
20use crate::security_manager::BondInformation;
21use crate::{BleHostError, Error, Identity, PacketPool, Stack};
22
23pub struct ConnectConfig<'d> {
25    pub scan_config: ScanConfig<'d>,
27    pub connect_params: ConnectParams,
29}
30
31pub struct ScanConfig<'d> {
33    pub active: bool,
35    pub filter_accept_list: &'d [(AddrKind, &'d BdAddr)],
37    pub phys: PhySet,
39    pub interval: Duration,
41    pub window: Duration,
43    pub timeout: Duration,
45}
46
47impl Default for ScanConfig<'_> {
48    fn default() -> Self {
49        Self {
50            active: true,
51            filter_accept_list: &[],
52            phys: PhySet::M1,
53            interval: Duration::from_secs(1),
54            window: Duration::from_secs(1),
55            timeout: Duration::from_secs(0),
56        }
57    }
58}
59
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62#[derive(Eq, PartialEq, Copy, Clone)]
63#[repr(u8)]
64pub enum PhySet {
65    M1 = 1,
67    M2 = 2,
69    M1M2 = 3,
71    Coded = 4,
73    M1Coded = 5,
75    M2Coded = 6,
77    M1M2Coded = 7,
79}
80
81pub struct ConnectParams {
83    pub min_connection_interval: Duration,
85    pub max_connection_interval: Duration,
87    pub max_latency: u16,
89    pub event_length: Duration,
91    pub supervision_timeout: Duration,
93}
94
95#[derive(Debug)]
97pub enum ConnectionEvent {
98    Disconnected {
100        reason: Status,
102    },
103    PhyUpdated {
105        tx_phy: PhyKind,
107        rx_phy: PhyKind,
109    },
110    ConnectionParamsUpdated {
112        conn_interval: Duration,
114        peripheral_latency: u16,
116        supervision_timeout: Duration,
118    },
119    #[cfg(feature = "security")]
120    Bonded {
122        bond_info: BondInformation,
124    },
125}
126
127impl Default for ConnectParams {
128    fn default() -> Self {
129        Self {
130            min_connection_interval: Duration::from_millis(80),
131            max_connection_interval: Duration::from_millis(80),
132            max_latency: 0,
133            event_length: Duration::from_secs(0),
134            supervision_timeout: Duration::from_secs(8),
135        }
136    }
137}
138
139pub struct Connection<'stack, P: PacketPool> {
143    index: u8,
144    manager: &'stack ConnectionManager<'stack, P>,
145}
146
147impl<P: PacketPool> Clone for Connection<'_, P> {
148    fn clone(&self) -> Self {
149        self.manager.inc_ref(self.index);
150        Connection::new(self.index, self.manager)
151    }
152}
153
154impl<P: PacketPool> Drop for Connection<'_, P> {
155    fn drop(&mut self) {
156        self.manager.dec_ref(self.index);
157    }
158}
159
160impl<'stack, P: PacketPool> Connection<'stack, P> {
161    pub(crate) fn new(index: u8, manager: &'stack ConnectionManager<'stack, P>) -> Self {
162        Self { index, manager }
163    }
164
165    pub(crate) fn set_att_mtu(&self, mtu: u16) {
166        self.manager.set_att_mtu(self.index, mtu);
167    }
168
169    pub(crate) fn get_att_mtu(&self) -> u16 {
170        self.manager.get_att_mtu(self.index)
171    }
172
173    pub(crate) async fn send(&self, pdu: Pdu<P::Packet>) {
174        self.manager.send(self.index, pdu).await
175    }
176
177    pub(crate) fn try_send(&self, pdu: Pdu<P::Packet>) -> Result<(), Error> {
178        self.manager.try_send(self.index, pdu)
179    }
180
181    pub(crate) async fn post_event(&self, event: ConnectionEvent) {
182        self.manager.post_event(self.index, event).await
183    }
184
185    pub async fn next(&self) -> ConnectionEvent {
187        self.manager.next(self.index).await
188    }
189
190    #[cfg(feature = "gatt")]
191    pub(crate) async fn next_gatt(&self) -> Pdu<P::Packet> {
192        self.manager.next_gatt(self.index).await
193    }
194
195    pub fn is_connected(&self) -> bool {
197        self.manager.is_connected(self.index)
198    }
199
200    pub fn handle(&self) -> ConnHandle {
202        self.manager.handle(self.index)
203    }
204
205    pub fn att_mtu(&self) -> u16 {
207        self.get_att_mtu()
208    }
209
210    pub fn role(&self) -> LeConnRole {
212        self.manager.role(self.index)
213    }
214
215    pub fn peer_address(&self) -> BdAddr {
217        self.manager.peer_address(self.index)
218    }
219
220    pub fn peer_identity(&self) -> Identity {
222        self.manager.peer_identity(self.index)
223    }
224
225    pub fn encrypted(&self) -> bool {
227        self.manager.get_encrypted(self.index)
228    }
229
230    pub fn disconnect(&self) {
232        self.manager
233            .request_disconnect(self.index, DisconnectReason::RemoteUserTerminatedConn);
234    }
235
236    #[cfg(feature = "connection-metrics")]
238    pub fn metrics<F: FnOnce(&ConnectionMetrics) -> R, R>(&self, f: F) -> R {
239        self.manager.metrics(self.index, f)
240    }
241
242    pub async fn rssi<T>(&self, stack: &Stack<'_, T, P>) -> Result<i8, BleHostError<T::Error>>
244    where
245        T: ControllerCmdSync<ReadRssi>,
246    {
247        let handle = self.handle();
248        let ret = stack.host.command(ReadRssi::new(handle)).await?;
249        Ok(ret.rssi)
250    }
251
252    pub async fn set_phy<T>(&self, stack: &Stack<'_, T, P>, phy: PhyKind) -> Result<(), BleHostError<T::Error>>
257    where
258        T: ControllerCmdAsync<LeSetPhy>,
259    {
260        let all_phys = AllPhys::new()
261            .set_has_no_rx_phy_preference(false)
262            .set_has_no_tx_phy_preference(false);
263        let mut mask = PhyMask::new()
264            .set_le_coded_preferred(false)
265            .set_le_1m_preferred(false)
266            .set_le_2m_preferred(false);
267        let mut options = PhyOptions::default();
268        match phy {
269            PhyKind::Le2M => {
270                mask = mask.set_le_2m_preferred(true);
271            }
272            PhyKind::Le1M => {
273                mask = mask.set_le_1m_preferred(true);
274            }
275            PhyKind::LeCoded => {
276                mask = mask.set_le_coded_preferred(true);
277                options = PhyOptions::S8CodingPreferred;
278            }
279            PhyKind::LeCodedS2 => {
280                mask = mask.set_le_coded_preferred(true);
281                options = PhyOptions::S2CodingPreferred;
282            }
283        }
284        stack
285            .host
286            .async_command(LeSetPhy::new(self.handle(), all_phys, mask, mask, options))
287            .await?;
288        Ok(())
289    }
290
291    pub async fn read_phy<T>(&self, stack: &Stack<'_, T, P>) -> Result<(PhyKind, PhyKind), BleHostError<T::Error>>
293    where
294        T: ControllerCmdSync<LeReadPhy>,
295    {
296        let res = stack.host.command(LeReadPhy::new(self.handle())).await?;
297        Ok((res.tx_phy, res.rx_phy))
298    }
299
300    pub async fn update_connection_params<T>(
302        &self,
303        stack: &Stack<'_, T, P>,
304        params: &ConnectParams,
305    ) -> Result<(), BleHostError<T::Error>>
306    where
307        T: ControllerCmdAsync<LeConnUpdate>,
308    {
309        let handle = self.handle();
310        match stack
311            .host
312            .async_command(LeConnUpdate::new(
313                handle,
314                params.min_connection_interval.into(),
315                params.max_connection_interval.into(),
316                params.max_latency,
317                params.supervision_timeout.into(),
318                params.event_length.into(),
319                params.event_length.into(),
320            ))
321            .await
322        {
323            Ok(_) => Ok(()),
324            Err(BleHostError::BleHost(crate::Error::Hci(bt_hci::param::Error::UNKNOWN_CONN_IDENTIFIER))) => {
325                Err(crate::Error::Disconnected.into())
326            }
327            Err(e) => Err(e),
328        }
329    }
330
331    #[cfg(feature = "gatt")]
333    pub fn with_attribute_server<
334        'values,
335        'server,
336        M: RawMutex,
337        const ATT_MAX: usize,
338        const CCCD_MAX: usize,
339        const CONN_MAX: usize,
340    >(
341        self,
342        server: &'server AttributeServer<'values, M, P, ATT_MAX, CCCD_MAX, CONN_MAX>,
343    ) -> Result<GattConnection<'stack, 'server, P>, Error> {
344        GattConnection::try_new(self, server)
345    }
346}