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}