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 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 bt_hci_duration(params.interval_min),
68 bt_hci_duration(params.interval_max),
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: bt_hci_duration(params.timeout.unwrap_or(embassy_time::Duration::from_micros(0))),
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 bt_hci_ext_duration(params.interval_min),
192 bt_hci_ext_duration(params.interval_max),
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 = bt_hci_duration(set.params.timeout.unwrap_or(embassy_time::Duration::from_micros(0)));
232 handles[i].max_ext_adv_events = set.params.max_events.unwrap_or(0);
233 }
234
235 trace!("[host] enabling extended advertising");
236 host.advertise_state.start(handles);
237 host.command(LeSetExtAdvEnable::new(true, handles)).await?;
238 drop.defuse();
239 Ok(Advertiser {
240 stack: self.stack,
241 extended: true,
242 done: false,
243 })
244 }
245
246 pub async fn update_adv_data_ext<'k>(
252 &mut self,
253 sets: &[AdvertisementSet<'k>],
254 handles: &mut [AdvSet],
255 ) -> Result<(), BleHostError<C::Error>>
256 where
257 C: for<'t> ControllerCmdSync<LeSetExtAdvData<'t>> + for<'t> ControllerCmdSync<LeSetExtScanResponseData<'t>>,
258 {
259 assert_eq!(sets.len(), handles.len());
260 let host = &self.stack.host;
261 for (i, set) in sets.iter().enumerate() {
262 let handle = handles[i].adv_handle;
263 let data: RawAdvertisement<'k> = set.data.into();
264 if !data.adv_data.is_empty() {
265 host.command(LeSetExtAdvData::new(
266 handle,
267 Operation::Complete,
268 set.params.fragment,
269 data.adv_data,
270 ))
271 .await?;
272 }
273 if !data.scan_data.is_empty() {
274 host.command(LeSetExtScanResponseData::new(
275 handle,
276 Operation::Complete,
277 set.params.fragment,
278 data.scan_data,
279 ))
280 .await?;
281 }
282 }
283 Ok(())
284 }
285
286 pub fn try_accept(&mut self) -> Option<Connection<'d, P>> {
290 if let Poll::Ready(conn) = self
291 .stack
292 .host
293 .connections
294 .poll_accept(LeConnRole::Peripheral, &[], None)
295 {
296 Some(conn)
297 } else {
298 None
299 }
300 }
301}
302
303pub struct Advertiser<'d, C, P: PacketPool> {
305 stack: &'d Stack<'d, C, P>,
306 extended: bool,
307 done: bool,
308}
309
310impl<'d, C: Controller, P: PacketPool> Advertiser<'d, C, P> {
311 pub async fn accept(mut self) -> Result<Connection<'d, P>, Error> {
315 let result = match select(
316 self.stack.host.connections.accept(LeConnRole::Peripheral, &[]),
317 self.stack.host.advertise_state.wait(),
318 )
319 .await
320 {
321 Either::First(conn) => Ok(conn),
322 Either::Second(_) => Err(Error::Timeout),
323 };
324 self.done = true;
325 result
326 }
327}
328
329impl<C, P: PacketPool> Drop for Advertiser<'_, C, P> {
330 fn drop(&mut self) {
331 if !self.done {
332 self.stack.host.advertise_command_state.cancel(self.extended);
333 } else {
334 self.stack.host.advertise_command_state.canceled();
335 }
336 }
337}