• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::reader::{unpack, Reader};
16 use crate::writer::{pack, Write, Writer};
17 
18 /// 5.4.5 ISO Data Packets
19 
20 /// Exchange of Isochronous Data between the Host and Controller
21 #[derive(Debug)]
22 pub struct IsoData<'a> {
23     /// Identify the connection
24     pub connection_handle: u16,
25     /// Fragmentation of the packet
26     pub sdu_fragment: IsoSduFragment,
27     /// Payload
28     pub payload: &'a [u8],
29 }
30 
31 /// Fragmentation indication of the SDU
32 #[derive(Debug)]
33 pub enum IsoSduFragment {
34     /// First SDU Fragment
35     First {
36         /// SDU Header
37         hdr: IsoSduHeader,
38         /// Last SDU fragment indication
39         is_last: bool,
40     },
41     /// Continuous fragment
42     Continue {
43         /// Last SDU fragment indication
44         is_last: bool,
45     },
46 }
47 
48 /// SDU Header information, when ISO Data in a first SDU fragment
49 #[derive(Debug, Default)]
50 pub struct IsoSduHeader {
51     /// Optional timestamp in microseconds
52     pub timestamp: Option<u32>,
53     /// Sequence number of the SDU
54     pub sequence_number: u16,
55     /// Total length of the SDU (sum of all fragments)
56     pub sdu_length: u16,
57     /// Only valid from Controller, indicate valid SDU data when 0
58     pub status: u16,
59 }
60 
61 impl<'a> IsoData<'a> {
62     /// Read an HCI ISO Data packet
from_bytes(data: &'a [u8]) -> Option<Self>63     pub fn from_bytes(data: &'a [u8]) -> Option<Self> {
64         Self::parse(&mut Reader::new(data))
65     }
66 
67     /// Output the HCI ISO Data packet
to_bytes(&self) -> Vec<u8>68     pub fn to_bytes(&self) -> Vec<u8> {
69         let mut w = Writer::new(Vec::with_capacity(12 + self.payload.len()));
70         w.write(self);
71         w.into_vec()
72     }
73 
74     /// New ISO Data packet, including a complete SDU
new(connection_handle: u16, sequence_number: u16, data: &'a [u8]) -> Self75     pub fn new(connection_handle: u16, sequence_number: u16, data: &'a [u8]) -> Self {
76         Self {
77             connection_handle,
78             sdu_fragment: IsoSduFragment::First {
79                 hdr: IsoSduHeader {
80                     sequence_number,
81                     sdu_length: data.len().try_into().unwrap(),
82                     ..Default::default()
83                 },
84                 is_last: true,
85             },
86             payload: data,
87         }
88     }
89 
parse(r: &mut Reader<'a>) -> Option<Self>90     fn parse(r: &mut Reader<'a>) -> Option<Self> {
91         let (connection_handle, pb_flag, ts_present) = unpack!(r.read_u16()?, (12, 2, 1));
92         let data_len = unpack!(r.read_u16()?, 14) as usize;
93 
94         let sdu_fragment = match pb_flag {
95             0b00 => IsoSduFragment::First {
96                 hdr: IsoSduHeader::parse(r, ts_present != 0)?,
97                 is_last: false,
98             },
99             0b10 => IsoSduFragment::First {
100                 hdr: IsoSduHeader::parse(r, ts_present != 0)?,
101                 is_last: true,
102             },
103             0b01 => IsoSduFragment::Continue { is_last: false },
104             0b11 => IsoSduFragment::Continue { is_last: true },
105             _ => unreachable!(),
106         };
107         let sdu_header_len = Self::sdu_header_len(&sdu_fragment);
108         if data_len < sdu_header_len {
109             return None;
110         }
111 
112         Some(Self { connection_handle, sdu_fragment, payload: r.get(data_len - sdu_header_len)? })
113     }
114 
sdu_header_len(sdu_fragment: &IsoSduFragment) -> usize115     fn sdu_header_len(sdu_fragment: &IsoSduFragment) -> usize {
116         match sdu_fragment {
117             IsoSduFragment::First { ref hdr, .. } => 4 * (1 + hdr.timestamp.is_some() as usize),
118             IsoSduFragment::Continue { .. } => 0,
119         }
120     }
121 }
122 
123 impl Write for IsoData<'_> {
write(&self, w: &mut Writer)124     fn write(&self, w: &mut Writer) {
125         let (pb_flag, hdr) = match self.sdu_fragment {
126             IsoSduFragment::First { ref hdr, is_last: false } => (0b00, Some(hdr)),
127             IsoSduFragment::First { ref hdr, is_last: true } => (0b10, Some(hdr)),
128             IsoSduFragment::Continue { is_last: false } => (0b01, None),
129             IsoSduFragment::Continue { is_last: true } => (0b11, None),
130         };
131 
132         let ts_present = hdr.is_some() && hdr.unwrap().timestamp.is_some();
133         w.write_u16(pack!((self.connection_handle, 12), (pb_flag, 2), ((ts_present as u16), 1)));
134 
135         let packet_len = Self::sdu_header_len(&self.sdu_fragment) + self.payload.len();
136         w.write_u16(pack!(u16::try_from(packet_len).unwrap(), 14));
137 
138         if let Some(hdr) = hdr {
139             w.write(hdr);
140         }
141         w.put(self.payload);
142     }
143 }
144 
145 impl IsoSduHeader {
parse(r: &mut Reader, ts_present: bool) -> Option<Self>146     fn parse(r: &mut Reader, ts_present: bool) -> Option<Self> {
147         let timestamp = match ts_present {
148             true => Some(r.read_u32::<4>()?),
149             false => None,
150         };
151         let sequence_number = r.read_u16()?;
152         let (sdu_length, _, status) = unpack!(r.read_u16()?, (12, 2, 2));
153         Some(Self { timestamp, sequence_number, sdu_length, status })
154     }
155 }
156 
157 impl Write for IsoSduHeader {
write(&self, w: &mut Writer)158     fn write(&self, w: &mut Writer) {
159         if let Some(timestamp) = self.timestamp {
160             w.write_u32::<4>(timestamp);
161         };
162         w.write_u16(self.sequence_number);
163         w.write_u16(pack!((self.sdu_length, 12), (0, 2), (self.status, 2)));
164     }
165 }
166 
167 #[test]
test_iso_data()168 fn test_iso_data() {
169     let dump = [
170         0x60, 0x60, 0x80, 0x00, 0x4d, 0xc8, 0xd0, 0x2f, 0x19, 0x03, 0x78, 0x00, 0x00, 0x00, 0x00,
171         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
172         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
175         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178         0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04,
179     ];
180     let Some(pkt) = IsoData::from_bytes(&dump) else { panic!() };
181     assert_eq!(pkt.connection_handle, 0x060);
182 
183     let IsoSduFragment::First { ref hdr, is_last } = pkt.sdu_fragment else { panic!() };
184     assert_eq!(hdr.timestamp, Some(802_211_917));
185     assert_eq!(hdr.sequence_number, 793);
186     assert_eq!(hdr.sdu_length, 120);
187     assert!(is_last);
188 
189     assert_eq!(
190         pkt.payload,
191         &[
192             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200             0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04
201         ]
202     );
203     assert_eq!(pkt.to_bytes(), &dump[..]);
204 }
205