ftdi-prog/ftdi-vcp-sys/src/lib.rs

214 lines
6.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::{BOOL, DWORD, LPDWORD, LPLONG, LPVOID, PUCHAR, UCHAR};
pub use winapi::shared::ntdef::{LONG, PVOID, ULONG};
#[allow(non_camel_case_types)]
pub type FT_HANDLE = PVOID;
#[allow(non_camel_case_types)]
pub 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,
// }
//
// 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 = 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);
#[link(name = "ftd2xx")]
#[allow(non_snake_case)]
#[allow(dead_code)]
extern "stdcall" {
pub fn FT_ListDevices(pArg1: PVOID, pArg2: PVOID, Flags: DWORD) -> FT_STATUS;
pub fn FT_CreateDeviceInfoList(lpdwNumDevs: LPDWORD) -> FT_STATUS;
pub fn FT_GetDeviceInfoList(
pDest: *mut FT_DEVICE_LIST_INFO_NODE,
lpdwNumDevs: LPDWORD,
) -> FT_STATUS;
pub fn FT_GetDeviceInfoDetail(
dwIndex: DWORD,
lpdwFlags: LPDWORD,
lpdwType: LPDWORD,
lpdwID: LPDWORD,
lpdwLocId: LPDWORD,
lpSerialNumber: LPVOID,
lpDescription: LPVOID,
pftHandle: *mut FT_HANDLE,
) -> FT_STATUS;
pub fn FT_GetComPortNumber(ftHandle: FT_HANDLE, lpdwComPortNumber: LPLONG) -> FT_STATUS;
pub fn FT_Open(deviceNumber: u32, pHandle: *mut FT_HANDLE) -> FT_STATUS;
pub fn FT_OpenEx(pArg1: PVOID, Flags: DWORD, pHandle: *mut FT_HANDLE) -> FT_STATUS;
pub fn FT_Close(ftHandle: FT_HANDLE) -> FT_STATUS;
pub fn FT_Write(
ftHandle: FT_HANDLE,
lpBuffer: LPVOID,
dwBytesToWrite: DWORD,
lpBytesWritten: LPDWORD,
) -> FT_STATUS;
pub fn FT_Read(
ftHandle: FT_HANDLE,
lpBuffer: LPVOID,
dwBytesToRead: DWORD,
lpBytesReturned: LPDWORD,
) -> 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> {
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"iCEBreaker V1.0e 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");
}
}
}