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

Redesign to reduce boilerplate code. Reorganize files #9

Merged
merged 4 commits into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ Cargo.lock

# misc
.hide*
.vscode
.vscode
NOTES.md
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ mockall = "0.13.1"
rand = "0.8.5"
typetag = "0.2.18"
anyhow = { version = "1.0.94", features = ["backtrace"] }
rust-fsm = "0.7.0"
event_bridge = "0.3.1"
210 changes: 210 additions & 0 deletions src/api/controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
//! Controller Module
//!
//! This module defines the traits and structures for managing the application's core functionalities,
//! including recording, storage, and Bluetooth interactions. It provides a set of asynchronous APIs
//! to handle various operations such as starting/stopping recordings, loading/storing data, and managing
//! Bluetooth devices.
use crate::model::bluetooth::{AdapterDescriptor, DeviceDescriptor, HeartrateMessage};
use anyhow::Result;
use async_trait::async_trait;
use btleplug::api::Central;
use std::{path::PathBuf, sync::Arc};
use time::Duration;
use tokio::sync::RwLock;

use super::model::{BluetoothModelApi, MeasurementModelApi};

#[derive(Clone, Debug)]
pub enum OutlierFilter {
MovingMAD { parameter: f64, _window: usize },
}

/// RecordingApi trait
///
/// This trait defines the asynchronous API for managing the recording process in the application.
/// It provides methods to start and stop the recording process.
#[async_trait]
pub trait RecordingApi {
/// start the recording process
async fn start_recording(&mut self) -> Result<()>;
/// stop the recording process
async fn stop_recording(&mut self) -> Result<()>;
}

/// StorageEventApi trait
///
/// This trait defines the asynchronous API for managing storage-related events in the application.
/// It provides methods to clear storage, load data from a file, store data to a file, and handle
/// new and recorded measurements.
#[async_trait]
pub trait StorageEventApi {
/// Clear the storage.
///
/// This method clears all the stored data.
async fn clear(&mut self) -> Result<()>;

/// Load data from a file.
///
/// This method loads data from the specified file path.
///
/// # Arguments
///
/// * `path` - A `PathBuf` representing the file path from which to load data.
async fn load_from_file(&mut self, path: PathBuf) -> Result<()>;

/// Store data to a file.
///
/// This method stores data to the specified file path.
///
/// # Arguments
///
/// * `path` - A `PathBuf` representing the file path to which to store data.
async fn store_to_file(&mut self, path: PathBuf) -> Result<()>;

/// Store the recorded measurement.
///
/// This method handles the storage of a new measurement.
async fn new_measurement(&mut self) -> Result<()>;

/// Store the recorded measurement.
///
/// This method handles the storage of the recorded measurement.
async fn store_recorded_measurement(&mut self) -> Result<()>;
}

/// StorageApi trait
///
/// This trait defines the asynchronous API for managing storage operations in the application.
/// It provides methods to interact with the active measurement.
///
/// # Type Parameters
///
/// * `MT` - A type that implements the `MeasurementModelApi` trait.
///
pub trait StorageApi<MT: MeasurementModelApi> {
/// Get the active measurement.
///
/// This method returns a reference to the active measurement, if any.
fn get_active_measurement(&mut self) -> &Option<Arc<RwLock<MT>>>;
}

/// MeasurementApi trait
///
/// This trait extends the `MeasurementModelApi` trait and defines additional asynchronous APIs
/// for mutatung measurement-related operations in the application. It provides methods to set
/// statistical windows, configure outlier filters, and record heart rate messages.
#[async_trait]
pub trait MeasurementApi: MeasurementModelApi {
/// Set the statistics window.
///
/// This method sets the duration of the window used for statistical calculations.
///
/// # Arguments
///
/// * `window` - A `Duration` representing the length of the statistics window.
async fn set_stats_window(&mut self, window: Duration) -> Result<()>;

/// Set the outlier filter.
///
/// This method configures the outlier filter used to process the measurements.
///
/// # Arguments
///
/// * `filter` - An `OutlierFilter` specifying the type and parameters of the filter.
async fn set_outlier_filter(&mut self, filter: OutlierFilter) -> Result<()>;

/// Record a heart rate message.
///
/// This method processes and records a new heart rate message.
///
/// # Arguments
///
/// * `msg` - A `HeartrateMessage` containing the heart rate data to be recorded.
async fn record_message(&mut self, msg: HeartrateMessage) -> Result<()>;
}

/// BluetoothApi trait
///
/// This trait extends the `BluetoothModelApi` trait and defines additional asynchronous APIs
/// for mutating Bluetooth operations in the application. It provides methods to discover adapters,
/// select adapters and peripherals, start and stop scanning, and start and stop listening for
/// Bluetooth events.
#[async_trait]
pub trait BluetoothApi: BluetoothModelApi + Send + Sync {
/// Discover Bluetooth adapters.
///
/// This method initiates the discovery of available Bluetooth adapters.
async fn discover_adapters(&mut self) -> Result<()>;

/// Select a Bluetooth adapter.
///
/// This method selects a Bluetooth adapter based on the provided adapter descriptor.
///
/// # Arguments
///
/// * `adapter` - An `AdapterDescriptor` representing the unique identifier of the adapter to be selected.
async fn select_adapter(&mut self, adapter: AdapterDescriptor) -> Result<()>;

/// Select a Bluetooth peripheral.
///
/// This method selects a Bluetooth peripheral based on the provided device descriptor.
///
/// # Arguments
///
/// * `device` - A `DeviceDescriptor` representing the unique identifier of the peripheral to be selected.
async fn select_peripheral(&mut self, device: DeviceDescriptor) -> Result<()>;

/// Start scanning for Bluetooth devices.
///
/// This method initiates the scanning process to discover Bluetooth peripherals.
async fn start_scan(&mut self) -> Result<()>;

/// Stop scanning for Bluetooth devices.
///
/// This method stops the ongoing scanning process for discovering Bluetooth peripherals.
#[allow(dead_code)]
async fn stop_scan(&mut self) -> Result<()>;

/// Start listening to the last selected bluetooth peripheral
async fn start_listening(&mut self) -> Result<()>;

/// Stop listening to the bluetooth peripheral
async fn stop_listening(&mut self) -> Result<()>;
}

/// AdapterDiscovery trait
///
/// This trait defines the asynchronous API for discovering Bluetooth adapters in the application.
/// It provides a method to discover available Bluetooth adapters.
///
/// # Type Parameters
///
/// * `A` - A type that implements the `Central` and `DisplayName` traits.
///
#[async_trait]
pub trait AdapterDiscovery<A: Central + DisplayName> {
/// Discover Bluetooth adapters.
///
/// This method initiates the discovery of available Bluetooth adapters and returns a vector of adapters.
///
/// # Returns
///
/// A `Result` containing a vector of discovered adapters of type `A` on success, or an error on failure.
async fn discover_adapters() -> Result<Vec<A>>;
}

/// DisplayName trait
///
/// This trait defines the asynchronous API for retrieving the display name of an object.
/// It provides a method to get the name to display for the implementing object.
#[async_trait]
pub trait DisplayName {
/// Get the name to display for the implementing object.
///
/// This method returns the display name of the object as a `String`.
///
/// # Returns
///
/// A `Result` containing the display name of the object as a `String` on success, or an error on failure.
async fn get_name(&self) -> Result<String>;
}
104 changes: 104 additions & 0 deletions src/api/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! This module defines the read only API for interacting with various models.
//! It provides interfaces for accessing data related to HRV measurements,
//! Bluetooth adapters, and stored acquisitions.
use btleplug::api::BDAddr;
use std::{fmt::Debug, sync::Arc};
use time::{Duration, OffsetDateTime};
use tokio::sync::RwLock;

use crate::model::{
bluetooth::{AdapterDescriptor, DeviceDescriptor, HeartrateMessage},
hrv::{HrvSessionData, HrvStatistics},
};

/// `MeasurementModelApi` trait.
///
/// Defines the interface for managing measurement-related data, including runtime measurements,
/// HRV statistics, and stored acquisitions.
pub trait MeasurementModelApi: Debug + Send + Sync {
/// Retrieves the start time of the current acquisition.
///
/// # Returns
/// An `OffsetDateTime` indicating the start time.
fn get_start_time(&self) -> &OffsetDateTime;

/// Retrieves the last heart rate message received.
///
/// # Returns
/// An optional `HeartrateMessage` representing the most recent measurement.
fn get_last_msg(&self) -> Option<&HeartrateMessage>;

/// Retrieves the current HRV statistics.
///
/// # Returns
/// A reference to an optional `HrvStatistics` containing computed HRV data.
fn get_hrv_stats(&self) -> Option<&HrvStatistics>;

/// Retrieves the configured statistics window.
///
/// # Returns
/// A reference to an optional `Duration` representing the analysis window size.
fn get_stats_window(&self) -> Option<&Duration>;

/// Getter for the filter parameter value (fraction of std. dev).
///
/// # Returns
/// The parameter value for the outlier filter.
fn get_outlier_filter_value(&self) -> f64;

/// Retrieves the points for the Poincare plot.
///
/// # Returns
/// A vector of `[f64; 2]` pairs representing the Poincare points.
fn get_poincare_points(&self) -> Vec<[f64; 2]>;

/// Retrieves the session data.
///
/// # Returns
/// A reference to the `HrvSessionData`.
fn get_session_data(&self) -> &HrvSessionData;

/// Retrieves the elapsed time since the start of the acquisition.
///
/// # Returns
/// A `Duration` representing the elapsed time.
fn get_elapsed_time(&self) -> Duration;
}

pub trait BluetoothModelApi: Debug + Send + Sync {
/// Gets the list of Bluetooth adapters as a vector of `(Name, UUID)` tuples.
///
/// # Returns
/// A vector of tuples containing adapter names and UUIDs.
fn get_adapters(&self) -> &[AdapterDescriptor];

/// Gets the currently selected adapter, if any.
///
/// # Returns
/// An optional reference to the selected adapter.
fn get_selected_adapter(&self) -> Option<AdapterDescriptor>;

/// Gets the list of discovered Bluetooth devices.
///
/// # Returns
/// A reference to the vector of devices.
fn get_devices(&self) -> &Arc<RwLock<Vec<DeviceDescriptor>>>;

fn get_selected_device(&self) -> Option<DeviceDescriptor>;

/// Gets the scanning status.
///
/// # Returns
/// `true` if scanning is active, `false` otherwise.
#[allow(dead_code)]
fn is_scanning(&self) -> bool;

fn is_listening_to(&self) -> Option<BDAddr>;
}

pub trait StorageModelApi: Debug + Sync + Send {
/// Returns a slice of handles to the stored acquisition models.
fn get_acquisitions(&self) -> &[ModelHandle<dyn MeasurementModelApi>];
}

pub type ModelHandle<T> = Arc<RwLock<T>>;
4 changes: 2 additions & 2 deletions src/core/view_trait.rs → src/api/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module defines the `ViewApi` trait, which is implemented by all views in the HRV analysis tool.
//! It provides a standardized interface for rendering and updating views.

use super::events::UiInputEvent;
use crate::core::events::AppEvent;

/// Trait defining the interface for application views.
///
Expand All @@ -17,7 +17,7 @@ pub trait ViewApi: Send {
///
/// # Returns
/// A result indicating success or failure.
fn render<F: Fn(UiInputEvent) + ?Sized>(
fn render<F: Fn(AppEvent) + ?Sized>(
&mut self,
publish: &F,
ctx: &egui::Context,
Expand Down
Loading
Loading