如何在Windows中使用python获取FTDI FT4232芯片位置信息或序列号?

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

我正在使用FTDI FT4232芯片在Windows 10上扩展四个COM端口。

这些扩展的COM端口链接到四个不同的设备。因此,如果我想通过这些COM端口与其他设备进行通信,则需要知道要调用哪些端口。

我正在使用python进行编码,这是我使用pyserial所获得的。

>python -m serial.tools.list_ports -v
COM3
    desc: USB Serial Port (COM3)
    hwid: USB VID:PID=0403:6011 SER=5
COM4
    desc: USB Serial Port (COM4)
    hwid: USB VID:PID=0403:6011 SER=5
COM5
    desc: USB Serial Port (COM5)
    hwid: USB VID:PID=0403:6011 SER=5
COM6
    desc: USB Serial Port (COM6)
    hwid: USB VID:PID=0403:6011 SER=5
4 ports found

但是在Linux中,pyserial可以获取可用于区分这四个端口的位置信息。

~$:python3 -m serial.tools.list_ports -v
/dev/ttyUSB0        
    desc: Quad RS232-HS
    hwid: USB VID:PID=0403:6011 LOCATION=1-2.1:1.0
/dev/ttyUSB1        
    desc: Quad RS232-HS
    hwid: USB VID:PID=0403:6011 LOCATION=1-2.1:1.1
/dev/ttyUSB2        
    desc: Quad RS232-HS
    hwid: USB VID:PID=0403:6011 LOCATION=1-2.1:1.2
/dev/ttyUSB3        
    desc: Quad RS232-HS
    hwid: USB VID:PID=0403:6011 LOCATION=1-2.1:1.3
4 ports found

任何人都知道这个问题吗?

pyserial ftdi
1个回答
0
投票

实际上在serial.tools.list_ports.comports返回的ListPortInfo中有一个location字段。但是,看起来Windows的list_ports(list_ports_windows.py)实现似乎无法正确恢复此信息。我通过将以下行添加到我的pyserial(安装在win10 64,python3.8)中,使用了日志记录模块对此进行了调查。添加

logging.debug("szHardwareID_str: %s" % szHardwareID_str) #added this lin

之后

# stringify
szHardwareID_str = szHardwareID.value

为我屈服:

DEBUG:root:szHardwareID_str: ACPI\PNP0501\0
DEBUG:root:szHardwareID_str: FTDIBUS\VID_0403+PID_6010+6&192CD50C&0&13&2\0000
DEBUG:root:szHardwareID_str: FTDIBUS\VID_0403+PID_6010+6&192CD50C&0&13&1\0000

因此可以看到该位置实际上在此字符串中,但是稍后的字符串分析未能正确提取此信息。即,所实现的搜索与locationID不匹配:

m = re.search(r'VID_([0-9a-f]{4})(&PID_([0-9a-f]{4}))?(&MI_(\d{2}))?(\\(\w+))?', szHardwareID_str, re.I)

长话短说:据我所知,您可以修改pyserial(通过创建补丁+拉取请求在本地或全局),也可以使用pyserial.tools.list_ports模块手动“提取”信息。例如:

import ctypes
import serial
import logging

import serial.tools.list_ports_windows as lp

logging.basicConfig(level=logging.DEBUG)

################copied from list_ports_windows.py
GUIDs = (lp.GUID * 8)()  # so far only seen one used, so hope 8 are enough...
guids_size = lp.DWORD()
if not lp.SetupDiClassGuidsFromName(
        "Ports",
        GUIDs,
        ctypes.sizeof(GUIDs),
        ctypes.byref(guids_size)):
    raise ctypes.WinError()

# repeat for all possible GUIDs
for index in range(guids_size.value):
    bInterfaceNumber = None
    g_hdi = lp.SetupDiGetClassDevs(
        ctypes.byref(GUIDs[index]),
        None,
        lp.NULL,
        lp.DIGCF_PRESENT)  # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports

    devinfo = lp.SP_DEVINFO_DATA()
    devinfo.cbSize = ctypes.sizeof(devinfo)
    index = 0
    while lp.SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)):
        index += 1

        # get the real com port name
        hkey = lp.SetupDiOpenDevRegKey(
            g_hdi,
            ctypes.byref(devinfo),
            lp.DICS_FLAG_GLOBAL,
            0,
            lp.DIREG_DEV,  # DIREG_DRV for SW info
            lp.KEY_READ)
        port_name_buffer = ctypes.create_unicode_buffer(250)
        port_name_length = lp.ULONG(ctypes.sizeof(port_name_buffer))
        lp.RegQueryValueEx(
            hkey,
            "PortName",
            None,
            None,
            ctypes.byref(port_name_buffer),
            ctypes.byref(port_name_length))
        lp.RegCloseKey(hkey)

        # unfortunately does this method also include parallel ports.
        # we could check for names starting with COM or just exclude LPT
        # and hope that other "unknown" names are serial ports...
        if port_name_buffer.value.startswith('LPT'):
            continue

        # hardware ID
        szHardwareID = ctypes.create_unicode_buffer(250)
        # try to get ID that includes serial number
        if not lp.SetupDiGetDeviceInstanceId(
                g_hdi,
                ctypes.byref(devinfo),
                #~ ctypes.byref(szHardwareID),
                szHardwareID,
                ctypes.sizeof(szHardwareID) - 1,
                None):
            # fall back to more generic hardware ID if that would fail
            if not lp.SetupDiGetDeviceRegistryProperty(
                    g_hdi,
                    ctypes.byref(devinfo),
                    lp.SPDRP_HARDWAREID,
                    None,
                    ctypes.byref(szHardwareID),
                    ctypes.sizeof(szHardwareID) - 1,
                    None):
                # Ignore ERROR_INSUFFICIENT_BUFFER
                if ctypes.GetLastError() != lp.ERROR_INSUFFICIENT_BUFFER:
                    raise ctypes.WinError()
        # stringify
        szHardwareID_str = szHardwareID.value

        print(szHardwareID_str)

但是一般的解决方案(即补丁)将是恕我直言的最佳方法。也许您可以在官方的pyserial存储库中打开一个问题。

© www.soinside.com 2019 - 2024. All rights reserved.