use std::fmt;
pub const UNICORN_SAMPLING_RATE: u32 = 250;
pub const UNICORN_EEG_CHANNELS_COUNT: usize = 8;
pub const UNICORN_ACCELEROMETER_CHANNELS_COUNT: usize = 3;
pub const UNICORN_GYROSCOPE_CHANNELS_COUNT: usize = 3;
pub const UNICORN_TOTAL_CHANNELS_COUNT: usize = 17;
pub const UNICORN_EEG_CONFIG_INDEX: usize = 0;
pub const UNICORN_ACCELEROMETER_CONFIG_INDEX: usize = 8;
pub const UNICORN_GYROSCOPE_CONFIG_INDEX: usize = 11;
pub const UNICORN_BATTERY_CONFIG_INDEX: usize = 14;
pub const UNICORN_COUNTER_CONFIG_INDEX: usize = 15;
pub const UNICORN_VALIDATION_CONFIG_INDEX: usize = 16;
pub const UNICORN_SERIAL_LENGTH_MAX: usize = 14;
pub const UNICORN_DEVICE_VERSION_LENGTH_MAX: usize = 6;
pub const UNICORN_FIRMWARE_VERSION_LENGTH_MAX: usize = 12;
pub const UNICORN_STRING_LENGTH_MAX: usize = 255;
pub const UNICORN_NUMBER_OF_DIGITAL_OUTPUTS: usize = 8;
pub const UNICORN_SUPPORTED_DEVICE_VERSION: &str = "1.";
pub const UNICORN_ERROR_SUCCESS: i32 = 0;
pub const UNICORN_ERROR_INVALID_PARAMETER: i32 = 1;
pub const UNICORN_ERROR_BLUETOOTH_INIT_FAILED: i32 = 2;
pub const UNICORN_ERROR_BLUETOOTH_SOCKET_FAILED: i32 = 3;
pub const UNICORN_ERROR_OPEN_DEVICE_FAILED: i32 = 4;
pub const UNICORN_ERROR_INVALID_CONFIGURATION: i32 = 5;
pub const UNICORN_ERROR_BUFFER_OVERFLOW: i32 = 6;
pub const UNICORN_ERROR_BUFFER_UNDERFLOW: i32 = 7;
pub const UNICORN_ERROR_OPERATION_NOT_ALLOWED: i32 = 8;
pub const UNICORN_ERROR_CONNECTION_PROBLEM: i32 = 9;
pub const UNICORN_ERROR_UNSUPPORTED_DEVICE: i32 = 10;
pub const UNICORN_ERROR_INVALID_HANDLE: i32 = 0xFFFFFFFEu32 as i32;
pub const UNICORN_ERROR_GENERAL_ERROR: i32 = 0xFFFFFFFFu32 as i32;
pub fn error_name(code: i32) -> &'static str {
match code {
UNICORN_ERROR_SUCCESS => "Success",
UNICORN_ERROR_INVALID_PARAMETER => "Invalid parameter",
UNICORN_ERROR_BLUETOOTH_INIT_FAILED => "Bluetooth init failed",
UNICORN_ERROR_BLUETOOTH_SOCKET_FAILED => "Bluetooth socket failed",
UNICORN_ERROR_OPEN_DEVICE_FAILED => "Open device failed",
UNICORN_ERROR_INVALID_CONFIGURATION => "Invalid configuration",
UNICORN_ERROR_BUFFER_OVERFLOW => "Buffer overflow",
UNICORN_ERROR_BUFFER_UNDERFLOW => "Buffer underflow",
UNICORN_ERROR_OPERATION_NOT_ALLOWED => "Operation not allowed",
UNICORN_ERROR_CONNECTION_PROBLEM => "Connection problem",
UNICORN_ERROR_UNSUPPORTED_DEVICE => "Unsupported device",
UNICORN_ERROR_INVALID_HANDLE => "Invalid handle",
UNICORN_ERROR_GENERAL_ERROR => "General error",
_ => "Unknown error",
}
}
pub type UnicornHandle = u64;
pub type UnicornDeviceSerial = [u8; UNICORN_SERIAL_LENGTH_MAX];
pub type UnicornDeviceVersion = [u8; UNICORN_DEVICE_VERSION_LENGTH_MAX];
pub type UnicornFirmwareVersion = [u8; UNICORN_FIRMWARE_VERSION_LENGTH_MAX];
pub type UnicornBool = i32;
#[repr(C)]
#[derive(Clone)]
pub struct UnicornAmplifierChannel {
pub name: [u8; 32],
pub unit: [u8; 32],
pub range: [f32; 2],
pub enabled: UnicornBool,
}
impl UnicornAmplifierChannel {
pub fn name_str(&self) -> String {
let nul = self.name.iter().position(|&b| b == 0).unwrap_or(32);
String::from_utf8_lossy(&self.name[..nul]).into_owned()
}
pub fn unit_str(&self) -> String {
let nul = self.unit.iter().position(|&b| b == 0).unwrap_or(32);
String::from_utf8_lossy(&self.unit[..nul]).into_owned()
}
pub fn is_enabled(&self) -> bool {
self.enabled != 0
}
}
impl fmt::Debug for UnicornAmplifierChannel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AmplifierChannel")
.field("name", &self.name_str())
.field("unit", &self.unit_str())
.field("range", &self.range)
.field("enabled", &self.is_enabled())
.finish()
}
}
#[repr(C)]
#[derive(Clone)]
pub struct UnicornAmplifierConfiguration {
pub channels: [UnicornAmplifierChannel; UNICORN_TOTAL_CHANNELS_COUNT],
}
impl fmt::Debug for UnicornAmplifierConfiguration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AmplifierConfiguration")
.field("channels", &self.channels.iter().map(|c| c.name_str()).collect::<Vec<_>>())
.finish()
}
}
#[repr(C)]
#[derive(Clone)]
pub struct UnicornDeviceInformation {
pub number_of_eeg_channels: u16,
pub serial: UnicornDeviceSerial,
pub firmware_version: UnicornFirmwareVersion,
pub device_version: UnicornDeviceVersion,
pub pcb_version: [u8; 4],
pub enclosure_version: [u8; 4],
}
impl UnicornDeviceInformation {
fn buf_to_string(buf: &[u8]) -> String {
let nul = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
String::from_utf8_lossy(&buf[..nul]).into_owned()
}
pub fn serial_str(&self) -> String {
Self::buf_to_string(&self.serial)
}
pub fn firmware_version_str(&self) -> String {
Self::buf_to_string(&self.firmware_version)
}
pub fn device_version_str(&self) -> String {
Self::buf_to_string(&self.device_version)
}
}
impl fmt::Debug for UnicornDeviceInformation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DeviceInformation")
.field("eeg_channels", &self.number_of_eeg_channels)
.field("serial", &self.serial_str())
.field("firmware", &self.firmware_version_str())
.field("device_version", &self.device_version_str())
.field("pcb_version", &self.pcb_version)
.field("enclosure_version", &self.enclosure_version)
.finish()
}
}
#[repr(C)]
#[derive(Clone)]
pub struct UnicornBluetoothAdapterInfo {
pub name: [u8; UNICORN_STRING_LENGTH_MAX],
pub manufacturer: [u8; UNICORN_STRING_LENGTH_MAX],
pub is_recommended_device: UnicornBool,
pub has_problem: UnicornBool,
}
impl UnicornBluetoothAdapterInfo {
pub fn name_str(&self) -> String {
let nul = self.name.iter().position(|&b| b == 0).unwrap_or(UNICORN_STRING_LENGTH_MAX);
String::from_utf8_lossy(&self.name[..nul]).into_owned()
}
pub fn manufacturer_str(&self) -> String {
let nul = self.manufacturer.iter().position(|&b| b == 0).unwrap_or(UNICORN_STRING_LENGTH_MAX);
String::from_utf8_lossy(&self.manufacturer[..nul]).into_owned()
}
}
impl fmt::Debug for UnicornBluetoothAdapterInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BluetoothAdapterInfo")
.field("name", &self.name_str())
.field("manufacturer", &self.manufacturer_str())
.field("is_recommended", &(self.is_recommended_device != 0))
.field("has_problem", &(self.has_problem != 0))
.finish()
}
}
pub const EEG_CHANNEL_NAMES: [&str; UNICORN_EEG_CHANNELS_COUNT] = [
"EEG 1", "EEG 2", "EEG 3", "EEG 4",
"EEG 5", "EEG 6", "EEG 7", "EEG 8",
];
pub const ALL_CHANNEL_NAMES: [&str; UNICORN_TOTAL_CHANNELS_COUNT] = [
"EEG 1", "EEG 2", "EEG 3", "EEG 4",
"EEG 5", "EEG 6", "EEG 7", "EEG 8",
"Accelerometer X", "Accelerometer Y", "Accelerometer Z",
"Gyroscope X", "Gyroscope Y", "Gyroscope Z",
"Battery Level",
"Counter",
"Validation Indicator",
];