]> code.octet-stream.net Git - m17rt/blobdiff - tools/m17rt-netclient/src/main.rs
Change clap to use derive syntax
[m17rt] / tools / m17rt-netclient / src / main.rs
index fbcfb155284981e5f958355c97937a1797fca35d..f8b189688a5180bc061f469085f88e358da850b4 100644 (file)
@@ -1,6 +1,6 @@
 use std::{io::stdin, sync::Arc};
 
-use clap::{Arg, value_parser};
+use clap::Parser;
 use m17app::{
     adapter::StreamAdapter,
     app::M17App,
@@ -9,76 +9,65 @@ use m17app::{
 };
 use m17codec2::{rx::Codec2RxAdapter, tx::Codec2TxAdapter};
 
+#[derive(Parser)]
+struct Args {
+    #[arg(short = 's', help = "Domain or IP of reflector")]
+    hostname: String,
+    #[arg(
+        short = 'p',
+        default_value = "17000",
+        help = "Reflector listening port"
+    )]
+    port: u16,
+    #[arg(short = 'c', value_parser = valid_callsign, help = "Your callsign for reflector registration and transmissions")]
+    callsign: M17Address,
+    #[arg(short = 'r', value_parser = valid_callsign, help = "Reflector designator/callsign, often starting with 'M17-'")]
+    reflector: M17Address,
+    #[arg(short = 'm', value_parser = valid_module, help = "Module to connect to (A-Z)")]
+    module: char,
+    #[arg(
+        short = 'i',
+        help = "Soundcard name for microphone, otherwise system default"
+    )]
+    input: Option<String>,
+    #[arg(
+        short = 'o',
+        help = "Soundcard name for speaker, otherwise system default"
+    )]
+    output: Option<String>,
+}
+
 fn main() {
-    let args = clap::Command::new("m17rt-netclient")
-        .arg(
-            Arg::new("hostname")
-                .long("hostname")
-                .short('s')
-                .required(true)
-                .help("Domain or IP of reflector"),
-        )
-        .arg(
-            Arg::new("port")
-                .long("port")
-                .short('p')
-                .value_parser(value_parser!(u16))
-                .default_value("17000")
-                .help("Reflector listening port"),
-        )
-        .arg(
-            Arg::new("callsign")
-                .long("callsign")
-                .short('c')
-                .value_parser(valid_callsign)
-                .required(true)
-                .help("Your callsign for reflector registration and transmissions"),
-        )
-        .arg(
-            Arg::new("module")
-                .long("module")
-                .short('m')
-                .value_parser(valid_module)
-                .required(true)
-                .help("Module to connect to (A-Z)"),
-        )
-        .arg(
-            Arg::new("input")
-                .long("input")
-                .short('i')
-                .help("Soundcard name for microphone, otherwise system default"),
-        )
-        .arg(
-            Arg::new("output")
-                .long("output")
-                .short('o')
-                .help("Soundcard name for speaker, otherwise system default"),
-        )
-        .get_matches();
+    let args = Args::parse();
 
-    let hostname = args.get_one::<String>("hostname").unwrap();
-    let port = args.get_one::<u16>("port").unwrap();
-    let callsign = args.get_one::<M17Address>("callsign").unwrap();
-    let module = args.get_one::<char>("module").unwrap();
-    let input = args.get_one::<String>("input");
-    let output = args.get_one::<String>("output");
+    // It is current convention that mrefd requires the destination of transmissions to match the reflector.
+    // If you are connected to "M17-XXX" on module B then you must set the dst to "M17-XXX B".
+    // This requirement is likely to change but for the purposes of this test client we'll hard-code the
+    // behaviour for the time being.
+    let ref_with_mod = format!("{} {}", args.reflector, args.module);
+    let Ok(reflector) = M17Address::from_callsign(&ref_with_mod) else {
+        println!(
+            "Unable to create valid destination address for reflector + callsign '{ref_with_mod}'"
+        );
+        std::process::exit(1);
+    };
 
-    let mut tx = Codec2TxAdapter::new(callsign.clone(), M17Address::new_broadcast());
-    if let Some(input) = input {
+    let mut tx = Codec2TxAdapter::new(args.callsign.clone(), reflector);
+    if let Some(input) = args.input {
         tx.set_input_card(input);
     }
     let ptt = tx.ptt();
 
     let mut rx = Codec2RxAdapter::new();
-    if let Some(output) = output {
+    if let Some(output) = args.output {
         rx.set_output_card(output);
     }
 
     let config = ReflectorClientConfig {
-        hostname: hostname.clone(),
-        port: *port,
-        module: *module,
-        local_callsign: callsign.clone(),
+        hostname: args.hostname,
+        port: args.port,
+        module: args.module,
+        local_callsign: args.callsign,
     };
     let tnc = ReflectorClientTnc::new(config, ConsoleStatusHandler);
     let app = M17App::new(tnc);