Read GPS data from a Neo6m gps module
Some checks failed
Continuous Integration / Rust Checks (map[args:--all -- --check --color always command:fmt]) (push) Has been cancelled
Continuous Integration / Rust Checks (map[args:--all-targets --all-features --workspace -- -D warnings command:clippy]) (push) Has been cancelled
Continuous Integration / Rust Checks (map[args:--release command:build]) (push) Has been cancelled

This commit is contained in:
Richard Patching 2025-05-20 18:53:34 +01:00
parent 4a32d32080
commit a22efdfca3
2 changed files with 124 additions and 72 deletions

View File

@ -19,13 +19,13 @@ opt-level = "z"
[features]
default = []
experimental = ["esp-idf-svc/experimental"]
[dependencies]
log = "0.4"
esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] }
esp-idf-hal = "0.45.2"
aniker-gps = { path = "../aniker-gps" }
log = "0.4"
[build-dependencies]
embuild = "0.33"
embuild = { version = "0.33", features = ["espidf"] }

View File

@ -1,92 +1,144 @@
use aniker_gps::{parse_gga, GpsError};
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::prelude::*;
use esp_idf_hal::uart::{UartConfig, UartDriver};
use esp_idf_svc::hal::delay::FreeRtos;
use esp_idf_svc::log::EspLogger;
use esp_idf_svc::sys::link_patches;
use log::info;
const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
const GPS_BAUD: u32 = 9600;
const INIT_DELAY_MS: u32 = 5000; // 5 second initialization delay
const POWER_CHECK_INTERVAL: u32 = 1000; // Check power every second
fn main() {
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize ESP-IDF
esp_idf_svc::sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();
link_patches();
EspLogger::initialize_default();
info!("Aniker GPS Test Application v{}", APP_VERSION);
info!("----------------------------------------");
info!("Aniker GPS Test Application Starting...");
info!("GPS Module Connections:");
info!("1. GPS TX → ESP32 GPIO16 D16(RX)");
info!("2. GPS RX → ESP32 GPIO17 D17(TX)");
info!("3. GPS VCC → 3.3V");
info!("4. GPS GND → GND");
info!("----------------------------------------");
info!("Please check if the red LED on the GPS module is lit");
info!("This indicates the module is receiving power");
info!("----------------------------------------");
// Example GPS sentences from different locations around the world:
// 1. Sydney Opera House, Australia
// 2. Mount Everest Base Camp, Nepal
// 3. Machu Picchu, Peru
// 4. Eiffel Tower, Paris, France
// 5. Table Mountain, Cape Town, South Africa
let test_sentences = vec![
// Sydney Opera House
"$GPGGA,023000,3357.3845,S,15112.7983,E,1,08,1.1,5.0,M,39.2,M,,*6D",
// Mount Everest Base Camp
"$GPGGA,023100,2759.1333,N,08656.9568,E,1,09,1.0,5364.0,M,-95.1,M,,*51",
// Machu Picchu
"$GPGGA,023200,1308.9511,S,07210.9327,W,1,07,1.2,2430.0,M,-15.3,M,,*62",
// Eiffel Tower
"$GPGGA,023300,4851.5156,N,00220.2978,E,1,10,0.9,33.0,M,47.0,M,,*68",
// Table Mountain
"$GPGGA,023400,3357.2828,S,01825.3214,E,1,08,1.0,1085.0,M,-33.0,M,,*6C",
];
// Initialize peripherals
let peripherals = Peripherals::take().unwrap();
// Process each test sentence
for (i, sentence) in test_sentences.iter().enumerate() {
let mut sentence = sentence.to_string();
// Configure UART
let config = UartConfig::default().baudrate(Hertz(GPS_BAUD));
info!("Processing location {}", i + 1);
info!("Raw NMEA: {}", sentence);
info!("Initializing UART with config: baudrate={}", GPS_BAUD);
match parse_gga(&mut sentence) {
Ok(position) => {
info!("Successfully parsed GPS data:");
info!(
" Latitude: {} {}",
position.lat.abs(),
if position.lat >= 0.0 { "N" } else { "S" }
);
info!(
" Longitude: {} {}",
position.long.abs(),
if position.long >= 0.0 { "E" } else { "W" }
);
info!(" Altitude: {:.1} meters", position.alt);
// Create UART driver
let mut uart_driver = UartDriver::new(
peripherals.uart2,
peripherals.pins.gpio17, // TX
peripherals.pins.gpio16, // RX
Option::<esp_idf_hal::gpio::Gpio0>::None, // RTS (not used)
Option::<esp_idf_hal::gpio::Gpio0>::None, // CTS (not used)
&config,
)?;
// Add a descriptive location name
let location = match i {
0 => "Sydney Opera House, Australia",
1 => "Mount Everest Base Camp, Nepal",
2 => "Machu Picchu, Peru",
3 => "Eiffel Tower, Paris, France",
4 => "Table Mountain, Cape Town, South Africa",
_ => "Unknown Location",
};
info!(" Location: {}", location);
info!("UART initialized at {} baud", GPS_BAUD);
info!(
"Waiting {}ms for GPS module to initialize...",
INIT_DELAY_MS
);
FreeRtos::delay_ms(INIT_DELAY_MS);
// Buffer for GPS data
let mut buffer = [0u8; 128];
let mut timeout_count = 0;
let mut last_data_time = 0;
let mut start_time = 0;
loop {
let current_time = last_data_time + 1;
// Read available data from UART with timeout
match uart_driver.read(&mut buffer, 1000) {
Ok(bytes_read) if bytes_read > 0 => {
timeout_count = 0; // Reset timeout counter on successful read
last_data_time = current_time;
let gps_data = String::from_utf8_lossy(&buffer[..bytes_read]);
info!("Raw GPS Data: {}", gps_data);
// Try to parse each line of GPS data
for line in gps_data.lines() {
if line.starts_with("$GPGGA") {
let mut sentence = line.to_string();
match parse_gga(&mut sentence) {
Ok(position) => {
info!("Successfully parsed GPS data:");
info!(
" Latitude: {} {}",
position.lat.abs(),
if position.lat >= 0.0 { "N" } else { "S" }
);
info!(
" Longitude: {} {}",
position.long.abs(),
if position.long >= 0.0 { "E" } else { "W" }
);
info!(" Altitude: {:.1} meters", position.alt);
}
Err(e) => {
info!("Error parsing GPS data:");
match e {
GpsError::InvalidMessageType => {
info!(" Invalid message type, expected GGA")
}
GpsError::InvalidLength => {
info!(" Invalid GGA sentence length")
}
GpsError::ParseError(msg) => info!(" Parse error: {}", msg),
GpsError::Other(msg) => info!(" Other error: {}", msg),
}
}
}
}
}
}
Ok(_) => {
timeout_count += 1;
if timeout_count % 10 == 0 {
// Only log every 10 timeouts to avoid spam
info!("No GPS data received (timeout #{})", timeout_count);
info!("Please check:");
info!("1. GPS module is powered (3.3V) - red LED should be lit");
info!("2. GPS TX is connected to ESP32 GPIO16 D16");
info!("3. GPS RX is connected to ESP32 GPIO17 D17");
info!("4. GPS GND is connected to ESP32 GND");
}
}
Err(e) => {
info!("Error parsing GPS data:");
match e {
GpsError::InvalidMessageType => {
info!(" Invalid message type, expected GGA")
}
GpsError::InvalidLength => info!(" Invalid GGA sentence length"),
GpsError::ParseError(msg) => info!(" Parse error: {}", msg),
GpsError::Other(msg) => info!(" Other error: {}", msg),
}
info!("UART read error: {:?}", e);
}
}
// Check if we've received any data in the last second
if current_time - last_data_time > POWER_CHECK_INTERVAL {
info!("GPS Module Status:");
info!("1. Power LED should be lit (red)");
info!(
"2. No data received for {} seconds",
(current_time - last_data_time) / 1000
);
info!(
"3. Total runtime: {} seconds",
(current_time - start_time) / 1000
);
}
info!("----------------------------------------");
// Add a small delay between processing sentences
FreeRtos::delay_ms(2000);
}
info!("Aniker GPS Test Application Complete");
// Keep the application running
loop {
FreeRtos::delay_ms(1000);
FreeRtos::delay_ms(3000); // Wait 3 seconds before next reading
}
}