diff --git a/src/mavlink/error.rs b/src/mavlink/error.rs
index 23975eb59b7384774098dacb2e31f5c5b7f1c878..b0aca6e4114deca47fb0c777683cc36b826924e9 100644
--- a/src/mavlink/error.rs
+++ b/src/mavlink/error.rs
@@ -1,11 +1,7 @@
 use thiserror::Error;
 
-pub type Result<T> = std::result::Result<T, MavlinkError>;
-
 #[derive(Debug, Error)]
 pub enum MavlinkError {
-    #[error("Error parsing field: {0}")]
-    UnknownField(String),
     #[error("Error parsing message: {0}")]
     ParseError(#[from] serde_json::Error),
 }
diff --git a/src/mavlink/reflection.rs b/src/mavlink/reflection.rs
index 8f81521e78a55057713a8488f0f94c68a5fcc157..68937c62c5b549a27abf81fa5bed5ae09f4540e8 100644
--- a/src/mavlink/reflection.rs
+++ b/src/mavlink/reflection.rs
@@ -105,7 +105,7 @@ pub struct IndexedField<'a> {
     field: &'a MavField,
 }
 
-impl<'a> IndexedField<'a> {
+impl IndexedField<'_> {
     pub fn msg(&self) -> &MavMessage {
         self.msg
     }
@@ -234,7 +234,7 @@ impl<'b> FieldLike<'_, 'b> for &str {
                     .iter()
                     .find(|f| f.name == *self)
                     .map(|f| IndexedField {
-                        id: msg.fields.iter().position(|f2| f2 == f).unwrap(),
+                        id: msg.fields.iter().position(|f2| f2 == f).log_unwrap(),
                         msg,
                         field: f,
                     })
diff --git a/src/ui/cache.rs b/src/ui/cache.rs
index 46b29cc2f5199005f2eb42e4ee4a5c827d457801..23d894d5b73859904f6767094245adcc0f44356a 100644
--- a/src/ui/cache.rs
+++ b/src/ui/cache.rs
@@ -1,7 +1,11 @@
 //! Module for caching expensive UI calls using egui's temporary memory storage.
 //! It provides utilities for caching the results of functions to avoid frequent recalculations.
 
-use std::time::{Duration, Instant};
+use std::{
+    collections::hash_map::DefaultHasher,
+    hash::{Hash, Hasher},
+    time::{Duration, Instant},
+};
 
 use egui::Context;
 use serialport::SerialPortInfo;
@@ -90,3 +94,69 @@ pub fn cached_first_stm32_port(ctx: &Context) -> Result<Option<SerialPortInfo>,
         SERIAL_PORT_REFRESH_INTERVAL,
     )
 }
+
+/// ChangeTracker manages the tracking of state changes using an integrity digest.
+///
+/// The `integrity_digest` field holds a 64-bit unsigned integer that represents
+/// a summary (or hash) of the current state. This can be used to verify that the
+/// cached UI state remains consistent, and to quickly detect any modifications.
+pub struct ChangeTracker {
+    integrity_digest: u64,
+}
+
+impl ChangeTracker {
+    /// Records the initial state of a hashable value by computing its hash digest.
+    ///
+    /// This method takes a reference to any value that implements the `Hash` trait,
+    /// computes its hash using the default hasher, and stores the resulting digest in a
+    /// newly created `ChangeTracker` instance. This digest serves as a reference point
+    /// for future state comparisons.
+    ///
+    /// # Parameters
+    ///
+    /// - `state`: A reference to the value whose state is to be recorded.
+    ///
+    /// # Returns
+    ///
+    /// A `ChangeTracker` initialized with the computed hash digest.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let initial_tracker = ChangeTracker::record_initial_state(&state);
+    /// ```
+    pub fn record_initial_state<T: Hash>(state: &T) -> Self {
+        let mut hasher = DefaultHasher::new();
+        state.hash(&mut hasher);
+        let integrity_digest = hasher.finish();
+        Self { integrity_digest }
+    }
+
+    /// Checks whether the hash of the current state differs from the initially recorded state.
+    ///
+    /// This method computes the hash digest of the current state (which must implement the
+    /// `Hash` trait) and compares it with the digest stored in the `ChangeTracker`. If the digests
+    /// differ, it indicates that the state has changed since the initial recording.
+    ///
+    /// # Parameters
+    ///
+    /// - `state`: A reference to the current state to be checked for changes.
+    ///
+    /// # Returns
+    ///
+    /// `true` if the current state's hash digest does not match the initially recorded digest,
+    /// indicating a change; `false` otherwise.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// if tracker.has_changed(&state) {
+    ///     println!("The state has changed.");
+    /// }
+    /// ```
+    pub fn has_changed<T: Hash>(&self, state: &T) -> bool {
+        let mut hasher = DefaultHasher::new();
+        state.hash(&mut hasher);
+        self.integrity_digest != hasher.finish()
+    }
+}
diff --git a/src/ui/panes/plot.rs b/src/ui/panes/plot.rs
index a2a48b2a36c7beeb7bc915f459d0dcc89d4cc24d..7c2e27d0ce9ed07888f0d8a41d9982874d3a05e0 100644
--- a/src/ui/panes/plot.rs
+++ b/src/ui/panes/plot.rs
@@ -8,14 +8,14 @@ use crate::{
         Message, MessageData, ROCKET_FLIGHT_TM_DATA, TimedMessage,
         reflection::{self, FieldLike},
     },
-    ui::app::PaneResponse,
+    ui::{app::PaneResponse, cache::ChangeTracker},
 };
 use egui::{Color32, Vec2b};
 use egui_plot::{Legend, Line, PlotPoint, PlotPoints};
 use egui_tiles::TileId;
 use mavlink_bindgen::parser::MavType;
 use serde::{Deserialize, Serialize};
-use source_window::{ChangeTracker, sources_window};
+use source_window::sources_window;
 use std::{hash::Hash, iter::zip};
 
 #[derive(Clone, Default, Debug, Serialize, Deserialize)]
@@ -170,14 +170,6 @@ impl PlotSettings {
         &self.x_field
     }
 
-    fn get_y_fields(&self) -> Vec<&FieldWithID> {
-        self.y_fields.iter().map(|(field, _)| field).collect()
-    }
-
-    // fn get_mut_msg_id(&mut self) -> &mut u32 {
-    //     &mut self.msg_sources.plot_message_id
-    // }
-
     fn get_mut_x_field(&mut self) -> &mut FieldWithID {
         &mut self.x_field
     }
@@ -194,10 +186,6 @@ impl PlotSettings {
         self.y_fields.len()
     }
 
-    // fn is_msg_id_changed(&self) -> bool {
-    //     self.msg_sources.plot_message_id != self.old_msg_sources.plot_message_id
-    // }
-
     fn contains_field(&self, field: &FieldWithID) -> bool {
         self.y_fields.iter().any(|(f, _)| f == field)
     }
@@ -262,12 +250,6 @@ impl Hash for LineSettings {
     }
 }
 
-impl LineSettings {
-    fn new(width: f32, color: Color32) -> Self {
-        Self { width, color }
-    }
-}
-
 /// A struct to hold a field and its ID in a message
 /// We use this and not `reflection::IndexedField` because we need to serialize it
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
diff --git a/src/ui/panes/plot/source_window.rs b/src/ui/panes/plot/source_window.rs
index b4dca59810d895e687f6a98136e8ac58031cde26..e49df739c1d240ee93186a1c1fbd11ced4a389ec 100644
--- a/src/ui/panes/plot/source_window.rs
+++ b/src/ui/panes/plot/source_window.rs
@@ -1,10 +1,8 @@
-use std::{
-    collections::hash_map::DefaultHasher,
-    hash::{Hash, Hasher},
+use crate::{
+    MAVLINK_PROFILE,
+    ui::{cache::ChangeTracker, panes::plot::FieldWithID},
 };
 
-use crate::{MAVLINK_PROFILE, ui::panes::plot::FieldWithID};
-
 use crate::error::ErrInstrument;
 
 use super::{LineSettings, PlotSettings};
@@ -78,7 +76,7 @@ pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut PlotSettings) {
         .spacing([10.0, 2.5])
         .show(ui, |ui| {
             for (i, (field, line_settings)) in
-                plot_settings.get_mut_y_fields().into_iter().enumerate()
+                plot_settings.get_mut_y_fields().iter_mut().enumerate()
             {
                 let LineSettings { width, color } = line_settings;
                 let widget_label = if plot_lines_len > 1 {
@@ -114,98 +112,3 @@ pub fn sources_window(ui: &mut egui::Ui, plot_settings: &mut PlotSettings) {
         plot_settings.add_field(next_field.to_owned());
     }
 }
-
-pub struct ChangeTracker {
-    integrity_digest: u64,
-}
-
-impl ChangeTracker {
-    pub fn record_initial_state<T: Hash>(state: &T) -> Self {
-        let mut hasher = DefaultHasher::new();
-        state.hash(&mut hasher);
-        let integrity_digest = hasher.finish();
-        Self { integrity_digest }
-    }
-
-    pub fn has_changed<T: Hash>(&self, state: &T) -> bool {
-        let mut hasher = DefaultHasher::new();
-        state.hash(&mut hasher);
-        self.integrity_digest != hasher.finish()
-    }
-}
-
-// pub struct SourceSettings<'a> {
-//     msg_sources: &'a mut PlotSettings,
-// }
-
-// impl<'a> SourceSettings<'a> {
-//     pub fn new(
-//         msg_sources: &'a mut PlotSettings,
-//         line_settings: &'a mut Vec<LineSettings>,
-//     ) -> Self {
-//         Self {
-//             old_msg_sources: msg_sources.clone(),
-//             msg_sources,
-//             line_settings,
-//         }
-//     }
-
-//     pub fn are_sources_changed(&self) -> bool {
-//         self.msg_sources != &self.old_msg_sources
-//     }
-
-//     pub fn fields_empty(&self) -> bool {
-//         self.msg_sources.y_field_ids.is_empty()
-//     }
-
-//     fn get_msg_id(&self) -> u32 {
-//         self.msg_sources.plot_message_id
-//     }
-
-//     fn get_x_field_id(&self) -> usize {
-//         self.msg_sources.x_field_id
-//     }
-
-//     fn get_mut_msg_id(&mut self) -> &mut u32 {
-//         &mut self.msg_sources.plot_message_id
-//     }
-
-//     fn get_mut_x_field_id(&mut self) -> &mut usize {
-//         &mut self.msg_sources.x_field_id
-//     }
-
-//     fn set_x_field_id(&mut self, field_id: usize) {
-//         self.msg_sources.x_field_id = field_id;
-//     }
-
-//     fn fields_len(&self) -> usize {
-//         self.msg_sources.y_field_ids.len()
-//     }
-
-//     fn is_msg_id_changed(&self) -> bool {
-//         self.msg_sources.plot_message_id != self.old_msg_sources.plot_message_id
-//     }
-
-//     fn contains_field(&self, field_id: usize) -> bool {
-//         self.msg_sources.y_field_ids.contains(&field_id)
-//     }
-
-//     fn sync_fields_with_lines(&mut self) {
-//         self.msg_sources.y_field_ids = self
-//             .line_settings
-//             .iter()
-//             .map(|ls| ls.field_id.clone())
-//             .collect();
-//     }
-
-//     fn add_field(&mut self, field_id: usize) {
-//         self.line_settings.push(LineSettings::new(field_id));
-//         self.msg_sources.y_field_ids.push(field_id);
-//     }
-
-//     fn clear_fields(&mut self) {
-//         self.msg_sources.y_field_ids.clear();
-//         self.line_settings.clear();
-//         self.msg_sources.x_field_id = 0;
-//     }
-// }