messy commit: start implementing ftdi-vcp-rs
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
37
ftdi-vcp-rs/Cargo.lock
generated
Normal file
37
ftdi-vcp-rs/Cargo.lock
generated
Normal file
@ -0,0 +1,37 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ftdi-vcp-rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ftdi-vcp-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ftdi-vcp-sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
10
ftdi-vcp-rs/Cargo.toml
Normal file
10
ftdi-vcp-rs/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "ftdi-vcp-rs"
|
||||
version = "0.1.0"
|
||||
authors = ["Sean Cross <sean@xobs.io>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
ftdi-vcp-sys = { path = "../ftdi-vcp-sys" }
|
120
ftdi-vcp-rs/src/lib.rs
Normal file
120
ftdi-vcp-rs/src/lib.rs
Normal file
@ -0,0 +1,120 @@
|
||||
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<FT_STATUS> 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<VCP, Error> {
|
||||
let c_str = CString::new(name).expect("string already contained null bytes");
|
||||
let mut handle = MaybeUninit::<FT_HANDLE>::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<usize, Error> {
|
||||
let mut com_port_number = MaybeUninit::<LONG>::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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user