use std::io::Read;
use std::time::Duration;
use crate::error::NeuroSkyError;
use crate::parser::Parser;
use crate::types::*;
pub struct MindWaveDevice {
port: Box<dyn serialport::SerialPort>,
parser: Parser,
}
impl MindWaveDevice {
pub fn find() -> Result<Vec<String>, NeuroSkyError> {
let ports = serialport::available_ports()?;
let mut result: Vec<String> = ports.iter()
.filter(|p| match &p.port_type {
serialport::SerialPortType::UsbPort(info) =>
info.vid == 0x04D8 ||
info.product.as_ref()
.map(|s| s.contains("MindWave") || s.contains("NeuroSky"))
.unwrap_or(false),
_ => false,
})
.map(|p| p.port_name.clone())
.collect();
if result.is_empty() {
result = ports.iter().map(|p| p.port_name.clone()).collect();
}
Ok(result)
}
pub fn open(port_name: &str) -> Result<Self, NeuroSkyError> {
let port = serialport::new(port_name, 57600)
.timeout(Duration::from_millis(3000))
.open()?;
Ok(MindWaveDevice { port, parser: Parser::new() })
}
pub fn open_bluetooth(port_name: &str) -> Result<Self, NeuroSkyError> {
let port = serialport::new(port_name, 115200)
.timeout(Duration::from_millis(3000))
.open()?;
Ok(MindWaveDevice { port, parser: Parser::new() })
}
pub fn auto_connect(&mut self) -> Result<(), NeuroSkyError> {
use std::io::Write;
self.port.write_all(&[CMD_AUTOCONNECT])
.map_err(|e| NeuroSkyError::SerialPort(e.to_string()))
}
pub fn read(&mut self) -> Result<Vec<Packet>, NeuroSkyError> {
let mut buf = [0u8; 512];
match self.port.read(&mut buf) {
Ok(n) => Ok(self.parser.parse(&buf[..n])),
Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => Ok(Vec::new()),
Err(e) => Err(NeuroSkyError::SerialPort(e.to_string())),
}
}
pub fn read_blocking(&mut self) -> Result<Vec<Packet>, NeuroSkyError> {
loop {
let packets = self.read()?;
if !packets.is_empty() { return Ok(packets); }
}
}
pub fn close(self) { drop(self); }
}