use crate::param::{param, ConnHandle};
use crate::{FromHciBytes, FromHciBytesError, HostToControllerPacket, PacketKind, ReadHci, ReadHciError, WriteHci};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum AclPacketBoundary {
FirstNonFlushable = 0x00,
Continuing = 0x01,
FirstFlushable = 0x02,
Complete = 0x03,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
pub enum AclBroadcastFlag {
PointToPoint = 0x00,
BrEdrBroadcast = 0x01,
Reserved = 0x02,
}
param! {
struct AclPacketHeader {
handle: u16,
data_len: u16,
}
}
impl AclPacketHeader {
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn boundary_flag(&self) -> AclPacketBoundary {
match (self.handle >> 12) & 0x03 {
0 => AclPacketBoundary::FirstNonFlushable,
1 => AclPacketBoundary::Continuing,
2 => AclPacketBoundary::FirstFlushable,
3 => AclPacketBoundary::Complete,
_ => unreachable!(),
}
}
pub fn broadcast_flag(&self) -> AclBroadcastFlag {
match (self.handle >> 14) & 0x03 {
0 => AclBroadcastFlag::PointToPoint,
1 => AclBroadcastFlag::BrEdrBroadcast,
2 => AclBroadcastFlag::Reserved,
3 => AclBroadcastFlag::Reserved,
_ => unreachable!(),
}
}
pub fn data_len(&self) -> usize {
usize::from(self.data_len)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AclPacket<'a> {
handle: u16,
data: &'a [u8],
}
impl<'a> AclPacket<'a> {
pub fn new(handle: ConnHandle, pbf: AclPacketBoundary, bf: AclBroadcastFlag, data: &'a [u8]) -> Self {
let handle: u16 = handle.into_inner() | ((pbf as u16) << 12) | ((bf as u16) << 14);
Self { handle, data }
}
pub fn from_header_hci_bytes(
header: AclPacketHeader,
data: &'a [u8],
) -> Result<(Self, &'a [u8]), FromHciBytesError> {
let data_len = usize::from(header.data_len);
if data.len() < data_len {
Err(FromHciBytesError::InvalidSize)
} else {
let (data, rest) = data.split_at(data_len);
Ok((
Self {
handle: header.handle,
data: &data[..data_len],
},
rest,
))
}
}
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn header(&self) -> AclPacketHeader {
AclPacketHeader {
handle: self.handle,
data_len: self.data.len() as u16,
}
}
pub fn boundary_flag(&self) -> AclPacketBoundary {
match (self.handle >> 12) & 0x03 {
0 => AclPacketBoundary::FirstNonFlushable,
1 => AclPacketBoundary::Continuing,
2 => AclPacketBoundary::FirstFlushable,
3 => AclPacketBoundary::Complete,
_ => unreachable!(),
}
}
pub fn broadcast_flag(&self) -> AclBroadcastFlag {
match (self.handle >> 14) & 0x03 {
0 => AclBroadcastFlag::PointToPoint,
1 => AclBroadcastFlag::BrEdrBroadcast,
2 => AclBroadcastFlag::Reserved,
3 => AclBroadcastFlag::Reserved,
_ => unreachable!(),
}
}
pub fn data(&self) -> &'a [u8] {
self.data
}
}
impl<'de> FromHciBytes<'de> for AclPacket<'de> {
fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
let (header, data) = AclPacketHeader::from_hci_bytes(data)?;
Self::from_header_hci_bytes(header, data)
}
}
impl<'de> ReadHci<'de> for AclPacket<'de> {
const MAX_LEN: usize = 255;
fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 4];
reader.read_exact(&mut header)?;
let (header, _) = AclPacketHeader::from_hci_bytes(&header)?;
let data_len = header.data_len();
if buf.len() < data_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_len);
reader.read_exact(buf)?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
async fn read_hci_async<R: embedded_io_async::Read>(
mut reader: R,
buf: &'de mut [u8],
) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 4];
reader.read_exact(&mut header).await?;
let (header, _) = AclPacketHeader::from_hci_bytes(&header)?;
let data_len = header.data_len();
if buf.len() < data_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_len);
reader.read_exact(buf).await?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
}
impl WriteHci for AclPacket<'_> {
#[inline(always)]
fn size(&self) -> usize {
4 + self.data.len()
}
#[inline(always)]
fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = AclPacketHeader {
handle: self.handle,
data_len: self.data.len() as u16,
};
header.write_hci(&mut writer)?;
writer.write_all(self.data)
}
#[inline(always)]
async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = AclPacketHeader {
handle: self.handle,
data_len: self.data.len() as u16,
};
header.write_hci_async(&mut writer).await?;
writer.write_all(self.data).await
}
}
impl HostToControllerPacket for AclPacket<'_> {
const KIND: PacketKind = PacketKind::AclData;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SyncPacketStatus {
Correct,
PossiblyInvalid,
NoData,
PartiallyLost,
}
param! {
struct SyncPacketHeader {
handle: u16,
data_len: u8,
}
}
impl SyncPacketHeader {
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn status(&self) -> SyncPacketStatus {
match (self.handle >> 12) & 0x03 {
0 => SyncPacketStatus::Correct,
1 => SyncPacketStatus::PossiblyInvalid,
2 => SyncPacketStatus::NoData,
3 => SyncPacketStatus::PartiallyLost,
_ => unreachable!(),
}
}
pub fn data_len(&self) -> usize {
usize::from(self.data_len)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct SyncPacket<'a> {
handle: u16,
data: &'a [u8],
}
impl<'a> SyncPacket<'a> {
pub fn from_header_hci_bytes(
header: SyncPacketHeader,
data: &'a [u8],
) -> Result<(Self, &'a [u8]), FromHciBytesError> {
let data_len = usize::from(header.data_len);
if data.len() < data_len {
Err(FromHciBytesError::InvalidSize)
} else {
let (data, rest) = data.split_at(data_len);
Ok((
Self {
handle: header.handle,
data: &data[..data_len],
},
rest,
))
}
}
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn status(&self) -> SyncPacketStatus {
match (self.handle >> 12) & 0x03 {
0 => SyncPacketStatus::Correct,
1 => SyncPacketStatus::PossiblyInvalid,
2 => SyncPacketStatus::NoData,
3 => SyncPacketStatus::PartiallyLost,
_ => unreachable!(),
}
}
pub fn data(&self) -> &[u8] {
self.data
}
}
impl<'de> FromHciBytes<'de> for SyncPacket<'de> {
fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
let (header, data) = SyncPacketHeader::from_hci_bytes(data)?;
Self::from_header_hci_bytes(header, data)
}
}
impl<'de> ReadHci<'de> for SyncPacket<'de> {
const MAX_LEN: usize = 258;
fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 3];
reader.read_exact(&mut header)?;
let (header, _) = SyncPacketHeader::from_hci_bytes(&header)?;
let data_len = header.data_len();
if buf.len() < data_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_len);
reader.read_exact(buf)?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
async fn read_hci_async<R: embedded_io_async::Read>(
mut reader: R,
buf: &'de mut [u8],
) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 3];
reader.read_exact(&mut header).await?;
let (header, _) = SyncPacketHeader::from_hci_bytes(&header)?;
let data_len = header.data_len();
if buf.len() < data_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_len);
reader.read_exact(buf).await?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
}
impl WriteHci for SyncPacket<'_> {
#[inline(always)]
fn size(&self) -> usize {
4 + self.data.len()
}
#[inline(always)]
fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = SyncPacketHeader {
handle: self.handle,
data_len: self.data.len() as u8,
};
header.write_hci(&mut writer)?;
writer.write_all(self.data)
}
#[inline(always)]
async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = SyncPacketHeader {
handle: self.handle,
data_len: self.data.len() as u8,
};
header.write_hci_async(&mut writer).await?;
writer.write_all(self.data).await
}
}
impl HostToControllerPacket for SyncPacket<'_> {
const KIND: PacketKind = PacketKind::SyncData;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum IsoPacketBoundary {
FirstFragment,
ContinuationFragment,
Complete,
LastFragment,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum IsoPacketStatus {
Correct,
PossiblyInvalid,
PartiallyLost,
}
param! {
struct IsoPacketHeader {
handle: u16,
data_load_len: u16,
}
}
impl IsoPacketHeader {
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn boundary_flag(&self) -> IsoPacketBoundary {
match (self.handle >> 12) & 0x03 {
0 => IsoPacketBoundary::FirstFragment,
1 => IsoPacketBoundary::ContinuationFragment,
2 => IsoPacketBoundary::Complete,
3 => IsoPacketBoundary::LastFragment,
_ => unreachable!(),
}
}
pub fn has_timestamp(&self) -> bool {
((self.handle >> 14) & 1) != 0
}
pub fn data_load_len(&self) -> usize {
usize::from(self.data_load_len)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IsoDataLoadHeader {
pub timestamp: Option<u32>,
pub sequence_num: u16,
pub iso_sdu_len: u16,
}
impl IsoDataLoadHeader {
pub fn from_hci_bytes(timestamp: bool, data: &[u8]) -> Result<(Self, &[u8]), FromHciBytesError> {
let (timestamp, data) = if timestamp {
u32::from_hci_bytes(data).map(|(x, y)| (Some(x), y))?
} else {
(None, data)
};
let (sequence_num, data) = u16::from_hci_bytes(data)?;
let (iso_sdu_len, data) = u16::from_hci_bytes(data)?;
Ok((
Self {
timestamp,
sequence_num,
iso_sdu_len,
},
data,
))
}
}
impl WriteHci for IsoDataLoadHeader {
#[inline(always)]
fn size(&self) -> usize {
if self.timestamp.is_some() {
8
} else {
4
}
}
#[inline(always)]
fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
if let Some(timestamp) = self.timestamp {
timestamp.write_hci(&mut writer)?;
}
self.sequence_num.write_hci(&mut writer)?;
self.iso_sdu_len.write_hci(writer)
}
#[inline(always)]
async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
if let Some(timestamp) = self.timestamp {
timestamp.write_hci_async(&mut writer).await?;
}
self.sequence_num.write_hci_async(&mut writer).await?;
self.iso_sdu_len.write_hci_async(writer).await
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IsoPacket<'a> {
handle: u16,
data_load_header: Option<IsoDataLoadHeader>,
data: &'a [u8],
}
impl<'a> IsoPacket<'a> {
pub fn from_header_hci_bytes(
header: IsoPacketHeader,
data: &'a [u8],
) -> Result<(Self, &'a [u8]), FromHciBytesError> {
let data_load_len = usize::from(header.data_load_len);
if data.len() < data_load_len {
Err(FromHciBytesError::InvalidSize)
} else {
let (data, rest) = data.split_at(data_load_len);
let (data_load_header, data) = match header.boundary_flag() {
IsoPacketBoundary::FirstFragment | IsoPacketBoundary::Complete => {
IsoDataLoadHeader::from_hci_bytes(header.has_timestamp(), &data[..data_load_len])
.map(|(x, y)| (Some(x), y))?
}
IsoPacketBoundary::ContinuationFragment | IsoPacketBoundary::LastFragment => (None, data),
};
Ok((
Self {
handle: header.handle,
data_load_header,
data,
},
rest,
))
}
}
pub fn handle(&self) -> ConnHandle {
ConnHandle::new(self.handle & 0xfff)
}
pub fn boundary_flag(&self) -> IsoPacketBoundary {
match (self.handle >> 12) & 0x03 {
0 => IsoPacketBoundary::FirstFragment,
1 => IsoPacketBoundary::ContinuationFragment,
2 => IsoPacketBoundary::Complete,
3 => IsoPacketBoundary::LastFragment,
_ => unreachable!(),
}
}
pub fn data_load_header(&self) -> Option<IsoDataLoadHeader> {
self.data_load_header
}
pub fn data_load_len(&self) -> usize {
self.data_load_header.as_ref().map(|x| x.size()).unwrap_or_default() + self.data.len()
}
pub fn data(&self) -> &[u8] {
self.data
}
}
impl<'de> FromHciBytes<'de> for IsoPacket<'de> {
fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
let (header, data) = IsoPacketHeader::from_hci_bytes(data)?;
Self::from_header_hci_bytes(header, data)
}
}
impl<'de> ReadHci<'de> for IsoPacket<'de> {
const MAX_LEN: usize = 255;
fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 4];
reader.read_exact(&mut header)?;
let (header, _) = IsoPacketHeader::from_hci_bytes(&header)?;
let data_load_len = header.data_load_len();
if buf.len() < data_load_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_load_len);
reader.read_exact(buf)?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
async fn read_hci_async<R: embedded_io_async::Read>(
mut reader: R,
buf: &'de mut [u8],
) -> Result<Self, ReadHciError<R::Error>> {
let mut header = [0; 4];
reader.read_exact(&mut header).await?;
let (header, _) = IsoPacketHeader::from_hci_bytes(&header)?;
let data_load_len = header.data_load_len();
if buf.len() < data_load_len {
Err(ReadHciError::BufferTooSmall)
} else {
let (buf, _) = buf.split_at_mut(data_load_len);
reader.read_exact(buf).await?;
let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
Ok(pkt)
}
}
}
impl WriteHci for IsoPacket<'_> {
#[inline(always)]
fn size(&self) -> usize {
4 + self.data_load_len()
}
#[inline(always)]
fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = IsoPacketHeader {
handle: self.handle,
data_load_len: self.data_load_len() as u16,
};
header.write_hci(&mut writer)?;
if let Some(data_load_header) = &self.data_load_header {
data_load_header.write_hci(&mut writer)?;
}
writer.write_all(self.data)
}
#[inline(always)]
async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
let header = IsoPacketHeader {
handle: self.handle,
data_load_len: self.data_load_len() as u16,
};
header.write_hci_async(&mut writer).await?;
if let Some(data_load_header) = &self.data_load_header {
data_load_header.write_hci_async(&mut writer).await?;
}
writer.write_all(self.data).await
}
}
impl HostToControllerPacket for IsoPacket<'_> {
const KIND: PacketKind = PacketKind::IsoData;
}
#[cfg(test)]
mod tests {
use super::AclPacketHeader;
use crate::param::ConnHandle;
use crate::FromHciBytes;
#[test]
fn test_decode_acl_handle() {
let input = &[32, 32, 0, 0];
let header = AclPacketHeader::from_hci_bytes_complete(input).unwrap();
assert_eq!(header.handle(), ConnHandle::new(32));
let input = &[0, 33, 0, 0];
let header = AclPacketHeader::from_hci_bytes_complete(input).unwrap();
assert_eq!(header.handle(), ConnHandle::new(256));
}
}