Skip to content

Commit

Permalink
expand basic_cli example with more cli-args
Browse files Browse the repository at this point in the history
Signed-off-by: Andrei Gherghescu <[email protected]>
  • Loading branch information
andrei-ng committed Nov 10, 2023
1 parent 9568b41 commit 48adddf
Show file tree
Hide file tree
Showing 2 changed files with 282 additions and 29 deletions.
1 change: 1 addition & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[workspace]
exclude = ["target"]
members = ["*"]
resolver = "2"
310 changes: 281 additions & 29 deletions examples/basic_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,79 +27,304 @@ fn main() {
.short('s')
.long("baud")
.required(false)
.default_value("9600")
.value_parser(value_parser!(u32))
.help("Baud rate of the port"),
.help("Baud rate of the port to open"),
)
.arg(
Arg::new("stop-bits")
.long("stop-bits")
.help("Number of stop bits to use")
.help("Number of stop bits to use for open port")
.required(false)
.value_parser(["1", "2"])
.default_value("1"),
)
.arg(
Arg::new("data-bits")
.long("data-bits")
.help("Number of data bits to use")
.help("Number of data bits to use for open port")
.required(false)
.value_parser(["5", "6", "7", "8"])
.value_parser(["7", "8"])
.default_value("8"),
)
.arg(
Arg::new("parity")
.long("parity")
.help("Parity to use for open port")
.required(false)
.value_parser(["even", "odd"]),
)
.subcommand(
Command::new("configure")
.about("Configure settings for specific UART/USB port")
.arg(
Arg::new("port")
.long("select")
.required(true)
.default_value("usb")
.value_parser(value_parser!(String))
.long_help(
"Apply specific configuration to the selected port. Supported: usb, uart1, uart2.
Configuration includes: protocol in/out, data-bits, stop-bits, parity, baud-rate",
),
)
.arg(
Arg::new("cfg-baud")
.value_name("baud")
.long("baud")
.required(false)
.default_value("9600")
.value_parser(value_parser!(u32))
.help("Baud rate to set"),
)
.arg(
Arg::new("stop-bits")
.long("stop-bits")
.help("Number of stop bits to set")
.required(false)
.value_parser(["1", "2"])
.default_value("1"),
)
.arg(
Arg::new("data-bits")
.long("data-bits")
.help("Number of data bits to set")
.required(false)
.value_parser(["7", "8"])
.default_value("8"),
)
.arg(
Arg::new("parity")
.long("parity")
.help("Parity to set")
.required(false)
.value_parser(["even", "odd"]),
)
.arg(
Arg::new("in-ublox")
.long("in-ublox")
.default_value("true")
.action(clap::ArgAction::SetTrue)
.help("Toggle receiving UBX proprietary protocol on port"),
)
.arg(
Arg::new("in-nmea")
.long("in-nmea")
.default_value("false")
.action(clap::ArgAction::SetTrue)
.help("Toggle receiving NMEA protocol on port"),
)
.arg(
Arg::new("in-rtcm")
.long("in-rtcm")
.default_value("false")
.action(clap::ArgAction::SetTrue)
.help("Toggle receiving RTCM protocol on port"),
)
.arg(
Arg::new("in-rtcm3")
.long("in-rtcm3")
.default_value("false")
.action(clap::ArgAction::SetTrue)
.help(
"Toggle receiving RTCM3 protocol on port.
Not supported on uBlox protocol versions below 20",
),
)
.arg(
Arg::new("out-ublox")
.long("out-ublox")
.action(clap::ArgAction::SetTrue)
.help("Toggle sending UBX proprietary protocol on port"),
)
.arg(
Arg::new("out-nmea")
.long("out-nmea")
.action(clap::ArgAction::SetTrue)
.help("Toggle sending NMEA protocol on port"),
)
.arg(
Arg::new("out-rtcm3")
.long("out-rtcm3")
.action(clap::ArgAction::SetTrue)
.help(
"Toggle seding RTCM3 protocol on port.
Not supported on uBlox protocol versions below 20",
),
),
)
.get_matches();

let port = matches
.get_one::<String>("port")
.expect("Expected required 'port' cli argumnet");

let baud = matches.get_one::<u32>("baud").cloned().unwrap_or(9600);
let stop_bits = match matches.get_one::<String>("stop-bits").map(|s| s.as_str()) {
Some("2") => SerialStopBits::Two,
_ => SerialStopBits::One,
};

let data_bits = match matches.get_one::<String>("data-bits").map(|s| s.as_str()) {
Some("5") => SerialDataBits::Five,
Some("6") => SerialDataBits::Six,
Some("7") => SerialDataBits::Seven,
_ => SerialDataBits::Eight,
Some("8") => SerialDataBits::Eight,
_ => {
println!("Number of DataBits supported by uBlox is either 7 or 8");
std::process::exit(1);
},
};

let parity = match matches.get_one::<String>("parity").map(|s| s.as_str()) {
Some("odd") => SerialParity::Even,
Some("even") => SerialParity::Odd,
_ => SerialParity::None,
};

let builder = serialport::new(port, baud)
.stop_bits(stop_bits)
.data_bits(data_bits)
.timeout(Duration::from_millis(1))
.parity(SerialParity::None)
.timeout(Duration::from_millis(10))
.parity(parity)
.flow_control(SerialFlowControl::None);

println!("{:?}", &builder);
let port = builder.open().unwrap_or_else(|e| {
eprintln!("Failed to open \"{}\". Error: {}", port, e);
::std::process::exit(1);
});

let mut device = Device::new(port);

// Configure the device to talk UBX
println!("Configuring UART1 port ...");
device
.write_all(
&CfgPrtUartBuilder {
portid: UartPortId::Uart1,
reserved0: 0,
tx_ready: 0,
mode: UartMode::new(DataBits::Eight, Parity::None, StopBits::One),
baud_rate: baud,
in_proto_mask: InProtoMask::UBLOX,
out_proto_mask: OutProtoMask::union(OutProtoMask::NMEA, OutProtoMask::UBLOX),
flags: 0,
reserved5: 0,
// Parse cli for configuring specific uBlox UART port
match matches.subcommand() {
Some(("cfg-port", sub_matches)) => {
let (port_id, port_name) =
match sub_matches.get_one::<String>("port").map(|s| s.as_str()) {
Some(x) if x == "usb" => (Some(UartPortId::Usb), x),
Some(x) if x == "uart1" => (Some(UartPortId::Uart1), x),
Some(x) if x == "uart2" => (Some(UartPortId::Uart2), x),
_ => (None, ""),
};

let baud = sub_matches.get_one::<u32>("baud").cloned().unwrap_or(9600);

let stop_bits = match sub_matches
.get_one::<String>("stop-bits")
.map(|s| s.as_str())
{
Some("2") => SerialStopBits::Two,
_ => SerialStopBits::One,
};

let data_bits = match sub_matches
.get_one::<String>("data-bits")
.map(|s| s.as_str())
{
Some("7") => SerialDataBits::Seven,
Some("8") => SerialDataBits::Eight,
_ => {
println!("Number of DataBits supported by uBlox is either 7 or 8");
std::process::exit(1);
},
};

let parity = match sub_matches.get_one::<String>("parity").map(|s| s.as_str()) {
Some("odd") => SerialParity::Even,
Some("even") => SerialParity::Odd,
_ => SerialParity::None,
};
let inproto = match (
sub_matches.get_flag("in-ublox"),
sub_matches.get_flag("in-nmea"),
sub_matches.get_flag("in-rtcm"),
sub_matches.get_flag("in-rtcm3"),
) {
(true, false, false, false) => InProtoMask::UBLOX,
(false, true, false, false) => InProtoMask::NMEA,
(false, false, true, false) => InProtoMask::RTCM,
(false, false, false, true) => InProtoMask::RTCM3,
(true, true, false, false) => {
InProtoMask::union(InProtoMask::UBLOX, InProtoMask::NMEA)
},
(true, false, true, false) => {
InProtoMask::union(InProtoMask::UBLOX, InProtoMask::RTCM)
},
(true, false, false, true) => {
InProtoMask::union(InProtoMask::UBLOX, InProtoMask::RTCM3)
},
(false, true, true, false) => {
InProtoMask::union(InProtoMask::NMEA, InProtoMask::RTCM)
},
(false, true, false, true) => {
InProtoMask::union(InProtoMask::NMEA, InProtoMask::RTCM3)
},
(true, true, true, false) => InProtoMask::union(
InProtoMask::union(InProtoMask::UBLOX, InProtoMask::NMEA),
InProtoMask::RTCM,
),
(true, true, false, true) => InProtoMask::union(
InProtoMask::union(InProtoMask::UBLOX, InProtoMask::NMEA),
InProtoMask::RTCM3,
),
(_, _, true, true) => {
eprintln!("Cannot use RTCM and RTCM3 simultaneously. Choose one or the other");
std::process::exit(1)
},
(false, false, false, false) => InProtoMask::UBLOX,
};

let outproto = match (
sub_matches.get_flag("out-ublox"),
sub_matches.get_flag("out-nmea"),
sub_matches.get_flag("out-rtcm3"),
) {
(true, false, false) => OutProtoMask::UBLOX,
(false, true, false) => OutProtoMask::NMEA,
(false, false, true) => OutProtoMask::RTCM3,
(true, true, false) => OutProtoMask::union(OutProtoMask::UBLOX, OutProtoMask::NMEA),
(true, false, true) => {
OutProtoMask::union(OutProtoMask::UBLOX, OutProtoMask::RTCM3)
},
(false, true, true) => OutProtoMask::union(OutProtoMask::NMEA, OutProtoMask::RTCM3),
(true, true, true) => OutProtoMask::union(
OutProtoMask::union(OutProtoMask::UBLOX, OutProtoMask::NMEA),
OutProtoMask::RTCM3,
),
(false, false, false) => OutProtoMask::UBLOX,
};

if let Some(port_id) = port_id {
println!("Configuring '{}' port ...", port_name.to_uppercase());
device
.write_all(
&CfgPrtUartBuilder {
portid: port_id,
reserved0: 0,
tx_ready: 0,
mode: UartMode::new(
ublox_databits(data_bits),
ublox_parity(parity),
ublox_stopbits(stop_bits),
),
baud_rate: baud,
in_proto_mask: inproto,
out_proto_mask: outproto,
flags: 0,
reserved5: 0,
}
.into_packet_bytes(),
)
.expect("Could not configure UBX-CFG-PRT-UART");
device
.wait_for_ack::<CfgPrtUart>()
.expect("Could not acknowledge UBX-CFG-PRT-UART msg");
}
.into_packet_bytes(),
)
.expect("Could not configure UBX-CFG-PRT-UART");
device
.wait_for_ack::<CfgPrtUart>()
.expect("Could not acknowledge UBX-CFG-PRT-UART msg");
},
_ => {},
}

// Enable the NavPvt packet
println!("Enable UBX-NAV-PVT message on selected ports ...");
device
.write_all(
&CfgMsgAllPortsBuilder::set_rate_for::<NavPvt>([0, 1, 0, 0, 0, 0]).into_packet_bytes(),
Expand Down Expand Up @@ -164,6 +389,33 @@ fn main() {
}
}

fn ublox_stopbits(s: SerialStopBits) -> StopBits {
// Seriaport crate doesn't support the other StopBits option of uBlox
match s {
SerialStopBits::One => StopBits::One,
SerialStopBits::Two => StopBits::Two,
}
}

fn ublox_databits(d: SerialDataBits) -> DataBits {
match d {
SerialDataBits::Seven => DataBits::Seven,
SerialDataBits::Eight => DataBits::Eight,
_ => {
println!("uBlox only supports Seven or Eight data bits");
DataBits::Eight
},
}
}

fn ublox_parity(v: SerialParity) -> Parity {
match v {
SerialParity::Even => Parity::Even,
SerialParity::Odd => Parity::Odd,
SerialParity::None => Parity::None,
}
}

struct Device {
port: Box<dyn serialport::SerialPort>,
parser: Parser<Vec<u8>>,
Expand Down

0 comments on commit 48adddf

Please sign in to comment.