diff --git a/Cargo.lock b/Cargo.lock index 299ba72..5204622 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,6 +222,12 @@ dependencies = [ "windows", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "syn" version = "2.0.106" @@ -253,6 +259,7 @@ dependencies = [ "pbr", "serial2", "serial_enumerator", + "shlex", "termion", ] diff --git a/Cargo.toml b/Cargo.toml index a5d3d4a..fa22414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ argp = "0.4.0" pbr = "1.1.1" serial2 = "0.2.32" serial_enumerator = "0.2.12" +shlex = "1.3.0" termion = "4.0.5" diff --git a/src/args.rs b/src/args.rs index 6a2ec6e..94cb725 100644 --- a/src/args.rs +++ b/src/args.rs @@ -55,6 +55,10 @@ pub struct ArgWrite { #[argp(description = "Path to the source Intel HEX file.")] pub path: OsString, + #[argp(option)] + #[argp(description = "Command to run before writing the file. Handy for compiling the program and running it at the same time.")] + pub cmd: Option, + #[argp(option, default = "0")] #[argp(description = "Start address where to write from. Only for raw binaries, defaults to 0.")] pub start: usize, diff --git a/src/main.rs b/src/main.rs index 2da4b81..4bb947f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use std::ffi::OsString; use std::io::{Cursor, Error, Write}; use std::time::{Duration, SystemTime}; @@ -201,12 +202,35 @@ fn write_chip_data(args: &ArgWrite, target: &mut PhysicalTarget) -> Result<(), E fn write_chip(args: ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error> { loop { + if let Some(cmd) = args.cmd.as_ref() { + let mut args = shlex::bytes::split(cmd.as_encoded_bytes()) + .ok_or(Error::other("Error parsing commandline arguments"))? + .into_iter() + .map(|x| unsafe { OsString::from_encoded_bytes_unchecked(x) }); + + let Some(name) = args.next() else { + Err(Error::other("No command provided"))? + }; + + let out = std::process::Command::new(name) + .args(args) + .output()?; + + if !out.status.success() { + Err(Error::other(format!("Command failed with exit code {}:\n\n{}", + out.status.code().unwrap_or(1), + String::from_utf8_lossy(&out.stderr))))? + } + + println!("Command `{}` successful.", cmd.to_string_lossy()); + } + write_chip_data(&args, target)?; if !args.monitor { break } let cause = Monitor::new() - .add_hook(Key::Ctrl('f'), "Re-flash target") + .add_hook(Key::Ctrl('f'), if args.cmd.is_none() { "Re-flash target" } else { "Re-run command and flash target" }) .run(target.port())?; if cause != Key::Ctrl('f') { break } @@ -241,7 +265,13 @@ fn main() { } None - }).unwrap(); + }); + + let Some(port) = port else { + println!("Could not find any compatible serial port. Please make sure that the target is connected."); + println!("If the issue persists, please specify the port manually with the `--port ...` argument."); + std::process::exit(1); + }; let mut target = PhysicalTarget::init(port, if args.slow { 57600 } else { 312500 }).unwrap(); @@ -254,6 +284,7 @@ fn main() { if let Err(err) = res { println!("An error occured during the operation: {}", err); + std::process::exit(1); } let end = SystemTime::now();