Skip to main content

elata_eeg_hal/
channel.rs

1//! Channel configuration and metadata
2
3/// Type of EEG channel
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum ChannelType {
6    /// Standard EEG electrode
7    Eeg,
8    /// Auxiliary channel (accelerometer, gyro, etc.)
9    Aux,
10    /// Reference electrode
11    Reference,
12    /// Ground electrode
13    Ground,
14}
15
16/// Information about a single channel
17#[derive(Debug, Clone)]
18pub struct Channel {
19    /// Channel index (0-based)
20    pub index: usize,
21    /// Channel name (e.g., "TP9", "AF7", "Fpz")
22    pub name: String,
23    /// Type of channel
24    pub channel_type: ChannelType,
25    /// 10-20 system location, if applicable
26    pub location: Option<String>,
27}
28
29impl Channel {
30    pub fn new(index: usize, name: impl Into<String>, channel_type: ChannelType) -> Self {
31        Self {
32            index,
33            name: name.into(),
34            channel_type,
35            location: None,
36        }
37    }
38
39    pub fn eeg(index: usize, name: impl Into<String>) -> Self {
40        Self::new(index, name, ChannelType::Eeg)
41    }
42
43    pub fn aux(index: usize, name: impl Into<String>) -> Self {
44        Self::new(index, name, ChannelType::Aux)
45    }
46
47    pub fn with_location(mut self, location: impl Into<String>) -> Self {
48        self.location = Some(location.into());
49        self
50    }
51}
52
53/// Channel configuration for a device
54#[derive(Debug, Clone)]
55pub struct ChannelConfig {
56    channels: Vec<Channel>,
57}
58
59impl ChannelConfig {
60    pub fn new(channels: Vec<Channel>) -> Self {
61        Self { channels }
62    }
63
64    /// Create a simple configuration with N EEG channels named Ch0, Ch1, etc.
65    pub fn simple(count: usize) -> Self {
66        let channels = (0..count)
67            .map(|i| Channel::eeg(i, format!("Ch{i}")))
68            .collect();
69        Self { channels }
70    }
71
72    /// Create a Muse-style channel configuration
73    pub fn muse() -> Self {
74        Self::new(vec![
75            Channel::eeg(0, "TP9").with_location("TP9"),
76            Channel::eeg(1, "AF7").with_location("AF7"),
77            Channel::eeg(2, "AF8").with_location("AF8"),
78            Channel::eeg(3, "TP10").with_location("TP10"),
79        ])
80    }
81
82    /// Create a Muse S Athena-style channel configuration (8-channel EEG)
83    pub fn muse_athena() -> Self {
84        Self::new(vec![
85            Channel::eeg(0, "TP9").with_location("TP9"),
86            Channel::eeg(1, "AF7").with_location("AF7"),
87            Channel::eeg(2, "AF8").with_location("AF8"),
88            Channel::eeg(3, "TP10").with_location("TP10"),
89            Channel::eeg(4, "AUX_1").with_location("AUX_1"),
90            Channel::eeg(5, "AUX_2").with_location("AUX_2"),
91            Channel::eeg(6, "AUX_3").with_location("AUX_3"),
92            Channel::eeg(7, "AUX_4").with_location("AUX_4"),
93        ])
94    }
95
96    pub fn channels(&self) -> &[Channel] {
97        &self.channels
98    }
99
100    pub fn channel_count(&self) -> usize {
101        self.channels.len()
102    }
103
104    pub fn eeg_channels(&self) -> impl Iterator<Item = &Channel> {
105        self.channels
106            .iter()
107            .filter(|c| c.channel_type == ChannelType::Eeg)
108    }
109
110    pub fn eeg_channel_count(&self) -> usize {
111        self.eeg_channels().count()
112    }
113
114    pub fn get_by_name(&self, name: &str) -> Option<&Channel> {
115        self.channels.iter().find(|c| c.name == name)
116    }
117
118    pub fn get_by_index(&self, index: usize) -> Option<&Channel> {
119        self.channels.get(index)
120    }
121}