From a22efdfca395c64b8c443b4361eec3848d278545 Mon Sep 17 00:00:00 2001 From: Richard Patching Date: Tue, 20 May 2025 18:53:34 +0100 Subject: [PATCH] Read GPS data from a Neo6m gps module --- Cargo.toml | 6 +- src/main.rs | 190 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 124 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a1f07e..a16cf95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/src/main.rs b/src/main.rs index 76a1f51..5413086 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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> { // 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::::None, // RTS (not used) + Option::::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 } }