Skip to content

Commit

Permalink
Implement Parameter Space Tooling (#1)
Browse files Browse the repository at this point in the history
* implement `mionps`/`mionparamspace`

this pr completely re-implements `mionps`, and `mionparamspace` in
sprig tooling. there probably isn't too many uses for `mionps`, and
`mionparamspace` directly, they're mostly just blockers for
re-implementing `cafe.bat`/`cafex.bat`/`mochiato`. They also seemed
like a much easier thing to "bite off" rather than taking a stab at
`FSEmul.exe` even though FSEmul will be the most useful part because
it seems like it's the actual PCFS implementation.

this took me way too long to do because frankly paramspace while small,
it's CLI tools are a pretty gigantic mess, and i just was NOT feeling it
with all the other personal stuff going on.

* add get-parameters/set-parameters to bridgectl

this ports over the equivalents of `mionps`/`mionparamspace` to
`bridgectl`. users can now get/set many parameters at once as
opposed to needing to call the CLI multiple times.

it also supports actually using parameter names rather than just
indexes, and setting values to hex values which is what dump, and
others show you anyway.

* add `dump-parameters` command

this adds in the last command bridgectl needs for the parameters port
part of the cat-dev, this is a shortcut for grabbing all the parameters
at once.
  • Loading branch information
Mythra authored Feb 5, 2024
1 parent ea6e96d commit ddcccc6
Show file tree
Hide file tree
Showing 38 changed files with 4,292 additions and 467 deletions.
346 changes: 192 additions & 154 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ members = [
"cmd/bridgectl",
"cmd/findbridge",
"cmd/getbridgeconfig",
"cmd/mionps",
"cmd/mionparamspace",
"cmd/setbridgeconfig",
"pkg/cat-dev",
"pkg/log",
Expand All @@ -15,17 +17,18 @@ fnv = "^1.0.7"
mac_address = "^1.1.5"
miette = { version = "^5.10.0", features = ["fancy"] }
network-interface = "^1.1.1"
once_cell = "^1.18.0"
once_cell = "^1.19.0"
time = "^0.3.31"
tracing = { version = "^0.1.40", features = ["valuable"] }
tokio = { version = "^1.34.0", features = ["full", "tracing"] }
tokio = { version = "^1.35.1", features = ["full", "tracing"] }
valuable = { version = "^0.1.0", features = ["derive"] }

[workspace.package]
authors = ["Cynthia <[email protected]>"]
edition = "2021"
license = "MIT"
repository = "https://github.com/rem-verse/sprig"
version = "0.0.1"
version = "0.0.2"

[profile.release]
codegen-units = 1
Expand Down
55 changes: 37 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ how these Development Environments exist.
something related to preservation, and don't have one. PLEASE reach out, I'd
be more than happy to use my hardware to test things for you.***

## Why The Name Sprig? ##

The name "sprig" was chosen after "sprigatito" the "Weed Cat Pokemon", because
not only was the code name for the Wii-U "CAT" (cat-dev/cat-r/etc.), and the
fact "Cat Bridge - Dev" is shortened to CBD (thus 'weed'). Plus Sprig is just a
fun word to say.

## What Parts Are Re-Implemented ##

As mentioned at the top of this repository ALMOST ALL of the tools here are
Expand All @@ -30,6 +37,18 @@ compilers besides MULTI (so we don't need the license keys!), and a suite of
tools designed from the ground up to offer a pleasent development experience.
As some of the CLI choices of the Cafe SDK are not great choices looking back.

### Overarching Cafe Tools ###

Official Tool Replacements:

- [ ] `cafe.bat`
- [ ] `cafex_env.bat`
- [ ] `cafex`

Sprig Custom Tooling:

- [ ] `mochiato`: our replacement for `cafe.bat`/`cafex_env.bat`

### Host Bridge Tools ###

The "Host Bridge" tools are a series of tools used for setting up a connection
Expand Down Expand Up @@ -67,17 +86,24 @@ Sprig Custom Tooling:
- [-] `bridgectl`: our replacement tool that wraps all the bridge commands, and
host-bridge utilities into a single tool.

## Overarching Cafe Tools ##

Official Tool Replacements:

- [ ] `cafe.bat`
- [ ] `cafex_env.bat`
- [ ] `cafex`

Sprig Custom Tooling:

- [ ] `mochiato`: our replacement for `cafe.bat`/`cafex_env.bat`
### Cat-Dev Bridge Internal Tools ###

There are some tools that are not explicitly mentioned being tools in any parts
of the developer facing documentation, however they are used for interacting
with that cat-dev bridges a developer would have used. Sometimes, these tools
were also used to build things ontop of them (e.g. `mionps` is used during
`cafe.bat`).

- [ ] `CatLog`: a port of the the csharp "CatLog" utility who's source was
included in some of the cafe sdk releases, which receives logs over
the serial port.
- [x] `mionps`: a tool used to fetch the "parameter space"
from a particular MION board. It is not clear what the parameter space
is, but it contains a whole bunch of configuration values you can
get/set.
- [x] `mionparameterspace`: a tool like `mionps`, but it has different output
and is probably an older version of `mionps` that couldn't be removed
cause someone depended on it's behavior somewhere.

## Building ##

Expand Down Expand Up @@ -114,10 +140,3 @@ on the OS you're using:
From there you can run: `./installer-scripts/<os-type>/<install scripts>`, and
read: `./installer-scripts/<os-type>/README.md` to get instructions on how to
build things for your OS.

## Why The Name Sprig? ##

The name "sprig" was chosen after "sprigatito" the "Weed Cat Pokemon", because
not only was the code name for the Wii-U "CAT" (cat-dev/cat-r/etc.), and the
fact "Cat Bridge - Dev" is shortened to CBD (thus 'weed'). Plus Sprig is just a
fun word to say.
2 changes: 1 addition & 1 deletion cmd/bridgectl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ publish = false

[dependencies]
cat-dev = { path = "../../pkg/cat-dev" }
clap = { version = "^4.4.10", features = ["color", "derive", "env", "error-context", "help", "suggestions", "unicode", "usage", "wrap_help"] }
clap = { version = "^4.4.18", features = ["color", "derive", "env", "error-context", "help", "suggestions", "unicode", "usage", "wrap_help"] }
fnv.workspace = true
log = { path = "../../pkg/log" }
mac_address.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions cmd/bridgectl/src/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async fn mion_find_by_name_or_ip(use_json: bool, bridge_name_or_ip: String) -> (
if use_json {
error!(
id = "bridgectl::add::failed_to_execute_broadcast",
cause = ?cause,
?cause,
help = "Could not setup sockets to broadcast and search for all MIONs; perhaps another program is already using the single MION port?",
);
} else {
Expand Down Expand Up @@ -245,7 +245,7 @@ async fn mion_find_name_from_ip(use_json: bool, bridge_ip: Ipv4Addr) -> String {
if use_json {
error!(
id = "bridgectl::add::failed_to_execute_search",
cause = ?cause,
?cause,
ip = %bridge_ip,
help = "Could not send packet directly to MION perhaps it's not on, or reachable?",
);
Expand Down
202 changes: 202 additions & 0 deletions cmd/bridgectl/src/commands/argv_helpers/bridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
//! Common helpers for dealing with bridge arguments.
use crate::{
exit_codes::{
ARGV_COULD_NOT_GET_DEFAULT_BRIDGE, GET_DEFAULT_CONFLICTING_FILTERS,
GET_DEFAULT_WITH_FILTERS,
},
utils::{add_context_to, bridge_state_from_path, get_bridge_state_path},
};
use mac_address::MacAddress;
use miette::miette;
use std::{net::Ipv4Addr, path::PathBuf};
use tracing::{error, field::valuable};

/// Attempt to get the filters to use to "find" a bridge from all of the
/// arguments.
///
/// This will return `None` if you should just find the default bridge.
/// This will return `Some` if you need to execute some sort of broadcast
/// to find the bridge.
///
/// - `use_json`: if we're outputting json logs.
/// - `just_fetch_default`: if the user specified the equivalent of a
/// `--default` flag.
/// - `flag_arguments`: The three flag filtering arguments ip/mac/name.
/// - `positional_argument`: The positional argument that could be the bridge
/// name.
/// - `positional_specified_is_bridge_name`: Some commands may have argv1 be
/// a bridge name, but ALTERNATIVELY it could be param 2, and they just used
/// flags to filter the bridge. This boolean lets you denote whether they
/// actually specified it as a name.
///
/// ## Panics
///
/// This function will exit/panic the program if the user specified conflicting
/// arguments (e.g. flag + positional of the same field).
pub fn coalesce_bridge_arguments(
use_json: bool,
just_fetch_default: bool,
flag_arguments: (Option<Ipv4Addr>, Option<String>, Option<String>),
positional_argument: Option<String>,
positional_specified_is_bridge_name: bool,
) -> Option<(Option<Ipv4Addr>, Option<MacAddress>, Option<String>)> {
if just_fetch_default {
if flag_arguments.0.is_some()
|| flag_arguments.1.is_some()
|| flag_arguments.2.is_some()
|| positional_specified_is_bridge_name
{
if use_json {
error!(
id = "bridgectl::argv::no_filters_allowed_on_default",
flags.ip = ?flag_arguments.0,
flags.mac = ?flag_arguments.1,
flags.name = ?flag_arguments.2,
args.positional = ?positional_argument,
suggestions = valuable(&[
"If you want to fetch the default bridge all you need to do is run: `bridgectl get-parameters <parameters> --default`",
"If you want to apply extra filtering you can do something like outputting JSON, and using `jq` to filter",
]),
);
} else {
error!(
"\n{:?}",
add_context_to(
miette!("Cannot specify filters when fetching the default bridge!"),
[
miette!("If you want to fetch the default bridge all you need to do is run: `bridgectl get-parameters <parameters> --default`."),
miette!(
help = format!(
"Flags: (--ip: `{:?}`, --mac: `{:?}`, --name: `{:?}`) / Positional Argument: `{:?}`",
flag_arguments.0,
flag_arguments.1,
flag_arguments.2,
positional_argument,
),
"If you want to apply extra filtering you can do something like outputting JSON, and using `jq` to filter.",
),
].into_iter(),
),
);
}

std::process::exit(GET_DEFAULT_WITH_FILTERS);
}

None
} else {
Some(coalesce_bridge_search_arguments(
use_json,
flag_arguments,
positional_argument,
))
}
}

/// Get the default bridge, or exit out if there is no default bridge
/// configured.
///
/// ## Panics
///
/// Will panic if there is no default bridge that has been configured.
pub async fn get_default_bridge(
use_json: bool,
host_state_path: Option<PathBuf>,
) -> (String, Option<Ipv4Addr>) {
let bridge_state =
bridge_state_from_path(get_bridge_state_path(&host_state_path, use_json), use_json).await;

if let Some(default_bridge) = bridge_state.get_default_bridge() {
default_bridge
} else if use_json {
error!(
id = "bridgectl::argv::no_default_bridge",
host_state_path = %bridge_state.get_path().display(),
suggestions = valuable(&[
"Please double check the configuration file located at the path specified, and ensure `BRIDGE_DEFAULT_NAME` is set to a real bridge name.",
"If the bridge isn't set as the default you can use `bridge add --default <name> <ip>`, or `bridge set-default <'name' or 'ip'>`.",
]),
"No default bridge present in configuration file.",
);
std::process::exit(ARGV_COULD_NOT_GET_DEFAULT_BRIDGE);
} else {
error!(
"\n{:?}",
add_context_to(
miette!("No default bridge present in the configuration file."),
[
miette!("Please double check the configuration file located at the path specified, and ensure `BRIDGE_DEFAULT_NAME` is set to a real bridge name."),
miette!(
help = format!("The bridge configuration file was located at: {}", bridge_state.get_path().display()),
"If the bridge isn't set as the default you can use `bridge add --default <name> <ip>`, or `bridge set-default <'name' or 'ip'>`.",
),
].into_iter(),
),
);
std::process::exit(ARGV_COULD_NOT_GET_DEFAULT_BRIDGE);
}
}

fn coalesce_bridge_search_arguments(
use_json: bool,
flag_arguments: (Option<Ipv4Addr>, Option<String>, Option<String>),
cli_arguments: Option<String>,
) -> (Option<Ipv4Addr>, Option<MacAddress>, Option<String>) {
let mac_flag = flag_arguments
.1
.and_then(|mac| MacAddress::try_from(mac.as_str()).ok());
let Some(cli_arg) = cli_arguments else {
return (flag_arguments.0, mac_flag, flag_arguments.2);
};

if let Ok(arg_as_ip) = cli_arg.parse::<Ipv4Addr>() {
if flag_arguments.0.is_none() {
return (Some(arg_as_ip), mac_flag, flag_arguments.2);
}
}
if let Ok(arg_as_mac) = cli_arg.parse::<MacAddress>() {
if mac_flag.is_none() {
return (flag_arguments.0, Some(arg_as_mac), flag_arguments.2);
}
}
if flag_arguments.2.is_none() {
return (flag_arguments.0, mac_flag, Some(cli_arg));
}

if use_json {
error!(
id = "bridgectl::argv::conflicting_filters_on_get",
flags.ip = ?flag_arguments.0,
flags.mac = ?mac_flag,
flags.name = ?flag_arguments.2,
args.positional = cli_arg,
suggestions = valuable(&[
"If the positional argument is a name, it may be trying to be parsed as something like an IP/Mac.",
"Get bridge can only filter down to one bridge, if you're trying to apply multiple ip filters/name filters/mac filters either use multiple `bridgectl get` calls, or use something like `bridgectl list`.",
]),
);
} else {
error!(
"\n{:?}",
add_context_to(
miette!("Positional argument conflicts with flag arguments!"),
[
miette!("If the positional argument is a name, it may be trying to be parsed as something like an IP/Mac."),
miette!(
help = format!(
"Flags: (--ip: `{:?}`, --mac: `{:?}`, --name: `{:?}`) / Positional Argument: `{:?}`",
flag_arguments.0,
mac_flag,
flag_arguments.2,
cli_arg,
),
"Get bridge can only filter down to one bridge, if you're trying to apply multiple ip filters/name filters/mac filters either use multiple `bridgectl get` calls, or use something like `bridgectl list`.",
),
].into_iter(),
),
);
}

std::process::exit(GET_DEFAULT_CONFLICTING_FILTERS);
}
7 changes: 7 additions & 0 deletions cmd/bridgectl/src/commands/argv_helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//! Argument helpers for commands that take a lot of the exact same arguments.
mod bridge;
mod strings;

pub use bridge::*;
pub use strings::*;
34 changes: 34 additions & 0 deletions cmd/bridgectl/src/commands/argv_helpers/strings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! String utility helpers
use std::{fmt::Display, num::ParseIntError};

/// Get a string potentially padded with spaces, or cut off with '...'.
pub fn get_padded_string(ty: impl Display, max_length: usize) -> String {
let mut to_return = String::with_capacity(max_length);
let as_display = format!("{ty}");
if as_display.len() > max_length {
to_return.push_str(&as_display[..(max_length - 3)]);
to_return.push_str("...");
} else {
to_return = as_display;
while to_return.len() < max_length {
to_return.push(' ');
}
}
to_return
}

/// Get a byte value which could potentially be a hex value.
pub fn get_byte_value(value: &str) -> Result<u8, ParseIntError> {
if let Some(hex_value) = value.strip_prefix("0x") {
u8::from_str_radix(hex_value, 16)
} else if value
.to_lowercase()
.chars()
.any(|character| matches!(character, 'a'..='f'))
{
u8::from_str_radix(value, 16)
} else {
value.parse::<u8>()
}
}
Loading

0 comments on commit ddcccc6

Please sign in to comment.