151 lines
4.1 KiB
Rust
151 lines
4.1 KiB
Rust
//! LSL stream information and types
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Channel format for LSL streams
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum ChannelFormat {
|
|
/// 32-bit floating point
|
|
Float32,
|
|
/// 64-bit floating point
|
|
Float64,
|
|
/// 32-bit signed integer
|
|
Int32,
|
|
/// 16-bit signed integer
|
|
Int16,
|
|
/// 8-bit signed integer
|
|
Int8,
|
|
/// Variable-length strings
|
|
String,
|
|
}
|
|
|
|
impl Default for ChannelFormat {
|
|
fn default() -> Self {
|
|
Self::Float32
|
|
}
|
|
}
|
|
|
|
/// Information about an LSL stream
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct LslStreamInfo {
|
|
/// Stream name (e.g., "MyBiosemi")
|
|
pub name: String,
|
|
/// Stream type (e.g., "EEG", "MEG", "Markers")
|
|
pub stream_type: String,
|
|
/// Number of channels
|
|
pub channel_count: usize,
|
|
/// Nominal sampling rate in Hz (0 for irregular rate)
|
|
pub nominal_srate: f64,
|
|
/// Data format
|
|
pub channel_format: ChannelFormat,
|
|
/// Unique source identifier (e.g., machine ID + serial number)
|
|
pub source_id: String,
|
|
/// Hostname of the source machine
|
|
pub hostname: String,
|
|
/// Version of the stream
|
|
pub version: i32,
|
|
/// Creation timestamp
|
|
pub created_at: f64,
|
|
/// Session ID
|
|
pub session_id: String,
|
|
/// Unique identifier for this stream instance
|
|
pub uid: String,
|
|
}
|
|
|
|
impl LslStreamInfo {
|
|
/// Create a new stream info
|
|
pub fn new(name: &str, stream_type: &str, channel_count: usize, srate: f64) -> Self {
|
|
Self {
|
|
name: name.to_string(),
|
|
stream_type: stream_type.to_string(),
|
|
channel_count,
|
|
nominal_srate: srate,
|
|
channel_format: ChannelFormat::Float32,
|
|
source_id: String::new(),
|
|
hostname: String::new(),
|
|
version: 1,
|
|
created_at: 0.0,
|
|
session_id: String::new(),
|
|
uid: uuid::Uuid::new_v4().to_string(),
|
|
}
|
|
}
|
|
|
|
/// Check if this is an EEG stream
|
|
pub fn is_eeg(&self) -> bool {
|
|
self.stream_type.to_uppercase() == "EEG"
|
|
}
|
|
|
|
/// Check if this is an MEG stream
|
|
pub fn is_meg(&self) -> bool {
|
|
self.stream_type.to_uppercase() == "MEG"
|
|
}
|
|
|
|
/// Check if this is a marker/event stream
|
|
pub fn is_markers(&self) -> bool {
|
|
let t = self.stream_type.to_uppercase();
|
|
t == "MARKERS" || t == "EVENTS" || t == "STIM"
|
|
}
|
|
|
|
/// Get the expected sample size in bytes
|
|
pub fn sample_size(&self) -> usize {
|
|
let bytes_per_channel = match self.channel_format {
|
|
ChannelFormat::Float32 => 4,
|
|
ChannelFormat::Float64 => 8,
|
|
ChannelFormat::Int32 => 4,
|
|
ChannelFormat::Int16 => 2,
|
|
ChannelFormat::Int8 => 1,
|
|
ChannelFormat::String => 0, // Variable
|
|
};
|
|
self.channel_count * bytes_per_channel
|
|
}
|
|
}
|
|
|
|
/// A single sample from an LSL stream
|
|
#[derive(Debug, Clone)]
|
|
pub struct LslSample {
|
|
/// Sample data (one value per channel)
|
|
pub data: Vec<f64>,
|
|
/// LSL timestamp of the sample
|
|
pub timestamp: f64,
|
|
}
|
|
|
|
impl LslSample {
|
|
/// Create a new sample
|
|
pub fn new(data: Vec<f64>, timestamp: f64) -> Self {
|
|
Self { data, timestamp }
|
|
}
|
|
|
|
/// Get the number of channels
|
|
pub fn n_channels(&self) -> usize {
|
|
self.data.len()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_stream_info_creation() {
|
|
let info = LslStreamInfo::new("TestEEG", "EEG", 64, 500.0);
|
|
assert_eq!(info.name, "TestEEG");
|
|
assert_eq!(info.channel_count, 64);
|
|
assert_eq!(info.nominal_srate, 500.0);
|
|
assert!(info.is_eeg());
|
|
assert!(!info.is_meg());
|
|
}
|
|
|
|
#[test]
|
|
fn test_sample_size() {
|
|
let mut info = LslStreamInfo::new("Test", "EEG", 32, 256.0);
|
|
info.channel_format = ChannelFormat::Float32;
|
|
assert_eq!(info.sample_size(), 32 * 4);
|
|
|
|
info.channel_format = ChannelFormat::Float64;
|
|
assert_eq!(info.sample_size(), 32 * 8);
|
|
|
|
info.channel_format = ChannelFormat::Int16;
|
|
assert_eq!(info.sample_size(), 32 * 2);
|
|
}
|
|
}
|