Skip to content

Commit

Permalink
merge ublox.rs upstream updates into this crate
Browse files Browse the repository at this point in the history
Signed-off-by: Andrei Gherghescu <[email protected]>
  • Loading branch information
andrei-ng committed Dec 23, 2024
1 parent 0dae562 commit d6f4804
Show file tree
Hide file tree
Showing 13 changed files with 430 additions and 35 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
members = ["ublox", "ublox_derive"]
resolver = "2"
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"
3 changes: 2 additions & 1 deletion examples/basic-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[package]
authors = ["Lane Kolbly <[email protected]>", "Andrei Gherghescu <[email protected]>"]
authors = ["Lane Kolbly <[email protected]>", "Andrei Gherghescu <[email protected]>"]
edition = "2021"
name = "basic-cli"
publish = false
rust-version = "1.70"
version = "0.1.0"

[dependencies]
Expand Down
271 changes: 255 additions & 16 deletions examples/basic-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,68 +27,275 @@ 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 opened 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 opened 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 ...");
// Parse cli for configuring specific uBlox UART port
if let Some(("configure", sub_matches)) = matches.subcommand() {
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: UartPortId::Uart1,
portid: port_id,
reserved0: 0,
tx_ready: 0,
mode: UartMode::new(DataBits::Eight, Parity::None, StopBits::One),
mode: UartMode::new(
ublox_databits(data_bits),
ublox_parity(parity),
ublox_stopbits(stop_bits),
),
baud_rate: baud,
in_proto_mask: InProtoMask::UBLOX,
out_proto_mask: OutProtoMask::union(OutProtoMask::NMEA, OutProtoMask::UBLOX),
in_proto_mask: inproto,
out_proto_mask: outproto,
flags: 0,
reserved5: 0,
}
Expand All @@ -98,11 +305,16 @@ fn main() {
device
.wait_for_ack::<CfgPrtUart>()
.expect("Could not acknowledge UBX-CFG-PRT-UART msg");
}
}

// Enable the NavPvt packet
// By setting 1 in the array below, we enable the NavPvt message for Uart1, Uart2 and USB
// The other positions are for I2C, SPI, etc. Consult your device manual.
println!("Enable UBX-NAV-PVT message on all serial ports: USB, UART1 and UART2 ...");
device
.write_all(
&CfgMsgAllPortsBuilder::set_rate_for::<NavPvt>([0, 1, 0, 0, 0, 0]).into_packet_bytes(),
&CfgMsgAllPortsBuilder::set_rate_for::<NavPvt>([0, 1, 1, 1, 0, 0]).into_packet_bytes(),
)
.expect("Could not configure ports for UBX-NAV-PVT");
device
Expand Down Expand Up @@ -164,6 +376,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
4 changes: 2 additions & 2 deletions ublox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "ublox"
publish = false
readme = "../README.md"
repository = "https://github.com/lkolbly/ublox"
version = "0.4.2"
version = "0.4.5"

[features]
alloc = []
Expand All @@ -19,7 +19,7 @@ bitflags = "2.3.1"
chrono = {version = "0.4.19", default-features = false, features = []}
num-traits = {version = "0.2.12", default-features = false}
serde = {version = "1.0.144", optional = true, default-features = false, features = ["derive"]}
ublox_derive = {path = "../ublox_derive", version = "0.0.4"}
ublox_derive = {path = "../ublox_derive", version = "=0.1.0"}

[dev-dependencies]
cpu-time = "1.0.0"
Expand Down
3 changes: 2 additions & 1 deletion ublox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//!
//! This project aims to build a pure-rust I/O library for ublox GPS devices, specifically using the UBX protocol.
//!
//! An example of using this library to talk to a device can be seen in the examples subfolder of this project.
//! An example of using this library to talk to a device can be seen in the examples/basic-cli subfolder of this project.
//! More examples are available in the examples subfolder.
//!
//! Constructing Packets
//! ====================
Expand Down
Loading

0 comments on commit d6f4804

Please sign in to comment.