pub struct CecDevice(/* private fields */);
Expand description
A handle on a CEC device.
Implementations§
Source§impl CecDevice
impl CecDevice
Sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self>
Open a CEC device. Typically /dev/cecX
let cec = CecDevice::open("/dev/cec0")?;
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
More examples
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas()?;
12 println!("capas {:?}", capas);
13
14 // clear existing logical addresses
15 let log = CecLogAddrs::default();
16 cec.set_log(log)?;
17
18 // set new address (PLAYBACK)
19 let log = CecLogAddrs::new(
20 VendorID::NONE,
21 Version::V1_4,
22 "pi4".to_string().try_into().unwrap(),
23 &[CecPrimDevType::PLAYBACK],
24 &[CecLogAddrType::PLAYBACK],
25 );
26 cec.set_log(log)?;
27
28 // ask Audiosystem to turn on (from standby)
29 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;
30
31 sleep(Duration::from_millis(10000));
32
33 // ask Audiosystem to switch to standby
34 cec.transmit(
35 CecLogicalAddress::Playback2,
36 CecLogicalAddress::Audiosystem,
37 CecOpcode::Standby,
38 )?;
39
40 sleep(Duration::from_millis(10000));
41
42 // ask TV to turn on
43 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;
44
45 sleep(Duration::from_millis(10000));
46
47 // ask TV to switch to standby
48 cec.transmit(
49 CecLogicalAddress::Playback2,
50 CecLogicalAddress::Tv,
51 CecOpcode::Standby,
52 )?;
53
54 Ok(())
55}
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}
Sourcepub fn poll<T: Into<PollTimeout>>(
&self,
events: PollFlags,
timeout: T,
) -> Result<PollFlags>
Available on crate feature poll
only.
pub fn poll<T: Into<PollTimeout>>( &self, events: PollFlags, timeout: T, ) -> Result<PollFlags>
poll
only.Poll for
- newly received Messages (
POLLIN
andPOLLRDNORM
flags) - room in the transmit queue (
POLLOUT
andPOLLWRNORM
flags) - events in the event queue (
POLLPRI
flag)
Specifying a PollTimeout::NONE
in timeout means an infinite timeout.
Specifying a timeout of PollTimeout::ZERO
causes poll() to return immediately, even if no file descriptors are ready.
You might want to look into polling multiple file descriptors at once by using CecDevice::as_raw_fd or tokio::AsyncCec.
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
Sourcepub fn get_capas(&self) -> Result<CecCaps>
pub fn get_capas(&self) -> Result<CecCaps>
query information on the devices capabilities. See CecCaps
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
More examples
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas()?;
12 println!("capas {:?}", capas);
13
14 // clear existing logical addresses
15 let log = CecLogAddrs::default();
16 cec.set_log(log)?;
17
18 // set new address (PLAYBACK)
19 let log = CecLogAddrs::new(
20 VendorID::NONE,
21 Version::V1_4,
22 "pi4".to_string().try_into().unwrap(),
23 &[CecPrimDevType::PLAYBACK],
24 &[CecLogAddrType::PLAYBACK],
25 );
26 cec.set_log(log)?;
27
28 // ask Audiosystem to turn on (from standby)
29 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;
30
31 sleep(Duration::from_millis(10000));
32
33 // ask Audiosystem to switch to standby
34 cec.transmit(
35 CecLogicalAddress::Playback2,
36 CecLogicalAddress::Audiosystem,
37 CecOpcode::Standby,
38 )?;
39
40 sleep(Duration::from_millis(10000));
41
42 // ask TV to turn on
43 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;
44
45 sleep(Duration::from_millis(10000));
46
47 // ask TV to switch to standby
48 cec.transmit(
49 CecLogicalAddress::Playback2,
50 CecLogicalAddress::Tv,
51 CecOpcode::Standby,
52 )?;
53
54 Ok(())
55}
Sourcepub fn set_mode(
&self,
initiator: CecModeInitiator,
follower: CecModeFollower,
) -> Result<()>
pub fn set_mode( &self, initiator: CecModeInitiator, follower: CecModeFollower, ) -> Result<()>
Change this handles mode.
By default any filehandle can use RECEIVE and TRANSMIT.
This sets initiator and/or follower mode which can be exclusive depending on the chosen mode.
The initiator is the filehandle that is used to initiate messages, i.e. it commands other CEC devices.
The follower is the filehandle that receives messages sent to the CEC adapter and processes them.
The CEC framework will process core messages unless requested otherwise by the follower.
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
More examples
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}
pub fn get_mode(&self) -> Result<(CecModeInitiator, CecModeFollower)>
Sourcepub fn set_phys(&self, addr: CecPhysicalAddress) -> Result<()>
pub fn set_phys(&self, addr: CecPhysicalAddress) -> Result<()>
Set the physical address of the adapter.
Only available if Capabilities::PHYS_ADDR is set. May not be available if that is handled internally. Not possible with CecModeInitiator::None.
To clear an existing physical address use CecPhysicalAddress::INVALID. The adapter will go to the unconfigured state.
If logical address types have been defined (see CecDevice::set_log), then it will block until all requested logical addresses have been claimed. If the file descriptor is in non-blocking mode then it will not wait for the logical addresses to be claimed, instead it just returns.
A CecEvent::StateChange event is sent when the physical address changes.
Sourcepub fn get_phys(&self) -> Result<CecPhysicalAddress>
pub fn get_phys(&self) -> Result<CecPhysicalAddress>
Query physical addresses If nothing is connected, then phys_addr is CecPhysicalAddress::INVALID.
Examples found in repository?
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}
Sourcepub fn set_log(&self, log: CecLogAddrs) -> Result<()>
pub fn set_log(&self, log: CecLogAddrs) -> Result<()>
Set logical address.
Only available if Capabilities::LOG_ADDRS is set. Not possible with CecModeInitiator::None.
To clear existing logical addresses set CecLogAddrs::default(). The adapter will go to the unconfigured state. Attempting to call set_log when logical address types are already defined will return with error EBUSY.
If the physical address is valid (see CecDevice::set_phys), then it will block until all requested logical addresses have been claimed. If the file descriptor is in non-blocking mode then it will not wait for the logical addresses to be claimed, instead it just returns.
A CecEvent::StateChange event is sent when the logical addresses are claimed or cleared.
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas()?;
12 println!("capas {:?}", capas);
13
14 // clear existing logical addresses
15 let log = CecLogAddrs::default();
16 cec.set_log(log)?;
17
18 // set new address (PLAYBACK)
19 let log = CecLogAddrs::new(
20 VendorID::NONE,
21 Version::V1_4,
22 "pi4".to_string().try_into().unwrap(),
23 &[CecPrimDevType::PLAYBACK],
24 &[CecLogAddrType::PLAYBACK],
25 );
26 cec.set_log(log)?;
27
28 // ask Audiosystem to turn on (from standby)
29 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;
30
31 sleep(Duration::from_millis(10000));
32
33 // ask Audiosystem to switch to standby
34 cec.transmit(
35 CecLogicalAddress::Playback2,
36 CecLogicalAddress::Audiosystem,
37 CecOpcode::Standby,
38 )?;
39
40 sleep(Duration::from_millis(10000));
41
42 // ask TV to turn on
43 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;
44
45 sleep(Duration::from_millis(10000));
46
47 // ask TV to switch to standby
48 cec.transmit(
49 CecLogicalAddress::Playback2,
50 CecLogicalAddress::Tv,
51 CecOpcode::Standby,
52 )?;
53
54 Ok(())
55}
Sourcepub fn get_log(&self) -> Result<CecLogAddrs>
pub fn get_log(&self) -> Result<CecLogAddrs>
Query logical addresses
Examples found in repository?
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}
Sourcepub fn get_event(&self) -> Result<CecEvent>
pub fn get_event(&self) -> Result<CecEvent>
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
Sourcepub fn turn_on(
&self,
from: CecLogicalAddress,
to: CecLogicalAddress,
) -> Result<()>
pub fn turn_on( &self, from: CecLogicalAddress, to: CecLogicalAddress, ) -> Result<()>
wake a remote cec device from standby
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas()?;
12 println!("capas {:?}", capas);
13
14 // clear existing logical addresses
15 let log = CecLogAddrs::default();
16 cec.set_log(log)?;
17
18 // set new address (PLAYBACK)
19 let log = CecLogAddrs::new(
20 VendorID::NONE,
21 Version::V1_4,
22 "pi4".to_string().try_into().unwrap(),
23 &[CecPrimDevType::PLAYBACK],
24 &[CecLogAddrType::PLAYBACK],
25 );
26 cec.set_log(log)?;
27
28 // ask Audiosystem to turn on (from standby)
29 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;
30
31 sleep(Duration::from_millis(10000));
32
33 // ask Audiosystem to switch to standby
34 cec.transmit(
35 CecLogicalAddress::Playback2,
36 CecLogicalAddress::Audiosystem,
37 CecOpcode::Standby,
38 )?;
39
40 sleep(Duration::from_millis(10000));
41
42 // ask TV to turn on
43 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;
44
45 sleep(Duration::from_millis(10000));
46
47 // ask TV to switch to standby
48 cec.transmit(
49 CecLogicalAddress::Playback2,
50 CecLogicalAddress::Tv,
51 CecOpcode::Standby,
52 )?;
53
54 Ok(())
55}
Sourcepub fn keypress(
&self,
from: CecLogicalAddress,
to: CecLogicalAddress,
key: CecUserControlCode,
) -> Result<()>
pub fn keypress( &self, from: CecLogicalAddress, to: CecLogicalAddress, key: CecUserControlCode, ) -> Result<()>
send a button press to a remote cec device
Sourcepub fn transmit(
&self,
from: CecLogicalAddress,
to: CecLogicalAddress,
opcode: CecOpcode,
) -> Result<()>
pub fn transmit( &self, from: CecLogicalAddress, to: CecLogicalAddress, opcode: CecOpcode, ) -> Result<()>
send a cec command without parameters to a remote device
transmitting from an address not in CecLogAddrMask will return InvalidInput
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas()?;
12 println!("capas {:?}", capas);
13
14 // clear existing logical addresses
15 let log = CecLogAddrs::default();
16 cec.set_log(log)?;
17
18 // set new address (PLAYBACK)
19 let log = CecLogAddrs::new(
20 VendorID::NONE,
21 Version::V1_4,
22 "pi4".to_string().try_into().unwrap(),
23 &[CecPrimDevType::PLAYBACK],
24 &[CecLogAddrType::PLAYBACK],
25 );
26 cec.set_log(log)?;
27
28 // ask Audiosystem to turn on (from standby)
29 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;
30
31 sleep(Duration::from_millis(10000));
32
33 // ask Audiosystem to switch to standby
34 cec.transmit(
35 CecLogicalAddress::Playback2,
36 CecLogicalAddress::Audiosystem,
37 CecOpcode::Standby,
38 )?;
39
40 sleep(Duration::from_millis(10000));
41
42 // ask TV to turn on
43 cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;
44
45 sleep(Duration::from_millis(10000));
46
47 // ask TV to switch to standby
48 cec.transmit(
49 CecLogicalAddress::Playback2,
50 CecLogicalAddress::Tv,
51 CecOpcode::Standby,
52 )?;
53
54 Ok(())
55}
Sourcepub fn transmit_data(
&self,
from: CecLogicalAddress,
to: CecLogicalAddress,
opcode: CecOpcode,
data: &[u8],
) -> Result<()>
pub fn transmit_data( &self, from: CecLogicalAddress, to: CecLogicalAddress, opcode: CecOpcode, data: &[u8], ) -> Result<()>
send a cec command with parameters to a remote device.
The format of data
depends on the opcode
.
Examples found in repository?
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}
Sourcepub fn request_data(
&self,
from: CecLogicalAddress,
to: CecLogicalAddress,
opcode: CecOpcode,
data: &[u8],
wait_for: CecOpcode,
) -> Result<Vec<u8>>
pub fn request_data( &self, from: CecLogicalAddress, to: CecLogicalAddress, opcode: CecOpcode, data: &[u8], wait_for: CecOpcode, ) -> Result<Vec<u8>>
send a cec command with parameters and wait for a reply with opcode wait_for
. Then return its payload.
returns timeout if no reply is received
if let Ok(audio) = cec.request_data(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem, CecOpcode::GiveAudioStatus, b"", CecOpcode::ReportAudioStatus){
let v = audio[0];
println!("Muted: {}", v & 0x80);
println!("Vol: {}%", v & 0x7f);
}
Sourcepub fn rec(&self) -> Result<CecMsg>
pub fn rec(&self) -> Result<CecMsg>
receive a single message. block forever the available messages depend on CecModeFollower
Examples found in repository?
9fn main() -> std::io::Result<()> {
10 let cec = CecDevice::open("/dev/cec0")?;
11 let capas = cec.get_capas();
12 println!("capas {:?}", capas);
13 cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;
14
15 loop {
16 let f = cec.poll(
17 PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
18 PollTimeout::NONE,
19 )?;
20
21 if f.intersects(PollFlags::POLLPRI) {
22 let evt = cec.get_event()?;
23 println!("evt {:x?}", evt);
24 }
25 if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
26 let msg = cec.rec()?;
27
28 if msg.is_ok() {
29 match (msg.initiator(), msg.destination(), msg.opcode()) {
30 (i, d, Some(Ok(o))) => {
31 println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
32 }
33 _ => println!("msg {:x?}", msg),
34 }
35 } else {
36 println!("msg {:x?}", msg);
37 }
38 }
39 }
40}
More examples
8fn main() -> std::io::Result<()> {
9 let cec = CecDevice::open("/dev/cec0")?;
10
11 cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;
12
13 let physical_addr = cec.get_phys()?;
14
15 loop {
16 let msg = cec.rec()?;
17 match msg.opcode() {
18 Some(Ok(CecOpcode::ActiveSource))
19 | Some(Ok(CecOpcode::RoutingInformation))
20 | Some(Ok(CecOpcode::SetStreamPath))
21 if physical_addr == msg.parameters() =>
22 {
23 // this is not done by the core
24 println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
25 cec.transmit_data(
26 CecLogicalAddress::Playback2,
27 CecLogicalAddress::UnregisteredBroadcast,
28 CecOpcode::ActiveSource,
29 &physical_addr.to_bytes(),
30 )?;
31 }
32 Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
33 Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
34 //dont answer brodcasts
35 println!(
36 "{:?}: {:?} {:x?}",
37 msg.initiator(),
38 opcode,
39 msg.parameters()
40 );
41 }
42 Some(Ok(CecOpcode::GetCecVersion)) => {
43 cec.transmit_data(
44 msg.destination(),
45 msg.initiator(),
46 CecOpcode::CecVersion,
47 &[Version::V1_3A.into()],
48 )?;
49 }
50 Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
51 cec.transmit_data(
52 msg.destination(),
53 msg.initiator(),
54 CecOpcode::FeatureAbort,
55 &[
56 CecOpcode::GiveDeviceVendorId.into(),
57 CecAbortReason::Unrecognized.into(),
58 ],
59 )?; /*
60 cec.transmit_data(
61 msg.destination(),
62 msg.initiator(),
63 CecOpcode::DeviceVendorId,
64 &[0,0,0])?;*/
65 }
66 Some(Ok(CecOpcode::Abort)) => {
67 cec.transmit_data(
68 msg.destination(),
69 msg.initiator(),
70 CecOpcode::FeatureAbort,
71 &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
72 )?;
73 }
74 Some(Ok(CecOpcode::GivePhysicalAddr)) => {
75 let l = cec.get_log()?;
76 let mut addr = Vec::with_capacity(3);
77 if let Some(log) = l.addresses().first() {
78 addr.extend_from_slice(&physical_addr.to_bytes());
79 addr.push((*log).into());
80
81 cec.transmit_data(
82 msg.destination(),
83 msg.initiator(),
84 CecOpcode::ReportPhysicalAddr,
85 &addr,
86 )?;
87 } //else no address yet?!?!?
88 }
89 Some(Ok(CecOpcode::GiveOsdName)) => {
90 cec.transmit_data(
91 msg.destination(),
92 msg.initiator(),
93 CecOpcode::SetOsdName,
94 b"pi4",
95 )?;
96 }
97 Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
98 cec.transmit_data(
99 msg.destination(),
100 msg.initiator(),
101 CecOpcode::ReportPowerStatus,
102 &[CecPowerStatus::On.into()],
103 )?;
104 }
105 Some(Ok(CecOpcode::GiveFeatures)) => {}
106 Some(Ok(opcode)) => {
107 println!(
108 "{:?} -> {:?} : {:?} {:x?}",
109 msg.initiator(),
110 msg.destination(),
111 opcode,
112 msg.parameters()
113 );
114 }
115 _ => {
116 println!("{:?}", msg);
117 }
118 }
119 }
120}