Initial commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
//! 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user