Compare commits

..

5 Commits

Author SHA1 Message Date
mattbk 06324c3183 Working snapshot. 2026-09-11 18:23:19 -05:00
mattbk 408b94d962 Make it work, add format argument. 2026-09-07 18:38:08 -05:00
mattbk 80ba685a95 Wait for one location and then exit. 2026-09-07 18:04:48 -05:00
mattbk 86c5720fb4 Update readme. 2026-09-07 15:16:44 -05:00
mattbk 011fc62b9b Update readme. 2026-09-07 15:11:55 -05:00
2 changed files with 141 additions and 98 deletions
+26 -24
View File
@@ -1,39 +1,41 @@
# Rust GPS GUI COM Port Reader
# gpsll
Using Rust and the following packages
```Rust
[dependencies]
eframe = { version = "0.27", features = ["wgpu", "persistence"] }
egui = "0.27"
egui_plot = "0.27"
serialport = "4.2"
nmea = "0.6"
nmea = {version = "0.6", features = ["GGA"]}
clap = { version = "4", features = ["derive"] }
chrono = "0.4.45"
```
I was able to open the U-Blox port on my GPS dongle and parse the longitude and latitude, printing the information in the streaming output for the user to see.
Also showing the Satellites its fixed to, and the satellites its attached to in the circle.
I wanted a simple way to export latitude and longitude from a GPS USB dongle to the terminal.
## Sample GUI Output
## Usage
```
A tool for echoing latitude and longitude from a GPS USB dongle.
![GUI_Output](GUI_output.png)
Usage: gpsll [OPTIONS]
## Acknowledgements
Options:
-c, --com <COM> COM port
-h, --help Print help
-V, --version Print version
```
- Professors at Kean University
- Professors at NJIT
- Research Mentors at Kean University
- StackOverflow Q&A Discussion
- ChatGPT
- ClaudeAI
```
Matt@computer % gpsll -c "/dev/tty.usbmodem1301"
Reading from "/dev/tty.usbmodem1301"
2026-09-07 15:14:43, 47.11, -97.22
2026-09-07 15:14:44, 47.11, -97.22
2026-09-07 15:14:46, 47.11, -97.22
2026-09-07 15:14:48, 47.11, -97.22
2026-09-07 15:14:49, 47.11, -97.22
2026-09-07 15:14:50, 47.11, -97.22
```
## Acknowledgments
## Authors
- [@FPyC639](https://github.com/FPyC639)
## Appendix
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/joseserra8x)
- Inspiration from https://github.com/FPyC639/Rust_GPS_GUI_COM_Port_Reader.
+101 -60
View File
@@ -1,22 +1,105 @@
use chrono::Local;
use clap::Parser;
use nmea::Nmea;
use nmea::SentenceType;
use std::thread;
use std::time::Duration;
use clap::Parser;
use chrono::Local;
/// Command-line arguments using Clap.
#[derive(Parser, Debug)]
#[command(author, version, about = "A tool for echoing latitude and longitude from a GPS USB dongle.")]
#[command(
author,
version,
about = "A tool for echoing latitude and longitude from a GPS USB dongle."
)]
struct Cli {
/// COM port
#[arg(short = 'c', long)]
com: Option<String>,
/// Format
#[arg(short = 'f', long, default_value = "csv")]
format: Option<String>,
}
// Function to get the location
fn get_loc(port: String, fmt: String) -> String {
let mut nmea = Nmea::default();
// Harcode port for dev
//let port_name = "/dev/tty.usbmodem1301";
let port_name = port;
//fn read_loc(com: &str) -> &str {
//println!("Reading from {port_name}");
let port = serialport::new(port_name, 9600)
.timeout(Duration::from_millis(1000))
.open();
if let Ok(mut serial) = port {
let mut buf = [0u8; 1024];
loop {
match serial.read(&mut buf) {
Ok(n) => {
let data = String::from_utf8_lossy(&buf[..n]);
for line in data.lines() {
// Check sentence type
let sentence_type = match nmea.parse(line) {
Ok(sentence_type) => sentence_type,
Err(_) => {
break;
}
};
// Only keep the GLL sentences
if sentence_type == SentenceType::GLL {
let lat = match nmea.latitude {
Some(lat) => lat,
None => -9999.25,
};
let lon = match nmea.longitude {
Some(lon) => lon,
None => -9999.25,
};
let date = Local::now();
//println!("{}, {lat}, {lon}", date.format("%Y-%m-%d %H:%M:%S"));
if fmt == "csv" {
return format!(
"{},{:.8},{:.8}",
date.format("%Y-%m-%d %H:%M:%S"),
lat,
lon
);
} else if fmt == "ssv" {
return format!(
"\"{}\" {:.8} {:.8}",
date.format("%Y-%m-%d %H:%M:%S"),
lat,
lon
);
}
}
}
}
Err(_) => {} // lol that I can just not put a return in?
}
}
} else {
// https://github.com/serialport/serialport-rs#listing-available-ports
let ports = serialport::available_ports().expect("No ports found!");
println!("Available Ports:");
for p in ports {
println!("{}", p.port_name);
}
return format!("\nCould not connect to port. Is it listed above?");
}
}
fn main() {
// Arguments
let cli = Cli::parse();
let com = match cli.com {
@@ -31,62 +114,20 @@ fn main() {
println!("\nMissing `-c` port argument, use one listed above.");
return;
} //todo!()
} ;
println!("Reading from {com:?}");
// Inifnite loop until I add controls
while 1 == 1 {
let mut nmea = Nmea::default();
// Harcode port for dev
//let port_name = "/dev/tty.usbmodem1301";
let port_name = com.clone();
// Thread for GPS streaming
thread::spawn(move || {
let port = serialport::new(port_name, 9600)
.timeout(Duration::from_millis(1000))
.open();
if let Ok(mut serial) = port {
let mut buf = [0u8; 1024];
loop {
match serial.read(&mut buf) {
Ok(n) => {
let data = String::from_utf8_lossy(&buf[..n]);
for line in data.lines() {
// Check sentence type
let sentence_type = match nmea.parse(line) {
Ok(sentence_type) => sentence_type,
Err(_) => {
return;
}
};
// Only keep the GLL sentences
if sentence_type == SentenceType::GLL {
let lat = match nmea.latitude {
Some(lat) => lat,
None => todo!()
} ;
let lon = match nmea.longitude {
Some(lon) => lon,
None => todo!()
} ;
let date = Local::now();
println!("{}, {lat}, {lon}", date.format("%Y-%m-%d %H:%M:%S"));
let fmt = match cli.format {
Some(fmt) => fmt,
None => {
return;
} //todo!()
};
}
}
}
Err(_) => break,
}
// Run the function
// Max rate is about 1 measurement per second
//loop {
let result = get_loc(com.clone(), fmt.clone());
println!("{result}");
//}
}
}
});
}
}