From 05230aa6c40349928172faa7ad13853b8c338a5b Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Thu, 23 Apr 2020 12:49:58 +0800 Subject: [PATCH] start implementing vcp wrapper functions Signed-off-by: Sean Cross --- ftdi-vcp-rs/src/lib.rs | 41 +++++++++++++++++++++------ ftdi-vcp-sys/lib/vcp-2.12.28/ftd2xx.h | 2 +- ftdi-vcp-sys/src/lib.rs | 21 ++++++++++---- src/main.rs | 15 ++++++---- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/ftdi-vcp-rs/src/lib.rs b/ftdi-vcp-rs/src/lib.rs index d3128d4..90e252f 100644 --- a/ftdi-vcp-rs/src/lib.rs +++ b/ftdi-vcp-rs/src/lib.rs @@ -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 { - 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::::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, diff --git a/ftdi-vcp-sys/lib/vcp-2.12.28/ftd2xx.h b/ftdi-vcp-sys/lib/vcp-2.12.28/ftd2xx.h index ec02ac6..32ace39 100644 --- a/ftdi-vcp-sys/lib/vcp-2.12.28/ftd2xx.h +++ b/ftdi-vcp-sys/lib/vcp-2.12.28/ftd2xx.h @@ -1,6 +1,6 @@ /*++ -Copyright © 2001-2011 Future Technology Devices International Limited +Copyright � 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 diff --git a/ftdi-vcp-sys/src/lib.rs b/ftdi-vcp-sys/src/lib.rs index 94b36c6..d02029a 100644 --- a/ftdi-vcp-sys/src/lib.rs +++ b/ftdi-vcp-sys/src/lib.rs @@ -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 { @@ -165,7 +176,7 @@ mod tests { for ch in item.Description.iter() { print!(" {:02x}", ch); } - println!(""); + println!(); println!("ftHandle: {:08x}", item.ftHandle as usize); } } diff --git a/src/main.rs b/src/main.rs index ddf07b7..fe35d79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(()) }