diff --git a/src/main.rs b/src/main.rs index d00f72ae3aa830528f61a4544248a12afd495ea0..df0dcc6b3874cde18eeee4307973f6d20715102a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,16 @@ static MAVLINK_PROFILE: LazyLock<ReflectionContext> = LazyLock::new(ReflectionCo static APP_NAME: &str = "segs"; +#[macro_export] +macro_rules! msg_broker { + () => { + $crate::MSG_MANAGER + .get() + .log_expect("Unable to get MessageBroker") + .lock() + }; +} + fn main() -> Result<(), eframe::Error> { // Set up logging (USE RUST_LOG=debug to see logs) let env_filter = EnvFilter::builder().from_env_lossy(); diff --git a/src/mavlink/reflection.rs b/src/mavlink/reflection.rs index 7f225a8ffd7c10d962fbad6d94b9c4279dc54b9e..528ffde5bb9979465bb760f8da74e80d5f620c3c 100644 --- a/src/mavlink/reflection.rs +++ b/src/mavlink/reflection.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; +use anyhow::anyhow; use mavlink_bindgen::parser::{MavProfile, MavType}; use crate::error::ErrInstrument; @@ -54,30 +55,28 @@ impl ReflectionContext { } /// Get all field names for a message by its ID. - pub fn get_fields_by_id(&self, message_id: u32) -> Vec<&str> { - self.mavlink_profile + pub fn get_fields_by_id(&self, message_id: u32) -> anyhow::Result<Vec<&str>> { + Ok(self + .mavlink_profile .messages .iter() .find(|(_, m)| m.id == message_id) .map(|(_, m)| &m.fields) - .unwrap_or_else(|| { - panic!("Message ID {} not found in profile", message_id); - }) + .ok_or(anyhow!("Message ID {} not found in profile", message_id))? .iter() .map(|f| f.name.as_str()) - .collect() + .collect()) } /// Get all plottable field names for a message by its ID. - pub fn get_plottable_fields_by_id(&self, message_id: u32) -> Vec<&str> { - self.mavlink_profile + pub fn get_plottable_fields_by_id(&self, message_id: u32) -> anyhow::Result<Vec<&str>> { + Ok(self + .mavlink_profile .messages .iter() .find(|(_, m)| m.id == message_id) .map(|(_, m)| &m.fields) - .unwrap_or_else(|| { - panic!("Message ID {} not found in profile", message_id); - }) + .ok_or(anyhow!("Message ID {} not found in profile", message_id))? .iter() .filter(|f| { matches!( @@ -95,21 +94,20 @@ impl ReflectionContext { ) }) .map(|f| f.name.as_str()) - .collect() + .collect()) } /// Get all field names for a message by its name. - pub fn get_fields_by_name(&self, message_name: &str) -> Vec<&str> { - self.mavlink_profile + pub fn get_fields_by_name(&self, message_name: &str) -> anyhow::Result<Vec<&str>> { + Ok(self + .mavlink_profile .messages .iter() .find(|(_, m)| m.name == message_name) .map(|(_, m)| &m.fields) - .unwrap_or_else(|| { - panic!("Message {} not found in profile", message_name); - }) + .ok_or(anyhow!("Message {} not found in profile", message_name))? .iter() .map(|f| f.name.as_str()) - .collect() + .collect()) } } diff --git a/src/ui/composable_view.rs b/src/ui/composable_view.rs index 174b62de2fb010362c2b9226864649d2e7361955..f8b6b3fa4c06186cfc7013b40797daf48a959b80 100644 --- a/src/ui/composable_view.rs +++ b/src/ui/composable_view.rs @@ -14,7 +14,7 @@ use std::{ use egui::{Key, Modifiers}; use egui_tiles::{Behavior, Container, Linear, LinearDir, Tile, TileId, Tiles, Tree}; use serde::{Deserialize, Serialize}; -use tracing::{debug, error, trace, warn}; +use tracing::{debug, error, trace}; #[derive(Default)] pub struct ComposableView { @@ -296,11 +296,7 @@ impl SourceWindow { ui.end_row(); }); if ui.button("Connect").clicked() { - MSG_MANAGER - .get() - .unwrap() - .lock() - .listen_from_ethernet_port(self.port); + msg_broker!().listen_from_ethernet_port(self.port); *can_be_closed = true; } } diff --git a/src/ui/panes/default.rs b/src/ui/panes/default.rs index 3cfd31c2a6e04b159fed5b6bb16a46680c59c0d2..f3963eddf750d0da9be94d8035609b4ae1a8abfe 100644 --- a/src/ui/panes/default.rs +++ b/src/ui/panes/default.rs @@ -7,7 +7,7 @@ use crate::ui::{ utils::{vertically_centered, SizingMemo}, }; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct DefaultPane { #[serde(skip)] centering_memo: SizingMemo, @@ -15,17 +15,8 @@ pub struct DefaultPane { contains_pointer: bool, } -impl Default for DefaultPane { - fn default() -> Self { - DefaultPane { - centering_memo: SizingMemo::default(), - contains_pointer: false, - } - } -} - impl PartialEq for DefaultPane { - fn eq(&self, other: &Self) -> bool { + fn eq(&self, _other: &Self) -> bool { true } } diff --git a/src/ui/panes/plot.rs b/src/ui/panes/plot.rs index d17d257455a52e70db4765e013126f500f8cba10..446e0752efeae32ac6634a0c7a8be12bd849153b 100644 --- a/src/ui/panes/plot.rs +++ b/src/ui/panes/plot.rs @@ -11,8 +11,8 @@ use crate::{ extract_from_message, MavlinkResult, MessageData, MessageView, TimedMessage, ROCKET_FLIGHT_TM_DATA, }, + msg_broker, ui::composable_view::PaneResponse, - MSG_MANAGER, }; use super::PaneBehavior; @@ -78,10 +78,7 @@ impl PaneBehavior for Plot2DPane { let mut plot_lines = Vec::new(); if self.plot_active { - MSG_MANAGER - .get() - .unwrap() - .lock() + msg_broker!() .refresh_view(view) .log_expect("MessageView may be invalid"); let acc_points = &view.points; diff --git a/src/ui/panes/plot/source_window.rs b/src/ui/panes/plot/source_window.rs index ecb4d610275296b0fc236b86d0c15c5418accf07..d68fa93ff2401c7e5457f2683af341a73f8fe101 100644 --- a/src/ui/panes/plot/source_window.rs +++ b/src/ui/panes/plot/source_window.rs @@ -3,6 +3,8 @@ use crate::{ MAVLINK_PROFILE, }; +use crate::error::ErrInstrument; + use super::{LineSettings, MsgSources}; pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut SourceSettings) { @@ -18,7 +20,7 @@ pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut SourceSettings) { for msg in MAVLINK_PROFILE.sorted_messages() { ui.selectable_value( plot_settings.get_mut_msg_id(), - MavMessage::message_id_from_name(msg).unwrap(), + MavMessage::message_id_from_name(msg).log_expect("Invalid message name"), msg, ); } @@ -30,7 +32,9 @@ pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut SourceSettings) { } // check fields and assign a default field_x and field_y once the msg is changed - let fields = MAVLINK_PROFILE.get_plottable_fields_by_id(*plot_settings.get_msg_id()); + let fields = MAVLINK_PROFILE + .get_plottable_fields_by_id(*plot_settings.get_msg_id()) + .log_expect("Invalid message id"); // get the first field that is in the list of fields or the previous if valid let x_field = plot_settings.get_x_field(); let new_field_x = fields @@ -104,7 +108,7 @@ pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut SourceSettings) { let next_field = fields .iter() .find(|f| !plot_settings.contains_field(f)) - .unwrap(); + .log_unwrap(); plot_settings.add_field(next_field.to_string()); } } diff --git a/src/ui/persistency/layout_manager.rs b/src/ui/persistency/layout_manager.rs index 33ed67147d8fec951205c11d556e96192db4506c..a7b857ca3af0ff779012f5ab98187621a3a67227 100644 --- a/src/ui/persistency/layout_manager.rs +++ b/src/ui/persistency/layout_manager.rs @@ -7,7 +7,7 @@ use std::{ use tracing::{info, trace, warn}; -use crate::{error::ErrInstrument, MSG_MANAGER}; +use crate::{error::ErrInstrument, msg_broker}; use super::super::composable_view::ComposableViewState; @@ -103,7 +103,7 @@ impl LayoutManager { .ok_or(anyhow::anyhow!("Layout not found"))?; *state = layout.clone(); self.current_layout = Some(path.as_ref().into()); - MSG_MANAGER.get().unwrap().lock().unsubscribe_all_views(); + msg_broker!().unsubscribe_all_views(); Ok(()) } diff --git a/src/ui/persistency/layout_manager_window.rs b/src/ui/persistency/layout_manager_window.rs index c5079837a5bb59ec8d38fe6502810e86575706bc..b3cdbdc10b4aa14885f3535f07848c600a618c71 100644 --- a/src/ui/persistency/layout_manager_window.rs +++ b/src/ui/persistency/layout_manager_window.rs @@ -216,14 +216,17 @@ fn show_action_buttons( debug!("Created layouts folder"); } - match fs::copy(file, destination.clone()) { - Ok(_) => { - debug!("Layout imported in {}", destination.to_str().unwrap()); - selection.replace(file_name.into()); - layout_manager.reload_layouts(); - layout_manager.load_layout(&file_name, state); - } - Err(e) => println!("Error importing layout: {:?}", e), + if let Err(e) = fs::copy(file, destination.clone()) { + // FIXME when error dialog will be implemented this will be changed + error!("Error importing layout: {:?}", e); + } + + debug!("Layout imported in {}", destination.to_str().log_unwrap()); + selection.replace(file_name.into()); + layout_manager.reload_layouts(); + if let Err(e) = layout_manager.load_layout(file_name, state) { + // FIXME when error dialog will be implemented this will be changed + error!("Error loading imported layout: {:?}", e); } } } @@ -251,14 +254,20 @@ fn show_action_buttons( let to_save = text_edit_resp.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)); - let to_save = to_save || save_button_resp.clicked(); - to_save + + to_save || save_button_resp.clicked() }); if to_save { let name = text_input.clone(); - layout_manager.save_layout(&name, &state); - *selection = Some(name.clone().into()); + if let Err(e) = layout_manager.save_layout(&name, state) { + // FIXME when error dialog will be implemented this will be changed + error!("Error saving layout: {:?}", e); + } else { + layout_manager.reload_layouts(); + selection.replace(name.clone().into()); + } + *selection = Some(name.into()); } }); });