Bike-X  0.8
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
list_ports_posix.py
Go to the documentation of this file.
1 import glob
2 import sys
3 import os
4 import re
5 
6 try:
7  import subprocess
8 except ImportError:
9  def popen(argv):
10  try:
11  si, so = os.popen4(' '.join(argv))
12  return so.read().strip()
13  except:
14  raise IOError('lsusb failed')
15 else:
16  def popen(argv):
17  try:
18  return subprocess.check_output(argv, stderr=subprocess.STDOUT).strip()
19  except:
20  raise IOError('lsusb failed')
21 
22 
23 # The comports function is expected to return an iterable that yields tuples of
24 # 3 strings: port name, human readable description and a hardware ID.
25 #
26 # as currently no method is known to get the second two strings easily, they
27 # are currently just identical to the port name.
28 
29 # try to detect the OS so that a device can be selected...
30 plat = sys.platform.lower()
31 
32 def read_line(filename):
33  """help function to read a single line from a file. returns none"""
34  try:
35  f = open(filename)
36  line = f.readline().strip()
37  f.close()
38  return line
39  except IOError:
40  return None
41 
42 def re_group(regexp, text):
43  """search for regexp in text, return 1st group on match"""
44  m = re.search(regexp, text)
45  if m: return m.group(1)
46 
47 
48 if plat[:5] == 'linux': # Linux (confirmed)
49  # try to extract descriptions from sysfs. this was done by experimenting,
50  # no guarantee that it works for all devices or in the future...
51 
52  def usb_sysfs_hw_string(sysfs_path):
53  """given a path to a usb device in sysfs, return a string describing it"""
54  bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
55  snr = read_line(sysfs_path+'/serial')
56  if snr:
57  snr_txt = ' SNR=%s' % (snr,)
58  else:
59  snr_txt = ''
60  return 'USB VID:PID=%s:%s%s' % (
61  read_line(sysfs_path+'/idVendor'),
62  read_line(sysfs_path+'/idProduct'),
63  snr_txt
64  )
65 
66  def usb_lsusb_string(sysfs_path):
67  bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
68  try:
69  desc = popen(['lsusb', '-v', '-s', '%s:%s' % (bus, dev)])
70  # descriptions from device
71  iManufacturer = re_group('iManufacturer\s+\w+ (.+)', desc)
72  iProduct = re_group('iProduct\s+\w+ (.+)', desc)
73  iSerial = re_group('iSerial\s+\w+ (.+)', desc) or ''
74  # descriptions from kernel
75  idVendor = re_group('idVendor\s+0x\w+ (.+)', desc)
76  idProduct = re_group('idProduct\s+0x\w+ (.+)', desc)
77  # create descriptions. prefer text from device, fall back to the others
78  return '%s %s %s' % (iManufacturer or idVendor, iProduct or idProduct, iSerial)
79  except IOError:
80  return base
81 
82  def describe(device):
83  """\
84  Get a human readable description.
85  For USB-Serial devices try to run lsusb to get a human readable description.
86  For USB-CDC devices read the description from sysfs.
87  """
88  base = os.path.basename(device)
89  # USB-Serial devices
90  sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
91  if os.path.exists(sys_dev_path):
92  sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
93  return usb_lsusb_string(sys_usb)
94  # USB-CDC devices
95  sys_dev_path = '/sys/class/tty/%s/device/interface' % (base,)
96  if os.path.exists(sys_dev_path):
97  return read_line(sys_dev_path)
98  return base
99 
100  def hwinfo(device):
101  """Try to get a HW identification using sysfs"""
102  base = os.path.basename(device)
103  if os.path.exists('/sys/class/tty/%s/device' % (base,)):
104  # PCI based devices
105  sys_id_path = '/sys/class/tty/%s/device/id' % (base,)
106  if os.path.exists(sys_id_path):
107  return read_line(sys_id_path)
108  # USB-Serial devices
109  sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
110  if os.path.exists(sys_dev_path):
111  sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
112  return usb_sysfs_hw_string(sys_usb)
113  # USB-CDC devices
114  if base.startswith('ttyACM'):
115  sys_dev_path = '/sys/class/tty/%s/device' % (base,)
116  if os.path.exists(sys_dev_path):
117  return usb_sysfs_hw_string(sys_dev_path + '/..')
118  return 'n/a' # XXX directly remove these from the list?
119 
120  def comports():
121  devices = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
122  return [(d, describe(d), hwinfo(d)) for d in devices]
123 
124 elif plat == 'cygwin': # cygwin/win32
125  def comports():
126  devices = glob.glob('/dev/com*')
127  return [(d, d, d) for d in devices]
128 
129 elif plat == 'openbsd3': # BSD
130  def comports():
131  devices = glob.glob('/dev/ttyp*')
132  return [(d, d, d) for d in devices]
133 
134 elif plat[:3] == 'bsd' or \
135  plat[:7] == 'freebsd' or \
136  plat[:7] == 'openbsd': # BSD
137 
138  def comports():
139  devices = glob.glob('/dev/cuad*')
140  return [(d, d, d) for d in devices]
141 
142 elif plat[:6] == 'darwin': # OS X (confirmed)
143  def comports():
144  """scan for available ports. return a list of device names."""
145  devices = glob.glob('/dev/tty.*')
146  return [(d, d, d) for d in devices]
147 
148 elif plat[:6] == 'netbsd': # NetBSD
149  def comports():
150  """scan for available ports. return a list of device names."""
151  devices = glob.glob('/dev/dty*')
152  return [(d, d, d) for d in devices]
153 
154 elif plat[:4] == 'irix': # IRIX
155  def comports():
156  """scan for available ports. return a list of device names."""
157  devices = glob.glob('/dev/ttyf*')
158  return [(d, d, d) for d in devices]
159 
160 elif plat[:2] == 'hp': # HP-UX (not tested)
161  def comports():
162  """scan for available ports. return a list of device names."""
163  devices = glob.glob('/dev/tty*p0')
164  return [(d, d, d) for d in devices]
165 
166 elif plat[:5] == 'sunos': # Solaris/SunOS
167  def comports():
168  """scan for available ports. return a list of device names."""
169  devices = glob.glob('/dev/tty*c')
170  return [(d, d, d) for d in devices]
171 
172 elif plat[:3] == 'aix': # AIX
173  def comports():
174  """scan for available ports. return a list of device names."""
175  devices = glob.glob('/dev/tty*')
176  return [(d, d, d) for d in devices]
177 
178 else:
179  # platform detection has failed...
180  sys.stderr.write("""\
181 don't know how to enumerate ttys on this system.
182 ! I you know how the serial ports are named send this information to
183 ! the author of this module:
184 
185 sys.platform = %r
186 os.name = %r
187 pySerial version = %s
188 
189 also add the naming scheme of the serial ports and with a bit luck you can get
190 this module running...
191 """ % (sys.platform, os.name, serial.VERSION))
192  raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
193 
194 # test
195 if __name__ == '__main__':
196  for port, desc, hwid in sorted(comports()):
197  print "%s: %s [%s]" % (port, desc, hwid)