/** Example program that shows several advanced capabilities when reading data. */ use lsl; use lsl::Pullable; // trait used by the inlet // for user input use std::io; use std::vec; fn main() -> Result<(), lsl::Error> { println!("Resolving EEG stream..."); // First we're resolving a stream that matches a given predicate (see function documentation). // You're not limited to the default meta-data here but can query against anything under desc/ // Some applications may use a finite timeout, e.g., 30 seconds, and some may also use a short // 2-3s timeout (assuming that the stream is already present), but allow more than one return // value and then to warn the user if there were multiple matching streams present. let res = lsl::resolve_bypred("name='BioSemi' and type='EEG'", 1, lsl::FOREVER)?; // Next we're creating an inlet to read from it. Let's say this is a real-time processing tool, // and we have no use for more than 10 seconds of data backlog accumulating in case our program // stalls for a while, so we set the max buffer length to 10s. We'll also ask that the data be // transmitted in chunks of 20 samples at a time, e.g., to save network bandwidth. let inl = lsl::StreamInlet::new(&res[0], 10, 8, true)?; // now that we have the inlet we can use it to retrieve the full StreamInfo object from it // (since custom meta-data could in theory be gigabytes, this is not transmitted by the resolve // call) let mut info = inl.info(5.0)?; // we can now traverse the extended meta-data of the stream to get the information we need // (usually we'll want at least the channel labels, which are typically stored as below) println!("\nThe channel labels were:"); let mut cursor = info.desc().child("channels").child("channel"); while cursor.is_valid() { print!(" {}", cursor.child_value_named("label")); cursor = cursor.next_sibling(); } // ... alternatively we could get an XML string and parse it using some other crate println!("\n\nThe StreamInfo's full XML dump is: {}", info.to_xml()?); println!("Press [Enter] to continue"); let mut ret = String::new(); io::stdin().read_line(&mut ret).expect("stdin read error"); // let's also suppose that we want to sync the received data's time stamps with our local_clock(), // e.g., to relate the data to some local events. We can enable that via post-processing, but // see also the inlet's time_correction() method for the manual way that gives you full control inl.set_postprocessing(&[ lsl::ProcessingOption::ClockSync, lsl::ProcessingOption::Dejitter, ])?; // now we're reading data in a loop and print it as we go println!("Reading data..."); let mut sample = vec::Vec::::new(); loop { // do a blocking read (with finite timeout) to get the next successive sample and its // time stamp; we read into a pre-allocated buffer (which will be right-sized by the pull // call) since that's more efficient for high-bandwidth data. let ts = inl.pull_sample_buf(&mut sample, 5.0)?; // if we're using a finite timeout we need to check if the timestamp is nonzero (zero means // no new data) if ts != 0.0 { println!("got {:?} at time {}", sample, ts); } else { println!("got no new data, waiting some more...") } } }