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::{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 let drop = crate::host::OnDrop::new(|| {
43 host.advertise_command_state.cancel(false);
44 });
45 host.advertise_command_state.request().await;
46
47 host.advertise_state.reset();
49
50 let data: RawAdvertisement = data.into();
51 if !data.props.legacy_adv() {
52 return Err(Error::ExtendedAdvertisingNotSupported.into());
53 }
54
55 let kind = match (data.props.connectable_adv(), data.props.scannable_adv()) {
56 (true, true) => AdvKind::AdvInd,
57 (true, false) => AdvKind::AdvDirectIndLow,
58 (false, true) => AdvKind::AdvScanInd,
59 (false, false) => AdvKind::AdvNonconnInd,
60 };
61 let peer = data.peer.unwrap_or(Address {
62 kind: AddrKind::PUBLIC,
63 addr: BdAddr::default(),
64 });
65
66 host.command(LeSetAdvParams::new(
67 params.interval_min.into(),
68 params.interval_max.into(),
69 kind,
70 host.address.map(|a| a.kind).unwrap_or(AddrKind::PUBLIC),
71 peer.kind,
72 peer.addr,
73 params.channel_map.unwrap_or(AdvChannelMap::ALL),
74 params.filter_policy,
75 ))
76 .await?;
77
78 if !data.adv_data.is_empty() {
79 let mut buf = [0; 31];
80 let to_copy = data.adv_data.len().min(buf.len());
81 buf[..to_copy].copy_from_slice(&data.adv_data[..to_copy]);
82 host.command(LeSetAdvData::new(to_copy as u8, buf)).await?;
83 }
84
85 if !data.scan_data.is_empty() {
86 let mut buf = [0; 31];
87 let to_copy = data.scan_data.len().min(buf.len());
88 buf[..to_copy].copy_from_slice(&data.scan_data[..to_copy]);
89 host.command(LeSetScanResponseData::new(to_copy as u8, buf)).await?;
90 }
91
92 let advset: [AdvSet; 1] = [AdvSet {
93 adv_handle: AdvHandle::new(0),
94 duration: params.timeout.unwrap_or(embassy_time::Duration::from_micros(0)).into(),
95 max_ext_adv_events: 0,
96 }];
97
98 trace!("[host] enabling advertising");
99 host.advertise_state.start(&advset[..]);
100 host.command(LeSetAdvEnable::new(true)).await?;
101 drop.defuse();
102 Ok(Advertiser {
103 stack: self.stack,
104 extended: false,
105 done: false,
106 })
107 }
108
109 pub async fn update_adv_data<'k>(&mut self, data: Advertisement<'k>) -> Result<(), BleHostError<C::Error>>
115 where
116 C: for<'t> ControllerCmdSync<LeSetAdvData> + for<'t> ControllerCmdSync<LeSetScanResponseData>,
117 {
118 let host = &self.stack.host;
119 let data: RawAdvertisement = data.into();
120 if !data.props.legacy_adv() {
121 return Err(Error::ExtendedAdvertisingNotSupported.into());
122 }
123 if !data.adv_data.is_empty() {
124 let mut buf = [0; 31];
125 let to_copy = data.adv_data.len().min(buf.len());
126 buf[..to_copy].copy_from_slice(&data.adv_data[..to_copy]);
127 host.command(LeSetAdvData::new(to_copy as u8, buf)).await?;
128 }
129 if !data.scan_data.is_empty() {
130 let mut buf = [0; 31];
131 let to_copy = data.scan_data.len().min(buf.len());
132 buf[..to_copy].copy_from_slice(&data.scan_data[..to_copy]);
133 host.command(LeSetScanResponseData::new(to_copy as u8, buf)).await?;
134 }
135 Ok(())
136 }
137
138 pub async fn advertise_ext<'k>(
148 &mut self,
149 sets: &[AdvertisementSet<'k>],
150 handles: &mut [AdvSet],
151 ) -> Result<Advertiser<'d, C, P>, BleHostError<C::Error>>
152 where
153 C: for<'t> ControllerCmdSync<LeSetExtAdvData<'t>>
154 + ControllerCmdSync<LeClearAdvSets>
155 + ControllerCmdSync<LeSetExtAdvParams>
156 + ControllerCmdSync<LeSetAdvSetRandomAddr>
157 + ControllerCmdSync<LeReadNumberOfSupportedAdvSets>
158 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
159 + for<'t> ControllerCmdSync<LeSetExtScanResponseData<'t>>,
160 {
161 assert_eq!(sets.len(), handles.len());
162 let host = &self.stack.host;
163 {
165 let result = host.command(LeReadNumberOfSupportedAdvSets::new()).await?;
166 if result < sets.len() as u8 || host.advertise_state.len() < sets.len() {
167 return Err(Error::InsufficientSpace.into());
168 }
169 }
170
171 let drop = crate::host::OnDrop::new(|| {
173 host.advertise_command_state.cancel(true);
174 });
175 host.advertise_command_state.request().await;
176
177 host.advertise_state.reset();
179
180 for (i, set) in sets.iter().enumerate() {
181 let handle = AdvHandle::new(i as u8);
182 let data: RawAdvertisement<'k> = set.data.into();
183 let params = set.params;
184 let peer = data.peer.unwrap_or(Address {
185 kind: AddrKind::PUBLIC,
186 addr: BdAddr::default(),
187 });
188 host.command(LeSetExtAdvParams::new(
189 handle,
190 data.props,
191 params.interval_min.into(),
192 params.interval_max.into(),
193 params.channel_map.unwrap_or(AdvChannelMap::ALL),
194 host.address.map(|a| a.kind).unwrap_or(AddrKind::PUBLIC),
195 peer.kind,
196 peer.addr,
197 params.filter_policy,
198 params.tx_power as i8,
199 params.primary_phy,
200 0,
201 params.secondary_phy,
202 0,
203 false,
204 ))
205 .await?;
206
207 if let Some(address) = host.address.as_ref() {
208 host.command(LeSetAdvSetRandomAddr::new(handle, address.addr)).await?;
209 }
210
211 if !data.adv_data.is_empty() {
212 host.command(LeSetExtAdvData::new(
213 handle,
214 Operation::Complete,
215 params.fragment,
216 data.adv_data,
217 ))
218 .await?;
219 }
220
221 if !data.scan_data.is_empty() {
222 host.command(LeSetExtScanResponseData::new(
223 handle,
224 Operation::Complete,
225 params.fragment,
226 data.scan_data,
227 ))
228 .await?;
229 }
230 handles[i].adv_handle = handle;
231 handles[i].duration = set
232 .params
233 .timeout
234 .unwrap_or(embassy_time::Duration::from_micros(0))
235 .into();
236 handles[i].max_ext_adv_events = set.params.max_events.unwrap_or(0);
237 }
238
239 trace!("[host] enabling extended advertising");
240 host.advertise_state.start(handles);
241 host.command(LeSetExtAdvEnable::new(true, handles)).await?;
242 drop.defuse();
243 Ok(Advertiser {
244 stack: self.stack,
245 extended: true,
246 done: false,
247 })
248 }
249
250 pub async fn update_adv_data_ext<'k>(
256 &mut self,
257 sets: &[AdvertisementSet<'k>],
258 handles: &mut [AdvSet],
259 ) -> Result<(), BleHostError<C::Error>>
260 where
261 C: for<'t> ControllerCmdSync<LeSetExtAdvData<'t>> + for<'t> ControllerCmdSync<LeSetExtScanResponseData<'t>>,
262 {
263 assert_eq!(sets.len(), handles.len());
264 let host = &self.stack.host;
265 for (i, set) in sets.iter().enumerate() {
266 let handle = handles[i].adv_handle;
267 let data: RawAdvertisement<'k> = set.data.into();
268 if !data.adv_data.is_empty() {
269 host.command(LeSetExtAdvData::new(
270 handle,
271 Operation::Complete,
272 set.params.fragment,
273 data.adv_data,
274 ))
275 .await?;
276 }
277 if !data.scan_data.is_empty() {
278 host.command(LeSetExtScanResponseData::new(
279 handle,
280 Operation::Complete,
281 set.params.fragment,
282 data.scan_data,
283 ))
284 .await?;
285 }
286 }
287 Ok(())
288 }
289
290 pub fn try_accept(&mut self) -> Option<Connection<'d, P>> {
294 if let Poll::Ready(conn) = self
295 .stack
296 .host
297 .connections
298 .poll_accept(LeConnRole::Peripheral, &[], None)
299 {
300 Some(conn)
301 } else {
302 None
303 }
304 }
305}
306
307pub struct Advertiser<'d, C, P: PacketPool> {
309 stack: &'d Stack<'d, C, P>,
310 extended: bool,
311 done: bool,
312}
313
314impl<'d, C: Controller, P: PacketPool> Advertiser<'d, C, P> {
315 pub async fn accept(mut self) -> Result<Connection<'d, P>, Error> {
319 let result = match select(
320 self.stack.host.connections.accept(LeConnRole::Peripheral, &[]),
321 self.stack.host.advertise_state.wait(),
322 )
323 .await
324 {
325 Either::First(conn) => Ok(conn),
326 Either::Second(_) => Err(Error::Timeout),
327 };
328 self.done = true;
329 result
330 }
331}
332
333impl<C, P: PacketPool> Drop for Advertiser<'_, C, P> {
334 fn drop(&mut self) {
335 if !self.done {
336 self.stack.host.advertise_command_state.cancel(self.extended);
337 } else {
338 self.stack.host.advertise_command_state.canceled();
339 }
340 }
341}