1#!/usr/bin/env python 2# 3# This is a helper module for the various platform dependent list_port 4# implementations. 5# 6# This file is part of pySerial. https://github.com/pyserial/pyserial 7# (C) 2015 Chris Liechti <cliechti@gmx.net> 8# 9# SPDX-License-Identifier: BSD-3-Clause 10 11from __future__ import absolute_import 12 13import re 14import glob 15import os 16import os.path 17 18 19def numsplit(text): 20 """\ 21 Convert string into a list of texts and numbers in order to support a 22 natural sorting. 23 """ 24 result = [] 25 for group in re.split(r'(\d+)', text): 26 if group: 27 try: 28 group = int(group) 29 except ValueError: 30 pass 31 result.append(group) 32 return result 33 34 35class ListPortInfo(object): 36 """Info collection base class for serial ports""" 37 38 def __init__(self, device, skip_link_detection=False): 39 self.device = device 40 self.name = os.path.basename(device) 41 self.description = 'n/a' 42 self.hwid = 'n/a' 43 # USB specific data 44 self.vid = None 45 self.pid = None 46 self.serial_number = None 47 self.location = None 48 self.manufacturer = None 49 self.product = None 50 self.interface = None 51 # special handling for links 52 if not skip_link_detection and device is not None and os.path.islink(device): 53 self.hwid = 'LINK={}'.format(os.path.realpath(device)) 54 55 def usb_description(self): 56 """return a short string to name the port based on USB info""" 57 if self.interface is not None: 58 return '{} - {}'.format(self.product, self.interface) 59 elif self.product is not None: 60 return self.product 61 else: 62 return self.name 63 64 def usb_info(self): 65 """return a string with USB related information about device""" 66 return 'USB VID:PID={:04X}:{:04X}{}{}'.format( 67 self.vid or 0, 68 self.pid or 0, 69 ' SER={}'.format(self.serial_number) if self.serial_number is not None else '', 70 ' LOCATION={}'.format(self.location) if self.location is not None else '') 71 72 def apply_usb_info(self): 73 """update description and hwid from USB data""" 74 self.description = self.usb_description() 75 self.hwid = self.usb_info() 76 77 def __eq__(self, other): 78 return isinstance(other, ListPortInfo) and self.device == other.device 79 80 def __hash__(self): 81 return hash(self.device) 82 83 def __lt__(self, other): 84 if not isinstance(other, ListPortInfo): 85 raise TypeError('unorderable types: {}() and {}()'.format( 86 type(self).__name__, 87 type(other).__name__)) 88 return numsplit(self.device) < numsplit(other.device) 89 90 def __str__(self): 91 return '{} - {}'.format(self.device, self.description) 92 93 def __getitem__(self, index): 94 """Item access: backwards compatible -> (port, desc, hwid)""" 95 if index == 0: 96 return self.device 97 elif index == 1: 98 return self.description 99 elif index == 2: 100 return self.hwid 101 else: 102 raise IndexError('{} > 2'.format(index)) 103 104 105# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 106def list_links(devices): 107 """\ 108 search all /dev devices and look for symlinks to known ports already 109 listed in devices. 110 """ 111 links = [] 112 for device in glob.glob('/dev/*'): 113 if os.path.islink(device) and os.path.realpath(device) in devices: 114 links.append(device) 115 return links 116 117 118# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 119# test 120if __name__ == '__main__': 121 print(ListPortInfo('dummy')) 122