Shell File Manager
import glob
import sys
import os
import re
try:
import subprocess
except ImportError:
def popen(argv):
try:
si, so = os.popen4(' '.join(argv))
return so.read().strip()
except:
raise IOError('lsusb failed')
else:
def popen(argv):
try:
return subprocess.check_output(argv, stderr=subprocess.STDOUT).strip()
except:
raise IOError('lsusb failed')
# The comports function is expected to return an iterable that yields tuples of
# 3 strings: port name, human readable description and a hardware ID.
#
# as currently no method is known to get the second two strings easily, they
# are currently just identical to the port name.
# try to detect the OS so that a device can be selected...
plat = sys.platform.lower()
def read_line(filename):
"""help function to read a single line from a file. returns none"""
try:
f = open(filename)
line = f.readline().strip()
f.close()
return line
except IOError:
return None
def re_group(regexp, text):
"""search for regexp in text, return 1st group on match"""
m = re.search(regexp, text)
if m: return m.group(1)
if plat[:5] == 'linux': # Linux (confirmed)
# try to extract descriptions from sysfs. this was done by experimenting,
# no guarantee that it works for all devices or in the future...
def usb_sysfs_hw_string(sysfs_path):
"""given a path to a usb device in sysfs, return a string describing it"""
bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
snr = read_line(sysfs_path+'/serial')
if snr:
snr_txt = ' SNR=%s' % (snr,)
else:
snr_txt = ''
return 'USB VID:PID=%s:%s%s' % (
read_line(sysfs_path+'/idVendor'),
read_line(sysfs_path+'/idProduct'),
snr_txt
)
def usb_lsusb_string(sysfs_path):
bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
try:
desc = popen(['lsusb', '-v', '-s', '%s:%s' % (bus, dev)])
# descriptions from device
iManufacturer = re_group('iManufacturer\s+\w+ (.+)', desc)
iProduct = re_group('iProduct\s+\w+ (.+)', desc)
iSerial = re_group('iSerial\s+\w+ (.+)', desc) or ''
# descriptions from kernel
idVendor = re_group('idVendor\s+0x\w+ (.+)', desc)
idProduct = re_group('idProduct\s+0x\w+ (.+)', desc)
# create descriptions. prefer text from device, fall back to the others
return '%s %s %s' % (iManufacturer or idVendor, iProduct or idProduct, iSerial)
except IOError:
return base
def describe(device):
"""\
Get a human readable description.
For USB-Serial devices try to run lsusb to get a human readable description.
For USB-CDC devices read the description from sysfs.
"""
base = os.path.basename(device)
# USB-Serial devices
sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
if os.path.exists(sys_dev_path):
sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
return usb_lsusb_string(sys_usb)
# USB-CDC devices
sys_dev_path = '/sys/class/tty/%s/device/interface' % (base,)
if os.path.exists(sys_dev_path):
return read_line(sys_dev_path)
return base
def hwinfo(device):
"""Try to get a HW identification using sysfs"""
base = os.path.basename(device)
if os.path.exists('/sys/class/tty/%s/device' % (base,)):
# PCI based devices
sys_id_path = '/sys/class/tty/%s/device/id' % (base,)
if os.path.exists(sys_id_path):
return read_line(sys_id_path)
# USB-Serial devices
sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
if os.path.exists(sys_dev_path):
sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
return usb_sysfs_hw_string(sys_usb)
# USB-CDC devices
if base.startswith('ttyACM'):
sys_dev_path = '/sys/class/tty/%s/device' % (base,)
if os.path.exists(sys_dev_path):
return usb_sysfs_hw_string(sys_dev_path + '/..')
return 'n/a' # XXX directly remove these from the list?
def comports():
devices = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
return [(d, describe(d), hwinfo(d)) for d in devices]
elif plat == 'cygwin': # cygwin/win32
def comports():
devices = glob.glob('/dev/com*')
return [(d, d, d) for d in devices]
elif plat == 'openbsd3': # BSD
def comports():
devices = glob.glob('/dev/ttyp*')
return [(d, d, d) for d in devices]
elif plat[:3] == 'bsd' or \
plat[:7] == 'freebsd' or \
plat[:7] == 'openbsd': # BSD
def comports():
devices = glob.glob('/dev/cuad*')
return [(d, d, d) for d in devices]
elif plat[:6] == 'darwin': # OS X (confirmed)
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/tty.*')
return [(d, d, d) for d in devices]
elif plat[:6] == 'netbsd': # NetBSD
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/dty*')
return [(d, d, d) for d in devices]
elif plat[:4] == 'irix': # IRIX
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/ttyf*')
return [(d, d, d) for d in devices]
elif plat[:2] == 'hp': # HP-UX (not tested)
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/tty*p0')
return [(d, d, d) for d in devices]
elif plat[:5] == 'sunos': # Solaris/SunOS
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/tty*c')
return [(d, d, d) for d in devices]
elif plat[:3] == 'aix': # AIX
def comports():
"""scan for available ports. return a list of device names."""
devices = glob.glob('/dev/tty*')
return [(d, d, d) for d in devices]
else:
# platform detection has failed...
sys.stderr.write("""\
don't know how to enumerate ttys on this system.
! I you know how the serial ports are named send this information to
! the author of this module:
sys.platform = %r
os.name = %r
pySerial version = %s
also add the naming scheme of the serial ports and with a bit luck you can get
this module running...
""" % (sys.platform, os.name, serial.VERSION))
raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
# test
if __name__ == '__main__':
for port, desc, hwid in sorted(comports()):
print "%s: %s [%s]" % (port, desc, hwid)
Shell File Manager Version 1.1, Coded By Shell
Email: [email protected]