From 8c7181add2b9519307538d4f32e2d75c26525902 Mon Sep 17 00:00:00 2001 From: Luke Else Date: Tue, 25 Jul 2023 21:15:59 +0100 Subject: [PATCH] Removed some unecessary code, cleaned up the main UI to show only speed, and finally made a start on implementing some sort of app state for different screens / menus --- src/appstate.rs | 25 +++++++++++++++++++++++ src/gps/gpsdata.rs | 50 ++++++++++++++++++++++++++++++++++++++-------- src/main.rs | 34 ++++++++++++++++--------------- 3 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 src/appstate.rs diff --git a/src/appstate.rs b/src/appstate.rs new file mode 100644 index 0000000..a2fae51 --- /dev/null +++ b/src/appstate.rs @@ -0,0 +1,25 @@ +/// Enum to store the state e.g. what should currently being displayed on the screen +pub enum AppState { + All, + Position, + Speed, + Altitude, +} + +impl Default for AppState { + /// Function to get the default state of the application + fn default() -> Self { + AppState::All + } +} + +impl AppState { + pub fn next(&mut self) { + match self { + AppState::All => *self = AppState::Position, + AppState::Position => *self = AppState::Speed, + AppState::Speed => *self = AppState::Altitude, + AppState::Altitude => *self = AppState::All, + } + } +} diff --git a/src/gps/gpsdata.rs b/src/gps/gpsdata.rs index 515a726..f7aeaba 100644 --- a/src/gps/gpsdata.rs +++ b/src/gps/gpsdata.rs @@ -1,6 +1,7 @@ use super::GpsError; use nmea_parser; +use nmea_parser::chrono::{DateTime, Utc}; use nmea_parser::gnss::FaaMode; /// Data structure to store all relevant data collected from the gps @@ -14,6 +15,8 @@ pub struct GpsData { speed: Option, /// Altitude reported from GPS location altitude: Option, + /// Timestamp of the last report + timestamp: Option> } impl ToString for GpsData { @@ -22,13 +25,16 @@ impl ToString for GpsData { self.latitude.unwrap_or_default(), self.longitude.unwrap_or_default(), self.speed.unwrap_or_default(), - self.altitude.unwrap_or_default() + self.altitude.unwrap_or_default(), ) } } impl GpsData { /// Function to go through and update GPS data from a nmea stream + /// + /// Takes in a reference to a buffer of raw serial data and then + /// tries to read it in as NMEA Data pub fn update(&mut self, buf: &Vec) -> Result<(), GpsError> { let mut nmea_parser = nmea_parser::NmeaParser::new(); @@ -56,19 +62,39 @@ impl GpsData { // print decoded gps data to serial match nmea { + // TODO: Investigate why the GGA Packets seem to come in mangled nmea_parser::ParsedMessage::Gga(gga) => { - self.altitude = gga.altitude; + // Update Altitude above ground level + self.altitude = match gga.altitude { + Some(_) => gga.altitude, + None => self.altitude + }; } nmea_parser::ParsedMessage::Gll(gll) => { + // FAA mode is used to determine the validity of the data in this case if gll.faa_mode.unwrap_or(FaaMode::NotValid) == FaaMode::Autonomous { - self.latitude = gll.latitude; - self.longitude = gll.longitude; + // Only make updates to position if we have new data, do not overwrite + // stale data + match gll.latitude { + Some(_) => self.latitude = gll.latitude, + None => {} + } + match gll.longitude { + Some(_) => self.longitude = gll.longitude, + None => {} + } + match gll.timestamp { + Some(_) => self.timestamp = gll.timestamp, + None => {} + } } }, nmea_parser::ParsedMessage::Rmc(rms) => { - self.latitude = rms.latitude; - self.longitude = rms.longitude; - self.speed = Some(knots_to_mph(rms.sog_knots.unwrap_or_default())); + // Update Ground Speed + match rms.sog_knots { + Some(_) => self.speed = Some(knots_to_mph(rms.sog_knots.unwrap_or_default())), + None => {} + } }, _ => {} } @@ -76,9 +102,17 @@ impl GpsData { Ok(()) } + + /// Function to get a &str of the current speed reported by the GPS module + pub fn get_speed(&self) -> String { + match self.speed { + Some(speed) => format!("{:.2?}mph\n", speed), + None => format!("AWAITING\nGPS\nDATA") + } + } } /// Function to simply convert knots to mph fn knots_to_mph(knots: f64) -> f64{ knots * 1.150779 -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 42e67ff..dccae62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ -use esp_idf_sys::{self as _}; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported +use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported use esp_idf_hal::{ + self, + interrupt, prelude::Peripherals, gpio::{AnyInputPin, AnyOutputPin}, delay::BLOCK, @@ -7,18 +9,18 @@ use esp_idf_hal::{ uart, i2c::{I2cConfig, I2cDriver} }; -use esp_idf_hal; use embedded_graphics::{ prelude::*, - image::{Image, ImageRaw}, - mono_font::{ascii::FONT_7X13, MonoTextStyle}, + mono_font::{ascii::FONT_7X13, ascii::FONT_10X20, MonoTextStyle}, pixelcolor::BinaryColor, text::{Text, Alignment}, }; use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; +mod appstate; + mod error; use error::Error; @@ -28,12 +30,14 @@ use gps::gpsdata; mod display; use display::DisplayError; + + fn main() -> Result<(), Error> { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 esp_idf_sys::link_patches(); // Bind the log crate to the ESP Logging facilities - esp_idf_svc::log::EspLogger::initialize_default(); + //esp_idf_svc::log::EspLogger::initialize_default(); // Get Peripherals and sysloop ready let peripherals = Peripherals::take().unwrap(); @@ -55,7 +59,7 @@ fn main() -> Result<(), Error> { None::, &config ).map_err(|err| Error::EspError(err))?; - + // Setup I2C driver let config = I2cConfig::new().baudrate(Hertz(921600)); let i2c = I2cDriver::new( @@ -70,13 +74,9 @@ fn main() -> Result<(), Error> { .into_buffered_graphics_mode(); display.init().map_err(|err| Error::DisplayError(DisplayError::SetupError(err)))?; - let raw: ImageRaw = ImageRaw::new(include_bytes!("./rust.raw"), 64); - let im: Image<'_, _> = Image::new(&raw, Point::new(32, 0)); - - im.draw(&mut display).map_err(|err| Error::DisplayError(DisplayError::SetupError(err)))?; - + let mut app_state = appstate::AppState::default(); let mut latest_data = gpsdata::GpsData::default(); - + loop { // Read buffer from UART let mut buf: Vec = ( @@ -89,14 +89,15 @@ fn main() -> Result<(), Error> { .map_err(|err| Error::GpsError(err))?; // Clear display ready for next write - let style = MonoTextStyle::new(&FONT_7X13, BinaryColor::On); + let style = MonoTextStyle::new(&FONT_10X20, BinaryColor::On); display.clear(BinaryColor::Off) .map_err(|_| Error::DisplayError(DisplayError::DrawingError))?; // Draw text to Display Text::with_alignment( - &latest_data.to_string().as_str(), - Point::new(64, 10), + &latest_data.get_speed().as_str(), + //&latest_data.to_string().as_str(), + Point::new(64, 20), style, Alignment::Center, ) @@ -107,4 +108,5 @@ fn main() -> Result<(), Error> { display.flush() .map_err(|_| Error::DisplayError(DisplayError::FlushError))?; } -} \ No newline at end of file +} +