1use core::future::Future;
4
5use embedded_io::ErrorType;
6
7use crate::controller::{ControllerCmdAsync, ControllerCmdSync};
8use crate::{param, FixedSizeValue, FromHciBytes, 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 + ::bt_hci_transport::PacketToController {
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
113pub trait AsyncCmd: Cmd {
116 fn exec<C: ControllerCmdAsync<Self>>(
118 &self,
119 controller: &C,
120 ) -> impl Future<Output = Result<(), Error<<C as ErrorType>::Error>>> {
121 controller.exec(self)
122 }
123}
124
125pub trait CmdReturnBuf: Copy + AsRef<[u8]> + AsMut<[u8]> {
127 const LEN: usize;
129
130 fn new() -> Self;
132}
133
134impl<const N: usize> CmdReturnBuf for [u8; N] {
135 const LEN: usize = N;
136
137 #[inline(always)]
138 fn new() -> Self {
139 [0; N]
140 }
141}
142
143pub trait SyncCmd: Cmd {
146 type Return: for<'a> FromHciBytes<'a> + Copy;
148 type Handle: FixedSizeValue;
150 type ReturnBuf: CmdReturnBuf;
152
153 fn param_handle(&self) -> Self::Handle;
155
156 fn return_handle(_data: &[u8]) -> Result<Self::Handle, crate::FromHciBytesError>;
165
166 fn exec<C: ControllerCmdSync<Self>>(
168 &self,
169 controller: &C,
170 ) -> impl Future<Output = Result<Self::Return, Error<<C as ErrorType>::Error>>> {
171 controller.exec(self)
172 }
173}
174
175#[doc(hidden)]
176#[macro_export]
177macro_rules! cmd {
178 (
179 $(#[$attrs:meta])*
180 $name:ident($group:ident, $cmd:expr) {
181 $params:ident$(<$life:lifetime>)? {
182 $($param_name:ident: $param_ty:ty,)+
183 }
184 $ret:ident {
185 $($ret_name:ident: $ret_ty:ty,)+
186 }
187 $(Handle = $handle_name:ident: $handle:ty;)?
188 }
189 ) => {
190 $crate::cmd! {
191 $(#[$attrs])*
192 $name($group, $cmd) {
193 $params$(<$life>)? {
194 $($param_name: $param_ty,)+
195 }
196 Return = $ret;
197 $(Handle = $handle_name: $handle;)?
198 }
199 }
200
201 $crate::param! {
202 #[doc = "Return parameters for"]
203 $(#[$attrs])*
204 struct $ret {
205 $($handle_name: $handle,)?
206 $($ret_name: $ret_ty,)*
207 }
208 }
209 };
210 (
211 $(#[$attrs:meta])*
212 $name:ident($group:ident, $cmd:expr) {
213 Params = ();
214 $ret:ident {
215 $($ret_name:ident: $ret_ty:ty,)+
216 }
217 }
218 ) => {
219 $crate::cmd! {
220 $(#[$attrs])*
221 $name($group, $cmd) {
222 Params = ();
223 Return = $ret;
224 }
225 }
226
227 $crate::param! {
228 #[doc = "Return parameters for"]
229 $(#[$attrs])*
230 struct $ret {
231 $($ret_name: $ret_ty,)*
232 }
233 }
234 };
235 (
236 $(#[$attrs:meta])*
237 $name:ident($group:ident, $cmd:expr) {
238 Params$(<$life:lifetime>)? = $param:ty;
239 $ret:ident {
240 $($ret_name:ident: $ret_ty:ty,)+
241 }
242 $(Handle = $handle_name:ident: $handle:ty;)?
243 }
244 ) => {
245 $crate::cmd! {
246 $(#[$attrs])*
247 $name($group, $cmd) {
248 Params$(<$life>)? = $param;
249 Return = $ret;
250 $(Handle = $handle;)?
251 }
252 }
253
254 $crate::param! {
255 #[doc = "Return parameters for"]
256 $(#[$attrs])*
257 struct $ret {
258 $($handle_name: $handle,)?
259 $($ret_name: $ret_ty,)*
260 }
261 }
262 };
263 (
264 $(#[$attrs:meta])*
265 $name:ident($group:ident, $cmd:expr) {
266 $params:ident$(<$life:lifetime>)? {
267 $($param_name:ident: $param_ty:ty,)+
268 }
269 $(
270 Return = $ret:ty;
271 $(Handle = $handle_name:ident: $handle:ty;)?
272 )?
273 }
274 ) => {
275 $crate::cmd! {
276 BASE
277 $(#[$attrs])*
278 $name($group, $cmd) {
279 Params$(<$life>)? = $params$(<$life>)?;
280 $(
281 Return = $ret;
282 $(Handle = $handle;)?
283 )?
284 }
285 }
286
287 impl$(<$life>)? $name$(<$life>)? {
288 #[allow(clippy::too_many_arguments)]
289 pub fn new($($($handle_name: $handle,)?)? $($param_name: $param_ty),+) -> Self {
291 Self($params {
292 $($($handle_name,)?)?
293 $($param_name,)*
294 })
295 }
296
297 $(
298 $(
299 fn handle(&self) -> $handle {
300 self.0.$handle_name
301 }
302 )?
303 )?
304 }
305
306 $crate::param! {
307 #[doc = "Parameters for"]
308 $(#[$attrs])*
309 struct $params$(<$life>)? {
310 $($($handle_name: $handle,)?)?
311 $($param_name: $param_ty,)*
312 }
313 }
314 };
315 (
316 $(#[$attrs:meta])*
317 $name:ident($group:ident, $cmd:expr) {
318 Params = ();
319 $(Return = $ret:ty;)?
320 }
321 ) => {
322 $crate::cmd! {
323 BASE
324 $(#[$attrs])*
325 $name($group, $cmd) {
326 Params = ();
327 $(Return = $ret;)?
328 }
329 }
330
331 impl $name {
332 pub fn new() -> Self {
334 Self(())
335 }
336 }
337
338 impl Default for $name {
339 fn default() -> Self {
340 Self(())
341 }
342 }
343 };
344 (
345 $(#[$attrs:meta])*
346 $name:ident($group:ident, $cmd:expr) {
347 Params$(<$life:lifetime>)? = $params:ty;
348 $(
349 Return = $ret:ty;
350 $(Handle = $handle:ty;)?
351 )?
352 }
353 ) => {
354 $crate::cmd! {
355 BASE
356 $(#[$attrs])*
357 $name($group, $cmd) {
358 Params$(<$life>)? = $params;
359 $(
360 Return = $ret;
361 $(Handle = $handle;)?
362 )?
363 }
364 }
365
366 impl$(<$life>)? $name$(<$life>)? {
367 pub fn new(param: $params) -> Self {
369 Self(param)
370 }
371
372 $(
373 $(
374 fn handle(&self) -> $handle {
375 self.0
376 }
377 )?
378 )?
379 }
380 };
381 (
382 BASE
383 $(#[$attrs:meta])*
384 $name:ident($group:ident, $cmd:expr) {
385 Params$(<$life:lifetime>)? = $params:ty;
386 $(
387 Return = $ret:ty;
388 $(Handle = $handle:ty;)?
389 )?
390 }
391 ) => {
392 $(#[$attrs])*
393 #[repr(transparent)]
394 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
395 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
396 pub struct $name$(<$life>)?($params);
397
398 #[automatically_derived]
399 #[allow(unused_mut, unused_variables, unused_imports)]
400 impl$(<$life>)? $crate::cmd::Cmd for $name$(<$life>)? {
401 const OPCODE: $crate::cmd::Opcode = $crate::cmd::Opcode::new($crate::cmd::OpcodeGroup::$group, $cmd);
402 type Params = $params;
403
404 fn params(&self) -> &$params {
405 &self.0
406 }
407 }
408
409 #[automatically_derived]
410 impl$(<$life>)? From<$params> for $name$(<$life>)? {
411 fn from(params: $params) -> Self {
412 Self(params)
413 }
414 }
415
416 impl$(<$life>)? ::bt_hci_transport::PacketToController for $name$(<$life>)? {
417 const KIND: ::bt_hci_transport::PacketKind = ::bt_hci_transport::PacketKind::Cmd;
418
419 #[inline(always)]
420 fn size(&self) -> usize {
421 <Self as $crate::WriteHci>::size(self)
422 }
423
424 fn write_hci<W: embedded_io::Write>(&self, writer: W) -> Result<(), W::Error> {
425 <Self as $crate::WriteHci>::write_hci(self, writer)
426 }
427
428 async fn write_hci_async<W: embedded_io_async::Write>(&self, writer: W) -> Result<(), W::Error> {
429 <Self as $crate::WriteHci>::write_hci_async(self, writer).await
430 }
431 }
432
433 impl$(<$life>)? $crate::WriteHci for $name$(<$life>)? {
434 #[inline(always)]
435 fn size(&self) -> usize {
436 <$params as $crate::WriteHci>::size(&self.0) + 3
437 }
438
439 fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
440 writer.write_all(&<Self as $crate::cmd::Cmd>::header(self))?;
441 <$params as $crate::WriteHci>::write_hci(&self.0, writer)
442 }
443
444 async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
445 writer.write_all(&<Self as $crate::cmd::Cmd>::header(self)).await?;
446 <$params as $crate::WriteHci>::write_hci_async(&self.0, writer).await
447 }
448 }
449
450 $crate::cmd! {
451 RETURN
452 $name$(<$life>)? {
453 $(
454 Return = $ret;
455 $(Handle = $handle;)?
456 )?
457 }
458 }
459 };
460 (
461 RETURN
462 $name:ident$(<$life:lifetime>)? {
463 Return = $ret:ty;
464 Handle = $handle:ty;
465 }
466 ) => {
467 impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
468 type Return = $ret;
469 type Handle = $handle;
470 type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
471
472 fn param_handle(&self) -> Self::Handle {
473 self.handle()
474 }
475
476 fn return_handle(data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
477 <$handle as $crate::FromHciBytes>::from_hci_bytes(data).map(|(x, _)| x)
478 }
479 }
480 };
481 (
482 RETURN
483 $name:ident$(<$life:lifetime>)? {
484 Return = $ret:ty;
485 }
486 ) => {
487 impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
488 type Return = $ret;
489 type Handle = ();
490 type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
491
492 fn param_handle(&self) {}
493
494 fn return_handle(_data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
495 Ok(())
496 }
497 }
498 };
499 (
500 RETURN
501 $name:ident$(<$life:lifetime>)? {
502 }
503 ) => {
504 impl$(<$life>)? $crate::cmd::AsyncCmd for $name$(<$life>)? {}
505 };
506}
507
508pub use cmd;