15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#!/usr/bin/env python 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# portable serial port access with python 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# This is a module that gathers a list of serial ports including details on OSX 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# with contributions from cibomahto, dgs3, FarMcKon, tedbrandston 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# and modifications by cliechti 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# this is distributed under a free software license, see license.txt 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# List all of the callout devices in OS/X by querying IOKit. 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# See the following for a reference of how to do this: 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# More help from darwin_hid.py 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Also see the 'IORegistryExplorer' for an idea of what we are actually searching 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import ctypes 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from ctypes import util 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import re 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit')) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault") 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault") 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)kCFStringEncodingMacRoman = 0 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOServiceMatching.restype = ctypes.c_void_p 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32] 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryGetPath.restype = ctypes.c_void_p 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p] 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IORegistryEntryGetName.restype = ctypes.c_void_p 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p] 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOObjectGetClass.restype = ctypes.c_void_p 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)iokit.IOObjectRelease.argtypes = [ctypes.c_void_p] 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32] 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFStringCreateWithCString.restype = ctypes.c_void_p 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32] 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFStringGetCStringPtr.restype = ctypes.c_char_p 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p] 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)cf.CFNumberGetValue.restype = ctypes.c_void_p 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def get_string_property(device_t, property): 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ Search the given device for the specified string property 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @param device_t Device to search 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @param property String to search for. 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @return Python string containing the value, or None if not found. 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key = cf.CFStringCreateWithCString( 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFAllocatorDefault, 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) property.encode("mac_roman"), 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFStringEncodingMacRoman 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CFContainer = iokit.IORegistryEntryCreateCFProperty( 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_t, 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key, 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFAllocatorDefault, 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ); 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output = None 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if CFContainer: 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output = cf.CFStringGetCStringPtr(CFContainer, 0) 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return output 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def get_int_property(device_t, property): 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ Search the given device for the specified string property 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @param device_t Device to search 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @param property String to search for. 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @return Python string containing the value, or None if not found. 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key = cf.CFStringCreateWithCString( 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFAllocatorDefault, 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) property.encode("mac_roman"), 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFStringEncodingMacRoman 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CFContainer = iokit.IORegistryEntryCreateCFProperty( 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_t, 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) key, 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kCFAllocatorDefault, 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) number = ctypes.c_uint16() 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if CFContainer: 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output = cf.CFNumberGetValue(CFContainer, 2, ctypes.byref(number)) 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return number.value 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def IORegistryEntryGetName(device): 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pathname = ctypes.create_string_buffer(100) # TODO: Is this ok? 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iokit.IOObjectGetClass( 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device, 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(pathname) 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return pathname.value 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def GetParentDeviceByType(device, parent_type): 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ Find the first parent of a device that implements the parent_type 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @param IOService Service to inspect 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @return Pointer to the parent type, or None if it was not found. 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice. 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while IORegistryEntryGetName(device) != parent_type: 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) parent = ctypes.c_void_p() 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) response = iokit.IORegistryEntryGetParentEntry( 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device, 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "IOService".encode("mac_roman"), 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(parent) 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # If we weren't able to find a parent for the device, we're done. 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if response != 0: 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return None 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device = parent 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return device 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def GetIOServicesByType(service_type): 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) serial_port_iterator = ctypes.c_void_p() 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) response = iokit.IOServiceGetMatchingServices( 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kIOMasterPortDefault, 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iokit.IOServiceMatching(service_type), 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ctypes.byref(serial_port_iterator) 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) services = [] 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while iokit.IOIteratorIsValid(serial_port_iterator): 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) service = iokit.IOIteratorNext(serial_port_iterator) 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not service: 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) services.append(service) 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) iokit.IOObjectRelease(serial_port_iterator) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return services 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def comports(): 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # Scan for all iokit serial ports 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) services = GetIOServicesByType('IOSerialBSDClient') 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ports = [] 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for service in services: 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info = [] 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # First, add the callout device file. 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info.append(get_string_property(service, "IOCalloutDevice")) 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # If the serial port is implemented by a 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) usb_device = GetParentDeviceByType(service, "IOUSBDevice") 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if usb_device != None: 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info.append(get_string_property(usb_device, "USB Product Name")) 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info.append( 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "USB VID:PID=%x:%x SNR=%s"%( 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) get_int_property(usb_device, "idVendor"), 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) get_int_property(usb_device, "idProduct"), 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) get_string_property(usb_device, "USB Serial Number")) 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ) 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info.append('n/a') 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info.append('n/a') 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ports.append(info) 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return ports 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# test 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)if __name__ == '__main__': 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for port, desc, hwid in sorted(comports()): 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) print "%s: %s [%s]" % (port, desc, hwid) 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 209