use structbuf::Unpacker;
use burble_crypto::LTK;
use crate::hci::*;
use crate::le::{Addr, RawAddr, TxPower};
impl Host {
pub async fn le_set_event_mask(&self, enable: &EventMask) -> Result<()> {
let r = self.exec_params(Opcode::LeSetEventMask, |cmd| {
cmd.u64(enable.le);
});
r.await?.ok()
}
pub async fn le_read_buffer_size(&self) -> Result<LeBufferSize> {
{
let r = self.exec(Opcode::LeReadBufferSizeV2).await?;
if r.status() != Status::UnknownCommand {
return r.ok();
}
}
self.exec(Opcode::LeReadBufferSize).await?.ok()
}
pub async fn le_long_term_key_request_reply(
&self,
h: ConnHandle,
k: Option<<K>,
) -> Result<()> {
let r = if let Some(k) = k {
let r = self.exec_params(Opcode::LeLongTermKeyRequestReply, |cmd| {
cmd.u16(h).u128(k);
});
r.await?
} else {
let r = self.exec_params(Opcode::LeLongTermKeyRequestNegativeReply, |cmd| {
cmd.u16(h);
});
r.await?
};
assert_eq!(r.map_ok(|_, p| ConnHandle::new(p.u16()))?, Some(h));
Ok(())
}
pub async fn le_read_phy(&self, h: ConnHandle) -> Result<(Phy, Phy)> {
let r = self.exec_params(Opcode::LeReadPhy, |cmd| {
cmd.u16(h);
});
r.await?.map_ok(|_, p| {
assert_eq!(ConnHandle::new(p.u16()), Some(h),);
(
Phy::try_from(p.u8()).expect("invalid phy"),
Phy::try_from(p.u8()).expect("invalid phy"),
)
})
}
pub async fn le_set_default_phy(&self, tx: Option<PhyMask>, rx: Option<PhyMask>) -> Result<()> {
let r = self.exec_params(Opcode::LeSetDefaultPhy, |cmd| {
cmd.u8(u8::from(tx.is_none()) | (u8::from(rx.is_none()) << 1))
.u8(tx.unwrap_or_default().bits())
.u8(rx.unwrap_or_default().bits());
});
r.await?.ok()
}
pub async fn le_set_advertising_set_random_address(
&self,
h: AdvHandle,
a: RawAddr,
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetAdvertisingSetRandomAddress, |cmd| {
cmd.u8(h).put(a);
});
r.await?.ok()
}
pub async fn le_set_extended_advertising_parameters(
&self,
h: AdvHandle,
p: AdvParams,
) -> Result<TxPower> {
let r = self.exec_params(Opcode::LeSetExtendedAdvertisingParameters, |cmd| {
cmd.u8(h)
.u16(p.props.bits())
.u24(ticks_625us(p.pri_interval.0).unwrap_or(0))
.u24(ticks_625us(p.pri_interval.1).unwrap_or(0))
.u8(p.pri_chan_map.bits())
.u8(p.addr_type)
.u8(match p.peer_addr {
Addr::Public(_) => 0x00,
Addr::Random(_) => 0x01,
})
.put(p.peer_addr.raw())
.u8(p.filter_policy)
.i8(p.tx_power.map_or(TxPower::NONE, i8::from))
.u8(p.pri_phy)
.u8(p.sec_max_skip)
.u8(p.sec_phy)
.u8(p.sid)
.bool(p.scan_request_notify);
});
r.await?.map_ok(|_, p| TxPower::new(p.i8()))
}
pub async fn le_set_extended_advertising_data(
&self,
h: AdvHandle,
op: AdvDataOp,
dont_frag: bool,
data: &[u8],
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetExtendedAdvertisingData, |cmd| {
cmd.u8(h).u8(op).bool(dont_frag);
cmd.u8(u8::try_from(data.len()).expect("data too long"));
cmd.put(data);
});
r.await?.ok()
}
pub async fn le_set_extended_scan_response_data(
&self,
h: AdvHandle,
op: AdvDataOp,
dont_frag: bool,
data: &[u8],
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetExtendedScanResponseData, |cmd| {
cmd.u8(h).u8(op).bool(dont_frag);
cmd.u8(u8::try_from(data.len()).expect("data too long"));
cmd.put(data);
});
r.await?.ok()
}
pub async fn le_set_extended_advertising_enable(
&self,
enable: bool,
cfg: &[AdvEnableParams],
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetExtendedAdvertisingEnable, |cmd| {
cmd.bool(enable);
cmd.u8(u8::try_from(cfg.len()).expect("too many parameters"));
for c in cfg {
cmd.u8(c.handle);
cmd.u16(ticks_10ms(c.duration).expect("invalid advertising duration"));
cmd.u8(c.max_events);
}
});
r.await?.ok()
}
pub async fn le_read_maximum_advertising_data_length(&self) -> Result<usize> {
let r = self.exec(Opcode::LeReadMaximumAdvertisingDataLength);
r.await?.map_ok(|_, p| usize::from(p.u16()))
}
pub async fn le_read_number_of_supported_advertising_sets(&self) -> Result<u8> {
let r = self.exec(Opcode::LeReadNumberOfSupportedAdvertisingSets);
r.await?.map_ok(|_, p| p.u8())
}
pub async fn le_remove_advertising_set(&self, h: AdvHandle) -> Result<()> {
let r = self.exec_params(Opcode::LeRemoveAdvertisingSet, |cmd| {
cmd.u8(h);
});
r.await?.ok()
}
pub async fn le_clear_advertising_sets(&self) -> Result<()> {
self.exec(Opcode::LeClearAdvertisingSets).await?.ok()
}
pub async fn le_set_periodic_advertising_parameters(
&self,
h: AdvHandle,
min: Duration,
max: Duration,
p: AdvProp,
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetPeriodicAdvertisingParameters, |cmd| {
cmd.u8(h)
.u16(ticks_1250us(min).unwrap_or(0))
.u16(ticks_1250us(max).unwrap_or(0))
.u16(p.bits());
});
r.await?.ok()
}
pub async fn le_set_periodic_advertising_data(
&self,
h: AdvHandle,
op: AdvDataOp,
data: &[u8],
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetPeriodicAdvertisingData, |cmd| {
cmd.u8(h).u8(op);
cmd.u8(u8::try_from(data.len()).expect("data too long"));
cmd.put(data);
});
r.await?.ok()
}
pub async fn le_set_periodic_advertising_enable(
&self,
enable: bool,
include_adi: bool,
h: AdvHandle,
) -> Result<()> {
let r = self.exec_params(Opcode::LeSetPeriodicAdvertisingEnable, |cmd| {
cmd.u8(u8::from(include_adi) << 1 | u8::from(enable)).u8(h);
});
r.await?.ok()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct LeBufferSize {
pub acl_data_len: u16,
pub acl_num_pkts: u8,
pub iso_data_len: u16,
pub iso_num_pkts: u8,
}
impl FromEvent for LeBufferSize {
fn unpack(e: &Event, p: &mut Unpacker) -> Self {
let v2 = e.opcode() == Opcode::LeReadBufferSizeV2;
Self {
acl_data_len: p.u16(),
acl_num_pkts: p.u8(),
iso_data_len: v2.then(|| p.u16()).unwrap_or_default(),
iso_num_pkts: v2.then(|| p.u8()).unwrap_or_default(),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct AdvParams {
pub props: AdvProp,
pub pri_interval: (Duration, Duration),
pub pri_chan_map: AdvChanMap,
pub addr_type: AdvAddrType,
pub peer_addr: Addr,
pub filter_policy: AdvFilterPolicy,
pub tx_power: Option<TxPower>,
pub pri_phy: Phy,
pub sec_max_skip: u8,
pub sec_phy: Phy,
pub sid: u8,
pub scan_request_notify: bool,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AdvEnableParams {
pub handle: AdvHandle,
pub duration: Duration,
pub max_events: u8,
}
impl From<AdvHandle> for AdvEnableParams {
#[inline]
fn from(h: AdvHandle) -> Self {
Self {
handle: h,
duration: Duration::default(),
max_events: 0,
}
}
}