cir 0.1.4

Linux Infrared Tooling
Documentation
use super::LinuxProtocol;

impl LinuxProtocol {
    /// Find the protocol that matches the name exactly
    pub fn find(name: &str) -> Option<&'static LinuxProtocol> {
        LINUX_PROTOCOLS.iter().find(|e| e.name == name)
    }

    /// Match protocol name with regard for spaces or dashes or underscores.
    /// Behaviour should match protocol_match() in ir-ctl
    pub fn find_like(name: &str) -> Option<&'static LinuxProtocol> {
        let str_like = |name: &str| -> String {
            name.chars()
                .filter_map(|ch| {
                    if matches!(ch, ' ' | '-' | '_') || !ch.is_ascii() {
                        None
                    } else {
                        Some(ch.to_ascii_lowercase())
                    }
                })
                .collect::<String>()
        };

        let name = str_like(name);

        LINUX_PROTOCOLS.iter().find(|e| str_like(e.name) == name)
    }

    /// Find list of protocols supported by this decoder. Some linux kernel decoders
    /// can decode multiple (closely related) IR protocols.
    pub fn find_decoder(name: &str) -> Option<&'static [LinuxProtocol]> {
        if let Some(start) = LINUX_PROTOCOLS.iter().position(|p| p.decoder == name) {
            let mut end = start;

            while LINUX_PROTOCOLS
                .get(end + 1)
                .map(|p| p.decoder == name)
                .unwrap_or_default()
            {
                end += 1;
            }

            Some(&LINUX_PROTOCOLS[start..=end])
        } else {
            None
        }
    }
}

pub const LINUX_PROTOCOLS: &[LinuxProtocol] = &[
    LinuxProtocol {
        name: "rc5",
        decoder: "rc-5",
        irp: Some(
            "{36k,msb,889}<1,-1|-1,1>(1,~CODE:1:6,T:1,CODE:5:8,CODE:6,^114m)+ [CODE:0..0x1FFF,T:0..1=0]",
        ),
        scancode_mask: 0x1f7f,
        protocol_no: 2,
    },
    LinuxProtocol {
        name: "rc5x_20",
        decoder: "rc-5",
        irp: Some("{36k,msb,889}<1,-1|-1,1>(1,~CODE:1:14,T:1,CODE:5:16,-4,CODE:6:8,CODE:6,^114m)+ [CODE:0..0x1fffff,T:0..1=0]"),
        scancode_mask: 0x1f7f3f,
        protocol_no: 3,
    },
    LinuxProtocol {
        name: "rc5_sz",
        decoder: "rc-5-sz",
        irp: Some("{36k,msb,889}<1,-1|-1,1>(1,CODE:1:13,T:1,CODE:12,^114m)+ [CODE:0..0x2fff,T:0..1=0]"),
        scancode_mask: 0x2fff,
        protocol_no: 4,
    },
    LinuxProtocol {
        name: "jvc",
        decoder: "jvc",
        irp: Some("{37.9k,527,33%}<1,-1|1,-3>(16,-8,CODE:8:8,CODE:8,1,^59.08m,(CODE:8:8,CODE:8,1,^46.42m)*) [CODE:0..0xffff]"),
        scancode_mask: 0xffff,
        protocol_no: 5,
    },
    LinuxProtocol {
        name: "sony12",
        decoder: "sony",
        irp: Some("{40k,600}<1,-1|2,-1>(4,-1,CODE:7,CODE:5:16,^45m)+ [CODE:0..0x1fffff]"),
        scancode_mask: 0x1f007f,
        protocol_no: 6,
    },
    LinuxProtocol {
        name: "sony15",
        decoder: "sony",
        irp: Some("{40k,600}<1,-1|2,-1>(4,-1,CODE:7,CODE:8:16,^45m)+ [CODE:0..0xffffff]"),
        scancode_mask: 0xff007f,
        protocol_no: 7,
    },
    LinuxProtocol {
        name: "sony20",
        decoder: "sony",
        irp: Some("{40k,600}<1,-1|2,-1>(4,-1,CODE:7,CODE:5:16,CODE:8:8,^45m)+ [CODE:0..0x1fffff]"),
        scancode_mask: 0x1fff7f,
        protocol_no: 8,
    },
    LinuxProtocol {
        name: "nec",
        decoder: "nec",
        irp: Some("{38.4k,564}<1,-1|1,-3>(16,-8,CODE:8:8,~CODE:8:8,CODE:8,~CODE:8,1,^108m,(16,-4,1,^108m)*) [CODE:0..0xffff]"),
        scancode_mask: 0xffff,
        protocol_no: 9,
    },
    LinuxProtocol {
        name: "necx",
        decoder: "nec",
        irp: Some("{38.4k,564}<1,-1|1,-3>(16,-8,CODE:8:16,CODE:8:8,CODE:8,~CODE:8,1,^108m,(16,-4,1,^108m)*) [CODE:0..0xffffff]"),
        scancode_mask: 0xffffff,
        protocol_no: 10,
    },
    LinuxProtocol {
        name: "nec32",
        decoder: "nec",
        irp: Some("{38.4k,564}<1,-1|1,-3>(16,-8,CODE:8:16,CODE:8:24,CODE:8,CODE:8:8,1,^108m,(16,-4,1,^108m)*) [CODE:0..0xffffffff]"),
        scancode_mask: 0xffff_ffff,
        protocol_no: 11,
    },
    LinuxProtocol {
        name: "sanyo",
        decoder: "sanyo",
        irp: Some("{38k,562.5}<1,-1|1,-3>(16,-8,CODE:13:8,~CODE:13:8,CODE:8,~CODE:8,1,-42,(16,-8,1,-150)*) [CODE:0..0x1fffff]"),
        scancode_mask: 0x1fffff,
        protocol_no: 12,
    },
    LinuxProtocol {
        name: "mcir2-kbd",
        decoder: "mce_kbd",
        irp: None,
        scancode_mask: u32::MAX,
        protocol_no: 13,
    },
    LinuxProtocol {
        name: "mcir2-mse",
        decoder: "mce_kbd",
        irp: None,
        scancode_mask: u32::MAX,
        protocol_no: 14,
    },
    LinuxProtocol {
        name: "rc6_0",
        decoder: "rc-6",
        irp: Some("{36k,444,msb}<-1,1|1,-1>(6,-2,1:1,0:3,<-2,2|2,-2>(T:1),CODE:16,^107m)+ [CODE:0..0xffff,T@:0..1=0]"),
        scancode_mask: 0xffff,
        protocol_no: 15,
    },
    LinuxProtocol {
        name: "rc6_6a_20",
        decoder: "rc-6",
        irp: Some("{36k,444,msb}<-1,1|1,-1>(6,-2,1:1,6:3,<-2,2|2,-2>(T:1),CODE:20,-100m)+ [CODE:0..0xfffff,T@:0..1=0]"),
        scancode_mask: 0xf_ffff,
        protocol_no: 16,
    },
    LinuxProtocol {
        name: "rc6_6a_24",
        decoder: "rc-6",
        irp: Some("{36k,444,msb}<-1,1|1,-1>(6,-2,1:1,6:3,<-2,2|2,-2>(T:1),CODE:24,^105m)+ [CODE:0..0xffffff,T@:0..1=0]"),
        scancode_mask: 0xff_ff_ff,
        protocol_no: 17,
    },
    LinuxProtocol {
        name: "rc6_6a_32",
        decoder: "rc-6",
        irp: Some("{36k,444,msb}<-1,1|1,-1>(6,-2,1:1,6:3,<-2,2|2,-2>(T:1),CODE:32,MCE=(CODE>>16)==0x800f||(CODE>>16)==0x8034||(CODE>>16)==0x8046,^105m)+{MCE=0}[CODE:0..0xffffffff,T@:0..1=0]"),
        scancode_mask: 0xffff_ffff,
        protocol_no: 18,
    },
    LinuxProtocol {
        name: "rc6_mce",
        decoder: "rc-6",
        irp: Some("{36k,444,msb}<-1,1|1,-1>(6,-2,1:1,6:3,-2,2,CODE:16:16,T:1,CODE:15,MCE=(CODE>>16)==0x800f||(CODE>>16)==0x8034||(CODE>>16)==0x8046,^105m)+{MCE=1}[CODE:0..0xffffffff,T@:0..1=0]"),
        scancode_mask: 0xffff_7fff,
        protocol_no: 19,
    },
    LinuxProtocol {
        name: "sharp",
        decoder: "sharp",
        irp: Some("{38k,264}<1,-3|1,-7>(CODE:5:8,CODE:8,1:2,1,-165,CODE:5:8,~CODE:8,2:2,1,-165)+ [CODE:0..0x1fff]"),
        scancode_mask: 0x1fff,
        protocol_no: 20,
    },
    LinuxProtocol {
        name: "xmp",
        decoder: "xmp",
        irp: Some("{38k,136,msb}<210u,-760u|210u,-896u|210u,-1032u|210u,-1168u|210u,-1304u|210u,-1449u|210u,-1576u|210u,-1712u|210u,-1848u|210u,-1984u|210u,-2120u|210u,-2256u|210u,-2392u|210u,-2528u|210u,-2664u|210u,-2800u> \
            ([T=0][T=8],CODE:4:20,C1:4,CODE:4:16,15:4,OEM:8,CODE:8:24,210u,-13.8m,CODE:4:20,C2:4,T:4,CODE:4:16,CODE:16,210u,-80.4m)+\
            { C1=-(CODE:4:20+CODE:4:16+15+4+OEM:4:4+OEM:4+CODE:4:24+CODE:4:28),C2=-(CODE:4:16+CODE:4:20+T+CODE:4:12+CODE:4:8+CODE:4:4+CODE:4),OEM=0x44 } \
            [CODE:0..UINT32_MAX]"),
        scancode_mask: u32::MAX,
        protocol_no: 21,
    },
    LinuxProtocol {
        name: "cec",
        decoder: "cec",
        irp: None,
        scancode_mask: u32::MAX,
        protocol_no: 22,
    },
    LinuxProtocol {
        name: "imon",
        decoder: "imon",
        irp: Some("{416,38k,msb}<1|-1>(1,\
            C:1:30,CODE:1:30,C:1:29,CODE:1:29,C:1:28,CODE:1:28,C:1:27,CODE:1:27,C:1:26,CODE:1:26,C:1:25,CODE:1:25,C:1:24,CODE:1:24,C:1:23,CODE:1:23,C:1:22,CODE:1:22,C:1:21,CODE:1:21,C:1:20,CODE:1:20,C:1:19,CODE:1:19,C:1:18,CODE:1:18,C:1:17,CODE:1:17,C:1:16,CODE:1:16,C:1:15,CODE:1:15,C:1:14,CODE:1:14,C:1:13,CODE:1:13,C:1:12,CODE:1:12,C:1:11,CODE:1:11,C:1:10,CODE:1:10,C:1:9,CODE:1:9,C:1:8,CODE:1:8,C:1:7,CODE:1:7,C:1:6,CODE:1:6,C:1:5,CODE:1:5,C:1:4,CODE:1:4,C:1:3,CODE:1:3,C:1:2,CODE:1:2,C:1:1,CODE:1:1,C:1,CODE:1,\
            ^106m) {C=CODE|(CODE>>1)|0xbc8081ff} [CODE:0..0x7fffffff]"),
        scancode_mask: 0x7fffffff,
        protocol_no: 23,
    },
    LinuxProtocol {
        name: "rc-mm-12",
        decoder: "rc-mm",
        irp: Some("{36k,1p,msb}<6,-10|6,-16|6,-22|6,-28>(15,-10,CODE:12,6,^1000)+ [CODE:0..0xfff]"),
        scancode_mask: 0xfff,
        protocol_no: 24,
    },
    LinuxProtocol {
        name: "rc-mm-24",
        decoder: "rc-mm",
        irp: Some("{36k,1p,msb}<6,-10|6,-16|6,-22|6,-28>(15,-10,CODE:24,6,^1000)+ [CODE:0..0xffffff]"),
        scancode_mask:  0xfff_fff,
        protocol_no: 25,
    },
    LinuxProtocol {
        name: "rc-mm-32",
        decoder: "rc-mm",
        // toggle?
        irp: Some("{36k,1p,msb}<6,-10|6,-16|6,-22|6,-28>(15,-10,CODE:32,5,^1000)+ [CODE:0..0xffffffff]"),
        scancode_mask: 0xffff_ffff,
        protocol_no: 26,
    },
    LinuxProtocol {
        name: "xbox-dvd",
        decoder: "xbox-dvd",
        // trailing space is a guess, should be verified on real hardware
        irp: Some("{38k,msb}<550,-900|550,-1900>(4000,-3900,~CODE:12,CODE:12,550,^100m)+ [CODE:0..0xfff]"),
        scancode_mask: 0xfff,
        protocol_no: 27,
    }
];

#[test]
fn find_like() {
    let p = LinuxProtocol::find_like("rc6-mce").unwrap();
    assert_eq!(p.name, "rc6_mce");

    let p = LinuxProtocol::find_like("rcmm12").unwrap();
    assert_eq!(p.name, "rc-mm-12");

    let p = LinuxProtocol::find_like("sony-12").unwrap();
    assert_eq!(p.name, "sony12");

    let Some(p) = LinuxProtocol::find_decoder("sony") else {
        panic!();
    };

    assert_eq!(p.len(), 3);
    assert_eq!(p[0].name, "sony12");
    assert_eq!(p[1].name, "sony15");
    assert_eq!(p[2].name, "sony20");
}