Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract parts of gui into smaller components #7

Merged
18 changes: 6 additions & 12 deletions src/data_source.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Data sources serve as an abstraction for the origin of the displayed data.

use std::any::Any;
use std::slice::Iter;
use std::sync::mpsc::SendError;

Expand All @@ -12,7 +13,6 @@ use mithril::settings::*;
use mithril::telemetry::*;

use crate::settings::AppSettings;
use crate::simulation::SimulationSettings;
use crate::state::*;

pub mod log_file;
Expand Down Expand Up @@ -43,9 +43,6 @@ pub trait DataSource {
/// Send an authenticated uplink command
fn send_command(&mut self, cmd: Command) -> Result<(), SendError<UplinkMessage>>;

/// The minimum fps required for the data source. Occasional redraws
/// are necessary if data source is live.
fn minimum_fps(&self) -> Option<u64>;
fn end(&self) -> Option<Instant>;

fn status_bar_ui(&mut self, _ui: &mut egui::Ui) {
Expand All @@ -55,13 +52,10 @@ pub trait DataSource {
None
}

fn is_log_file(&self) -> bool {
false
}

fn simulation_settings(&mut self) -> Option<&mut SimulationSettings> {
None
}

fn apply_settings(&mut self, _settings: &AppSettings) {}

/// Helper methods to allow us to downcast from a boxed DataSource trait to a specific
/// implementation type.
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
27 changes: 14 additions & 13 deletions src/data_source/log_file.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! A data source based on a logfile, either passed as a file path, or with
//! some raw bytes.

use std::any::Any;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Read;
Expand Down Expand Up @@ -75,7 +76,7 @@ impl LogFileDataSource {
}

impl DataSource for LogFileDataSource {
fn update(&mut self, _ctx: &egui::Context) {
fn update(&mut self, ctx: &egui::Context) {
if let Some(file) = self.file.as_mut() {
if let Err(e) = file.read_to_end(&mut self.buffer) {
error!("Failed to read log file: {:?}", e);
Expand Down Expand Up @@ -129,6 +130,10 @@ impl DataSource for LogFileDataSource {
for (t, msg) in self.messages.drain(..pointer) {
self.vehicle_states.push((t, msg.into()));
}

if self.replay {
ctx.request_repaint_after(Duration::from_millis(16));
}
}

fn vehicle_states<'a>(&'a self) -> Iter<'_, (Instant, VehicleState)> {
Expand Down Expand Up @@ -156,18 +161,6 @@ impl DataSource for LogFileDataSource {
Ok(())
}

fn minimum_fps(&self) -> Option<u64> {
if self.replay && self.last_time.map(|t| t > Instant::now()).unwrap_or(true) {
Some(60)
} else {
None
}
}

fn is_log_file(&self) -> bool {
true
}

fn end(&self) -> Option<Instant> {
if self.replay {
let last = self.last_time.unwrap_or(Instant::now());
Expand All @@ -186,4 +179,12 @@ impl DataSource for LogFileDataSource {
.unwrap_or_default();
ui.weak(name);
}

fn as_any(&self) -> &dyn Any {
self
}

fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
44 changes: 32 additions & 12 deletions src/data_source/serial.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! A serial port data source. The default.

use std::any::Any;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Read, Write};
Expand Down Expand Up @@ -53,6 +54,7 @@ pub enum SerialStatus {
/// messages.
#[cfg(not(target_arch = "wasm32"))] // TODO: serial ports on wasm?
pub fn downlink_port(
ctx: Option<egui::Context>,
downlink_tx: &mut Sender<DownlinkMessage>,
uplink_rx: &mut Receiver<UplinkMessage>,
port: String,
Expand Down Expand Up @@ -112,6 +114,9 @@ pub fn downlink_port(
// If successful, send msg through channel.
downlink_tx.send(msg)?;
last_message = now;
if let Some(ctx) = &ctx {
ctx.request_repaint();
}
}

now = Instant::now();
Expand Down Expand Up @@ -140,6 +145,7 @@ pub fn find_serial_port() -> Option<String> {
/// Run in a separate thread using `spawn_downlink_monitor`.
#[cfg(not(target_arch = "wasm32"))] // TODO: serial ports on wasm?
pub fn downlink_monitor(
ctx: Option<egui::Context>,
serial_status_tx: Sender<(SerialStatus, Option<String>)>,
mut downlink_tx: Sender<DownlinkMessage>,
mut uplink_rx: Receiver<UplinkMessage>,
Expand All @@ -149,9 +155,12 @@ pub fn downlink_monitor(
// If a device was connected, start reading messages.
if let Some(p) = find_serial_port() {
serial_status_tx.send((SerialStatus::Connected, Some(p.clone())))?;
if let Err(e) = downlink_port(&mut downlink_tx, &mut uplink_rx, p.clone(), send_heartbeats) {
if let Err(e) = downlink_port(ctx.clone(), &mut downlink_tx, &mut uplink_rx, p.clone(), send_heartbeats) {
eprintln!("{:?}", e);
serial_status_tx.send((SerialStatus::Error, Some(p)))?;
if let Some(ctx) = &ctx {
ctx.request_repaint();
}
}
}

Expand All @@ -162,13 +171,14 @@ pub fn downlink_monitor(
/// Spawns `downlink_monitor` in a new thread.
#[cfg(not(target_arch = "wasm32"))] // TODO: serial ports on wasm?
pub fn spawn_downlink_monitor(
ctx: Option<egui::Context>,
serial_status_tx: Sender<(SerialStatus, Option<String>)>,
downlink_tx: Sender<DownlinkMessage>,
uplink_rx: Receiver<UplinkMessage>,
send_heartbeats: bool,
) -> JoinHandle<()> {
std::thread::spawn(move || {
downlink_monitor(serial_status_tx, downlink_tx, uplink_rx, send_heartbeats).unwrap_or_default()
downlink_monitor(ctx, serial_status_tx, downlink_tx, uplink_rx, send_heartbeats).unwrap_or_default()
})
}

Expand All @@ -193,13 +203,15 @@ pub struct SerialDataSource {

impl SerialDataSource {
/// Create a new serial port data source.
pub fn new(lora_settings: LoRaSettings) -> Self {
pub fn new(ctx: &egui::Context, lora_settings: LoRaSettings) -> Self {
let (downlink_tx, downlink_rx) = std::sync::mpsc::channel::<DownlinkMessage>();
let (uplink_tx, uplink_rx) = std::sync::mpsc::channel::<UplinkMessage>();
let (serial_status_tx, serial_status_rx) = std::sync::mpsc::channel::<(SerialStatus, Option<String>)>();

let ctx = ctx.clone();

#[cfg(not(target_arch = "wasm32"))] // TODO: can't spawn threads on wasm
spawn_downlink_monitor(serial_status_tx, downlink_tx, uplink_rx, true);
spawn_downlink_monitor(Some(ctx), serial_status_tx, downlink_tx, uplink_rx, true);

let telemetry_log_path = Self::new_telemetry_log_path();
let telemetry_log_file = File::create(&telemetry_log_path);
Expand Down Expand Up @@ -354,14 +366,6 @@ impl DataSource for SerialDataSource {
self.send(UplinkMessage::Command(cmd))
}

fn minimum_fps(&self) -> Option<u64> {
if self.last_time.map(|t| t.elapsed() > Duration::from_secs_f64(10.0)).unwrap_or(false) {
Some(1)
} else {
Some(u64::max(30, u64::min(self.message_receipt_times.len() as u64, 60)))
}
}

fn end(&self) -> Option<Instant> {
let postroll = Duration::from_secs_f64(10.0);

Expand Down Expand Up @@ -396,6 +400,14 @@ impl DataSource for SerialDataSource {
}

fn status_bar_ui(&mut self, ui: &mut egui::Ui) {
#[cfg(not(target_arch = "wasm32"))]
if ui.button("⏮ Reset").clicked() {
self.reset();
}

#[cfg(not(target_arch = "wasm32"))]
ui.separator();

let (status_color, status_text) = match self.serial_status {
SerialStatus::Init => (Color32::from_rgb(0x92, 0x83, 0x74), "Not connected".to_string()),
SerialStatus::Connected => (Color32::from_rgb(0x98, 0x97, 0x1a), "Connected".to_string()),
Expand All @@ -413,4 +425,12 @@ impl DataSource for SerialDataSource {

ui.weak(format!("{} {}", serial_port, telemetry_log_info));
}

fn as_any(&self) -> &dyn Any {
self
}

fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
19 changes: 10 additions & 9 deletions src/data_source/simulation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! A simulation data source

use std::any::Any;
use std::sync::mpsc::SendError;
use std::time::Duration;
use std::slice::Iter;
Expand All @@ -20,7 +21,7 @@ use crate::state::VehicleState;

#[derive(Default)]
pub struct SimulationDataSource {
settings: SimulationSettings,
pub settings: SimulationSettings,
state: Option<SimulationState>,
vehicle_states: Vec<(Instant, VehicleState)>,
}
Expand Down Expand Up @@ -72,14 +73,6 @@ impl DataSource for SimulationDataSource {
Ok(())
}

fn minimum_fps(&self) -> Option<u64> {
None
}

fn simulation_settings(&mut self) -> Option<&mut SimulationSettings> {
Some(&mut self.settings)
}

fn end(&self) -> Option<Instant> {
self.vehicle_states.last().map(|(t, _vs)| *t)
}
Expand All @@ -88,4 +81,12 @@ impl DataSource for SimulationDataSource {
ui.colored_label(Color32::KHAKI, "Simulation");
// TODO: maybe computation times or something?
}

fn as_any(&self) -> &dyn Any {
self
}

fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
Loading