1#![allow(clippy::len_without_is_empty)]
9
10#[cfg(test)]
11use linux_cec_macros::message_test;
12use linux_cec_macros::{MessageEnum, Operand};
13use num_enum::{IntoPrimitive, TryFromPrimitive};
14#[cfg(test)]
15use std::str::FromStr;
16
17use crate::operand::OperandEncodable;
18use crate::{cdc, constants, operand, AddressingType, PhysicalAddress, Result};
19#[cfg(test)]
20use crate::{Error, Range};
21
22pub use crate::cdc::{Message as CdcMessage, Opcode as CdcOpcode};
23
24#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, MessageEnum)]
25#[repr(u8)]
26#[non_exhaustive]
27pub enum Message {
28 #[addressing = "broadcast"]
29 ActiveSource {
30 address: PhysicalAddress,
31 } = constants::CEC_MSG_ACTIVE_SOURCE,
32 ImageViewOn = constants::CEC_MSG_IMAGE_VIEW_ON,
33 TextViewOn = constants::CEC_MSG_TEXT_VIEW_ON,
34 InactiveSource {
35 address: PhysicalAddress,
36 } = constants::CEC_MSG_INACTIVE_SOURCE,
37 #[addressing = "broadcast"]
38 RequestActiveSource = constants::CEC_MSG_REQUEST_ACTIVE_SOURCE,
39 #[addressing = "broadcast"]
40 RoutingChange {
41 original_address: PhysicalAddress,
42 new_address: PhysicalAddress,
43 } = constants::CEC_MSG_ROUTING_CHANGE,
44 #[addressing = "broadcast"]
45 RoutingInformation {
46 address: PhysicalAddress,
47 } = constants::CEC_MSG_ROUTING_INFORMATION,
48 #[addressing = "broadcast"]
49 SetStreamPath {
50 address: PhysicalAddress,
51 } = constants::CEC_MSG_SET_STREAM_PATH,
52 #[addressing = "either"]
53 Standby = constants::CEC_MSG_STANDBY,
54 RecordOff = constants::CEC_MSG_RECORD_OFF,
55 RecordOn {
56 source: operand::RecordSource,
57 } = constants::CEC_MSG_RECORD_ON,
58 RecordStatus {
59 status: operand::RecordStatusInfo,
60 } = constants::CEC_MSG_RECORD_STATUS,
61 RecordTvScreen = constants::CEC_MSG_RECORD_TV_SCREEN,
62 ClearAnalogueTimer {
63 day_of_month: operand::DayOfMonth,
64 month_of_year: operand::MonthOfYear,
65 start_time: operand::Time,
66 duration: operand::Duration,
67 recording_sequence: operand::RecordingSequence,
68 service_id: operand::AnalogueServiceId,
69 } = constants::CEC_MSG_CLEAR_ANALOGUE_TIMER,
70 ClearDigitalTimer {
71 day_of_month: operand::DayOfMonth,
72 month_of_year: operand::MonthOfYear,
73 start_time: operand::Time,
74 duration: operand::Duration,
75 recording_sequence: operand::RecordingSequence,
76 service_id: operand::DigitalServiceId,
77 } = constants::CEC_MSG_CLEAR_DIGITAL_TIMER,
78 ClearExtTimer {
79 day_of_month: operand::DayOfMonth,
80 month_of_year: operand::MonthOfYear,
81 start_time: operand::Time,
82 duration: operand::Duration,
83 recording_sequence: operand::RecordingSequence,
84 external_source: operand::ExternalSource,
85 } = constants::CEC_MSG_CLEAR_EXT_TIMER,
86 SetAnalogueTimer {
87 day_of_month: operand::DayOfMonth,
88 month_of_year: operand::MonthOfYear,
89 start_time: operand::Time,
90 duration: operand::Duration,
91 recording_sequence: operand::RecordingSequence,
92 service_id: operand::AnalogueServiceId,
93 } = constants::CEC_MSG_SET_ANALOGUE_TIMER,
94 SetDigitalTimer {
95 day_of_month: operand::DayOfMonth,
96 month_of_year: operand::MonthOfYear,
97 start_time: operand::Time,
98 duration: operand::Duration,
99 recording_sequence: operand::RecordingSequence,
100 service_id: operand::DigitalServiceId,
101 } = constants::CEC_MSG_SET_DIGITAL_TIMER,
102 SetExtTimer {
103 day_of_month: operand::DayOfMonth,
104 month_of_year: operand::MonthOfYear,
105 start_time: operand::Time,
106 duration: operand::Duration,
107 recording_sequence: operand::RecordingSequence,
108 external_source: operand::ExternalSource,
109 } = constants::CEC_MSG_SET_EXT_TIMER,
110 SetTimerProgramTitle {
111 title: operand::BufferOperand,
112 } = constants::CEC_MSG_SET_TIMER_PROGRAM_TITLE,
113 TimerClearedStatus {
114 status: operand::TimerClearedStatusData,
115 } = constants::CEC_MSG_TIMER_CLEARED_STATUS,
116 TimerStatus {
117 status: operand::TimerStatusData,
118 } = constants::CEC_MSG_TIMER_STATUS,
119 CecVersion {
120 version: operand::Version,
121 } = constants::CEC_MSG_CEC_VERSION,
122 GetCecVersion = constants::CEC_MSG_GET_CEC_VERSION,
123 GivePhysicalAddr = constants::CEC_MSG_GIVE_PHYSICAL_ADDR,
124 GetMenuLanguage = constants::CEC_MSG_GET_MENU_LANGUAGE,
125 #[addressing = "broadcast"]
126 ReportPhysicalAddr {
127 physical_address: PhysicalAddress,
128 device_type: operand::PrimaryDeviceType,
129 } = constants::CEC_MSG_REPORT_PHYSICAL_ADDR,
130 #[addressing = "broadcast"]
131 SetMenuLanguage {
132 language: [u8; 3],
133 } = constants::CEC_MSG_SET_MENU_LANGUAGE,
134 DeckControl {
135 mode: operand::DeckControlMode,
136 } = constants::CEC_MSG_DECK_CONTROL,
137 DeckStatus {
138 info: operand::DeckInfo,
139 } = constants::CEC_MSG_DECK_STATUS,
140 GiveDeckStatus {
141 request: operand::StatusRequest,
142 } = constants::CEC_MSG_GIVE_DECK_STATUS,
143 Play {
144 mode: operand::PlayMode,
145 } = constants::CEC_MSG_PLAY,
146 GiveTunerDeviceStatus {
147 request: operand::StatusRequest,
148 } = constants::CEC_MSG_GIVE_TUNER_DEVICE_STATUS,
149 SelectAnalogueService {
150 service_id: operand::AnalogueServiceId,
151 } = constants::CEC_MSG_SELECT_ANALOGUE_SERVICE,
152 SelectDigitalService {
153 service_id: operand::DigitalServiceId,
154 } = constants::CEC_MSG_SELECT_DIGITAL_SERVICE,
155 TunerDeviceStatus {
156 info: operand::TunerDeviceInfo,
157 } = constants::CEC_MSG_TUNER_DEVICE_STATUS,
158 TunerStepDecrement = constants::CEC_MSG_TUNER_STEP_DECREMENT,
159 TunerStepIncrement = constants::CEC_MSG_TUNER_STEP_INCREMENT,
160 #[addressing = "broadcast"]
161 DeviceVendorId {
162 vendor_id: crate::VendorId,
163 } = constants::CEC_MSG_DEVICE_VENDOR_ID,
164 GiveDeviceVendorId = constants::CEC_MSG_GIVE_DEVICE_VENDOR_ID,
165 VendorCommand {
166 command: operand::BufferOperand,
167 } = constants::CEC_MSG_VENDOR_COMMAND,
168 #[addressing = "either"]
169 VendorCommandWithId {
170 vendor_id: crate::VendorId,
171 vendor_specific_data: operand::BoundedBufferOperand<11, u8>,
172 } = constants::CEC_MSG_VENDOR_COMMAND_WITH_ID,
173 #[addressing = "either"]
174 VendorRemoteButtonDown {
175 rc_code: operand::BufferOperand,
176 } = constants::CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN,
177 #[addressing = "either"]
178 VendorRemoteButtonUp = constants::CEC_MSG_VENDOR_REMOTE_BUTTON_UP,
179 SetOsdString {
180 display_control: operand::DisplayControl,
181 osd_string: operand::BoundedBufferOperand<13, u8>,
182 } = constants::CEC_MSG_SET_OSD_STRING,
183 GiveOsdName = constants::CEC_MSG_GIVE_OSD_NAME,
184 SetOsdName {
185 name: operand::BufferOperand,
186 } = constants::CEC_MSG_SET_OSD_NAME,
187 MenuRequest {
188 request_type: operand::MenuRequestType,
189 } = constants::CEC_MSG_MENU_REQUEST,
190 MenuStatus {
191 state: operand::MenuState,
192 } = constants::CEC_MSG_MENU_STATUS,
193 UserControlPressed {
194 ui_command: operand::UiCommand,
195 } = constants::CEC_MSG_USER_CONTROL_PRESSED,
196 UserControlReleased = constants::CEC_MSG_USER_CONTROL_RELEASED,
197 GiveDevicePowerStatus = constants::CEC_MSG_GIVE_DEVICE_POWER_STATUS,
198 #[addressing = "either"]
199 ReportPowerStatus {
200 status: operand::PowerStatus,
201 } = constants::CEC_MSG_REPORT_POWER_STATUS,
202 FeatureAbort {
203 opcode: u8,
204 abort_reason: operand::AbortReason,
205 } = constants::CEC_MSG_FEATURE_ABORT,
206 Abort = constants::CEC_MSG_ABORT,
207 GiveAudioStatus = constants::CEC_MSG_GIVE_AUDIO_STATUS,
208 GiveSystemAudioModeStatus = constants::CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS,
209 ReportAudioStatus {
210 status: operand::AudioStatus,
211 } = constants::CEC_MSG_REPORT_AUDIO_STATUS,
212 ReportShortAudioDescriptor {
213 descriptors: operand::BoundedBufferOperand<4, operand::ShortAudioDescriptor>,
214 } = constants::CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR,
215 RequestShortAudioDescriptor {
216 descriptors: operand::BoundedBufferOperand<4, operand::AudioFormatIdAndCode>,
217 } = constants::CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR,
218 #[addressing = "either"]
219 SetSystemAudioMode {
220 status: bool,
221 } = constants::CEC_MSG_SET_SYSTEM_AUDIO_MODE,
222 SystemAudioModeRequest {
223 physical_address: PhysicalAddress,
224 } = constants::CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST,
225 SystemAudioModeStatus {
226 status: bool,
227 } = constants::CEC_MSG_SYSTEM_AUDIO_MODE_STATUS,
228 SetAudioRate {
229 audio_rate: operand::AudioRate,
230 } = constants::CEC_MSG_SET_AUDIO_RATE,
231 InitiateArc = constants::CEC_MSG_INITIATE_ARC,
233 ReportArcInitiated = constants::CEC_MSG_REPORT_ARC_INITIATED,
234 ReportArcTerminated = constants::CEC_MSG_REPORT_ARC_TERMINATED,
235 RequestArcInitiation = constants::CEC_MSG_REQUEST_ARC_INITIATION,
236 RequestArcTermination = constants::CEC_MSG_REQUEST_ARC_TERMINATION,
237 TerminateArc = constants::CEC_MSG_TERMINATE_ARC,
238 #[addressing = "broadcast"]
239 CdcMessage {
240 initiator: PhysicalAddress,
241 message: cdc::Message,
242 } = constants::CEC_MSG_CDC_MESSAGE,
243 #[addressing = "broadcast"]
245 ReportFeatures {
246 version: operand::Version,
247 device_types: operand::AllDeviceTypes,
248 rc_profile: operand::RcProfile,
249 device_features: operand::DeviceFeatures,
250 } = constants::CEC_MSG_REPORT_FEATURES,
251 GiveFeatures = constants::CEC_MSG_GIVE_FEATURES,
252 #[addressing = "broadcast"]
253 RequestCurrentLatency {
254 physical_address: PhysicalAddress,
255 } = constants::CEC_MSG_REQUEST_CURRENT_LATENCY,
256 #[addressing = "broadcast"]
257 ReportCurrentLatency {
258 physical_address: PhysicalAddress,
259 video_latency: operand::Delay,
260 flags: operand::LatencyFlags,
261 audio_output_delay: Option<operand::Delay>,
262 } = constants::CEC_MSG_REPORT_CURRENT_LATENCY,
263 SetAudioVolumeLevel {
265 volume_level: operand::AudioVolumeLevel,
266 } = constants::CEC_MSG_SET_AUDIO_VOLUME_LEVEL,
267}
268
269impl Message {
270 #[must_use]
271 pub fn opcode(&self) -> Opcode {
272 let opcode = unsafe { *<*const _>::from(self).cast::<u8>() };
273 Opcode::try_from_primitive(opcode).unwrap()
274 }
275
276 #[must_use]
279 pub fn can_directly_address(&self) -> bool {
280 self.opcode().can_directly_address()
281 }
282
283 #[must_use]
286 pub fn can_broadcast(&self) -> bool {
287 self.opcode().can_broadcast()
288 }
289
290 #[must_use]
294 pub fn addressing_type(&self) -> AddressingType {
295 self.opcode().addressing_type()
296 }
297}
298
299impl Opcode {
300 #[must_use]
301 pub fn can_directly_address(&self) -> bool {
302 matches!(
303 self.addressing_type(),
304 AddressingType::Direct | AddressingType::Either
305 )
306 }
307
308 #[must_use]
309 pub fn can_broadcast(&self) -> bool {
310 matches!(
311 self.addressing_type(),
312 AddressingType::Broadcast | AddressingType::Either
313 )
314 }
315}
316
317#[cfg(test)]
318mod test_active_source {
319 use super::*;
320
321 message_test! {
322 ty: ActiveSource,
323 instance: Message::ActiveSource {
324 address: PhysicalAddress(0x1234),
325 },
326 bytes: [0x12, 0x34],
327 extra: [Overfull, Empty],
328 }
329
330 #[test]
331 fn test_decoding_missing_byte() {
332 assert_eq!(
333 Message::try_from_bytes(&[Opcode::ActiveSource as u8, 0x12]),
334 Err(Error::OutOfRange {
335 expected: Range::AtLeast(3),
336 got: 2,
337 quantity: "bytes",
338 })
339 );
340 }
341}
342
343#[cfg(test)]
344mod test_inactive_source {
345 use super::*;
346
347 message_test! {
348 ty: InactiveSource,
349 instance: Message::InactiveSource {
350 address: PhysicalAddress(0x1234),
351 },
352 bytes: [0x12, 0x34],
353 extra: [Overfull, Empty],
354 }
355
356 #[test]
357 fn test_decoding_missing_byte() {
358 assert_eq!(
359 Message::try_from_bytes(&[Opcode::InactiveSource as u8, 0x12]),
360 Err(Error::OutOfRange {
361 expected: Range::AtLeast(3),
362 got: 2,
363 quantity: "bytes",
364 })
365 );
366 }
367}
368
369#[cfg(test)]
370mod test_routing_change {
371 use super::*;
372
373 message_test! {
374 ty: RoutingChange,
375 instance: Message::RoutingChange {
376 original_address: PhysicalAddress(0x1234),
377 new_address: PhysicalAddress(0x5678),
378 },
379 bytes: [0x12, 0x34, 0x56, 0x78],
380 extra: [Overfull, Empty],
381 }
382
383 #[test]
384 fn test_decoding_missing_byte() {
385 assert_eq!(
386 Message::try_from_bytes(&[Opcode::RoutingChange as u8, 0x12, 0x34, 0x56]),
387 Err(Error::OutOfRange {
388 expected: Range::AtLeast(5),
389 got: 4,
390 quantity: "bytes",
391 })
392 );
393 }
394
395 #[test]
396 fn test_decoding_missing_operand() {
397 assert_eq!(
398 Message::try_from_bytes(&[Opcode::RoutingChange as u8, 0x12, 0x34]),
399 Err(Error::OutOfRange {
400 expected: Range::AtLeast(5),
401 got: 3,
402 quantity: "bytes",
403 })
404 );
405 }
406
407 #[test]
408 fn test_decoding_missing_operand_and_byte() {
409 assert_eq!(
410 Message::try_from_bytes(&[Opcode::RoutingChange as u8, 0x12]),
411 Err(Error::OutOfRange {
412 expected: Range::AtLeast(5),
413 got: 2,
414 quantity: "bytes",
415 })
416 );
417 }
418}
419
420#[cfg(test)]
421mod test_routing_information {
422 use super::*;
423
424 message_test! {
425 ty: RoutingInformation,
426 instance: Message::RoutingInformation {
427 address: PhysicalAddress(0x1234),
428 },
429 bytes: [0x12, 0x34],
430 extra: [Overfull, Empty],
431 }
432
433 #[test]
434 fn test_decoding_missing_byte() {
435 assert_eq!(
436 Message::try_from_bytes(&[Opcode::RoutingInformation as u8, 0x12]),
437 Err(Error::OutOfRange {
438 expected: Range::AtLeast(3),
439 got: 2,
440 quantity: "bytes",
441 })
442 );
443 }
444}
445
446#[cfg(test)]
447mod test_set_stream_path {
448 use super::*;
449
450 message_test! {
451 ty: SetStreamPath,
452 instance: Message::SetStreamPath {
453 address: PhysicalAddress(0x1234),
454 },
455 bytes: [0x12, 0x34],
456 extra: [Overfull, Empty],
457 }
458
459 #[test]
460 fn test_decoding_missing_byte() {
461 assert_eq!(
462 Message::try_from_bytes(&[Opcode::SetStreamPath as u8, 0x12]),
463 Err(Error::OutOfRange {
464 expected: Range::AtLeast(3),
465 got: 2,
466 quantity: "bytes",
467 })
468 );
469 }
470}
471
472#[cfg(test)]
473mod test_record_on {
474 use super::*;
475
476 message_test! {
477 name: _own,
478 ty: RecordOn,
479 instance: Message::RecordOn {
480 source: operand::RecordSource::Own,
481 },
482 bytes: [operand::RecordSourceType::Own as u8],
483 extra: [Overfull],
484 }
485
486 message_test! {
487 name: _digital,
488 ty: RecordOn,
489 instance: Message::RecordOn {
490 source: operand::RecordSource::DigitalService(
491 operand::DigitalServiceId::AribGeneric(operand::AribData {
492 transport_stream_id: 0x1234,
493 service_id: 0x5678,
494 original_network_id: 0x9ABC,
495 })
496 )
497 },
498 bytes: [
499 operand::RecordSourceType::Digital as u8,
500 operand::DigitalServiceBroadcastSystem::AribGeneric as u8,
501 0x12,
502 0x34,
503 0x56,
504 0x78,
505 0x9A,
506 0xBC
507 ],
508 extra: [Overfull],
509 }
510
511 message_test! {
512 name: _analogue,
513 ty: RecordOn,
514 instance: Message::RecordOn {
515 source: operand::RecordSource::AnalogueService(operand::AnalogueServiceId {
516 broadcast_type: operand::AnalogueBroadcastType::Satellite,
517 frequency: 0x1234,
518 broadcast_system: operand::BroadcastSystem::SecamL,
519 })
520 },
521 bytes: [
522 operand::RecordSourceType::Analogue as u8,
523 operand::AnalogueBroadcastType::Satellite as u8,
524 0x12,
525 0x34,
526 operand::BroadcastSystem::SecamL as u8
527 ],
528 extra: [Overfull],
529 }
530
531 #[test]
532 fn test_decode_missing_operands() {
533 assert_eq!(
534 Message::try_from_bytes(&[Opcode::RecordOn as u8]),
535 Err(Error::OutOfRange {
536 expected: Range::AtLeast(2),
537 got: 1,
538 quantity: "bytes",
539 })
540 );
541 }
542
543 #[test]
544 fn test_opcode() {
545 assert_eq!(
546 Message::RecordOn {
547 source: operand::RecordSource::Own
548 }
549 .opcode(),
550 Opcode::RecordOn
551 );
552 }
553}
554
555#[cfg(test)]
556mod test_record_status {
557 use super::*;
558
559 message_test! {
560 ty: RecordStatus,
561 instance: Message::RecordStatus {
562 status: operand::RecordStatusInfo::CurrentSource
563 },
564 bytes: [operand::RecordStatusInfo::CurrentSource as u8],
565 extra: [Overfull, Empty],
566 }
567
568 #[test]
569 fn test_decode_invalid_operand() {
570 assert_eq!(
571 Message::try_from_bytes(&[Opcode::RecordStatus as u8, 0xFE]),
572 Err(Error::InvalidValueForType {
573 ty: "RecordStatusInfo",
574 value: String::from("254"),
575 })
576 );
577 }
578}
579
580#[cfg(test)]
581mod test_clear_analogue_timer {
582 use super::*;
583
584 message_test! {
585 ty: ClearAnalogueTimer,
586 instance: Message::ClearAnalogueTimer {
587 day_of_month: operand::DayOfMonth::Day1,
588 month_of_year: operand::MonthOfYear::January,
589 start_time: operand::Time {
590 hour: operand::Hour::try_from(12).unwrap(),
591 minute: operand::Minute::try_from(30).unwrap(),
592 },
593 duration: operand::Duration {
594 hours: operand::DurationHours::try_from(99).unwrap(),
595 minutes: operand::Minute::try_from(59).unwrap(),
596 },
597 recording_sequence: operand::RecordingSequence::SUNDAY,
598 service_id: operand::AnalogueServiceId {
599 broadcast_type: operand::AnalogueBroadcastType::Terrestrial,
600 frequency: 0x1234,
601 broadcast_system: operand::BroadcastSystem::NtscM
602 },
603 },
604 bytes: [
605 operand::DayOfMonth::Day1 as u8,
606 operand::MonthOfYear::January as u8,
607 0x12,
608 0x30,
609 0x99,
610 0x59,
611 constants::CEC_OP_REC_SEQ_SUNDAY,
612 operand::AnalogueBroadcastType::Terrestrial as u8,
613 0x12,
614 0x34,
615 operand::BroadcastSystem::NtscM as u8
616 ],
617 extra: [Overfull, Empty],
618 }
619
620 #[test]
621 fn test_decoding_missing_operand_1() {
622 assert_eq!(
623 Message::try_from_bytes(&[
624 Opcode::ClearAnalogueTimer as u8,
625 operand::DayOfMonth::Day1 as u8,
626 operand::MonthOfYear::January as u8,
627 0x12,
628 0x30,
629 0x99,
630 0x59,
631 constants::CEC_OP_REC_SEQ_SUNDAY,
632 ]),
633 Err(Error::OutOfRange {
634 expected: Range::AtLeast(12),
635 got: 8,
636 quantity: "bytes",
637 })
638 );
639 }
640
641 #[test]
642 fn test_decoding_missing_operand_2() {
643 assert_eq!(
644 Message::try_from_bytes(&[
645 Opcode::ClearAnalogueTimer as u8,
646 operand::DayOfMonth::Day1 as u8,
647 operand::MonthOfYear::January as u8,
648 0x12,
649 0x30,
650 0x99,
651 0x59,
652 ]),
653 Err(Error::OutOfRange {
654 expected: Range::AtLeast(12),
655 got: 7,
656 quantity: "bytes",
657 })
658 );
659 }
660
661 #[test]
662 fn test_decoding_missing_operand_3() {
663 assert_eq!(
664 Message::try_from_bytes(&[
665 Opcode::ClearAnalogueTimer as u8,
666 operand::DayOfMonth::Day1 as u8,
667 operand::MonthOfYear::January as u8,
668 0x12,
669 0x30,
670 ]),
671 Err(Error::OutOfRange {
672 expected: Range::AtLeast(12),
673 got: 5,
674 quantity: "bytes",
675 })
676 );
677 }
678
679 #[test]
680 fn test_decoding_missing_operand_4() {
681 assert_eq!(
682 Message::try_from_bytes(&[
683 Opcode::ClearAnalogueTimer as u8,
684 operand::DayOfMonth::Day1 as u8,
685 operand::MonthOfYear::January as u8,
686 ]),
687 Err(Error::OutOfRange {
688 expected: Range::AtLeast(12),
689 got: 3,
690 quantity: "bytes",
691 })
692 );
693 }
694
695 #[test]
696 fn test_decoding_missing_operand_5() {
697 assert_eq!(
698 Message::try_from_bytes(&[
699 Opcode::ClearAnalogueTimer as u8,
700 operand::DayOfMonth::Day1 as u8,
701 ]),
702 Err(Error::OutOfRange {
703 expected: Range::AtLeast(12),
704 got: 2,
705 quantity: "bytes",
706 })
707 );
708 }
709}
710
711#[cfg(test)]
712mod test_clear_digital_timer {
713 use super::*;
714
715 message_test! {
716 ty: ClearDigitalTimer,
717 instance: Message::ClearDigitalTimer {
718 day_of_month: operand::DayOfMonth::Day1,
719 month_of_year: operand::MonthOfYear::January,
720 start_time: operand::Time {
721 hour: operand::Hour::try_from(12).unwrap(),
722 minute: operand::Minute::try_from(30).unwrap(),
723 },
724 duration: operand::Duration {
725 hours: operand::DurationHours::try_from(99).unwrap(),
726 minutes: operand::Minute::try_from(59).unwrap(),
727 },
728 recording_sequence: operand::RecordingSequence::SUNDAY,
729 service_id: operand::DigitalServiceId::AtscCable(
730 operand::AtscData {
731 transport_stream_id: 0x1234,
732 program_number: 0x5678,
733 }
734 ),
735 },
736 bytes: [
737 operand::DayOfMonth::Day1 as u8,
738 operand::MonthOfYear::January as u8,
739 0x12,
740 0x30,
741 0x99,
742 0x59,
743 constants::CEC_OP_REC_SEQ_SUNDAY,
744 operand::DigitalServiceBroadcastSystem::AtscCable as u8,
745 0x12,
746 0x34,
747 0x56,
748 0x78,
749 0,
750 0,
751 ],
752 extra: [Empty],
753 }
754
755 #[test]
756 fn test_decoding_missing_operand_1() {
757 assert_eq!(
758 Message::try_from_bytes(&[
759 Opcode::ClearDigitalTimer as u8,
760 operand::DayOfMonth::Day1 as u8,
761 operand::MonthOfYear::January as u8,
762 0x12,
763 0x30,
764 0x99,
765 0x59,
766 constants::CEC_OP_REC_SEQ_SUNDAY,
767 ]),
768 Err(Error::OutOfRange {
769 expected: Range::AtLeast(15),
770 got: 8,
771 quantity: "bytes",
772 })
773 );
774 }
775
776 #[test]
777 fn test_decoding_missing_operand_2() {
778 assert_eq!(
779 Message::try_from_bytes(&[
780 Opcode::ClearDigitalTimer as u8,
781 operand::DayOfMonth::Day1 as u8,
782 operand::MonthOfYear::January as u8,
783 0x12,
784 0x30,
785 0x99,
786 0x59,
787 ]),
788 Err(Error::OutOfRange {
789 expected: Range::AtLeast(15),
790 got: 7,
791 quantity: "bytes",
792 })
793 );
794 }
795
796 #[test]
797 fn test_decoding_missing_operand_3() {
798 assert_eq!(
799 Message::try_from_bytes(&[
800 Opcode::ClearDigitalTimer as u8,
801 operand::DayOfMonth::Day1 as u8,
802 operand::MonthOfYear::January as u8,
803 0x12,
804 0x30,
805 ]),
806 Err(Error::OutOfRange {
807 expected: Range::AtLeast(15),
808 got: 5,
809 quantity: "bytes",
810 })
811 );
812 }
813
814 #[test]
815 fn test_decoding_missing_operand_4() {
816 assert_eq!(
817 Message::try_from_bytes(&[
818 Opcode::ClearDigitalTimer as u8,
819 operand::DayOfMonth::Day1 as u8,
820 operand::MonthOfYear::January as u8,
821 ]),
822 Err(Error::OutOfRange {
823 expected: Range::AtLeast(15),
824 got: 3,
825 quantity: "bytes",
826 })
827 );
828 }
829
830 #[test]
831 fn test_decoding_missing_operand_5() {
832 assert_eq!(
833 Message::try_from_bytes(&[
834 Opcode::ClearDigitalTimer as u8,
835 operand::DayOfMonth::Day1 as u8,
836 ]),
837 Err(Error::OutOfRange {
838 expected: Range::AtLeast(15),
839 got: 2,
840 quantity: "bytes",
841 })
842 );
843 }
844}
845
846#[cfg(test)]
847mod test_clear_ext_timer {
848 use super::*;
849
850 message_test! {
851 name: _phys_addr,
852 ty: ClearExtTimer,
853 instance: Message::ClearExtTimer {
854 day_of_month: operand::DayOfMonth::Day1,
855 month_of_year: operand::MonthOfYear::January,
856 start_time: operand::Time {
857 hour: operand::Hour::try_from(12).unwrap(),
858 minute: operand::Minute::try_from(30).unwrap(),
859 },
860 duration: operand::Duration {
861 hours: operand::DurationHours::try_from(99).unwrap(),
862 minutes: operand::Minute::try_from(59).unwrap(),
863 },
864 recording_sequence: operand::RecordingSequence::SUNDAY,
865 external_source: operand::ExternalSource::PhysicalAddress(PhysicalAddress(0x1234)),
866 },
867 bytes: [
868 operand::DayOfMonth::Day1 as u8,
869 operand::MonthOfYear::January as u8,
870 0x12,
871 0x30,
872 0x99,
873 0x59,
874 constants::CEC_OP_REC_SEQ_SUNDAY,
875 0x12,
876 0x34,
877 ],
878 }
879
880 message_test! {
881 name: _plug,
882 ty: ClearExtTimer,
883 instance: Message::ClearExtTimer {
884 day_of_month: operand::DayOfMonth::Day1,
885 month_of_year: operand::MonthOfYear::January,
886 start_time: operand::Time {
887 hour: operand::Hour::try_from(12).unwrap(),
888 minute: operand::Minute::try_from(30).unwrap(),
889 },
890 duration: operand::Duration {
891 hours: operand::DurationHours::try_from(99).unwrap(),
892 minutes: operand::Minute::try_from(59).unwrap(),
893 },
894 recording_sequence: operand::RecordingSequence::SUNDAY,
895 external_source: operand::ExternalSource::Plug(0x56),
896 },
897 bytes: [
898 operand::DayOfMonth::Day1 as u8,
899 operand::MonthOfYear::January as u8,
900 0x12,
901 0x30,
902 0x99,
903 0x59,
904 constants::CEC_OP_REC_SEQ_SUNDAY,
905 0x56,
906 ],
907 }
908
909 #[test]
910 fn test_opcode() {
911 assert_eq!(
912 Message::ClearExtTimer {
913 day_of_month: operand::DayOfMonth::Day1,
914 month_of_year: operand::MonthOfYear::January,
915 start_time: operand::Time {
916 hour: operand::Hour::try_from(12).unwrap(),
917 minute: operand::Minute::try_from(30).unwrap(),
918 },
919 duration: operand::Duration {
920 hours: operand::DurationHours::try_from(99).unwrap(),
921 minutes: operand::Minute::try_from(59).unwrap(),
922 },
923 recording_sequence: operand::RecordingSequence::SUNDAY,
924 external_source: operand::ExternalSource::Plug(0x56),
925 }
926 .opcode(),
927 Opcode::ClearExtTimer
928 );
929 }
930
931 #[test]
932 fn test_decoding_missing_operand_1() {
933 assert_eq!(
934 Message::try_from_bytes(&[
935 Opcode::ClearExtTimer as u8,
936 operand::DayOfMonth::Day1 as u8,
937 operand::MonthOfYear::January as u8,
938 0x12,
939 0x30,
940 0x99,
941 0x59,
942 constants::CEC_OP_REC_SEQ_SUNDAY,
943 ]),
944 Err(Error::OutOfRange {
945 expected: Range::Only(vec![9, 10]),
946 got: 8,
947 quantity: "bytes",
948 })
949 );
950 }
951
952 #[test]
953 fn test_decoding_missing_operand_2() {
954 assert_eq!(
955 Message::try_from_bytes(&[
956 Opcode::ClearExtTimer as u8,
957 operand::DayOfMonth::Day1 as u8,
958 operand::MonthOfYear::January as u8,
959 0x12,
960 0x30,
961 0x99,
962 0x59,
963 ]),
964 Err(Error::OutOfRange {
965 expected: Range::Only(vec![9, 10]),
966 got: 7,
967 quantity: "bytes",
968 })
969 );
970 }
971
972 #[test]
973 fn test_decoding_missing_operand_3() {
974 assert_eq!(
975 Message::try_from_bytes(&[
976 Opcode::ClearExtTimer as u8,
977 operand::DayOfMonth::Day1 as u8,
978 operand::MonthOfYear::January as u8,
979 0x12,
980 0x30,
981 ]),
982 Err(Error::OutOfRange {
983 expected: Range::Only(vec![9, 10]),
984 got: 5,
985 quantity: "bytes",
986 })
987 );
988 }
989
990 #[test]
991 fn test_decoding_missing_operand_4() {
992 assert_eq!(
993 Message::try_from_bytes(&[
994 Opcode::ClearExtTimer as u8,
995 operand::DayOfMonth::Day1 as u8,
996 operand::MonthOfYear::January as u8,
997 ]),
998 Err(Error::OutOfRange {
999 expected: Range::Only(vec![9, 10]),
1000 got: 3,
1001 quantity: "bytes",
1002 })
1003 );
1004 }
1005
1006 #[test]
1007 fn test_decoding_missing_operand_5() {
1008 assert_eq!(
1009 Message::try_from_bytes(&[
1010 Opcode::ClearExtTimer as u8,
1011 operand::DayOfMonth::Day1 as u8,
1012 ]),
1013 Err(Error::OutOfRange {
1014 expected: Range::Only(vec![9, 10]),
1015 got: 2,
1016 quantity: "bytes",
1017 })
1018 );
1019 }
1020
1021 #[test]
1022 fn test_decoding_missing_operand_6() {
1023 assert_eq!(
1024 Message::try_from_bytes(&[Opcode::ClearExtTimer as u8]),
1025 Err(Error::OutOfRange {
1026 expected: Range::Only(vec![9, 10]),
1027 got: 1,
1028 quantity: "bytes",
1029 })
1030 );
1031 }
1032}
1033
1034#[cfg(test)]
1035mod test_set_analogue_timer {
1036 use super::*;
1037
1038 message_test! {
1039 ty: SetAnalogueTimer,
1040 instance: Message::SetAnalogueTimer {
1041 day_of_month: operand::DayOfMonth::Day1,
1042 month_of_year: operand::MonthOfYear::January,
1043 start_time: operand::Time {
1044 hour: operand::Hour::try_from(12).unwrap(),
1045 minute: operand::Minute::try_from(30).unwrap(),
1046 },
1047 duration: operand::Duration {
1048 hours: operand::DurationHours::try_from(99).unwrap(),
1049 minutes: operand::Minute::try_from(59).unwrap(),
1050 },
1051 recording_sequence: operand::RecordingSequence::SUNDAY,
1052 service_id: operand::AnalogueServiceId {
1053 broadcast_type: operand::AnalogueBroadcastType::Terrestrial,
1054 frequency: 0x1234,
1055 broadcast_system: operand::BroadcastSystem::NtscM
1056 },
1057 },
1058 bytes: [
1059 operand::DayOfMonth::Day1 as u8,
1060 operand::MonthOfYear::January as u8,
1061 0x12,
1062 0x30,
1063 0x99,
1064 0x59,
1065 constants::CEC_OP_REC_SEQ_SUNDAY,
1066 operand::AnalogueBroadcastType::Terrestrial as u8,
1067 0x12,
1068 0x34,
1069 operand::BroadcastSystem::NtscM as u8
1070 ],
1071 extra: [Overfull, Empty],
1072 }
1073
1074 #[test]
1075 fn test_decoding_missing_operand_1() {
1076 assert_eq!(
1077 Message::try_from_bytes(&[
1078 Opcode::SetAnalogueTimer as u8,
1079 operand::DayOfMonth::Day1 as u8,
1080 operand::MonthOfYear::January as u8,
1081 0x12,
1082 0x30,
1083 0x99,
1084 0x59,
1085 constants::CEC_OP_REC_SEQ_SUNDAY,
1086 ]),
1087 Err(Error::OutOfRange {
1088 expected: Range::AtLeast(12),
1089 got: 8,
1090 quantity: "bytes",
1091 })
1092 );
1093 }
1094
1095 #[test]
1096 fn test_decoding_missing_operand_2() {
1097 assert_eq!(
1098 Message::try_from_bytes(&[
1099 Opcode::SetAnalogueTimer as u8,
1100 operand::DayOfMonth::Day1 as u8,
1101 operand::MonthOfYear::January as u8,
1102 0x12,
1103 0x30,
1104 0x99,
1105 0x59,
1106 ]),
1107 Err(Error::OutOfRange {
1108 expected: Range::AtLeast(12),
1109 got: 7,
1110 quantity: "bytes",
1111 })
1112 );
1113 }
1114
1115 #[test]
1116 fn test_decoding_missing_operand_3() {
1117 assert_eq!(
1118 Message::try_from_bytes(&[
1119 Opcode::SetAnalogueTimer as u8,
1120 operand::DayOfMonth::Day1 as u8,
1121 operand::MonthOfYear::January as u8,
1122 0x12,
1123 0x30,
1124 ]),
1125 Err(Error::OutOfRange {
1126 expected: Range::AtLeast(12),
1127 got: 5,
1128 quantity: "bytes",
1129 })
1130 );
1131 }
1132
1133 #[test]
1134 fn test_decoding_missing_operand_4() {
1135 assert_eq!(
1136 Message::try_from_bytes(&[
1137 Opcode::SetAnalogueTimer as u8,
1138 operand::DayOfMonth::Day1 as u8,
1139 operand::MonthOfYear::January as u8,
1140 ]),
1141 Err(Error::OutOfRange {
1142 expected: Range::AtLeast(12),
1143 got: 3,
1144 quantity: "bytes",
1145 })
1146 );
1147 }
1148
1149 #[test]
1150 fn test_decoding_missing_operand_5() {
1151 assert_eq!(
1152 Message::try_from_bytes(&[
1153 Opcode::SetAnalogueTimer as u8,
1154 operand::DayOfMonth::Day1 as u8,
1155 ]),
1156 Err(Error::OutOfRange {
1157 expected: Range::AtLeast(12),
1158 got: 2,
1159 quantity: "bytes",
1160 })
1161 );
1162 }
1163}
1164
1165#[cfg(test)]
1166mod test_set_digital_timer {
1167 use super::*;
1168
1169 message_test! {
1170 ty: SetDigitalTimer,
1171 instance: Message::SetDigitalTimer {
1172 day_of_month: operand::DayOfMonth::Day1,
1173 month_of_year: operand::MonthOfYear::January,
1174 start_time: operand::Time {
1175 hour: operand::Hour::try_from(12).unwrap(),
1176 minute: operand::Minute::try_from(30).unwrap(),
1177 },
1178 duration: operand::Duration {
1179 hours: operand::DurationHours::try_from(99).unwrap(),
1180 minutes: operand::Minute::try_from(59).unwrap(),
1181 },
1182 recording_sequence: operand::RecordingSequence::SUNDAY,
1183 service_id: operand::DigitalServiceId::AtscCable(
1184 operand::AtscData {
1185 transport_stream_id: 0x1234,
1186 program_number: 0x5678,
1187 }
1188 ),
1189 },
1190 bytes: [
1191 operand::DayOfMonth::Day1 as u8,
1192 operand::MonthOfYear::January as u8,
1193 0x12,
1194 0x30,
1195 0x99,
1196 0x59,
1197 constants::CEC_OP_REC_SEQ_SUNDAY,
1198 operand::DigitalServiceBroadcastSystem::AtscCable as u8,
1199 0x12,
1200 0x34,
1201 0x56,
1202 0x78,
1203 0,
1204 0,
1205 ],
1206 extra: [Empty],
1207 }
1208
1209 #[test]
1210 fn test_decoding_missing_operand_1() {
1211 assert_eq!(
1212 Message::try_from_bytes(&[
1213 Opcode::SetDigitalTimer as u8,
1214 operand::DayOfMonth::Day1 as u8,
1215 operand::MonthOfYear::January as u8,
1216 0x12,
1217 0x30,
1218 0x99,
1219 0x59,
1220 constants::CEC_OP_REC_SEQ_SUNDAY,
1221 ]),
1222 Err(Error::OutOfRange {
1223 expected: Range::AtLeast(15),
1224 got: 8,
1225 quantity: "bytes",
1226 })
1227 );
1228 }
1229
1230 #[test]
1231 fn test_decoding_missing_operand_2() {
1232 assert_eq!(
1233 Message::try_from_bytes(&[
1234 Opcode::SetDigitalTimer as u8,
1235 operand::DayOfMonth::Day1 as u8,
1236 operand::MonthOfYear::January as u8,
1237 0x12,
1238 0x30,
1239 0x99,
1240 0x59,
1241 ]),
1242 Err(Error::OutOfRange {
1243 expected: Range::AtLeast(15),
1244 got: 7,
1245 quantity: "bytes",
1246 })
1247 );
1248 }
1249
1250 #[test]
1251 fn test_decoding_missing_operand_3() {
1252 assert_eq!(
1253 Message::try_from_bytes(&[
1254 Opcode::SetDigitalTimer as u8,
1255 operand::DayOfMonth::Day1 as u8,
1256 operand::MonthOfYear::January as u8,
1257 0x12,
1258 0x30,
1259 ]),
1260 Err(Error::OutOfRange {
1261 expected: Range::AtLeast(15),
1262 got: 5,
1263 quantity: "bytes",
1264 })
1265 );
1266 }
1267
1268 #[test]
1269 fn test_decoding_missing_operand_4() {
1270 assert_eq!(
1271 Message::try_from_bytes(&[
1272 Opcode::SetDigitalTimer as u8,
1273 operand::DayOfMonth::Day1 as u8,
1274 operand::MonthOfYear::January as u8,
1275 ]),
1276 Err(Error::OutOfRange {
1277 expected: Range::AtLeast(15),
1278 got: 3,
1279 quantity: "bytes",
1280 })
1281 );
1282 }
1283
1284 #[test]
1285 fn test_decoding_missing_operand_5() {
1286 assert_eq!(
1287 Message::try_from_bytes(&[
1288 Opcode::SetDigitalTimer as u8,
1289 operand::DayOfMonth::Day1 as u8,
1290 ]),
1291 Err(Error::OutOfRange {
1292 expected: Range::AtLeast(15),
1293 got: 2,
1294 quantity: "bytes",
1295 })
1296 );
1297 }
1298
1299 #[test]
1300 fn test_decoding_missing_operand_6() {
1301 assert_eq!(
1302 Message::try_from_bytes(&[Opcode::SetDigitalTimer as u8]),
1303 Err(Error::OutOfRange {
1304 expected: Range::AtLeast(15),
1305 got: 1,
1306 quantity: "bytes",
1307 })
1308 );
1309 }
1310}
1311
1312#[cfg(test)]
1313mod test_set_ext_timer {
1314 use super::*;
1315
1316 message_test! {
1317 name: _phys_addr,
1318 ty: SetExtTimer,
1319 instance: Message::SetExtTimer {
1320 day_of_month: operand::DayOfMonth::Day1,
1321 month_of_year: operand::MonthOfYear::January,
1322 start_time: operand::Time {
1323 hour: operand::Hour::try_from(12).unwrap(),
1324 minute: operand::Minute::try_from(30).unwrap(),
1325 },
1326 duration: operand::Duration {
1327 hours: operand::DurationHours::try_from(99).unwrap(),
1328 minutes: operand::Minute::try_from(59).unwrap(),
1329 },
1330 recording_sequence: operand::RecordingSequence::SUNDAY,
1331 external_source: operand::ExternalSource::PhysicalAddress(PhysicalAddress(0x1234)),
1332 },
1333 bytes: [
1334 operand::DayOfMonth::Day1 as u8,
1335 operand::MonthOfYear::January as u8,
1336 0x12,
1337 0x30,
1338 0x99,
1339 0x59,
1340 constants::CEC_OP_REC_SEQ_SUNDAY,
1341 0x12,
1342 0x34,
1343 ],
1344 }
1345
1346 message_test! {
1347 name: _plug,
1348 ty: SetExtTimer,
1349 instance: Message::SetExtTimer {
1350 day_of_month: operand::DayOfMonth::Day1,
1351 month_of_year: operand::MonthOfYear::January,
1352 start_time: operand::Time {
1353 hour: operand::Hour::try_from(12).unwrap(),
1354 minute: operand::Minute::try_from(30).unwrap(),
1355 },
1356 duration: operand::Duration {
1357 hours: operand::DurationHours::try_from(99).unwrap(),
1358 minutes: operand::Minute::try_from(59).unwrap(),
1359 },
1360 recording_sequence: operand::RecordingSequence::SUNDAY,
1361 external_source: operand::ExternalSource::Plug(0x56),
1362 },
1363 bytes: [
1364 operand::DayOfMonth::Day1 as u8,
1365 operand::MonthOfYear::January as u8,
1366 0x12,
1367 0x30,
1368 0x99,
1369 0x59,
1370 constants::CEC_OP_REC_SEQ_SUNDAY,
1371 0x56,
1372 ],
1373 }
1374
1375 #[test]
1376 fn test_opcode() {
1377 assert_eq!(
1378 Message::SetExtTimer {
1379 day_of_month: operand::DayOfMonth::Day1,
1380 month_of_year: operand::MonthOfYear::January,
1381 start_time: operand::Time {
1382 hour: operand::Hour::try_from(12).unwrap(),
1383 minute: operand::Minute::try_from(30).unwrap(),
1384 },
1385 duration: operand::Duration {
1386 hours: operand::DurationHours::try_from(99).unwrap(),
1387 minutes: operand::Minute::try_from(59).unwrap(),
1388 },
1389 recording_sequence: operand::RecordingSequence::SUNDAY,
1390 external_source: operand::ExternalSource::Plug(0x56),
1391 }
1392 .opcode(),
1393 Opcode::SetExtTimer
1394 );
1395 }
1396
1397 #[test]
1398 fn test_decoding_missing_operand_1() {
1399 assert_eq!(
1400 Message::try_from_bytes(&[
1401 Opcode::SetExtTimer as u8,
1402 operand::DayOfMonth::Day1 as u8,
1403 operand::MonthOfYear::January as u8,
1404 0x12,
1405 0x30,
1406 0x99,
1407 0x59,
1408 constants::CEC_OP_REC_SEQ_SUNDAY,
1409 ]),
1410 Err(Error::OutOfRange {
1411 expected: Range::Only(vec![9, 10]),
1412 got: 8,
1413 quantity: "bytes",
1414 })
1415 );
1416 }
1417
1418 #[test]
1419 fn test_decoding_missing_operand_2() {
1420 assert_eq!(
1421 Message::try_from_bytes(&[
1422 Opcode::SetExtTimer as u8,
1423 operand::DayOfMonth::Day1 as u8,
1424 operand::MonthOfYear::January as u8,
1425 0x12,
1426 0x30,
1427 0x99,
1428 0x59,
1429 ]),
1430 Err(Error::OutOfRange {
1431 expected: Range::Only(vec![9, 10]),
1432 got: 7,
1433 quantity: "bytes",
1434 })
1435 );
1436 }
1437
1438 #[test]
1439 fn test_decoding_missing_operand_3() {
1440 assert_eq!(
1441 Message::try_from_bytes(&[
1442 Opcode::SetExtTimer as u8,
1443 operand::DayOfMonth::Day1 as u8,
1444 operand::MonthOfYear::January as u8,
1445 0x12,
1446 0x30,
1447 ]),
1448 Err(Error::OutOfRange {
1449 expected: Range::Only(vec![9, 10]),
1450 got: 5,
1451 quantity: "bytes",
1452 })
1453 );
1454 }
1455
1456 #[test]
1457 fn test_decoding_missing_operand_4() {
1458 assert_eq!(
1459 Message::try_from_bytes(&[
1460 Opcode::SetExtTimer as u8,
1461 operand::DayOfMonth::Day1 as u8,
1462 operand::MonthOfYear::January as u8,
1463 ]),
1464 Err(Error::OutOfRange {
1465 expected: Range::Only(vec![9, 10]),
1466 got: 3,
1467 quantity: "bytes",
1468 })
1469 );
1470 }
1471
1472 #[test]
1473 fn test_decoding_missing_operand_5() {
1474 assert_eq!(
1475 Message::try_from_bytes(&[Opcode::SetExtTimer as u8, operand::DayOfMonth::Day1 as u8]),
1476 Err(Error::OutOfRange {
1477 expected: Range::Only(vec![9, 10]),
1478 got: 2,
1479 quantity: "bytes",
1480 })
1481 );
1482 }
1483
1484 #[test]
1485 fn test_decoding_missing_operand_6() {
1486 assert_eq!(
1487 Message::try_from_bytes(&[Opcode::SetExtTimer as u8]),
1488 Err(Error::OutOfRange {
1489 expected: Range::Only(vec![9, 10]),
1490 got: 1,
1491 quantity: "bytes",
1492 })
1493 );
1494 }
1495}
1496
1497#[cfg(test)]
1498mod test_set_timer_program_title {
1499 use super::*;
1500
1501 message_test! {
1502 name: _empty,
1503 ty: SetTimerProgramTitle,
1504 instance: Message::SetTimerProgramTitle {
1505 title: operand::BufferOperand::from_str("").unwrap(),
1506 },
1507 bytes: [],
1508 }
1509
1510 message_test! {
1511 name: _full,
1512 ty: SetTimerProgramTitle,
1513 instance: Message::SetTimerProgramTitle {
1514 title: operand::BufferOperand::from_str("12345678901234").unwrap(),
1515 },
1516 bytes: [
1517 b'1',
1518 b'2',
1519 b'3',
1520 b'4',
1521 b'5',
1522 b'6',
1523 b'7',
1524 b'8',
1525 b'9',
1526 b'0',
1527 b'1',
1528 b'2',
1529 b'3',
1530 b'4'
1531 ],
1532 }
1533
1534 #[test]
1535 fn test_opcode() {
1536 assert_eq!(
1537 Message::SetTimerProgramTitle {
1538 title: operand::BufferOperand::from_str("12345678901234").unwrap(),
1539 }
1540 .opcode(),
1541 Opcode::SetTimerProgramTitle
1542 );
1543 }
1544}
1545
1546#[cfg(test)]
1547mod test_timer_cleared_status {
1548 use super::*;
1549
1550 message_test! {
1551 ty: TimerClearedStatus,
1552 instance: Message::TimerClearedStatus {
1553 status: operand::TimerClearedStatusData::Cleared,
1554 },
1555 bytes: [operand::TimerClearedStatusData::Cleared as u8],
1556 extra: [Overfull, Empty],
1557 }
1558}
1559
1560#[cfg(test)]
1561mod test_timer_status {
1562 use super::*;
1563
1564 message_test! {
1565 ty: TimerStatus,
1566 instance: Message::TimerStatus {
1567 status: operand::TimerStatusData {
1568 overlap_warning: false,
1569 media_info: operand::MediaInfo::UnprotectedMedia,
1570 programmed_info: operand::TimerProgrammedInfo::Programmed(operand::ProgrammedInfo::EnoughSpace),
1571 },
1572 },
1573 bytes: [(operand::MediaInfo::UnprotectedMedia as u8) | 0x10 | constants::CEC_OP_PROG_INFO_ENOUGH_SPACE],
1574 extra: [Overfull, Empty],
1575 }
1576
1577 message_test! {
1578 name: _no_duration,
1579 ty: TimerStatus,
1580 instance: Message::TimerStatus {
1581 status: operand::TimerStatusData {
1582 overlap_warning: false,
1583 media_info: operand::MediaInfo::UnprotectedMedia,
1584 programmed_info: operand::TimerProgrammedInfo::Programmed(operand::ProgrammedInfo::NotEnoughSpace {
1585 duration_available: None,
1586 }),
1587 },
1588 },
1589 bytes: [(operand::MediaInfo::UnprotectedMedia as u8) | 0x10 | constants::CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE],
1590 }
1591
1592 message_test! {
1593 name: _duration,
1594 ty: TimerStatus,
1595 instance: Message::TimerStatus {
1596 status: operand::TimerStatusData {
1597 overlap_warning: false,
1598 media_info: operand::MediaInfo::UnprotectedMedia,
1599 programmed_info: operand::TimerProgrammedInfo::Programmed(operand::ProgrammedInfo::NotEnoughSpace {
1600 duration_available: Some(operand::Duration {
1601 hours: operand::DurationHours::try_from(30).unwrap(),
1602 minutes: operand::Minute::try_from(45).unwrap(),
1603 }),
1604 }),
1605 },
1606 },
1607 bytes: [
1608 (operand::MediaInfo::UnprotectedMedia as u8) | 0x10 | constants::CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE,
1609 0x30,
1610 0x45
1611 ],
1612 extra: [Overfull],
1613 }
1614}
1615
1616#[cfg(test)]
1617mod test_cec_version {
1618 use super::*;
1619
1620 message_test! {
1621 ty: CecVersion,
1622 instance: Message::CecVersion {
1623 version: operand::Version::V2_0,
1624 },
1625 bytes: [operand::Version::V2_0 as u8],
1626 extra: [Overfull, Empty],
1627 }
1628}
1629
1630#[cfg(test)]
1631mod test_report_physical_addr {
1632 use super::*;
1633
1634 message_test! {
1635 ty: ReportPhysicalAddr,
1636 instance: Message::ReportPhysicalAddr {
1637 physical_address: PhysicalAddress(0x1234),
1638 device_type: operand::PrimaryDeviceType::Processor,
1639 },
1640 bytes: [0x12, 0x34, operand::PrimaryDeviceType::Processor as u8],
1641 extra: [Overfull, Empty],
1642 }
1643
1644 #[test]
1645 fn test_decoding_missing_operand() {
1646 assert_eq!(
1647 Message::try_from_bytes(&[Opcode::ReportPhysicalAddr as u8, 0x12, 0x34]),
1648 Err(Error::OutOfRange {
1649 expected: Range::AtLeast(4),
1650 got: 3,
1651 quantity: "bytes",
1652 })
1653 );
1654 }
1655
1656 #[test]
1657 fn test_decoding_missing_operand_and_byte() {
1658 assert_eq!(
1659 Message::try_from_bytes(&[Opcode::ReportPhysicalAddr as u8, 0x12]),
1660 Err(Error::OutOfRange {
1661 expected: Range::AtLeast(4),
1662 got: 2,
1663 quantity: "bytes",
1664 })
1665 );
1666 }
1667}
1668
1669#[cfg(test)]
1670mod test_set_menu_language {
1671 use super::*;
1672
1673 message_test! {
1674 ty: SetMenuLanguage,
1675 instance: Message::SetMenuLanguage {
1676 language: [0x12, 0x34, 0x56],
1677 },
1678 bytes: [0x12, 0x34, 0x56],
1679 extra: [Overfull, Empty],
1680 }
1681
1682 #[test]
1683 fn test_decoding_missing_byte() {
1684 assert_eq!(
1685 Message::try_from_bytes(&[Opcode::SetMenuLanguage as u8, 0x12, 0x34]),
1686 Err(Error::OutOfRange {
1687 expected: Range::AtLeast(4),
1688 got: 3,
1689 quantity: "bytes",
1690 })
1691 );
1692 }
1693
1694 #[test]
1695 fn test_decoding_missing_bytes() {
1696 assert_eq!(
1697 Message::try_from_bytes(&[Opcode::SetMenuLanguage as u8, 0x12]),
1698 Err(Error::OutOfRange {
1699 expected: Range::AtLeast(4),
1700 got: 2,
1701 quantity: "bytes",
1702 })
1703 );
1704 }
1705}
1706
1707#[cfg(test)]
1708mod test_deck_control {
1709 use super::*;
1710
1711 message_test! {
1712 ty: DeckControl,
1713 instance: Message::DeckControl {
1714 mode: operand::DeckControlMode::Stop,
1715 },
1716 bytes: [operand::DeckControlMode::Stop as u8],
1717 extra: [Overfull, Empty],
1718 }
1719}
1720
1721#[cfg(test)]
1722mod test_deck_status {
1723 use super::*;
1724
1725 message_test! {
1726 ty: DeckStatus,
1727 instance: Message::DeckStatus {
1728 info: operand::DeckInfo::Record,
1729 },
1730 bytes: [operand::DeckInfo::Record as u8],
1731 extra: [Overfull, Empty],
1732 }
1733}
1734
1735#[cfg(test)]
1736mod test_give_deck_status {
1737 use super::*;
1738
1739 message_test! {
1740 ty: GiveDeckStatus,
1741 instance: Message::GiveDeckStatus {
1742 request: operand::StatusRequest::Once,
1743 },
1744 bytes: [operand::StatusRequest::Once as u8],
1745 extra: [Overfull, Empty],
1746 }
1747}
1748
1749#[cfg(test)]
1750mod test_play {
1751 use super::*;
1752
1753 message_test! {
1754 ty: Play,
1755 instance: Message::Play {
1756 mode: operand::PlayMode::Still,
1757 },
1758 bytes: [operand::PlayMode::Still as u8],
1759 extra: [Overfull, Empty],
1760 }
1761}
1762
1763#[cfg(test)]
1764mod test_give_tuner_device_status {
1765 use super::*;
1766
1767 message_test! {
1768 ty: GiveTunerDeviceStatus,
1769 instance: Message::GiveTunerDeviceStatus {
1770 request: operand::StatusRequest::Once,
1771 },
1772 bytes: [operand::StatusRequest::Once as u8],
1773 extra: [Overfull, Empty],
1774 }
1775}
1776
1777#[cfg(test)]
1778mod test_select_analogue_service {
1779 use super::*;
1780
1781 message_test! {
1782 ty: SelectAnalogueService,
1783 instance: Message::SelectAnalogueService {
1784 service_id: operand::AnalogueServiceId {
1785 broadcast_type: operand::AnalogueBroadcastType::Terrestrial,
1786 frequency: 0x1234,
1787 broadcast_system: operand::BroadcastSystem::PalBG,
1788 },
1789 },
1790 bytes: [
1791 operand::AnalogueBroadcastType::Terrestrial as u8,
1792 0x12,
1793 0x34,
1794 operand::BroadcastSystem::PalBG as u8
1795 ],
1796 extra: [Overfull, Empty],
1797 }
1798}
1799
1800#[cfg(test)]
1801mod test_select_digital_service {
1802 use super::*;
1803
1804 message_test! {
1805 ty: SelectDigitalService,
1806 instance: Message::SelectDigitalService {
1807 service_id: operand::DigitalServiceId::AribGeneric(operand::AribData {
1808 transport_stream_id: 0x1234,
1809 service_id: 0x5678,
1810 original_network_id: 0xABCD,
1811 }),
1812 },
1813 bytes: [
1814 operand::DigitalServiceBroadcastSystem::AribGeneric as u8,
1815 0x12,
1816 0x34,
1817 0x56,
1818 0x78,
1819 0xAB,
1820 0xCD,
1821 ],
1822 extra: [Overfull, Empty],
1823 }
1824}
1825
1826#[cfg(test)]
1827mod test_tuner_device_status {
1828 use super::*;
1829
1830 message_test! {
1831 ty: TunerDeviceStatus,
1832 instance: Message::TunerDeviceStatus {
1833 info: operand::TunerDeviceInfo {
1834 recording: true,
1835 tuner_display_info: operand::TunerDisplayInfo::Analogue,
1836 service_id: operand::ServiceId::Analogue(operand::AnalogueServiceId {
1837 broadcast_type: operand::AnalogueBroadcastType::Terrestrial,
1838 frequency: 0x1234,
1839 broadcast_system: operand::BroadcastSystem::PalBG,
1840 }),
1841 },
1842 },
1843 bytes: [
1844 0x82,
1845 operand::AnalogueBroadcastType::Terrestrial as u8,
1846 0x12,
1847 0x34,
1848 operand::BroadcastSystem::PalBG as u8
1849 ],
1850 extra: [Empty],
1851 }
1852}
1853
1854#[cfg(test)]
1855mod test_device_vendor_id {
1856 use super::*;
1857
1858 message_test! {
1859 ty: DeviceVendorId,
1860 instance: Message::DeviceVendorId {
1861 vendor_id: crate::VendorId([0x12, 0x34, 0x56]),
1862 },
1863 bytes: [0x12, 0x34, 0x56],
1864 extra: [Overfull, Empty],
1865 }
1866}
1867
1868#[cfg(test)]
1869mod test_vendor_command {
1870 use super::*;
1871
1872 message_test! {
1873 name: _empty,
1874 ty: VendorCommand,
1875 instance: Message::VendorCommand {
1876 command: operand::BufferOperand::from_str("").unwrap(),
1877 },
1878 bytes: [],
1879 }
1880
1881 message_test! {
1882 name: _full,
1883 ty: VendorCommand,
1884 instance: Message::VendorCommand {
1885 command: operand::BufferOperand::from_str("12345678901234").unwrap(),
1886 },
1887 bytes: [
1888 b'1',
1889 b'2',
1890 b'3',
1891 b'4',
1892 b'5',
1893 b'6',
1894 b'7',
1895 b'8',
1896 b'9',
1897 b'0',
1898 b'1',
1899 b'2',
1900 b'3',
1901 b'4'
1902 ],
1903 }
1904
1905 #[test]
1906 fn test_opcode() {
1907 assert_eq!(
1908 Message::VendorCommand {
1909 command: operand::BufferOperand::from_str("12345678901234").unwrap(),
1910 }
1911 .opcode(),
1912 Opcode::VendorCommand
1913 );
1914 }
1915}
1916
1917#[cfg(test)]
1918mod test_vendor_command_with_id {
1919 use super::*;
1920
1921 message_test! {
1922 name: _empty,
1923 ty: VendorCommandWithId,
1924 instance: Message::VendorCommandWithId {
1925 vendor_id: crate::VendorId([0x12, 0x34, 0x56]),
1926 vendor_specific_data: operand::BoundedBufferOperand::<11, u8>::from_str("").unwrap(),
1927 },
1928 bytes: [0x12, 0x34, 0x56],
1929 }
1930
1931 message_test! {
1932 name: _full,
1933 ty: VendorCommandWithId,
1934 instance: Message::VendorCommandWithId {
1935 vendor_id: crate::VendorId([0x12, 0x34, 0x56]),
1936 vendor_specific_data: operand::BoundedBufferOperand::<11, u8>::from_str("12345678901").unwrap(),
1937 },
1938 bytes: [
1939 0x12,
1940 0x34,
1941 0x56,
1942 b'1',
1943 b'2',
1944 b'3',
1945 b'4',
1946 b'5',
1947 b'6',
1948 b'7',
1949 b'8',
1950 b'9',
1951 b'0',
1952 b'1',
1953 ],
1954 }
1955
1956 #[test]
1957 fn test_opcode() {
1958 assert_eq!(
1959 Message::VendorCommandWithId {
1960 vendor_id: crate::VendorId([0x12, 0x34, 0x56]),
1961 vendor_specific_data: operand::BoundedBufferOperand::<11, u8>::from_str("")
1962 .unwrap(),
1963 }
1964 .opcode(),
1965 Opcode::VendorCommandWithId
1966 );
1967 }
1968
1969 #[test]
1970 fn test_decoding_missing_operand() {
1971 assert_eq!(
1972 Message::try_from_bytes(&[Opcode::VendorCommandWithId as u8]),
1973 Err(Error::OutOfRange {
1974 expected: Range::AtLeast(4),
1975 got: 1,
1976 quantity: "bytes",
1977 })
1978 );
1979 }
1980}
1981
1982#[cfg(test)]
1983mod test_vendor_remote_button_down {
1984 use super::*;
1985
1986 message_test! {
1987 name: _empty,
1988 ty: VendorRemoteButtonDown,
1989 instance: Message::VendorRemoteButtonDown {
1990 rc_code: operand::BufferOperand::from_str("").unwrap(),
1991 },
1992 bytes: [],
1993 }
1994
1995 message_test! {
1996 name: _full,
1997 ty: VendorRemoteButtonDown,
1998 instance: Message::VendorRemoteButtonDown {
1999 rc_code: operand::BufferOperand::from_str("12345678901234").unwrap(),
2000 },
2001 bytes: [
2002 b'1',
2003 b'2',
2004 b'3',
2005 b'4',
2006 b'5',
2007 b'6',
2008 b'7',
2009 b'8',
2010 b'9',
2011 b'0',
2012 b'1',
2013 b'2',
2014 b'3',
2015 b'4'
2016 ],
2017 }
2018
2019 #[test]
2020 fn test_opcode() {
2021 assert_eq!(
2022 Message::VendorRemoteButtonDown {
2023 rc_code: operand::BufferOperand::from_str("12345678901234").unwrap(),
2024 }
2025 .opcode(),
2026 Opcode::VendorRemoteButtonDown
2027 );
2028 }
2029}
2030
2031#[cfg(test)]
2032mod test_set_osd_string {
2033 use super::*;
2034
2035 message_test! {
2036 name: _empty,
2037 ty: SetOsdString,
2038 instance: Message::SetOsdString {
2039 display_control: operand::DisplayControl::UntilCleared,
2040 osd_string: operand::BoundedBufferOperand::<13, u8>::from_str("").unwrap(),
2041 },
2042 bytes: [operand::DisplayControl::UntilCleared as u8],
2043 }
2044
2045 message_test! {
2046 name: _full,
2047 ty: SetOsdString,
2048 instance: Message::SetOsdString {
2049 display_control: operand::DisplayControl::UntilCleared,
2050 osd_string: operand::BoundedBufferOperand::<13, u8>::from_str("1234567890123").unwrap(),
2051 },
2052 bytes: [
2053 operand::DisplayControl::UntilCleared as u8,
2054 b'1',
2055 b'2',
2056 b'3',
2057 b'4',
2058 b'5',
2059 b'6',
2060 b'7',
2061 b'8',
2062 b'9',
2063 b'0',
2064 b'1',
2065 b'2',
2066 b'3',
2067 ],
2068 }
2069
2070 #[test]
2071 fn test_opcode() {
2072 assert_eq!(
2073 Message::SetOsdString {
2074 display_control: operand::DisplayControl::UntilCleared,
2075 osd_string: operand::BoundedBufferOperand::<13, u8>::from_str("").unwrap(),
2076 }
2077 .opcode(),
2078 Opcode::SetOsdString
2079 );
2080 }
2081
2082 #[test]
2083 fn test_decoding_missing_operand() {
2084 assert_eq!(
2085 Message::try_from_bytes(&[Opcode::SetOsdString as u8]),
2086 Err(Error::OutOfRange {
2087 expected: Range::AtLeast(2),
2088 got: 1,
2089 quantity: "bytes",
2090 })
2091 );
2092 }
2093}
2094
2095#[cfg(test)]
2096mod test_set_osd_name {
2097 use super::*;
2098
2099 message_test! {
2100 name: _empty,
2101 ty: SetOsdName,
2102 instance: Message::SetOsdName {
2103 name: operand::BufferOperand::from_str("").unwrap(),
2104 },
2105 bytes: [],
2106 }
2107
2108 message_test! {
2109 name: _full,
2110 ty: SetOsdName,
2111 instance: Message::SetOsdName {
2112 name: operand::BufferOperand::from_str("12345678901234").unwrap(),
2113 },
2114 bytes: [
2115 b'1',
2116 b'2',
2117 b'3',
2118 b'4',
2119 b'5',
2120 b'6',
2121 b'7',
2122 b'8',
2123 b'9',
2124 b'0',
2125 b'1',
2126 b'2',
2127 b'3',
2128 b'4'
2129 ],
2130 }
2131
2132 #[test]
2133 fn test_opcode() {
2134 assert_eq!(
2135 Message::SetOsdName {
2136 name: operand::BufferOperand::from_str("12345678901234").unwrap(),
2137 }
2138 .opcode(),
2139 Opcode::SetOsdName
2140 );
2141 }
2142}
2143
2144#[cfg(test)]
2145mod test_menu_request {
2146 use super::*;
2147
2148 message_test! {
2149 ty: MenuRequest,
2150 instance: Message::MenuRequest {
2151 request_type: operand::MenuRequestType::Query,
2152 },
2153 bytes: [operand::MenuRequestType::Query as u8],
2154 extra: [Overfull, Empty],
2155 }
2156}
2157
2158#[cfg(test)]
2159mod test_menu_state {
2160 use super::*;
2161
2162 message_test! {
2163 ty: MenuStatus,
2164 instance: Message::MenuStatus {
2165 state: operand::MenuState::Deactivated,
2166 },
2167 bytes: [operand::MenuState::Deactivated as u8],
2168 extra: [Overfull, Empty],
2169 }
2170}
2171
2172#[cfg(test)]
2173mod test_user_control_pressed {
2174 use super::*;
2175
2176 message_test! {
2177 ty: UserControlPressed,
2178 instance: Message::UserControlPressed {
2179 ui_command: operand::UiCommand::Play,
2180 },
2181 bytes: [constants::CEC_OP_UI_CMD_PLAY as u8],
2182 extra: [Overfull, Empty],
2183 }
2184}
2185
2186#[cfg(test)]
2187mod test_report_power_status {
2188 use super::*;
2189
2190 message_test! {
2191 ty: ReportPowerStatus,
2192 instance: Message::ReportPowerStatus {
2193 status: operand::PowerStatus::ToOn,
2194 },
2195 bytes: [operand::PowerStatus::ToOn as u8],
2196 extra: [Overfull, Empty],
2197 }
2198}
2199
2200#[cfg(test)]
2201mod test_feature_abort {
2202 use super::*;
2203
2204 message_test! {
2205 ty: FeatureAbort,
2206 instance: Message::FeatureAbort {
2207 opcode: Opcode::FeatureAbort.into(),
2208 abort_reason: operand::AbortReason::IncorrectMode,
2209 },
2210 bytes: [Opcode::FeatureAbort as u8, operand::AbortReason::IncorrectMode as u8],
2211 extra: [Overfull, Empty],
2212 }
2213
2214 #[test]
2215 fn test_decoding_missing_operand() {
2216 assert_eq!(
2217 Message::try_from_bytes(&[Opcode::FeatureAbort as u8, Opcode::FeatureAbort as u8]),
2218 Err(Error::OutOfRange {
2219 expected: Range::AtLeast(3),
2220 got: 2,
2221 quantity: "bytes",
2222 })
2223 );
2224 }
2225}
2226
2227#[cfg(test)]
2228mod test_report_audio_status {
2229 use super::*;
2230
2231 message_test! {
2232 ty: ReportAudioStatus,
2233 instance: Message::ReportAudioStatus {
2234 status: operand::AudioStatus::new().with_volume(2).with_mute(true),
2235 },
2236 bytes: [0x82],
2237 extra: [Overfull, Empty],
2238 }
2239}
2240
2241#[cfg(test)]
2242mod test_report_short_audio_descriptor {
2243 use super::*;
2244
2245 message_test! {
2246 name: _empty,
2247 ty: ReportShortAudioDescriptor,
2248 instance: Message::ReportShortAudioDescriptor {
2249 descriptors: operand::BoundedBufferOperand::default(),
2250 },
2251 bytes: [],
2252 }
2253
2254 message_test! {
2255 name: _full,
2256 ty: ReportShortAudioDescriptor,
2257 instance: Message::ReportShortAudioDescriptor {
2258 descriptors: operand::BoundedBufferOperand::try_from([
2259 [0x01, 0x23, 0x45],
2260 [0x67, 0x89, 0xAB],
2261 [0xCD, 0xEF, 0xFE],
2262 [0xDC, 0xBA, 0x98]
2263 ].as_ref())
2264 .unwrap(),
2265 },
2266 bytes: [
2267 0x01,
2268 0x23,
2269 0x45,
2270 0x67,
2271 0x89,
2272 0xAB,
2273 0xCD,
2274 0xEF,
2275 0xFE,
2276 0xDC,
2277 0xBA,
2278 0x98,
2279 ],
2280 }
2281
2282 #[test]
2283 fn test_opcode() {
2284 assert_eq!(
2285 Message::ReportShortAudioDescriptor {
2286 descriptors: operand::BoundedBufferOperand::try_from(
2287 [
2288 [0x01, 0x23, 0x45],
2289 [0x67, 0x89, 0xAB],
2290 [0xCD, 0xEF, 0xFE],
2291 [0xDC, 0xBA, 0x98]
2292 ]
2293 .as_ref()
2294 )
2295 .unwrap(),
2296 }
2297 .opcode(),
2298 Opcode::ReportShortAudioDescriptor
2299 );
2300 }
2301}
2302
2303#[cfg(test)]
2304mod test_request_short_audio_descriptor {
2305 use super::*;
2306
2307 message_test! {
2308 name: _empty,
2309 ty: RequestShortAudioDescriptor,
2310 instance: Message::RequestShortAudioDescriptor {
2311 descriptors: operand::BoundedBufferOperand::default(),
2312 },
2313 bytes: [],
2314 }
2315
2316 message_test! {
2317 name: _full,
2318 ty: RequestShortAudioDescriptor,
2319 instance: Message::RequestShortAudioDescriptor {
2320 descriptors: operand::BoundedBufferOperand::try_from([
2321 operand::AudioFormatIdAndCode::new()
2322 .with_code(1)
2323 .with_id(operand::AudioFormatId::CEA861),
2324 operand::AudioFormatIdAndCode::new()
2325 .with_code(2)
2326 .with_id(operand::AudioFormatId::CEA861),
2327 operand::AudioFormatIdAndCode::new()
2328 .with_code(3)
2329 .with_id(operand::AudioFormatId::CEA861Cxt),
2330 operand::AudioFormatIdAndCode::new()
2331 .with_code(4)
2332 .with_id(operand::AudioFormatId::CEA861Cxt),
2333 ].as_ref())
2334 .unwrap(),
2335 },
2336 bytes: [0x01, 0x02, 0x43, 0x44],
2337 }
2338
2339 #[test]
2340 fn test_opcode() {
2341 assert_eq!(
2342 Message::RequestShortAudioDescriptor {
2343 descriptors: operand::BoundedBufferOperand::try_from(
2344 [
2345 operand::AudioFormatIdAndCode::new()
2346 .with_code(1)
2347 .with_id(operand::AudioFormatId::CEA861),
2348 operand::AudioFormatIdAndCode::new()
2349 .with_code(2)
2350 .with_id(operand::AudioFormatId::CEA861),
2351 operand::AudioFormatIdAndCode::new()
2352 .with_code(3)
2353 .with_id(operand::AudioFormatId::CEA861Cxt),
2354 operand::AudioFormatIdAndCode::new()
2355 .with_code(4)
2356 .with_id(operand::AudioFormatId::CEA861Cxt),
2357 ]
2358 .as_ref()
2359 )
2360 .unwrap(),
2361 }
2362 .opcode(),
2363 Opcode::RequestShortAudioDescriptor
2364 );
2365 }
2366}
2367
2368#[cfg(test)]
2369mod test_set_system_audio_mode {
2370 use super::*;
2371
2372 message_test! {
2373 ty: SetSystemAudioMode,
2374 instance: Message::SetSystemAudioMode {
2375 status: true,
2376 },
2377 bytes: [0x01],
2378 extra: [Overfull, Empty],
2379 }
2380}
2381
2382#[cfg(test)]
2383mod test_system_audio_mode_request {
2384 use super::*;
2385
2386 message_test! {
2387 ty: SystemAudioModeRequest,
2388 instance: Message::SystemAudioModeRequest {
2389 physical_address: PhysicalAddress(0x1234),
2390 },
2391 bytes: [0x12, 0x34],
2392 extra: [Overfull, Empty],
2393 }
2394
2395 #[test]
2396 fn test_decoding_missing_byte() {
2397 assert_eq!(
2398 Message::try_from_bytes(&[Opcode::SystemAudioModeRequest as u8, 0x12]),
2399 Err(Error::OutOfRange {
2400 expected: Range::AtLeast(3),
2401 got: 2,
2402 quantity: "bytes",
2403 })
2404 );
2405 }
2406}
2407
2408#[cfg(test)]
2409mod test_system_audio_mode_status {
2410 use super::*;
2411
2412 message_test! {
2413 ty: SystemAudioModeStatus,
2414 instance: Message::SystemAudioModeStatus {
2415 status: true,
2416 },
2417 bytes: [0x01],
2418 extra: [Overfull, Empty],
2419 }
2420}
2421
2422#[cfg(test)]
2423mod test_set_audio_rate {
2424 use super::*;
2425
2426 message_test! {
2427 ty: SetAudioRate,
2428 instance: Message::SetAudioRate {
2429 audio_rate: operand::AudioRate::WideFast,
2430 },
2431 bytes: [operand::AudioRate::WideFast as u8],
2432 extra: [Overfull, Empty],
2433 }
2434}
2435
2436#[cfg(test)]
2437mod test_cdc_message {
2438 use super::*;
2439
2440 message_test! {
2441 ty: CdcMessage,
2442 instance: Message::CdcMessage {
2443 initiator: PhysicalAddress(0x0123),
2444 message: CdcMessage::HecRequestDeactivation {
2445 terminating_address1: PhysicalAddress(0x4567),
2446 terminating_address2: PhysicalAddress(0x89AB),
2447 terminating_address3: PhysicalAddress(0xCDEF)
2448 },
2449 },
2450 bytes: [0x01, 0x23, CdcOpcode::HecRequestDeactivation as u8, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF],
2451 extra: [Overfull, Empty],
2452 }
2453
2454 #[test]
2455 fn test_decoding_missing_operand() {
2456 assert_eq!(
2457 Message::try_from_bytes(&[
2458 Opcode::CdcMessage as u8,
2459 0x01,
2460 0x23,
2461 CdcOpcode::HecRequestDeactivation as u8
2462 ]),
2463 Err(Error::OutOfRange {
2464 expected: Range::AtLeast(10),
2465 got: 4,
2466 quantity: "bytes",
2467 })
2468 );
2469 }
2470
2471 #[test]
2472 fn test_decoding_missing_opcode() {
2473 assert_eq!(
2474 Message::try_from_bytes(&[Opcode::CdcMessage as u8, 0x01, 0x23]),
2475 Err(Error::OutOfRange {
2476 expected: Range::AtLeast(4),
2477 got: 3,
2478 quantity: "bytes",
2479 })
2480 );
2481 }
2482
2483 #[test]
2484 fn test_decoding_missing_opcode_and_byte() {
2485 assert_eq!(
2486 Message::try_from_bytes(&[Opcode::CdcMessage as u8, 0x01]),
2487 Err(Error::OutOfRange {
2488 expected: Range::AtLeast(4),
2489 got: 2,
2490 quantity: "bytes",
2491 })
2492 );
2493 }
2494}
2495
2496#[cfg(test)]
2497mod test_report_features {
2498 use super::*;
2499
2500 message_test! {
2501 name: _empty,
2502 ty: ReportFeatures,
2503 instance: Message::ReportFeatures {
2504 version: operand::Version::V2_0,
2505 device_types: operand::AllDeviceTypes::PLAYBACK,
2506 rc_profile: operand::RcProfile::new(
2507 operand::RcProfile1::Source(operand::RcProfileSource::all())),
2508 device_features: operand::DeviceFeatures::new(operand::DeviceFeatures1::all()),
2509 },
2510 bytes: [
2511 operand::Version::V2_0 as u8,
2512 operand::AllDeviceTypes::PLAYBACK.bits(),
2513 operand::RcProfileSource::all().bits(),
2514 operand::DeviceFeatures1::all().bits()
2515 ],
2516 extra: [Overfull],
2517 }
2518
2519 message_test! {
2520 name: _extra_rc_profiles,
2521 ty: ReportFeatures,
2522 instance: Message::ReportFeatures {
2523 version: operand::Version::V2_0,
2524 device_types: operand::AllDeviceTypes::PLAYBACK,
2525 rc_profile: operand::RcProfile {
2526 rc_profile_1: operand::RcProfile1::Source(operand::RcProfileSource::all()),
2527 rc_profile_n: operand::BoundedBufferOperand::try_from([
2528 0,
2529 0,
2530 0,
2531 0,
2532 0,
2533 0,
2534 0,
2535 0,
2536 0
2537 ].as_ref()).unwrap(),
2538 },
2539 device_features: operand::DeviceFeatures::new(operand::DeviceFeatures1::all()),
2540 },
2541 bytes: [
2542 operand::Version::V2_0 as u8,
2543 operand::AllDeviceTypes::PLAYBACK.bits(),
2544 operand::RcProfileSource::all().bits() | 0x80,
2545 0x80,
2546 0x80,
2547 0x80,
2548 0x80,
2549 0x80,
2550 0x80,
2551 0x80,
2552 0x80,
2553 0x0,
2554 operand::DeviceFeatures1::all().bits()
2555 ],
2556 }
2557
2558 message_test! {
2559 name: _extra_device_features,
2560 ty: ReportFeatures,
2561 instance: Message::ReportFeatures {
2562 version: operand::Version::V2_0,
2563 device_types: operand::AllDeviceTypes::PLAYBACK,
2564 rc_profile: operand::RcProfile::new(operand::RcProfile1::Source(operand::RcProfileSource::all())),
2565 device_features: operand::DeviceFeatures {
2566 device_features_1: operand::DeviceFeatures1::all(),
2567 device_features_n: operand::BoundedBufferOperand::try_from([
2568 0,
2569 0,
2570 0,
2571 0,
2572 0,
2573 0,
2574 0,
2575 0,
2576 0
2577 ].as_ref()).unwrap(),
2578 },
2579 },
2580 bytes: [
2581 operand::Version::V2_0 as u8,
2582 operand::AllDeviceTypes::PLAYBACK.bits(),
2583 operand::RcProfileSource::all().bits(),
2584 operand::DeviceFeatures1::all().bits() | 0x80,
2585 0x80,
2586 0x80,
2587 0x80,
2588 0x80,
2589 0x80,
2590 0x80,
2591 0x80,
2592 0x80,
2593 0x0,
2594 ],
2595 }
2596
2597 message_test! {
2598 name: _balanced,
2599 ty: ReportFeatures,
2600 instance: Message::ReportFeatures {
2601 version: operand::Version::V2_0,
2602 device_types: operand::AllDeviceTypes::PLAYBACK,
2603 rc_profile: operand::RcProfile {
2604 rc_profile_1: operand::RcProfile1::Source(operand::RcProfileSource::all()),
2605 rc_profile_n: operand::BoundedBufferOperand::try_from([
2606 0,
2607 0,
2608 0,
2609 0,
2610 0
2611 ].as_ref()).unwrap(),
2612 },
2613 device_features: operand::DeviceFeatures {
2614 device_features_1: operand::DeviceFeatures1::all(),
2615 device_features_n: operand::BoundedBufferOperand::try_from([
2616 0,
2617 0,
2618 0,
2619 0,
2620 0
2621 ].as_ref()).unwrap(),
2622 },
2623 },
2624 bytes: [
2625 operand::Version::V2_0 as u8,
2626 operand::AllDeviceTypes::PLAYBACK.bits(),
2627 operand::RcProfileSource::all().bits() | 0x80,
2628 0x80,
2629 0x80,
2630 0x80,
2631 0x80,
2632 0x0,
2633 operand::DeviceFeatures1::all().bits() | 0x80,
2634 0x80,
2635 0x80,
2636 0x80,
2637 0x80,
2638 0x0,
2639 ],
2640 }
2641
2642 #[test]
2643 fn test_opcode() {
2644 assert_eq!(
2645 Message::ReportFeatures {
2646 version: operand::Version::V2_0,
2647 device_types: operand::AllDeviceTypes::PLAYBACK,
2648 rc_profile: operand::RcProfile::new(operand::RcProfile1::Source(
2649 operand::RcProfileSource::all()
2650 )),
2651 device_features: operand::DeviceFeatures::new(operand::DeviceFeatures1::all()),
2652 }
2653 .opcode(),
2654 Opcode::ReportFeatures
2655 );
2656 }
2657
2658 #[test]
2659 fn test_decoding_missing_operand_1() {
2660 assert_eq!(
2661 Message::try_from_bytes(&[
2662 Opcode::ReportFeatures as u8,
2663 operand::Version::V2_0 as u8,
2664 operand::AllDeviceTypes::PLAYBACK.bits(),
2665 operand::RcProfileSource::all().bits(),
2666 ]),
2667 Err(Error::OutOfRange {
2668 expected: Range::AtLeast(5),
2669 got: 4,
2670 quantity: "bytes",
2671 })
2672 );
2673 }
2674
2675 #[test]
2676 fn test_decoding_missing_operand_2() {
2677 assert_eq!(
2678 Message::try_from_bytes(&[
2679 Opcode::ReportFeatures as u8,
2680 operand::Version::V2_0 as u8,
2681 operand::AllDeviceTypes::PLAYBACK.bits(),
2682 ]),
2683 Err(Error::OutOfRange {
2684 expected: Range::AtLeast(5),
2685 got: 3,
2686 quantity: "bytes",
2687 })
2688 );
2689 }
2690
2691 #[test]
2692 fn test_decoding_missing_operand_3() {
2693 assert_eq!(
2694 Message::try_from_bytes(&[Opcode::ReportFeatures as u8, operand::Version::V2_0 as u8]),
2695 Err(Error::OutOfRange {
2696 expected: Range::AtLeast(5),
2697 got: 2,
2698 quantity: "bytes",
2699 })
2700 );
2701 }
2702
2703 #[test]
2704 fn test_decoding_missing_operands() {
2705 assert_eq!(
2706 Message::try_from_bytes(&[Opcode::ReportFeatures as u8]),
2707 Err(Error::OutOfRange {
2708 expected: Range::AtLeast(5),
2709 got: 1,
2710 quantity: "bytes",
2711 })
2712 );
2713 }
2714}
2715
2716#[cfg(test)]
2717mod test_request_current_latency {
2718 use super::*;
2719
2720 message_test! {
2721 ty: RequestCurrentLatency,
2722 instance: Message::RequestCurrentLatency {
2723 physical_address: PhysicalAddress(0x1234),
2724 },
2725 bytes: [0x12, 0x34],
2726 extra: [Overfull, Empty],
2727 }
2728
2729 #[test]
2730 fn test_decoding_missing_byte() {
2731 assert_eq!(
2732 Message::try_from_bytes(&[Opcode::RequestCurrentLatency as u8, 0x12]),
2733 Err(Error::OutOfRange {
2734 expected: Range::AtLeast(3),
2735 got: 2,
2736 quantity: "bytes",
2737 })
2738 );
2739 }
2740}
2741
2742#[cfg(test)]
2743mod test_report_current_latency {
2744 use super::*;
2745
2746 message_test! {
2747 ty: ReportCurrentLatency,
2748 instance: Message::ReportCurrentLatency {
2749 physical_address: PhysicalAddress(0x1234),
2750 video_latency: operand::Delay::try_from(0x56).unwrap(),
2751 flags: operand::LatencyFlags::new()
2752 .with_audio_out_compensated(operand::AudioOutputCompensated::PartialDelay)
2753 .with_low_latency_mode(true),
2754 audio_output_delay: Some(operand::Delay::try_from(0x78).unwrap()),
2755 },
2756 bytes: [0x12, 0x34, 0x56, 0x07, 0x78],
2757 extra: [Overfull, Empty],
2758 }
2759
2760 message_test! {
2761 name: _no_delay,
2762 ty: ReportCurrentLatency,
2763 instance: Message::ReportCurrentLatency {
2764 physical_address: PhysicalAddress(0x1234),
2765 video_latency: operand::Delay::try_from(0x56).unwrap(),
2766 flags: operand::LatencyFlags::new()
2767 .with_audio_out_compensated(operand::AudioOutputCompensated::NoDelay)
2768 .with_low_latency_mode(true),
2769 audio_output_delay: None,
2770 },
2771 bytes: [0x12, 0x34, 0x56, 0x06],
2772 }
2773
2774 #[test]
2775 fn test_decoding_missing_operand_1() {
2776 assert_eq!(
2777 Message::try_from_bytes(&[Opcode::ReportCurrentLatency as u8, 0x12, 0x34, 0x56]),
2778 Err(Error::OutOfRange {
2779 expected: Range::AtLeast(5),
2780 got: 4,
2781 quantity: "bytes",
2782 })
2783 );
2784 }
2785
2786 #[test]
2787 fn test_decoding_missing_operand_2() {
2788 assert_eq!(
2789 Message::try_from_bytes(&[Opcode::ReportCurrentLatency as u8, 0x12, 0x34]),
2790 Err(Error::OutOfRange {
2791 expected: Range::AtLeast(5),
2792 got: 3,
2793 quantity: "bytes",
2794 })
2795 );
2796 }
2797
2798 #[test]
2799 fn test_decoding_missing_operand_2_and_byte() {
2800 assert_eq!(
2801 Message::try_from_bytes(&[Opcode::ReportCurrentLatency as u8, 0x12]),
2802 Err(Error::OutOfRange {
2803 expected: Range::AtLeast(5),
2804 got: 2,
2805 quantity: "bytes",
2806 })
2807 );
2808 }
2809}