From 4521068708382d205016a342f5a2b12882f42bbd Mon Sep 17 00:00:00 2001 From: Kiran Shila Date: Wed, 14 Aug 2024 16:48:30 -0700 Subject: [PATCH] feat: Add support for 4232HA Co-authored-by: Alex Martens --- CHANGELOG.md | 4 +++ src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/mpsse.rs | 17 ++++++++-- src/types.rs | 8 +++-- 4 files changed, 105 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af9dad1..f54c9b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] +### Added +- Added support for the 4232HA + ## [0.32.4] - 2024-03-04 ### Added - Added EEPROM implementations for the 232R. diff --git a/src/lib.rs b/src/lib.rs index 8606807..65403d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -341,7 +341,7 @@ pub fn list_devices() -> Result, FtStatus> { /// Lists FTDI devices using the Linux file system. /// /// There is a bug in the vendor driver where the `serial_number` and -/// `description` fields may be blank on the FT4232H and FT2232H when only +/// `description` fields may be blank on the FT4232H(A) FT2232H when only /// some of the ports are unbound from the `ftdi_sio` linux kernel module. /// /// This will not work if you have a custom VID/PID programmed onto your FTDI @@ -426,7 +426,7 @@ pub fn list_devices_fs() -> io::Result> { let port_letters: Option<&'static [char]> = match device_type { DeviceType::FT2232H => Some(&['A', 'B']), - DeviceType::FT4232H => Some(&['A', 'B', 'C', 'D']), + DeviceType::FT4232H | DeviceType::FT4232HA => Some(&['A', 'B', 'C', 'D']), _ => None, }; @@ -546,7 +546,7 @@ pub struct Ft232r { /// ```no_run /// use libftd2xx::{Ft2232h, Ftdi}; /// -/// let ft4232h: Ft2232h = Ftdi::new()?.try_into()?; +/// let ft2232h: Ft2232h = Ftdi::new()?.try_into()?; /// # Ok::<(), libftd2xx::DeviceTypeError>(()) /// ``` #[derive(Debug)] @@ -571,6 +571,23 @@ pub struct Ft4232h { ftdi: Ftdi, } +/// FT4232HA device. +/// +/// # Example +/// +/// Converting from an unknown FTDI device. +/// +/// ```no_run +/// use libftd2xx::{Ft4232ha, Ftdi}; +/// +/// let ft4232ha: Ft4232ha = Ftdi::new()?.try_into()?; +/// # Ok::<(), libftd2xx::DeviceTypeError>(()) +/// ``` +#[derive(Debug)] +pub struct Ft4232ha { + ftdi: Ftdi, +} + /// FTD2XX functions common to all devices. pub trait FtdiCommon { /// FTDI device type. @@ -622,6 +639,7 @@ pub trait FtdiCommon { 0x1800 => Ok(DeviceType::FT4222H_0), 0x1900 => Ok(DeviceType::FT4222H_1_2), 0x2100 => Ok(DeviceType::FT4222_PROG), + 0x3600 => Ok(DeviceType::FT4232HA), _ => Err(FtStatus::OTHER_ERROR), } } @@ -1642,7 +1660,7 @@ pub trait FtdiCommon { /// It is the responsibility of the application to close the handle after /// successfully calling this method. /// - /// For FT4232H, FT2232H and FT2232 devices, `cycle_port` will only work + /// For FT4232H(A), FT2232H and FT2232 devices, `cycle_port` will only work /// under Windows XP and later. /// /// # Example @@ -1857,7 +1875,7 @@ pub trait FtdiEeprom< /// /// # Example /// - /// This example uses the FT232H. + /// This example uses the FT4232H. /// /// ```no_run /// use libftd2xx::{Ft4232h, Ftdi, FtdiEeprom}; @@ -2061,7 +2079,7 @@ impl Ftdi { } impl Ft232h { - /// Open a `Ft4232h` device and initialize the handle. + /// Open a `Ft232h` device and initialize the handle. /// /// # Safety /// @@ -2272,6 +2290,59 @@ impl Ft4232h { } } +impl Ft4232ha { + /// Open a `Ft4232ha` device and initialize the handle. + /// + /// # Safety + /// + /// This is **unchecked** meaning a device type check will not be performed. + /// Methods that require this specific device type may fail in unexpected + /// ways if the wrong device is used. + /// + /// # Example + /// + /// ```no_run + /// use libftd2xx::Ft4232ha; + /// + /// let mut ft = unsafe { Ft4232ha::with_serial_number_unchecked("FT4PWSEOA")? }; + /// # Ok::<(), libftd2xx::FtStatus>(()) + /// ``` + pub unsafe fn with_serial_number_unchecked(serial_number: &str) -> Result { + let handle = ft_open_ex(serial_number, FT_OPEN_BY_SERIAL_NUMBER)?; + Ok(Ft4232ha { + ftdi: Ftdi { handle }, + }) + } + + /// Open a `Ft4232ha` device and initialize the handle. + /// + /// # Example + /// + /// ```no_run + /// use libftd2xx::Ft4232ha; + /// + /// Ft4232ha::with_serial_number("FT4PWSEOA")?; + /// # Ok::<(), libftd2xx::DeviceTypeError>(()) + /// ``` + pub fn with_serial_number(serial_number: &str) -> Result { + Ftdi::with_serial_number(serial_number)?.try_into() + } + + /// Open a `Ft4232ha` device by its device description. + /// + /// # Example + /// + /// ```no_run + /// use libftd2xx::Ft4232ha; + /// + /// Ft4232ha::with_description("Quad RS232-HS A")?; + /// # Ok::<(), libftd2xx::DeviceTypeError>(()) + /// ``` + pub fn with_description(description: &str) -> Result { + Ftdi::with_description(description)?.try_into() + } +} + impl FtdiCommon for Ftdi { const DEVICE_TYPE: DeviceType = DeviceType::Unknown; @@ -2351,11 +2422,13 @@ impl_boilerplate_for!(Ft232h, DeviceType::FT232H); impl_boilerplate_for!(Ft232r, DeviceType::FT232R); impl_boilerplate_for!(Ft2232h, DeviceType::FT2232H); impl_boilerplate_for!(Ft4232h, DeviceType::FT4232H); +impl_boilerplate_for!(Ft4232ha, DeviceType::FT4232HA); impl_try_from_for!(Ft232h); impl_try_from_for!(Ft232r); impl_try_from_for!(Ft2232h); impl_try_from_for!(Ft4232h); +impl_try_from_for!(Ft4232ha); impl FtdiEeprom for Ft232h {} impl FtdiEeprom for Ft232r {} @@ -2366,6 +2439,8 @@ impl FtdiMpsse for Ft232h {} impl FtdiMpsse for Ft232r {} impl FtdiMpsse for Ft2232h {} impl FtdiMpsse for Ft4232h {} +impl FtdiMpsse for Ft4232ha {} impl Ftx232hMpsse for Ft232h {} impl Ftx232hMpsse for Ft2232h {} impl Ftx232hMpsse for Ft4232h {} +impl Ftx232hMpsse for Ft4232ha {} diff --git a/src/mpsse.rs b/src/mpsse.rs index 801bd30..cb3c000 100644 --- a/src/mpsse.rs +++ b/src/mpsse.rs @@ -30,7 +30,7 @@ fn clock_divisor(device: DeviceType, frequency: u32) -> (u32, Option) { check_limits(device, frequency, 6_000_000); (6_000_000 / frequency - 1, None) } - DeviceType::FT2232H | DeviceType::FT4232H | DeviceType::FT232H => { + DeviceType::FT2232H | DeviceType::FT4232H | DeviceType::FT4232HA | DeviceType::FT232H => { check_limits(device, frequency, 30_000_000); if frequency <= 6_000_000 { (6_000_000 / frequency - 1, Some(true)) @@ -80,7 +80,18 @@ mod clock_divisor { 6_000_001, (3, Some(false)) ); - pos!(max, DeviceType::FT4232H, 30_000_000, (0, Some(false))); + pos!( + ft4232h_max, + DeviceType::FT4232H, + 30_000_000, + (0, Some(false)) + ); + pos!( + ft4232ha_max, + DeviceType::FT4232HA, + 30_000_000, + (0, Some(false)) + ); neg!(panic_unknown, DeviceType::Unknown, 1_000); neg!(panic_ft232c_min, DeviceType::FT2232C, 91); @@ -424,7 +435,7 @@ pub trait FtdiMpsse: FtdiCommon { } /// This contains MPSSE commands that are only available on the the FT232H, -/// FT2232H, and FT4232H devices. +/// FT2232H, and FT4232H(A) devices. /// /// For details about the MPSSE read the [FTDI MPSSE Basics]. /// diff --git a/src/types.rs b/src/types.rs index 37c8e6d..e3add84 100644 --- a/src/types.rs +++ b/src/types.rs @@ -237,7 +237,7 @@ pub enum DeviceType { impl DeviceType { /// Get a device type with a USB product ID. /// - /// This is not entirely accurate since soem devices share the same PID. + /// This is not entirely accurate since some devices share the same PID. /// /// # Example /// @@ -254,6 +254,8 @@ impl DeviceType { Some(DeviceType::FT2232H) } else if pid == 0x6011 { Some(DeviceType::FT4232H) + } else if pid == 0x6048 { + Some(DeviceType::FT4232HA) } else if pid == 0x6014 { Some(DeviceType::FT232H) } else if pid == 0x6015 { @@ -281,6 +283,7 @@ impl From for DeviceType { DEVICE_232R => DeviceType::FT232R, DEVICE_2232H => DeviceType::FT2232H, DEVICE_4232H => DeviceType::FT4232H, + DEVICE_4232HA => DeviceType::FT4232HA, DEVICE_232H => DeviceType::FT232H, DEVICE_X_SERIES => DeviceType::FT_X_SERIES, DEVICE_4222H_0 => DeviceType::FT4222H_0, @@ -433,7 +436,7 @@ pub enum BitMode { Reset = FT_BITMODE_RESET as u8, /// Asynchronous bit bang. AsyncBitbang = FT_BITMODE_ASYNC_BITBANG as u8, - /// MPSSE (FT2232, FT2232H, FT4232H and FT232H devices only) + /// MPSSE (FT2232, FT2232H, FT4232H(A) and FT232H devices only) Mpsse = FT_BITMODE_MPSSE as u8, /// Synchronous Bit Bang /// (FT232R, FT245R,FT2232, FT2232H, FT4232H and FT232H devices only) @@ -606,6 +609,7 @@ pub struct DeviceInfo { /// * `0x6001` FT232AM/FT232BM/FT232R /// * `0x6010` FT2232C/FT2232D/FT2232H /// * `0x6011` FT4232/FT4232H + /// * `0x6048` FT4232HA /// * `0x6014` FT232H /// * `0x6015` FT230X/FT231X/FT234X pub product_id: u16,