1#!/usr/bin/env python 2# 3# This is a module that gathers a list of serial ports including details on 4# GNU/Linux systems. 5# 6# This file is part of pySerial. https://github.com/pyserial/pyserial 7# (C) 2011-2015 Chris Liechti <cliechti@gmx.net> 8# 9# SPDX-License-Identifier: BSD-3-Clause 10 11from __future__ import absolute_import 12 13import glob 14import os 15from serial.tools import list_ports_common 16 17 18class SysFS(list_ports_common.ListPortInfo): 19 """Wrapper for easy sysfs access and device info""" 20 21 def __init__(self, device): 22 super(SysFS, self).__init__(device) 23 # special handling for links 24 if device is not None and os.path.islink(device): 25 device = os.path.realpath(device) 26 is_link = True 27 else: 28 is_link = False 29 self.usb_device_path = None 30 if os.path.exists('/sys/class/tty/{}/device'.format(self.name)): 31 self.device_path = os.path.realpath('/sys/class/tty/{}/device'.format(self.name)) 32 self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem'))) 33 else: 34 self.device_path = None 35 self.subsystem = None 36 # check device type 37 if self.subsystem == 'usb-serial': 38 self.usb_interface_path = os.path.dirname(self.device_path) 39 elif self.subsystem == 'usb': 40 self.usb_interface_path = self.device_path 41 else: 42 self.usb_interface_path = None 43 # fill-in info for USB devices 44 if self.usb_interface_path is not None: 45 self.usb_device_path = os.path.dirname(self.usb_interface_path) 46 47 try: 48 num_if = int(self.read_line(self.usb_device_path, 'bNumInterfaces')) 49 except ValueError: 50 num_if = 1 51 52 self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16) 53 self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16) 54 self.serial_number = self.read_line(self.usb_device_path, 'serial') 55 if num_if > 1: # multi interface devices like FT4232 56 self.location = os.path.basename(self.usb_interface_path) 57 else: 58 self.location = os.path.basename(self.usb_device_path) 59 60 self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer') 61 self.product = self.read_line(self.usb_device_path, 'product') 62 self.interface = self.read_line(self.usb_interface_path, 'interface') 63 64 if self.subsystem in ('usb', 'usb-serial'): 65 self.apply_usb_info() 66 #~ elif self.subsystem in ('pnp', 'amba'): # PCI based devices, raspi 67 elif self.subsystem == 'pnp': # PCI based devices 68 self.description = self.name 69 self.hwid = self.read_line(self.device_path, 'id') 70 elif self.subsystem == 'amba': # raspi 71 self.description = self.name 72 self.hwid = os.path.basename(self.device_path) 73 74 if is_link: 75 self.hwid += ' LINK={}'.format(device) 76 77 def read_line(self, *args): 78 """\ 79 Helper function to read a single line from a file. 80 One or more parameters are allowed, they are joined with os.path.join. 81 Returns None on errors.. 82 """ 83 try: 84 with open(os.path.join(*args)) as f: 85 line = f.readline().strip() 86 return line 87 except IOError: 88 return None 89 90 91def comports(include_links=False): 92 devices = glob.glob('/dev/ttyS*') # built-in serial ports 93 devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver 94 devices.extend(glob.glob('/dev/ttyXRUSB*')) # xr-usb-serial port exar (DELL Edge 3001) 95 devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile 96 devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi) 97 devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices 98 devices.extend(glob.glob('/dev/ttyAP*')) # Advantech multi-port serial controllers 99 if include_links: 100 devices.extend(list_ports_common.list_links(devices)) 101 return [info 102 for info in [SysFS(d) for d in devices] 103 if info.subsystem != "platform"] # hide non-present internal serial ports 104 105# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 106# test 107if __name__ == '__main__': 108 for info in sorted(comports()): 109 print("{0}: {0.subsystem}".format(info)) 110