From cfcbff686102768a2dfbe128cffed7b9cef0750c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 20 May 2024 14:50:14 +0100 Subject: [PATCH] Remove cir transmit subcommand Signed-off-by: Sean Young --- README.md | 14 +- cir/src/bin/cir.rs | 311 ++++++++++++++----------------- cir/src/bin/commands/transmit.rs | 270 +++++++++++---------------- cir/src/keymap/encode.rs | 106 +++++------ cir/src/lircd_conf/encode.rs | 108 ++++++----- cir/tests/encode_tests.rs | 35 ++-- 6 files changed, 385 insertions(+), 459 deletions(-) diff --git a/README.md b/README.md index 3adb75a4..3bebf8b9 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,9 @@ rc0: LIRC Set Tx Carrier : yes LIRC Set Tx Duty Cycle : no LIRC Transmitters : 2 - BPF protocols : + BPF protocols : Supported Protocols : rc-5 nec rc-6 jvc sony rc-5-sz sanyo sharp mce_kbd xmp imon rc-mm - Enabled Protocols : + Enabled Protocols : ``` ## Transmit/Send (cir transmit) @@ -75,25 +75,25 @@ If you have a `.lircd.conf` file or `.toml` keymap, you can transmit with the fo command: ```bash -cir transmit keymap RM-Y173.lircd.conf KEY_CHANNELUP +cir transmit --keymap RM-Y173.lircd.conf --code KEY_CHANNELUP ``` Alternatively, you can send raw IR directly like so: ```bash -cir transmit rawir '+9000 -4500 +560' +cir transmit '+9000 -4500 +560' ``` You can also send files or linux kernel scancodes, using the same options like `ir-ctl`. This supports mode2 files or raw IR files. ```bash -cir transmit rawir -s input-file -S nec:0xcafe +cir transmit -f input-file -S nec:0xcafe ``` You can send pronto codes: ```bash -cir transmit pronto '5000 0073 0000 0001 0001 0001' +cir transmit --pronto '5000 0073 0000 0001 0001 0001' ``` Lastly you use IRP notation and set the parameters. This is great for experimenting with IRP; use the `--dry-run` (`-n`) to avoid sending. ```bash -cir transmit irp -n -fF=2 '{40k,600}<1,-1|2,-1>(4,-1,F:8,^45m)[F:0..255]' +cir transmit -n -aF=2 --irp '{40k,600}<1,-1|2,-1>(4,-1,F:8,^45m)[F:0..255]' ``` This will give the following output: ``` diff --git a/cir/src/bin/cir.rs b/cir/src/bin/cir.rs index 740fa63d..7a862119 100644 --- a/cir/src/bin/cir.rs +++ b/cir/src/bin/cir.rs @@ -28,20 +28,14 @@ struct App { command: Commands, } -#[derive(Subcommand)] enum Commands { - #[command(about = "Decode IR", arg_required_else_help = true)] Decode(Decode), - #[command(about = "Transmit IR", arg_required_else_help = true)] Transmit(Transmit), #[cfg(target_os = "linux")] - #[command(about = "List IR and CEC devices")] List(List), #[cfg(target_os = "linux")] - #[command(about = "Configure IR and CEC devices")] Keymap(Keymap), #[cfg(target_os = "linux")] - #[command(about = "Receive IR and print to stdout")] Test(Test), } @@ -86,7 +80,7 @@ struct Decode { irp: Option, /// Keymap or lircd.conf file - #[arg(long = "keymap", short = 'k')] + #[arg(long = "keymap", short = 'k', required_unless_present = "irp")] keymap: Option, #[clap(flatten)] @@ -283,7 +277,7 @@ struct Auto { cfgfile: PathBuf, } -#[derive(Args)] +#[derive(Args, Debug)] struct Transmit { #[cfg(target_os = "linux")] #[clap(flatten)] @@ -294,69 +288,19 @@ struct Transmit { #[arg( long = "transmitters", short = 'e', - global = true, value_delimiter = ',', help_heading = "DEVICE" )] transmitters: Vec, /// Encode IR but do not actually send - #[arg(long = "dry-run", short = 'n', global = true)] + #[arg(long = "dry-run", short = 'n')] dry_run: bool, - #[command(subcommand)] - commands: TransmitCommands, -} + /// List the codes in the keymap + #[arg(long = "list-codes", short = 'l', requires = "KEYMAP")] + list_codes: bool, -#[derive(Debug)] -enum TransmitCommands { - Irp(TransmitIrp), - Pronto(TransmitPronto), - RawIR(TransmitRawIR), - Keymap(TransmitKeymap), -} - -#[derive(Args, Debug)] -struct TransmitIrp { - #[arg(long, hide = true)] - pronto: bool, - - /// Set carrier in Hz, 0 for unmodulated - #[cfg(target_os = "linux")] - #[arg(long = "carrier", short = 'c', value_parser = value_parser!(i64).range(1..1_000_000), help_heading = "DEVICE")] - carrier: Option, - - /// Override duty cycle % (1 to 99) - #[cfg(target_os = "linux")] - #[arg(long = "duty-cycle", short = 'u', value_parser = value_parser!(u8).range(1..99), help_heading = "DEVICE")] - duty_cycle: Option, - - /// Number of IRP repeats to encode - #[arg(long = "repeats", short = 'r', value_parser = value_parser!(u64).range(0..99), default_value_t = 1)] - repeats: u64, - - /// Set input variable like KEY=VALUE - #[arg(long = "field", short = 'f', value_delimiter = ',')] - fields: Vec, - - /// IRP Notation - #[arg(name = "IRP")] - irp: String, -} - -#[derive(Args, Debug)] -struct TransmitPronto { - /// Number of times to repeat signal - #[arg(long = "repeats", short = 'r', value_parser = value_parser!(u64).range(0..99), default_value_t = 1)] - repeats: u64, - - /// Pronto Hex code - #[arg(name = "PRONTO")] - pronto: String, -} - -#[derive(Args, Debug)] -struct TransmitRawIR { /// Read from rawir or mode2 file #[arg(long = "file", short = 'f', name = "FILE", help_heading = "INPUT")] files: Vec, @@ -374,10 +318,49 @@ struct TransmitRawIR { #[arg(long = "gap", short = 'g', name = "GAP", help_heading = "INPUT")] gaps: Vec, + /// Pronto Hex code + #[arg(long = "pronto", short = 'p', name = "PRONTO", help_heading = "INPUT")] + pronto: Vec, + /// Raw IR text #[arg(name = "RAWIR", help_heading = "INPUT")] rawir: Vec, + /// Number of IRP repeats to encode + #[arg( + long = "repeats", + short = 'r', + value_parser = value_parser!(u64).range(0..99), + default_value_t = 0, + help_heading = "INPUT" + )] + repeats: u64, + + /// Set input variable like KEY=VALUE + #[arg( + long = "argument", + short = 'a', + value_delimiter = ',', + help_heading = "INPUT" + )] + arguments: Vec, + + /// IRP Notation + #[arg(long = "irp", short = 'i', name = "IRP", help_heading = "INPUT")] + irp: Vec, + + /// Keymap or lircd.conf file + #[arg(name = "KEYMAP", long = "keymap", short = 'k', help_heading = "INPUT")] + keymap: Option, + + /// Remote to use from lircd.conf file + #[arg(name = "REMOTE", long = "remote", short = 'm', help_heading = "INPUT")] + remote: Option, + + /// Code from keymap to send + #[arg(name = "CODES", long = "code", short = 'K', help_heading = "INPUT")] + codes: Vec, + /// Set carrier in Hz, 0 for unmodulated #[cfg(target_os = "linux")] #[arg(long = "carrier", short = 'c', value_parser = value_parser!(i64).range(1..1_000_000), help_heading = "DEVICE")] @@ -392,44 +375,31 @@ struct TransmitRawIR { transmitables: Vec, } -impl TransmitRawIR { +impl Transmit { fn transmitables(&mut self, matches: &ArgMatches) { let mut part = Vec::new(); - if let Some(files) = matches.get_many::("FILE") { - let mut indices = matches.indices_of("FILE").unwrap(); - - for file in files { - part.push((Transmitables::File(file.clone()), indices.next().unwrap())); - } - } - - if let Some(rawirs) = matches.get_many::("RAWIR") { - let mut indices = matches.indices_of("RAWIR").unwrap(); - - for rawir in rawirs { - part.push((Transmitables::RawIR(rawir.clone()), indices.next().unwrap())); - } - } - - if let Some(scancodes) = matches.get_many::("SCANCODE") { - let mut indices = matches.indices_of("SCANCODE").unwrap(); + macro_rules! arg { + ($id:literal, $ty:ty, $transmitable:ident) => {{} + if let Some(values) = matches.get_many::<$ty>($id) { + let mut indices = matches.indices_of($id).unwrap(); - for scancode in scancodes { - part.push(( - Transmitables::Scancode(scancode.clone()), - indices.next().unwrap(), - )); - } + for value in values { + part.push(( + Transmitables::$transmitable(value.clone()), + indices.next().unwrap(), + )); + } + }}; } - if let Some(gaps) = matches.get_many::("GAP") { - let mut indices = matches.indices_of("GAP").unwrap(); - - for gap in gaps { - part.push((Transmitables::Gap(*gap), indices.next().unwrap())); - } - } + arg!("FILE", OsString, File); + arg!("RAWIR", String, RawIR); + arg!("PRONTO", String, Pronto); + arg!("CODES", String, Code); + arg!("IRP", String, Irp); + arg!("GAP", u32, Gap); + arg!("SCANCODE", String, Scancode); part.sort_by(|a, b| a.1.cmp(&b.1)); @@ -441,79 +411,61 @@ impl TransmitRawIR { enum Transmitables { File(OsString), RawIR(String), + Pronto(String), + Code(String), + Irp(String), Gap(u32), Scancode(String), } -#[derive(Args, Debug)] -struct TransmitKeymap { - /// Override carrier in Hz, 0 for unmodulated - #[cfg(target_os = "linux")] - #[arg(long = "carrier", short = 'c', value_parser = value_parser!(i64).range(0..1_000_000), help_heading = "DEVICE")] - carrier: Option, - - /// Override duty cycle % (1 to 99) - #[cfg(target_os = "linux")] - #[arg(long = "duty-cycle", short = 'u', value_parser = value_parser!(u8).range(1..99), help_heading = "DEVICE")] - duty_cycle: Option, - - /// Keymap or lircd.conf file - #[arg(name = "KEYMAP")] - keymap: PathBuf, - - /// Remote to use from lircd.conf file - #[arg(name = "REMOTE", long = "remote", short = 'm')] - remote: Option, - - /// Number of times to repeat signal - #[arg(long = "repeats", short = 'r', value_parser = value_parser!(u64).range(0..99), default_value_t = 0)] - repeats: u64, - - /// Code to send, leave empty to list codes - #[arg(name = "CODES")] - codes: Vec, -} - -impl FromArgMatches for TransmitCommands { +impl FromArgMatches for Commands { fn from_arg_matches(matches: &ArgMatches) -> Result { match matches.subcommand() { - Some(("irp", args)) => Ok(Self::Irp(TransmitIrp::from_arg_matches(args)?)), - Some(("rawir", args)) => { - let mut rawir = TransmitRawIR::from_arg_matches(args)?; + Some(("decode", args)) => Ok(Self::Decode(Decode::from_arg_matches(args)?)), + Some(("transmit", args)) => { + let mut tx = Transmit::from_arg_matches(args)?; - rawir.transmitables(args); + tx.transmitables(args); - Ok(Self::RawIR(rawir)) + Ok(Self::Transmit(tx)) } - Some(("pronto", args)) => Ok(Self::Pronto(TransmitPronto::from_arg_matches(args)?)), - Some(("keymap", args)) => Ok(Self::Keymap(TransmitKeymap::from_arg_matches(args)?)), + #[cfg(target_os = "linux")] + Some(("list", args)) => Ok(Self::List(List::from_arg_matches(args)?)), + #[cfg(target_os = "linux")] + Some(("keymap", args)) => Ok(Self::Keymap(Keymap::from_arg_matches(args)?)), + #[cfg(target_os = "linux")] + Some(("test", args)) => Ok(Self::Test(Test::from_arg_matches(args)?)), Some((_, _)) => Err(Error::raw( ErrorKind::InvalidSubcommand, - "Valid subcommands are `irp`, `keymap`, `pronto`, and `rawir`", + "Valid subcommands are `decode`, `transmit`, `list`, `keymap`, and `test`", )), None => Err(Error::raw( ErrorKind::MissingSubcommand, - "Valid subcommands are `irp`, `keymap`, `pronto`, and `rawir`", + "Valid subcommands are `decode`, `transmit`, `list`, `keymap`, and `test``", )), } } fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> { match matches.subcommand() { - Some(("irp", args)) => *self = Self::Irp(TransmitIrp::from_arg_matches(args)?), + Some(("decode", args)) => *self = Self::Decode(Decode::from_arg_matches(args)?), Some(("rawir", args)) => { - let mut rawir = TransmitRawIR::from_arg_matches(args)?; + let mut tx = Transmit::from_arg_matches(args)?; - rawir.transmitables(args); + tx.transmitables(args); - *self = Self::RawIR(rawir); + *self = Self::Transmit(tx); } - Some(("pronto", args)) => *self = Self::Pronto(TransmitPronto::from_arg_matches(args)?), - Some(("keymap", args)) => *self = Self::Keymap(TransmitKeymap::from_arg_matches(args)?), + #[cfg(target_os = "linux")] + Some(("list", args)) => *self = Self::List(List::from_arg_matches(args)?), + #[cfg(target_os = "linux")] + Some(("keymap", args)) => *self = Self::Keymap(Keymap::from_arg_matches(args)?), + #[cfg(target_os = "linux")] + Some(("test", args)) => *self = Self::Test(Test::from_arg_matches(args)?), Some((_, _)) => { return Err(Error::raw( ErrorKind::InvalidSubcommand, - "Valid subcommands are `irp`, `keymap`, `pronto`, and `rawir`", + "Valid subcommands are `decode`, `transmit`, `list`, `keymap`, and `test`", )) } None => (), @@ -523,36 +475,61 @@ impl FromArgMatches for TransmitCommands { } } -impl Subcommand for TransmitCommands { +impl Subcommand for Commands { + #[allow(clippy::let_and_return)] fn augment_subcommands(cmd: Command) -> Command { - cmd.subcommand(TransmitIrp::augment_args( - Command::new("irp").about("Encode using IRP Notation and transmit"), - )) - .subcommand(TransmitKeymap::augment_args( - Command::new("keymap").about("Transmit codes from keymap or lircd.conf file"), - )) - .subcommand(TransmitPronto::augment_args( - Command::new("pronto").about("Parse pronto hex code and transmit"), - )) - .subcommand(TransmitRawIR::augment_args( - Command::new("rawir").about("Parse raw IR and transmit"), - )) - .subcommand_required(true) + let cmd = cmd + .subcommand(Decode::augment_args( + Command::new("decode").about("Decode IR"), + )) + .subcommand(Transmit::augment_args( + Command::new("transmit").about("Transmit IR"), + )); + + #[cfg(target_os = "linux")] + let cmd = cmd + .subcommand(List::augment_args( + Command::new("list").about("List IR and CEC devices"), + )) + .subcommand_required(true) + .subcommand(List::augment_args( + Command::new("keymap").about("Configure IR and CEC devices"), + )) + .subcommand_required(true) + .subcommand(List::augment_args( + Command::new("test").about("Receive IR and print to stdout"), + )) + .subcommand_required(true); + + cmd } + + #[allow(clippy::let_and_return)] fn augment_subcommands_for_update(cmd: Command) -> Command { - cmd.subcommand(TransmitIrp::augment_args( - Command::new("irp").about("Encode using IRP Notation and transmit"), - )) - .subcommand(TransmitKeymap::augment_args( - Command::new("keymap").about("Transmit codes from keymap or lircd.conf file"), - )) - .subcommand(TransmitPronto::augment_args( - Command::new("pronto").about("Parse pronto hex code and transmit"), - )) - .subcommand(TransmitRawIR::augment_args( - Command::new("rawir").about("Parse raw IR and transmit"), - )) - .subcommand_required(true) + let cmd = cmd + .subcommand(Decode::augment_args( + Command::new("decode").about("Decode IR"), + )) + .subcommand(Transmit::augment_args( + Command::new("transmit").about("Transmit IR"), + )); + + #[cfg(target_os = "linux")] + let cmd = cmd + .subcommand(List::augment_args( + Command::new("list").about("List IR and CEC devices"), + )) + .subcommand_required(true) + .subcommand(List::augment_args( + Command::new("keymap").about("Configure IR and CEC devices"), + )) + .subcommand_required(true) + .subcommand(List::augment_args( + Command::new("test").about("Receive IR and print to stdout"), + )) + .subcommand_required(true); + + cmd } fn has_subcommand(name: &str) -> bool { matches!(name, "irp" | "keymap" | "pronto" | "rawir") diff --git a/cir/src/bin/commands/transmit.rs b/cir/src/bin/commands/transmit.rs index d42b548c..0564863a 100644 --- a/cir/src/bin/commands/transmit.rs +++ b/cir/src/bin/commands/transmit.rs @@ -117,185 +117,70 @@ pub fn transmit(transmit: &crate::Transmit) { } fn encode_args(transmit: &crate::Transmit) -> Message { - match &transmit.commands { - crate::TransmitCommands::Irp(tx_irp) => { - let mut vars = irp::Vartable::new(); + let mut vars = irp::Vartable::new(); - for field in &tx_irp.fields { - let list: Vec<&str> = field.trim().split('=').collect(); + for field in &transmit.arguments { + let list: Vec<&str> = field.trim().split('=').collect(); - if list.len() != 2 { - eprintln!("argument to --field must be X=1"); - std::process::exit(2); - } - - let value = match if list[1].starts_with("0x") { - i64::from_str_radix(&list[1][2..], 16) - } else if list[1].starts_with("0o") { - i64::from_str_radix(&list[1][2..], 8) - } else if list[1].starts_with("0b") { - i64::from_str_radix(&list[1][2..], 2) - } else { - list[1].parse() - } { - Ok(v) => v, - Err(_) => { - eprintln!("‘{}’ is not a valid number", list[1]); - std::process::exit(2); - } - }; - - vars.set(list[0].to_string(), value); - } - - let irp = match Irp::parse(&tx_irp.irp) { - Ok(m) => m, - Err(s) => { - eprintln!("unable to parse irp ‘{}’: {s}", tx_irp.irp); - std::process::exit(2); - } - }; - - #[allow(unused_mut)] - let mut m = if tx_irp.pronto { - match irp.encode_pronto(vars) { - Ok(p) => { - println!("{p}"); - std::process::exit(0); - } - Err(s) => { - eprintln!("error: {s}"); - std::process::exit(2); - } - } - } else { - match irp.encode_raw(vars, tx_irp.repeats) { - Ok(m) => m, - Err(s) => { - eprintln!("error: {s}"); - std::process::exit(2); - } - } - }; - - #[cfg(target_os = "linux")] - if tx_irp.carrier.is_some() { - m.carrier = tx_irp.carrier; - } - - #[cfg(target_os = "linux")] - if tx_irp.duty_cycle.is_some() { - m.duty_cycle = tx_irp.duty_cycle; - } - - m - } - crate::TransmitCommands::Pronto(pronto) => { - let p = match Pronto::parse(&pronto.pronto) { - Ok(pronto) => pronto, - Err(err) => { - eprintln!("error: {err}"); - std::process::exit(2); - } - }; - - p.encode(pronto.repeats as usize) - } - crate::TransmitCommands::RawIR(rawir) => encode_rawir(rawir), - crate::TransmitCommands::Keymap(args) => { - if args.keymap.to_string_lossy().ends_with(".lircd.conf") { - encode_lircd_conf(args) - } else { - encode_keymap(args) - } - } - } -} - -fn encode_keymap(args: &crate::TransmitKeymap) -> Message { - let remotes = match Keymap::parse_file(&args.keymap) { - Ok(r) => r, - Err(e) => { - log::error!("{e}"); + if list.len() != 2 { + eprintln!("argument to --field must be X=1"); std::process::exit(2); } - }; - - if !args.codes.is_empty() { - let codes: Vec<&str> = args.codes.iter().map(|v| v.as_str()).collect(); - let m = cir::keymap::encode(&remotes, args.remote.as_deref(), &codes, args.repeats); - - match m { - #[allow(unused_mut)] - Ok(mut m) => { - #[cfg(target_os = "linux")] - if args.carrier.is_some() { - m.carrier = args.carrier; - } - - #[cfg(target_os = "linux")] - if args.duty_cycle.is_some() { - m.duty_cycle = args.duty_cycle; - } - - m - } - Err(e) => { - error!("{}", e); - - list_keymap_remotes(&args.keymap, &remotes, None); + let value = match if list[1].starts_with("0x") { + i64::from_str_radix(&list[1][2..], 16) + } else if list[1].starts_with("0o") { + i64::from_str_radix(&list[1][2..], 8) + } else if list[1].starts_with("0b") { + i64::from_str_radix(&list[1][2..], 2) + } else { + list[1].parse() + } { + Ok(v) => v, + Err(_) => { + eprintln!("‘{}’ is not a valid number", list[1]); std::process::exit(2); } - } - } else { - list_keymap_remotes(&args.keymap, &remotes, args.remote.as_deref()); + }; - std::process::exit(2); + vars.set(list[0].to_string(), value); } -} - -fn encode_lircd_conf(lircd: &crate::TransmitKeymap) -> Message { - let remotes = match lircd_conf::parse(&lircd.keymap) { - Ok(r) => r, - Err(_) => std::process::exit(2), - }; - if !lircd.codes.is_empty() { - let codes: Vec<&str> = lircd.codes.iter().map(|v| v.as_str()).collect(); - let m = lircd_conf::encode(&remotes, lircd.remote.as_deref(), &codes, lircd.repeats); + let (lircd_conf, keymap) = if let Some(path) = &transmit.keymap { + if path.to_string_lossy().ends_with(".lircd.conf") { + match lircd_conf::parse(path) { + Ok(r) => { + if transmit.list_codes { + list_lircd_remotes(path, &r, transmit.remote.as_deref()); - match m { - #[allow(unused_mut)] - Ok(mut m) => { - #[cfg(target_os = "linux")] - if lircd.carrier.is_some() { - m.carrier = lircd.carrier; - } + std::process::exit(0); + } - #[cfg(target_os = "linux")] - if lircd.duty_cycle.is_some() { - m.duty_cycle = lircd.duty_cycle; + (Some(r), None) } - - m + Err(_) => std::process::exit(2), } - Err(e) => { - error!("{}", e); + } else { + match Keymap::parse_file(path) { + Ok(r) => { + if transmit.list_codes { + list_keymap_remotes(path, &r, transmit.remote.as_deref()); - list_lircd_remotes(&lircd.keymap, &remotes, None); + std::process::exit(0); + } - std::process::exit(2); + (None, Some(r)) + } + Err(e) => { + log::error!("{e}"); + std::process::exit(2); + } } } } else { - list_lircd_remotes(&lircd.keymap, &remotes, lircd.remote.as_deref()); - - std::process::exit(2); - } -} + (None, None) + }; -fn encode_rawir(transmit: &crate::TransmitRawIR) -> Message { enum Part { Raw(Message), Gap(u32), @@ -366,6 +251,73 @@ fn encode_rawir(transmit: &crate::TransmitRawIR) -> Message { crate::Transmitables::Gap(gap) => { part.push(Part::Gap(*gap)); } + crate::Transmitables::Pronto(pronto) => { + let p = match Pronto::parse(pronto) { + Ok(pronto) => pronto, + Err(err) => { + eprintln!("error: {err}"); + std::process::exit(2); + } + }; + + let m = p.encode(transmit.repeats as usize); + + part.push(Part::Raw(m)); + } + crate::Transmitables::Irp(irp_notation) => { + let irp = match Irp::parse(irp_notation) { + Ok(m) => m, + Err(s) => { + eprintln!("unable to parse irp ‘{}’: {s}", irp_notation); + std::process::exit(2); + } + }; + match irp.encode_raw(vars.clone(), transmit.repeats) { + Ok(m) => { + part.push(Part::Raw(m)); + } + Err(s) => { + eprintln!("error: {s}"); + std::process::exit(2); + } + } + } + crate::Transmitables::Code(code) => { + if let Some(lircd_conf) = &lircd_conf { + match lircd_conf::encode( + lircd_conf, + transmit.remote.as_deref(), + code, + transmit.repeats, + ) { + Ok(m) => { + part.push(Part::Raw(m)); + } + Err(s) => { + eprintln!("error: {s}"); + std::process::exit(2); + } + } + } else if let Some(keymap) = &keymap { + match cir::keymap::encode( + keymap, + transmit.remote.as_deref(), + code, + transmit.repeats, + ) { + Ok(m) => { + part.push(Part::Raw(m)); + } + Err(s) => { + eprintln!("error: {s}"); + std::process::exit(2); + } + } + } else { + eprintln!("error: missing --keymap argument for --code"); + std::process::exit(2); + } + } } } diff --git a/cir/src/keymap/encode.rs b/cir/src/keymap/encode.rs index 71f63894..35511b13 100644 --- a/cir/src/keymap/encode.rs +++ b/cir/src/keymap/encode.rs @@ -8,7 +8,7 @@ use itertools::Itertools; pub fn encode( keymaps: &[Keymap], remote: Option<&str>, - codes: &[&str], + code: &str, repeats: u64, ) -> Result { let mut message = Message::new(); @@ -32,73 +32,63 @@ pub fn encode( } } - for encode_code in codes { - let remotes: Vec<(&Keymap, usize)> = remotes - .iter() - .filter_map(|remote| { - let count = remote - .scancodes - .values() - .filter(|code| code == encode_code) - .count() - + remote - .raw - .iter() - .filter(|code| code.keycode == *encode_code) - .count(); - - if count > 0 { - Some((*remote, count)) - } else { - None - } - }) - .collect(); - - if remotes.len() > 1 { - log::warn!( - "multiple remotes have a definition of code {}: {}", - encode_code, - remotes - .iter() - .map(|remote| remote.0.name.as_str()) - .join(", ") - ); - } + let remotes: Vec<(&Keymap, usize)> = remotes + .iter() + .filter_map(|remote| { + let count = remote.scancodes.values().filter(|v| *v == code).count() + + remote.raw.iter().filter(|v| v.keycode == *code).count(); - if remotes.is_empty() { - return Err(format!("code {encode_code} not found")); - } + if count > 0 { + Some((*remote, count)) + } else { + None + } + }) + .collect(); - let (remote, count) = remotes[0]; + if remotes.len() > 1 { + log::warn!( + "multiple remotes have a definition of code {}: {}", + code, + remotes + .iter() + .map(|remote| remote.0.name.as_str()) + .join(", ") + ); + } - if count > 1 { - log::warn!( - "remote {} has {} definitions of the code {}", - remote.name, - count, - *encode_code - ); - } + if remotes.is_empty() { + return Err(format!("code {code} not found")); + } - for raw_code in &remote.raw { - if raw_code.keycode == *encode_code { - let encoded = remote.encode_raw(raw_code, repeats); + let (remote, count) = remotes[0]; - message.extend(&encoded); + if count > 1 { + log::warn!( + "remote {} has {} definitions of the code {}", + remote.name, + count, + code + ); + } - break; - } + for raw_code in &remote.raw { + if raw_code.keycode == code { + let encoded = remote.encode_raw(raw_code, repeats); + + message.extend(&encoded); + + break; } + } - for (scancode, keycode) in &remote.scancodes { - if keycode == *encode_code { - let encoded = remote.encode_scancode(*scancode, repeats)?; + for (scancode, keycode) in &remote.scancodes { + if keycode == code { + let encoded = remote.encode_scancode(*scancode, repeats)?; - message.extend(&encoded); + message.extend(&encoded); - break; - } + break; } } diff --git a/cir/src/lircd_conf/encode.rs b/cir/src/lircd_conf/encode.rs index 129881cd..a6452a09 100644 --- a/cir/src/lircd_conf/encode.rs +++ b/cir/src/lircd_conf/encode.rs @@ -10,7 +10,7 @@ use num_integer::Integer; pub fn encode( lirc_remotes: &[Remote], remote: Option<&str>, - codes: &[&str], + code_name: &str, repeats: u64, ) -> Result { let mut message = Message::new(); @@ -34,71 +34,69 @@ pub fn encode( } } - for encode_code in codes { - let remotes: Vec<(&Remote, usize)> = remotes - .iter() - .filter_map(|remote| { - let count = remote - .codes - .iter() - .filter(|code| code.name == *encode_code) - .count() - + remote - .raw_codes - .iter() - .filter(|code| code.name == *encode_code) - .count(); - - if count > 0 { - Some((*remote, count)) - } else { - None - } - }) - .collect(); - - if remotes.len() > 1 { - warn!( - "multiple remotes have a definition of code {}: {}", - encode_code, - remotes + let remotes: Vec<(&Remote, usize)> = remotes + .iter() + .filter_map(|remote| { + let count = remote + .codes + .iter() + .filter(|code| code.name == code_name) + .count() + + remote + .raw_codes .iter() - .map(|remote| remote.0.name.as_str()) - .join(", ") - ); - } + .filter(|code| code.name == code_name) + .count(); - if remotes.is_empty() { - return Err(format!("code {encode_code} not found")); - } + if count > 0 { + Some((*remote, count)) + } else { + None + } + }) + .collect(); + + if remotes.len() > 1 { + warn!( + "multiple remotes have a definition of code {}: {}", + code_name, + remotes + .iter() + .map(|remote| remote.0.name.as_str()) + .join(", ") + ); + } - let (remote, count) = remotes[0]; + if remotes.is_empty() { + return Err(format!("code {code_name} not found")); + } - if count > 1 { - warn!( - "remote {} has {} definitions of the code {}", - remote.name, count, *encode_code - ); - } + let (remote, count) = remotes[0]; - for raw_code in &remote.raw_codes { - if raw_code.name == *encode_code { - let encoded = remote.encode_raw(raw_code, repeats)?; + if count > 1 { + warn!( + "remote {} has {} definitions of the code {}", + remote.name, count, code_name + ); + } - message.extend(&encoded); + for raw_code in &remote.raw_codes { + if raw_code.name == code_name { + let encoded = remote.encode_raw(raw_code, repeats)?; - break; - } + message.extend(&encoded); + + break; } + } - for code in &remote.codes { - if code.name == *encode_code { - let encoded = remote.encode(code, repeats)?; + for code in &remote.codes { + if code.name == code_name { + let encoded = remote.encode(code, repeats)?; - message.extend(&encoded); + message.extend(&encoded); - break; - } + break; } } diff --git a/cir/tests/encode_tests.rs b/cir/tests/encode_tests.rs index f08863e2..d0dc00f9 100644 --- a/cir/tests/encode_tests.rs +++ b/cir/tests/encode_tests.rs @@ -8,9 +8,11 @@ fn encode_test() { .args([ "transmit", "--dry-run", - "irp", - "-fF=12", + "-aF=12", + "--irp", "{40k,600}<1,-1|2,-1>(4,-1,F:8,^45m)+[F:0..255]", + "--repeats", + "1", ]) .assert(); @@ -37,8 +39,9 @@ fn encode_lircd_raw_test() { .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "../testdata/lircd_conf/pace/DC420N.lircd.conf", + "--code", "1", ]) .assert(); @@ -67,8 +70,9 @@ fn encode_lircd_aiwa_test() { .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "../testdata/lircd_conf/aiwa/RC-5VP05.lircd.conf", + "-K", "AUTO", ]) .assert(); @@ -96,7 +100,6 @@ fn encode_rawir_test() { .args([ "transmit", "--dry-run", - "rawir", r#"1000 200 1000"#, @@ -122,7 +125,6 @@ fn encode_rawir_test() { .args([ "transmit", "--dry-run", - "rawir", "-f", "../testdata/rawir/mode2", "345", @@ -158,10 +160,11 @@ fn encode_lircd_grundig_test() { .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "../testdata/lircd_conf/grundig/RP75_LCD.lircd.conf", "-m", "grundig_rp75", + "--code", "0", ]) .assert(); @@ -189,8 +192,9 @@ fn empty_lircd_conf() { .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "../testdata/lircd_conf/empty", + "--list-codes", ]) .assert(); @@ -217,8 +221,9 @@ fn keymaps() { "transmit", "--dry-run", "-v", - "keymap", + "--keymap", "../testdata/rc_keymaps/RM-687C.toml", + "--code", "KEY_0", ]) .assert(); @@ -244,8 +249,9 @@ info: rawir: +2369 -637 +1166 -637 +565 -637 +565 -637 +1166 -637 +565 -637 +565 .args([ "transmit", "--dry-run", - "keymap", + "-k", "../testdata/rc_keymaps/RM-786.toml", + "-K", "KEY_CABLEFWD", ]) .assert(); @@ -269,8 +275,9 @@ info: rawir: +2369 -637 +1166 -637 +565 -637 +565 -637 +1166 -637 +565 -637 +565 .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "foo.toml", + "--code", "KEY_CABLEFWD", ]) .assert(); @@ -294,8 +301,9 @@ info: rawir: +2369 -637 +1166 -637 +565 -637 +565 -637 +1166 -637 +565 -637 +565 .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "Cargo.toml", + "--code", "KEY_CABLEFWD", ]) .assert(); @@ -319,8 +327,9 @@ info: rawir: +2369 -637 +1166 -637 +565 -637 +565 -637 +1166 -637 +565 -637 +565 .args([ "transmit", "--dry-run", - "keymap", + "--keymap", "../testdata/rc_keymaps/rc6_mce.toml", + "--code", "KEY_ENTER", "-v", ])