ta1394_avc_general/
lib.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2022 Takashi Sakamoto
3
4#![doc = include_str!("../README.md")]
5
6pub mod config_rom;
7pub mod general;
8
9/// The type of subunit for AV/C address defined by 1394 Trading Association.
10#[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
102/// The AV/C address of first music subunit for convenience.
103pub const MUSIC_SUBUNIT_0: AvcAddrSubunit = AvcAddrSubunit {
104    subunit_type: AvcSubunitType::Music,
105    subunit_id: 0,
106};
107
108/// The AV/C address of first audio subunit for convenience.
109pub const AUDIO_SUBUNIT_0: AvcAddrSubunit = AvcAddrSubunit {
110    subunit_type: AvcSubunitType::Audio,
111    subunit_id: 0,
112};
113
114/// The data of AV/C address in subunit case.
115#[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/// For AV/C address in both unit and subunit cases.
174#[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/// The type of command in AV/C transaction.
215#[derive(Clone, Copy, Debug, Eq, PartialEq)]
216pub enum AvcCmdType {
217    /// Perform an operation to the addressed target.
218    Control,
219    /// Check current status of the addressed target.
220    Status,
221    /// Check whether the addressed target supports a particular Control command including operands.
222    SpecificInquiry,
223    /// Schedule notification of a change in the addressed target.
224    Notify,
225    /// Check whether the addressed target supports a particular Control command just with opcode.
226    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/// The status of response in AV/C transaction.
271#[derive(Debug, Eq, PartialEq)]
272pub enum AvcRespCode {
273    /// The target does not implement the requested command or the addressed subunit.
274    NotImplemented,
275    /// The requested CONTROL command has been processed or is scheduled to process.
276    Accepted,
277    /// The target refused to process the requested command due to some reasons.
278    Rejected,
279    /// The target is under transition state and can not process the requested STATUS command.
280    InTransition,
281    /// The target implements the inquired command or returns current status against the requested
282    /// STATUS command.
283    ImplementedStable,
284    /// The actual notification scheduled by the NOTIFY command.
285    Changed,
286    /// The intermediate response during AV/C deferred transaction.
287    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/// The error to build command frame for AV/C transaction.
338#[derive(Debug, Copy, Clone, Eq, PartialEq)]
339pub enum AvcCmdBuildError {
340    /// Invalid address for the operation.
341    InvalidAddress,
342    /// Fail to prepare operands for the operation.
343    InvalidOperands,
344    /// Operands too long.
345    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/// The error to build command frame for AV/C transaction.
359#[derive(Debug, Copy, Clone, Eq, PartialEq)]
360pub enum AvcRespParseError {
361    /// The length of response frame is shorter than expected.
362    TooShortResp(
363        /// The expected length at least.
364        usize,
365    ),
366    /// The status code in response frame is not expected.
367    UnexpectedStatus,
368    /// The address in response frame is not expected.
369    UnexpectedAddr,
370    /// The operation code in response frame is not expected.
371    UnexpectedOpcode,
372    /// Any of operand in response frame is not expected.
373    UnexpectedOperands(
374        /// The first offset for unexpected operand.
375        usize,
376    ),
377}
378
379impl AvcRespParseError {
380    /// Add given offset to some enumerations.
381    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
406/// For AV/C operation with opcode.
407pub trait AvcOp {
408    /// The code to specify operation.
409    const OPCODE: u8;
410}
411
412/// The AV/C operation supporting control and inquiry command.
413pub 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
418/// The AV/C operation supporting status command.
419pub 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
424/// The AV/C operation supporting notify command.
425pub 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/// For error reporting of AV/C transaction.
431#[derive(Debug, Copy, Clone, Eq, PartialEq)]
432pub enum Ta1394AvcError<T: std::fmt::Display + Clone> {
433    /// Fail to build command frame.
434    CmdBuild(AvcCmdBuildError),
435    /// Fail to initiate and finish AV/C transaction by Function Control Protocol.
436    CommunicationFailure(T),
437    /// Fail to parse response frame.
438    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
451/// For AV/C transaction defined by 1394 Trading Association.
452pub trait Ta1394Avc<T: std::fmt::Display + Clone> {
453    /// The maximum size of frame in both command and response.
454    const FRAME_SIZE: usize = 0x200;
455
456    /// The mask for first byte of response frame to detect status code. The rest bits express
457    /// Command/transaction set (CTS) but appears not to be used actually.
458    const RESP_CODE_MASK: u8 = 0x0f;
459
460    /// Transmit given command frame and return received response frame.
461    ///
462    /// Initiate request transaction and wait for response transaction by Function Control
463    /// Protocol (FCP) in IEC 61883-1. When detecting `AvcRespCode::INTERIM` in received response
464    /// frame, wait for further response transaction as final result, according to "deferred
465    /// transaction" in AV/C general specification.
466    ///
467    /// The call of method is expected to yield running processor to wait for the response.
468    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        // For audio subunit.
616        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        // For music subunit.
620        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}