use std::{error::Error, fmt, fmt::Formatter, mem::MaybeUninit, os::raw::c_char, time::Duration};
use si_usb_xp::*;
#[allow(dead_code)]
mod si_usb_xp {
include!("bindings.rs");
}
pub fn devices_count() -> Result<usize, SilabsUsbXpressError> {
let (status, num) = unsafe {
let mut num = MaybeUninit::uninit();
let status = SI_GetNumDevices(num.as_mut_ptr());
(status, num.assume_init())
};
match status as u32 {
SI_SUCCESS => Ok(num as usize),
SI_DEVICE_NOT_FOUND => Err(SilabsUsbXpressError::DeviceNotFound),
_ => unreachable!(),
}
}
#[derive(Copy, Clone, Debug)]
pub enum ProductStringType {
SerialNumber = 0,
Description = 1,
LinkName = 2,
VID = 3,
PID = 4,
}
pub fn product_string(
device_ix: usize,
product_string_type: ProductStringType,
) -> Result<String, SilabsUsbXpressError> {
let mut buffer: [c_char; 256] = [0; 256];
let status = unsafe {
SI_GetProductString(
device_ix as i32,
buffer.as_mut_ptr(),
product_string_type as i32,
)
};
match status as u32 {
SI_SUCCESS => {
let mut string = String::from_utf8(buffer.iter().map(|&c| c as u8).collect())
.unwrap()
.trim_end_matches("\0")
.to_owned();
match product_string_type {
ProductStringType::PID | ProductStringType::VID => {
if string.len() < 4 {
for _ in 0..4 - string.len() {
string.insert(0, '0');
}
}
Ok(string.to_uppercase())
}
_ => Ok(string),
}
}
SI_DEVICE_NOT_FOUND => Err(SilabsUsbXpressError::DeviceNotFound),
_ => unreachable!(),
}
}
pub struct UsbXpress {
inner: *mut SiPrivate,
device_ix: usize,
}
impl UsbXpress {
pub fn open(device_ix: usize) -> Result<Self, SilabsUsbXpressError> {
let mut handle: MaybeUninit<*mut SiPrivate> = MaybeUninit::uninit();
let (status, handle) = unsafe {
let status = SI_Open(device_ix as i32, handle.as_mut_ptr());
(status, handle.assume_init())
};
match status as u32 {
SI_SUCCESS => Ok(UsbXpress {
inner: handle,
device_ix: device_ix,
}),
SI_SYSTEM_ERROR_CODE => Err(SilabsUsbXpressError::SystemErrorCode),
SI_GLOBAL_DATA_ERROR => Err(SilabsUsbXpressError::GlobalDataError),
_ => unreachable!(),
}
}
pub fn close(self) -> Result<(), SilabsUsbXpressError> {
let status = unsafe { SI_Close(self.inner) };
match status as u32 {
SI_SUCCESS => Ok(()),
SI_SYSTEM_ERROR_CODE => Err(SilabsUsbXpressError::SystemErrorCode),
SI_GLOBAL_DATA_ERROR => Err(SilabsUsbXpressError::GlobalDataError),
_ => unreachable!(),
}
}
pub fn read(&mut self, bytes_to_read: usize) -> Result<Vec<u8>, SilabsUsbXpressError> {
let mut buffer = Vec::with_capacity(bytes_to_read);
let status = unsafe {
let mut bytes_returned = MaybeUninit::uninit();
let status = SI_Read(
self.inner,
buffer.as_mut_slice().as_mut_ptr(),
bytes_to_read as i32,
bytes_returned.as_mut_ptr(),
MaybeUninit::uninit().as_mut_ptr(),
);
buffer.set_len(bytes_returned.assume_init() as usize);
status
};
match status as u32 {
SI_SUCCESS => Ok(buffer.iter().map(|&c| c as u8).collect()),
SI_READ_ERROR => Err(SilabsUsbXpressError::ReadError),
SI_READ_TIMED_OUT => Err(SilabsUsbXpressError::ReadTimeOut),
SI_IO_PENDING => Err(SilabsUsbXpressError::IoPending),
SI_SYSTEM_ERROR_CODE => Err(SilabsUsbXpressError::SystemErrorCode),
SI_INVALID_REQUEST_LENGTH => Err(SilabsUsbXpressError::InvalidRequestLength),
SI_DEVICE_IO_FAILED => Err(SilabsUsbXpressError::DeviceIoFailed),
_ => unreachable!(),
}
}
pub fn write(&mut self, to_write: &Vec<u8>) -> Result<usize, SilabsUsbXpressError> {
let mut buffer: Vec<c_char> = to_write.iter().map(|&c| c as c_char).collect();
let (status, bytes_written) = unsafe {
let mut bytes_written = MaybeUninit::uninit();
let status = SI_Write(
self.inner,
buffer.as_mut_ptr(),
to_write.len() as i32,
bytes_written.as_mut_ptr(),
MaybeUninit::uninit().as_mut_ptr(),
);
(status, bytes_written.assume_init())
};
match status as u32 {
SI_SUCCESS => Ok(bytes_written as usize),
SI_WRITE_ERROR => Err(SilabsUsbXpressError::WriteError),
SI_INVALID_REQUEST_LENGTH => Err(SilabsUsbXpressError::InvalidRequestLength),
SI_WRITE_TIMED_OUT => Err(SilabsUsbXpressError::WriteTimeOut),
SI_IO_PENDING => Err(SilabsUsbXpressError::IoPending),
SI_SYSTEM_ERROR_CODE => Err(SilabsUsbXpressError::SystemErrorCode),
SI_DEVICE_IO_FAILED => Err(SilabsUsbXpressError::DeviceIoFailed),
_ => unreachable!(),
}
}
pub fn device_io_control() {
unimplemented!()
}
pub fn flush_buffers(&mut self) -> Result<(), SilabsUsbXpressError> {
let status = unsafe { SI_FlushBuffers(self.inner, 1 as c_char, 1 as c_char) };
match status as u32 {
SI_SUCCESS => Ok(()),
SI_SYSTEM_ERROR_CODE => Err(SilabsUsbXpressError::SystemErrorCode),
_ => unreachable!(),
}
}
pub fn check_rx_queue(&mut self) -> Result<(usize, usize), SilabsUsbXpressError> {
let (status, num_bytes_in_queue, queue_status) = unsafe {
let mut num_bytes_in_queue = MaybeUninit::uninit();
let mut queue_status = MaybeUninit::uninit();
let status = SI_CheckRXQueue(
self.inner,
num_bytes_in_queue.as_mut_ptr(),
queue_status.as_mut_ptr(),
);
(
status,
num_bytes_in_queue.assume_init(),
queue_status.assume_init(),
)
};
match status as u32 {
SI_SUCCESS => Ok((num_bytes_in_queue as usize, queue_status as usize)),
SI_DEVICE_IO_FAILED => Err(SilabsUsbXpressError::DeviceIoFailed),
_ => unreachable!(),
}
}
}
impl fmt::Debug for UsbXpress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SiHandle")
.field("device_ix", &self.device_ix)
.finish()
}
}
pub fn set_timeouts<R: Into<Option<Duration>>, W: Into<Option<Duration>>>(
read: R,
write: W,
) -> Result<(), SilabsUsbXpressError> {
let status = unsafe {
SI_SetTimeouts(
read.into().unwrap_or(Duration::from_secs(1)).as_millis() as i32,
write.into().unwrap_or(Duration::from_secs(1)).as_millis() as i32,
)
};
match status as u32 {
SI_SUCCESS => Ok(()),
SI_DEVICE_IO_FAILED => Err(SilabsUsbXpressError::DeviceIoFailed),
_ => unreachable!(),
}
}
#[derive(Debug)]
pub struct Timeout {
read: Duration,
write: Duration,
}
impl Timeout {
pub fn read_timeout(&self) -> Duration {
self.read
}
pub fn write_timeout(&self) -> Duration {
self.write
}
}
pub fn timeouts() -> Result<Timeout, SilabsUsbXpressError> {
let (status, read, write) = unsafe {
let mut read = MaybeUninit::uninit();
let mut write = MaybeUninit::uninit();
let status = SI_GetTimeouts(read.as_mut_ptr(), write.as_mut_ptr());
(status, read.assume_init(), write.assume_init())
};
match status as u32 {
SI_SUCCESS => Ok(Timeout {
read: Duration::from_millis(read as u64),
write: Duration::from_millis(write as u64),
}),
SI_DEVICE_IO_FAILED => Err(SilabsUsbXpressError::DeviceIoFailed),
_ => unreachable!(),
}
}
#[derive(Debug)]
pub enum SilabsUsbXpressError {
ConnectionError,
DeviceNotFound,
SystemErrorCode,
GlobalDataError,
ReadError,
ReadTimeOut,
IoPending,
InvalidRequestLength,
DeviceIoFailed,
WriteError,
WriteTimeOut,
}
impl fmt::Display for SilabsUsbXpressError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(&format!("{:?}", self))
}
}
impl Error for SilabsUsbXpressError {}