Рейтинг@Mail.ru

Класс-обёртка для работы с библиотекой FTD2XX на Visual Basic .NET

автор:
Be the first to comment! Программирование
Print Friendly, PDF & Email

Предлагается класс-обёртка для работы с библиотекой ftd2xx.dll, которая позволяет управлять различными микросхемами фирмы FTDI.

За основу данного кода взят проект класса-обёртки на языке C# с официального сайта FTDI. По сравнению с данным примером, классу был придан более объектно-ориентированный стиль. Кроме того, класс был разделён на два класса. В первом классе Ftdi находится базовая функциональность, которая чаще всего нужна для работы с микросхемами FTDI. Во втором содержится код, необходимый для работы с ЭСППЗУ микросхем FTDI.

Замечу, что пришлось все члены типа IntPtr переделать на тип Integer. Это связано с тем, что в Visual Studio 2019 при работе с IntPtr возникает ошибка BC30657. Микрософт до сих пор не исправила её (Visual Studio 2019 версия 16.6.3), хотя они в курсе проблемы.

Ошибка BC30657 при преобразовании в IntPtr в Visual Studio 2019
Ошибка BC30657 при преобразовании в IntPtr в Visual Studio 2019

При этом при вызове нативных функций, которые требуют тип IntPtr, получить его можно двумя способами: либо создавая новый объект, инициализируя его значением целого числа integerValue:

New IntPtr(integerValue)

Либо через приведение типов:

CType(integerValue, IntPtr)

Также можно обратить внимание на вызов делегатов, которые повсеместно встречаются в коде при обращении к нативным функциям в библиотеке. При получении делегата по указателю, его можно вызвать тоже двумя способами. Например, в методе открытия устройства OpenByIndex() встречается такое:

Dim tFT_Open As OpenDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(pFT_Open), GetType(OpenDelegate)), OpenDelegate) 'получение делегата по указателю
status = tFT_Open.Invoke(index, ftHandle) 'использование делегата

Это эквивалентно более краткой записи, когда можно опустить указание метода Invoke() и сразу записать аргументы, передаваемые делегату (или пустые скобки, если аргументы не передаются):

status = tFT_Open(index, ftHandle) 

Нативные (родные) функции, методы – в данном контексте имеются в виду функции Windows, для выполнения которых необходимо обратиться к Windows API. Это функции, которые выполняются не средой .NET Framework, а непосредственно операционной системой. В противоположность нативному коду, существует т.н. «управляемый» код. Он выполняется под управлением фреймворка .NET, а точнее CLR – общеязыковой исполняющей среды. Нативный код также называют «неуправляемый».

В данном классе используются лишь три нативных метода, которые объявляются с атрибутом DllImport в классе Ftdi. Все они берутся из динамически загружаемой библиотеки Windows kernel32.dll.

Базовые функции для работы с микросхемами FTDI
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization
Imports System.Threading
Imports System.Text

Namespace FTD2XX_NET

    ''' <summary>
    ''' Класс для работы с устройствами FTDI.
    ''' </summary>
    Public Class Ftdi
        Implements IDisposable

#Region "CTORs"

        ''' <summary>
        ''' Конструктор по умолчанию, который не открывает устройство.
        ''' </summary>
        Public Sub New()
            'ничего не делает
        End Sub

        ''' <summary>
        ''' Конструктор, который открывает заданное устройство по индексу.
        ''' </summary>
        ''' <param name="index">Индекс устройства.</param>
        Public Sub New(index As Integer)
            Me.New()
            OpenByIndex(index)
        End Sub

        ''' <summary>
        ''' Конструктор, который открывает заданное устройство по серийному номеру.
        ''' </summary>
        ''' <param name="serial">Серийный номер. Должен точно соответствовать даже регистром.</param>
        Public Sub New(serial As String)
            Me.New()
            OpenBySerialNumber(serial)
        End Sub

        ''' <summary>
        ''' Освобождает библиотеку ftd2xx.
        ''' </summary>
        Public Shared Sub UnloadLibrary()
            If FreeLibrary(Ftd2xxDllHandle) Then
                _Ftd2xxDllHandle = CLOSED_HANDLE
                Debug.WriteLine("Library unloaded.")
            End If
        End Sub

#End Region '/CTORs

#Region "КОНСТАНТЫ"

        Public Const FT_DEFAULT_BAUD_RATE As UInteger = 9600UI
        Public Const FT_COM_PORT_NOT_ASSIGNED As Integer = -1
        Public Const FT_DEFAULT_DEADMAN_TIMEOUT As UInteger = 5000UI
        Public Const FT_DEFAULT_LATENCY As Byte = 16
        Public Const FT_DEFAULT_IN_TRANSFER_SIZE As UInteger = 4096UI
        Public Const FT_DEFAULT_OUT_TRANSFER_SIZE As UInteger = 4096UI

        Private Const CLOSED_HANDLE As Integer = 0
        Private Const NOT_INIT As Integer = -1

#End Region '/КОНСТАНТЫ

#Region "READ-ONLY PROPS"

        ''' <summary>
        ''' Путь к библиотеке ftd2xx.
        ''' </summary>
        Public Shared ReadOnly Property LibPath As String
            Get
                Return _LibPath
            End Get
        End Property
        Private Shared _LibPath As String = "ftd2xx.dll"

        ''' <summary>
        ''' Объект для работы с ПЗУ.
        ''' </summary>
        Public ReadOnly Property Eeprom As FTD2XX_NET.Eeprom
            Get
                If (_Eeprom Is Nothing) Then
                    _Eeprom = New Eeprom(Ftd2xxDllHandle, FtHandle, DeviceType)
                End If
                Return _Eeprom
            End Get
        End Property
        Private _Eeprom As FTD2XX_NET.Eeprom

        ''' <summary>
        ''' Загружена ли библиотека.
        ''' </summary>
        Public Shared ReadOnly Property IsLibraryLoaded As Boolean
            Get
                Return (Ftd2xxDllHandle <> CLOSED_HANDLE)
            End Get
        End Property

        ''' <summary>
        ''' Открыто ли устройство.
        ''' </summary>
        Public ReadOnly Property IsDeviceOpen As Boolean
            Get
                Return (FtHandle <> CLOSED_HANDLE)
            End Get
        End Property

        ''' <summary>
        ''' Признак канала (A, B и т.д.).
        ''' </summary>
        Private ReadOnly Property InterfaceIdentifier As String
            Get
                If (_InterfaceIdentifier.Length = 0) AndAlso IsLibraryLoaded AndAlso IsDeviceOpen Then
                    Dim devType As FT_DEVICE = DeviceType
                    If (devType = FT_DEVICE.FT_DEVICE_2232) OrElse (devType = FT_DEVICE.FT_DEVICE_2232H) OrElse (devType = FT_DEVICE.FT_DEVICE_4232H) Then
                        _InterfaceIdentifier = Description().Substring(Description.Length - 1)
                    End If
                End If
                Return _InterfaceIdentifier
            End Get
        End Property
        Private _InterfaceIdentifier As String = ""

        ''' <summary>
        ''' Тип текущего чипа FTDI.
        ''' </summary>
        Public ReadOnly Property DeviceType As FT_DEVICE
            Get
                If (_DeviceType = FT_DEVICE.FT_DEVICE_UNKNOWN) AndAlso IsLibraryLoaded AndAlso IsDeviceOpen Then
                    Dim devType As FT_DEVICE = FT_DEVICE.FT_DEVICE_UNKNOWN
                    Dim num As UInteger = 0
                    Dim sn As Byte() = New Byte(15) {}
                    Dim descr As Byte() = New Byte(63) {}
                    Dim dlg As GetDeviceInfoDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetDeviceInfo, IntPtr), GetType(GetDeviceInfoDelegate)), GetDeviceInfoDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, devType, num, sn, descr, 0)
                    _DeviceType = devType
                End If
                Return _DeviceType
            End Get
        End Property
        Private _DeviceType As FT_DEVICE = FT_DEVICE.FT_DEVICE_UNKNOWN

        ''' <summary>
        ''' Vendor ID и Product ID текущего устройства.
        ''' </summary>
        Public ReadOnly Property DeviceID As UInteger
            Get
                If (_DeviceID = 0) AndAlso IsLibraryLoaded AndAlso IsDeviceOpen Then
                    Dim devid As UInteger
                    Dim dev As FT_DEVICE = FT_DEVICE.FT_DEVICE_UNKNOWN
                    Dim sn As Byte() = New Byte(15) {}
                    Dim descr As Byte() = New Byte(63) {}
                    Dim dlg As GetDeviceInfoDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetDeviceInfo, IntPtr), GetType(GetDeviceInfoDelegate)), GetDeviceInfoDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, dev, devid, sn, descr, 0)
                    _DeviceID = devid
                End If
                Return _DeviceID
            End Get
        End Property
        Private _DeviceID As UInteger = 0

        ''' <summary>
        ''' Описание текущего устройства.
        ''' </summary>
        Public ReadOnly Property Description As String
            Get
                If (_Description.Length = 0) AndAlso IsLibraryLoaded AndAlso IsDeviceOpen Then
                    Dim sn As Byte() = New Byte(15) {}
                    Dim descr As Byte() = New Byte(63) {}
                    Dim num As UInteger = 0UI
                    Dim dev As FT_DEVICE = FT_DEVICE.FT_DEVICE_UNKNOWN
                    Dim dlg As GetDeviceInfoDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetDeviceInfo, IntPtr), GetType(GetDeviceInfoDelegate)), GetDeviceInfoDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, dev, num, sn, descr, 0)
                    Dim d As String = Encoding.ASCII.GetString(descr)
                    _Description = d.Substring(0, d.IndexOf(vbNullChar))
                End If
                Return _Description
            End Get
        End Property
        Private _Description As String = String.Empty

        ''' <summary>
        ''' Серийный номер устройства.
        ''' </summary>
        Public ReadOnly Property SerialNumber As String
            Get
                If (_SerialNumber.Length = 0) AndAlso IsLibraryLoaded AndAlso IsDeviceOpen Then
                    Dim sn As Byte() = New Byte(15) {}
                    Dim descr As Byte() = New Byte(63) {}
                    Dim num As UInteger = 0UI
                    Dim dev As FT_DEVICE = FT_DEVICE.FT_DEVICE_UNKNOWN
                    Dim dlg As GetDeviceInfoDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetDeviceInfo, IntPtr), GetType(GetDeviceInfoDelegate)), GetDeviceInfoDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, dev, num, sn, descr, 0)
                    Dim serNum As String = Encoding.ASCII.GetString(sn)
                    _SerialNumber = serNum.Substring(0, serNum.IndexOf(vbNullChar))
                End If
                Return _SerialNumber
            End Get
        End Property
        Private _SerialNumber As String = String.Empty

        ''' <summary>
        ''' Текущая версия драйвера FTDIBUS.SYS.
        ''' </summary>
        Public ReadOnly Property DriverVersion As UInteger
            Get
                If (_DriverVersion = 0) AndAlso (Pft_GetDriverVersion <> NOT_INIT) Then
                    Dim dlg As GetDriverVersionDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_GetDriverVersion), GetType(GetDriverVersionDelegate)), GetDriverVersionDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, _DriverVersion)
                End If
                Return _DriverVersion
            End Get
        End Property
        Private _DriverVersion As UInteger = 0

        ''' <summary>
        ''' Текущая версия драйвера FTD2XX.DLL.
        ''' </summary>
        Public Shared ReadOnly Property LibraryVersion As UInteger
            Get
                If (_LibraryVersion = 0) Then
                    Dim pft_GetLibraryVersion As Integer = GetProcAddress(Ftd2xxDllHandle, "FT_GetLibraryVersion")
                    Dim dlg As GetLibraryVersionDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(pft_GetLibraryVersion), GetType(GetLibraryVersionDelegate)), GetLibraryVersionDelegate)
                    Dim status As FT_STATUS = dlg.Invoke(_LibraryVersion)
                End If
                Return _LibraryVersion
            End Get
        End Property
        Private Shared _LibraryVersion As UInteger = 0

#End Region '/READ-ONLY PROPS

#Region "ОТКРЫТИЕ, ЗАКРЫТИЕ"

        'Дескриптор устройства:
        Private FtHandle As Integer = CLOSED_HANDLE

        ''' <summary>
        ''' Открывает устройство FTDI по индексу <paramref name="index"/>.
        ''' </summary>
        ''' <remarks>
        ''' Это не гарантирует открытие заданного устройства.
        ''' </remarks>
        Public Sub OpenByIndex(index As Integer)
            Dim dlg As OpenDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Open), GetType(OpenDelegate)), OpenDelegate)
            Dim status As FT_STATUS = dlg(CUInt(index), FtHandle)
            If (status = FT_STATUS.FT_OK) Then
                Dim uWordLength As Byte = 8
                Dim uStopBits As Byte = 0
                Dim uParity As Byte = 0
                Dim dDlg As SetDataCharacteristicsDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetDataCharacteristics), GetType(SetDataCharacteristicsDelegate)), SetDataCharacteristicsDelegate)
                status = dDlg(FtHandle, uWordLength, uStopBits, uParity)
                CheckErrors(status)

                Dim usFlowControl As UShort = 0US
                Dim uXon As Byte = 17
                Dim uXoff As Byte = 19
                Dim fDlg As SetFlowControlDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetFlowControl), GetType(SetFlowControlDelegate)), SetFlowControlDelegate)
                status = fDlg(FtHandle, usFlowControl, uXon, uXoff)
                CheckErrors(status)

                Dim dwBaudRate As UInteger = FT_DEFAULT_BAUD_RATE
                Dim bDlg As SetBaudRateDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetBaudRate), GetType(SetBaudRateDelegate)), SetBaudRateDelegate)
                status = bDlg(FtHandle, dwBaudRate)
            Else
                FtHandle = CLOSED_HANDLE
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Открывает устройство FTDI по серийному номеру <paramref name="serialnumber"/>.
        ''' </summary>
        Public Sub OpenBySerialNumber(serialnumber As String)
            Dim dlg As OpenExDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_OpenEx, IntPtr), GetType(OpenExDelegate)), OpenExDelegate)
            Dim status As FT_STATUS = dlg(serialnumber, FT_OPEN_BY.SERIAL_NUMBER, FtHandle)
            If (status = FT_STATUS.FT_OK) Then
                Dim uWordLength As Byte = 8
                Dim uStopBits As Byte = 0
                Dim uParity As Byte = 0
                Dim dDlg As SetDataCharacteristicsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetDataCharacteristics, IntPtr), GetType(SetDataCharacteristicsDelegate)), SetDataCharacteristicsDelegate)
                status = dDlg(FtHandle, uWordLength, uStopBits, uParity)
                CheckErrors(status)

                Dim usFlowControl As UShort = 0US
                Dim uXon As Byte = 17
                Dim uXoff As Byte = 19
                Dim fDlg As SetFlowControlDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetFlowControl, IntPtr), GetType(SetFlowControlDelegate)), SetFlowControlDelegate)
                status = fDlg(FtHandle, usFlowControl, uXon, uXoff)
                CheckErrors(status)

                Dim dwBaudRate As UInteger = FT_DEFAULT_BAUD_RATE
                Dim bDlg As SetBaudRateDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetBaudRate, IntPtr), GetType(SetBaudRateDelegate)), SetBaudRateDelegate)
                status = bDlg(FtHandle, dwBaudRate)
            Else
                FtHandle = CLOSED_HANDLE
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Открывает устройство FTDI по описанию <paramref name="description"/>.
        ''' </summary>
        Public Sub OpenByDescription(description As String)
            Dim dlg As OpenExDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_OpenEx, IntPtr), GetType(OpenExDelegate)), OpenExDelegate)
            Dim status As FT_STATUS = dlg(description, FT_OPEN_BY.DESCRIPTION, FtHandle)
            If (status = FT_STATUS.FT_OK) Then
                Dim uWordLength As Byte = 8
                Dim uStopBits As Byte = 0
                Dim uParity As Byte = 0
                Dim dDlg As SetDataCharacteristicsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetDataCharacteristics, IntPtr), GetType(SetDataCharacteristicsDelegate)), SetDataCharacteristicsDelegate)
                status = dDlg(FtHandle, uWordLength, uStopBits, uParity)
                CheckErrors(status)

                Dim usFlowControl As UShort = 0US
                Dim uXon As Byte = 17
                Dim uXoff As Byte = 19
                Dim fDlg As SetFlowControlDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetFlowControl, IntPtr), GetType(SetFlowControlDelegate)), SetFlowControlDelegate)
                status = fDlg(FtHandle, usFlowControl, uXon, uXoff)
                CheckErrors(status)

                Dim dwBaudRate As UInteger = FT_DEFAULT_BAUD_RATE
                Dim bDlg As SetBaudRateDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetBaudRate, IntPtr), GetType(SetBaudRateDelegate)), SetBaudRateDelegate)
                status = bDlg(FtHandle, dwBaudRate)
            Else
                FtHandle = CLOSED_HANDLE
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Открывает устройство FTDI по физическому расположению <paramref name="location"/>.
        ''' </summary>
        Public Sub OpenByLocation(location As UInteger)
            Dim dlg As OpenExLocDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_OpenEx, IntPtr), GetType(OpenExLocDelegate)), OpenExLocDelegate)
            Dim status As FT_STATUS = dlg(location, FT_OPEN_BY.LOCATION, FtHandle)
            If (status = FT_STATUS.FT_OK) Then
                Dim uWordLength As Byte = 8
                Dim uStopBits As Byte = 0
                Dim uParity As Byte = 0
                Dim dDlg As SetDataCharacteristicsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetDataCharacteristics, IntPtr), GetType(SetDataCharacteristicsDelegate)), SetDataCharacteristicsDelegate)
                status = dDlg(FtHandle, uWordLength, uStopBits, uParity)
                CheckErrors(status)

                Dim usFlowControl As UShort = 0US
                Dim uXon As Byte = 17
                Dim uXoff As Byte = 19
                Dim fDlg As SetFlowControlDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetFlowControl, IntPtr), GetType(SetFlowControlDelegate)), SetFlowControlDelegate)
                status = fDlg(FtHandle, usFlowControl, uXon, uXoff)
                CheckErrors(status)

                Dim dwBaudRate As UInteger = FT_DEFAULT_BAUD_RATE
                Dim bDlg As SetBaudRateDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetBaudRate, IntPtr), GetType(SetBaudRateDelegate)), SetBaudRateDelegate)
                status = bDlg(FtHandle, dwBaudRate)
            Else
                FtHandle = CLOSED_HANDLE
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Закрывает открытое устройство.
        ''' </summary>
        Public Sub Close()
            If (FtHandle <> CLOSED_HANDLE) AndAlso (Pft_Close <> NOT_INIT) Then
                Dim dlg As CloseDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Close), GetType(CloseDelegate)), CloseDelegate)
                Dim status As FT_STATUS = dlg.Invoke(FtHandle)
                CheckErrors(status)
                If (status = FT_STATUS.FT_OK) Then
                    FtHandle = CLOSED_HANDLE
                End If
            End If
        End Sub

#End Region '/ОТКРЫТИЕ, ЗАКРЫТИЕ

#Region "ИНФО"

        ''' <summary>
        ''' Возвращает число доступных устройств FTDI.
        ''' </summary>
        Public Shared Function GetNumberOfDevices() As Integer
            Dim devCount As UInteger = 0
            Dim dlg As CreateDeviceInfoListDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_CreateDeviceInfoList), GetType(CreateDeviceInfoListDelegate)), CreateDeviceInfoListDelegate)
            Dim status As FT_STATUS = dlg.Invoke(devCount)
            CheckErrors(status)
            Return CInt(devCount)
        End Function

        ''' <summary>
        ''' Возвращает информацию обо всех доступных устройствах FTDI.
        ''' </summary>
        Public Shared Function GetDeviceList() As FT_DEVICE_INFO_NODE()
            Dim numDevices As UInteger = 0UI
            Dim dlg As CreateDeviceInfoListDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_CreateDeviceInfoList), GetType(CreateDeviceInfoListDelegate)), CreateDeviceInfoListDelegate)
            Dim status As FT_STATUS = dlg(numDevices)
            CheckErrors(status)
            If (numDevices > 0) Then
                Dim devicelist(CInt(numDevices - 1)) As FT_DEVICE_INFO_NODE
                Dim gdiDeleg As GetDeviceInfoDetailDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_GetDeviceInfoDetail), GetType(GetDeviceInfoDetailDelegate)), GetDeviceInfoDetailDelegate)
                For i As Integer = 0 To CInt(numDevices - 1)
                    devicelist(i) = New FT_DEVICE_INFO_NODE()
                    Dim sn As Byte() = New Byte(15) {}
                    Dim descr As Byte() = New Byte(63) {}
                    status = gdiDeleg(CUInt(i), devicelist(i).Flags, devicelist(i).Type, devicelist(i).ID, devicelist(i).LocId, sn, descr, devicelist(i).FtHandle)
                    CheckErrors(status)
                    devicelist(i).SerialNumber = Encoding.ASCII.GetString(sn)
                    devicelist(i).Description = Encoding.ASCII.GetString(descr)
                    Dim endOfStringIndex As Integer = devicelist(i).SerialNumber.IndexOf(vbNullChar)
                    If (endOfStringIndex <> -1) Then
                        devicelist(i).SerialNumber = devicelist(i).SerialNumber.Substring(0, endOfStringIndex)
                    End If
                    endOfStringIndex = devicelist(i).Description.IndexOf(vbNullChar)
                    If (endOfStringIndex <> -1) Then
                        devicelist(i).Description = devicelist(i).Description.Substring(0, endOfStringIndex)
                    End If
                Next
                Return devicelist
            End If
            Return New FT_DEVICE_INFO_NODE() {}
        End Function

        ''' <summary>
        ''' Возвращает число доступных байтов в приёмном буфере.
        ''' </summary>
        Public Function GetRxBytesAvailable() As Integer
            Dim rxQueue As UInteger
            Dim dlg As GetQueueStatusDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetQueueStatus, IntPtr), GetType(GetQueueStatusDelegate)), GetQueueStatusDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, rxQueue)
            CheckErrors(status)
            Return CInt(rxQueue)
        End Function

        ''' <summary>
        ''' Возвращает ожидающее число байтов в передающем буфере.
        ''' </summary>
        Public Function GetTxBytesWaiting() As Integer
            Dim txQueue As UInteger
            Dim inTxLen As UInteger = 0UI
            Dim eventType As UInteger = 0UI
            Dim dlg As GetStatusDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetStatus, IntPtr), GetType(GetStatusDelegate)), GetStatusDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, inTxLen, txQueue, eventType)
            CheckErrors(status)
            Return CInt(txQueue)
        End Function

        ''' <summary>
        ''' Возвращает тип события после его возникновения.
        ''' </summary>
        ''' <remarks>
        ''' Можно использовать чтобы определить, какое событие сработало, когда ожидаются осбытия разных типов.
        ''' </remarks>
        Public Function GetEventType() As FT_EVENTS
            Dim eventType As UInteger
            Dim inTxLen As UInteger = 0UI
            Dim txQueue As UInteger = 0UI
            Dim dlg As GetStatusDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetStatus, IntPtr), GetType(GetStatusDelegate)), GetStatusDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, inTxLen, txQueue, eventType)
            CheckErrors(status)
            Return CType(eventType, FT_EVENTS)
        End Function

        ''' <summary>
        ''' Возвращает текущее состояние модема (битовую маску).
        ''' </summary>
        Public Function GetModemStatus() As FT_MODEM_STATUS
            Dim s As UInteger = 0UI
            Dim dlg As GetModemStatusDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetModemStatus, IntPtr), GetType(GetModemStatusDelegate)), GetModemStatusDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, s)
            CheckErrors(status)
            Dim modemStatus As FT_MODEM_STATUS = CType(s And &HFF, FT_MODEM_STATUS)
            Return modemStatus
        End Function

        ''' <summary>
        ''' Возвращает текущее состояние линии (битовую маску).
        ''' </summary>
        Public Function GetLineStatus() As FT_LINE_STATUS
            Dim s As UInteger = 0UI
            Dim dlg As GetModemStatusDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetModemStatus, IntPtr), GetType(GetModemStatusDelegate)), GetModemStatusDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, s)
            CheckErrors(status)
            Dim lineStatus As FT_LINE_STATUS = CType((s >> 8) And &HFF, FT_LINE_STATUS)
            Return lineStatus
        End Function

        ''' <summary>
        ''' Возвращает назначенный порт или пустую строку, если порт не был назначен.
        ''' </summary>
        Public Function GetComPort() As String
            Dim portNum As Integer = FT_COM_PORT_NOT_ASSIGNED
            Dim dlg As GetComPortNumberDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetComPortNumber, IntPtr), GetType(GetComPortNumberDelegate)), GetComPortNumberDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, portNum)
            CheckErrors(status)
            If (portNum <> FT_COM_PORT_NOT_ASSIGNED) Then
                Return $"COM{portNum}"
            End If
            Return String.Empty
        End Function

        ''' <summary>
        ''' Возвращает состояние выводов входа/выхода (битовую маску).
        ''' </summary>
        Public Function GetPinStates() As Byte
            Dim bitMode As Byte
            Dim dlg As GetBitModeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_GetBitMode, IntPtr), GetType(GetBitModeDelegate)), GetBitModeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, bitMode)
            CheckErrors(status)
            Return bitMode
        End Function

#End Region '/ИНФО

#Region "ПАРАМЕТРЫ"

        ''' <summary>
        ''' Задаёт битрейт.
        ''' </summary>
        ''' <param name="baudRate">Желаемый битрейт устройства, бит/сек.</param>
        Public Sub SetBaudRate(Optional baudRate As Integer = FT_DEFAULT_BAUD_RATE)
            Dim dlg As SetBaudRateDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetBaudRate, IntPtr), GetType(SetBaudRateDelegate)), SetBaudRateDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, CUInt(baudRate))
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Устанавливает число битов данных, стоповых и тип проверки чётности.
        ''' </summary>
        ''' <param name="dataBits">Число битов данных.</param>
        ''' <param name="stopBits">Число стоповых бит.</param>
        ''' <param name="parity">Тип проверки чётности.</param>
        Public Sub SetDataCharacteristics(dataBits As FT_DATA_BITS, stopBits As FT_STOP_BITS, parity As FT_PARITY)
            Dim dlg As SetDataCharacteristicsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetDataCharacteristics, IntPtr), GetType(SetDataCharacteristicsDelegate)), SetDataCharacteristicsDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, dataBits, stopBits, parity)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Устанавливает тип управления потоком данных.
        ''' </summary>
        ''' <param name="flowControl">Тип управления потоком.</param>
        ''' <param name="xOn">Символ Xon для Xon/Xoff. Игнорируется, если Xon/XOff не используется.</param>
        ''' <param name="xOff">Символ Xoff для Xon/Xoff. Игнорируется, если Xon/XOff не используется.</param>
        Public Sub SetFlowControl(flowControl As FT_FLOW_CONTROL, Optional xOn As Byte = 0, Optional xOff As Byte = 0)
            Dim dlg As SetFlowControlDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetFlowControl, IntPtr), GetType(SetFlowControlDelegate)), SetFlowControlDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, flowControl, xOn, xOff)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Выставляет или сбрасывает линию Request To Send (RTS).
        ''' </summary>
        ''' <param name="enable">True выставляет, False сбрасывает RTS.</param>
        Public Sub SetRts(enable As Boolean)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If enable Then
                Dim dlg As SetRtsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetRts, IntPtr), GetType(SetRtsDelegate)), SetRtsDelegate)
                status = dlg.Invoke(FtHandle)
            Else
                Dim dlg As ClrRtsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_ClrRts, IntPtr), GetType(ClrRtsDelegate)), ClrRtsDelegate)
                status = dlg.Invoke(FtHandle)
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Выставляет или сбрасывает линию Data Terminal Ready (DTR).
        ''' </summary>
        ''' <param name="enable">True выставляет, False сбрасывает DTR.</param>
        Public Sub SetDtr(enable As Boolean)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If enable Then
                Dim dlg As SetDtrDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetDtr, IntPtr), GetType(SetDtrDelegate)), SetDtrDelegate)
                status = dlg.Invoke(FtHandle)
            Else
                Dim dlg As ClrDtrDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_ClrDtr, IntPtr), GetType(ClrDtrDelegate)), ClrDtrDelegate)
                status = dlg.Invoke(FtHandle)
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Устанавливает время ожидания чтения и записи.
        ''' </summary>
        ''' <param name="readTimeout">Время ожидания при чтении, мс. Значение "0" означает бесконечное ожидание.</param>
        ''' <param name="writeTimeout">Время ожидания при записи, мс. Значение "0" означает бесконечное ожидание.</param>
        Public Sub SetTimeouts(readTimeout As UInteger, writeTimeout As UInteger)
            Dim dlg As SetTimeoutsDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(Pft_SetTimeouts, IntPtr), GetType(SetTimeoutsDelegate)), SetTimeoutsDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, readTimeout, writeTimeout)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Устанавливает или сбрасывает состояние прерывания.
        ''' </summary>
        ''' <param name="enable">True включает, False выключает.</param>
        Public Sub SetBreak(enable As Boolean)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If enable Then
                Dim dlg As SetBreakOnDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetBreakOn), GetType(SetBreakOnDelegate)), SetBreakOnDelegate)
                status = dlg(FtHandle)
            Else
                Dim dlg As SetBreakOffDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetBreakOff), GetType(SetBreakOffDelegate)), SetBreakOffDelegate)
                status = dlg(FtHandle)
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Задаёт число повторов (reset pipe retry count). По умолчанию 50.
        ''' </summary>
        ''' <param name="resetPipeRetryCount">Число повторов. В электрически шумных средах бОльшие значения лучше.</param>
        Public Sub SetResetPipeRetryCount(resetPipeRetryCount As Integer)
            Dim dlg As SetResetPipeRetryCountDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetResetPipeRetryCount), GetType(SetResetPipeRetryCountDelegate)), SetResetPipeRetryCountDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, CUInt(resetPipeRetryCount))
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Задаёт время простоя шины USB.
        ''' </summary>
        ''' <param name="deadmanTimeout">Время простоя, мс.</param>
        Public Sub SetDeadmanTimeout(Optional deadmanTimeout As UInteger = FT_DEFAULT_DEADMAN_TIMEOUT)
            Dim dlg As SetDeadmanTimeoutDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetDeadmanTimeout), GetType(SetDeadmanTimeoutDelegate)), SetDeadmanTimeoutDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, deadmanTimeout)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Задаёт задержку в шине USB.
        ''' </summary>
        ''' <param name="latency">Задержка, мс.
        ''' Значения 2...255 мс для FT232BM, FT245BM и FT2232.
        ''' Значения 0...255 мс для прочих устройств.</param>
        Public Sub SetLatency(Optional latency As Byte = FT_DEFAULT_LATENCY)
            If (latency < 2) Then
                If ((DeviceType = FT_DEVICE.FT_DEVICE_BM) OrElse (DeviceType = FT_DEVICE.FT_DEVICE_2232)) Then
                    latency = 2
                End If
            End If
            Dim dlg As SetLatencyTimerDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetLatencyTimer), GetType(SetLatencyTimerDelegate)), SetLatencyTimerDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, latency)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Получает значение задержки, мс.
        ''' </summary>
        Public Function GetLatency() As Byte
            Dim latency As Byte
            Dim dlg As GetLatencyTimerDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_GetLatencyTimer), GetType(GetLatencyTimerDelegate)), GetLatencyTimerDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, latency)
            CheckErrors(status)
            Return latency
        End Function

        ''' <summary>
        ''' Задаёт размеры передающего и принимающего буферов USB.
        ''' </summary>
        ''' <param name="inSize">Резмер в байтах входящего буфера USB. Кратно 64. Значение по умолчанию 4 кб.</param>
        ''' <param name="outSize">Резмер в байтах исходящего буфера USB. Кратно 64. Значение по умолчанию 4 кб.</param>
        Public Sub SetTransferSize(Optional inSize As Integer = FT_DEFAULT_IN_TRANSFER_SIZE, Optional outSize As Integer = FT_DEFAULT_OUT_TRANSFER_SIZE)
            Dim dlg As SetUsbParametersDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetUSBParameters), GetType(SetUsbParametersDelegate)), SetUsbParametersDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, CUInt(inSize), CUInt(outSize))
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Задаёт символы для событий "получение данных" и "возникновение ошибки".
        ''' </summary>
        ''' <param name="eventChar">Символ, который будет вызывать передачу в данных хост при его получении.</param>
        ''' <param name="eventCharEnable">Включает (True) или выключает (False) символ <paramref name="eventChar"/>.</param>
        ''' <param name="errorChar">Символ, который будет вставлен в поток данных, чтобы показать возникновение ошибки.</param>
        ''' <param name="errorCharEnable">Включает (True) или выключает (False) символ <paramref name="errorChar"/>.</param>
        Public Sub SetCharacters(eventChar As Byte, eventCharEnable As Boolean, errorChar As Byte, errorCharEnable As Boolean)
            Dim dlg As SetCharsDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetChars), GetType(SetCharsDelegate)), SetCharsDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, eventChar, Convert.ToByte(eventCharEnable), errorChar, Convert.ToByte(errorCharEnable))
            CheckErrors(status)
        End Sub

#End Region '/ПАРАМЕТРЫ

#Region "ЧТЕНИЕ, ЗАПИСЬ"

        ''' <summary>
        ''' Читает данные из открытого устройства.
        ''' </summary>
        ''' <param name="numBytesToRead">Число байтов, которые нужно прочитать.</param>
        Public Function Read(numBytesToRead As Integer) As Byte()
            Dim data(numBytesToRead - 1) As Byte
            If (data.Length < numBytesToRead) Then
                numBytesToRead = data.Length
            End If
            Dim numBytesRed As UInteger
            Dim dlg As ReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Read), GetType(ReadDelegate)), ReadDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, data, CUInt(numBytesToRead), numBytesRed)
            CheckErrors(status)
            Return data
        End Function

        ''' <summary>
        ''' Записывает данные в открытое устройство и возвращает число реально переданных данных.
        ''' </summary>
        ''' <param name="data">Массив данных для записи.</param>
        ''' <param name="numBytesToWrite">Число байтов для записи.</param>
        Public Function Write(data As Byte(), numBytesToWrite As Integer) As Integer
            Dim numBytesWritten As UInteger = 0UI
            Dim dlg As WriteDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Write), GetType(WriteDelegate)), WriteDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, data, CUInt(numBytesToWrite), numBytesWritten)
            CheckErrors(status)
            Return CInt(numBytesWritten)
        End Function

#End Region '/ЧТЕНИЕ, ЗАПИСЬ

#Region "УПРАВЛЕНИЕ"

        ''' <summary>
        ''' Сбрасывает открытое устройство.
        ''' </summary>
        Public Sub ResetDevice()
            Dim dlg As ResetDeviceDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_ResetDevice), GetType(ResetDeviceDelegate)), ResetDeviceDelegate)
            Dim status As FT_STATUS = dlg(FtHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Очищает заданные буферы.
        ''' Purge buffer constant definitions.
        ''' </summary>
        Public Sub Purge(purgeMask As FT_PURGE)
            Dim dlg As PurgeDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Purge), GetType(PurgeDelegate)), PurgeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, purgeMask)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Регистрирует уведомление о событиях.
        ''' </summary>
        ''' <remarks>
        ''' После регистрации уведомления, событие может быть перехвачено методами ожидания <see cref="EventWaitHandle.WaitOne()"/>.
        ''' Если мониторятся несколько типов событий, вызывающее событие можно определить вызовом метода <see cref="GetEventType()"/>.
        ''' </remarks>
        ''' <param name="eventMask">Тип сигнального события.</param>
        ''' <param name="eventHandle">Указатель обработчика события.</param>
        Public Sub SetEventNotification(eventMask As FT_EVENTS, eventHandle As EventWaitHandle)
            Dim dlg As SetEventNotificationDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetEventNotification), GetType(SetEventNotificationDelegate)), SetEventNotificationDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, eventMask, eventHandle.SafeWaitHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Останавливает работу планировщика шины USB (опрос заданий).
        ''' </summary>
        Public Sub StopInTask()
            Dim dlg As StopInTaskDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_StopInTask), GetType(StopInTaskDelegate)), StopInTaskDelegate)
            Dim status As FT_STATUS = dlg(FtHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Возобновляет работу планировщика заданий шины USB (опрос заданий).
        ''' </summary>
        Public Sub RestartInTask()
            Dim dlg As RestartInTaskDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_RestartInTask), GetType(RestartInTaskDelegate)), RestartInTaskDelegate)
            Dim status As FT_STATUS = dlg(FtHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Перезагружает порт устройства.
        ''' </summary>
        Public Sub ResetPort()
            Dim dlg As ResetPortDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_ResetPort), GetType(ResetPortDelegate)), ResetPortDelegate)
            Dim status As FT_STATUS = dlg(FtHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Вызывает перенумерацию устройств на шине USB. Эквивалентно извлечению и вставке устройства USB.
        ''' </summary>
        Public Sub CyclePort()
            Dim dlg As CyclePortDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_CyclePort), GetType(CyclePortDelegate)), CyclePortDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle)
            CheckErrors(status)

            Dim cDlg As CloseDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Close), GetType(CloseDelegate)), CloseDelegate)
            status = cDlg.Invoke(FtHandle)
            If (status = FT_STATUS.FT_OK) Then
                FtHandle = CLOSED_HANDLE
            End If
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Переводит устройство в заданный режим.
        ''' </summary>
        ''' <param name="mask">Задаёт направления выводов. 0 соответствует ВХОДУ, 1 - ВЫХОДУ.
        ''' В режиме CBUS Bit Bang, верхняя тетрада байта задаёт направление, а нижняя - уровень (0 - низкий, 1 - высокий).
        ''' </param>
        ''' <param name="bitMode">Режим работы.
        ''' <list type="bullet">
        ''' <item>Для FT232H валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MPSSE"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_CBUS_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MCU_HOST"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_FAST_SERIAL"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO"/>.</item>
        ''' <item>Для FT2232H валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MPSSE"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>, FT_BIT_MODE_MCU_HOST, FT_BIT_MODE_FAST_SERIAL, FT_BIT_MODE_SYNC_FIFO.</item>
        ''' <item>Для FT4232H валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MPSSE"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>.</item>
        ''' <item>Для FT232R валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_CBUS_BITBANG"/>.</item>
        ''' <item>Для FT245R валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>.</item>
        ''' <item>Для FT2232 валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MPSSE"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_SYNC_BITBANG"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_MCU_HOST"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_FAST_SERIAL"/>.</item>
        ''' <item>Для FT232B и FT245B валидны <see cref="FT_BIT_MODES.FT_BIT_MODE_RESET"/>, <see cref="FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG"/>.</item>
        ''' </list>
        ''' </param>
        Public Sub SetBitMode(mask As Byte, bitMode As FT_BIT_MODES)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            Select Case DeviceType
                Case FT_DEVICE.FT_DEVICE_AM
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)

                Case FT_DEVICE.FT_DEVICE_100AX
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)

                Case FT_DEVICE.FT_DEVICE_BM
                    If (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                        If ((bitMode And 1) = 0) Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                    End If

                Case FT_DEVICE.FT_DEVICE_2232
                    If (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                        If ((bitMode And &H1F) = 0) Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                        If (bitMode = FT_BIT_MODES.FT_BIT_MODE_MPSSE) AndAlso (Me.InterfaceIdentifier <> "A") Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                    End If

                Case FT_DEVICE.FT_DEVICE_232R
                    If (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                        If ((bitMode And 37) = 0) Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                    End If

                Case FT_DEVICE.FT_DEVICE_2232H
                    If (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                        If ((bitMode And 95) = 0) Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                        If ((bitMode = FT_BIT_MODES.FT_BIT_MODE_MCU_HOST) Or (bitMode = FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO)) AndAlso (Me.InterfaceIdentifier <> "A") Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                    End If

                Case FT_DEVICE.FT_DEVICE_4232H
                    If (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                        If ((bitMode And 7) = 0) Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                        If (bitMode = FT_BIT_MODES.FT_BIT_MODE_MPSSE) AndAlso (Me.InterfaceIdentifier <> "A") AndAlso (Me.InterfaceIdentifier <> "B") Then
                            CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                        End If
                    End If

                Case FT_DEVICE.FT_DEVICE_232H
                    If (bitMode > FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO) Then
                        CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                    End If
            End Select

            If (DeviceType = FT_DEVICE.FT_DEVICE_AM) Then
                CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_100AX) Then
                CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_BM) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                If ((bitMode And 1) = 0) Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_2232) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                If ((bitMode And &H1F) = 0) Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If
                If (bitMode = FT_BIT_MODES.FT_BIT_MODE_MPSSE) AndAlso (Me.InterfaceIdentifier <> "A") Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_232R) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                If ((bitMode And 37) = 0) Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_2232H) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                If ((bitMode And 95) = 0) Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If
                If ((bitMode = FT_BIT_MODES.FT_BIT_MODE_MCU_HOST) Or (bitMode = FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO)) AndAlso (Me.InterfaceIdentifier <> "A") Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_4232H) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) Then
                If ((bitMode And 7) = 0) Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If
                If (bitMode = FT_BIT_MODES.FT_BIT_MODE_MPSSE) AndAlso (Me.InterfaceIdentifier <> "A") AndAlso (Me.InterfaceIdentifier <> "B") Then
                    CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)
                End If

            ElseIf (DeviceType = FT_DEVICE.FT_DEVICE_232H) AndAlso (bitMode <> FT_BIT_MODES.FT_BIT_MODE_RESET) AndAlso (bitMode > FT_BIT_MODES.FT_BIT_MODE_SYNC_FIFO) Then
                CheckErrors(status, FT_ERROR.FT_INVALID_BITMODE)

            End If

            Dim dlg As SetBitModeDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_SetBitMode), GetType(SetBitModeDelegate)), SetBitModeDelegate)
            status = dlg.Invoke(FtHandle, mask, bitMode)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Возвращает состояние бита по индексу <paramref name="index"/>.
        ''' </summary>
        Public Function GetGpio(index As Integer) As Boolean
            Dim b As Byte = GetPinStates()
            Return CBool((b >> index) And 1)
        End Function

        ''' <summary>
        ''' Устанавливает для выбранного GPIO значение <paramref name="value"/>.
        ''' </summary>
        ''' <remarks>
        ''' 1 - ВЫХОД, 0 - ВХОД.
        ''' SetBitMode(0000_1111, Mode) 'all gpio high 
        ''' SetBitMode(0001_1111, Mode) 'gpio0 low
        ''' SetBitMode(0010_1111, Mode) 'gpio1 low
        ''' SetBitMode(0100_1111, Mode) 'gpio2 low
        ''' SetBitMode(1000_1111, Mode) 'gpio3 low
        ''' </remarks>
        Public Sub SetGpio(index As Integer, value As Boolean)
            If (index < 0) OrElse (index > 3) Then
                Throw New ArgumentException("Номер GPIO должен лежать в диапазоне от 0 до 3.")
            End If
            Dim b As Byte = GetPinStates()
            Dim bv As New Specialized.BitVector32(b)
            Dim shift As Integer = 4 + index
            bv(1 << shift) = value
            Dim mask As Byte = CByte(bv.Data Xor &HFF)
            SetBitMode(mask, FT_BIT_MODES.FT_BIT_MODE_ASYNC_BITBANG) 'TODO Проверить выставление GPIO!!!
        End Sub

        ''' <summary>
        ''' Получает данные от FT4222 используя командный интерфейс вендора.
        ''' </summary>
        Public Sub VendorCmdGet(request As UShort, buf As Byte(), len As UShort)
            Dim dlg As VendorCmdGetDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_VendorCmdGet), GetType(VendorCmdGetDelegate)), VendorCmdGetDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, request, buf, len)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Выставляет данные FT4222 используя командный интерфейс вендора.
        ''' </summary>
        Public Sub VendorCmdSet(request As UShort, buf As Byte(), len As UShort)
            Dim dlg As VendorCmdSetDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_VendorCmdSet), GetType(VendorCmdSetDelegate)), VendorCmdSetDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, request, buf, len)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Проверяет изменения состава аппаратуры на шине USB.
        ''' </summary>
        ''' <remarks>
        ''' Эквивалентно нажатию кнопки "Обновить конфигурацию оборудования" в менеджере устройств.
        ''' </remarks>
        Public Shared Sub Rescan()
            Dim dlg As RescanDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Rescan), GetType(RescanDelegate)), RescanDelegate)
            Dim status As FT_STATUS = dlg.Invoke()
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Принудительно перезагружает драйверы для устройств с заданными VID и PID.
        ''' </summary>
        ''' <remarks>Если VID и PID равны 0, будет перезагружен драйвер USB хаба, что вызовет перезагрузку всех подключённых к шине USB устройств.</remarks>
        Public Shared Sub Reload(vendorID As UShort, productID As UShort)
            Dim dlg As ReloadDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(Pft_Reload), GetType(ReloadDelegate)), ReloadDelegate)
            Dim status As FT_STATUS = dlg(vendorID, productID)
            CheckErrors(status)
        End Sub


#End Region '/УПРАВЛЕНИЕ

#Region "HELPERS"

        ''' <summary>
        ''' Проверяет результат выполнения метода и выбрасывает исключение, если статус с ошибкой.
        ''' </summary>
        Public Shared Sub CheckErrors(status As FT_STATUS, Optional additionalInfo As FT_ERROR = FT_ERROR.FT_NO_ERROR)
            Select Case status
                Case FT_STATUS.FT_OK
                    'ничего не делаем
                Case FT_STATUS.FT_OTHER_ERROR
                    Throw New FT_EXCEPTION("Ошибка при попытке соединения с устройством FTDI.")
                Case FT_STATUS.FT_INVALID_HANDLE
                    Throw New FT_EXCEPTION("Неверный дескриптор устройства FTDI.")
                Case FT_STATUS.FT_DEVICE_NOT_FOUND
                    Throw New FT_EXCEPTION("Устройство FTDI не найдено.")
                Case FT_STATUS.FT_DEVICE_NOT_OPENED
                    Throw New FT_EXCEPTION("Устройство FTDI не открыто.")
                Case FT_STATUS.FT_IO_ERROR
                    Throw New FT_EXCEPTION("Ошибка ввода-вывода устройства FTDI.")
                Case FT_STATUS.FT_INSUFFICIENT_RESOURCES
                    Throw New FT_EXCEPTION("Недостаточно ресурсов.")
                Case FT_STATUS.FT_INVALID_PARAMETER
                    Throw New FT_EXCEPTION("Неверный параметр вызываемой функции FTD2XX.")
                Case FT_STATUS.FT_INVALID_BAUD_RATE
                    Throw New FT_EXCEPTION("Неверный битрейт устройства FTDI.")
                Case FT_STATUS.FT_DEVICE_NOT_OPENED_FOR_ERASE
                    Throw New FT_EXCEPTION("Устройство FTDI не открыто для стирания ЭСППЗУ.")
                Case FT_STATUS.FT_DEVICE_NOT_OPENED_FOR_WRITE
                    Throw New FT_EXCEPTION("Устройство FTDI не открыто для записи.")
                Case FT_STATUS.FT_FAILED_TO_WRITE_DEVICE
                    Throw New FT_EXCEPTION("Сбой при попытке записи в устройство FTDI.")
                Case FT_STATUS.FT_EEPROM_READ_FAILED
                    Throw New FT_EXCEPTION("Сбой чтения EEPROM устройства FTDI.")
                Case FT_STATUS.FT_EEPROM_WRITE_FAILED
                    Throw New FT_EXCEPTION("Сбой записи EEPROM устройства FTDI.")
                Case FT_STATUS.FT_EEPROM_ERASE_FAILED
                    Throw New FT_EXCEPTION("Сбой при стирании EEPROM устройства FTDI.")
                Case FT_STATUS.FT_EEPROM_NOT_PRESENT
                    Throw New FT_EXCEPTION("EEPROM не подходит для устройства FTDI.")
                Case FT_STATUS.FT_EEPROM_NOT_PROGRAMMED
                    Throw New FT_EXCEPTION("EEPROM устройства FTDI не запрограммировано.")
                Case FT_STATUS.FT_INVALID_ARGS
                    Throw New FT_EXCEPTION("Неверные аргументы при вызове функции FTD2XX.")
            End Select
            Select Case additionalInfo
                Case FT_ERROR.FT_NO_ERROR
                    Return
                Case FT_ERROR.FT_INCORRECT_DEVICE
                    Throw New FT_EXCEPTION("Тип текущего устройства не совпадает со структурой памяти EEPROM.")
                Case FT_ERROR.FT_INVALID_BITMODE
                    Throw New FT_EXCEPTION("Указанный битовый режим не является допустимым для текущего устройства.")
                Case FT_ERROR.FT_BUFFER_SIZE
                    Throw New FT_EXCEPTION("Предоставленный буфер имеет недостаточный размер.")
                Case Else
                    Debug.WriteLine("Значение не содержится в перечислении FT_ERROR.")
            End Select
        End Sub

#End Region '/HELPERS

#Region "NATIVE"

        ''' <summary>
        ''' Задаёт произвольный путь к библиотеке ftd2xx.
        ''' </summary>
        Public Shared Sub SetLibraryPath(libPath As String)
            UnloadLibrary()
            _LibPath = libPath
        End Sub

        <DllImport("kernel32.dll", SetLastError:=True)>
        Private Shared Function LoadLibrary(dllToLoad As String) As Integer
        End Function

        <DllImport("kernel32.dll", SetLastError:=True)>
        Private Shared Function FreeLibrary(hModule As Integer) As Boolean
        End Function

        <DllImport("kernel32.dll", SetLastError:=True)>
        Private Shared Function GetProcAddress(hModule As Integer, procedureName As String) As Integer
        End Function

        ''' <summary>
        ''' Дескриптор библиотеки ftd2xx.
        ''' </summary>
        Private Shared ReadOnly Property Ftd2xxDllHandle As Integer
            Get
                If (_Ftd2xxDllHandle = CLOSED_HANDLE) Then
                    _Ftd2xxDllHandle = LoadLibrary(LibPath)
                    If (Not IsLibraryLoaded) Then
                        Throw New FT_EXCEPTION("Ошибка загрузки библиотеки ftd2xx.dll.")
                    End If
                    FindFunctionPointers()
                End If
                Return _Ftd2xxDllHandle
            End Get
        End Property
        Private Shared _Ftd2xxDllHandle As Integer = CLOSED_HANDLE

        Private Shared ReadOnly Property Pft_CreateDeviceInfoList As Integer
            Get
                If (_Pft_CreateDeviceInfoList = NOT_INIT) Then
                    _Pft_CreateDeviceInfoList = GetProcAddress(Ftd2xxDllHandle, "FT_CreateDeviceInfoList")
                End If
                Return _Pft_CreateDeviceInfoList
            End Get
        End Property
        Private Shared _Pft_CreateDeviceInfoList As Integer = NOT_INIT

        Private Shared ReadOnly Property Pft_Close As Integer
            Get
                If (_Pft_Close = NOT_INIT) Then
                    _Pft_Close = GetProcAddress(Ftd2xxDllHandle, "FT_Close")
                End If
                Return _Pft_Close
            End Get
        End Property
        Private Shared _Pft_Close As Integer = NOT_INIT

        Private Shared ReadOnly Property Pft_GetComPortNumber As Integer
            Get
                If (_Pft_GetComPortNumber = NOT_INIT) Then
                    _Pft_GetComPortNumber = GetProcAddress(Ftd2xxDllHandle, "FT_GetComPortNumber")
                End If
                Return _Pft_GetComPortNumber
            End Get
        End Property
        Private Shared _Pft_GetComPortNumber As Integer = NOT_INIT

        'Статические поля:
        Private Shared Pft_GetDeviceInfoDetail As Integer = NOT_INIT
        Private Shared Pft_Open As Integer = NOT_INIT
        Private Shared Pft_OpenEx As Integer = NOT_INIT
        Private Shared Pft_Read As Integer = NOT_INIT
        Private Shared Pft_Write As Integer = NOT_INIT
        Private Shared Pft_GetQueueStatus As Integer = NOT_INIT
        Private Shared Pft_GetModemStatus As Integer = NOT_INIT
        Private Shared Pft_GetStatus As Integer = NOT_INIT
        Private Shared Pft_SetBaudRate As Integer = NOT_INIT
        Private Shared Pft_SetDataCharacteristics As Integer = NOT_INIT
        Private Shared Pft_SetFlowControl As Integer = NOT_INIT
        Private Shared Pft_SetDtr As Integer = NOT_INIT
        Private Shared Pft_ClrDtr As Integer = NOT_INIT
        Private Shared Pft_SetRts As Integer = NOT_INIT
        Private Shared Pft_ClrRts As Integer = NOT_INIT
        Private Shared Pft_ResetDevice As Integer = NOT_INIT
        Private Shared Pft_ResetPort As Integer = NOT_INIT
        Private Shared Pft_CyclePort As Integer = NOT_INIT
        Private Shared Pft_Rescan As Integer = NOT_INIT
        Private Shared Pft_Reload As Integer = NOT_INIT
        Private Shared Pft_Purge As Integer = NOT_INIT
        Private Shared Pft_SetTimeouts As Integer = NOT_INIT
        Private Shared Pft_SetBreakOn As Integer = NOT_INIT
        Private Shared Pft_SetBreakOff As Integer = NOT_INIT
        Private Shared Pft_GetDeviceInfo As Integer = NOT_INIT
        Private Shared Pft_SetResetPipeRetryCount As Integer = NOT_INIT
        Private Shared Pft_StopInTask As Integer = NOT_INIT
        Private Shared Pft_RestartInTask As Integer = NOT_INIT
        Private Shared Pft_GetDriverVersion As Integer = NOT_INIT
        Private Shared Pft_SetDeadmanTimeout As Integer = NOT_INIT
        Private Shared Pft_SetChars As Integer = NOT_INIT
        Private Shared Pft_SetEventNotification As Integer = NOT_INIT
        Private Shared Pft_SetLatencyTimer As Integer = NOT_INIT
        Private Shared Pft_GetLatencyTimer As Integer = NOT_INIT
        Private Shared Pft_SetBitMode As Integer = NOT_INIT
        Private Shared Pft_GetBitMode As Integer = NOT_INIT
        Private Shared Pft_SetUSBParameters As Integer = NOT_INIT
        Private Shared Pft_VendorCmdGet As Integer = NOT_INIT
        Private Shared Pft_VendorCmdSet As Integer = NOT_INIT

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function CreateDeviceInfoListDelegate(ByRef numdevs As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetDeviceInfoDetailDelegate(index As UInteger, ByRef flags As UInteger, ByRef chiptype As FT_DEVICE, ByRef id As UInteger, ByRef locid As UInteger, serialnumber As Byte(), description As Byte(), ByRef ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function OpenDelegate(index As UInteger, ByRef ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function OpenExDelegate(devstring As String, dwFlags As FT_OPEN_BY, ByRef ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function OpenExLocDelegate(devloc As UInteger, dwFlags As UInteger, ByRef ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function CloseDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ReadDelegate(ftHandle As Integer, lpBuffer As Byte(), dwBytesToRead As UInteger, ByRef lpdwBytesReturned As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function WriteDelegate(ftHandle As Integer, lpBuffer As Byte(), dwBytesToWrite As UInteger, ByRef lpdwBytesWritten As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetQueueStatusDelegate(ftHandle As Integer, ByRef lpdwAmountInRxQueue As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetModemStatusDelegate(ftHandle As Integer, ByRef lpdwModemStatus As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetStatusDelegate(ftHandle As Integer, ByRef lpdwAmountInRxQueue As UInteger, ByRef lpdwAmountInTxQueue As UInteger, ByRef lpdwEventStatus As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetBaudRateDelegate(ftHandle As Integer, dwBaudRate As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetDataCharacteristicsDelegate(ftHandle As Integer, uWordLength As Byte, uStopBits As Byte, uParity As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetFlowControlDelegate(ftHandle As Integer, usFlowControl As UShort, uXon As Byte, uXoff As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetDtrDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ClrDtrDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetRtsDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ClrRtsDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ResetDeviceDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ResetPortDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function CyclePortDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function RescanDelegate() As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ReloadDelegate(wVID As UShort, wPID As UShort) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function PurgeDelegate(ftHandle As Integer, dwMask As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetTimeoutsDelegate(ftHandle As Integer, dwReadTimeout As UInteger, dwWriteTimeout As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetBreakOnDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetBreakOffDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetDeviceInfoDelegate(ftHandle As Integer, ByRef pftType As FT_DEVICE, ByRef lpdwID As UInteger, pcSerialNumber As Byte(), pcDescription As Byte(), pvDummy As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetResetPipeRetryCountDelegate(ftHandle As Integer, dwCount As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function StopInTaskDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function RestartInTaskDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetDriverVersionDelegate(ftHandle As Integer, ByRef lpdwDriverVersion As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetLibraryVersionDelegate(ByRef lpdwLibraryVersion As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetDeadmanTimeoutDelegate(ftHandle As Integer, dwDeadmanTimeout As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetCharsDelegate(ftHandle As Integer, uEventCh As Byte, uEventChEn As Byte, uErrorCh As Byte, uErrorChEn As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetEventNotificationDelegate(ftHandle As Integer, dwEventMask As UInteger, hEvent As SafeHandle) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetComPortNumberDelegate(ftHandle As Integer, ByRef dwComPortNumber As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetLatencyTimerDelegate(ftHandle As Integer, ucLatency As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetLatencyTimerDelegate(ftHandle As Integer, ByRef ucLatency As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetBitModeDelegate(ftHandle As Integer, ucMask As Byte, ucMode As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function GetBitModeDelegate(ftHandle As Integer, ByRef ucMode As Byte) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function SetUsbParametersDelegate(ftHandle As Integer, dwInTransferSize As UInteger, dwOutTransferSize As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function VendorCmdGetDelegate(ftHandle As Integer, request As UShort, buf As Byte(), len As UShort) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function VendorCmdSetDelegate(ftHandle As Integer, request As UShort, buf As Byte(), len As UShort) As FT_STATUS

        ''' <summary>
        ''' Ищет указатели на нативные функции в библиотеке ftd2xx.
        ''' </summary>
        Private Shared Sub FindFunctionPointers()
            If (Pft_GetDeviceInfoDetail = NOT_INIT) Then
                Pft_GetDeviceInfoDetail = GetProcAddress(Ftd2xxDllHandle, "FT_GetDeviceInfoDetail")
            End If
            If (Pft_Open = NOT_INIT) Then
                Pft_Open = GetProcAddress(Ftd2xxDllHandle, "FT_Open")
            End If
            If (Pft_OpenEx = NOT_INIT) Then
                Pft_OpenEx = GetProcAddress(Ftd2xxDllHandle, "FT_OpenEx")
            End If
            If (Pft_Read = NOT_INIT) Then
                Pft_Read = GetProcAddress(Ftd2xxDllHandle, "FT_Read")
            End If
            If (Pft_Write = NOT_INIT) Then
                Pft_Write = GetProcAddress(Ftd2xxDllHandle, "FT_Write")
            End If
            If (Pft_GetQueueStatus = NOT_INIT) Then
                Pft_GetQueueStatus = GetProcAddress(Ftd2xxDllHandle, "FT_GetQueueStatus")
            End If
            If (Pft_GetModemStatus = NOT_INIT) Then
                Pft_GetModemStatus = GetProcAddress(Ftd2xxDllHandle, "FT_GetModemStatus")
            End If
            If (Pft_GetStatus = NOT_INIT) Then
                Pft_GetStatus = GetProcAddress(Ftd2xxDllHandle, "FT_GetStatus")
            End If
            If (Pft_SetBaudRate = NOT_INIT) Then
                Pft_SetBaudRate = GetProcAddress(Ftd2xxDllHandle, "FT_SetBaudRate")
            End If
            If (Pft_SetDataCharacteristics = NOT_INIT) Then
                Pft_SetDataCharacteristics = GetProcAddress(Ftd2xxDllHandle, "FT_SetDataCharacteristics")
            End If
            If (Pft_SetFlowControl = NOT_INIT) Then
                Pft_SetFlowControl = GetProcAddress(Ftd2xxDllHandle, "FT_SetFlowControl")
            End If
            If (Pft_SetDtr = NOT_INIT) Then
                Pft_SetDtr = GetProcAddress(Ftd2xxDllHandle, "FT_SetDtr")
            End If
            If (Pft_ClrDtr = NOT_INIT) Then
                Pft_ClrDtr = GetProcAddress(Ftd2xxDllHandle, "FT_ClrDtr")
            End If
            If (Pft_SetRts = NOT_INIT) Then
                Pft_SetRts = GetProcAddress(Ftd2xxDllHandle, "FT_SetRts")
            End If
            If (Pft_ClrRts = NOT_INIT) Then
                Pft_ClrRts = GetProcAddress(Ftd2xxDllHandle, "FT_ClrRts")
            End If
            If (Pft_ResetDevice = NOT_INIT) Then
                Pft_ResetDevice = GetProcAddress(Ftd2xxDllHandle, "FT_ResetDevice")
            End If
            If (Pft_ResetPort = NOT_INIT) Then
                Pft_ResetPort = GetProcAddress(Ftd2xxDllHandle, "FT_ResetPort")
            End If
            If (Pft_CyclePort = NOT_INIT) Then
                Pft_CyclePort = GetProcAddress(Ftd2xxDllHandle, "FT_CyclePort")
            End If
            If (Pft_Rescan = NOT_INIT) Then
                Pft_Rescan = GetProcAddress(Ftd2xxDllHandle, "FT_Rescan")
            End If
            If (Pft_Reload = NOT_INIT) Then
                Pft_Reload = GetProcAddress(Ftd2xxDllHandle, "FT_Reload")
            End If
            If (Pft_Purge = NOT_INIT) Then
                Pft_Purge = GetProcAddress(Ftd2xxDllHandle, "FT_Purge")
            End If
            If (Pft_SetTimeouts = NOT_INIT) Then
                Pft_SetTimeouts = GetProcAddress(Ftd2xxDllHandle, "FT_SetTimeouts")
            End If
            If (Pft_SetBreakOn = NOT_INIT) Then
                Pft_SetBreakOn = GetProcAddress(Ftd2xxDllHandle, "FT_SetBreakOn")
            End If
            If (Pft_SetBreakOff = NOT_INIT) Then
                Pft_SetBreakOff = GetProcAddress(Ftd2xxDllHandle, "FT_SetBreakOff")
            End If
            If (Pft_GetDeviceInfo = NOT_INIT) Then
                Pft_GetDeviceInfo = GetProcAddress(Ftd2xxDllHandle, "FT_GetDeviceInfo")
            End If
            If (Pft_SetResetPipeRetryCount = NOT_INIT) Then
                Pft_SetResetPipeRetryCount = GetProcAddress(Ftd2xxDllHandle, "FT_SetResetPipeRetryCount")
            End If
            If (Pft_StopInTask = NOT_INIT) Then
                Pft_StopInTask = GetProcAddress(Ftd2xxDllHandle, "FT_StopInTask")
            End If
            If (Pft_RestartInTask = NOT_INIT) Then
                Pft_RestartInTask = GetProcAddress(Ftd2xxDllHandle, "FT_RestartInTask")
            End If
            If (Pft_GetDriverVersion = NOT_INIT) Then
                Pft_GetDriverVersion = GetProcAddress(Ftd2xxDllHandle, "FT_GetDriverVersion")
            End If
            If (Pft_SetDeadmanTimeout = NOT_INIT) Then
                Pft_SetDeadmanTimeout = GetProcAddress(Ftd2xxDllHandle, "FT_SetDeadmanTimeout")
            End If
            If (Pft_SetChars = NOT_INIT) Then
                Pft_SetChars = GetProcAddress(Ftd2xxDllHandle, "FT_SetChars")
            End If
            If (Pft_SetEventNotification = NOT_INIT) Then
                Pft_SetEventNotification = GetProcAddress(Ftd2xxDllHandle, "FT_SetEventNotification")
            End If
            If (Pft_SetLatencyTimer = NOT_INIT) Then
                Pft_SetLatencyTimer = GetProcAddress(Ftd2xxDllHandle, "FT_SetLatencyTimer")
            End If
            If (Pft_GetLatencyTimer = NOT_INIT) Then
                Pft_GetLatencyTimer = GetProcAddress(Ftd2xxDllHandle, "FT_GetLatencyTimer")
            End If
            If (Pft_SetBitMode = NOT_INIT) Then
                Pft_SetBitMode = GetProcAddress(Ftd2xxDllHandle, "FT_SetBitMode")
            End If
            If (Pft_GetBitMode = NOT_INIT) Then
                Pft_GetBitMode = GetProcAddress(Ftd2xxDllHandle, "FT_GetBitMode")
            End If
            If (Pft_SetUSBParameters = NOT_INIT) Then
                Pft_SetUSBParameters = GetProcAddress(Ftd2xxDllHandle, "FT_SetUSBParameters")
            End If
            If (Pft_VendorCmdGet = NOT_INIT) Then
                Pft_VendorCmdGet = GetProcAddress(Ftd2xxDllHandle, "FT_VendorCmdGet")
            End If
            If (Pft_VendorCmdSet = NOT_INIT) Then
                Pft_VendorCmdSet = GetProcAddress(Ftd2xxDllHandle, "FT_VendorCmdSet")
            End If
        End Sub

#End Region '/NATIVE

#Region "NESTED TYPES"

        Public Enum FT_STATUS
            FT_OK
            FT_INVALID_HANDLE
            FT_DEVICE_NOT_FOUND
            FT_DEVICE_NOT_OPENED
            FT_IO_ERROR
            FT_INSUFFICIENT_RESOURCES
            FT_INVALID_PARAMETER
            FT_INVALID_BAUD_RATE
            FT_DEVICE_NOT_OPENED_FOR_ERASE
            FT_DEVICE_NOT_OPENED_FOR_WRITE
            FT_FAILED_TO_WRITE_DEVICE
            FT_EEPROM_READ_FAILED
            FT_EEPROM_WRITE_FAILED
            FT_EEPROM_ERASE_FAILED
            FT_EEPROM_NOT_PRESENT
            FT_EEPROM_NOT_PROGRAMMED
            FT_INVALID_ARGS
            FT_OTHER_ERROR
        End Enum

        Public Enum FT_OPEN_BY As UInteger
            SERIAL_NUMBER = 1UI
            DESCRIPTION = 2UI
            LOCATION = 4UI
        End Enum

        Public Enum FT_ERROR
            FT_NO_ERROR
            FT_INCORRECT_DEVICE
            FT_INVALID_BITMODE
            FT_BUFFER_SIZE
        End Enum

        Public Enum FT_DATA_BITS As Byte
            FT_BITS_7 = 7
            FT_BITS_8 = 8
        End Enum

        Public Enum FT_STOP_BITS As Byte
            FT_STOP_BITS_1 = 0
            FT_STOP_BITS_2 = 2
        End Enum

        Public Enum FT_PARITY As Byte
            FT_PARITY_NONE
            FT_PARITY_ODD
            FT_PARITY_EVEN
            FT_PARITY_MARK
            FT_PARITY_SPACE
        End Enum

        <Flags()>
        Public Enum FT_FLOW_CONTROL As UShort
            FT_FLOW_NONE = &H0
            FT_FLOW_RTS_CTS = &H100
            FT_FLOW_DTR_DSR = &H200
            FT_FLOW_XON_XOFF = &H400
        End Enum

        ''' <summary>
        ''' Purge buffer constant definitions.
        ''' </summary>
        <Flags()>
        Public Enum FT_PURGE As Byte
            ''' <summary>
            ''' Очистить приёмный буфер.
            ''' </summary>
            FT_PURGE_RX = 1
            ''' <summary>
            ''' Очистить передающий буфер.
            ''' </summary>
            FT_PURGE_TX = 2
        End Enum

        <Flags()>
        Public Enum FT_MODEM_STATUS As Byte
            None = 0
            ''' <summary>
            ''' Состояние модема "Clear To Send".
            ''' </summary>
            FT_CTS = &H10
            ''' <summary>
            ''' Состояние модема "Data Set Ready".
            ''' </summary>
            FT_DSR = &H20
            ''' <summary>
            ''' Состояние модема "Ring Indicator".
            ''' </summary>
            FT_RI = &H40
            ''' <summary>
            ''' Состояние модема "Data Carrier Detect".
            ''' </summary>
            FT_DCD = &H80
        End Enum

        <Flags()>
        Public Enum FT_LINE_STATUS As Byte
            None = 0
            ''' <summary>
            ''' Статус линии "Overrun Error".
            ''' </summary>
            FT_OE = 2
            ''' <summary>
            ''' Статус линии "Parity Error".
            ''' </summary>
            FT_PE = 4
            ''' <summary>
            ''' Статус линии "Framing Error".
            ''' </summary>
            FT_FE = 8
            ''' <summary>
            ''' Статус линии "Break Interrupt".
            ''' </summary>
            FT_BI = 16
        End Enum

        <Flags()>
        Public Enum FT_EVENTS As UInteger
            ''' <summary>
            ''' Событие по получению управляющего символа.
            ''' </summary>
            FT_EVENT_RXCHAR = 1UI
            ''' <summary>
            ''' Событие по изменению статуса модема.
            ''' </summary>
            FT_EVENT_MODEM_STATUS = 2UI
            ''' <summary>
            ''' Событие по изменению статуса линии.
            ''' </summary>
            FT_EVENT_LINE_STATUS = 4UI
        End Enum

        <Flags()>
        Public Enum FT_BIT_MODES As Byte
            FT_BIT_MODE_RESET = 0
            FT_BIT_MODE_ASYNC_BITBANG = 1
            FT_BIT_MODE_MPSSE = 2
            FT_BIT_MODE_SYNC_BITBANG = 4
            FT_BIT_MODE_MCU_HOST = 8
            FT_BIT_MODE_FAST_SERIAL = 16
            FT_BIT_MODE_CBUS_BITBANG = 32
            FT_BIT_MODE_SYNC_FIFO = 64
        End Enum

        Public Enum FT_CBUS_OPTIONS As Byte
            FT_CBUS_TXDEN
            FT_CBUS_PWRON
            FT_CBUS_RXLED
            FT_CBUS_TXLED
            FT_CBUS_TXRXLED
            FT_CBUS_SLEEP
            FT_CBUS_CLK48
            FT_CBUS_CLK24
            FT_CBUS_CLK12
            FT_CBUS_CLK6
            FT_CBUS_IOMODE
            FT_CBUS_BITBANG_WR
            FT_CBUS_BITBANG_RD
        End Enum

        Public Enum FT_232H_CBUS_OPTIONS As Byte
            FT_CBUS_TRISTATE
            FT_CBUS_RXLED
            FT_CBUS_TXLED
            FT_CBUS_TXRXLED
            FT_CBUS_PWREN
            FT_CBUS_SLEEP
            FT_CBUS_DRIVE_0
            FT_CBUS_DRIVE_1
            FT_CBUS_IOMODE
            FT_CBUS_TXDEN
            FT_CBUS_CLK30
            FT_CBUS_CLK15
            FT_CBUS_CLK7_5
        End Enum

        Public Enum FT_XSERIES_CBUS_OPTIONS As Byte
            FT_CBUS_TRISTATE
            FT_CBUS_RXLED
            FT_CBUS_TXLED
            FT_CBUS_TXRXLED
            FT_CBUS_PWREN
            FT_CBUS_SLEEP
            FT_CBUS_Drive_0
            FT_CBUS_Drive_1
            FT_CBUS_GPIO
            FT_CBUS_TXDEN
            FT_CBUS_CLK24MHz
            FT_CBUS_CLK12MHz
            FT_CBUS_CLK6MHz
            FT_CBUS_BCD_Charger
            FT_CBUS_BCD_Charger_N
            FT_CBUS_I2C_TXE
            FT_CBUS_I2C_RXF
            FT_CBUS_VBUS_Sense
            FT_CBUS_BitBang_WR
            FT_CBUS_BitBang_RD
            FT_CBUS_Time_Stamp
            FT_CBUS_Keep_Awake
        End Enum

        Public Enum FT_FLAGS As UInteger
            FT_FLAGS_OPENED = 1UI
            FT_FLAGS_HISPEED = 2UI
        End Enum

        Public Enum FT_DRIVE_CURRENT As Byte
            FT_DRIVE_CURRENT_4MA = 4
            FT_DRIVE_CURRENT_8MA = 8
            FT_DRIVE_CURRENT_12MA = 12
            FT_DRIVE_CURRENT_16MA = 16
        End Enum

        Public Enum FT_DEVICE As UInteger
            FT_DEVICE_BM = 0
            FT_DEVICE_AM
            FT_DEVICE_100AX
            FT_DEVICE_UNKNOWN
            FT_DEVICE_2232
            FT_DEVICE_232R
            FT_DEVICE_2232H
            FT_DEVICE_4232H
            FT_DEVICE_232H
            FT_DEVICE_X_SERIES
            FT_DEVICE_4222H_0
            FT_DEVICE_4222H_1_2
            FT_DEVICE_4222H_3
            FT_DEVICE_4222_PROG
        End Enum

        Public Structure FT_DEVICE_INFO_NODE
            Public Flags As UInteger
            Public Type As FT_DEVICE
            Public ID As UInteger
            Public LocId As UInteger
            Public SerialNumber As String
            Public Description As String
            Public FtHandle As Integer
        End Structure

        <Serializable()>
        Public Class FT_EXCEPTION
            Inherits Exception

            Public Sub New()
            End Sub

            Public Sub New(message As String)
                MyBase.New(message)
            End Sub

            Public Sub New(message As String, inner As Exception)
                MyBase.New(message, inner)
            End Sub

            Protected Sub New(info As SerializationInfo, context As StreamingContext)
                MyBase.New(info, context)
            End Sub

        End Class '/FT_EXCEPTION

#End Region '/NESTED TYPES

#Region "DISPOSABLE"

        Private DisposedValue As Boolean

        Protected Overridable Sub Dispose(disposing As Boolean)
            If (Not DisposedValue) Then
                If disposing Then
                    Close()
                End If
                DisposedValue = True
            End If
        End Sub

        Public Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub

#End Region '/DISPOSABLE

    End Class '/Ftdi

End Namespace

Также большой по объёму класс Eeprom. Он содержит большое число структур, которые описывают то, каким образом хранятся данные в ППЗУ различных типов микросхем FTDI. Если вы не планируете работать с ПЗУ своей микросхемы, то можно не использовать этот класс. Для этого следует исключить из только что описанного класса Ftdi свойство Eeprom.

Функции для работы с ППЗУ микросхем FTDI
Imports System.Runtime.InteropServices
Imports System.Text
Imports FTD2XX_NET.Ftdi

Namespace FTD2XX_NET

    ''' <summary>
    ''' Работа с ППЗУ микросхем FTDI.
    ''' </summary>
    Public Class Eeprom

#Region "CTOR"

        Private ReadOnly FtHandle As Integer
        Private ReadOnly DeviceType As FT_DEVICE

        Friend Sub New(ftDllHandle As Integer, ftHandle As Integer, devType As FT_DEVICE)
            Me.FtHandle = ftHandle
            Me.DeviceType = devType
            FindEeFunctionPointers(ftDllHandle)
        End Sub

#End Region '/CTOR

#Region "ЧТЕНИЕ ППЗУ"

        ''' <summary>
        ''' Читает из ПЗУ и возвращает одно слово данных по адресу <paramref name="address"/>.
        ''' </summary>
        ''' <param name="address">Адрес ячейки памяти.</param>
        Public Function ReadEeprom(address As UInteger) As UShort
            Dim value As UShort
            Dim dlg As ReadEeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_ReadEE, IntPtr), GetType(ReadEeDelegate)), ReadEeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, address, value)
            CheckErrors(status)
            Return value
        End Function

        ''' <summary>
        ''' Читает данные из ПЗУ устройства.
        ''' </summary>
        Public Function ReadEeprom() As FT_EEPROM_DATA
            Select Case DeviceType
                Case FT_DEVICE.FT_DEVICE_BM
                    Return ReadFt232bEeprom()
                Case FT_DEVICE.FT_DEVICE_2232
                    Return ReadFt2232Eeprom()
                Case FT_DEVICE.FT_DEVICE_232R
                    Return ReadFt232rEeprom()
                Case FT_DEVICE.FT_DEVICE_2232H
                    Return ReadFt2232hEeprom()
                Case FT_DEVICE.FT_DEVICE_4232H
                    Return ReadFt4232hEeprom()
                Case FT_DEVICE.FT_DEVICE_232H
                    Return ReadFt232hEeprom()
                Case FT_DEVICE.FT_DEVICE_X_SERIES
                    Return ReadXSeriesEeprom()
            End Select
            Throw New FT_EXCEPTION("Ошибка чтения ППЗУ.")
        End Function

        Private Function ReadFt232bEeprom() As FT232B_EEPROM_STRUCTURE
            Dim ee232b As New FT232B_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim dlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Read, IntPtr), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, programData)
            ee232b.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee232b.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee232b.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee232b.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee232b.VendorID = programData.VendorID
            ee232b.ProductID = programData.ProductID
            ee232b.MaxPower = programData.MaxPower
            ee232b.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee232b.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee232b.PullDownEnable = Convert.ToBoolean(programData.PullDownEnable)
            ee232b.SerNumEnable = Convert.ToBoolean(programData.SerNumEnable)
            ee232b.USBVersionEnable = Convert.ToBoolean(programData.USBVersionEnable)
            ee232b.USBVersion = programData.USBVersion
            Return ee232b
        End Function

        Private Function ReadFt2232Eeprom() As FT2232_EEPROM_STRUCTURE
            Dim ee2232 As New FT2232_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim dlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Read, IntPtr), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, programData)
            ee2232.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee2232.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee2232.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee2232.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee2232.VendorID = programData.VendorID
            ee2232.ProductID = programData.ProductID
            ee2232.MaxPower = programData.MaxPower
            ee2232.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee2232.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee2232.PullDownEnable = Convert.ToBoolean(programData.PullDownEnable5)
            ee2232.SerNumEnable = Convert.ToBoolean(programData.SerNumEnable5)
            ee2232.USBVersionEnable = Convert.ToBoolean(programData.USBVersionEnable5)
            ee2232.USBVersion = programData.USBVersion5
            ee2232.AIsHighCurrent = Convert.ToBoolean(programData.AIsHighCurrent)
            ee2232.BIsHighCurrent = Convert.ToBoolean(programData.BIsHighCurrent)
            ee2232.IFAIsFifo = Convert.ToBoolean(programData.IFAIsFifo)
            ee2232.IFAIsFifoTar = Convert.ToBoolean(programData.IFAIsFifoTar)
            ee2232.IFAIsFastSer = Convert.ToBoolean(programData.IFAIsFastSer)
            ee2232.AIsVCP = Convert.ToBoolean(programData.AIsVCP)
            ee2232.IFBIsFifo = Convert.ToBoolean(programData.IFBIsFifo)
            ee2232.IFBIsFifoTar = Convert.ToBoolean(programData.IFBIsFifoTar)
            ee2232.IFBIsFastSer = Convert.ToBoolean(programData.IFBIsFastSer)
            ee2232.BIsVCP = Convert.ToBoolean(programData.BIsVCP)
            Return ee2232
        End Function

        Private Function ReadFt232rEeprom() As FT232R_EEPROM_STRUCTURE
            Dim ee232r As New FT232R_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim rdDlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Read, IntPtr), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = rdDlg(FtHandle, programData)
            ee232r.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee232r.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee232r.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee232r.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee232r.VendorID = programData.VendorID
            ee232r.ProductID = programData.ProductID
            ee232r.MaxPower = programData.MaxPower
            ee232r.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee232r.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee232r.UseExtOsc = Convert.ToBoolean(programData.UseExtOsc)
            ee232r.HighDriveIOs = Convert.ToBoolean(programData.HighDriveIOs)
            ee232r.EndpointSize = programData.EndpointSize
            ee232r.PullDownEnable = Convert.ToBoolean(programData.PullDownEnableR)
            ee232r.SerNumEnable = Convert.ToBoolean(programData.SerNumEnableR)
            ee232r.InvertTXD = Convert.ToBoolean(programData.InvertTXD)
            ee232r.InvertRXD = Convert.ToBoolean(programData.InvertRXD)
            ee232r.InvertRTS = Convert.ToBoolean(programData.InvertRTS)
            ee232r.InvertCTS = Convert.ToBoolean(programData.InvertCTS)
            ee232r.InvertDTR = Convert.ToBoolean(programData.InvertDTR)
            ee232r.InvertDSR = Convert.ToBoolean(programData.InvertDSR)
            ee232r.InvertDCD = Convert.ToBoolean(programData.InvertDCD)
            ee232r.InvertRI = Convert.ToBoolean(programData.InvertRI)
            ee232r.Cbus0 = programData.Cbus0
            ee232r.Cbus1 = programData.Cbus1
            ee232r.Cbus2 = programData.Cbus2
            ee232r.Cbus3 = programData.Cbus3
            ee232r.Cbus4 = programData.Cbus4
            ee232r.RIsD2XX = Convert.ToBoolean(programData.RIsD2XX)
            Return ee232r
        End Function

        Private Function ReadFt2232hEeprom() As FT2232H_EEPROM_STRUCTURE
            Dim ee2232h As New FT2232H_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 3UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim dlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Read, IntPtr), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, programData)
            ee2232h.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee2232h.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee2232h.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee2232h.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee2232h.VendorID = programData.VendorID
            ee2232h.ProductID = programData.ProductID
            ee2232h.MaxPower = programData.MaxPower
            ee2232h.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee2232h.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee2232h.PullDownEnable = Convert.ToBoolean(programData.PullDownEnable7)
            ee2232h.SerNumEnable = Convert.ToBoolean(programData.SerNumEnable7)
            ee2232h.ALSlowSlew = Convert.ToBoolean(programData.ALSlowSlew)
            ee2232h.ALSchmittInput = Convert.ToBoolean(programData.ALSchmittInput)
            ee2232h.ALDriveCurrent = programData.ALDriveCurrent
            ee2232h.AHSlowSlew = Convert.ToBoolean(programData.AHSlowSlew)
            ee2232h.AHSchmittInput = Convert.ToBoolean(programData.AHSchmittInput)
            ee2232h.AHDriveCurrent = programData.AHDriveCurrent
            ee2232h.BLSlowSlew = Convert.ToBoolean(programData.BLSlowSlew)
            ee2232h.BLSchmittInput = Convert.ToBoolean(programData.BLSchmittInput)
            ee2232h.BLDriveCurrent = programData.BLDriveCurrent
            ee2232h.BHSlowSlew = Convert.ToBoolean(programData.BHSlowSlew)
            ee2232h.BHSchmittInput = Convert.ToBoolean(programData.BHSchmittInput)
            ee2232h.BHDriveCurrent = programData.BHDriveCurrent
            ee2232h.IFAIsFifo = Convert.ToBoolean(programData.IFAIsFifo7)
            ee2232h.IFAIsFifoTar = Convert.ToBoolean(programData.IFAIsFifoTar7)
            ee2232h.IFAIsFastSer = Convert.ToBoolean(programData.IFAIsFastSer7)
            ee2232h.AIsVCP = Convert.ToBoolean(programData.AIsVCP7)
            ee2232h.IFBIsFifo = Convert.ToBoolean(programData.IFBIsFifo7)
            ee2232h.IFBIsFifoTar = Convert.ToBoolean(programData.IFBIsFifoTar7)
            ee2232h.IFBIsFastSer = Convert.ToBoolean(programData.IFBIsFastSer7)
            ee2232h.BIsVCP = Convert.ToBoolean(programData.BIsVCP7)
            ee2232h.PowerSaveEnable = Convert.ToBoolean(programData.PowerSaveEnable)
            Return ee2232h
        End Function

        Private Function ReadFt4232hEeprom() As FT4232H_EEPROM_STRUCTURE
            Dim ee4232h As New FT4232H_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 4UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim dlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Read, IntPtr), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, programData)
            ee4232h.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee4232h.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee4232h.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee4232h.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee4232h.VendorID = programData.VendorID
            ee4232h.ProductID = programData.ProductID
            ee4232h.MaxPower = programData.MaxPower
            ee4232h.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee4232h.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee4232h.PullDownEnable = Convert.ToBoolean(programData.PullDownEnable8)
            ee4232h.SerNumEnable = Convert.ToBoolean(programData.SerNumEnable8)
            ee4232h.ASlowSlew = Convert.ToBoolean(programData.ASlowSlew)
            ee4232h.ASchmittInput = Convert.ToBoolean(programData.ASchmittInput)
            ee4232h.ADriveCurrent = programData.ADriveCurrent
            ee4232h.BSlowSlew = Convert.ToBoolean(programData.BSlowSlew)
            ee4232h.BSchmittInput = Convert.ToBoolean(programData.BSchmittInput)
            ee4232h.BDriveCurrent = programData.BDriveCurrent
            ee4232h.CSlowSlew = Convert.ToBoolean(programData.CSlowSlew)
            ee4232h.CSchmittInput = Convert.ToBoolean(programData.CSchmittInput)
            ee4232h.CDriveCurrent = programData.CDriveCurrent
            ee4232h.DSlowSlew = Convert.ToBoolean(programData.DSlowSlew)
            ee4232h.DSchmittInput = Convert.ToBoolean(programData.DSchmittInput)
            ee4232h.DDriveCurrent = programData.DDriveCurrent
            ee4232h.ARIIsTXDEN = Convert.ToBoolean(programData.ARIIsTXDEN)
            ee4232h.BRIIsTXDEN = Convert.ToBoolean(programData.BRIIsTXDEN)
            ee4232h.CRIIsTXDEN = Convert.ToBoolean(programData.CRIIsTXDEN)
            ee4232h.DRIIsTXDEN = Convert.ToBoolean(programData.DRIIsTXDEN)
            ee4232h.AIsVCP = Convert.ToBoolean(programData.AIsVCP8)
            ee4232h.BIsVCP = Convert.ToBoolean(programData.BIsVCP8)
            ee4232h.CIsVCP = Convert.ToBoolean(programData.CIsVCP8)
            ee4232h.DIsVCP = Convert.ToBoolean(programData.DIsVCP8)
            Return ee4232h
        End Function

        Private Function ReadFt232hEeprom() As FT232H_EEPROM_STRUCTURE
            Dim ee232h As New FT232H_EEPROM_STRUCTURE()
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 5UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16)
            }
            Dim dlg As EeReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(PFt_EE_Read), GetType(EeReadDelegate)), EeReadDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, programData)
            ee232h.Manufacturer = Marshal.PtrToStringAnsi(programData.Manufacturer)
            ee232h.ManufacturerID = Marshal.PtrToStringAnsi(programData.ManufacturerID)
            ee232h.Description = Marshal.PtrToStringAnsi(programData.Description)
            ee232h.SerialNumber = Marshal.PtrToStringAnsi(programData.SerialNumber)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            ee232h.VendorID = programData.VendorID
            ee232h.ProductID = programData.ProductID
            ee232h.MaxPower = programData.MaxPower
            ee232h.SelfPowered = Convert.ToBoolean(programData.SelfPowered)
            ee232h.RemoteWakeup = Convert.ToBoolean(programData.RemoteWakeup)
            ee232h.PullDownEnable = Convert.ToBoolean(programData.PullDownEnableH)
            ee232h.SerNumEnable = Convert.ToBoolean(programData.SerNumEnableH)
            ee232h.ACSlowSlew = Convert.ToBoolean(programData.ACSlowSlewH)
            ee232h.ACSchmittInput = Convert.ToBoolean(programData.ACSchmittInputH)
            ee232h.ACDriveCurrent = programData.ACDriveCurrentH
            ee232h.ADSlowSlew = Convert.ToBoolean(programData.ADSlowSlewH)
            ee232h.ADSchmittInput = Convert.ToBoolean(programData.ADSchmittInputH)
            ee232h.ADDriveCurrent = programData.ADDriveCurrentH
            ee232h.Cbus0 = CType(programData.Cbus0H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus1 = CType(programData.Cbus1H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus2 = CType(programData.Cbus2H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus3 = CType(programData.Cbus3H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus4 = CType(programData.Cbus4H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus5 = CType(programData.Cbus5H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus6 = CType(programData.Cbus6H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus7 = CType(programData.Cbus7H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus8 = CType(programData.Cbus8H, FT_232H_CBUS_OPTIONS)
            ee232h.Cbus9 = CType(programData.Cbus9H, FT_232H_CBUS_OPTIONS)
            ee232h.IsFifo = Convert.ToBoolean(programData.IsFifoH)
            ee232h.IsFifoTar = Convert.ToBoolean(programData.IsFifoTarH)
            ee232h.IsFastSer = Convert.ToBoolean(programData.IsFastSerH)
            ee232h.IsFT1248 = Convert.ToBoolean(programData.IsFT1248H)
            ee232h.FT1248Cpol = Convert.ToBoolean(programData.FT1248CpolH)
            ee232h.FT1248Lsb = Convert.ToBoolean(programData.FT1248LsbH)
            ee232h.FT1248FlowControl = Convert.ToBoolean(programData.FT1248FlowControlH)
            ee232h.IsVCP = Convert.ToBoolean(programData.IsVCPH)
            ee232h.PowerSaveEnable = Convert.ToBoolean(programData.PowerSaveEnableH)
            Return ee232h
        End Function

        Private Function ReadXSeriesEeprom() As FT_XSERIES_EEPROM_STRUCTURE
            Dim eeX As New FT_XSERIES_EEPROM_STRUCTURE()
            Dim header As New FT_EEPROM_HEADER() With {.DeviceType = FT_DEVICE.FT_DEVICE_X_SERIES}
            Dim programData As New FT_XSERIES_DATA() With {.common = header}
            Dim strSize As Integer = Marshal.SizeOf(programData)
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(strSize)
            Marshal.StructureToPtr(programData, intPtr, False)
            Dim man As Byte() = New Byte(31) {}
            Dim id As Byte() = New Byte(15) {}
            Dim descr As Byte() = New Byte(63) {}
            Dim sn As Byte() = New Byte(15) {}
            Dim dlg As EepromReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(PFt_EEPROM_Read), GetType(EepromReadDelegate)), EepromReadDelegate)
            Dim status As FT_STATUS = dlg.Invoke(FtHandle, intPtr, CUInt(strSize), man, id, descr, sn)
            programData = CType(Marshal.PtrToStructure(intPtr, GetType(FT_XSERIES_DATA)), FT_XSERIES_DATA)
            Dim utf8Encoding As New UTF8Encoding()
            eeX.Manufacturer = utf8Encoding.GetString(man)
            eeX.ManufacturerID = utf8Encoding.GetString(id)
            eeX.Description = utf8Encoding.GetString(descr)
            eeX.SerialNumber = utf8Encoding.GetString(sn)
            eeX.VendorID = programData.common.VendorId
            eeX.ProductID = programData.common.ProductId
            eeX.MaxPower = programData.common.MaxPower
            eeX.SelfPowered = Convert.ToBoolean(programData.common.SelfPowered)
            eeX.RemoteWakeup = Convert.ToBoolean(programData.common.RemoteWakeup)
            eeX.SerNumEnable = Convert.ToBoolean(programData.common.SerNumEnable)
            eeX.PullDownEnable = Convert.ToBoolean(programData.common.PullDownEnable)
            eeX.Cbus0 = CType(programData.Cbus0, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus1 = CType(programData.Cbus1, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus2 = CType(programData.Cbus2, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus3 = CType(programData.Cbus3, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus4 = CType(programData.Cbus4, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus5 = CType(programData.Cbus5, FT_XSERIES_CBUS_OPTIONS)
            eeX.Cbus6 = CType(programData.Cbus6, FT_XSERIES_CBUS_OPTIONS)
            eeX.ACDriveCurrent = programData.ACDriveCurrent
            eeX.ACSchmittInput = programData.ACSchmittInput
            eeX.ACSlowSlew = programData.ACSlowSlew
            eeX.ADDriveCurrent = programData.ADDriveCurrent
            eeX.ADSchmittInput = programData.ADSchmittInput
            eeX.ADSlowSlew = programData.ADSlowSlew
            eeX.BCDDisableSleep = programData.BCDDisableSleep
            eeX.BCDEnable = programData.BCDEnable
            eeX.BCDForceCbusPWREN = programData.BCDForceCbusPWREN
            eeX.FT1248Cpol = programData.FT1248Cpol
            eeX.FT1248FlowControl = programData.FT1248FlowControl
            eeX.FT1248Lsb = programData.FT1248Lsb
            eeX.I2CDeviceId = programData.I2CDeviceId
            eeX.I2CDisableSchmitt = programData.I2CDisableSchmitt
            eeX.I2CSlaveAddress = programData.I2CSlaveAddress
            eeX.InvertCTS = programData.InvertCTS
            eeX.InvertDCD = programData.InvertDCD
            eeX.InvertDSR = programData.InvertDSR
            eeX.InvertDTR = programData.InvertDTR
            eeX.InvertRI = programData.InvertRI
            eeX.InvertRTS = programData.InvertRTS
            eeX.InvertRXD = programData.InvertRXD
            eeX.InvertTXD = programData.InvertTXD
            eeX.PowerSaveEnable = programData.PowerSaveEnable
            eeX.RS485EchoSuppress = programData.RS485EchoSuppress
            eeX.IsVCP = programData.DriverType
            Marshal.DestroyStructure(intPtr, GetType(FT_XSERIES_DATA))
            Marshal.FreeHGlobal(intPtr)
            CheckErrors(status) 'статус проверяем после выгрузки всех неуправляемых ресурсов
            Return eeX
        End Function

#End Region '/ЧТЕНИЕ ППЗУ

#Region "ЗАПИСЬ ППЗУ"

        ''' <summary>
        ''' Стирает ПЗУ устройства.
        ''' </summary>
        ''' <remarks>
        ''' Для устройств FT232R и FT245R функция недоступна.
        ''' </remarks>
        Public Sub EraseEeprom()
            If (DeviceType = FT_DEVICE.FT_DEVICE_232R) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER, FT_ERROR.FT_INCORRECT_DEVICE)
            End If
            Dim dlg As EraseEeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EraseEE, IntPtr), GetType(EraseEeDelegate)), EraseEeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Записывает в ПЗУ по заданному адресу <paramref name="address"/> слово данных <paramref name="value"/>.
        ''' </summary>
        Public Sub WriteEeprom(address As UInteger, value As UShort)
            Dim dlg As WriteEeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_WriteEE, IntPtr), GetType(WriteEeDelegate)), WriteEeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, address, value)
            CheckErrors(status)
        End Sub

        ''' <summary>
        ''' Записывает заданную конфигурацию <paramref name="data"/> в ПЗУ микросхемы FTDI.
        ''' </summary>
        Public Sub WriteEeprom(data As FT_EEPROM_DATA)
            Select Case DeviceType
                Case FT_DEVICE.FT_DEVICE_BM
                    WriteFt232bEeprom(CType(data, FT232B_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_2232
                    WriteFt2232Eeprom(CType(data, FT2232_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_232R
                    WriteFt232rEeprom(CType(data, FT232R_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_2232H
                    WriteFt2232hEeprom(CType(data, FT2232H_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_4232H
                    WriteFt4232hEeprom(CType(data, FT4232H_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_232H
                    WriteFt232hEeprom(CType(data, FT232H_EEPROM_STRUCTURE))
                Case FT_DEVICE.FT_DEVICE_X_SERIES
                    WriteXSeriesEeprom(CType(data, FT_XSERIES_EEPROM_STRUCTURE))
                Case Else
                    CheckErrors(FT_STATUS.FT_OTHER_ERROR, FT_ERROR.FT_INCORRECT_DEVICE)
            End Select
        End Sub

        Private Sub WriteFt232bEeprom(ee232b As FT232B_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee232b.VendorID = 0US) OrElse (ee232b.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee232b.Manufacturer.Length > 32) Then
                ee232b.Manufacturer = ee232b.Manufacturer.Substring(0, 32)
            End If
            If (ee232b.ManufacturerID.Length > 16) Then
                ee232b.ManufacturerID = ee232b.ManufacturerID.Substring(0, 16)
            End If
            If (ee232b.Description.Length > 64) Then
                ee232b.Description = ee232b.Description.Substring(0, 64)
            End If
            If (ee232b.SerialNumber.Length > 16) Then
                ee232b.SerialNumber = ee232b.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee232b.VendorID,
                .ProductID = ee232b.ProductID,
                .MaxPower = ee232b.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee232b.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee232b.RemoteWakeup),
                .Rev4 = Convert.ToByte(True),
                .PullDownEnable = Convert.ToByte(ee232b.PullDownEnable),
                .SerNumEnable = Convert.ToByte(ee232b.SerNumEnable),
                .USBVersionEnable = Convert.ToByte(ee232b.USBVersionEnable),
                .USBVersion = ee232b.USBVersion
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee232b.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232b.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee232b.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee232b.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteFt2232Eeprom(ee2232 As FT2232_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee2232.VendorID = 0US) OrElse (ee2232.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee2232.Manufacturer.Length > 32) Then
                ee2232.Manufacturer = ee2232.Manufacturer.Substring(0, 32)
            End If
            If (ee2232.ManufacturerID.Length > 16) Then
                ee2232.ManufacturerID = ee2232.ManufacturerID.Substring(0, 16)
            End If
            If (ee2232.Description.Length > 64) Then
                ee2232.Description = ee2232.Description.Substring(0, 64)
            End If
            If (ee2232.SerialNumber.Length > 16) Then
                ee2232.SerialNumber = ee2232.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee2232.VendorID,
                .ProductID = ee2232.ProductID,
                .MaxPower = ee2232.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee2232.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee2232.RemoteWakeup),
                .Rev5 = Convert.ToByte(True),
                .PullDownEnable5 = Convert.ToByte(ee2232.PullDownEnable),
                .SerNumEnable5 = Convert.ToByte(ee2232.SerNumEnable),
                .USBVersionEnable5 = Convert.ToByte(ee2232.USBVersionEnable),
                .USBVersion5 = ee2232.USBVersion,
                .AIsHighCurrent = Convert.ToByte(ee2232.AIsHighCurrent),
                .BIsHighCurrent = Convert.ToByte(ee2232.BIsHighCurrent),
                .IFAIsFifo = Convert.ToByte(ee2232.IFAIsFifo),
                .IFAIsFifoTar = Convert.ToByte(ee2232.IFAIsFifoTar),
                .IFAIsFastSer = Convert.ToByte(ee2232.IFAIsFastSer),
                .AIsVCP = Convert.ToByte(ee2232.AIsVCP),
                .IFBIsFifo = Convert.ToByte(ee2232.IFBIsFifo),
                .IFBIsFifoTar = Convert.ToByte(ee2232.IFBIsFifoTar),
                .IFBIsFastSer = Convert.ToByte(ee2232.IFBIsFastSer),
                .BIsVCP = Convert.ToByte(ee2232.BIsVCP)
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee2232.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee2232.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee2232.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee2232.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteFt232rEeprom(ee232r As FT232R_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee232r.VendorID = 0US) OrElse (ee232r.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee232r.Manufacturer.Length > 32) Then
                ee232r.Manufacturer = ee232r.Manufacturer.Substring(0, 32)
            End If
            If (ee232r.ManufacturerID.Length > 16) Then
                ee232r.ManufacturerID = ee232r.ManufacturerID.Substring(0, 16)
            End If
            If (ee232r.Description.Length > 64) Then
                ee232r.Description = ee232r.Description.Substring(0, 64)
            End If
            If (ee232r.SerialNumber.Length > 16) Then
                ee232r.SerialNumber = ee232r.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 2UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee232r.VendorID,
                .ProductID = ee232r.ProductID,
                .MaxPower = ee232r.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee232r.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee232r.RemoteWakeup),
                .PullDownEnableR = Convert.ToByte(ee232r.PullDownEnable),
                .SerNumEnableR = Convert.ToByte(ee232r.SerNumEnable),
                .UseExtOsc = Convert.ToByte(ee232r.UseExtOsc),
                .HighDriveIOs = Convert.ToByte(ee232r.HighDriveIOs),
                .EndpointSize = 64,
                .InvertTXD = Convert.ToByte(ee232r.InvertTXD),
                .InvertRXD = Convert.ToByte(ee232r.InvertRXD),
                .InvertRTS = Convert.ToByte(ee232r.InvertRTS),
                .InvertCTS = Convert.ToByte(ee232r.InvertCTS),
                .InvertDTR = Convert.ToByte(ee232r.InvertDTR),
                .InvertDSR = Convert.ToByte(ee232r.InvertDSR),
                .InvertDCD = Convert.ToByte(ee232r.InvertDCD),
                .InvertRI = Convert.ToByte(ee232r.InvertRI),
                .Cbus0 = ee232r.Cbus0,
                .Cbus1 = ee232r.Cbus1,
                .Cbus2 = ee232r.Cbus2,
                .Cbus3 = ee232r.Cbus3,
                .Cbus4 = ee232r.Cbus4,
                .RIsD2XX = Convert.ToByte(ee232r.RIsD2XX)
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee232r.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232r.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee232r.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee232r.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteFt2232hEeprom(ee2232h As FT2232H_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee2232h.VendorID = 0US) OrElse (ee2232h.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee2232h.Manufacturer.Length > 32) Then
                ee2232h.Manufacturer = ee2232h.Manufacturer.Substring(0, 32)
            End If
            If (ee2232h.ManufacturerID.Length > 16) Then
                ee2232h.ManufacturerID = ee2232h.ManufacturerID.Substring(0, 16)
            End If
            If (ee2232h.Description.Length > 64) Then
                ee2232h.Description = ee2232h.Description.Substring(0, 64)
            End If
            If (ee2232h.SerialNumber.Length > 16) Then
                ee2232h.SerialNumber = ee2232h.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 3UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee2232h.VendorID,
                .ProductID = ee2232h.ProductID,
                .MaxPower = ee2232h.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee2232h.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee2232h.RemoteWakeup),
                .PullDownEnable7 = Convert.ToByte(ee2232h.PullDownEnable),
                .SerNumEnable7 = Convert.ToByte(ee2232h.SerNumEnable),
                .ALSlowSlew = Convert.ToByte(ee2232h.ALSlowSlew),
                .ALSchmittInput = Convert.ToByte(ee2232h.ALSchmittInput),
                .ALDriveCurrent = ee2232h.ALDriveCurrent,
                .AHSlowSlew = Convert.ToByte(ee2232h.AHSlowSlew),
                .AHSchmittInput = Convert.ToByte(ee2232h.AHSchmittInput),
                .AHDriveCurrent = ee2232h.AHDriveCurrent,
                .BLSlowSlew = Convert.ToByte(ee2232h.BLSlowSlew),
                .BLSchmittInput = Convert.ToByte(ee2232h.BLSchmittInput),
                .BLDriveCurrent = ee2232h.BLDriveCurrent,
                .BHSlowSlew = Convert.ToByte(ee2232h.BHSlowSlew),
                .BHSchmittInput = Convert.ToByte(ee2232h.BHSchmittInput),
                .BHDriveCurrent = ee2232h.BHDriveCurrent,
                .IFAIsFifo7 = Convert.ToByte(ee2232h.IFAIsFifo),
                .IFAIsFifoTar7 = Convert.ToByte(ee2232h.IFAIsFifoTar),
                .IFAIsFastSer7 = Convert.ToByte(ee2232h.IFAIsFastSer),
                .AIsVCP7 = Convert.ToByte(ee2232h.AIsVCP),
                .IFBIsFifo7 = Convert.ToByte(ee2232h.IFBIsFifo),
                .IFBIsFifoTar7 = Convert.ToByte(ee2232h.IFBIsFifoTar),
                .IFBIsFastSer7 = Convert.ToByte(ee2232h.IFBIsFastSer),
                .BIsVCP7 = Convert.ToByte(ee2232h.BIsVCP),
                .PowerSaveEnable = Convert.ToByte(ee2232h.PowerSaveEnable)
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee2232h.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee2232h.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee2232h.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee2232h.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteFt4232hEeprom(ee4232h As FT4232H_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee4232h.VendorID = 0US) OrElse (ee4232h.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee4232h.Manufacturer.Length > 32) Then
                ee4232h.Manufacturer = ee4232h.Manufacturer.Substring(0, 32)
            End If
            If (ee4232h.ManufacturerID.Length > 16) Then
                ee4232h.ManufacturerID = ee4232h.ManufacturerID.Substring(0, 16)
            End If
            If (ee4232h.Description.Length > 64) Then
                ee4232h.Description = ee4232h.Description.Substring(0, 64)
            End If
            If (ee4232h.SerialNumber.Length > 16) Then
                ee4232h.SerialNumber = ee4232h.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 4UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee4232h.VendorID,
                .ProductID = ee4232h.ProductID,
                .MaxPower = ee4232h.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee4232h.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee4232h.RemoteWakeup),
                .PullDownEnable8 = Convert.ToByte(ee4232h.PullDownEnable),
                .SerNumEnable8 = Convert.ToByte(ee4232h.SerNumEnable),
                .ASlowSlew = Convert.ToByte(ee4232h.ASlowSlew),
                .ASchmittInput = Convert.ToByte(ee4232h.ASchmittInput),
                .ADriveCurrent = ee4232h.ADriveCurrent,
                .BSlowSlew = Convert.ToByte(ee4232h.BSlowSlew),
                .BSchmittInput = Convert.ToByte(ee4232h.BSchmittInput),
                .BDriveCurrent = ee4232h.BDriveCurrent,
                .CSlowSlew = Convert.ToByte(ee4232h.CSlowSlew),
                .CSchmittInput = Convert.ToByte(ee4232h.CSchmittInput),
                .CDriveCurrent = ee4232h.CDriveCurrent,
                .DSlowSlew = Convert.ToByte(ee4232h.DSlowSlew),
                .DSchmittInput = Convert.ToByte(ee4232h.DSchmittInput),
                .DDriveCurrent = ee4232h.DDriveCurrent,
                .ARIIsTXDEN = Convert.ToByte(ee4232h.ARIIsTXDEN),
                .BRIIsTXDEN = Convert.ToByte(ee4232h.BRIIsTXDEN),
                .CRIIsTXDEN = Convert.ToByte(ee4232h.CRIIsTXDEN),
                .DRIIsTXDEN = Convert.ToByte(ee4232h.DRIIsTXDEN),
                .AIsVCP8 = Convert.ToByte(ee4232h.AIsVCP),
                .BIsVCP8 = Convert.ToByte(ee4232h.BIsVCP),
                .CIsVCP8 = Convert.ToByte(ee4232h.CIsVCP),
                .DIsVCP8 = Convert.ToByte(ee4232h.DIsVCP)
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee4232h.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee4232h.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee4232h.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee4232h.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteFt232hEeprom(ee232h As FT232H_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (ee232h.VendorID = 0US) OrElse (ee232h.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (ee232h.Manufacturer.Length > 32) Then
                ee232h.Manufacturer = ee232h.Manufacturer.Substring(0, 32)
            End If
            If (ee232h.ManufacturerID.Length > 16) Then
                ee232h.ManufacturerID = ee232h.ManufacturerID.Substring(0, 16)
            End If
            If (ee232h.Description.Length > 64) Then
                ee232h.Description = ee232h.Description.Substring(0, 64)
            End If
            If (ee232h.SerialNumber.Length > 16) Then
                ee232h.SerialNumber = ee232h.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_PROGRAM_DATA() With {
                .Signature1 = 0UI,
                .Signature2 = UInteger.MaxValue,
                .Version = 5UI,
                .Manufacturer = Marshal.AllocHGlobal(32),
                .ManufacturerID = Marshal.AllocHGlobal(16),
                .Description = Marshal.AllocHGlobal(64),
                .SerialNumber = Marshal.AllocHGlobal(16),
                .VendorID = ee232h.VendorID,
                .ProductID = ee232h.ProductID,
                .MaxPower = ee232h.MaxPower,
                .SelfPowered = Convert.ToUInt16(ee232h.SelfPowered),
                .RemoteWakeup = Convert.ToUInt16(ee232h.RemoteWakeup),
                .PullDownEnableH = Convert.ToByte(ee232h.PullDownEnable),
                .SerNumEnableH = Convert.ToByte(ee232h.SerNumEnable),
                .ACSlowSlewH = Convert.ToByte(ee232h.ACSlowSlew),
                .ACSchmittInputH = Convert.ToByte(ee232h.ACSchmittInput),
                .ACDriveCurrentH = ee232h.ACDriveCurrent,
                .ADSlowSlewH = Convert.ToByte(ee232h.ADSlowSlew),
                .ADSchmittInputH = Convert.ToByte(ee232h.ADSchmittInput),
                .ADDriveCurrentH = ee232h.ADDriveCurrent,
                .Cbus0H = CType(ee232h.Cbus0, FT_CBUS_OPTIONS),
                .Cbus1H = CType(ee232h.Cbus1, FT_CBUS_OPTIONS),
                .Cbus2H = CType(ee232h.Cbus2, FT_CBUS_OPTIONS),
                .Cbus3H = CType(ee232h.Cbus3, FT_CBUS_OPTIONS),
                .Cbus4H = CType(ee232h.Cbus4, FT_CBUS_OPTIONS),
                .Cbus5H = CType(ee232h.Cbus5, FT_CBUS_OPTIONS),
                .Cbus6H = CType(ee232h.Cbus6, FT_CBUS_OPTIONS),
                .Cbus7H = CType(ee232h.Cbus7, FT_CBUS_OPTIONS),
                .Cbus8H = CType(ee232h.Cbus8, FT_CBUS_OPTIONS),
                .Cbus9H = CType(ee232h.Cbus9, FT_CBUS_OPTIONS),
                .IsFifoH = Convert.ToByte(ee232h.IsFifo),
                .IsFifoTarH = Convert.ToByte(ee232h.IsFifoTar),
                .IsFastSerH = Convert.ToByte(ee232h.IsFastSer),
                .IsFT1248H = Convert.ToByte(ee232h.IsFT1248),
                .FT1248CpolH = Convert.ToByte(ee232h.FT1248Cpol),
                .FT1248LsbH = Convert.ToByte(ee232h.FT1248Lsb),
                .FT1248FlowControlH = Convert.ToByte(ee232h.FT1248FlowControl),
                .IsVCPH = Convert.ToByte(ee232h.IsVCP),
                .PowerSaveEnableH = Convert.ToByte(ee232h.PowerSaveEnable)
            }
            programData.Manufacturer = Marshal.StringToHGlobalAnsi(ee232h.Manufacturer)
            programData.ManufacturerID = Marshal.StringToHGlobalAnsi(ee232h.ManufacturerID)
            programData.Description = Marshal.StringToHGlobalAnsi(ee232h.Description)
            programData.SerialNumber = Marshal.StringToHGlobalAnsi(ee232h.SerialNumber)
            Dim dlg As EeProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_Program, IntPtr), GetType(EeProgramDelegate)), EeProgramDelegate)
            status = dlg(FtHandle, programData)
            Marshal.FreeHGlobal(programData.Manufacturer)
            Marshal.FreeHGlobal(programData.ManufacturerID)
            Marshal.FreeHGlobal(programData.Description)
            Marshal.FreeHGlobal(programData.SerialNumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

        Private Sub WriteXSeriesEeprom(eeX As FT_XSERIES_EEPROM_STRUCTURE)
            Dim status As FT_STATUS = FT_STATUS.FT_OTHER_ERROR
            If (eeX.VendorID = 0US) OrElse (eeX.ProductID = 0US) Then
                CheckErrors(FT_STATUS.FT_INVALID_PARAMETER)
            End If
            If (eeX.Manufacturer.Length > 32) Then
                eeX.Manufacturer = eeX.Manufacturer.Substring(0, 32)
            End If
            If (eeX.ManufacturerID.Length > 16) Then
                eeX.ManufacturerID = eeX.ManufacturerID.Substring(0, 16)
            End If
            If (eeX.Description.Length > 64) Then
                eeX.Description = eeX.Description.Substring(0, 64)
            End If
            If (eeX.SerialNumber.Length > 16) Then
                eeX.SerialNumber = eeX.SerialNumber.Substring(0, 16)
            End If
            Dim programData As New FT_XSERIES_DATA() With {
                .Cbus0 = CType(eeX.Cbus0, FT_CBUS_OPTIONS),
                .Cbus1 = CType(eeX.Cbus1, FT_CBUS_OPTIONS),
                .Cbus2 = CType(eeX.Cbus2, FT_CBUS_OPTIONS),
                .Cbus3 = CType(eeX.Cbus3, FT_CBUS_OPTIONS),
                .Cbus4 = CType(eeX.Cbus4, FT_CBUS_OPTIONS),
                .Cbus5 = CType(eeX.Cbus5, FT_CBUS_OPTIONS),
                .Cbus6 = CType(eeX.Cbus6, FT_CBUS_OPTIONS),
                .ACDriveCurrent = eeX.ACDriveCurrent,
                .ACSchmittInput = eeX.ACSchmittInput,
                .ACSlowSlew = eeX.ACSlowSlew,
                .ADDriveCurrent = eeX.ADDriveCurrent,
                .ADSchmittInput = eeX.ADSchmittInput,
                .ADSlowSlew = eeX.ADSlowSlew,
                .BCDDisableSleep = eeX.BCDDisableSleep,
                .BCDEnable = eeX.BCDEnable,
                .BCDForceCbusPWREN = eeX.BCDForceCbusPWREN,
                .FT1248Cpol = eeX.FT1248Cpol,
                .FT1248FlowControl = eeX.FT1248FlowControl,
                .FT1248Lsb = eeX.FT1248Lsb,
                .I2CDeviceId = eeX.I2CDeviceId,
                .I2CDisableSchmitt = eeX.I2CDisableSchmitt,
                .I2CSlaveAddress = eeX.I2CSlaveAddress,
                .InvertCTS = eeX.InvertCTS,
                .InvertDCD = eeX.InvertDCD,
                .InvertDSR = eeX.InvertDSR,
                .InvertDTR = eeX.InvertDTR,
                .InvertRI = eeX.InvertRI,
                .InvertRTS = eeX.InvertRTS,
                .InvertRXD = eeX.InvertRXD,
                .InvertTXD = eeX.InvertTXD,
                .PowerSaveEnable = eeX.PowerSaveEnable,
                .RS485EchoSuppress = eeX.RS485EchoSuppress,
                .DriverType = eeX.IsVCP
            }
            programData.Common.DeviceType = FT_DEVICE.FT_DEVICE_X_SERIES
            programData.Common.VendorId = eeX.VendorID
            programData.Common.ProductId = eeX.ProductID
            programData.Common.MaxPower = eeX.MaxPower
            programData.Common.SelfPowered = Convert.ToByte(eeX.SelfPowered)
            programData.Common.RemoteWakeup = Convert.ToByte(eeX.RemoteWakeup)
            programData.Common.SerNumEnable = Convert.ToByte(eeX.SerNumEnable)
            programData.Common.PullDownEnable = Convert.ToByte(eeX.PullDownEnable)
            Dim utf8Encoding As UTF8Encoding = New UTF8Encoding()
            Dim manufacturer As Byte() = utf8Encoding.GetBytes(eeX.Manufacturer)
            Dim manufacturerID As Byte() = utf8Encoding.GetBytes(eeX.ManufacturerID)
            Dim description As Byte() = utf8Encoding.GetBytes(eeX.Description)
            Dim serialnumber As Byte() = utf8Encoding.GetBytes(eeX.SerialNumber)
            Dim programDataSize As Integer = Marshal.SizeOf(programData)
            Dim ptr As IntPtr = Marshal.AllocHGlobal(programDataSize)
            Marshal.StructureToPtr(programData, ptr, False)
            Dim dlg As EepromProgramDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EEPROM_Program, IntPtr), GetType(EepromProgramDelegate)), EepromProgramDelegate)
            status = dlg(FtHandle, ptr, CUInt(programDataSize), manufacturer, manufacturerID, description, serialnumber)
            CheckErrors(status) 'статус проверяем после освобождения всех неуправляемых ресурсов
        End Sub

#End Region '/ЗАПИСЬ ППЗУ

#Region "ПОЛЬЗОВАТЕЛЬСКАЯ ОБЛАСТЬ ППЗУ FTDI"

        ''' <summary>
        ''' Размер пользовательской области ПЗУ в байтах.
        ''' </summary>
        Public ReadOnly Property UserAreaSize As Integer
            Get
                If (_UserAreaSize = NOT_INIT) Then
                    Dim uaSize As UInteger
                    Dim dlg As EeUaSizeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_UASize, IntPtr), GetType(EeUaSizeDelegate)), EeUaSizeDelegate)
                    Dim status As FT_STATUS = dlg(FtHandle, uaSize)
                    CheckErrors(status)
                    _UserAreaSize = CInt(uaSize)
                End If
                Return _UserAreaSize
            End Get
        End Property
        Private _UserAreaSize As Integer = NOT_INIT

        ''' <summary>
        ''' Читает данные пользовательской области ПЗУ.
        ''' </summary>
        Public Function ReadUserArea() As Byte()
            Dim userAreaDataBuffer As Byte() = New Byte() {}
            Dim bufSize As UInteger = 0UI
            Dim dlg As EeUaSizeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_UASize, IntPtr), GetType(EeUaSizeDelegate)), EeUaSizeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, bufSize)
            ReDim userAreaDataBuffer(CInt(bufSize - 1))
            If (userAreaDataBuffer.Length >= bufSize) Then
                Dim numBytesWereRead As UInteger = 0
                Dim rdDlg As EeUaReadDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_UARead, IntPtr), GetType(EeUaReadDelegate)), EeUaReadDelegate)
                status = status Or rdDlg(FtHandle, userAreaDataBuffer, userAreaDataBuffer.Length, numBytesWereRead)
            End If
            CheckErrors(status)
            Return userAreaDataBuffer
        End Function

        ''' <summary>
        ''' Записывает данные в пользовательскую область ПЗУ.
        ''' </summary>
        Public Sub WriteUserArea(data As Byte())
            Dim bufSize As UInteger = 0UI
            Dim dlg As EeUaSizeDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_UASize, IntPtr), GetType(EeUaSizeDelegate)), EeUaSizeDelegate)
            Dim status As FT_STATUS = dlg(FtHandle, bufSize)
            If (data.Length <= bufSize) Then
                Dim wDlg As EeUaWriteDelegate = CType(Marshal.GetDelegateForFunctionPointer(CType(PFt_EE_UAWrite, IntPtr), GetType(EeUaWriteDelegate)), EeUaWriteDelegate)
                status = status Or wDlg(FtHandle, data, data.Length)
            End If
            CheckErrors(status)
        End Sub

#End Region '/ПОЛЬЗОВАТЕЛЬСКАЯ ОБЛАСТЬ ППЗУ FTDI

#Region "СТРУКТУРЫ ОБЪЕКТОВ В ППЗУ FTDI"

        <StructLayout(LayoutKind.Sequential, Pack:=4)>
        Private Structure FT_PROGRAM_DATA
            Public Signature1 As UInteger
            Public Signature2 As UInteger
            Public Version As UInteger
            Public VendorID As UShort
            Public ProductID As UShort
            Public Manufacturer As IntPtr
            Public ManufacturerID As IntPtr
            Public Description As IntPtr
            Public SerialNumber As IntPtr
            Public MaxPower As UShort
            Public PnP As UShort
            Public SelfPowered As UShort
            Public RemoteWakeup As UShort

            'FT232B extensions
            Public Rev4 As Byte
            Public IsoIn As Byte
            Public IsoOut As Byte
            Public PullDownEnable As Byte
            Public SerNumEnable As Byte
            Public USBVersionEnable As Byte
            Public USBVersion As USB_VERSION

            'FT2232D extensions
            Public Rev5 As Byte
            Public IsoInA As Byte
            Public IsoInB As Byte
            Public IsoOutA As Byte
            Public IsoOutB As Byte
            Public PullDownEnable5 As Byte
            Public SerNumEnable5 As Byte
            Public USBVersionEnable5 As Byte
            Public USBVersion5 As USB_VERSION
            Public AIsHighCurrent As Byte
            Public BIsHighCurrent As Byte
            Public IFAIsFifo As Byte
            Public IFAIsFifoTar As Byte
            Public IFAIsFastSer As Byte
            Public AIsVCP As Byte
            Public IFBIsFifo As Byte
            Public IFBIsFifoTar As Byte
            Public IFBIsFastSer As Byte

            'FT232R extensions
            Public BIsVCP As Byte
            Public UseExtOsc As Byte
            Public HighDriveIOs As Byte
            Public EndpointSize As Byte
            Public PullDownEnableR As Byte
            Public SerNumEnableR As Byte
            Public InvertTXD As Byte 'non-zero if invert TXD
            Public InvertRXD As Byte 'non-zero if invert RXD
            Public InvertRTS As Byte 'non-zero if invert RTS
            Public InvertCTS As Byte 'non-zero if invert CTS
            Public InvertDTR As Byte 'non-zero if invert DTR
            Public InvertDSR As Byte 'non-zero if invert DSR
            Public InvertDCD As Byte 'non-zero if invert DCD
            Public InvertRI As Byte  'non-zero if invert RI
            Public Cbus0 As FT_CBUS_OPTIONS 'Cbus Mux control - Ignored for FT245R
            Public Cbus1 As FT_CBUS_OPTIONS 'Cbus Mux control - Ignored for FT245R
            Public Cbus2 As FT_CBUS_OPTIONS 'Cbus Mux control - Ignored for FT245R
            Public Cbus3 As FT_CBUS_OPTIONS 'Cbus Mux control - Ignored for FT245R
            Public Cbus4 As FT_CBUS_OPTIONS 'Cbus Mux control - Ignored for FT245R
            Public RIsD2XX As Byte 'Default to loading VCP

            'FT2232H extensions
            Public PullDownEnable7 As Byte
            Public SerNumEnable7 As Byte
            Public ALSlowSlew As Byte    'non-zero if AL pins have slow slew
            Public ALSchmittInput As Byte 'non-zero if AL pins are Schmitt input
            Public ALDriveCurrent As FT_DRIVE_CURRENT
            Public AHSlowSlew As Byte    'non-zero if AH pins have slow slew
            Public AHSchmittInput As Byte 'non-zero if AH pins are Schmitt input
            Public AHDriveCurrent As FT_DRIVE_CURRENT
            Public BLSlowSlew As Byte    'non-zero if BL pins have slow slew
            Public BLSchmittInput As Byte 'non-zero if BL pins are Schmitt input
            Public BLDriveCurrent As FT_DRIVE_CURRENT
            Public BHSlowSlew As Byte    'non-zero if BH pins have slow slew
            Public BHSchmittInput As Byte 'non-zero if BH pins are Schmitt input
            Public BHDriveCurrent As FT_DRIVE_CURRENT
            Public IFAIsFifo7 As Byte     'non-zero if interface is 245 FIFO
            Public IFAIsFifoTar7 As Byte  'non-zero if interface is 245 FIFO CPU target
            Public IFAIsFastSer7 As Byte  'non-zero if interface is Fast serial
            Public AIsVCP7 As Byte        'non-zero if interface is to use VCP drivers
            Public IFBIsFifo7 As Byte     'non-zero if interface is 245 FIFO
            Public IFBIsFifoTar7 As Byte  'non-zero if interface is 245 FIFO CPU target
            Public IFBIsFastSer7 As Byte  'non-zero if interface is Fast serial
            Public BIsVCP7 As Byte        'non-zero if interface is to use VCP drivers
            Public PowerSaveEnable As Byte 'non-zero if using BCBUS7 to save power for self-powered designs

            'FT4232H extensions
            Public PullDownEnable8 As Byte
            Public SerNumEnable8 As Byte
            Public ASlowSlew As Byte    'non-zero if AL pins have slow slew
            Public ASchmittInput As Byte 'non-zero if AL pins are Schmitt input
            Public ADriveCurrent As FT_DRIVE_CURRENT
            Public BSlowSlew As Byte    'non-zero if AH pins have slow slew
            Public BSchmittInput As Byte 'non-zero if AH pins are Schmitt input
            Public BDriveCurrent As FT_DRIVE_CURRENT
            Public CSlowSlew As Byte    'non-zero if BL pins have slow slew
            Public CSchmittInput As Byte 'non-zero if BL pins are Schmitt input
            Public CDriveCurrent As FT_DRIVE_CURRENT
            Public DSlowSlew As Byte    'non-zero if BH pins have slow slew
            Public DSchmittInput As Byte 'non-zero if BH pins are Schmitt input
            Public DDriveCurrent As FT_DRIVE_CURRENT
            Public ARIIsTXDEN As Byte
            Public BRIIsTXDEN As Byte
            Public CRIIsTXDEN As Byte
            Public DRIIsTXDEN As Byte
            Public AIsVCP8 As Byte 'non-zero if interface is to use VCP drivers
            Public BIsVCP8 As Byte 'non-zero if interface is to use VCP drivers
            Public CIsVCP8 As Byte 'non-zero if interface is to use VCP drivers
            Public DIsVCP8 As Byte 'non-zero if interface is to use VCP drivers

            'FT232H extensions
            Public PullDownEnableH As Byte 'non-zero if pull down enabled
            Public SerNumEnableH As Byte  'non-zero if serial number to be used
            Public ACSlowSlewH As Byte    'non-zero if AC pins have slow slew
            Public ACSchmittInputH As Byte 'non-zero if AC pins are Schmitt input
            Public ACDriveCurrentH As FT_DRIVE_CURRENT
            Public ADSlowSlewH As Byte    'non-zero if AD pins have slow slew
            Public ADSchmittInputH As Byte 'non-zero if AD pins are Schmitt input
            Public ADDriveCurrentH As FT_DRIVE_CURRENT
            Public Cbus0H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus1H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus2H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus3H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus4H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus5H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus6H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus7H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus8H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus9H As FT_CBUS_OPTIONS 'Cbus Mux control
            Public IsFifoH As Byte     'non-zero if interface is 245 FIFO
            Public IsFifoTarH As Byte  'non-zero if interface is 245 FIFO CPU target
            Public IsFastSerH As Byte  'non-zero if interface is Fast serial
            Public IsFT1248H As Byte   'non-zero if interface is FT1248
            Public FT1248CpolH As Byte 'FT1248 clock polarity
            Public FT1248LsbH As Byte  'FT1248 data is LSB (1) or MSB (0)
            Public FT1248FlowControlH As Byte 'FT1248 flow control enable
            Public IsVCPH As Byte          'non-zero if interface is to use VCP drivers
            Public PowerSaveEnableH As Byte 'non-zero if using ACBUS7 to save power for self-powered designs
        End Structure

        <StructLayout(LayoutKind.Sequential, Pack:=4)>
        Private Structure FT_EEPROM_HEADER
            Public DeviceType As FT_DEVICE 'FTxxxx device type to be programmed

            'Device descriptor options
            Public VendorId As UShort  '0x0403
            Public ProductId As UShort '0x6001
            Public SerNumEnable As Byte 'non-zero if serial number to be used

            'Config descriptor options
            ''' <summary>
            ''' 0...500.
            ''' </summary>
            Public MaxPower As UShort
            ''' <summary>
            ''' 1 = self powered, 0 = bus powered.
            ''' </summary>
            Public SelfPowered As Byte
            ''' <summary>
            ''' 1 = capable, 0 = not capable.
            ''' </summary>
            Public RemoteWakeup As Byte

            'Hardware options
            Public PullDownEnable As Byte 'non-zero if pull down in suspend enabled
        End Structure

        <StructLayout(LayoutKind.Sequential, Pack:=4)>
        Private Structure FT_XSERIES_DATA
            Public Common As FT_EEPROM_HEADER
            Public ACSlowSlew As Byte    'non-zero if AC bus pins have slow slew
            Public ACSchmittInput As Byte 'non-zero if AC bus pins are Schmitt input
            Public ACDriveCurrent As FT_DRIVE_CURRENT
            Public ADSlowSlew As Byte    'non-zero if AD bus pins have slow slew
            Public ADSchmittInput As Byte 'non-zero if AD bus pins are Schmitt input
            Public ADDriveCurrent As FT_DRIVE_CURRENT

            'CBUS options
            Public Cbus0 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus1 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus2 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus3 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus4 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus5 As FT_CBUS_OPTIONS 'Cbus Mux control
            Public Cbus6 As FT_CBUS_OPTIONS 'Cbus Mux control

            'UART signal options
            Public InvertTXD As Byte 'non-zero if invert TXD
            Public InvertRXD As Byte 'non-zero if invert RXD
            Public InvertRTS As Byte 'non-zero if invert RTS
            Public InvertCTS As Byte 'non-zero if invert CTS
            Public InvertDTR As Byte 'non-zero if invert DTR
            Public InvertDSR As Byte 'non-zero if invert DSR
            Public InvertDCD As Byte 'non-zero if invert DCD
            Public InvertRI As Byte ' non-zero if invert RI

            ' Battery Charge Detect options
            ''' <summary>
            ''' Enable Battery Charger Detection.
            ''' </summary>
            Public BCDEnable As Byte
            ''' <summary>
            ''' Asserts the power enable signal on CBUS when charging port detected.
            ''' </summary>
            Public BCDForceCbusPWREN As Byte
            ''' <summary>
            ''' Forces the device never to go into sleep mode.
            ''' </summary>
            Public BCDDisableSleep As Byte

            ' I2C options

            ''' <summary>
            ''' I2C slave device address.
            ''' </summary>
            Public I2CSlaveAddress As UShort
            ''' <summary>
            ''' I2C device ID.
            ''' </summary>
            Public I2CDeviceId As UInteger
            ''' <summary>
            ''' Disable I2C Schmitt trigger.
            ''' </summary>
            Public I2CDisableSchmitt As Byte

            ' FT1248 options

            ''' <summary>
            ''' FT1248 clock polarity - clock idle high (1) or clock idle low (0)
            ''' </summary>
            Public FT1248Cpol As Byte
            ''' <summary>
            ''' FT1248 data is LSB (1) or MSB (0).
            ''' </summary>
            Public FT1248Lsb As Byte
            ''' <summary>
            ''' FT1248 flow control enable.
            ''' </summary>
            Public FT1248FlowControl As Byte

            'Hardware options
            Public RS485EchoSuppress As Byte
            Public PowerSaveEnable As Byte

            'Driver option
            Public DriverType As Byte
        End Structure

        Public Class FT_EEPROM_DATA
            Public VendorID As UShort = &H403US
            Public ProductID As UShort = &H6001US
            Public Manufacturer As String = "FTDI"
            ''' <summary>
            ''' Аббревиатура производителя, которая используется как префикс в автоматически генерируемых серийных номерах.
            ''' </summary>
            Public ManufacturerID As String = "FT"
            Public Description As String = "USB-Serial Converter"
            Public SerialNumber As String = ""
            ''' <summary>
            ''' Максимальная мощность, требующаяся устройству.
            ''' </summary>
            Public MaxPower As UShort = &H90
            ''' <summary>
            ''' Показывает, устройство имеет свой собственный источник питания (self-powered) или берёт питание от USB порта (bus-powered).
            ''' </summary>
            Public SelfPowered As Boolean
            ''' <summary>
            ''' Определяет, может ли устройство выводить ПК из режима ожидания, переключая линию RI.
            ''' </summary>
            Public RemoteWakeup As Boolean
        End Class

        Public Class FT232B_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Определяет, притянуты ли выводы IO, когда устройство в режиме ожидания.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Используется ли серийный номер.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if the USB version number is enabled.
            ''' </summary>
            Public USBVersionEnable As Boolean = True
            ''' <summary>
            ''' The USB version number.
            ''' </summary>
            Public USBVersion As USB_VERSION = USB_VERSION.VER_20
        End Class

        Public Class FT2232_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Определяет, притянуты ли выводы IO, когда устройство в режиме ожидания.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if the USB version number is enabled.
            ''' </summary>
            Public USBVersionEnable As Boolean = True
            ''' <summary>
            ''' The USB version number.
            ''' </summary>
            Public USBVersion As USB_VERSION = USB_VERSION.VER_20
            ''' <summary>
            ''' Enables high current IOs on channel A.
            ''' </summary>
            Public AIsHighCurrent As Boolean
            ''' <summary>
            ''' Enables high current IOs on channel B.
            ''' </summary>
            Public BIsHighCurrent As Boolean
            ''' <summary>
            ''' Determines if channel A is in FIFO mode.
            ''' </summary>
            Public IFAIsFifo As Boolean
            ''' <summary>
            ''' Determines if channel A is in FIFO target mode.
            ''' </summary>
            Public IFAIsFifoTar As Boolean
            ''' <summary>
            ''' Determines if channel A is in fast serial mode.
            ''' </summary>
            Public IFAIsFastSer As Boolean
            ''' <summary>
            ''' Determines if channel A loads the VCP driver.
            ''' </summary>
            Public AIsVCP As Boolean = True
            ''' <summary>
            ''' Determines if channel B is in FIFO mode.
            ''' </summary>
            Public IFBIsFifo As Boolean
            ''' <summary>
            ''' Determines if channel B is in FIFO target mode.
            ''' </summary>
            Public IFBIsFifoTar As Boolean
            ''' <summary>
            ''' Determines if channel B is in fast serial mode.
            ''' </summary>
            Public IFBIsFastSer As Boolean
            ''' <summary>
            ''' Determines if channel B loads the VCP driver.
            ''' </summary>
            Public BIsVCP As Boolean = True
        End Class

        ''' <summary>
        ''' EEPROM для FT232R и FT245R.
        ''' </summary>
        Public Class FT232R_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Disables the FT232R internal clock source.
            ''' If the device has external oscillator enabled it must have an external oscillator fitted to function.
            ''' </summary>
            Public UseExtOsc As Boolean
            ''' <summary>
            ''' Enables high current IOs.
            ''' </summary>
            Public HighDriveIOs As Boolean
            ''' <summary>
            ''' Sets the endpoint size. This should always be set to 64.
            ''' </summary>
            Public EndpointSize As Byte = 64
            ''' <summary>
            ''' Determines if IOs are pulled down when the device is in suspend.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Inverts the sense of the TXD line.
            ''' </summary>
            Public InvertTXD As Boolean
            ''' <summary>
            ''' Inverts the sense of the RXD line.
            ''' </summary>
            Public InvertRXD As Boolean
            ''' <summary>
            ''' Inverts the sense of the RTS line.
            ''' </summary>
            Public InvertRTS As Boolean
            ''' <summary>
            ''' Inverts the sense of the CTS line.
            ''' </summary>
            Public InvertCTS As Boolean
            ''' <summary>
            ''' Inverts the sense of the DTR line.
            ''' </summary>
            Public InvertDTR As Boolean
            ''' <summary>
            ''' Inverts the sense of the DSR line.
            ''' </summary>
            Public InvertDSR As Boolean
            ''' <summary>
            ''' Inverts the sense of the DCD line.
            ''' </summary>
            Public InvertDCD As Boolean
            ''' <summary>
            ''' Inverts the sense of the RI line.
            ''' </summary>
            Public InvertRI As Boolean
            Public Cbus0 As FT_CBUS_OPTIONS = FT_CBUS_OPTIONS.FT_CBUS_SLEEP
            Public Cbus1 As FT_CBUS_OPTIONS = FT_CBUS_OPTIONS.FT_CBUS_SLEEP
            Public Cbus2 As FT_CBUS_OPTIONS = FT_CBUS_OPTIONS.FT_CBUS_SLEEP
            Public Cbus3 As FT_CBUS_OPTIONS = FT_CBUS_OPTIONS.FT_CBUS_SLEEP
            Public Cbus4 As FT_CBUS_OPTIONS = FT_CBUS_OPTIONS.FT_CBUS_SLEEP
            ''' <summary>
            ''' Determines if the VCP driver is loaded.
            ''' </summary>
            Public RIsD2XX As Boolean
        End Class

        Public Class FT2232H_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Determines if IOs are pulled down when the device is in suspend.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if AL pins have a slow slew rate.
            ''' </summary>
            Public ALSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the AL pins have a Schmitt input.
            ''' </summary>
            Public ALSchmittInput As Boolean
            ''' <summary>
            ''' Determines the AL pins drive current in mA.
            ''' </summary>
            Public ALDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if AH pins have a slow slew rate.
            ''' </summary>
            Public AHSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the AH pins have a Schmitt input.
            ''' </summary>
            Public AHSchmittInput As Boolean
            ''' <summary>
            ''' Determines the AH pins drive current in mA.
            ''' </summary>
            Public AHDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if BL pins have a slow slew rate.
            ''' </summary>
            Public BLSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the BL pins have a Schmitt input.
            ''' </summary>
            Public BLSchmittInput As Boolean
            ''' <summary>
            ''' Determines the BL pins drive current in mA.
            ''' </summary>
            Public BLDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if BH pins have a slow slew rate.
            ''' </summary>
            Public BHSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the BH pins have a Schmitt input.
            ''' </summary>
            Public BHSchmittInput As Boolean
            ''' <summary>
            ''' Determines the BH pins drive current in mA.
            ''' </summary>
            Public BHDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if channel A is in FIFO mode.
            ''' </summary>
            Public IFAIsFifo As Boolean
            ''' <summary>
            ''' Determines if channel A is in FIFO target mode.
            ''' </summary>
            Public IFAIsFifoTar As Boolean
            ''' <summary>
            ''' Determines if channel A is in fast serial mode.
            ''' </summary>
            Public IFAIsFastSer As Boolean
            ''' <summary>
            ''' Determines if channel A loads the VCP driver.
            ''' </summary>
            Public AIsVCP As Boolean = True
            ''' <summary>
            ''' Determines if channel B is in FIFO mode.
            ''' </summary>
            Public IFBIsFifo As Boolean
            ''' <summary>
            ''' Determines if channel B is in FIFO target mode.
            ''' </summary>
            Public IFBIsFifoTar As Boolean
            ''' <summary>
            ''' Determines if channel B is in fast serial mode.
            ''' </summary>
            Public IFBIsFastSer As Boolean
            ''' <summary>
            ''' Determines if channel B loads the VCP driver.
            ''' </summary>
            Public BIsVCP As Boolean = True
            ''' <summary>
            ''' For self-powered designs, keeps the FT2232H in low power state until BCBUS7 is high.
            ''' </summary>
            Public PowerSaveEnable As Boolean
        End Class

        Public Class FT4232H_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Determines if IOs are pulled down when the device is in suspend.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if A pins have a slow slew rate.
            ''' </summary>
            Public ASlowSlew As Boolean
            ''' <summary>
            ''' Determines if the A pins have a Schmitt input.
            ''' </summary>
            Public ASchmittInput As Boolean
            ''' <summary>
            ''' Determines the A pins drive current in mA.
            ''' </summary>
            Public ADriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if B pins have a slow slew rate.
            ''' </summary>
            Public BSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the B pins have a Schmitt input.
            ''' </summary>
            Public BSchmittInput As Boolean
            ''' <summary>
            ''' Determines the B pins drive current in mA.
            ''' </summary>
            Public BDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if C pins have a slow slew rate.
            ''' </summary>
            Public CSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the C pins have a Schmitt input.
            ''' </summary>
            Public CSchmittInput As Boolean
            ''' <summary>
            ''' Determines the C pins drive current in mA.
            ''' </summary>
            Public CDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if D pins have a slow slew rate.
            ''' </summary>
            Public DSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the D pins have a Schmitt input.
            ''' </summary>
            Public DSchmittInput As Boolean
            ''' <summary>
            ''' Determines the D pins drive current in mA.
            ''' </summary>
            Public DDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' RI of port A acts as RS485 transmit enable (TXDEN).
            ''' </summary>
            Public ARIIsTXDEN As Boolean
            ''' <summary>
            ''' RI of port B acts as RS485 transmit enable (TXDEN).
            ''' </summary>
            Public BRIIsTXDEN As Boolean
            ''' <summary>
            ''' RI of port C acts as RS485 transmit enable (TXDEN).
            ''' </summary>
            Public CRIIsTXDEN As Boolean
            ''' <summary>
            ''' RI of port D acts as RS485 transmit enable (TXDEN).
            ''' </summary>
            Public DRIIsTXDEN As Boolean
            ''' <summary>
            ''' Determines if channel A loads the VCP driver.
            ''' </summary>
            Public AIsVCP As Boolean = True
            ''' <summary>
            ''' Determines if channel B loads the VCP driver.
            ''' </summary>
            Public BIsVCP As Boolean = True
            ''' <summary>
            ''' Determines if channel C loads the VCP driver.
            ''' </summary>
            Public CIsVCP As Boolean = True
            ''' <summary>
            ''' Determines if channel D loads the VCP driver.
            ''' </summary>
            Public DIsVCP As Boolean = True
        End Class

        Public Class FT232H_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Determines if IOs are pulled down when the device is in suspend.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if AC pins have a slow slew rate.
            ''' </summary>
            Public ACSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the AC pins have a Schmitt input.
            ''' </summary>
            Public ACSchmittInput As Boolean
            ''' <summary>
            ''' Determines the AC pins drive current in mA.
            ''' </summary>
            Public ACDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if AD pins have a slow slew rate.
            ''' </summary>
            Public ADSlowSlew As Boolean
            ''' <summary>
            ''' Determines if the AD pins have a Schmitt input.
            ''' </summary>
            Public ADSchmittInput As Boolean
            ''' <summary>
            ''' Determines the AD pins drive current in mA.
            ''' </summary>
            Public ADDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Sets the function of the CBUS0 pin for FT232H devices.
            ''' </summary>
            Public Cbus0 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS1 pin for FT232H devices.
            ''' </summary>
            Public Cbus1 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS2 pin for FT232H devices.
            ''' </summary>
            Public Cbus2 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS3 pin for FT232H devices.
            ''' </summary>
            Public Cbus3 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS4 pin for FT232H devices.
            ''' </summary>
            Public Cbus4 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS5 pin for FT232H devices.
            ''' </summary>
            Public Cbus5 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS6 pin for FT232H devices.
            ''' </summary>
            Public Cbus6 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS7 pin for FT232H devices.
            ''' </summary>
            Public Cbus7 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS8 pin for FT232H devices.
            ''' </summary>
            Public Cbus8 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS9 pin for FT232H devices.
            ''' </summary>
            Public Cbus9 As FT_232H_CBUS_OPTIONS = FT_232H_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Determines if the device is in FIFO mode.
            ''' </summary>
            Public IsFifo As Boolean
            ''' <summary>
            ''' Determines if the device is in FIFO target mode.
            ''' </summary>
            Public IsFifoTar As Boolean
            ''' <summary>
            ''' Determines if the device is in fast serial mode.
            ''' </summary>
            Public IsFastSer As Boolean
            ''' <summary>
            ''' Determines if the device is in FT1248 mode.
            ''' </summary>
            Public IsFT1248 As Boolean
            ''' <summary>
            ''' Determines FT1248 mode clock polarity.
            ''' </summary>
            Public FT1248Cpol As Boolean
            ''' <summary>
            ''' Determines if data is ent MSB (0) or LSB (1) in FT1248 mode.
            ''' </summary>
            Public FT1248Lsb As Boolean
            ''' <summary>
            ''' Determines if FT1248 mode uses flow control.
            ''' </summary>
            Public FT1248FlowControl As Boolean
            ''' <summary>
            ''' Determines if the VCP driver is loaded.
            ''' </summary>
            Public IsVCP As Boolean = True
            ''' <summary>
            ''' For self-powered designs, keeps the FT232H in low power state until ACBUS7 is high.
            ''' </summary>
            Public PowerSaveEnable As Boolean
        End Class

        Public Class FT_XSERIES_EEPROM_STRUCTURE : Inherits FT_EEPROM_DATA
            ''' <summary>
            ''' Determines if IOs are pulled down when the device Is in suspend.
            ''' </summary>
            Public PullDownEnable As Boolean
            ''' <summary>
            ''' Determines if the serial number is enabled.
            ''' </summary>
            Public SerNumEnable As Boolean = True
            ''' <summary>
            ''' Determines if the USB version number is enabled.
            ''' </summary>
            Public USBVersionEnable As Boolean = True
            ''' <summary>
            ''' The USB version number.
            ''' </summary>
            Public USBVersion As USB_VERSION = USB_VERSION.VER_20
            ''' <summary>
            ''' Determines if AC pins have a slow slew rate.
            ''' </summary>
            Public ACSlowSlew As Byte
            ''' <summary>
            ''' Determines if the AC pins have a Schmitt input.
            ''' </summary>
            Public ACSchmittInput As Byte
            ''' <summary>
            ''' Determines the AC pins drive current in mA.
            ''' </summary>
            Public ACDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Determines if AD pins have a slow slew rate.
            ''' </summary>
            Public ADSlowSlew As Byte
            ''' <summary>
            ''' Determines if AD pins have a schmitt input.
            ''' </summary>
            Public ADSchmittInput As Byte
            ''' <summary>
            ''' Determines the AD pins drive current in mA.
            ''' </summary>
            Public ADDriveCurrent As FT_DRIVE_CURRENT = FT_DRIVE_CURRENT.FT_DRIVE_CURRENT_4MA
            ''' <summary>
            ''' Sets the function of the CBUS0 pin for FT232H devices.
            ''' </summary>
            Public Cbus0 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS1 pin for FT232H devices.
            ''' </summary>
            Public Cbus1 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS2 pin for FT232H devices.
            ''' </summary>
            Public Cbus2 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS3 pin for FT232H devices.
            ''' </summary>
            Public Cbus3 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS4 pin for FT232H devices.
            ''' </summary>
            Public Cbus4 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS5 pin for FT232H devices.
            ''' </summary>
            Public Cbus5 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Sets the function of the CBUS6 pin for FT232H devices.
            ''' </summary>
            Public Cbus6 As FT_XSERIES_CBUS_OPTIONS = FT_XSERIES_CBUS_OPTIONS.FT_CBUS_TRISTATE
            ''' <summary>
            ''' Inverts the sense of the TXD line.
            ''' </summary>
            Public InvertTXD As Byte
            ''' <summary>
            ''' Inverts the sense of the RXD line.
            ''' </summary>
            Public InvertRXD As Byte
            ''' <summary>
            ''' Inverts the sense of the RTS line.
            ''' </summary>
            Public InvertRTS As Byte
            ''' <summary>
            ''' Inverts the sense of the CTS line.
            ''' </summary>
            Public InvertCTS As Byte
            ''' <summary>
            ''' Inverts the sense of the DTR line.
            ''' </summary>
            Public InvertDTR As Byte
            ''' <summary>
            ''' Inverts the sense of the DSR line.
            ''' </summary>
            Public InvertDSR As Byte
            ''' <summary>
            ''' Inverts the sense of the DCD line.
            ''' </summary>
            Public InvertDCD As Byte
            ''' <summary>
            ''' Inverts the sense of the RI line.
            ''' </summary>
            Public InvertRI As Byte
            ''' <summary>
            ''' Determines whether the Battery Charge Detection option is enabled.
            ''' </summary>
            Public BCDEnable As Byte
            ''' <summary>
            ''' Asserts the power enable signal on CBUS when charging port detected.
            ''' </summary>
            Public BCDForceCbusPWREN As Byte
            ''' <summary>
            ''' Forces the device never to go into sleep mode.
            ''' </summary>
            Public BCDDisableSleep As Byte
            ''' <summary>
            ''' I2C slave device address.
            ''' </summary>
            Public I2CSlaveAddress As UShort
            ''' <summary>
            ''' I2C device ID.
            ''' </summary>
            Public I2CDeviceId As UInteger
            ''' <summary>
            ''' Disable I2C Schmitt trigger.
            ''' </summary>
            Public I2CDisableSchmitt As Byte
            ''' <summary>
            ''' FT1248 clock polarity - clock idle high (1) or clock idle low (0).
            ''' </summary>
            Public FT1248Cpol As Byte
            ''' <summary>
            ''' FT1248 data is LSB (1) or MSB (0).
            ''' </summary>
            Public FT1248Lsb As Byte
            ''' <summary>
            ''' FT1248 flow control enable.
            ''' </summary>
            Public FT1248FlowControl As Byte
            ''' <summary>
            ''' Enable RS485 Echo Suppression.
            ''' </summary>
            Public RS485EchoSuppress As Byte
            ''' <summary>
            ''' Enable Power Save mode.
            ''' </summary>
            Public PowerSaveEnable As Byte
            ''' <summary>
            ''' Determines whether the VCP driver is loaded.
            ''' </summary>
            Public IsVCP As Byte
        End Class

#End Region '/СТРУКТУРЫ ОБЪЕКТОВ В ППЗУ FTDI

#Region "УКАЗАТЕЛИ НА ФУНКЦИИ БИБЛИОТЕКИ ДЛЯ РАБОТЫ С ППЗУ"

        Private Const NOT_INIT As Integer = -1

        Private Shared PFt_ReadEE As Integer = NOT_INIT
        Private Shared PFt_WriteEE As Integer = NOT_INIT
        Private Shared PFt_EraseEE As Integer = NOT_INIT
        Private Shared PFt_EE_UASize As Integer = NOT_INIT
        Private Shared PFt_EE_UARead As Integer = NOT_INIT
        Private Shared PFt_EE_UAWrite As Integer = NOT_INIT
        Private Shared PFt_EE_Read As Integer = NOT_INIT
        Private Shared PFt_EE_Program As Integer = NOT_INIT
        Private Shared PFt_EEPROM_Read As Integer = NOT_INIT
        Private Shared PFt_EEPROM_Program As Integer = NOT_INIT

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EeReadDelegate(ftHandle As Integer, ByRef pData As FT_PROGRAM_DATA) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EeProgramDelegate(ftHandle As Integer, ByRef pData As FT_PROGRAM_DATA) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EepromReadDelegate(ftHandle As Integer, eepromData As IntPtr, eepromDataSize As UInteger, manufacturer As Byte(), manufacturerID As Byte(), description As Byte(), serialnumber As Byte()) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EepromProgramDelegate(ftHandle As Integer, eepromData As IntPtr, eepromDataSize As UInteger, manufacturer As Byte(), manufacturerID As Byte(), description As Byte(), serialnumber As Byte()) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function WriteEeDelegate(ftHandle As Integer, dwWordOffset As UInteger, wValue As UShort) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EraseEeDelegate(ftHandle As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EeUaSizeDelegate(ftHandle As Integer, ByRef dwSize As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EeUaReadDelegate(ftHandle As Integer, pucData As Byte(), dwDataLen As Integer, ByRef lpdwDataRead As UInteger) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function EeUaWriteDelegate(ftHandle As Integer, pucData As Byte(), dwDataLen As Integer) As FT_STATUS

        <UnmanagedFunctionPointer(CallingConvention.StdCall)>
        Private Delegate Function ReadEeDelegate(ftHandle As Integer, dwWordOffset As UInteger, ByRef lpwValue As UShort) As FT_STATUS

        Private Shared Sub FindEeFunctionPointers(ftd2xxDllHandle As Integer)
            If (PFt_ReadEE = NOT_INIT) Then
                PFt_ReadEE = GetProcAddress(ftd2xxDllHandle, "FT_ReadEE")
            End If
            If (PFt_WriteEE = NOT_INIT) Then
                PFt_WriteEE = GetProcAddress(ftd2xxDllHandle, "FT_WriteEE")
            End If
            If (PFt_EraseEE = NOT_INIT) Then
                PFt_EraseEE = GetProcAddress(ftd2xxDllHandle, "FT_EraseEE")
            End If
            If (PFt_EE_UASize = NOT_INIT) Then
                PFt_EE_UASize = GetProcAddress(ftd2xxDllHandle, "FT_EE_UASize")
            End If
            If (PFt_EE_UARead = NOT_INIT) Then
                PFt_EE_UARead = GetProcAddress(ftd2xxDllHandle, "FT_EE_UARead")
            End If
            If (PFt_EE_UAWrite = NOT_INIT) Then
                PFt_EE_UAWrite = GetProcAddress(ftd2xxDllHandle, "FT_EE_UAWrite")
            End If
            If (PFt_EE_Read = NOT_INIT) Then
                PFt_EE_Read = GetProcAddress(ftd2xxDllHandle, "FT_EE_Read")
            End If
            If (PFt_EE_Program = NOT_INIT) Then
                PFt_EE_Program = GetProcAddress(ftd2xxDllHandle, "FT_EE_Program")
            End If
            If (PFt_EEPROM_Read = NOT_INIT) Then
                PFt_EEPROM_Read = GetProcAddress(ftd2xxDllHandle, "FT_EEPROM_Read")
            End If
            If (PFt_EEPROM_Program = NOT_INIT) Then
                PFt_EEPROM_Program = GetProcAddress(ftd2xxDllHandle, "FT_EEPROM_Program")
            End If
        End Sub

        <DllImport("kernel32.dll", SetLastError:=True)>
        Private Shared Function GetProcAddress(hModule As Integer, procedureName As String) As Integer
        End Function

#End Region '/УКАЗАТЕЛИ НА ФУНКЦИИ БИБЛИОТЕКИ ДЛЯ РАБОТЫ С ППЗУ

#Region "ПЕРЕЧИСЛЕНИЯ"

        Public Enum FT_DRIVE_CURRENT As Byte
            FT_DRIVE_CURRENT_4MA = 4
            FT_DRIVE_CURRENT_8MA = 8
            FT_DRIVE_CURRENT_12MA = 12
            FT_DRIVE_CURRENT_16MA = 16
        End Enum

        Public Enum FT_232H_CBUS_OPTIONS As Byte
            FT_CBUS_TRISTATE = 0
            FT_CBUS_RXLED = 1
            FT_CBUS_TXLED = &H2
            FT_CBUS_TXRXLED = &H3
            FT_CBUS_PWREN = &H4
            FT_CBUS_SLEEP = &H5
            FT_CBUS_DRIVE_0 = &H6
            FT_CBUS_DRIVE_1 = &H7
            FT_CBUS_IOMODE = &H8
            FT_CBUS_TXDEN = &H9
            FT_CBUS_CLK30 = &HA
            FT_CBUS_CLK15 = &HB
            FT_CBUS_CLK7_5 = &HC
        End Enum

        Public Enum FT_XSERIES_CBUS_OPTIONS As Byte
            FT_CBUS_TRISTATE = &H0
            FT_CBUS_RXLED = &H1
            FT_CBUS_TXLED = &H2
            FT_CBUS_TXRXLED = &H3
            FT_CBUS_PWREN = &H4
            FT_CBUS_SLEEP = &H5
            FT_CBUS_Drive_0 = &H6
            FT_CBUS_Drive_1 = &H7
            FT_CBUS_GPIO = &H8
            FT_CBUS_TXDEN = &H9
            FT_CBUS_CLK24MHz = &HA
            FT_CBUS_CLK12MHz = &HB
            FT_CBUS_CLK6MHz = &HC
            FT_CBUS_BCD_Charger = &HD
            FT_CBUS_BCD_Charger_N = &HE
            FT_CBUS_I2C_TXE = &HF
            FT_CBUS_I2C_RXF = &H10
            FT_CBUS_VBUS_Sense = &H11
            FT_CBUS_BitBang_WR = &H12
            FT_CBUS_BitBang_RD = &H13
            FT_CBUS_Time_Stamp = &H14
            FT_CBUS_Keep_Awake = &H15
        End Enum

        Public Enum USB_VERSION As UShort
            VER_11 = &H110
            VER_20 = &H200
        End Enum

#End Region '/ПЕРЕЧИСЛЕНИЯ

    End Class '/Eeprom

End Namespace

Использовать данный класс можно, например, так:

Console.WriteLine($"Число подключённых устройств FTDI: {Ftdi.GetNumberOfDevices()}")
Using ft as New FTD2XX_NET.Ftdi(0)
    Console.WriteLine("Открыто устройство с индексом 0.")
    Console.WriteLine($"Описание: {ft.Description}")
    Console.WriteLine($"Серийный номер: {ft.SerialNumber}")
    Console.WriteLine($"Размер пользовательского ПЗУ: {ft.Eeprom.UserAreaSize} байт")
End Using

Ещё один интересный момент – использование уведомлений о событии. Например, можно задать уведомление о приходе данных на вход микросхемы FTDI:

Dim ftEvent As New AutoResetEvent(False) 'объявляем сигнальный объект
ft.SetEventNotification(FT_EVENTS.FT_EVENT_RXCHAR, ftEvent) 'назначаем ему событие прихода данных

Далее где-то в коде можно подождать, пока сработает это уведомление:

If ftEvent.WaitOne() Then ...
    'какая-то обработка данных

Чтобы всё работало, в системе должен быть установлен драйвер для устройства FTDI, а также в заданной директории (путь задаётся в классе Ftdi) должна находиться dll-ка FTD2XX.DLL, которую необходимо скачать с сайта производителя.

Понятно, что данный код несовершенен, и я буду его периодически обновлять. Все самые свежие обновления данного класса Ftdi будут размещаться в репозитории на GitHub.

Last modified onЧетверг, 17 Февраль 2022 19:01 Read 4783 times
Ключевые слова: :

Поблагодарить автора:

Поделиться

Print Friendly, PDF & Email

Leave a comment