From 48adddf841fbfe238833619a6f1efdbf9cb1b447 Mon Sep 17 00:00:00 2001 From: Andrei Gherghescu <8067229+andrei-ng@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:03:34 +0100 Subject: [PATCH] expand basic_cli example with more cli-args Signed-off-by: Andrei Gherghescu <8067229+andrei-ng@users.noreply.github.com> --- examples/Cargo.toml | 1 + examples/basic_cli/src/main.rs | 310 ++++++++++++++++++++++++++++++--- 2 files changed, 282 insertions(+), 29 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 748801c..9843613 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,3 +1,4 @@ [workspace] exclude = ["target"] members = ["*"] +resolver = "2" diff --git a/examples/basic_cli/src/main.rs b/examples/basic_cli/src/main.rs index 318880b..2f47c0f 100644 --- a/examples/basic_cli/src/main.rs +++ b/examples/basic_cli/src/main.rs @@ -27,13 +27,14 @@ 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"), @@ -41,33 +42,149 @@ fn main() { .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::("port") .expect("Expected required 'port' cli argumnet"); + let baud = matches.get_one::("baud").cloned().unwrap_or(9600); let stop_bits = match matches.get_one::("stop-bits").map(|s| s.as_str()) { Some("2") => SerialStopBits::Two, _ => SerialStopBits::One, }; + let data_bits = match matches.get_one::("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::("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); @@ -75,31 +192,139 @@ fn main() { 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::("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::("baud").cloned().unwrap_or(9600); + + let stop_bits = match sub_matches + .get_one::("stop-bits") + .map(|s| s.as_str()) + { + Some("2") => SerialStopBits::Two, + _ => SerialStopBits::One, + }; + + let data_bits = match sub_matches + .get_one::("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::("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::() + .expect("Could not acknowledge UBX-CFG-PRT-UART msg"); } - .into_packet_bytes(), - ) - .expect("Could not configure UBX-CFG-PRT-UART"); - device - .wait_for_ack::() - .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::([0, 1, 0, 0, 0, 0]).into_packet_bytes(), @@ -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, parser: Parser>,