1use core::future::Future;
4
5use embedded_io::ErrorType;
6
7use crate::controller::{ControllerCmdAsync, ControllerCmdSync};
8use crate::{param, FixedSizeValue, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
9
10pub mod controller_baseband;
11pub mod info;
12pub mod le;
13pub mod link_control;
14pub mod status;
15
16#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub struct OpcodeGroup(u8);
22
23impl OpcodeGroup {
24 pub const LINK_CONTROL: OpcodeGroup = OpcodeGroup(1);
26 pub const LINK_POLICY: OpcodeGroup = OpcodeGroup(2);
28 pub const CONTROL_BASEBAND: OpcodeGroup = OpcodeGroup(3);
30 pub const INFO_PARAMS: OpcodeGroup = OpcodeGroup(4);
32 pub const STATUS_PARAMS: OpcodeGroup = OpcodeGroup(5);
34 pub const TESTING: OpcodeGroup = OpcodeGroup(6);
36 pub const LE: OpcodeGroup = OpcodeGroup(8);
38 pub const VENDOR_SPECIFIC: OpcodeGroup = OpcodeGroup(0x3f);
40
41 pub const fn new(val: u8) -> Self {
43 Self(val)
44 }
45}
46
47param!(
48 struct Opcode(u16)
52);
53
54impl Opcode {
55 pub const UNSOLICITED: Opcode = Opcode::new(OpcodeGroup(0), 0);
57
58 pub const fn new(ogf: OpcodeGroup, ocf: u16) -> Self {
60 Self(((ogf.0 as u16) << 10) | ocf)
61 }
62
63 pub const fn group(self) -> OpcodeGroup {
65 OpcodeGroup((self.0 >> 10) as u8)
66 }
67
68 pub const fn cmd(self) -> u16 {
70 self.0 & 0x03ff
71 }
72
73 pub const fn to_raw(self) -> u16 {
75 self.0
76 }
77}
78
79#[derive(Debug)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum Error<E> {
83 Hci(param::Error),
85 Io(E),
87}
88
89impl<E> From<param::Error> for Error<E> {
90 fn from(e: param::Error) -> Self {
91 Self::Hci(e)
92 }
93}
94
95pub trait Cmd: WriteHci {
97 const OPCODE: Opcode;
99
100 type Params: WriteHci;
102
103 fn params(&self) -> &Self::Params;
105
106 fn header(&self) -> [u8; 3] {
108 let opcode_bytes = Self::OPCODE.0.to_le_bytes();
109 [opcode_bytes[0], opcode_bytes[1], self.params().size() as u8]
110 }
111}
112
113impl<T: Cmd> HostToControllerPacket for T {
114 const KIND: PacketKind = PacketKind::Cmd;
115}
116
117pub trait AsyncCmd: Cmd {
120 fn exec<C: ControllerCmdAsync<Self>>(
122 &self,
123 controller: &C,
124 ) -> impl Future<Output = Result<(), Error<<C as ErrorType>::Error>>> {
125 controller.exec(self)
126 }
127}
128
129pub trait CmdReturnBuf: Copy + AsRef<[u8]> + AsMut<[u8]> {
131 const LEN: usize;
133
134 fn new() -> Self;
136}
137
138impl<const N: usize> CmdReturnBuf for [u8; N] {
139 const LEN: usize = N;
140
141 #[inline(always)]
142 fn new() -> Self {
143 [0; N]
144 }
145}
146
147pub trait SyncCmd: Cmd {
150 type Return: for<'a> FromHciBytes<'a> + Copy;
152 type Handle: FixedSizeValue;
154 type ReturnBuf: CmdReturnBuf;
156
157 fn param_handle(&self) -> Self::Handle;
159
160 fn return_handle(_data: &[u8]) -> Result<Self::Handle, crate::FromHciBytesError>;
169
170 fn exec<C: ControllerCmdSync<Self>>(
172 &self,
173 controller: &C,
174 ) -> impl Future<Output = Result<Self::Return, Error<<C as ErrorType>::Error>>> {
175 controller.exec(self)
176 }
177}
178
179#[doc(hidden)]
180#[macro_export]
181macro_rules! cmd {
182 (
183 $(#[$attrs:meta])*
184 $name:ident($group:ident, $cmd:expr) {
185 $params:ident$(<$life:lifetime>)? {
186 $($param_name:ident: $param_ty:ty,)+
187 }
188 $ret:ident {
189 $($ret_name:ident: $ret_ty:ty,)+
190 }
191 $(Handle = $handle_name:ident: $handle:ty;)?
192 }
193 ) => {
194 $crate::cmd! {
195 $(#[$attrs])*
196 $name($group, $cmd) {
197 $params$(<$life>)? {
198 $($param_name: $param_ty,)+
199 }
200 Return = $ret;
201 $(Handle = $handle_name: $handle;)?
202 }
203 }
204
205 $crate::param! {
206 #[doc = "Return parameters for"]
207 $(#[$attrs])*
208 struct $ret {
209 $($handle_name: $handle,)?
210 $($ret_name: $ret_ty,)*
211 }
212 }
213 };
214 (
215 $(#[$attrs:meta])*
216 $name:ident($group:ident, $cmd:expr) {
217 Params = ();
218 $ret:ident {
219 $($ret_name:ident: $ret_ty:ty,)+
220 }
221 }
222 ) => {
223 $crate::cmd! {
224 $(#[$attrs])*
225 $name($group, $cmd) {
226 Params = ();
227 Return = $ret;
228 }
229 }
230
231 $crate::param! {
232 #[doc = "Return parameters for"]
233 $(#[$attrs])*
234 struct $ret {
235 $($ret_name: $ret_ty,)*
236 }
237 }
238 };
239 (
240 $(#[$attrs:meta])*
241 $name:ident($group:ident, $cmd:expr) {
242 Params$(<$life:lifetime>)? = $param:ty;
243 $ret:ident {
244 $($ret_name:ident: $ret_ty:ty,)+
245 }
246 $(Handle = $handle_name:ident: $handle:ty;)?
247 }
248 ) => {
249 $crate::cmd! {
250 $(#[$attrs])*
251 $name($group, $cmd) {
252 Params$(<$life>)? = $param;
253 Return = $ret;
254 $(Handle = $handle;)?
255 }
256 }
257
258 $crate::param! {
259 #[doc = "Return parameters for"]
260 $(#[$attrs])*
261 struct $ret {
262 $($handle_name: $handle,)?
263 $($ret_name: $ret_ty,)*
264 }
265 }
266 };
267 (
268 $(#[$attrs:meta])*
269 $name:ident($group:ident, $cmd:expr) {
270 $params:ident$(<$life:lifetime>)? {
271 $($param_name:ident: $param_ty:ty,)+
272 }
273 $(
274 Return = $ret:ty;
275 $(Handle = $handle_name:ident: $handle:ty;)?
276 )?
277 }
278 ) => {
279 $crate::cmd! {
280 BASE
281 $(#[$attrs])*
282 $name($group, $cmd) {
283 Params$(<$life>)? = $params$(<$life>)?;
284 $(
285 Return = $ret;
286 $(Handle = $handle;)?
287 )?
288 }
289 }
290
291 impl$(<$life>)? $name$(<$life>)? {
292 #[allow(clippy::too_many_arguments)]
293 pub fn new($($($handle_name: $handle,)?)? $($param_name: $param_ty),+) -> Self {
295 Self($params {
296 $($($handle_name,)?)?
297 $($param_name,)*
298 })
299 }
300
301 $(
302 $(
303 fn handle(&self) -> $handle {
304 self.0.$handle_name
305 }
306 )?
307 )?
308 }
309
310 $crate::param! {
311 #[doc = "Parameters for"]
312 $(#[$attrs])*
313 struct $params$(<$life>)? {
314 $($($handle_name: $handle,)?)?
315 $($param_name: $param_ty,)*
316 }
317 }
318 };
319 (
320 $(#[$attrs:meta])*
321 $name:ident($group:ident, $cmd:expr) {
322 Params = ();
323 $(Return = $ret:ty;)?
324 }
325 ) => {
326 $crate::cmd! {
327 BASE
328 $(#[$attrs])*
329 $name($group, $cmd) {
330 Params = ();
331 $(Return = $ret;)?
332 }
333 }
334
335 impl $name {
336 pub fn new() -> Self {
338 Self(())
339 }
340 }
341
342 impl Default for $name {
343 fn default() -> Self {
344 Self(())
345 }
346 }
347 };
348 (
349 $(#[$attrs:meta])*
350 $name:ident($group:ident, $cmd:expr) {
351 Params$(<$life:lifetime>)? = $params:ty;
352 $(
353 Return = $ret:ty;
354 $(Handle = $handle:ty;)?
355 )?
356 }
357 ) => {
358 $crate::cmd! {
359 BASE
360 $(#[$attrs])*
361 $name($group, $cmd) {
362 Params$(<$life>)? = $params;
363 $(
364 Return = $ret;
365 $(Handle = $handle;)?
366 )?
367 }
368 }
369
370 impl$(<$life>)? $name$(<$life>)? {
371 pub fn new(param: $params) -> Self {
373 Self(param)
374 }
375
376 $(
377 $(
378 fn handle(&self) -> $handle {
379 self.0
380 }
381 )?
382 )?
383 }
384 };
385 (
386 BASE
387 $(#[$attrs:meta])*
388 $name:ident($group:ident, $cmd:expr) {
389 Params$(<$life:lifetime>)? = $params:ty;
390 $(
391 Return = $ret:ty;
392 $(Handle = $handle:ty;)?
393 )?
394 }
395 ) => {
396 $(#[$attrs])*
397 #[repr(transparent)]
398 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
399 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
400 pub struct $name$(<$life>)?($params);
401
402 #[automatically_derived]
403 #[allow(unused_mut, unused_variables, unused_imports)]
404 impl$(<$life>)? $crate::cmd::Cmd for $name$(<$life>)? {
405 const OPCODE: $crate::cmd::Opcode = $crate::cmd::Opcode::new($crate::cmd::OpcodeGroup::$group, $cmd);
406 type Params = $params;
407
408 fn params(&self) -> &$params {
409 &self.0
410 }
411 }
412
413 #[automatically_derived]
414 impl$(<$life>)? From<$params> for $name$(<$life>)? {
415 fn from(params: $params) -> Self {
416 Self(params)
417 }
418 }
419
420 impl$(<$life>)? $crate::WriteHci for $name$(<$life>)? {
421 #[inline(always)]
422 fn size(&self) -> usize {
423 <$params as $crate::WriteHci>::size(&self.0) + 3
424 }
425
426 fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
427 writer.write_all(&<Self as $crate::cmd::Cmd>::header(self))?;
428 <$params as $crate::WriteHci>::write_hci(&self.0, writer)
429 }
430
431 async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
432 writer.write_all(&<Self as $crate::cmd::Cmd>::header(self)).await?;
433 <$params as $crate::WriteHci>::write_hci_async(&self.0, writer).await
434 }
435 }
436
437 $crate::cmd! {
438 RETURN
439 $name$(<$life>)? {
440 $(
441 Return = $ret;
442 $(Handle = $handle;)?
443 )?
444 }
445 }
446 };
447 (
448 RETURN
449 $name:ident$(<$life:lifetime>)? {
450 Return = $ret:ty;
451 Handle = $handle:ty;
452 }
453 ) => {
454 impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
455 type Return = $ret;
456 type Handle = $handle;
457 type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
458
459 fn param_handle(&self) -> Self::Handle {
460 self.handle()
461 }
462
463 fn return_handle(data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
464 <$handle as $crate::FromHciBytes>::from_hci_bytes(data).map(|(x, _)| x)
465 }
466 }
467 };
468 (
469 RETURN
470 $name:ident$(<$life:lifetime>)? {
471 Return = $ret:ty;
472 }
473 ) => {
474 impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
475 type Return = $ret;
476 type Handle = ();
477 type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
478
479 fn param_handle(&self) {}
480
481 fn return_handle(_data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
482 Ok(())
483 }
484 }
485 };
486 (
487 RETURN
488 $name:ident$(<$life:lifetime>)? {
489 }
490 ) => {
491 impl$(<$life>)? $crate::cmd::AsyncCmd for $name$(<$life>)? {}
492 };
493}
494
495pub use cmd;