Struct cec_linux::CecDevice

source ·
pub struct CecDevice(/* private fields */);
Expand description

A handle on a CEC device.

Implementations§

source§

impl CecDevice

source

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?
examples/monitor.rs (line 10)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/switch_power.rs (line 10)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas()?;
    println!("capas  {:?}", capas);

    // clear existing logical addresses
    let log = CecLogAddrs::default();
    cec.set_log(log)?;

    // set new address (PLAYBACK)
    let log = CecLogAddrs::new(
        VendorID::NONE,
        Version::V1_4,
        "pi4".to_string().try_into().unwrap(),
        &[CecPrimDevType::PLAYBACK],
        &[CecLogAddrType::PLAYBACK],
    );
    cec.set_log(log)?;

    // ask Audiosystem to turn on (from standby)
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;

    sleep(Duration::from_millis(10000));

    // ask Audiosystem to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Audiosystem,
        CecOpcode::Standby,
    )?;

    sleep(Duration::from_millis(10000));

    // ask TV to turn on
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;

    sleep(Duration::from_millis(10000));

    // ask TV to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Tv,
        CecOpcode::Standby,
    )?;

    Ok(())
}
examples/pass.rs (line 9)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

pub fn poll<T: Into<PollTimeout>>( &self, events: PollFlags, timeout: T ) -> Result<PollFlags>

Available on crate feature poll only.

Poll for

  1. newly received Messages (POLLIN and POLLRDNORM flags)
  2. room in the transmit queue (POLLOUT and POLLWRNORM flags)
  3. 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?
examples/monitor.rs (lines 16-19)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
source

pub fn get_capas(&self) -> Result<CecCaps>

query information on the devices capabilities. See CecCaps

Examples found in repository?
examples/monitor.rs (line 11)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/switch_power.rs (line 11)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas()?;
    println!("capas  {:?}", capas);

    // clear existing logical addresses
    let log = CecLogAddrs::default();
    cec.set_log(log)?;

    // set new address (PLAYBACK)
    let log = CecLogAddrs::new(
        VendorID::NONE,
        Version::V1_4,
        "pi4".to_string().try_into().unwrap(),
        &[CecPrimDevType::PLAYBACK],
        &[CecLogAddrType::PLAYBACK],
    );
    cec.set_log(log)?;

    // ask Audiosystem to turn on (from standby)
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;

    sleep(Duration::from_millis(10000));

    // ask Audiosystem to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Audiosystem,
        CecOpcode::Standby,
    )?;

    sleep(Duration::from_millis(10000));

    // ask TV to turn on
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;

    sleep(Duration::from_millis(10000));

    // ask TV to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Tv,
        CecOpcode::Standby,
    )?;

    Ok(())
}
source

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?
examples/monitor.rs (line 13)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/pass.rs (line 11)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

pub fn get_mode(&self) -> Result<(CecModeInitiator, CecModeFollower)>

source

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.

source

pub fn get_phys(&self) -> Result<CecPhysicalAddress>

Query physical addresses If nothing is connected, then phys_addr is CecPhysicalAddress::INVALID.

Examples found in repository?
examples/pass.rs (line 13)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

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?
examples/switch_power.rs (line 16)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas()?;
    println!("capas  {:?}", capas);

    // clear existing logical addresses
    let log = CecLogAddrs::default();
    cec.set_log(log)?;

    // set new address (PLAYBACK)
    let log = CecLogAddrs::new(
        VendorID::NONE,
        Version::V1_4,
        "pi4".to_string().try_into().unwrap(),
        &[CecPrimDevType::PLAYBACK],
        &[CecLogAddrType::PLAYBACK],
    );
    cec.set_log(log)?;

    // ask Audiosystem to turn on (from standby)
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;

    sleep(Duration::from_millis(10000));

    // ask Audiosystem to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Audiosystem,
        CecOpcode::Standby,
    )?;

    sleep(Duration::from_millis(10000));

    // ask TV to turn on
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;

    sleep(Duration::from_millis(10000));

    // ask TV to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Tv,
        CecOpcode::Standby,
    )?;

    Ok(())
}
source

pub fn get_log(&self) -> Result<CecLogAddrs>

Query logical addresses

Examples found in repository?
examples/pass.rs (line 75)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

pub fn get_event(&self) -> Result<CecEvent>

Examples found in repository?
examples/monitor.rs (line 22)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
source

pub fn turn_on( &self, from: CecLogicalAddress, to: CecLogicalAddress ) -> Result<()>

wake a remote cec device from standby

Examples found in repository?
examples/switch_power.rs (line 29)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas()?;
    println!("capas  {:?}", capas);

    // clear existing logical addresses
    let log = CecLogAddrs::default();
    cec.set_log(log)?;

    // set new address (PLAYBACK)
    let log = CecLogAddrs::new(
        VendorID::NONE,
        Version::V1_4,
        "pi4".to_string().try_into().unwrap(),
        &[CecPrimDevType::PLAYBACK],
        &[CecLogAddrType::PLAYBACK],
    );
    cec.set_log(log)?;

    // ask Audiosystem to turn on (from standby)
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;

    sleep(Duration::from_millis(10000));

    // ask Audiosystem to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Audiosystem,
        CecOpcode::Standby,
    )?;

    sleep(Duration::from_millis(10000));

    // ask TV to turn on
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;

    sleep(Duration::from_millis(10000));

    // ask TV to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Tv,
        CecOpcode::Standby,
    )?;

    Ok(())
}
source

pub fn keypress( &self, from: CecLogicalAddress, to: CecLogicalAddress, key: CecUserControlCode ) -> Result<()>

send a button press to a remote cec device

source

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?
examples/switch_power.rs (lines 34-38)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas()?;
    println!("capas  {:?}", capas);

    // clear existing logical addresses
    let log = CecLogAddrs::default();
    cec.set_log(log)?;

    // set new address (PLAYBACK)
    let log = CecLogAddrs::new(
        VendorID::NONE,
        Version::V1_4,
        "pi4".to_string().try_into().unwrap(),
        &[CecPrimDevType::PLAYBACK],
        &[CecLogAddrType::PLAYBACK],
    );
    cec.set_log(log)?;

    // ask Audiosystem to turn on (from standby)
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Audiosystem)?;

    sleep(Duration::from_millis(10000));

    // ask Audiosystem to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Audiosystem,
        CecOpcode::Standby,
    )?;

    sleep(Duration::from_millis(10000));

    // ask TV to turn on
    cec.turn_on(CecLogicalAddress::Playback2, CecLogicalAddress::Tv)?;

    sleep(Duration::from_millis(10000));

    // ask TV to switch to standby
    cec.transmit(
        CecLogicalAddress::Playback2,
        CecLogicalAddress::Tv,
        CecOpcode::Standby,
    )?;

    Ok(())
}
source

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?
examples/pass.rs (lines 25-30)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

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);
}
source

pub fn rec(&self) -> Result<CecMsg>

receive a single message. block forever the available messages depend on CecModeFollower

Examples found in repository?
examples/monitor.rs (line 26)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;
    let capas = cec.get_capas();
    println!("capas  {:?}", capas);
    cec.set_mode(CecModeInitiator::None, CecModeFollower::Monitor)?;

    loop {
        let f = cec.poll(
            PollFlags::POLLIN | PollFlags::POLLRDNORM | PollFlags::POLLPRI,
            PollTimeout::NONE,
        )?;

        if f.intersects(PollFlags::POLLPRI) {
            let evt = cec.get_event()?;
            println!("evt {:x?}", evt);
        }
        if f.contains(PollFlags::POLLIN | PollFlags::POLLRDNORM) {
            let msg = cec.rec()?;

            if msg.is_ok() {
                match (msg.initiator(), msg.destination(), msg.opcode()) {
                    (i, d, Some(Ok(o))) => {
                        println!("msg {:?}->{:?} {:?} {:x?}", i, d, o, msg.parameters());
                    }
                    _ => println!("msg {:x?}", msg),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/pass.rs (line 16)
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
fn main() -> std::io::Result<()> {
    let cec = CecDevice::open("/dev/cec0")?;

    cec.set_mode(CecModeInitiator::Send, CecModeFollower::ExclusivePassthru)?;

    let physical_addr = cec.get_phys()?;

    loop {
        let msg = cec.rec()?;
        match msg.opcode() {
            Some(Ok(CecOpcode::ActiveSource))
            | Some(Ok(CecOpcode::RoutingInformation))
            | Some(Ok(CecOpcode::SetStreamPath))
                if physical_addr == msg.parameters() =>
            {
                // this is not done by the core
                println!("THIS IS US {:?}", msg.opcode().unwrap().unwrap());
                cec.transmit_data(
                    CecLogicalAddress::Playback2,
                    CecLogicalAddress::UnregisteredBroadcast,
                    CecOpcode::ActiveSource,
                    &physical_addr.to_bytes(),
                )?;
            }
            Some(Ok(CecOpcode::ReportPhysicalAddr)) => {} //core is still taking care of that
            Some(Ok(opcode)) if msg.destination() == CecLogicalAddress::UnregisteredBroadcast => {
                //dont answer brodcasts
                println!(
                    "{:?}: {:?} {:x?}",
                    msg.initiator(),
                    opcode,
                    msg.parameters()
                );
            }
            Some(Ok(CecOpcode::GetCecVersion)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::CecVersion,
                    &[Version::V1_3A.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveDeviceVendorId)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[
                        CecOpcode::GiveDeviceVendorId.into(),
                        CecAbortReason::Unrecognized.into(),
                    ],
                )?; /*
                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::DeviceVendorId,
                    &[0,0,0])?;*/
            }
            Some(Ok(CecOpcode::Abort)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::FeatureAbort,
                    &[CecOpcode::Abort.into(), CecAbortReason::Other.into()],
                )?;
            }
            Some(Ok(CecOpcode::GivePhysicalAddr)) => {
                let l = cec.get_log()?;
                let mut addr = Vec::with_capacity(3);
                if let Some(log) = l.addresses().first() {
                    addr.extend_from_slice(&physical_addr.to_bytes());
                    addr.push((*log).into());

                    cec.transmit_data(
                        msg.destination(),
                        msg.initiator(),
                        CecOpcode::ReportPhysicalAddr,
                        &addr,
                    )?;
                } //else no address yet?!?!?
            }
            Some(Ok(CecOpcode::GiveOsdName)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::SetOsdName,
                    b"pi4",
                )?;
            }
            Some(Ok(CecOpcode::GiveDevicePowerStatus)) => {
                cec.transmit_data(
                    msg.destination(),
                    msg.initiator(),
                    CecOpcode::ReportPowerStatus,
                    &[CecPowerStatus::On.into()],
                )?;
            }
            Some(Ok(CecOpcode::GiveFeatures)) => {}
            Some(Ok(opcode)) => {
                println!(
                    "{:?} -> {:?} : {:?} {:x?}",
                    msg.initiator(),
                    msg.destination(),
                    opcode,
                    msg.parameters()
                );
            }
            _ => {
                println!("{:?}", msg);
            }
        }
    }
}
source

pub fn rec_for(&self, timeout: u32) -> Result<CecMsg>

receive a single message. block for at most timeout ms. the available messages depend on CecModeFollower

Trait Implementations§

source§

impl AsRawFd for CecDevice

source§

fn as_raw_fd(&self) -> RawFd

Extracts the raw file descriptor. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.