use core::future::Future;
use embedded_io::ErrorType;
use crate::controller::{ControllerCmdAsync, ControllerCmdSync};
use crate::{param, FixedSizeValue, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
pub mod controller_baseband;
pub mod info;
pub mod le;
pub mod link_control;
pub mod status;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OpcodeGroup(u8);
impl OpcodeGroup {
pub const LINK_CONTROL: OpcodeGroup = OpcodeGroup(1);
pub const LINK_POLICY: OpcodeGroup = OpcodeGroup(2);
pub const CONTROL_BASEBAND: OpcodeGroup = OpcodeGroup(3);
pub const INFO_PARAMS: OpcodeGroup = OpcodeGroup(4);
pub const STATUS_PARAMS: OpcodeGroup = OpcodeGroup(5);
pub const TESTING: OpcodeGroup = OpcodeGroup(6);
pub const LE: OpcodeGroup = OpcodeGroup(8);
pub const VENDOR_SPECIFIC: OpcodeGroup = OpcodeGroup(0x3f);
pub const fn new(val: u8) -> Self {
Self(val)
}
}
param!(
struct Opcode(u16)
);
impl Opcode {
pub const UNSOLICITED: Opcode = Opcode::new(OpcodeGroup(0), 0);
pub const fn new(ogf: OpcodeGroup, ocf: u16) -> Self {
Self(((ogf.0 as u16) << 10) | ocf)
}
pub const fn group(self) -> OpcodeGroup {
OpcodeGroup((self.0 >> 10) as u8)
}
pub const fn cmd(self) -> u16 {
self.0 & 0x03ff
}
pub const fn to_raw(self) -> u16 {
self.0
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error<E> {
Hci(param::Error),
Io(E),
}
impl<E> From<param::Error> for Error<E> {
fn from(e: param::Error) -> Self {
Self::Hci(e)
}
}
pub trait Cmd: WriteHci {
const OPCODE: Opcode;
type Params: WriteHci;
fn params(&self) -> &Self::Params;
fn header(&self) -> [u8; 3] {
let opcode_bytes = Self::OPCODE.0.to_le_bytes();
[opcode_bytes[0], opcode_bytes[1], self.params().size() as u8]
}
}
impl<T: Cmd> HostToControllerPacket for T {
const KIND: PacketKind = PacketKind::Cmd;
}
pub trait AsyncCmd: Cmd {
fn exec<C: ControllerCmdAsync<Self>>(
&self,
controller: &C,
) -> impl Future<Output = Result<(), Error<<C as ErrorType>::Error>>> {
controller.exec(self)
}
}
pub trait CmdReturnBuf: Copy + AsRef<[u8]> + AsMut<[u8]> {
const LEN: usize;
fn new() -> Self;
}
impl<const N: usize> CmdReturnBuf for [u8; N] {
const LEN: usize = N;
#[inline(always)]
fn new() -> Self {
[0; N]
}
}
pub trait SyncCmd: Cmd {
type Return: for<'a> FromHciBytes<'a> + Copy;
type Handle: FixedSizeValue;
type ReturnBuf: CmdReturnBuf;
fn param_handle(&self) -> Self::Handle;
fn return_handle(_data: &[u8]) -> Result<Self::Handle, crate::FromHciBytesError>;
fn exec<C: ControllerCmdSync<Self>>(
&self,
controller: &C,
) -> impl Future<Output = Result<Self::Return, Error<<C as ErrorType>::Error>>> {
controller.exec(self)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! cmd {
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
$params:ident$(<$life:lifetime>)? {
$($param_name:ident: $param_ty:ty,)+
}
$ret:ident {
$($ret_name:ident: $ret_ty:ty,)+
}
$(Handle = $handle_name:ident: $handle:ty;)?
}
) => {
$crate::cmd! {
$(#[$attrs])*
$name($group, $cmd) {
$params$(<$life>)? {
$($param_name: $param_ty,)+
}
Return = $ret;
$(Handle = $handle_name: $handle;)?
}
}
$crate::param! {
#[doc = "Return parameters for"]
$(#[$attrs])*
struct $ret {
$($handle_name: $handle,)?
$($ret_name: $ret_ty,)*
}
}
};
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
Params = ();
$ret:ident {
$($ret_name:ident: $ret_ty:ty,)+
}
}
) => {
$crate::cmd! {
$(#[$attrs])*
$name($group, $cmd) {
Params = ();
Return = $ret;
}
}
$crate::param! {
#[doc = "Return parameters for"]
$(#[$attrs])*
struct $ret {
$($ret_name: $ret_ty,)*
}
}
};
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
Params$(<$life:lifetime>)? = $param:ty;
$ret:ident {
$($ret_name:ident: $ret_ty:ty,)+
}
$(Handle = $handle_name:ident: $handle:ty;)?
}
) => {
$crate::cmd! {
$(#[$attrs])*
$name($group, $cmd) {
Params$(<$life>)? = $param;
Return = $ret;
$(Handle = $handle;)?
}
}
$crate::param! {
#[doc = "Return parameters for"]
$(#[$attrs])*
struct $ret {
$($handle_name: $handle,)?
$($ret_name: $ret_ty,)*
}
}
};
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
$params:ident$(<$life:lifetime>)? {
$($param_name:ident: $param_ty:ty,)+
}
$(
Return = $ret:ty;
$(Handle = $handle_name:ident: $handle:ty;)?
)?
}
) => {
$crate::cmd! {
BASE
$(#[$attrs])*
$name($group, $cmd) {
Params$(<$life>)? = $params$(<$life>)?;
$(
Return = $ret;
$(Handle = $handle;)?
)?
}
}
impl$(<$life>)? $name$(<$life>)? {
#[allow(clippy::too_many_arguments)]
pub fn new($($($handle_name: $handle,)?)? $($param_name: $param_ty),+) -> Self {
Self($params {
$($($handle_name,)?)?
$($param_name,)*
})
}
$(
$(
fn handle(&self) -> $handle {
self.0.$handle_name
}
)?
)?
}
$crate::param! {
#[doc = "Parameters for"]
$(#[$attrs])*
struct $params$(<$life>)? {
$($($handle_name: $handle,)?)?
$($param_name: $param_ty,)*
}
}
};
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
Params = ();
$(Return = $ret:ty;)?
}
) => {
$crate::cmd! {
BASE
$(#[$attrs])*
$name($group, $cmd) {
Params = ();
$(Return = $ret;)?
}
}
impl $name {
pub fn new() -> Self {
Self(())
}
}
impl Default for $name {
fn default() -> Self {
Self(())
}
}
};
(
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
Params$(<$life:lifetime>)? = $params:ty;
$(
Return = $ret:ty;
$(Handle = $handle:ty;)?
)?
}
) => {
$crate::cmd! {
BASE
$(#[$attrs])*
$name($group, $cmd) {
Params$(<$life>)? = $params;
$(
Return = $ret;
$(Handle = $handle;)?
)?
}
}
impl$(<$life>)? $name$(<$life>)? {
pub fn new(param: $params) -> Self {
Self(param)
}
$(
$(
fn handle(&self) -> $handle {
self.0
}
)?
)?
}
};
(
BASE
$(#[$attrs:meta])*
$name:ident($group:ident, $cmd:expr) {
Params$(<$life:lifetime>)? = $params:ty;
$(
Return = $ret:ty;
$(Handle = $handle:ty;)?
)?
}
) => {
$(#[$attrs])*
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct $name$(<$life>)?($params);
#[automatically_derived]
#[allow(unused_mut, unused_variables, unused_imports)]
impl$(<$life>)? $crate::cmd::Cmd for $name$(<$life>)? {
const OPCODE: $crate::cmd::Opcode = $crate::cmd::Opcode::new($crate::cmd::OpcodeGroup::$group, $cmd);
type Params = $params;
fn params(&self) -> &$params {
&self.0
}
}
#[automatically_derived]
impl$(<$life>)? From<$params> for $name$(<$life>)? {
fn from(params: $params) -> Self {
Self(params)
}
}
impl$(<$life>)? $crate::WriteHci for $name$(<$life>)? {
#[inline(always)]
fn size(&self) -> usize {
<$params as $crate::WriteHci>::size(&self.0) + 3
}
fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
writer.write_all(&<Self as $crate::cmd::Cmd>::header(self))?;
<$params as $crate::WriteHci>::write_hci(&self.0, writer)
}
async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
writer.write_all(&<Self as $crate::cmd::Cmd>::header(self)).await?;
<$params as $crate::WriteHci>::write_hci_async(&self.0, writer).await
}
}
$crate::cmd! {
RETURN
$name$(<$life>)? {
$(
Return = $ret;
$(Handle = $handle;)?
)?
}
}
};
(
RETURN
$name:ident$(<$life:lifetime>)? {
Return = $ret:ty;
Handle = $handle:ty;
}
) => {
impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
type Return = $ret;
type Handle = $handle;
type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
fn param_handle(&self) -> Self::Handle {
self.handle()
}
fn return_handle(data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
<$handle as $crate::FromHciBytes>::from_hci_bytes(data).map(|(x, _)| x)
}
}
};
(
RETURN
$name:ident$(<$life:lifetime>)? {
Return = $ret:ty;
}
) => {
impl$(<$life>)? $crate::cmd::SyncCmd for $name$(<$life>)? {
type Return = $ret;
type Handle = ();
type ReturnBuf = [u8; <$ret as $crate::ReadHci>::MAX_LEN];
fn param_handle(&self) {}
fn return_handle(_data: &[u8]) -> Result<Self::Handle, $crate::FromHciBytesError> {
Ok(())
}
}
};
(
RETURN
$name:ident$(<$life:lifetime>)? {
}
) => {
impl$(<$life>)? $crate::cmd::AsyncCmd for $name$(<$life>)? {}
};
}
pub use cmd;