elata_eeg_hal/device.rs
1//! Core device abstraction trait
2
3use crate::channel::ChannelConfig;
4use crate::error::Result;
5use crate::sample::SampleBuffer;
6
7/// State of an EEG device
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum DeviceState {
10 /// Device is not connected
11 Disconnected,
12 /// Device is connected but not streaming
13 Connected,
14 /// Device is actively streaming data
15 Streaming,
16}
17
18/// Information about an EEG device
19#[derive(Debug, Clone)]
20pub struct DeviceInfo {
21 /// Human-readable device name
22 pub name: String,
23 /// Device manufacturer
24 pub manufacturer: String,
25 /// Sample rate in Hz
26 pub sample_rate: u16,
27 /// Channel configuration
28 pub channels: ChannelConfig,
29}
30
31impl DeviceInfo {
32 pub fn new(
33 name: impl Into<String>,
34 manufacturer: impl Into<String>,
35 sample_rate: u16,
36 channels: ChannelConfig,
37 ) -> Self {
38 Self {
39 name: name.into(),
40 manufacturer: manufacturer.into(),
41 sample_rate,
42 channels,
43 }
44 }
45}
46
47/// Core trait for EEG devices
48///
49/// This trait provides a unified interface for all EEG devices, whether
50/// physical (Muse S, OpenBCI) or synthetic (for testing).
51///
52/// # Lifecycle
53///
54/// 1. Create device instance
55/// 2. Call `connect()` to establish connection
56/// 3. Call `start_stream()` to begin data acquisition
57/// 4. Call `read_samples()` to get data
58/// 5. Call `stop_stream()` when done
59/// 6. Call `disconnect()` to release resources
60pub trait EegDevice {
61 /// Get device information
62 fn info(&self) -> DeviceInfo;
63
64 /// Get current device state
65 fn state(&self) -> DeviceState;
66
67 /// Connect to the device
68 fn connect(&mut self) -> Result<()>;
69
70 /// Disconnect from the device
71 fn disconnect(&mut self) -> Result<()>;
72
73 /// Start streaming data
74 fn start_stream(&mut self) -> Result<()>;
75
76 /// Stop streaming data
77 fn stop_stream(&mut self) -> Result<()>;
78
79 /// Read available samples into the buffer
80 ///
81 /// Returns the number of samples read. This may be 0 if no data is available.
82 /// The buffer is NOT cleared before reading; new samples are appended.
83 fn read_samples(&mut self, buffer: &mut SampleBuffer) -> Result<usize>;
84
85 /// Check if the device is connected
86 fn is_connected(&self) -> bool {
87 matches!(
88 self.state(),
89 DeviceState::Connected | DeviceState::Streaming
90 )
91 }
92
93 /// Check if the device is streaming
94 fn is_streaming(&self) -> bool {
95 self.state() == DeviceState::Streaming
96 }
97}
98
99/// Extension trait for devices that support configuration
100pub trait ConfigurableDevice: EegDevice {
101 /// Set the sample rate (if supported by the device)
102 fn set_sample_rate(&mut self, rate: u16) -> Result<()>;
103
104 /// Enable or disable specific channels
105 fn set_channels_enabled(&mut self, enabled: &[bool]) -> Result<()>;
106}