1use core::task::Poll;
3
4use bt_hci::cmd::le::{
5 LeClearAdvSets, LeReadNumberOfSupportedAdvSets, LeSetAdvData, LeSetAdvEnable, LeSetAdvParams,
6 LeSetAdvSetRandomAddr, LeSetExtAdvData, LeSetExtAdvEnable, LeSetExtAdvParams, LeSetExtScanResponseData,
7 LeSetScanResponseData,
8};
9use bt_hci::controller::{Controller, ControllerCmdSync};
10use bt_hci::param::{AddrKind, AdvChannelMap, AdvHandle, AdvKind, AdvSet, BdAddr, LeConnRole, Operation};
11use embassy_futures::select::{select, Either};
12
13use crate::advertise::{Advertisement, AdvertisementParameters, AdvertisementSet, RawAdvertisement};
14use crate::connection::Connection;
15use crate::{bt_hci_duration, bt_hci_ext_duration, Address, BleHostError, Error, PacketPool, Stack};
16
17pub struct Peripheral<'d, C, P: PacketPool> {
19 stack: &'d Stack<'d, C, P>,
20}
21
22impl<'d, C: Controller, P: PacketPool> Peripheral<'d, C, P> {
23 pub(crate) fn new(stack: &'d Stack<'d, C, P>) -> Self {
24 Self { stack }
25 }
26
27 pub async fn advertise<'k>(
29 &mut self,
30 params: &AdvertisementParameters,
31 data: Advertisement<'k>,
32 ) -> Result<Advertiser<'d, C, P>, BleHostError<C::Error>>
33 where
34 C: for<'t> ControllerCmdSync<LeSetAdvData>
35 + ControllerCmdSync<LeSetAdvParams>
36 + for<'t> ControllerCmdSync<LeSetAdvEnable>
37 + for<'t> ControllerCmdSync<LeSetScanResponseData>,
38 {
39 let host = &self.stack.host;
40
41 if !data.is_valid() {
42 return Err(BleHostError::BleHost(Error::InvalidValue));
43 }
44
45 let drop = crate::host::OnDrop::new(|| {
47 host.advertise_command_state.cancel(false);
48 });
49 host.advertise_command_state.request().await;
50
51 host.advertise_state.reset();
53
54 let data: RawAdvertisement = data.into();
55 if !data.props.legacy_adv() {
56 return Err(Error::ExtendedAdvertisingNotSupported.into());
57 }
58
59 let kind = match (
60 data.props.connectable_adv(),
61 data.props.scannable_adv(),
62 data.props.high_duty_cycle_directed_connectable_adv(),
63 ) {
64 (true, true, _) => AdvKind::AdvInd,
65 (true, false, true) => AdvKind::AdvDirectIndHigh,
66 (true, false, false) => AdvKind::AdvDirectIndLow,
67 (false, true, _) => AdvKind::AdvScanInd,
68 (false, false, _) => AdvKind::AdvNonconnInd,
69 };
70 let peer = data.peer.unwrap_or(Address {
71 kind: AddrKind::PUBLIC,
72 addr: BdAddr::default(),
73 });
74
75 host.command(LeSetAdvParams::new(
76 bt_hci_duration(params.interval_min),
77 bt_hci_duration(params.interval_max),
78 kind,
79 host.address.map(|a| a.kind).unwrap_or(AddrKind::PUBLIC),
80 peer.kind,
81 peer.addr,
82 params.channel_map.unwrap_or(AdvChannelMap::ALL),
83 params.filter_policy,
84 ))
85 .await?;
86
87 if !data.adv_data.is_empty() {
88 let mut buf = [0; 31];
89 let to_copy = data.adv_data.len().min(buf.len());
90 buf[..to_copy].copy_from_slice(&data.adv_data[..to_copy]);
91 host.command(LeSetAdvData::new(to_copy as u8, buf)).await?;
92 }
93
94 if !data.scan_data.is_empty() {
95 let mut buf = [0; 31];
96 let to_copy = data.scan_data.len().min(buf.len());
97 buf[..to_copy].copy_from_slice(&data.scan_data[..to_copy]);
98 host.command(LeSetScanResponseData::new(to_copy as u8, buf)).await?;
99 }
100
101 let advset: [AdvSet; 1] = [AdvSet {
102 adv_handle: AdvHandle::new(0),
103 duration: bt_hci_duration(params.timeout.unwrap_or(embassy_time::Duration::from_micros(0))),
104 max_ext_adv_events: 0,
105 }];
106
107 trace!("[host] enabling advertising");
108 host.advertise_state.start(&advset[..]);
109 host.command(LeSetAdvEnable::new(true)).await?;
110 drop.defuse();
111 Ok(Advertiser {
112 stack: self.stack,
113 extended: false,
114 done: false,
115 })
116 }
117
118 pub async fn update_adv_data<'k>(&mut self, data: Advertisement<'k>) -> Result<(), BleHostError<C::Error>>
124 where
125 C: for<'t> ControllerCmdSync<LeSetAdvData> + for<'t> ControllerCmdSync<LeSetScanResponseData>,
126 {
127 let host = &self.stack.host;
128
129 if !data.is_valid() {
130 return Err(BleHostError::BleHost(Error::InvalidValue));
131 }
132
133 let data: RawAdvertisement = data.into();
134 if !data.props.legacy_adv() {
135 return Err(Error::ExtendedAdvertisingNotSupported.into());
136 }
137 if !data.adv_data.is_empty() {
138 let mut buf = [0; 31];
139 let to_copy = data.adv_data.len().min(buf.len());
140 buf[..to_copy].copy_from_slice(&data.adv_data[..to_copy]);
141 host.command(LeSetAdvData::new(to_copy as u8, buf)).await?;
142 }
143 if !data.scan_data.is_empty() {
144 let mut buf = [0; 31];
145 let to_copy = data.scan_data.len().min(buf.len());
146 buf[..to_copy].copy_from_slice(&data.scan_data[..to_copy]);
147 host.command(LeSetScanResponseData::new(to_copy as u8, buf)).await?;
148 }
149 Ok(())
150 }
151
152 pub async fn advertise_ext<'k>(
162 &mut self,
163 sets: &[AdvertisementSet<'k>],
164 handles: &mut [AdvSet],
165 ) -> Result<Advertiser<'d, C, P>, BleHostError<C::Error>>
166 where
167 C: for<'t> ControllerCmdSync<LeSetExtAdvData<'t>>
168 + ControllerCmdSync<LeClearAdvSets>
169 + ControllerCmdSync<LeSetExtAdvParams>
170 + ControllerCmdSync<LeSetAdvSetRandomAddr>
171 + ControllerCmdSync<LeReadNumberOfSupportedAdvSets>
172 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
173 + for<'t> ControllerCmdSync<LeSetExtScanResponseData<'t>>,
174 {
175 assert_eq!(sets.len(), handles.len());
176 let host = &self.stack.host;
177
178 for set in sets.iter() {
180 if !set.data.is_valid() {
181 return Err(BleHostError::BleHost(Error::InvalidValue));
182 }
183 }
184
185 {
187 let result = host.command(LeReadNumberOfSupportedAdvSets::new()).await?;
188 if result < sets.len() as u8 || host.advertise_state.len() < sets.len() {
189 return Err(Error::InsufficientSpace.into());
190 }
191 }
192
193 let drop = crate::host::OnDrop::new(|| {
195 host.advertise_command_state.cancel(true);
196 });
197 host.advertise_command_state.request().await;
198
199 host.advertise_state.reset();
201
202 for (i, set) in sets.iter().enumerate() {
203 let handle = AdvHandle::new(i as u8);
204 let data: RawAdvertisement<'k> = set.data.into();
205 let params = set.params;
206 let peer = data.peer.unwrap_or(Address {
207 kind: AddrKind::PUBLIC,
208 addr: BdAddr::default(),
209 });
210 host.command(LeSetExtAdvParams::new(
211 handle,
212 data.props,
213 bt_hci_ext_duration(params.interval_min),
214 bt_hci_ext_duration(params.interval_max),
215 params.channel_map.unwrap_or(AdvChannelMap::ALL),
216 host.address.map(|a| a.kind).unwrap_or(AddrKind::PUBLIC),
217 peer.kind,
218 peer.addr,
219 params.filter_policy,
220 params.tx_power as i8,
221 params.primary_phy,
222 0,
223 params.secondary_phy,
224 0,
225 false,
226 ))
227 .await?;
228
229 if let Some(address) = host.address.as_ref() {
230 host.command(LeSetAdvSetRandomAddr::new(handle, address.addr)).await?;
231 }
232
233 if !data.adv_data.is_empty() {
234 host.command(LeSetExtAdvData::new(
235 handle,
236 Operation::Complete,
237 params.fragment,
238 data.adv_data,
239 ))
240 .await?;
241 }
242
243 if !data.scan_data.is_empty() {
244 host.command(LeSetExtScanResponseData::new(
245 handle,
246 Operation::Complete,
247 params.fragment,
248 data.scan_data,
249 ))
250 .await?;
251 }
252 handles[i].adv_handle = handle;
253 handles[i].duration = bt_hci_duration(set.params.timeout.unwrap_or(embassy_time::Duration::from_micros(0)));
254 handles[i].max_ext_adv_events = set.params.max_events.unwrap_or(0);
255 }
256
257 trace!("[host] enabling extended advertising");
258 host.advertise_state.start(handles);
259 host.command(LeSetExtAdvEnable::new(true, handles)).await?;
260 drop.defuse();
261 Ok(Advertiser {
262 stack: self.stack,
263 extended: true,
264 done: false,
265 })
266 }
267
268 pub async fn update_adv_data_ext<'k>(
274 &mut self,
275 sets: &[AdvertisementSet<'k>],
276 handles: &mut [AdvSet],
277 ) -> Result<(), BleHostError<C::Error>>
278 where
279 C: for<'t> ControllerCmdSync<LeSetExtAdvData<'t>> + for<'t> ControllerCmdSync<LeSetExtScanResponseData<'t>>,
280 {
281 assert_eq!(sets.len(), handles.len());
282 let host = &self.stack.host;
283 for (i, set) in sets.iter().enumerate() {
284 if !set.data.is_valid() {
285 return Err(BleHostError::BleHost(Error::InvalidValue));
286 }
287
288 let handle = handles[i].adv_handle;
289 let data: RawAdvertisement<'k> = set.data.into();
290 if !data.adv_data.is_empty() {
291 host.command(LeSetExtAdvData::new(
292 handle,
293 Operation::Complete,
294 set.params.fragment,
295 data.adv_data,
296 ))
297 .await?;
298 }
299 if !data.scan_data.is_empty() {
300 host.command(LeSetExtScanResponseData::new(
301 handle,
302 Operation::Complete,
303 set.params.fragment,
304 data.scan_data,
305 ))
306 .await?;
307 }
308 }
309 Ok(())
310 }
311
312 pub fn try_accept(&mut self) -> Option<Connection<'d, P>> {
316 if let Poll::Ready(conn) = self
317 .stack
318 .host
319 .connections
320 .poll_accept(LeConnRole::Peripheral, &[], None)
321 {
322 Some(conn)
323 } else {
324 None
325 }
326 }
327}
328
329pub struct Advertiser<'d, C, P: PacketPool> {
331 stack: &'d Stack<'d, C, P>,
332 extended: bool,
333 done: bool,
334}
335
336impl<'d, C: Controller, P: PacketPool> Advertiser<'d, C, P> {
337 pub async fn accept(mut self) -> Result<Connection<'d, P>, Error> {
341 let result = match select(
342 self.stack.host.connections.accept(LeConnRole::Peripheral, &[]),
343 self.stack.host.advertise_state.wait(),
344 )
345 .await
346 {
347 Either::First(conn) => Ok(conn),
348 Either::Second(_) => Err(Error::Timeout),
349 };
350 self.done = true;
351 result
352 }
353}
354
355impl<C, P: PacketPool> Drop for Advertiser<'_, C, P> {
356 fn drop(&mut self) {
357 if !self.done {
358 self.stack.host.advertise_command_state.cancel(self.extended);
359 } else {
360 self.stack.host.advertise_command_state.canceled();
361 }
362 }
363}