1use core::cell::RefCell;
4use core::future::{poll_fn, Future};
5use core::mem::MaybeUninit;
6use core::task::Poll;
7
8use cmd::controller_baseband::Reset;
9use embassy_sync::blocking_mutex::raw::NoopRawMutex;
10use embassy_sync::signal::Signal;
11use embassy_sync::waitqueue::AtomicWaker;
12use embedded_io::ErrorType;
13use futures_intrusive::sync::LocalSemaphore;
14
15use crate::cmd::{Cmd, CmdReturnBuf};
16use crate::event::{CommandComplete, CommandStatus, EventKind};
17use crate::param::{RemainingBytes, Status};
18use crate::transport::Transport;
19use crate::{cmd, data, ControllerToHostPacket, FixedSizeValue, FromHciBytes, FromHciBytesError};
20
21pub mod blocking;
22
23pub trait Controller: ErrorType {
25 fn write_acl_data(&self, packet: &data::AclPacket) -> impl Future<Output = Result<(), Self::Error>>;
27 fn write_sync_data(&self, packet: &data::SyncPacket) -> impl Future<Output = Result<(), Self::Error>>;
29 fn write_iso_data(&self, packet: &data::IsoPacket) -> impl Future<Output = Result<(), Self::Error>>;
31
32 fn read<'a>(&self, buf: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>>;
34}
35
36pub trait ControllerCmdSync<C: cmd::SyncCmd + ?Sized>: Controller {
38 fn exec(&self, cmd: &C) -> impl Future<Output = Result<C::Return, cmd::Error<Self::Error>>>;
40}
41
42pub trait ControllerCmdAsync<C: cmd::AsyncCmd + ?Sized>: Controller {
44 fn exec(&self, cmd: &C) -> impl Future<Output = Result<(), cmd::Error<Self::Error>>>;
46}
47
48pub struct ExternalController<T, const SLOTS: usize> {
56 transport: T,
57 slots: ControllerState<SLOTS>,
58}
59
60impl<T, const SLOTS: usize> ExternalController<T, SLOTS> {
61 pub fn new(transport: T) -> Self {
63 Self {
64 slots: ControllerState::new(),
65 transport,
66 }
67 }
68}
69
70impl<T, const SLOTS: usize> ErrorType for ExternalController<T, SLOTS>
71where
72 T: ErrorType,
73{
74 type Error = T::Error;
75}
76
77impl<T, const SLOTS: usize> Controller for ExternalController<T, SLOTS>
78where
79 T: Transport,
80 T::Error: From<FromHciBytesError>,
81{
82 async fn write_acl_data(&self, packet: &data::AclPacket<'_>) -> Result<(), Self::Error> {
83 self.transport.write(packet).await?;
84 Ok(())
85 }
86
87 async fn write_sync_data(&self, packet: &data::SyncPacket<'_>) -> Result<(), Self::Error> {
88 self.transport.write(packet).await?;
89 Ok(())
90 }
91
92 async fn write_iso_data(&self, packet: &data::IsoPacket<'_>) -> Result<(), Self::Error> {
93 self.transport.write(packet).await?;
94 Ok(())
95 }
96
97 async fn read<'a>(&self, buf: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
98 loop {
99 {
100 let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) };
102 let value = self.transport.read(&mut buf[..]).await?;
103 match value {
104 ControllerToHostPacket::Event(ref event) => match event.kind {
105 EventKind::CommandComplete => {
106 let e = CommandComplete::from_hci_bytes_complete(event.data)?;
107 self.slots.complete(
108 e.cmd_opcode,
109 e.status,
110 e.num_hci_cmd_pkts as usize,
111 e.return_param_bytes.as_ref(),
112 );
113 continue;
114 }
115 EventKind::CommandStatus => {
116 let e = CommandStatus::from_hci_bytes_complete(event.data)?;
117 self.slots
118 .complete(e.cmd_opcode, e.status, e.num_hci_cmd_pkts as usize, &[]);
119 continue;
120 }
121 _ => return Ok(value),
122 },
123 _ => return Ok(value),
124 }
125 }
126 }
127 }
128}
129
130impl<T, const SLOTS: usize> blocking::Controller for ExternalController<T, SLOTS>
131where
132 T: crate::transport::blocking::Transport,
133 T::Error: From<FromHciBytesError>,
134{
135 fn write_acl_data(&self, packet: &data::AclPacket<'_>) -> Result<(), Self::Error> {
136 loop {
137 match self.try_write_acl_data(packet) {
138 Err(blocking::TryError::Busy) => {}
139 Err(blocking::TryError::Error(e)) => return Err(e),
140 Ok(r) => return Ok(r),
141 }
142 }
143 }
144
145 fn write_sync_data(&self, packet: &data::SyncPacket<'_>) -> Result<(), Self::Error> {
146 loop {
147 match self.try_write_sync_data(packet) {
148 Err(blocking::TryError::Busy) => {}
149 Err(blocking::TryError::Error(e)) => return Err(e),
150 Ok(r) => return Ok(r),
151 }
152 }
153 }
154
155 fn write_iso_data(&self, packet: &data::IsoPacket<'_>) -> Result<(), Self::Error> {
156 loop {
157 match self.try_write_iso_data(packet) {
158 Err(blocking::TryError::Busy) => {}
159 Err(blocking::TryError::Error(e)) => return Err(e),
160 Ok(r) => return Ok(r),
161 }
162 }
163 }
164
165 fn read<'a>(&self, buf: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, Self::Error> {
166 loop {
167 let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) };
169 match self.try_read(buf) {
170 Err(blocking::TryError::Busy) => {}
171 Err(blocking::TryError::Error(e)) => return Err(e),
172 Ok(r) => return Ok(r),
173 }
174 }
175 }
176
177 fn try_write_acl_data(&self, packet: &data::AclPacket<'_>) -> Result<(), blocking::TryError<Self::Error>> {
178 self.transport.write(packet)?;
179 Ok(())
180 }
181
182 fn try_write_sync_data(&self, packet: &data::SyncPacket<'_>) -> Result<(), blocking::TryError<Self::Error>> {
183 self.transport.write(packet)?;
184 Ok(())
185 }
186
187 fn try_write_iso_data(&self, packet: &data::IsoPacket<'_>) -> Result<(), blocking::TryError<Self::Error>> {
188 self.transport.write(packet)?;
189 Ok(())
190 }
191
192 fn try_read<'a>(&self, buf: &'a mut [u8]) -> Result<ControllerToHostPacket<'a>, blocking::TryError<Self::Error>> {
193 loop {
194 {
195 let buf = unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr(), buf.len()) };
197 let value = self.transport.read(&mut buf[..])?;
198 match value {
199 ControllerToHostPacket::Event(ref event) => match event.kind {
200 EventKind::CommandComplete => {
201 let e = CommandComplete::from_hci_bytes_complete(event.data)?;
202 self.slots.complete(
203 e.cmd_opcode,
204 e.status,
205 e.num_hci_cmd_pkts as usize,
206 e.return_param_bytes.as_ref(),
207 );
208 continue;
209 }
210 EventKind::CommandStatus => {
211 let e = CommandStatus::from_hci_bytes_complete(event.data)?;
212 self.slots
213 .complete(e.cmd_opcode, e.status, e.num_hci_cmd_pkts as usize, &[]);
214 continue;
215 }
216 _ => return Ok(value),
217 },
218 _ => return Ok(value),
219 }
220 }
221 }
222 }
223}
224
225impl<T, C, const SLOTS: usize> ControllerCmdSync<C> for ExternalController<T, SLOTS>
226where
227 T: Transport,
228 C: cmd::SyncCmd,
229 C::Return: FixedSizeValue,
230 T::Error: From<FromHciBytesError>,
231{
232 async fn exec(&self, cmd: &C) -> Result<C::Return, cmd::Error<Self::Error>> {
233 let mut retval: C::ReturnBuf = C::ReturnBuf::new();
234
235 let (slot, idx) = self.slots.acquire(C::OPCODE, retval.as_mut()).await;
237 let _d = OnDrop::new(|| {
238 self.slots.release_slot(idx);
239 });
240
241 self.transport.write(cmd).await.map_err(cmd::Error::Io)?;
242
243 let result = slot.wait().await;
244 let return_param_bytes = RemainingBytes::from_hci_bytes_complete(&retval.as_ref()[..result.len]).unwrap();
245 let e = CommandComplete {
246 num_hci_cmd_pkts: 0,
247 status: result.status,
248 cmd_opcode: C::OPCODE,
249 return_param_bytes,
250 };
251 let r = e.to_result::<C>().map_err(cmd::Error::Hci)?;
252 Ok(r)
254 }
255}
256
257impl<T, C, const SLOTS: usize> ControllerCmdAsync<C> for ExternalController<T, SLOTS>
258where
259 T: Transport,
260 C: cmd::AsyncCmd,
261 T::Error: From<FromHciBytesError>,
262{
263 async fn exec(&self, cmd: &C) -> Result<(), cmd::Error<Self::Error>> {
264 let (slot, idx) = self.slots.acquire(C::OPCODE, &mut []).await;
265 let _d = OnDrop::new(|| {
266 self.slots.release_slot(idx);
267 });
268
269 self.transport.write(cmd).await.map_err(cmd::Error::Io)?;
270
271 let result = slot.wait().await;
272 result.status.to_result()?;
273 Ok(())
274 }
275}
276
277struct ControllerState<const SLOTS: usize> {
278 permits: LocalSemaphore,
279 slots: RefCell<[CommandSlot; SLOTS]>,
280 signals: [Signal<NoopRawMutex, CommandResponse>; SLOTS],
281 waker: AtomicWaker,
282}
283
284struct CommandResponse {
285 status: Status,
286 len: usize,
287}
288
289enum CommandSlot {
290 Empty,
291 Pending { opcode: u16, event: *mut [u8] },
292}
293
294impl<const SLOTS: usize> Default for ControllerState<SLOTS> {
295 fn default() -> Self {
296 Self::new()
297 }
298}
299
300impl<const SLOTS: usize> ControllerState<SLOTS> {
301 const EMPTY_SLOT: CommandSlot = CommandSlot::Empty;
302 #[allow(clippy::declare_interior_mutable_const)]
303 const EMPTY_SIGNAL: Signal<NoopRawMutex, CommandResponse> = Signal::new();
304
305 fn new() -> Self {
306 Self {
307 permits: LocalSemaphore::new(true, 1),
308 slots: RefCell::new([Self::EMPTY_SLOT; SLOTS]),
309 signals: [Self::EMPTY_SIGNAL; SLOTS],
310 waker: AtomicWaker::new(),
311 }
312 }
313
314 fn complete(&self, op: cmd::Opcode, status: Status, num_hci_command_packets: usize, data: &[u8]) {
315 let mut slots = self.slots.borrow_mut();
316 for (idx, slot) in slots.iter_mut().enumerate() {
317 match slot {
318 CommandSlot::Pending { opcode, event } if *opcode == op.to_raw() => {
319 if !data.is_empty() {
320 assert!(!event.is_null());
321 unsafe { (&mut (**event))[..data.len()].copy_from_slice(data) };
323 }
324 self.signals[idx].signal(CommandResponse {
325 status,
326 len: data.len(),
327 });
328 if op != Reset::OPCODE {
329 break;
330 }
331 }
332 CommandSlot::Pending { opcode: _, event: _ } if op == Reset::OPCODE => {
333 self.signals[idx].signal(CommandResponse {
335 status: Status::CONTROLLER_BUSY,
336 len: 0,
337 });
338 }
339 _ => {}
340 }
341 }
342
343 self.permits
345 .release(num_hci_command_packets.saturating_sub(self.permits.permits()));
346 }
347
348 fn release_slot(&self, idx: usize) {
349 let mut slots = self.slots.borrow_mut();
350 slots[idx] = CommandSlot::Empty;
351 }
352
353 async fn acquire(&self, op: cmd::Opcode, event: *mut [u8]) -> (&Signal<NoopRawMutex, CommandResponse>, usize) {
354 let to_acquire = if op == Reset::OPCODE { self.permits.permits() } else { 1 };
355 let mut permit = self.permits.acquire(to_acquire).await;
356 permit.disarm();
357 poll_fn(|cx| match self.acquire_slot(op, event) {
358 Some(ret) => Poll::Ready(ret),
359 None => {
360 self.waker.register(cx.waker());
361 Poll::Pending
362 }
363 })
364 .await
365 }
366
367 fn acquire_slot(
368 &self,
369 op: cmd::Opcode,
370 event: *mut [u8],
371 ) -> Option<(&Signal<NoopRawMutex, CommandResponse>, usize)> {
372 let mut slots = self.slots.borrow_mut();
373 for slot in slots.iter() {
375 match slot {
376 CommandSlot::Pending { opcode, event: _ } if *opcode == op.to_raw() => {
377 return None;
378 }
379 _ => {}
380 }
381 }
382 for (idx, slot) in slots.iter_mut().enumerate() {
384 if matches!(slot, CommandSlot::Empty) {
385 *slot = CommandSlot::Pending {
386 opcode: op.to_raw(),
387 event,
388 };
389 self.signals[idx].reset();
390 return Some((&self.signals[idx], idx));
391 }
392 }
393 None
394 }
395}
396
397#[must_use = "to delay the drop handler invocation to the end of the scope"]
399struct OnDrop<F: FnOnce()> {
400 f: MaybeUninit<F>,
401}
402
403impl<F: FnOnce()> OnDrop<F> {
404 pub(crate) fn new(f: F) -> Self {
406 Self { f: MaybeUninit::new(f) }
407 }
408}
409
410impl<F: FnOnce()> Drop for OnDrop<F> {
411 fn drop(&mut self) {
412 unsafe { self.f.as_ptr().read()() }
413 }
414}