189 lines
5.8 KiB
Rust
189 lines
5.8 KiB
Rust
#![allow(non_camel_case_types, non_snake_case)]
|
|
|
|
extern crate winapi;
|
|
// use winapi::um::winnt::{PVOID, ULONG, DWORD};
|
|
pub use winapi::shared::minwindef::{DWORD, LPDWORD, LPLONG, LPVOID};
|
|
pub use winapi::shared::ntdef::{PVOID, ULONG, LONG};
|
|
|
|
#[allow(non_camel_case_types)]
|
|
type FT_HANDLE = PVOID;
|
|
#[allow(non_camel_case_types)]
|
|
type FT_STATUS = ULONG;
|
|
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(C)]
|
|
#[derive(Clone)]
|
|
pub struct FT_DEVICE_LIST_INFO_NODE {
|
|
Flags: ULONG,
|
|
Type: ULONG,
|
|
ID: ULONG,
|
|
LocId: DWORD,
|
|
SerialNumber: [u8; 16],
|
|
Description: [u8; 64],
|
|
ftHandle: FT_HANDLE,
|
|
}
|
|
|
|
#[repr(C)]
|
|
pub enum FtStatus {
|
|
FT_OK = 0,
|
|
FT_INVALID_HANDLE = 1,
|
|
FT_DEVICE_NOT_FOUND = 2,
|
|
FT_DEVICE_NOT_OPENED = 3,
|
|
FT_IO_ERROR = 4,
|
|
FT_INSUFFICIENT_RESOURCES = 5,
|
|
FT_INVALID_PARAMETER = 6,
|
|
FT_INVALID_BAUD_RATE = 7,
|
|
|
|
FT_DEVICE_NOT_OPENED_FOR_ERASE = 8,
|
|
FT_DEVICE_NOT_OPENED_FOR_WRITE = 9,
|
|
FT_FAILED_TO_WRITE_DEVICE = 10,
|
|
FT_EEPROM_READ_FAILED = 11,
|
|
FT_EEPROM_WRITE_FAILED = 12,
|
|
FT_EEPROM_ERASE_FAILED = 13,
|
|
FT_EEPROM_NOT_PRESENT = 14,
|
|
FT_EEPROM_NOT_PROGRAMMED = 15,
|
|
FT_INVALID_ARGS = 16,
|
|
FT_NOT_SUPPORTED = 17,
|
|
FT_OTHER_ERROR = 18,
|
|
FT_DEVICE_LIST_NOT_READY = 19,
|
|
}
|
|
|
|
// // Device information flags
|
|
// enum FT_FLAGS {
|
|
// FT_FLAGS_OPENED = 1,
|
|
// FT_FLAGS_HISPEED = 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_MASK: DWORD = (FT_LIST_NUMBER_ONLY | FT_LIST_BY_INDEX | FT_LIST_ALL);
|
|
|
|
#[link(name = "ftd2xx")]
|
|
#[allow(non_snake_case)]
|
|
#[allow(dead_code)]
|
|
extern "stdcall" {
|
|
fn FT_ListDevices(pArg1: PVOID, pArg2: PVOID, Flags: DWORD) -> FT_STATUS;
|
|
fn FT_CreateDeviceInfoList(lpdwNumDevs: LPDWORD) -> FT_STATUS;
|
|
fn FT_GetDeviceInfoList(
|
|
pDest: *mut FT_DEVICE_LIST_INFO_NODE,
|
|
lpdwNumDevs: LPDWORD,
|
|
) -> FT_STATUS;
|
|
fn FT_GetDeviceInfoDetail(
|
|
dwIndex: DWORD,
|
|
lpdwFlags: LPDWORD,
|
|
lpdwType: LPDWORD,
|
|
lpdwID: LPDWORD,
|
|
lpdwLocId: LPDWORD,
|
|
lpSerialNumber: LPVOID,
|
|
lpDescription: LPVOID,
|
|
pftHandle: *mut FT_HANDLE,
|
|
) -> FT_STATUS;
|
|
fn FT_GetComPortNumber(ftHandle: FT_HANDLE, lpdwComPortNumber: LPLONG) -> FT_STATUS;
|
|
fn FT_Open(deviceNumber: u32, pHandle: *mut FT_HANDLE) -> FT_STATUS;
|
|
fn FT_OpenEx(pArg1: PVOID, Flags: DWORD, pHandle: *mut FT_HANDLE) -> FT_STATUS;
|
|
fn FT_Close(ftHandle: FT_HANDLE) -> FT_STATUS;
|
|
}
|
|
|
|
pub fn create_device_info_list() -> Result<usize, usize> {
|
|
let device_count: DWORD = 0;
|
|
let result = unsafe { FT_CreateDeviceInfoList(&device_count as *const _ as LPDWORD) };
|
|
if result == 0 {
|
|
Ok(device_count as usize)
|
|
} else {
|
|
Err(result as usize)
|
|
}
|
|
}
|
|
|
|
pub fn get_device_info_list() -> Result<Vec<FT_DEVICE_LIST_INFO_NODE>, usize> {
|
|
let mut dev_info = vec![];
|
|
|
|
let device_count = create_device_info_list()?;
|
|
dev_info.resize(
|
|
device_count as usize,
|
|
FT_DEVICE_LIST_INFO_NODE {
|
|
Flags: 0,
|
|
Type: 0,
|
|
ID: 0,
|
|
LocId: 0,
|
|
SerialNumber: [0; 16],
|
|
Description: [0; 64],
|
|
ftHandle: 0 as FT_HANDLE,
|
|
},
|
|
);
|
|
let result = unsafe {
|
|
FT_GetDeviceInfoList(dev_info.as_mut_ptr(), &device_count as *const _ as LPDWORD)
|
|
};
|
|
if result != 0 {
|
|
return Err(result as usize);
|
|
}
|
|
Ok(dev_info)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::*;
|
|
use std::ffi::CStr;
|
|
#[test]
|
|
fn list_devices() {
|
|
println!("Listing devices...");
|
|
let device_count = create_device_info_list().expect("couldn't list devices");
|
|
// let result = unsafe { FT_ListDevices(&device_count as *const i32 as PVOID, 0 as PVOID, FT_LIST_NUMBER_ONLY) };
|
|
println!("There are {} devices", device_count);
|
|
|
|
let dev_info = get_device_info_list().expect("couldn't get device info list");
|
|
for item in dev_info {
|
|
println!("Flags: {:08x}", item.Flags);
|
|
println!("Type: {:08x}", item.Type);
|
|
println!("ID: {:08x}", item.ID);
|
|
println!("LocId: {:08x}", item.LocId);
|
|
println!("SerialNumber: {:?}", item.SerialNumber);
|
|
// let description = CStr::from_bytes_with_nul(&item.Description).expect("couldn't parse item string");
|
|
let p = &item.Description as *const u8 as *const i8;
|
|
let description = unsafe { CStr::from_ptr(p) };
|
|
println!("Description: {}", description.to_string_lossy()); //String::from_utf8_lossy(&item.Description));
|
|
print!(" ");
|
|
for ch in item.Description.iter() {
|
|
print!(" {:02x}", ch);
|
|
}
|
|
println!("");
|
|
println!("ftHandle: {:08x}", item.ftHandle as usize);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn open_device() {
|
|
let desc = b"Lattice FTUSB Interface Cable B\0";
|
|
let mut handle = 0 as FT_HANDLE;
|
|
let result = unsafe {
|
|
FT_OpenEx(
|
|
desc.as_ptr() as PVOID,
|
|
FT_OPEN_BY_DESCRIPTION,
|
|
(&mut handle) as *mut FT_HANDLE,
|
|
)
|
|
};
|
|
println!("Result: {}", result);
|
|
if result != 0 {
|
|
panic!("couldn't open handle: result not 0");
|
|
}
|
|
|
|
let mut com_port_number: LONG = 0;
|
|
let result = unsafe { FT_GetComPortNumber(handle, &mut com_port_number) };
|
|
if result != 0 {
|
|
panic!("couldn't get com port number");
|
|
}
|
|
println!("Device opened on COM{}:", com_port_number);
|
|
|
|
let result = unsafe { FT_Close(handle) };
|
|
println!("Result: {}", result);
|
|
if result != 0 {
|
|
panic!("couldn't close handle: result not 0");
|
|
}
|
|
}
|
|
}
|