use ftdi_vcp_sys::{ FT_Close, FT_GetComPortNumber, FT_OpenEx, FT_HANDLE, FT_OPEN_BY_DESCRIPTION, FT_STATUS, LONG, PVOID, }; use std::ffi::CString; use std::mem::MaybeUninit; use std::convert::TryInto; #[derive(PartialEq, Debug)] pub enum Error { NoError, InvalidHandle, DeviceNotFound, DeviceNotOpened, IoError, InsufficientResources, InvalidParameter, InvalidBaudRate, DeviceNotOpenedForErase, DeviceNotOpenedForWrite, FailedToWriteDevice, EepromReadFailed, EepromWriteFailed, EepromEraseFailed, EepromNotPresent, EepromNotProgrammed, InvalidArgs, NotSupported, OtherError, DeviceListNotReady, NoComPortAssigned, UnknownError(FT_STATUS), } impl From for Error { fn from(src: FT_STATUS) -> Self { match src { 0 => Error::NoError, 1 => Error::InvalidHandle, 2 => Error::DeviceNotFound, 3 => Error::DeviceNotOpened, 4 => Error::IoError, 5 => Error::InsufficientResources, 6 => Error::InvalidParameter, 7 => Error::InvalidBaudRate, 8 => Error::DeviceNotOpenedForErase, 9 => Error::DeviceNotOpenedForWrite, 10 => Error::FailedToWriteDevice, 11 => Error::EepromReadFailed, 12 => Error::EepromWriteFailed, 13 => Error::EepromEraseFailed, 14 => Error::EepromNotPresent, 15 => Error::EepromNotProgrammed, 16 => Error::InvalidArgs, 17 => Error::NotSupported, 18 => Error::OtherError, 19 => Error::DeviceListNotReady, x => Error::UnknownError(x), } } } pub struct VCP { handle: FT_HANDLE, } impl VCP { pub fn new_from_name(name: &str) -> Result { let c_str = CString::new(name).expect("string already contained null bytes"); let mut handle = MaybeUninit::::uninit(); let result = Error::from(unsafe { FT_OpenEx( c_str.as_ptr() as PVOID, FT_OPEN_BY_DESCRIPTION, handle.as_mut_ptr(), ) }); if result != Error::NoError { Err(result) } else { Ok(VCP { handle: unsafe { handle.assume_init() }, }) } } pub fn com_port(&self) -> Result { let mut com_port_number = MaybeUninit::::uninit(); let result = Error::from(unsafe { FT_GetComPortNumber(self.handle, com_port_number.as_mut_ptr()) }); if result != Error::NoError { Err(result) } else { let com_port_number = unsafe { com_port_number.assume_init() }; if let Ok(e) = com_port_number.try_into() { Ok(e) } else { Err(Error::NoComPortAssigned) } } } } impl Drop for VCP { fn drop(&mut self) { let result = Error::from(unsafe { FT_Close(self.handle) }); if result != Error::NoError { panic!("unable to close device: {:?}", result); } } } #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } }