diff --git a/rust/.gitignore b/rust/.gitignore index c41cc9e..9437db6 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +/Cargo.lock \ No newline at end of file diff --git a/rust/Cargo.lock b/rust/Cargo.lock deleted file mode 100644 index a5eec72..0000000 --- a/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "tockloader" -version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 9c93b89..59905e5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.1.1", features = ["cargo"] } diff --git a/rust/src/cli.rs b/rust/src/cli.rs new file mode 100644 index 0000000..51d4fa3 --- /dev/null +++ b/rust/src/cli.rs @@ -0,0 +1,72 @@ +use clap::{arg, crate_version, Command}; + +/// Create the [command](clap::Command) object which will handle all of the command line arguments. +pub fn make_cli() -> Command { + Command::new("tockloader") + .about("This is a sample description.") + .version(crate_version!()) + .arg_required_else_help(true) + .subcommands(get_subcommands()) + .args([ + arg!(--debug "Print additional debugging information").action(clap::ArgAction::SetTrue) + ]) + // Note: arg_require_else_help will trigger the help command if no argument/subcommand is given. + // This means that the --debug flag will not trigger the help menu, even if alone it does nothing. +} + +/// Generate all of the [subcommands](clap::Command) used by the program. +fn get_subcommands() -> Vec { + vec![Command::new("listen") + .about("Open a terminal to receive UART data") + .args(get_app_args()) + .args(get_channel_args()) + .arg_required_else_help(true)] +} + +/// Generate all of the [arguments](clap::Arg) that are required by subcommands which work with apps. +fn get_app_args() -> Vec { + vec![ + arg!(-a --"app-address"
"Address where apps are located"), + arg!(--force "Allow apps on boards that are not listed as compatible") + .action(clap::ArgAction::SetTrue), + arg!(--"bundle-apps" "Concatenate apps and flash all together, re-flashing apps as needed") + .action(clap::ArgAction::SetTrue), + ] + // Note: the .action(clap::ArgAction::SetTrue) doesn't seem to be necessary, though in clap documentation it is used. +} + +/// Generate all of the [arguments](clap::Arg) that are required by subcommands which work +/// with channels and computer-board communication. +fn get_channel_args() -> Vec { + vec![ + arg!(-p --port "The serial port or device name to use"), + arg!(--serial "Use the serial bootloader to flash") + .action(clap::ArgAction::SetTrue), + arg!(--jlink "Use JLinkExe to flash") + .action(clap::ArgAction::SetTrue), + arg!(--openocd "Use OpenOCD to flash") + .action(clap::ArgAction::SetTrue), + arg!(--"jlink-device" "The device type to pass to JLinkExe. Useful for initial commissioning.") + .default_value("cortex-m0"), + arg!(--"jlink-cmd" "The JLinkExe binary to invoke"), + arg!(--"jlink-speed" "The JLink speed to pass to JLinkExe"), + arg!(--"jlink-if" "The interface type to pass to JLinkExe"), + arg!(--"openocd-board" "The cfg file in OpenOCD `board` folder"), + arg!(--"openocd-cmd" "The openocd binary to invoke") + .default_value("openocd"), + // These may not work out of the box + arg!(--"openocd-options" "Tockloader-specific flags to direct how Tockloader uses OpenOCD"), + arg!(--"openocd-commands" "Directly specify which OpenOCD commands to use for \"program\", \"read\", or \"erase\" actions"), + // ----- + arg!(--"flash-file" "Operate on a binary flash file instead of a proper board") + .action(clap::ArgAction::SetTrue), + arg!(--board "Explicitly specify the board that is being targeted"), + arg!(--arch "Explicitly specify the architecture of the board that is being targeted"), + arg!(--"page-size" "Explicitly specify how many bytes in a flash page") + .default_value("0"), + arg!(--"baud-rate" "If using serial, set the target baud rate") + .default_value("115200"), + arg!(--"no-bootloader-entry" "Tell Tockloader to assume the bootloader is already active") + .action(clap::ArgAction::SetTrue), + ] +} diff --git a/rust/src/main.rs b/rust/src/main.rs index e7a11a9..8048d20 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,3 +1,27 @@ +mod cli; +use cli::make_cli; + fn main() { - println!("Hello, world!"); + let matches = make_cli().get_matches(); + + if matches.get_flag("debug") { + println!("Debug mode enabled"); + } + + match matches.subcommand() { + Some(("listen", sub_matches)) => { + println!("Got the listen subcommand"); + let default_adr = "NONE".to_string(); + let adr = sub_matches + .get_one::("app-address") + .unwrap_or(&default_adr); + println!("{}", format!("With App Address {adr}")); + } + // If only the "--debug" flag is set, then this branch is executed + // Or, more likely at this stage, a subcommand hasn't been implemented yet. + _ => { + println!("Could not run the provided subcommand."); + _ = make_cli().print_help(); + } + } }