start implementing vcp wrapper functions

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2020-04-23 12:49:58 +08:00
parent e3bacc1e32
commit 05230aa6c4
4 changed files with 59 additions and 20 deletions

View File

@ -1,11 +1,12 @@
use ftdi_vcp_sys::{
FT_Close, FT_GetBitMode, FT_GetComPortNumber, FT_OpenEx, FT_SetBitMode, FT_Write, DWORD,
FT_HANDLE, FT_OPEN_BY_DESCRIPTION, FT_STATUS, LONG, LPDWORD, LPVOID, PVOID, UCHAR,
FT_Close, FT_GetBitMode, FT_GetComPortNumber, FT_OpenEx, FT_Purge, FT_ResetDevice,
FT_SetBitMode, FT_Write, DWORD, FT_HANDLE, FT_OPEN_BY_DESCRIPTION, FT_STATUS, LONG, LPDWORD,
LPVOID, PVOID, UCHAR,
};
use std::convert::TryInto;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::io::{Read, Write};
use std::mem::MaybeUninit;
#[derive(Debug)]
pub enum BitMode {
@ -77,6 +78,10 @@ pub enum Error {
OtherError,
DeviceListNotReady,
NoComPortAssigned,
/// The provided string contained at least one NULL byte
StringContainsNullByte,
// UnknownBitMode(u8),
UnknownError(FT_STATUS),
}
@ -124,7 +129,7 @@ pub struct VCP {
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 c_str = CString::new(name).or(Err(Error::StringContainsNullByte))?;
let mut handle = MaybeUninit::<FT_HANDLE>::uninit();
let result = Error::from(unsafe {
FT_OpenEx(
@ -165,9 +170,30 @@ impl VCP {
}
/// Set the given signals to "OUTPUT". All other signals will be "INPUT".
pub fn set_bit_mode(&mut self, outputs: u8) -> Result<(), Error> {
pub fn set_bitmode(&mut self, outputs: u8, bitmode: BitMode) -> Result<(), Error> {
let result = Error::from(unsafe { FT_SetBitMode(self.handle, outputs, bitmode.to_u8()) });
if result != Error::NoError {
Err(result)
} else {
Ok(())
}
}
pub fn reset(&mut self) -> Result<(), Error> {
let result = Error::from(unsafe { FT_ResetDevice(self.handle) });
if result != Error::NoError {
Err(result)
} else {
Ok(())
}
}
pub fn purge(&mut self) -> Result<(), Error> {
let result = Error::from(unsafe {
FT_SetBitMode(self.handle, outputs, BitMode::SyncBitbang.to_u8())
FT_Purge(
self.handle,
ftdi_vcp_sys::FT_PURGE_RX | ftdi_vcp_sys::FT_PURGE_TX,
)
});
if result != Error::NoError {
Err(result)
@ -206,8 +232,7 @@ impl Write for VCP {
FT_Write(
self.handle,
buf.as_ptr() as LPVOID,
buf
.len()
buf.len()
.try_into()
.expect("couldn't convert buffer length to DWORD"),
bytes_written.as_mut_ptr() as LPDWORD,

View File

@ -1,6 +1,6 @@
/*++
Copyright © 2001-2011 Future Technology Devices International Limited
Copyright <EFBFBD> 2001-2011 Future Technology Devices International Limited
THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES

View File

@ -2,7 +2,7 @@
extern crate winapi;
// use winapi::um::winnt::{PVOID, ULONG, DWORD};
pub use winapi::shared::minwindef::{DWORD, LPDWORD, LPLONG, LPVOID, UCHAR, PUCHAR};
pub use winapi::shared::minwindef::{BOOL, DWORD, LPDWORD, LPLONG, LPVOID, PUCHAR, UCHAR};
pub use winapi::shared::ntdef::{LONG, PVOID, ULONG};
#[allow(non_camel_case_types)]
@ -54,13 +54,19 @@ pub enum FtStatus {
// FT_FLAGS_HISPEED = 2,
// }
//
// Purge rx and tx buffers
//
pub const FT_PURGE_RX: DWORD = 1;
pub const FT_PURGE_TX: DWORD = 2;
pub const FT_OPEN_BY_SERIAL_NUMBER: DWORD = 1;
pub const FT_OPEN_BY_DESCRIPTION: DWORD = 2;
pub const FT_OPEN_BY_LOCATION: DWORD = 4;
pub const FT_LIST_NUMBER_ONLY: DWORD = 0x80000000;
pub const FT_LIST_BY_INDEX: DWORD = 0x40000000;
pub const FT_LIST_ALL: DWORD = 0x20000000;
pub const FT_LIST_NUMBER_ONLY: DWORD = 0x8000_0000;
pub const FT_LIST_BY_INDEX: DWORD = 0x4000_0000;
pub const FT_LIST_ALL: DWORD = 0x2000_0000;
pub const FT_LIST_MASK: DWORD = (FT_LIST_NUMBER_ONLY | FT_LIST_BY_INDEX | FT_LIST_ALL);
@ -102,6 +108,11 @@ extern "stdcall" {
) -> FT_STATUS;
pub fn FT_SetBitMode(ftHandle: FT_HANDLE, ucMask: UCHAR, ucEnable: UCHAR) -> FT_STATUS;
pub fn FT_GetBitMode(ftHandle: FT_HANDLE, pucMode: PUCHAR) -> FT_STATUS;
pub fn FT_SetLatencyTimer(ftHandle: FT_HANDLE, ucLatency: UCHAR) -> FT_STATUS;
pub fn FT_GetLatencyTimer(ftHandle: FT_HANDLE, pucLatency: PUCHAR) -> FT_STATUS;
pub fn FT_ResetDevice(ftHandle: FT_HANDLE) -> FT_STATUS;
pub fn FT_Purge(ftHandle: FT_HANDLE, dwMask: ULONG) -> FT_STATUS;
pub fn FT_W32_PurgeComm(ftHandle: FT_HANDLE, dwMask: DWORD) -> BOOL;
}
pub fn create_device_info_list() -> Result<usize, usize> {
@ -165,7 +176,7 @@ mod tests {
for ch in item.Description.iter() {
print!(" {:02x}", ch);
}
println!("");
println!();
println!("ftHandle: {:08x}", item.ftHandle as usize);
}
}

View File

@ -6,21 +6,24 @@
#define FT_LIST_MASK (FT_LIST_NUMBER_ONLY|FT_LIST_BY_INDEX|FT_LIST_ALL)
*/
use ftdi_vcp_rs::VCP;
use ftdi_vcp_rs::{VCP, BitMode};
use std::thread::sleep;
use std::time::Duration;
fn main() {
fn main() -> Result<(), ftdi_vcp_rs::Error> {
let mut vcp = VCP::new_from_name("iCEBreaker V1.0e A").expect("couldn't open vcp");
println!("Opened VCP: {:?}", vcp);
vcp.set_bit_mode(0x80).expect("couldn't set bit mode");
vcp.reset()?;
vcp.set_bitmode(0x80, BitMode::SyncBitbang)?;
for i in 0..10 {
if i & 1 != 0 {
vcp.write(&[0x80]).expect("couldn't set all 1");
vcp.write(&[0x80])?;
} else {
vcp.write(&[0x00]).expect("couldn't set all 1");
vcp.write(&[0x00])?;
}
sleep(Duration::from_millis(500));
}
println!("VCP COM{}:", vcp.com_port().expect("couldn't get com port"));
println!("VCP COM{}:", vcp.com_port()?);
Ok(())
}