//! Neuro service for state management. use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; use super::types::*; /// Loaded recording with metadata pub struct LoadedRecording { pub handle: RecordingHandle, pub data: Vec>, pub sfreq: f64, pub channel_names: Vec, pub channel_types: Vec, pub events: Vec, } /// Loaded BIDS dataset storage pub struct LoadedBidsDataset { pub handle: BidsDatasetHandle, pub dataset: rtx_neuro::io::bids::BidsDataset, } /// Epochs data storage pub struct EpochsData { pub handle: EpochsHandle, /// [n_epochs x n_channels x n_times] pub data: Vec>>, pub times: Vec, pub channel_names: Vec, } /// Forward model storage pub struct ForwardModel { pub handle: ForwardHandle, /// Gain matrix [n_sensors x n_sources*3] pub gain: Vec>, /// Source positions [n_sources x 3] pub source_positions: Vec<[f64; 3]>, /// Sensor positions [n_sensors x 3] pub sensor_positions: Vec<[f64; 3]>, } /// Inverse operator storage pub struct InverseOperator { pub handle: InverseHandle, /// Inverse kernel [n_sources x n_channels] pub kernel: Vec>, /// Source positions pub source_positions: Vec<[f64; 3]>, } /// SSP projector storage pub struct SspProjectorData { pub handle: SspHandle, /// Projector vectors [n_projectors x n_channels] pub vectors: Vec>, /// Active flags pub active: Vec, } /// ICA model storage #[derive(Clone)] pub struct IcaModelData { pub handle: IcaHandle, /// Unmixing matrix [n_components x n_channels] pub unmixing: Vec>, /// Mixing matrix [n_channels x n_components] pub mixing: Vec>, } /// Loaded FreeSurfer subject storage pub struct LoadedFreeSurferSubject { pub handle: FreeSurferHandleDto, pub subject: rtx_neuro_anatomy::FreeSurferSubject, } /// Handle to artifact detector pub struct ArtifactDetectorHandle { pub config: ArtifactDetectorConfigDto, } /// Holds GNN model and metadata pub struct GnnModelHolder { pub config: GnnModelConfigDto, pub n_parameters: usize, } /// Neuro service managing recordings and processing pub struct NeuroService { pub(crate) recordings: HashMap, pub(crate) epochs: HashMap, pub(crate) forward_models: HashMap, pub(crate) inverse_operators: HashMap, pub(crate) ssp_projectors: HashMap, pub(crate) ica_models: HashMap, pub(crate) bids_datasets: HashMap, pub(crate) freesurfer_subjects: HashMap, pub(crate) active_recording: Option, pub(crate) counter: usize, } impl NeuroService { /// Create a new neuro service pub fn new() -> Self { Self { recordings: HashMap::new(), epochs: HashMap::new(), forward_models: HashMap::new(), inverse_operators: HashMap::new(), ssp_projectors: HashMap::new(), ica_models: HashMap::new(), bids_datasets: HashMap::new(), freesurfer_subjects: HashMap::new(), active_recording: None, counter: 0, } } /// Generate a unique ID pub fn next_id(&mut self, prefix: &str) -> String { self.counter += 1; format!("{}_{}", prefix, self.counter) } /// Get service status pub fn status(&self) -> NeuroStatus { let memory_usage = self.recordings.values().map(|r| { r.data.iter().map(|ch| ch.len() * std::mem::size_of::()).sum::() }).sum::() + self.epochs.values().map(|e| { e.data.iter().map(|ep| { ep.iter().map(|ch| ch.len() * std::mem::size_of::()).sum::() }).sum::() }).sum::(); NeuroStatus { n_recordings: self.recordings.len(), active_recording: self.active_recording.clone(), n_epochs_sets: self.epochs.len(), memory_usage, } } /// Reset the service, clearing all data pub fn reset(&mut self) { self.recordings.clear(); self.epochs.clear(); self.forward_models.clear(); self.inverse_operators.clear(); self.ssp_projectors.clear(); self.ica_models.clear(); self.bids_datasets.clear(); self.freesurfer_subjects.clear(); self.active_recording = None; } } impl Default for NeuroService { fn default() -> Self { Self::new() } } /// Type alias for the neuro state used by Tauri commands pub type NeuroState = Arc>; /// State for LSL service pub type LslState = Arc>; /// BCI pipeline state pub type BciState = Arc>>; /// State for artifact detector pub type ArtifactDetectorState = Arc>>; /// GNN state for managing models pub type GnnModelState = Arc>>; /// Separate state for the database to avoid async/sync conflicts pub type DatabaseState = Arc>>;