1#![doc = include_str!("../README.md")]
5
6pub mod config_rom;
7pub mod general;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum AvcSubunitType {
12 Monitor,
13 Audio,
14 Printer,
15 Disc,
16 Tape,
17 Tuner,
18 Ca,
19 Camera,
20 Panel,
21 BulletinBoard,
22 CameraStorage,
23 Music,
24 VendorUnique,
25 Extended,
26 Reserved(u8),
27}
28
29impl Default for AvcSubunitType {
30 fn default() -> Self {
31 Self::Reserved(AvcAddrSubunit::SUBUNIT_TYPE_MASK)
32 }
33}
34
35impl AvcSubunitType {
36 const MONITOR: u8 = 0x00;
37 const AUDIO: u8 = 0x01;
38 const PRINTER: u8 = 0x02;
39 const DISC: u8 = 0x03;
40 const TAPE: u8 = 0x04;
41 const TUNER: u8 = 0x05;
42 const CA: u8 = 0x06;
43 const CAMERA: u8 = 0x07;
44 const PANEL: u8 = 0x09;
45 const BULLETIN_BOARD: u8 = 0x0a;
46 const CAMERA_STORAGE: u8 = 0x0b;
47 const MUSIC: u8 = 0x0c;
48 const VENDOR_UNIQUE: u8 = 0x1c;
49 const EXTENDED: u8 = 0x1e;
50}
51
52impl From<u8> for AvcSubunitType {
53 fn from(val: u8) -> Self {
54 match val {
55 AvcSubunitType::MONITOR => AvcSubunitType::Monitor,
56 AvcSubunitType::AUDIO => AvcSubunitType::Audio,
57 AvcSubunitType::PRINTER => AvcSubunitType::Printer,
58 AvcSubunitType::DISC => AvcSubunitType::Disc,
59 AvcSubunitType::TAPE => AvcSubunitType::Tape,
60 AvcSubunitType::TUNER => AvcSubunitType::Tuner,
61 AvcSubunitType::CA => AvcSubunitType::Ca,
62 AvcSubunitType::CAMERA => AvcSubunitType::Camera,
63 AvcSubunitType::PANEL => AvcSubunitType::Panel,
64 AvcSubunitType::BULLETIN_BOARD => AvcSubunitType::BulletinBoard,
65 AvcSubunitType::CAMERA_STORAGE => AvcSubunitType::CameraStorage,
66 AvcSubunitType::MUSIC => AvcSubunitType::Music,
67 AvcSubunitType::VENDOR_UNIQUE => AvcSubunitType::VendorUnique,
68 AvcSubunitType::EXTENDED => AvcSubunitType::Extended,
69 _ => AvcSubunitType::Reserved(val),
70 }
71 }
72}
73
74impl From<&AvcSubunitType> for u8 {
75 fn from(subunit_type: &AvcSubunitType) -> Self {
76 match subunit_type {
77 AvcSubunitType::Monitor => AvcSubunitType::MONITOR,
78 AvcSubunitType::Audio => AvcSubunitType::AUDIO,
79 AvcSubunitType::Printer => AvcSubunitType::PRINTER,
80 AvcSubunitType::Disc => AvcSubunitType::DISC,
81 AvcSubunitType::Tape => AvcSubunitType::TAPE,
82 AvcSubunitType::Tuner => AvcSubunitType::TUNER,
83 AvcSubunitType::Ca => AvcSubunitType::CA,
84 AvcSubunitType::Camera => AvcSubunitType::CAMERA,
85 AvcSubunitType::Panel => AvcSubunitType::PANEL,
86 AvcSubunitType::BulletinBoard => AvcSubunitType::BULLETIN_BOARD,
87 AvcSubunitType::CameraStorage => AvcSubunitType::CAMERA_STORAGE,
88 AvcSubunitType::Music => AvcSubunitType::MUSIC,
89 AvcSubunitType::VendorUnique => AvcSubunitType::VENDOR_UNIQUE,
90 AvcSubunitType::Extended => AvcSubunitType::EXTENDED,
91 AvcSubunitType::Reserved(value) => *value,
92 }
93 }
94}
95
96impl From<AvcSubunitType> for u8 {
97 fn from(subunit_type: AvcSubunitType) -> Self {
98 Self::from(&subunit_type)
99 }
100}
101
102pub const MUSIC_SUBUNIT_0: AvcAddrSubunit = AvcAddrSubunit {
104 subunit_type: AvcSubunitType::Music,
105 subunit_id: 0,
106};
107
108pub const AUDIO_SUBUNIT_0: AvcAddrSubunit = AvcAddrSubunit {
110 subunit_type: AvcSubunitType::Audio,
111 subunit_id: 0,
112};
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
116pub struct AvcAddrSubunit {
117 pub subunit_type: AvcSubunitType,
118 pub subunit_id: u8,
119}
120
121impl Default for AvcAddrSubunit {
122 fn default() -> Self {
123 Self {
124 subunit_type: Default::default(),
125 subunit_id: Self::SUBUNIT_ID_MASK,
126 }
127 }
128}
129
130impl AvcAddrSubunit {
131 const SUBUNIT_TYPE_SHIFT: usize = 3;
132 const SUBUNIT_TYPE_MASK: u8 = 0x1f;
133 const SUBUNIT_ID_SHIFT: usize = 0;
134 const SUBUNIT_ID_MASK: u8 = 0x07;
135
136 pub fn new(subunit_type: AvcSubunitType, mut subunit_id: u8) -> Self {
137 subunit_id &= Self::SUBUNIT_ID_MASK;
138 AvcAddrSubunit {
139 subunit_type,
140 subunit_id,
141 }
142 }
143}
144
145impl From<u8> for AvcAddrSubunit {
146 fn from(val: u8) -> Self {
147 let subunit_type =
148 AvcSubunitType::from((val >> Self::SUBUNIT_TYPE_SHIFT) & Self::SUBUNIT_TYPE_MASK);
149 let subunit_id = (val >> Self::SUBUNIT_ID_SHIFT) & Self::SUBUNIT_ID_MASK;
150 AvcAddrSubunit {
151 subunit_type,
152 subunit_id,
153 }
154 }
155}
156
157impl From<&AvcAddrSubunit> for u8 {
158 fn from(subunit: &AvcAddrSubunit) -> Self {
159 let mut val = u8::from(subunit.subunit_type);
160 val = (val & AvcAddrSubunit::SUBUNIT_TYPE_MASK) << AvcAddrSubunit::SUBUNIT_TYPE_SHIFT;
161 val |= (subunit.subunit_id & AvcAddrSubunit::SUBUNIT_ID_MASK)
162 << AvcAddrSubunit::SUBUNIT_ID_SHIFT;
163 val
164 }
165}
166
167impl From<AvcAddrSubunit> for u8 {
168 fn from(subunit: AvcAddrSubunit) -> Self {
169 Self::from(&subunit)
170 }
171}
172
173#[derive(Clone, Copy, Debug, Eq, PartialEq)]
175pub enum AvcAddr {
176 Unit,
177 Subunit(AvcAddrSubunit),
178}
179
180impl Default for AvcAddr {
181 fn default() -> Self {
182 Self::Unit
183 }
184}
185
186impl AvcAddr {
187 pub const UNIT_ADDR: u8 = 0xff;
188}
189
190impl From<u8> for AvcAddr {
191 fn from(val: u8) -> Self {
192 match val {
193 Self::UNIT_ADDR => AvcAddr::Unit,
194 _ => AvcAddr::Subunit(AvcAddrSubunit::from(val)),
195 }
196 }
197}
198
199impl From<&AvcAddr> for u8 {
200 fn from(addr: &AvcAddr) -> Self {
201 match addr {
202 AvcAddr::Unit => AvcAddr::UNIT_ADDR,
203 AvcAddr::Subunit(d) => u8::from(*d),
204 }
205 }
206}
207
208impl From<AvcAddr> for u8 {
209 fn from(addr: AvcAddr) -> Self {
210 Self::from(&addr)
211 }
212}
213
214#[derive(Clone, Copy, Debug, Eq, PartialEq)]
216pub enum AvcCmdType {
217 Control,
219 Status,
221 SpecificInquiry,
223 Notify,
225 GeneralInquiry,
227 Reserved(u8),
228}
229
230impl AvcCmdType {
231 const CONTROL: u8 = 0x00;
232 const STATUS: u8 = 0x01;
233 const SPECIFIC_INQUIRY: u8 = 0x02;
234 const NOTIFY: u8 = 0x03;
235 const GENERAL_INQUIRY: u8 = 0x04;
236}
237
238impl Default for AvcCmdType {
239 fn default() -> Self {
240 Self::Reserved(0xff)
241 }
242}
243
244impl From<u8> for AvcCmdType {
245 fn from(val: u8) -> Self {
246 match val {
247 AvcCmdType::CONTROL => AvcCmdType::Control,
248 AvcCmdType::STATUS => AvcCmdType::Status,
249 AvcCmdType::SPECIFIC_INQUIRY => AvcCmdType::SpecificInquiry,
250 AvcCmdType::NOTIFY => AvcCmdType::Notify,
251 AvcCmdType::GENERAL_INQUIRY => AvcCmdType::GeneralInquiry,
252 _ => Self::Reserved(val),
253 }
254 }
255}
256
257impl From<AvcCmdType> for u8 {
258 fn from(code: AvcCmdType) -> Self {
259 match code {
260 AvcCmdType::Control => AvcCmdType::CONTROL,
261 AvcCmdType::Status => AvcCmdType::STATUS,
262 AvcCmdType::SpecificInquiry => AvcCmdType::SPECIFIC_INQUIRY,
263 AvcCmdType::Notify => AvcCmdType::NOTIFY,
264 AvcCmdType::GeneralInquiry => AvcCmdType::GENERAL_INQUIRY,
265 AvcCmdType::Reserved(val) => val,
266 }
267 }
268}
269
270#[derive(Debug, Eq, PartialEq)]
272pub enum AvcRespCode {
273 NotImplemented,
275 Accepted,
277 Rejected,
279 InTransition,
281 ImplementedStable,
284 Changed,
286 Interim,
288 Reserved(u8),
289}
290
291impl AvcRespCode {
292 const NOT_IMPLEMENTED: u8 = 0x08;
293 const ACCEPTED: u8 = 0x09;
294 const REJECTED: u8 = 0x0a;
295 const IN_TRANSITION: u8 = 0x0b;
296 const IMPLEMENTED_STABLE: u8 = 0x0c;
297 const CHANGED: u8 = 0x0d;
298 const INTERIM: u8 = 0x0f;
299}
300
301impl Default for AvcRespCode {
302 fn default() -> Self {
303 Self::Reserved(0xff)
304 }
305}
306
307impl From<u8> for AvcRespCode {
308 fn from(val: u8) -> Self {
309 match val {
310 AvcRespCode::NOT_IMPLEMENTED => AvcRespCode::NotImplemented,
311 AvcRespCode::ACCEPTED => AvcRespCode::Accepted,
312 AvcRespCode::REJECTED => AvcRespCode::Rejected,
313 AvcRespCode::IN_TRANSITION => AvcRespCode::InTransition,
314 AvcRespCode::IMPLEMENTED_STABLE => AvcRespCode::ImplementedStable,
315 AvcRespCode::CHANGED => AvcRespCode::Changed,
316 AvcRespCode::INTERIM => AvcRespCode::Interim,
317 _ => Self::Reserved(val),
318 }
319 }
320}
321
322impl From<AvcRespCode> for u8 {
323 fn from(resp: AvcRespCode) -> Self {
324 match resp {
325 AvcRespCode::NotImplemented => AvcRespCode::NOT_IMPLEMENTED,
326 AvcRespCode::Accepted => AvcRespCode::ACCEPTED,
327 AvcRespCode::Rejected => AvcRespCode::REJECTED,
328 AvcRespCode::InTransition => AvcRespCode::IN_TRANSITION,
329 AvcRespCode::ImplementedStable => AvcRespCode::IMPLEMENTED_STABLE,
330 AvcRespCode::Changed => AvcRespCode::CHANGED,
331 AvcRespCode::Interim => AvcRespCode::INTERIM,
332 AvcRespCode::Reserved(val) => val,
333 }
334 }
335}
336
337#[derive(Debug, Copy, Clone, Eq, PartialEq)]
339pub enum AvcCmdBuildError {
340 InvalidAddress,
342 InvalidOperands,
344 TooLongOperands,
346}
347
348impl std::fmt::Display for AvcCmdBuildError {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 match self {
351 Self::InvalidAddress => write!(f, "invalid address"),
352 Self::InvalidOperands => write!(f, "invalid operands"),
353 Self::TooLongOperands => write!(f, "too long operands"),
354 }
355 }
356}
357
358#[derive(Debug, Copy, Clone, Eq, PartialEq)]
360pub enum AvcRespParseError {
361 TooShortResp(
363 usize,
365 ),
366 UnexpectedStatus,
368 UnexpectedAddr,
370 UnexpectedOpcode,
372 UnexpectedOperands(
374 usize,
376 ),
377}
378
379impl AvcRespParseError {
380 pub fn add_offset(mut self, offset: usize) -> Self {
382 match &mut self {
383 AvcRespParseError::TooShortResp(pos) | AvcRespParseError::UnexpectedOperands(pos) => {
384 *pos += offset
385 }
386 _ => (),
387 }
388 self
389 }
390}
391
392impl std::fmt::Display for AvcRespParseError {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 match self {
395 Self::TooShortResp(expected) => write!(f, "response frame too short {}", expected),
396 Self::UnexpectedStatus => write!(f, "unexpected response status"),
397 Self::UnexpectedAddr => write!(f, "unexpected response address"),
398 Self::UnexpectedOpcode => write!(f, "unexpected response operation code"),
399 Self::UnexpectedOperands(offset) => {
400 write!(f, "unexpected response operands at {}", offset)
401 }
402 }
403 }
404}
405
406pub trait AvcOp {
408 const OPCODE: u8;
410}
411
412pub trait AvcControl {
414 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError>;
415 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError>;
416}
417
418pub trait AvcStatus {
420 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError>;
421 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError>;
422}
423
424pub trait AvcNotify {
426 fn build_operands(&mut self, addr: &AvcAddr) -> Result<Vec<u8>, AvcCmdBuildError>;
427 fn parse_operands(&mut self, addr: &AvcAddr, operands: &[u8]) -> Result<(), AvcRespParseError>;
428}
429
430#[derive(Debug, Copy, Clone, Eq, PartialEq)]
432pub enum Ta1394AvcError<T: std::fmt::Display + Clone> {
433 CmdBuild(AvcCmdBuildError),
435 CommunicationFailure(T),
437 RespParse(AvcRespParseError),
439}
440
441impl<T: std::fmt::Display + Clone> std::fmt::Display for Ta1394AvcError<T> {
442 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
443 match self {
444 Self::CmdBuild(cause) => write!(f, "Fail to build command frame: {}", cause),
445 Self::CommunicationFailure(cause) => write!(f, "Fail to communicate: {}", cause),
446 Self::RespParse(cause) => write!(f, "Fail to parse response frame: {}", cause),
447 }
448 }
449}
450
451pub trait Ta1394Avc<T: std::fmt::Display + Clone> {
453 const FRAME_SIZE: usize = 0x200;
455
456 const RESP_CODE_MASK: u8 = 0x0f;
459
460 fn transaction(&self, command_frame: &[u8], timeout_ms: u32) -> Result<Vec<u8>, T>;
469
470 fn compose_command_frame(
471 ctype: AvcCmdType,
472 addr: &AvcAddr,
473 opcode: u8,
474 operands: &[u8],
475 ) -> Result<Vec<u8>, Ta1394AvcError<T>> {
476 let mut frame = Vec::new();
477 frame.push(ctype.into());
478 frame.push(addr.into());
479 frame.push(opcode);
480 frame.extend_from_slice(operands);
481
482 if frame.len() > Self::FRAME_SIZE {
483 Err(Ta1394AvcError::CmdBuild(AvcCmdBuildError::TooLongOperands))?;
484 }
485
486 Ok(frame)
487 }
488
489 fn detect_response_operands<'a>(
490 frame: &'a [u8],
491 addr: &AvcAddr,
492 opcode: u8,
493 ) -> Result<(AvcRespCode, &'a [u8]), AvcRespParseError> {
494 if frame[1] != addr.into() {
495 Err(AvcRespParseError::UnexpectedAddr)
496 } else if frame[2] != opcode {
497 Err(AvcRespParseError::UnexpectedOpcode)
498 } else {
499 let rcode = AvcRespCode::from(frame[0] & Self::RESP_CODE_MASK);
500 let operands = &frame[3..];
501 Ok((rcode, operands))
502 }
503 }
504
505 fn control<O: AvcOp + AvcControl>(
506 &self,
507 addr: &AvcAddr,
508 op: &mut O,
509 timeout_ms: u32,
510 ) -> Result<(), Ta1394AvcError<T>> {
511 let operands =
512 AvcControl::build_operands(op, addr).map_err(|err| Ta1394AvcError::CmdBuild(err))?;
513 let command_frame =
514 Self::compose_command_frame(AvcCmdType::Control, addr, O::OPCODE, &operands)?;
515 let response_frame = self
516 .transaction(&command_frame, timeout_ms)
517 .map_err(|cause| Ta1394AvcError::CommunicationFailure(cause))?;
518 Self::detect_response_operands(&response_frame, addr, O::OPCODE)
519 .and_then(|(rcode, operands)| match rcode {
520 AvcRespCode::Accepted => AvcControl::parse_operands(op, addr, &operands),
521 _ => Err(AvcRespParseError::UnexpectedStatus),
522 })
523 .map_err(|err| Ta1394AvcError::RespParse(err))
524 }
525
526 fn status<O: AvcOp + AvcStatus>(
527 &self,
528 addr: &AvcAddr,
529 op: &mut O,
530 timeout_ms: u32,
531 ) -> Result<(), Ta1394AvcError<T>> {
532 let operands =
533 AvcStatus::build_operands(op, addr).map_err(|err| Ta1394AvcError::CmdBuild(err))?;
534 let command_frame =
535 Self::compose_command_frame(AvcCmdType::Status, addr, O::OPCODE, &operands)?;
536 let response_frame = self
537 .transaction(&command_frame, timeout_ms)
538 .map_err(|cause| Ta1394AvcError::CommunicationFailure(cause))?;
539 Self::detect_response_operands(&response_frame, addr, O::OPCODE)
540 .and_then(|(rcode, operands)| match rcode {
541 AvcRespCode::ImplementedStable => AvcStatus::parse_operands(op, addr, &operands),
542 _ => Err(AvcRespParseError::UnexpectedStatus),
543 })
544 .map_err(|err| Ta1394AvcError::RespParse(err))
545 }
546
547 fn specific_inquiry<O: AvcOp + AvcControl>(
548 &self,
549 addr: &AvcAddr,
550 op: &mut O,
551 timeout_ms: u32,
552 ) -> Result<(), Ta1394AvcError<T>> {
553 let operands =
554 AvcControl::build_operands(op, addr).map_err(|err| Ta1394AvcError::CmdBuild(err))?;
555 let command_frame =
556 Self::compose_command_frame(AvcCmdType::SpecificInquiry, addr, O::OPCODE, &operands)?;
557 let response_frame = self
558 .transaction(&command_frame, timeout_ms)
559 .map_err(|cause| Ta1394AvcError::CommunicationFailure(cause))?;
560 Self::detect_response_operands(&response_frame, addr, O::OPCODE)
561 .and_then(|(rcode, operands)| match rcode {
562 AvcRespCode::ImplementedStable => AvcControl::parse_operands(op, addr, &operands),
563 _ => Err(AvcRespParseError::UnexpectedStatus),
564 })
565 .map_err(|err| Ta1394AvcError::RespParse(err))
566 }
567
568 fn notify<O: AvcOp + AvcNotify>(
569 &self,
570 addr: &AvcAddr,
571 op: &mut O,
572 timeout_ms: u32,
573 ) -> Result<(), Ta1394AvcError<T>> {
574 let operands =
575 AvcNotify::build_operands(op, addr).map_err(|err| Ta1394AvcError::CmdBuild(err))?;
576 let command_frame =
577 Self::compose_command_frame(AvcCmdType::Notify, addr, O::OPCODE, &operands)?;
578 let response_frame = self
579 .transaction(&command_frame, timeout_ms)
580 .map_err(|cause| Ta1394AvcError::CommunicationFailure(cause))?;
581 Self::detect_response_operands(&response_frame, addr, O::OPCODE)
582 .and_then(|(rcode, operands)| match rcode {
583 AvcRespCode::Changed => AvcNotify::parse_operands(op, addr, &operands),
584 _ => Err(AvcRespParseError::UnexpectedStatus),
585 })
586 .map_err(|err| Ta1394AvcError::RespParse(err))
587 }
588}
589
590#[cfg(test)]
591mod test {
592 use crate::*;
593
594 #[test]
595 fn avcsubunittype_from() {
596 assert_eq!(0x00, u8::from(AvcSubunitType::from(0x00)));
597 assert_eq!(0x01, u8::from(AvcSubunitType::from(0x01)));
598 assert_eq!(0x02, u8::from(AvcSubunitType::from(0x02)));
599 assert_eq!(0x03, u8::from(AvcSubunitType::from(0x03)));
600 assert_eq!(0x04, u8::from(AvcSubunitType::from(0x04)));
601 assert_eq!(0x05, u8::from(AvcSubunitType::from(0x05)));
602 assert_eq!(0x06, u8::from(AvcSubunitType::from(0x06)));
603 assert_eq!(0x07, u8::from(AvcSubunitType::from(0x07)));
604 assert_eq!(0x09, u8::from(AvcSubunitType::from(0x09)));
605 assert_eq!(0x0a, u8::from(AvcSubunitType::from(0x0a)));
606 assert_eq!(0x0b, u8::from(AvcSubunitType::from(0x0b)));
607 assert_eq!(0x0c, u8::from(AvcSubunitType::from(0x0c)));
608 assert_eq!(0x1c, u8::from(AvcSubunitType::from(0x1c)));
609 assert_eq!(0x1e, u8::from(AvcSubunitType::from(0x1e)));
610 assert_eq!(0xff, u8::from(AvcSubunitType::from(0xff)));
611 }
612
613 #[test]
614 fn avcaddrsubunit_from() {
615 assert_eq!(0x80, u8::from(AvcAddrSubunit::from(0x80)));
617 assert_eq!(0x81, u8::from(AvcAddrSubunit::from(0x81)));
618 assert_eq!(0x82, u8::from(AvcAddrSubunit::from(0x82)));
619 assert_eq!(0x60, u8::from(AvcAddrSubunit::from(0x60)));
621 assert_eq!(0x61, u8::from(AvcAddrSubunit::from(0x61)));
622 assert_eq!(0x62, u8::from(AvcAddrSubunit::from(0x62)));
623 }
624
625 #[test]
626 fn avcaddr_from() {
627 assert_eq!(AvcAddr::from(0xff), AvcAddr::Unit);
628 assert_eq!(
629 AvcAddr::from(0x09),
630 AvcAddr::Subunit(AvcAddrSubunit::new(AvcSubunitType::Audio, 0x01))
631 );
632 assert_eq!(
633 AvcAddr::from(0x63),
634 AvcAddr::Subunit(AvcAddrSubunit::new(AvcSubunitType::Music, 0x03))
635 );
636 assert_eq!(
637 AvcAddr::from(0x87),
638 AvcAddr::Subunit(AvcAddrSubunit::new(AvcSubunitType::Reserved(0x10), 0x07))
639 );
640 }
641
642 #[test]
643 fn avccmdtype_from() {
644 assert_eq!(0x00, u8::from(AvcCmdType::from(0x00)));
645 assert_eq!(0x01, u8::from(AvcCmdType::from(0x01)));
646 assert_eq!(0x02, u8::from(AvcCmdType::from(0x02)));
647 assert_eq!(0x03, u8::from(AvcCmdType::from(0x03)));
648 assert_eq!(0x04, u8::from(AvcCmdType::from(0x04)));
649 }
650
651 #[test]
652 fn avcrespcode_from() {
653 assert_eq!(0x08, u8::from(AvcRespCode::from(0x08)));
654 assert_eq!(0x09, u8::from(AvcRespCode::from(0x09)));
655 assert_eq!(0x0a, u8::from(AvcRespCode::from(0x0a)));
656 assert_eq!(0x0b, u8::from(AvcRespCode::from(0x0b)));
657 assert_eq!(0x0c, u8::from(AvcRespCode::from(0x0c)));
658 assert_eq!(0x0d, u8::from(AvcRespCode::from(0x0d)));
659 assert_eq!(0x0e, u8::from(AvcRespCode::from(0x0e)));
660 assert_eq!(0x0f, u8::from(AvcRespCode::from(0x0f)));
661 assert_eq!(0xff, u8::from(AvcRespCode::from(0xff)));
662 }
663}