]>
code.octet-stream.net Git - m17rt/blob - tools/m17rt-netclient/src/main.rs
1 use std
::{io
::stdin
, sync
::Arc
};
3 use clap
::{Arg
, value_parser
};
5 adapter
::StreamAdapter
,
7 link_setup
::M17Address
,
8 reflector
::{ReflectorClientConfig
, ReflectorClientTnc
, StatusHandler
},
10 use m17codec2
::{rx
::Codec2RxAdapter
, tx
::Codec2TxAdapter
};
13 let args
= clap
::Command
::new("m17rt-netclient")
19 .help("Domain or IP of reflector"),
25 .value_parser(value_parser
!(u16))
26 .default_value("17000")
27 .help("Reflector listening port"),
33 .value_parser(valid_callsign
)
35 .help("Your callsign for reflector registration and transmissions"),
41 .value_parser(valid_callsign
)
43 .help("Reflector designator/callsign, often starting with 'M17-'"),
49 .value_parser(valid_module
)
51 .help("Module to connect to (A-Z)"),
57 .help("Soundcard name for microphone, otherwise system default"),
63 .help("Soundcard name for speaker, otherwise system default"),
67 let hostname
= args
.get_one
::<String
>("hostname").unwrap
();
68 let port
= args
.get_one
::<u16>("port").unwrap
();
69 let callsign
= args
.get_one
::<M17Address
>("callsign").unwrap
();
70 let reflector
= args
.get_one
::<M17Address
>("reflector").unwrap
();
71 let module
= args
.get_one
::<char>("module").unwrap
();
72 let input
= args
.get_one
::<String
>("input");
73 let output
= args
.get_one
::<String
>("output");
75 let ref_with_mod
= format
!("{} {}", reflector
, module
);
76 let Ok(reflector
) = M17Address
::from_callsign(&ref_with_mod
) else {
78 "Unable to create valid destination address for reflector + callsign '{ref_with_mod}'"
80 std
::process
::exit(1);
83 let mut tx
= Codec2TxAdapter
::new(callsign
.clone(), reflector
);
84 if let Some(input
) = input
{
85 tx
.set_input_card(input
);
89 let mut rx
= Codec2RxAdapter
::new();
90 if let Some(output
) = output
{
91 rx
.set_output_card(output
);
94 let config
= ReflectorClientConfig
{
95 hostname
: hostname
.clone(),
98 local_callsign
: callsign
.clone(),
100 let tnc
= ReflectorClientTnc
::new(config
, ConsoleStatusHandler
);
101 let app
= M17App
::new(tnc
);
102 app
.add_stream_adapter(ConsoleAdapter
).unwrap
();
103 app
.add_stream_adapter(tx
).unwrap
();
104 app
.add_stream_adapter(rx
).unwrap
();
105 app
.start().unwrap
();
107 println
!(">>> PRESS ENTER TO TOGGLE PTT <<<");
108 let mut buf
= String
::new();
111 let _
= stdin().read_line(&mut buf
);
113 println
!("PTT ON: PRESS ENTER TO END");
115 let _
= stdin().read_line(&mut buf
);
121 fn valid_module(m
: &str) -> Result
<char, String
> {
122 let m
= m
.to_ascii_uppercase();
123 if m
.len() != 1 || !m
.chars().next().unwrap
().is
_alphabet
ic
() {
124 return Err("Module must be a single letter from A to Z".to_owned());
126 Ok(m
.chars().next().unwrap
())
129 fn valid_callsign(c
: &str) -> Result
<M17Address
, String
> {
130 M17Address
::from_callsign(c
).map_err(|e
| e
.to_string())
133 struct ConsoleAdapter
;
134 impl StreamAdapter
for ConsoleAdapter
{
135 fn stream_began(&self, link_setup
: m17app
::link_setup
::LinkSetup
) {
137 "Incoming transmission begins. From: {} To: {}",
139 link_setup
.destination()
143 fn stream_data(&self, _frame_number
: u16, is_final
: bool
, _data
: Arc
<[u8; 16]>) {
145 println
!("Incoming transmission ends.");
150 struct ConsoleStatusHandler
;
151 impl StatusHandler
for ConsoleStatusHandler
{
152 fn status_changed(&mut self, status
: m17app
::reflector
::TncStatus
) {
153 println
!("Client status: {status:?}")