Skip to main content

bt_hci/
data.rs

1//! HCI data packets [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-c8fdfc58-ec59-1a87-6e78-0a01de2e0846)
2
3use crate::param::{param, ConnHandle};
4use crate::{FromHciBytes, FromHciBytesError, HostToControllerPacket, PacketKind, ReadHci, ReadHciError, WriteHci};
5
6/// HCI ACL Data packet `Packet_Boundary_Flag` [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-49cf6aaa-b2f3-30b0-e737-5b515d3b3168)
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9#[repr(u8)]
10pub enum AclPacketBoundary {
11    /// First non-automatically-flushable packet of a higher layer message (start of a non-automatically-flushable
12    /// L2CAP PDU) from Host to Controller.
13    FirstNonFlushable = 0x00,
14    /// Continuing fragment of a higher layer message
15    Continuing = 0x01,
16    /// First automatically flushable packet of a higher layer message (start of an automatically-flushable L2CAP PDU).
17    FirstFlushable = 0x02,
18    /// A complete L2CAP PDU. Automatically flushable.
19    Complete = 0x03,
20}
21
22/// HCI ACL Data packet `Broadcast_Flag` [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-49cf6aaa-b2f3-30b0-e737-5b515d3b3168)
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[repr(u8)]
26pub enum AclBroadcastFlag {
27    /// Point-to-point (ACL-U or LE-U)
28    PointToPoint = 0x00,
29    /// BR/EDR broadcast (APB-U)
30    BrEdrBroadcast = 0x01,
31    /// Reserved for future use.
32    Reserved = 0x02,
33}
34
35param! {
36    /// HCI ACL Data Packet header [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-49cf6aaa-b2f3-30b0-e737-5b515d3b3168)
37    struct AclPacketHeader {
38        handle: u16,
39        data_len: u16,
40    }
41}
42
43impl AclPacketHeader {
44    /// `Connection_Handle` to be used for transmitting a data packet or segment over a Controller.
45    pub fn handle(&self) -> ConnHandle {
46        ConnHandle::new(self.handle & 0xfff)
47    }
48
49    /// The `Packet_Boundary_Flag` of the packet
50    pub fn boundary_flag(&self) -> AclPacketBoundary {
51        match (self.handle >> 12) & 0x03 {
52            0 => AclPacketBoundary::FirstNonFlushable,
53            1 => AclPacketBoundary::Continuing,
54            2 => AclPacketBoundary::FirstFlushable,
55            3 => AclPacketBoundary::Complete,
56            _ => unreachable!(),
57        }
58    }
59
60    /// The `Broadcast_Flag` of the packet
61    pub fn broadcast_flag(&self) -> AclBroadcastFlag {
62        match (self.handle >> 14) & 0x03 {
63            0 => AclBroadcastFlag::PointToPoint,
64            1 => AclBroadcastFlag::BrEdrBroadcast,
65            2 => AclBroadcastFlag::Reserved,
66            3 => AclBroadcastFlag::Reserved,
67            _ => unreachable!(),
68        }
69    }
70
71    /// The length of the data field of the packet
72    pub fn data_len(&self) -> usize {
73        usize::from(self.data_len)
74    }
75}
76
77/// HCI ACL Data Packet [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-49cf6aaa-b2f3-30b0-e737-5b515d3b3168)
78#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub struct AclPacket<'a> {
81    handle: u16,
82    data: &'a [u8],
83}
84
85impl<'a> AclPacket<'a> {
86    /// Create a new instance.
87    pub fn new(handle: ConnHandle, pbf: AclPacketBoundary, bf: AclBroadcastFlag, data: &'a [u8]) -> Self {
88        let handle: u16 = handle.into_inner() | ((pbf as u16) << 12) | ((bf as u16) << 14);
89        Self { handle, data }
90    }
91
92    /// Create an `AclPacket` from `header` and `data`
93    pub fn from_header_hci_bytes(
94        header: AclPacketHeader,
95        data: &'a [u8],
96    ) -> Result<(Self, &'a [u8]), FromHciBytesError> {
97        let data_len = usize::from(header.data_len);
98        if data.len() < data_len {
99            Err(FromHciBytesError::InvalidSize)
100        } else {
101            let (data, rest) = data.split_at(data_len);
102            Ok((
103                Self {
104                    handle: header.handle,
105                    data: &data[..data_len],
106                },
107                rest,
108            ))
109        }
110    }
111
112    /// `Connection_Handle` to be used for transmitting a data packet or segment over a Controller.
113    pub fn handle(&self) -> ConnHandle {
114        ConnHandle::new(self.handle & 0xfff)
115    }
116
117    /// Raw handle value including the `Packet_Boundary_Flag` and `Broadcast_Flag`.
118    pub fn header(&self) -> AclPacketHeader {
119        AclPacketHeader {
120            handle: self.handle,
121            data_len: self.data.len() as u16,
122        }
123    }
124
125    /// The `Packet_Boundary_Flag` of the packet
126    pub fn boundary_flag(&self) -> AclPacketBoundary {
127        match (self.handle >> 12) & 0x03 {
128            0 => AclPacketBoundary::FirstNonFlushable,
129            1 => AclPacketBoundary::Continuing,
130            2 => AclPacketBoundary::FirstFlushable,
131            3 => AclPacketBoundary::Complete,
132            _ => unreachable!(),
133        }
134    }
135
136    /// The `Broadcast_Flag` of the packet
137    pub fn broadcast_flag(&self) -> AclBroadcastFlag {
138        match (self.handle >> 14) & 0x03 {
139            0 => AclBroadcastFlag::PointToPoint,
140            1 => AclBroadcastFlag::BrEdrBroadcast,
141            2 => AclBroadcastFlag::Reserved,
142            3 => AclBroadcastFlag::Reserved,
143            _ => unreachable!(),
144        }
145    }
146
147    /// The data of the packet
148    pub fn data(&self) -> &'a [u8] {
149        self.data
150    }
151}
152
153impl<'de> FromHciBytes<'de> for AclPacket<'de> {
154    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
155        let (header, data) = AclPacketHeader::from_hci_bytes(data)?;
156        Self::from_header_hci_bytes(header, data)
157    }
158}
159
160impl<'de> ReadHci<'de> for AclPacket<'de> {
161    const MAX_LEN: usize = 255;
162
163    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
164        let mut header = [0; 4];
165        reader.read_exact(&mut header)?;
166        let (header, _) = AclPacketHeader::from_hci_bytes(&header)?;
167        let data_len = header.data_len();
168        if buf.len() < data_len {
169            Err(ReadHciError::BufferTooSmall)
170        } else {
171            let (buf, _) = buf.split_at_mut(data_len);
172            reader.read_exact(buf)?;
173            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
174            Ok(pkt)
175        }
176    }
177
178    async fn read_hci_async<R: embedded_io_async::Read>(
179        mut reader: R,
180        buf: &'de mut [u8],
181    ) -> Result<Self, ReadHciError<R::Error>> {
182        let mut header = [0; 4];
183        reader.read_exact(&mut header).await?;
184        let (header, _) = AclPacketHeader::from_hci_bytes(&header)?;
185        let data_len = header.data_len();
186        if buf.len() < data_len {
187            Err(ReadHciError::BufferTooSmall)
188        } else {
189            let (buf, _) = buf.split_at_mut(data_len);
190            reader.read_exact(buf).await?;
191            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
192            Ok(pkt)
193        }
194    }
195}
196
197impl WriteHci for AclPacket<'_> {
198    #[inline(always)]
199    fn size(&self) -> usize {
200        4 + self.data.len()
201    }
202
203    #[inline(always)]
204    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
205        let header = AclPacketHeader {
206            handle: self.handle,
207            data_len: self.data.len() as u16,
208        };
209        header.write_hci(&mut writer)?;
210        writer.write_all(self.data)
211    }
212
213    #[inline(always)]
214    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
215        let header = AclPacketHeader {
216            handle: self.handle,
217            data_len: self.data.len() as u16,
218        };
219        header.write_hci_async(&mut writer).await?;
220        writer.write_all(self.data).await
221    }
222}
223
224impl HostToControllerPacket for AclPacket<'_> {
225    const KIND: PacketKind = PacketKind::AclData;
226}
227
228/// HCI Synchronous Data packet `Packet_Status_Flag` [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ea780739-1980-92c8-1a0a-96fcf9bec7b7)
229#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
230#[cfg_attr(feature = "defmt", derive(defmt::Format))]
231pub enum SyncPacketStatus {
232    /// Correctly received data. The payload data belongs to received eSCO or SCO packets that the Baseband marked as
233    /// โ€œgood dataโ€.
234    Correct,
235    /// Possibly invalid data. At least one eSCO packet has been marked by the Baseband as โ€œdata with possible errorsโ€
236    /// and all others have been marked as โ€œgood dataโ€ in the eSCO interval(s) corresponding to the HCI Synchronous
237    /// Data packet.
238    PossiblyInvalid,
239    /// No data received. All data from the Baseband received during the (e)SCO interval(s) corresponding to the HCI
240    /// Synchronous Data packet have been marked as "lost data" by the Baseband. The Payload data octets shall be set
241    /// to 0.
242    NoData,
243    /// Data partially lost. Not all, but at least one (e)SCO packet has been marked as โ€œlost dataโ€ by the Baseband in
244    /// the (e)SCO intervals corresponding to the HCI Synchronous Data packet. The payload data octets corresponding to
245    /// the missing (e)SCO packets shall be set to 0.
246    PartiallyLost,
247}
248
249param! {
250    /// HCI Synchronous Data packet header [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ea780739-1980-92c8-1a0a-96fcf9bec7b7)
251    struct SyncPacketHeader {
252        handle: u16,
253        data_len: u8,
254    }
255}
256
257impl SyncPacketHeader {
258    /// `Connection_Handle` to be used to for transmitting a synchronous data packet or segment.
259    pub fn handle(&self) -> ConnHandle {
260        ConnHandle::new(self.handle & 0xfff)
261    }
262
263    /// The `Packet_Status_Flag` of the packet
264    pub fn status(&self) -> SyncPacketStatus {
265        match (self.handle >> 12) & 0x03 {
266            0 => SyncPacketStatus::Correct,
267            1 => SyncPacketStatus::PossiblyInvalid,
268            2 => SyncPacketStatus::NoData,
269            3 => SyncPacketStatus::PartiallyLost,
270            _ => unreachable!(),
271        }
272    }
273
274    /// The length of the data field of the packet
275    pub fn data_len(&self) -> usize {
276        usize::from(self.data_len)
277    }
278}
279
280/// HCI Synchronous Data packet [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-ea780739-1980-92c8-1a0a-96fcf9bec7b7)
281#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
282#[cfg_attr(feature = "defmt", derive(defmt::Format))]
283pub struct SyncPacket<'a> {
284    handle: u16,
285    data: &'a [u8],
286}
287
288impl<'a> SyncPacket<'a> {
289    /// Create a `SyncPacket` from `header` and `data`
290    pub fn from_header_hci_bytes(
291        header: SyncPacketHeader,
292        data: &'a [u8],
293    ) -> Result<(Self, &'a [u8]), FromHciBytesError> {
294        let data_len = usize::from(header.data_len);
295        if data.len() < data_len {
296            Err(FromHciBytesError::InvalidSize)
297        } else {
298            let (data, rest) = data.split_at(data_len);
299            Ok((
300                Self {
301                    handle: header.handle,
302                    data: &data[..data_len],
303                },
304                rest,
305            ))
306        }
307    }
308
309    /// `Connection_Handle` to be used to for transmitting a synchronous data packet or segment.
310    pub fn handle(&self) -> ConnHandle {
311        ConnHandle::new(self.handle & 0xfff)
312    }
313
314    /// The `Packet_Status_Flag` of the packet
315    pub fn status(&self) -> SyncPacketStatus {
316        match (self.handle >> 12) & 0x03 {
317            0 => SyncPacketStatus::Correct,
318            1 => SyncPacketStatus::PossiblyInvalid,
319            2 => SyncPacketStatus::NoData,
320            3 => SyncPacketStatus::PartiallyLost,
321            _ => unreachable!(),
322        }
323    }
324
325    /// The data of the packet
326    pub fn data(&self) -> &[u8] {
327        self.data
328    }
329}
330
331impl<'de> FromHciBytes<'de> for SyncPacket<'de> {
332    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
333        let (header, data) = SyncPacketHeader::from_hci_bytes(data)?;
334        Self::from_header_hci_bytes(header, data)
335    }
336}
337
338impl<'de> ReadHci<'de> for SyncPacket<'de> {
339    const MAX_LEN: usize = 258;
340
341    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
342        let mut header = [0; 3];
343        reader.read_exact(&mut header)?;
344        let (header, _) = SyncPacketHeader::from_hci_bytes(&header)?;
345        let data_len = header.data_len();
346        if buf.len() < data_len {
347            Err(ReadHciError::BufferTooSmall)
348        } else {
349            let (buf, _) = buf.split_at_mut(data_len);
350            reader.read_exact(buf)?;
351            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
352            Ok(pkt)
353        }
354    }
355
356    async fn read_hci_async<R: embedded_io_async::Read>(
357        mut reader: R,
358        buf: &'de mut [u8],
359    ) -> Result<Self, ReadHciError<R::Error>> {
360        let mut header = [0; 3];
361        reader.read_exact(&mut header).await?;
362        let (header, _) = SyncPacketHeader::from_hci_bytes(&header)?;
363        let data_len = header.data_len();
364        if buf.len() < data_len {
365            Err(ReadHciError::BufferTooSmall)
366        } else {
367            let (buf, _) = buf.split_at_mut(data_len);
368            reader.read_exact(buf).await?;
369            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
370            Ok(pkt)
371        }
372    }
373}
374
375impl WriteHci for SyncPacket<'_> {
376    #[inline(always)]
377    fn size(&self) -> usize {
378        4 + self.data.len()
379    }
380
381    #[inline(always)]
382    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
383        let header = SyncPacketHeader {
384            handle: self.handle,
385            data_len: self.data.len() as u8,
386        };
387        header.write_hci(&mut writer)?;
388        writer.write_all(self.data)
389    }
390
391    #[inline(always)]
392    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
393        let header = SyncPacketHeader {
394            handle: self.handle,
395            data_len: self.data.len() as u8,
396        };
397        header.write_hci_async(&mut writer).await?;
398        writer.write_all(self.data).await
399    }
400}
401
402impl HostToControllerPacket for SyncPacket<'_> {
403    const KIND: PacketKind = PacketKind::SyncData;
404}
405
406/// HCI ISO Data packet `PB_Flag` [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b)
407#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
408#[cfg_attr(feature = "defmt", derive(defmt::Format))]
409pub enum IsoPacketBoundary {
410    /// The `ISO_Data_Load` field contains a header and the first fragment of a fragmented SDU.
411    FirstFragment,
412    /// The `ISO_Data_Load` field contains a continuation fragment of an SDU.
413    ContinuationFragment,
414    /// The `ISO_Data_Load` field contains a header and a complete SDU.
415    Complete,
416    /// The `ISO_Data_Load` field contains the last fragment of an SDU.
417    LastFragment,
418}
419
420/// HCI ISO Data packet `Packet_Status_Flag` [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b)
421#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
422#[cfg_attr(feature = "defmt", derive(defmt::Format))]
423pub enum IsoPacketStatus {
424    /// Valid data. The complete SDU was received correctly.
425    Correct,
426    /// Possibly invalid data. The contents of the ISO_SDU_Fragment may contain errors or part of the SDU may be
427    /// missing. This is reported as "data with possible errors".
428    PossiblyInvalid,
429    /// Part(s) of the SDU were not received correctly. This is reported as "lost data".
430    PartiallyLost,
431}
432
433param! {
434    /// HCI ISO Data packet header [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b)
435    struct IsoPacketHeader {
436        handle: u16,
437        data_load_len: u16,
438    }
439}
440
441impl IsoPacketHeader {
442    /// The identifier of the logical channel between the Host and the Controller.
443    pub fn handle(&self) -> ConnHandle {
444        ConnHandle::new(self.handle & 0xfff)
445    }
446
447    /// The `PB_Flag` of the packet
448    pub fn boundary_flag(&self) -> IsoPacketBoundary {
449        match (self.handle >> 12) & 0x03 {
450            0 => IsoPacketBoundary::FirstFragment,
451            1 => IsoPacketBoundary::ContinuationFragment,
452            2 => IsoPacketBoundary::Complete,
453            3 => IsoPacketBoundary::LastFragment,
454            _ => unreachable!(),
455        }
456    }
457
458    /// Indicates if the `ISO_Data_Load` field contains a `Time_Stamp` field.
459    pub fn has_timestamp(&self) -> bool {
460        ((self.handle >> 14) & 1) != 0
461    }
462
463    /// The length of the `ISO_Data_Load` field in octets.
464    ///
465    ///  In the Host to Controller direction, `ISO_Data_Load_Length` shall be less than or equal to the size of the
466    /// buffer supported by the Controller (which is returned using the `ISO_Data_Packet_Length` return parameter of
467    /// the LE Read Buffer Size command).
468    pub fn data_load_len(&self) -> usize {
469        usize::from(self.data_load_len)
470    }
471}
472
473/// HCI ISO Data conditional header values [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b)
474#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
475#[cfg_attr(feature = "defmt", derive(defmt::Format))]
476pub struct IsoDataLoadHeader {
477    /// A time in microseconds.
478    ///
479    /// See Bluetooth Core Specification Vol 6, Part G, ยง3
480    pub timestamp: Option<u32>,
481    /// The sequence number of the SDU.
482    ///
483    /// See Bluetooth Core Specification Vol 6, Part G, ยง1
484    pub sequence_num: u16,
485    /// The total length of the SDU (and not of any individual fragments), in octets.
486    pub iso_sdu_len: u16,
487}
488
489impl IsoDataLoadHeader {
490    /// Create an `IsoDataLoadHeader` from `data`.
491    ///
492    /// `timestamp` indicates whether the data load header includes a timestamp field.
493    pub fn from_hci_bytes(timestamp: bool, data: &[u8]) -> Result<(Self, &[u8]), FromHciBytesError> {
494        let (timestamp, data) = if timestamp {
495            u32::from_hci_bytes(data).map(|(x, y)| (Some(x), y))?
496        } else {
497            (None, data)
498        };
499
500        let (sequence_num, data) = u16::from_hci_bytes(data)?;
501        let (iso_sdu_len, data) = u16::from_hci_bytes(data)?;
502
503        Ok((
504            Self {
505                timestamp,
506                sequence_num,
507                iso_sdu_len,
508            },
509            data,
510        ))
511    }
512}
513
514impl WriteHci for IsoDataLoadHeader {
515    #[inline(always)]
516    fn size(&self) -> usize {
517        if self.timestamp.is_some() {
518            8
519        } else {
520            4
521        }
522    }
523
524    #[inline(always)]
525    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
526        if let Some(timestamp) = self.timestamp {
527            timestamp.write_hci(&mut writer)?;
528        }
529        self.sequence_num.write_hci(&mut writer)?;
530        self.iso_sdu_len.write_hci(writer)
531    }
532
533    #[inline(always)]
534    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
535        if let Some(timestamp) = self.timestamp {
536            timestamp.write_hci_async(&mut writer).await?;
537        }
538        self.sequence_num.write_hci_async(&mut writer).await?;
539        self.iso_sdu_len.write_hci_async(writer).await
540    }
541}
542
543/// HCI ISO Data packet [๐Ÿ“–](https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host-controller-interface/host-controller-interface-functional-specification.html#UUID-9b5fb085-278b-5084-ac33-bee2839abe6b)
544#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
545#[cfg_attr(feature = "defmt", derive(defmt::Format))]
546pub struct IsoPacket<'a> {
547    handle: u16,
548    data_load_header: Option<IsoDataLoadHeader>,
549    data: &'a [u8],
550}
551
552impl<'a> IsoPacket<'a> {
553    /// Create an `IsoPacket` from `header` and `data`
554    pub fn from_header_hci_bytes(
555        header: IsoPacketHeader,
556        data: &'a [u8],
557    ) -> Result<(Self, &'a [u8]), FromHciBytesError> {
558        let data_load_len = usize::from(header.data_load_len);
559        if data.len() < data_load_len {
560            Err(FromHciBytesError::InvalidSize)
561        } else {
562            let (data, rest) = data.split_at(data_load_len);
563            let (data_load_header, data) = match header.boundary_flag() {
564                IsoPacketBoundary::FirstFragment | IsoPacketBoundary::Complete => {
565                    IsoDataLoadHeader::from_hci_bytes(header.has_timestamp(), &data[..data_load_len])
566                        .map(|(x, y)| (Some(x), y))?
567                }
568                IsoPacketBoundary::ContinuationFragment | IsoPacketBoundary::LastFragment => (None, data),
569            };
570
571            Ok((
572                Self {
573                    handle: header.handle,
574                    data_load_header,
575                    data,
576                },
577                rest,
578            ))
579        }
580    }
581
582    /// The identifier of the logical channel between the Host and the Controller.
583    pub fn handle(&self) -> ConnHandle {
584        ConnHandle::new(self.handle & 0xfff)
585    }
586
587    /// The `PB_Flag` of the packet
588    pub fn boundary_flag(&self) -> IsoPacketBoundary {
589        match (self.handle >> 12) & 0x03 {
590            0 => IsoPacketBoundary::FirstFragment,
591            1 => IsoPacketBoundary::ContinuationFragment,
592            2 => IsoPacketBoundary::Complete,
593            3 => IsoPacketBoundary::LastFragment,
594            _ => unreachable!(),
595        }
596    }
597
598    /// Gets the [`IsoDataLoadHeader`] for this packet, if present.
599    pub fn data_load_header(&self) -> Option<IsoDataLoadHeader> {
600        self.data_load_header
601    }
602
603    /// Gets the size of the data section of this packet, including the [`IsoDataLoadHeader`] (if present).
604    pub fn data_load_len(&self) -> usize {
605        self.data_load_header.as_ref().map(|x| x.size()).unwrap_or_default() + self.data.len()
606    }
607
608    /// Gets the data for this packet
609    pub fn data(&self) -> &[u8] {
610        self.data
611    }
612}
613
614impl<'de> FromHciBytes<'de> for IsoPacket<'de> {
615    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
616        let (header, data) = IsoPacketHeader::from_hci_bytes(data)?;
617        Self::from_header_hci_bytes(header, data)
618    }
619}
620
621impl<'de> ReadHci<'de> for IsoPacket<'de> {
622    const MAX_LEN: usize = 255;
623
624    fn read_hci<R: embedded_io::Read>(mut reader: R, buf: &'de mut [u8]) -> Result<Self, ReadHciError<R::Error>> {
625        let mut header = [0; 4];
626        reader.read_exact(&mut header)?;
627        let (header, _) = IsoPacketHeader::from_hci_bytes(&header)?;
628        let data_load_len = header.data_load_len();
629        if buf.len() < data_load_len {
630            Err(ReadHciError::BufferTooSmall)
631        } else {
632            let (buf, _) = buf.split_at_mut(data_load_len);
633            reader.read_exact(buf)?;
634            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
635            Ok(pkt)
636        }
637    }
638
639    async fn read_hci_async<R: embedded_io_async::Read>(
640        mut reader: R,
641        buf: &'de mut [u8],
642    ) -> Result<Self, ReadHciError<R::Error>> {
643        let mut header = [0; 4];
644        reader.read_exact(&mut header).await?;
645        let (header, _) = IsoPacketHeader::from_hci_bytes(&header)?;
646        let data_load_len = header.data_load_len();
647        if buf.len() < data_load_len {
648            Err(ReadHciError::BufferTooSmall)
649        } else {
650            let (buf, _) = buf.split_at_mut(data_load_len);
651            reader.read_exact(buf).await?;
652            let (pkt, _) = Self::from_header_hci_bytes(header, buf)?;
653            Ok(pkt)
654        }
655    }
656}
657
658impl WriteHci for IsoPacket<'_> {
659    #[inline(always)]
660    fn size(&self) -> usize {
661        4 + self.data_load_len()
662    }
663
664    #[inline(always)]
665    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
666        let header = IsoPacketHeader {
667            handle: self.handle,
668            data_load_len: self.data_load_len() as u16,
669        };
670        header.write_hci(&mut writer)?;
671        if let Some(data_load_header) = &self.data_load_header {
672            data_load_header.write_hci(&mut writer)?;
673        }
674        writer.write_all(self.data)
675    }
676
677    #[inline(always)]
678    async fn write_hci_async<W: embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
679        let header = IsoPacketHeader {
680            handle: self.handle,
681            data_load_len: self.data_load_len() as u16,
682        };
683        header.write_hci_async(&mut writer).await?;
684        if let Some(data_load_header) = &self.data_load_header {
685            data_load_header.write_hci_async(&mut writer).await?;
686        }
687        writer.write_all(self.data).await
688    }
689}
690
691impl HostToControllerPacket for IsoPacket<'_> {
692    const KIND: PacketKind = PacketKind::IsoData;
693}
694
695#[cfg(test)]
696mod tests {
697    use super::AclPacketHeader;
698    use crate::param::ConnHandle;
699    use crate::FromHciBytes;
700
701    #[test]
702    fn test_decode_acl_handle() {
703        let input = &[32, 32, 0, 0];
704        let header = AclPacketHeader::from_hci_bytes_complete(input).unwrap();
705        assert_eq!(header.handle(), ConnHandle::new(32));
706
707        let input = &[0, 33, 0, 0];
708        let header = AclPacketHeader::from_hci_bytes_complete(input).unwrap();
709        assert_eq!(header.handle(), ConnHandle::new(256));
710    }
711}