1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
use std::path::PathBuf;
use clap::Parser;
/// Access every feature of the Nintendo Switch controllers
///
/// Env variables:
///
/// - `RUST_LOG=<level>`:
///
/// - `trace`: log every bluetooth packet
///
/// - `debug`: only log important packets
///
/// - `LOG_PRETTY=1`: use a more verbose logging format
///
/// - `LOG_TIMING=1`: show timings
#[derive(Parser)]
pub struct Opts {
#[clap(subcommand)]
pub subcmd: SubCommand,
/// Wait for a controller to connect
#[clap(short, long)]
pub wait: bool,
}
#[derive(Parser)]
pub enum SubCommand {
/// Calibrate the controller
///
/// The calibration will be stored on the controller and used by the Switch.
Calibrate(Calibrate),
/// Print settings from the controller
Get,
/// Configure settings of the controller
Set(Set),
/// Show live inputs from the controller
Monitor,
PulseRate,
#[cfg(feature = "interface")]
Tui,
/// Dump the memory of the controller to a binary file
Dump,
/// Restore the memory of the controller from a dump file
Restore,
/// Decode raw reports exchanged between the controller and the Switch
///
/// See the `relay` subcommand to record new traces.
///
/// See the `trace/` folder for recorded dumps, and
/// [relay_joycon.py](https://github.com/Yamakaky/joycontrol/blob/capture-text-file/scripts/relay_joycon.py)
/// for capturing new dumps.
Decode,
/// Relay the bluetooth trafic between a controller and the Switch
///
/// Important commands are decoded and shown, and a full log can be recorded.
/// See the `decode` subcommand to decode logs.
Relay(Relay),
/// Ringcon-specific actions
Ringcon(Ringcon),
Camera,
}
#[derive(Parser)]
pub struct Calibrate {
#[clap(subcommand)]
pub subcmd: CalibrateE,
}
#[derive(Parser)]
pub enum CalibrateE {
/// Calibrate the sticks
Sticks,
/// Calibrate the gyroscope
Gyroscope,
/// Reset gyroscope and sticks calibration to factory values
Reset,
}
#[derive(Parser)]
pub struct Set {
#[clap(subcommand)]
pub subcmd: SetE,
}
#[derive(Parser)]
pub enum SetE {
/// Change the color of the controller
///
/// This is used by the switch for the controller icons. Every color is in `RRGGBB` format.
Color(SetColor),
}
#[derive(Parser)]
pub struct SetColor {
/// Color of the body of the controller
pub body: String,
/// Color of the buttons, sticks and triggers
pub buttons: String,
/// Color of the left grip (Pro Controller only)
pub left_grip: Option<String>,
/// Color of the right grip (Pro Controller only)
pub right_grip: Option<String>,
}
#[derive(Parser)]
pub struct Ringcon {
#[clap(subcommand)]
pub subcmd: RingconE,
}
#[derive(Parser)]
pub enum RingconE {
/// Get the number of flex stored in the ringcon
StoredFlex,
/// Show the flex value in realtime
Monitor,
/// Random experiments
Exp,
}
#[derive(Parser)]
pub struct Relay {
/// Bluetooth MAC address of the Switch
#[clap(short, long, validator(is_mac))]
pub address: String,
/// Location of the log to write
#[clap(short, long)]
pub output: Option<PathBuf>,
/// Decode important HID reports and print them to stdout
#[clap(short, long)]
pub verbose: bool,
}
fn is_mac(input: &str) -> Result<(), String> {
let mut i = 0;
for x in input.split(":").map(|x| u8::from_str_radix(x, 16)) {
match x {
Ok(_) => i += 1,
Err(e) => return Err(format!("MAC parsing error: {}", e)),
}
}
if i == 6 {
Ok(())
} else {
Err("invalid MAC address".to_string())
}
}