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::derive::{Read, Write};
16 use crate::reader::{Read, Reader};
17 use crate::writer::{pack, Write, Writer};
18
19 /// HCI Command, as defined in Part E - 5.4.1
20 #[derive(Debug)]
21 pub enum Command {
22 /// 7.3.2 Reset Command
23 Reset(Reset),
24 /// 7.8.97 LE Set CIG Parameters
25 LeSetCigParameters(LeSetCigParameters),
26 /// 7.8.99 LE Create CIS
27 LeCreateCis(LeCreateCis),
28 /// 7.8.100 LE Remove CIG
29 LeRemoveCig(LeRemoveCig),
30 /// 7.8.103 LE Create BIG
31 LeCreateBig(LeCreateBig),
32 /// 7.8.109 LE Setup ISO Data Path
33 LeSetupIsoDataPath(LeSetupIsoDataPath),
34 /// 7.8.110 LE Remove ISO Data Path
35 LeRemoveIsoDataPath(LeRemoveIsoDataPath),
36 /// Unknown command
37 Unknown(OpCode),
38 }
39
40 /// HCI Command Return Parameters
41 #[derive(Debug, Read, Write)]
42 pub enum ReturnParameters {
43 /// 7.3.2 Reset Command
44 Reset(ResetComplete),
45 /// 7.8.2 LE Read Buffer Size [V1]
46 LeReadBufferSizeV1(LeReadBufferSizeV1Complete),
47 /// 7.8.2 LE Read Buffer Size [V2]
48 LeReadBufferSizeV2(LeReadBufferSizeV2Complete),
49 /// 7.8.97 LE Set CIG Parameters
50 LeSetCigParameters(LeSetCigParametersComplete),
51 /// 7.8.100 LE Remove CIG
52 LeRemoveCig(LeRemoveCigComplete),
53 /// 7.8.109 LE Setup ISO Data Path
54 LeSetupIsoDataPath(LeIsoDataPathComplete),
55 /// 7.8.110 LE Remove ISO Data Path
56 LeRemoveIsoDataPath(LeIsoDataPathComplete),
57 /// Unknown command
58 Unknown(OpCode),
59 }
60
61 impl Command {
62 /// Read an HCI Command packet
from_bytes(data: &[u8]) -> Result<Self, Option<OpCode>>63 pub fn from_bytes(data: &[u8]) -> Result<Self, Option<OpCode>> {
64 fn parse_packet(data: &[u8]) -> Option<(OpCode, Reader)> {
65 let mut r = Reader::new(data);
66 let opcode = r.read()?;
67 let len = r.read_u8()? as usize;
68 Some((opcode, Reader::new(r.get(len)?)))
69 }
70
71 let Some((opcode, mut r)) = parse_packet(data) else {
72 return Err(None);
73 };
74 Self::dispatch_read(opcode, &mut r).ok_or(Some(opcode))
75 }
76
dispatch_read(opcode: OpCode, r: &mut Reader) -> Option<Command>77 fn dispatch_read(opcode: OpCode, r: &mut Reader) -> Option<Command> {
78 Some(match opcode {
79 Reset::OPCODE => Self::Reset(r.read()?),
80 LeSetCigParameters::OPCODE => Self::LeSetCigParameters(r.read()?),
81 LeCreateCis::OPCODE => Self::LeCreateCis(r.read()?),
82 LeRemoveCig::OPCODE => Self::LeRemoveCig(r.read()?),
83 LeCreateBig::OPCODE => Self::LeCreateBig(r.read()?),
84 LeSetupIsoDataPath::OPCODE => Self::LeSetupIsoDataPath(r.read()?),
85 LeRemoveIsoDataPath::OPCODE => Self::LeRemoveIsoDataPath(r.read()?),
86 opcode => Self::Unknown(opcode),
87 })
88 }
89
to_bytes<T: CommandOpCode + Write>(command: &T) -> Vec<u8>90 fn to_bytes<T: CommandOpCode + Write>(command: &T) -> Vec<u8> {
91 let mut w = Writer::new(Vec::with_capacity(3 + 255));
92 w.write(&T::OPCODE);
93 w.write_u8(0);
94 w.write(command);
95
96 let mut vec = w.into_vec();
97 vec[2] = (vec.len() - 3).try_into().unwrap();
98 vec
99 }
100 }
101
102 /// OpCode of HCI Command, as defined in Part E - 5.4.1
103 #[derive(Debug, Clone, Copy, PartialEq)]
104 pub struct OpCode(u16);
105
106 impl OpCode {
107 /// OpCode from OpCode Group Field (OGF) and OpCode Command Field (OCF).
from(ogf: u16, ocf: u16) -> Self108 pub const fn from(ogf: u16, ocf: u16) -> Self {
109 Self(pack!((ocf, 10), (ogf, 6)))
110 }
111 }
112
113 impl From<u16> for OpCode {
from(v: u16) -> Self114 fn from(v: u16) -> Self {
115 OpCode(v)
116 }
117 }
118
119 impl Read for OpCode {
read(r: &mut Reader) -> Option<Self>120 fn read(r: &mut Reader) -> Option<Self> {
121 Some(r.read_u16()?.into())
122 }
123 }
124
125 impl Write for OpCode {
write(&self, w: &mut Writer)126 fn write(&self, w: &mut Writer) {
127 w.write_u16(self.0)
128 }
129 }
130
131 /// Define command OpCode
132 pub trait CommandOpCode {
133 /// OpCode of the command
134 const OPCODE: OpCode;
135 }
136
137 /// Build command from definition
138 pub trait CommandToBytes: CommandOpCode + Write {
139 /// Output the HCI Command packet
to_bytes(&self) -> Vec<u8> where Self: Sized + CommandOpCode + Write140 fn to_bytes(&self) -> Vec<u8>
141 where
142 Self: Sized + CommandOpCode + Write;
143 }
144
145 pub use defs::*;
146
147 #[allow(missing_docs)]
148 #[rustfmt::skip]
149 mod defs {
150
151 use super::*;
152 use crate::derive::CommandToBytes;
153 use crate::status::*;
154
155 #[cfg(test)]
156 use crate::{Event, EventToBytes};
157
158
159 // 7.3.2 Reset Command
160
161 impl CommandOpCode for Reset {
162 const OPCODE: OpCode = OpCode::from(0x03, 0x003);
163 }
164
165 #[derive(Debug, Read, Write, CommandToBytes)]
166 pub struct Reset {}
167
168 #[derive(Debug, Read, Write)]
169 pub struct ResetComplete {
170 pub status: Status,
171 }
172
173 #[test]
test_reset()174 fn test_reset() {
175 let dump = [0x03, 0x0c, 0x00];
176 let Ok(Command::Reset(c)) = Command::from_bytes(&dump) else { panic!() };
177 assert_eq!(c.to_bytes(), &dump[..]);
178 }
179
180 #[test]
test_reset_complete()181 fn test_reset_complete() {
182 let dump = [0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00];
183 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
184 let ReturnParameters::Reset(ref p) = e.return_parameters else { panic!() };
185 assert_eq!(p.status, Status::Success);
186 assert_eq!(e.to_bytes(), &dump[..]);
187 }
188
189
190 // 7.8.2 LE Read Buffer Size
191
192 impl CommandOpCode for LeReadBufferSizeV1 {
193 const OPCODE: OpCode = OpCode::from(0x08, 0x002);
194 }
195
196 #[derive(Debug)]
197 pub struct LeReadBufferSizeV1;
198
199 #[derive(Debug, Read, Write)]
200 pub struct LeReadBufferSizeV1Complete {
201 pub status: Status,
202 pub le_acl_data_packet_length: u16,
203 pub total_num_le_acl_data_packets: u8,
204 }
205
206 #[test]
test_le_read_buffer_size_v1_complete()207 fn test_le_read_buffer_size_v1_complete() {
208 let dump = [0x0e, 0x07, 0x01, 0x02, 0x20, 0x00, 0xfb, 0x00, 0x0f];
209 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
210 let ReturnParameters::LeReadBufferSizeV1(ref p) = e.return_parameters else { panic!() };
211 assert_eq!(p.status, Status::Success);
212 assert_eq!(p.le_acl_data_packet_length, 251);
213 assert_eq!(p.total_num_le_acl_data_packets, 15);
214 assert_eq!(e.to_bytes(), &dump[..]);
215 }
216
217 impl CommandOpCode for LeReadBufferSizeV2 {
218 const OPCODE: OpCode = OpCode::from(0x08, 0x060);
219 }
220
221 #[derive(Debug)]
222 pub struct LeReadBufferSizeV2;
223
224 #[derive(Debug, Read, Write)]
225 pub struct LeReadBufferSizeV2Complete {
226 pub status: Status,
227 pub le_acl_data_packet_length: u16,
228 pub total_num_le_acl_data_packets: u8,
229 pub iso_data_packet_length: u16,
230 pub total_num_iso_data_packets: u8,
231 }
232
233 #[test]
test_le_read_buffer_size_v2_complete()234 fn test_le_read_buffer_size_v2_complete() {
235 let dump = [0x0e, 0x0a, 0x01, 0x60, 0x20, 0x00, 0xfb, 0x00, 0x0f, 0xfd, 0x03, 0x18];
236 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
237 let ReturnParameters::LeReadBufferSizeV2(ref p) = e.return_parameters else { panic!() };
238 assert_eq!(p.status, Status::Success);
239 assert_eq!(p.le_acl_data_packet_length, 251);
240 assert_eq!(p.total_num_le_acl_data_packets, 15);
241 assert_eq!(p.iso_data_packet_length, 1021);
242 assert_eq!(p.total_num_iso_data_packets, 24);
243 assert_eq!(e.to_bytes(), &dump[..]);
244 }
245
246
247 // 7.8.97 LE Set CIG Parameters
248
249 impl CommandOpCode for LeSetCigParameters {
250 const OPCODE: OpCode = OpCode::from(0x08, 0x062);
251 }
252
253 #[derive(Debug, Read, Write, CommandToBytes)]
254 pub struct LeSetCigParameters {
255 pub cig_id: u8,
256 #[N(3)] pub sdu_interval_c_to_p: u32,
257 #[N(3)] pub sdu_interval_p_to_c: u32,
258 pub worst_case_sca: u8,
259 pub packing: u8,
260 pub framing: u8,
261 pub max_transport_latency_c_to_p: u16,
262 pub max_transport_latency_p_to_c: u16,
263 pub cis: Vec<LeCisInCigParameters>,
264 }
265
266 #[derive(Debug, Read, Write)]
267 pub struct LeCisInCigParameters {
268 pub cis_id: u8,
269 pub max_sdu_c_to_p: u16,
270 pub max_sdu_p_to_c: u16,
271 pub phy_c_to_p: u8,
272 pub phy_p_to_c: u8,
273 pub rtn_c_to_p: u8,
274 pub rtn_p_to_c: u8,
275 }
276
277 #[test]
test_le_set_cig_parameters()278 fn test_le_set_cig_parameters() {
279 let dump = [
280 0x62, 0x20, 0x21, 0x01, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x64, 0x00, 0x05,
281 0x00, 0x02, 0x00, 0x78, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0d, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00,
282 0x02, 0x03, 0x0d, 0x00
283 ];
284 let Ok(Command::LeSetCigParameters(c)) = Command::from_bytes(&dump) else { panic!() };
285 assert_eq!(c.cig_id, 0x01);
286 assert_eq!(c.sdu_interval_c_to_p, 10_000);
287 assert_eq!(c.sdu_interval_p_to_c, 0);
288 assert_eq!(c.worst_case_sca, 1);
289 assert_eq!(c.packing, 0);
290 assert_eq!(c.framing, 0);
291 assert_eq!(c.max_transport_latency_c_to_p, 100);
292 assert_eq!(c.max_transport_latency_p_to_c, 5);
293 assert_eq!(c.cis.len(), 2);
294 assert_eq!(c.cis[0].cis_id, 0);
295 assert_eq!(c.cis[0].max_sdu_c_to_p, 120);
296 assert_eq!(c.cis[0].max_sdu_p_to_c, 0);
297 assert_eq!(c.cis[0].phy_c_to_p, 0x02);
298 assert_eq!(c.cis[0].phy_p_to_c, 0x03);
299 assert_eq!(c.cis[0].rtn_c_to_p, 13);
300 assert_eq!(c.cis[0].rtn_p_to_c, 0);
301 assert_eq!(c.cis[1].cis_id, 1);
302 assert_eq!(c.cis[1].max_sdu_c_to_p, 120);
303 assert_eq!(c.cis[1].max_sdu_p_to_c, 0);
304 assert_eq!(c.cis[1].phy_c_to_p, 0x02);
305 assert_eq!(c.cis[1].phy_p_to_c, 0x03);
306 assert_eq!(c.cis[1].rtn_c_to_p, 13);
307 assert_eq!(c.cis[1].rtn_p_to_c, 0);
308 assert_eq!(c.to_bytes(), &dump[..]);
309 }
310
311 #[derive(Debug, Read, Write)]
312 pub struct LeSetCigParametersComplete {
313 pub status: Status,
314 pub cig_id: u8,
315 pub connection_handles: Vec<u16>,
316 }
317
318 #[test]
test_le_set_cig_parameters_complete()319 fn test_le_set_cig_parameters_complete() {
320 let dump = [0x0e, 0x0a, 0x01, 0x62, 0x20, 0x00, 0x01, 0x02, 0x60, 0x00, 0x61, 0x00];
321 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
322 let ReturnParameters::LeSetCigParameters(ref p) = e.return_parameters else { panic!() };
323 assert_eq!(p.status, Status::Success);
324 assert_eq!(p.cig_id, 1);
325 assert_eq!(p.connection_handles.len(), 2);
326 assert_eq!(p.connection_handles[0], 0x60);
327 assert_eq!(p.connection_handles[1], 0x61);
328 assert_eq!(e.to_bytes(), &dump[..]);
329 }
330
331
332 // 7.8.99 LE Create CIS
333
334 impl CommandOpCode for LeCreateCis {
335 const OPCODE: OpCode = OpCode::from(0x08, 0x064);
336 }
337
338 #[derive(Debug, Read, Write, CommandToBytes)]
339 pub struct LeCreateCis {
340 pub connection_handles: Vec<CisAclConnectionHandle>,
341 }
342
343 #[derive(Debug, Read, Write)]
344 pub struct CisAclConnectionHandle {
345 pub cis: u16,
346 pub acl: u16,
347 }
348
349 #[test]
test_le_create_cis()350 fn test_le_create_cis () {
351 let dump = [0x64, 0x20, 0x09, 0x02, 0x60, 0x00, 0x40, 0x00, 0x61, 0x00, 0x41, 0x00];
352 let Ok(Command::LeCreateCis(c)) = Command::from_bytes(&dump) else { panic!() };
353 assert_eq!(c.connection_handles.len(), 2);
354 assert_eq!(c.connection_handles[0].cis, 0x60);
355 assert_eq!(c.connection_handles[0].acl, 0x40);
356 assert_eq!(c.connection_handles[1].cis, 0x61);
357 assert_eq!(c.connection_handles[1].acl, 0x41);
358 assert_eq!(c.to_bytes(), &dump[..]);
359 }
360
361
362 // 7.8.100 LE Remove CIG
363
364 impl CommandOpCode for LeRemoveCig {
365 const OPCODE: OpCode = OpCode::from(0x08, 0x065);
366 }
367
368 #[derive(Debug, Read, Write, CommandToBytes)]
369 pub struct LeRemoveCig {
370 pub cig_id: u8,
371 }
372
373 #[derive(Debug, Read, Write)]
374 pub struct LeRemoveCigComplete {
375 pub status: Status,
376 pub cig_id: u8,
377 }
378
379 #[test]
test_le_remove_cig()380 fn test_le_remove_cig() {
381 let dump = [0x65, 0x20, 0x01, 0x01];
382 let Ok(Command::LeRemoveCig(c)) = Command::from_bytes(&dump) else { panic!() };
383 assert_eq!(c.cig_id, 0x01);
384 assert_eq!(c.to_bytes(), &dump[..]);
385 }
386
387 #[test]
test_le_remove_cig_complete()388 fn test_le_remove_cig_complete() {
389 let dump = [0x0e, 0x05, 0x01, 0x65, 0x20, 0x00, 0x01];
390 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
391 let ReturnParameters::LeRemoveCig(ref p) = e.return_parameters else { panic!() };
392 assert_eq!(p.status, Status::Success);
393 assert_eq!(p.cig_id, 0x01);
394 assert_eq!(e.to_bytes(), &dump[..]);
395 }
396
397
398 // 7.8.103 LE Create BIG
399
400 impl CommandOpCode for LeCreateBig {
401 const OPCODE: OpCode = OpCode::from(0x08, 0x068);
402 }
403
404 #[derive(Debug, Read, Write, CommandToBytes)]
405 pub struct LeCreateBig {
406 pub big_handle: u8,
407 pub advertising_handle: u8,
408 pub num_bis: u8,
409 #[N(3)] pub sdu_interval: u32,
410 pub max_sdu: u16,
411 pub max_transport_latency: u16,
412 pub rtn: u8,
413 pub phy: u8,
414 pub packing: u8,
415 pub framing: u8,
416 pub encryption: u8,
417 pub broadcast_code: [u8; 16],
418 }
419
420 #[test]
test_le_create_big()421 fn test_le_create_big() {
422 let dump = [
423 0x68, 0x20, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x27, 0x00, 0x78, 0x00, 0x3c, 0x00, 0x04, 0x02, 0x00,
424 0x00, 0x01, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34, 0x31, 0x32,
425 0x33, 0x34
426 ];
427 let Ok(Command::LeCreateBig(c)) = Command::from_bytes(&dump) else { panic!() };
428 assert_eq!(c.big_handle, 0x00);
429 assert_eq!(c.advertising_handle, 0x00);
430 assert_eq!(c.num_bis, 2);
431 assert_eq!(c.sdu_interval, 10_000);
432 assert_eq!(c.max_sdu, 120);
433 assert_eq!(c.max_transport_latency, 60);
434 assert_eq!(c.rtn, 4);
435 assert_eq!(c.phy, 0x02);
436 assert_eq!(c.packing, 0x00);
437 assert_eq!(c.framing, 0x00);
438 assert_eq!(c.encryption, 1);
439 assert_eq!(c.broadcast_code, [
440 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
441 0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34
442 ]);
443 assert_eq!(c.to_bytes(), &dump[..]);
444 }
445
446
447 // 7.8.109 LE Setup ISO Data Path
448
449 impl CommandOpCode for LeSetupIsoDataPath {
450 const OPCODE: OpCode = OpCode::from(0x08, 0x06e);
451 }
452
453 #[derive(Clone, Debug, Read, Write, CommandToBytes)]
454 pub struct LeSetupIsoDataPath {
455 pub connection_handle: u16,
456 pub data_path_direction: LeDataPathDirection,
457 pub data_path_id: u8,
458 pub codec_id: LeCodecId,
459 #[N(3)] pub controller_delay: u32,
460 pub codec_configuration: Vec<u8>,
461 }
462
463 #[derive(Clone, Debug, PartialEq, Read, Write)]
464 pub enum LeDataPathDirection {
465 Input = 0x00,
466 Output = 0x01,
467 }
468
469 #[derive(Clone, Debug, Read, Write)]
470 pub struct LeCodecId {
471 pub coding_format: CodingFormat,
472 pub company_id: u16,
473 pub vendor_id: u16,
474 }
475
476 #[derive(Clone, Debug, PartialEq, Read, Write)]
477 pub enum CodingFormat {
478 ULawLog = 0x00,
479 ALawLog = 0x01,
480 Cvsd = 0x02,
481 Transparent = 0x03,
482 LinearPcm = 0x04,
483 MSbc = 0x05,
484 Lc3 = 0x06,
485 G729A = 0x07,
486 VendorSpecific = 0xff,
487 }
488
489 #[derive(Debug, Read, Write)]
490 pub struct LeIsoDataPathComplete {
491 pub status: Status,
492 pub connection_handle: u16,
493 }
494
495 #[test]
test_le_setup_iso_data_path()496 fn test_le_setup_iso_data_path() {
497 let dump = [
498 0x6e, 0x20, 0x0d, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
499 ];
500 let Ok(Command::LeSetupIsoDataPath(c)) = Command::from_bytes(&dump) else { panic!() };
501 assert_eq!(c.connection_handle, 0x60);
502 assert_eq!(c.data_path_direction, LeDataPathDirection::Input);
503 assert_eq!(c.data_path_id, 0x00);
504 assert_eq!(c.codec_id.coding_format, CodingFormat::Transparent);
505 assert_eq!(c.codec_id.company_id, 0);
506 assert_eq!(c.codec_id.vendor_id, 0);
507 assert_eq!(c.controller_delay, 0);
508 assert_eq!(c.codec_configuration.len(), 0);
509 assert_eq!(c.to_bytes(), &dump[..]);
510 }
511
512 #[test]
test_le_setup_iso_data_path_complete()513 fn test_le_setup_iso_data_path_complete() {
514 let dump = [0x0e, 0x06, 0x01, 0x6e, 0x20, 0x00, 0x60, 0x00];
515 let Ok(Event::CommandComplete(e)) = Event::from_bytes(&dump) else { panic!() };
516 let ReturnParameters::LeSetupIsoDataPath(ref p) = e.return_parameters else { panic!() };
517 assert_eq!(p.status, Status::Success);
518 assert_eq!(p.connection_handle, 0x60);
519 assert_eq!(e.to_bytes(), &dump[..]);
520 }
521
522
523 // 7.8.110 LE Remove ISO Data Path
524
525 impl CommandOpCode for LeRemoveIsoDataPath {
526 const OPCODE: OpCode = OpCode::from(0x08, 0x06f);
527 }
528
529 #[derive(Debug, Read, Write, CommandToBytes)]
530 pub struct LeRemoveIsoDataPath {
531 pub connection_handle: u16,
532 pub data_path_direction: u8,
533 }
534
535 #[test]
test_le_remove_iso_data_path()536 fn test_le_remove_iso_data_path() {
537 let dump = [0x6f, 0x20, 0x03, 0x60, 0x00, 0x01];
538 let Ok(Command::LeRemoveIsoDataPath(c)) = Command::from_bytes(&dump) else { panic!() };
539 assert_eq!(c.connection_handle, 0x60);
540 assert_eq!(c.data_path_direction, 0x01);
541 assert_eq!(c.to_bytes(), &dump[..]);
542 }
543
544 }
545