1 # Win32 serial port scanner from PySerial.
2 # Modified by Andrew Q Righter for the GoodFET Project.
8 def ValidHandle(value):
10 raise ctypes.WinError()
14 HDEVINFO = ctypes.c_int
17 PCTSTR = ctypes.c_char_p
19 DWORD = ctypes.c_ulong
20 PDWORD = ctypes.POINTER(DWORD)
21 ULONG = ctypes.c_ulong
22 ULONG_PTR = ctypes.POINTER(ULONG)
23 #~ PBYTE = ctypes.c_char_p
24 PBYTE = ctypes.c_void_p
26 class GUID(ctypes.Structure):
28 ('Data1', ctypes.c_ulong),
29 ('Data2', ctypes.c_ushort),
30 ('Data3', ctypes.c_ushort),
31 ('Data4', ctypes.c_ubyte*8),
34 return "{%08x-%04x-%04x-%s-%s}" % (
38 ''.join(["%02x" % d for d in self.Data4[:2]]),
39 ''.join(["%02x" % d for d in self.Data4[2:]]),
42 class SP_DEVINFO_DATA(ctypes.Structure):
47 ('Reserved', ULONG_PTR),
50 return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst)
51 PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
53 class SP_DEVICE_INTERFACE_DATA(ctypes.Structure):
56 ('InterfaceClassGuid', GUID),
58 ('Reserved', ULONG_PTR),
61 return "InterfaceClassGuid:%s Flags:%s" % (self.InterfaceClassGuid, self.Flags)
63 PSP_DEVICE_INTERFACE_DATA = ctypes.POINTER(SP_DEVICE_INTERFACE_DATA)
65 PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
67 class dummy(ctypes.Structure):
68 _fields_=[("d1", DWORD), ("d2", CHAR)]
70 SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_A = ctypes.sizeof(dummy)
72 SetupDiDestroyDeviceInfoList = ctypes.windll.setupapi.SetupDiDestroyDeviceInfoList
73 SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO]
74 SetupDiDestroyDeviceInfoList.restype = BOOL
76 SetupDiGetClassDevs = ctypes.windll.setupapi.SetupDiGetClassDevsA
77 SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD]
78 SetupDiGetClassDevs.restype = ValidHandle # HDEVINFO
80 SetupDiEnumDeviceInterfaces = ctypes.windll.setupapi.SetupDiEnumDeviceInterfaces
81 SetupDiEnumDeviceInterfaces.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, ctypes.POINTER(GUID), DWORD, PSP_DEVICE_INTERFACE_DATA]
82 SetupDiEnumDeviceInterfaces.restype = BOOL
84 SetupDiGetDeviceInterfaceDetail = ctypes.windll.setupapi.SetupDiGetDeviceInterfaceDetailA
85 SetupDiGetDeviceInterfaceDetail.argtypes = [HDEVINFO, PSP_DEVICE_INTERFACE_DATA, PSP_DEVICE_INTERFACE_DETAIL_DATA, DWORD, PDWORD, PSP_DEVINFO_DATA]
86 SetupDiGetDeviceInterfaceDetail.restype = BOOL
88 SetupDiGetDeviceRegistryProperty = ctypes.windll.setupapi.SetupDiGetDeviceRegistryPropertyA
89 SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD]
90 SetupDiGetDeviceRegistryProperty.restype = BOOL
93 GUID_CLASS_COMPORT = GUID(0x86e0d1e0L, 0x8089, 0x11d0,
94 (ctypes.c_ubyte*8)(0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73))
97 DIGCF_DEVICEINTERFACE = 16
98 INVALID_HANDLE_VALUE = 0
99 ERROR_INSUFFICIENT_BUFFER = 122
101 SPDRP_FRIENDLYNAME = 12
102 SPDRP_LOCATION_INFORMATION = 13
103 ERROR_NO_MORE_ITEMS = 259
107 def comports(available_only=True):
108 """This generator scans the device registry for com ports and yields
109 (order, port, desc, hwid). If available_only is true only return currently
110 existing ports. Order is a helper to get sorted lists. it can be ignored
112 flags = DIGCF_DEVICEINTERFACE
114 flags |= DIGCF_PRESENT
115 g_hdi = SetupDiGetClassDevs(ctypes.byref(GUID_CLASS_COMPORT), None, NULL, flags);
116 #~ for i in range(256):
117 for dwIndex in range(256):
118 did = SP_DEVICE_INTERFACE_DATA()
119 did.cbSize = ctypes.sizeof(did)
121 if not SetupDiEnumDeviceInterfaces(
124 ctypes.byref(GUID_CLASS_COMPORT),
128 if ctypes.GetLastError() != ERROR_NO_MORE_ITEMS:
129 raise ctypes.WinError()
134 if not SetupDiGetDeviceInterfaceDetail(
137 None, 0, ctypes.byref(dwNeeded),
140 # Ignore ERROR_INSUFFICIENT_BUFFER
141 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
142 raise ctypes.WinError()
144 class SP_DEVICE_INTERFACE_DETAIL_DATA_A(ctypes.Structure):
147 ('DevicePath', CHAR*(dwNeeded.value - ctypes.sizeof(DWORD))),
150 return "DevicePath:%s" % (self.DevicePath,)
151 idd = SP_DEVICE_INTERFACE_DETAIL_DATA_A()
152 idd.cbSize = SIZEOF_SP_DEVICE_INTERFACE_DETAIL_DATA_A
153 devinfo = SP_DEVINFO_DATA()
154 devinfo.cbSize = ctypes.sizeof(devinfo)
155 if not SetupDiGetDeviceInterfaceDetail(
158 ctypes.byref(idd), dwNeeded, None,
159 ctypes.byref(devinfo)
161 raise ctypes.WinError()
164 szHardwareID = ctypes.create_string_buffer(250)
165 if not SetupDiGetDeviceRegistryProperty(
167 ctypes.byref(devinfo),
170 ctypes.byref(szHardwareID), ctypes.sizeof(szHardwareID) - 1,
173 # Ignore ERROR_INSUFFICIENT_BUFFER
174 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
175 raise ctypes.WinError()
178 szFriendlyName = ctypes.create_string_buffer(1024)
179 if not SetupDiGetDeviceRegistryProperty(
181 ctypes.byref(devinfo),
184 ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1,
187 # Ignore ERROR_INSUFFICIENT_BUFFER
188 if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
189 #~ raise ctypes.WinError()
190 # not getting friendly name for com0com devices, try something else
191 szFriendlyName = ctypes.create_string_buffer(1024)
192 if SetupDiGetDeviceRegistryProperty(
194 ctypes.byref(devinfo),
195 SPDRP_LOCATION_INFORMATION,
197 ctypes.byref(szFriendlyName), ctypes.sizeof(szFriendlyName) - 1,
200 port_name = "\\\\.\\" + szFriendlyName.value
203 port_name = szFriendlyName.value
207 m = re.search(r"\((.*?(\d+))\)", szFriendlyName.value)
208 #~ print szFriendlyName.value, m.groups()
209 port_name = m.group(1)
210 order = int(m.group(2))
211 except AttributeError, msg:
212 port_name = szFriendlyName.value
214 yield order, port_name, szFriendlyName.value, szHardwareID.value
216 SetupDiDestroyDeviceInfoList(g_hdi)
219 if __name__ == '__main__':
222 #print "Serial ports"
225 for order, port, desc, hwid in sorted(comports()):
226 print "%-10s: %s (%s) ->" % (port, desc, hwid),
228 serial.Serial(port) # test open
229 except serial.serialutil.SerialException:
230 print "Can't be openend"
236 # ADDED ITERATORS TO LIST FOR CONVENIENCE
239 for order, port, desc, hwid in comports():
247 except serial.serialutil.SerialException:
248 print "Can not be opened."
253 # List of all ports the system knows (registry)
256 print "All serial ports (registry)"
258 for order, port, desc, hwid in sorted(comports(False)):
259 print "%-10s: %s (%s)" % (port, desc, hwid)