diff --git a/tool/Cargo.lock b/tool/Cargo.lock index 799a9a8..166e70d 100644 --- a/tool/Cargo.lock +++ b/tool/Cargo.lock @@ -1,10 +1,55 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cc" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hidapi" version = "1.2.5" @@ -30,18 +75,73 @@ name = "redox_hwio" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "system76_ectool" version = "0.2.3" dependencies = [ + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)", "redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum cc 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +"checksum hermit-abi 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" "checksum hidapi 1.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76c352a18370f7e7e47bcbfcbdc5432b8c80c705b5d751a25232c659fcf5c775" "checksum libc 0.2.81 (registry+https://github.com/rust-lang/crates.io-index)" = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" "checksum pkg-config 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" "checksum redox_hwio 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41aa2c4c67329a04106644cad336238aa5adecfd73d06fb10339d472ce6d8070" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/tool/Cargo.toml b/tool/Cargo.toml index db742a0..40a0be7 100644 --- a/tool/Cargo.toml +++ b/tool/Cargo.toml @@ -16,6 +16,7 @@ name = "system76_ectool" required-features = ["std"] [dependencies] +clap = "2" libc = { version = "0.2", optional = true } hidapi = { version = "1.2", default-features = false, features = ["linux-static-hidraw"], optional = true } redox_hwio = { version = "0.1.3", optional = true } diff --git a/tool/src/main.rs b/tool/src/main.rs index b90bb73..1741bb6 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -1,3 +1,4 @@ +use clap::{Arg, App, AppSettings, SubCommand}; use ectool::{ Access, AccessLpcLinux, @@ -10,7 +11,7 @@ use ectool::{ SpiTarget, }; use std::{ - env, + fmt::Display, fs, process, str::{self, FromStr}, @@ -262,151 +263,153 @@ unsafe fn keymap_set(layer: u8, output: u8, input: u8, value: u16) -> Result<(), ec.keymap_set(layer, output, input, value) } -fn usage() { - eprintln!(" console"); - eprintln!(" flash [file]"); - eprintln!(" flash_backup [file]"); - eprintln!(" fan [index] "); - eprintln!(" info"); - eprintln!(" keymap [layer] [output] [input] "); - eprintln!(" print [message]"); -} - -fn parse_arg_opt, F: FromStr>(args: &mut I, name: &str) -> Option { - match args.next() { - Some(arg) => match arg.parse::() { - Ok(ok) => Some(ok), - Err(_err) => { - eprintln!("failed to parse {}: '{}'", name, arg); - process::exit(1); - }, - }, - None => None, - } -} - -fn parse_arg, F: FromStr>(args: &mut I, name: &str) -> F { - match parse_arg_opt(args, name) { - Some(some) => some, - None => { - eprintln!("no {} provided", name); - process::exit(1); - } - } +fn validate_from_str(s: String) -> Result<(), String> + where T::Err: Display { + s.parse::() + .and(Ok(())) + .map_err(|err| format!("{}", err)) } fn main() { - let mut args = env::args().skip(1); - match args.next() { - Some(arg) => match arg.as_str() { - "console" => match unsafe { console() } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to read console: {:X?}", err); - process::exit(1); - }, - }, - "fan" => { - let index = parse_arg(&mut args, "index"); - let duty_opt = parse_arg_opt(&mut args, "duty"); - match duty_opt { - Some(duty) => match unsafe { fan_set(index, duty) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to set fan {} to {}: {:X?}", index, duty, err); - process::exit(1); - }, - }, - None => match unsafe { fan_get(index) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to get fan {}: {:X?}", index, err); - process::exit(1); - }, - }, - } - }, - "flash" => match args.next() { - Some(path) => match unsafe { flash(&path, SpiTarget::Main) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to flash '{}': {:X?}", path, err); - process::exit(1); - }, - }, - None => { - eprintln!("no file provided"); - process::exit(1); - } - }, - "flash_backup" => match args.next() { - Some(path) => match unsafe { flash(&path, SpiTarget::Backup) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to flash '{}': {:X?}", path, err); - process::exit(1); - }, - }, - None => { - eprintln!("no file provided"); - process::exit(1); - } - }, - "info" => match unsafe { info() } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to read info: {:X?}", err); - process::exit(1); - }, - }, - "keymap" => { - let layer = parse_arg(&mut args, "layer"); - let output = parse_arg(&mut args, "output"); - let input = parse_arg(&mut args, "input"); - match args.next() { - Some(value_str) => match u16::from_str_radix(value_str.trim_start_matches("0x"), 16) { - Ok(value) => match unsafe { keymap_set(layer, output, input, value) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to set keymap {}, {}, {} to {}: {:X?}", layer, output, input, value, err); - process::exit(1); - }, - }, - Err(err) => { - eprintln!("failed to parse value: '{}': {}", arg, err); - process::exit(1); - } - }, - None => match unsafe { keymap_get(layer, output, input) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to get keymap {}, {}, {}: {:X?}", layer, output, input, err); - process::exit(1); - }, - }, - } - }, - "print" => for mut arg in args { - arg.push('\n'); - match unsafe { print(&arg.as_bytes()) } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to print '{}': {:X?}", arg, err); - process::exit(1); - }, - } - }, - _ => { - eprintln!("unknown subcommand '{}'", arg); - usage(); + let matches = App::new("system76_ectool") + .setting(AppSettings::SubcommandRequired) + .subcommand(SubCommand::with_name("console")) + .subcommand(SubCommand::with_name("fan") + .arg(Arg::with_name("index") + .validator(validate_from_str::) + .required(true) + ) + .arg(Arg::with_name("duty") + .validator(validate_from_str::) + ) + ) + .subcommand(SubCommand::with_name("flash") + .arg(Arg::with_name("path") + .required(true) + ) + ) + .subcommand(SubCommand::with_name("flash_backup") + .arg(Arg::with_name("path") + .required(true) + ) + ) + .subcommand(SubCommand::with_name("info")) + .subcommand(SubCommand::with_name("keymap") + .arg(Arg::with_name("layer") + .validator(validate_from_str::) + .required(true) + ) + .arg(Arg::with_name("output") + .validator(validate_from_str::) + .required(true) + ) + .arg(Arg::with_name("input") + .validator(validate_from_str::) + .required(true) + ) + .arg(Arg::with_name("value")) + ) + .subcommand(SubCommand::with_name("print") + .arg(Arg::with_name("message") + .required(true) + .multiple(true) + ) + ) + .get_matches(); + + match matches.subcommand() { + ("console", Some(_sub_m)) => match unsafe { console() } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to read console: {:X?}", err); process::exit(1); }, }, - None => { - eprintln!("no subcommand provided"); - usage(); - process::exit(1); + ("fan", Some(sub_m)) => { + let index = sub_m.value_of("index").unwrap().parse::().unwrap(); + let duty_opt = sub_m.value_of("duty").map(|x| x.parse::().unwrap()); + match duty_opt { + Some(duty) => match unsafe { fan_set(index, duty) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to set fan {} to {}: {:X?}", index, duty, err); + process::exit(1); + }, + }, + None => match unsafe { fan_get(index) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to get fan {}: {:X?}", index, err); + process::exit(1); + }, + }, + } }, + ("flash", Some(sub_m)) => { + let path = sub_m.value_of("path").unwrap(); + match unsafe { flash(&path, SpiTarget::Main) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to flash '{}': {:X?}", path, err); + process::exit(1); + }, + } + }, + ("flash_backup", Some(sub_m)) => { + let path = sub_m.value_of("path").unwrap(); + match unsafe { flash(&path, SpiTarget::Backup) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to flash '{}': {:X?}", path, err); + process::exit(1); + }, + } + }, + ("info", Some(_sub_m)) => match unsafe { info() } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to read info: {:X?}", err); + process::exit(1); + }, + }, + ("keymap", Some(sub_m)) => { + let layer = sub_m.value_of("layer").unwrap().parse::().unwrap(); + let output = sub_m.value_of("output").unwrap().parse::().unwrap(); + let input = sub_m.value_of("input").unwrap().parse::().unwrap(); + match sub_m.value_of("value") { + Some(value_str) => match u16::from_str_radix(value_str.trim_start_matches("0x"), 16) { + Ok(value) => match unsafe { keymap_set(layer, output, input, value) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to set keymap {}, {}, {} to {}: {:X?}", layer, output, input, value, err); + process::exit(1); + }, + }, + Err(err) => { + eprintln!("failed to parse value: '{}': {}", value_str, err); + process::exit(1); + } + }, + None => match unsafe { keymap_get(layer, output, input) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to get keymap {}, {}, {}: {:X?}", layer, output, input, err); + process::exit(1); + }, + }, + } + }, + ("print", Some(sub_m)) => for arg in sub_m.values_of("message").unwrap() { + let mut arg = arg.to_owned(); + arg.push('\n'); + match unsafe { print(&arg.as_bytes()) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to print '{}': {:X?}", arg, err); + process::exit(1); + }, + } + }, + _ => unreachable!() } - }