不打开连接可以知道FTDI设备端口号吗?

问题描述 投票:0回答:1

我想列出 FTDI 端口及其描述,这是我的程序:

#include <iostream>
#include "ftd2xx.h"

int main( int argc, char* argv[] )
{
    DWORD numDevs = 0, i = 0;
    FT_DEVICE_LIST_INFO_NODE *ftDevList = NULL;
    FT_STATUS ftStatus;

    /* Get the number of FTDI D2XX devices connected to the system.
     * This also trigs in the driver the creation of a list which we later get
     * using FT_GetDeviceInfoList(). */
    if( (ftStatus = FT_CreateDeviceInfoList(&numDevs)) != FT_OK )
    {
        std::cout << "FT_CreateDeviceInfoList failed with error " << ftStatus << std::endl;
        return 1;
    }

    if( numDevs != 0 )
    {
        /* Ask the FTDI USB driver the list of all numDevs FTDI D2XX devices which
         * are plugged in the PC: */
        ftDevList = (FT_DEVICE_LIST_INFO_NODE *)
                        malloc(numDevs * sizeof(FT_DEVICE_LIST_INFO_NODE));
        if ( !ftDevList )
        {
            std::cout << "Could not get device list" << std::endl;
            return 1;
        }

        if ( (ftStatus = FT_GetDeviceInfoList(ftDevList, &numDevs)) != FT_OK )
        {
            std::cout << "FT_GetDeviceInfoList failed with error " << ftStatus << std::endl;
            return 1;
        }

        for ( i = 0 ; i < numDevs ; i++ )
        {
            FT_HANDLE ftOpenHandle;
            if ((ftStatus = FT_Open(i,&ftOpenHandle)) == FT_OK)
            {
                LONG lComPortNumber = 0;
                if ( (ftStatus = FT_GetComPortNumber(ftOpenHandle,&lComPortNumber)) == FT_OK) 
                {
                    if (lComPortNumber == -1)
                    {
                        // No COM port assigned
                    }
                    else 
                    {
                        std::cout << "COM" << lComPortNumber << " is " << ftDevList[i].Description << std::endl;  
                    }
                }
                else 
                {
                    std::cout << "FT_GetComPortNumber failed with error " << ftStatus << std::endl;
                    return 1;
                }
                FT_Close(ftOpenHandle);
            }
            else
            {
                std::cout << "FT_Open failed with error " << ftStatus << std::endl;
                return 1;
            }
        }

        free( ftDevList );
    }
    // else: No need to build this empty list. We have all the information: "there is 
    // no USB FTDI device plugged in the PC".

    return 0;
}

但是,正如您所看到的,这会打开端口

FT_Open
/
FT_Close
。我只是很惊讶端口号不是
FT_DEVICE_LIST_INFO_NODE
的一部分...为什么我需要打开端口来检索这些基本信息?例如,使用 WIN32 API,可以在不“打开”的情况下枚举端口...有没有办法使用 FTDI 驱动程序来做到这一点?

c++ usb ftdi
1个回答
0
投票

简而言之,使用 FTDI DLL,只有在打开后才能读取 COM 端口字符串。 此外,如果由另一个进程打开,FT_CreateDeviceInfoList 不会返回任何内容。简直没用!

但是..有一个技巧, 您可以随时访问设备管理器中看到的内容,而不会“中断”。 在这里您可以找到 COM 端口和 FTDI 序列号的缓存副本 --> 即使连接打开时<--

步骤:

  • 从 COM 端口的设备管理器中创建一个列表(其中包含 FTDI 序列号和 COM 端口)
  • 从 FTDI 制作清单 FT_CreateDeviceInfoList(其中包含 FTDI 序列号)
  • 比较 两个列表。任何未出现在中的 FTDI 端口 FT_CreateDeviceInfoList 已打开

我不知道在 C++ 中如何做到这一点,但是在 Windows 上的 C# 中,你明白了..

using System.Management;
...
public class DeviceManagerInfoStruct
{
    public required string? Caption { get; set; }
    public required string? Service { get; set; }
    public required string? DeviceID { get; set; }
}
...
IEnumerable<DeviceManagerInfoStruct?> ports;
// Build a query that selects all devices where PNPClass=="Ports"  (Class in device manager)
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-pnpentity#properties
using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE PNPClass like 'Ports'"))
{
    // Extract all records found in the device manager under 'Ports (LPT & COM)'
    var Ports_LPT_COM = searcher.Get().Cast<ManagementBaseObject>().ToList();
    // Populate the ports struct with DeviceManager information
    ports = Ports_LPT_COM.Select( dm_info =>
        new DeviceManagerInfo
        {
            Caption = dm_info["Caption"]?.ToString(),
            Service = dm_info["Service"]?.ToString(),
            DeviceID = dm_info["DeviceID"]?.ToString()
        } );
}
// Print results
foreach (var port in ports)
    Console.WriteLine($"Caption={port?.Caption}, Service={port?.Service}, DeviceID={port?.DeviceID}");

如果Service==FTSER2K,则它是FTDI。 您在 [Caption] 中有 COM 编号,在 [DeviceID] 中有序列号。

我得到以下结果。

Caption=ECP Printer Port (LPT1), Service=Parport, DeviceID=ACPI\PNP0401\5
Caption=Communications Port (COM1), Service=Serial, DeviceID=ACPI\PNP0501\0
Caption=USB Serial Port (COM9), Service=FTSER2K, DeviceID=FTDIBUS\VID_0403+PID_6001+FTDWGWNQA\0000
Caption=USB Serial Port (COM13), Service=FTSER2K, DeviceID=FTDIBUS\VID_0403+PID_6014+FT9UOLFJA\0000
Caption=Standard Serial over Bluetooth link (COM6), Service=BTHMODEM, DeviceID=BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0002\8&31A2A89E&0&D8373B6C9E26_C00000000
Caption=Standard Serial over Bluetooth link (COM7), Service=BTHMODEM, DeviceID=BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000\8&31A2A89E&0&000000000000_00000000
Caption=USB Serial Port (COM18), Service=FTSER2K, DeviceID=FTDIBUS\VID_0403+PID_6010+FT9OETCDA\0000
Caption=USB Serial Port (COM19), Service=FTSER2K, DeviceID=FTDIBUS\VID_0403+PID_6010+FT9OETCDB\0000
© www.soinside.com 2019 - 2024. All rights reserved.