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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } 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
56
57
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 {
        cec_version: Version::V1_4,
        num_log_addrs: 1,
        vendor_id: CEC_VENDOR_ID_NONE,
        osd_name: "pi4".to_string().try_into().unwrap(),
        primary_device_type: [CecPrimDevType::PLAYBACK; 4],
        log_addr_type: [CecLogAddrType::PLAYBACK; 4],
        ..Default::default()
    };
    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 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
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

                        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(&self, events: PollFlags, timeout: i32) -> 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)

timeout is in milliseconds.
Specifying a negative value in timeout means an infinite timeout. Specifying a timeout of 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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } 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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } 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
56
57
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 {
        cec_version: Version::V1_4,
        num_log_addrs: 1,
        vendor_id: CEC_VENDOR_ID_NONE,
        osd_name: "pi4".to_string().try_into().unwrap(),
        primary_device_type: [CecPrimDevType::PLAYBACK; 4],
        log_addr_type: [CecLogAddrType::PLAYBACK; 4],
        ..Default::default()
    };
    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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/pass.rs (line 12)
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

                        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: u16) -> 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 CEC_PHYS_ADDR_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 CEC_EVENT_STATE_CHANGE event is sent when the physical address changes.

The physical address is a 16-bit number where each group of 4 bits represent a digit of the physical address a.b.c.d where the most significant 4 bits represent ‘a’. The CEC root device (usually the TV) has address 0.0.0.0. Every device that is hooked up to an input of the TV has address a.0.0.0 (where ‘a’ is ≥ 1), devices hooked up to those in turn have addresses a.b.0.0, etc. So a topology of up to 5 devices deep is supported. The physical address a device shall use is stored in the EDID of the sink.
For example, the EDID for each HDMI input of the TV will have a different physical address of the form a.0.0.0 that the sources will read out and use as their physical address.
If nothing is connected, then phys_addr is 0xffff. See HDMI 1.4b, section 8.7 (Physical Address).

source

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

Query physical addresses e.g. 0x3300 -> 3.3.0.0

Examples found in repository?
examples/pass.rs (line 14)
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

                        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 num_log_addrs to 0. All other fields will be ignored in that case. 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 CEC_EVENT_STATE_CHANGE 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
56
57
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 {
        cec_version: Version::V1_4,
        num_log_addrs: 1,
        vendor_id: CEC_VENDOR_ID_NONE,
        osd_name: "pi4".to_string().try_into().unwrap(),
        primary_device_type: [CecPrimDevType::PLAYBACK; 4],
        log_addr_type: [CecLogAddrType::PLAYBACK; 4],
        ..Default::default()
    };
    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 66)
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

                        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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } 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 31)
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
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 {
        cec_version: Version::V1_4,
        num_log_addrs: 1,
        vendor_id: CEC_VENDOR_ID_NONE,
        osd_name: "pi4".to_string().try_into().unwrap(),
        primary_device_type: [CecPrimDevType::PLAYBACK; 4],
        log_addr_type: [CecLogAddrType::PLAYBACK; 4],
        ..Default::default()
    };
    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 36-40)
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
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 {
        cec_version: Version::V1_4,
        num_log_addrs: 1,
        vendor_id: CEC_VENDOR_ID_NONE,
        osd_name: "pi4".to_string().try_into().unwrap(),
        primary_device_type: [CecPrimDevType::PLAYBACK; 4],
        log_addr_type: [CecLogAddrType::PLAYBACK; 4],
        ..Default::default()
    };
    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 (line 24)
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

                        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. 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
41
42
43
44
45
46
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,
            -1,
        )?;

        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.msg[..msg.len as usize]),
                }
            } else {
                println!("msg {:x?}", msg);
            }
        }
    }
}
More examples
Hide additional examples
examples/pass.rs (line 17)
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
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 msg.parameters() == physical_addr.to_be_bytes() =>
            {
                // 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_be_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 l.num_log_addrs > 0 {
                    if let Some(log) = l.log_addr.first() {
                        addr.extend_from_slice(&physical_addr.to_be_bytes());
                        addr.push(*log);

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

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.