You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.6KB

  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. from __future__ import absolute_import
  11. import re
  12. import glob
  13. import os
  14. import os.path
  15. def numsplit(text):
  16. """\
  17. Convert string into a list of texts and numbers in order to support a
  18. natural sorting.
  19. """
  20. result = []
  21. for group in re.split(r'(\d+)', text):
  22. if group:
  23. try:
  24. group = int(group)
  25. except ValueError:
  26. pass
  27. result.append(group)
  28. return result
  29. class ListPortInfo(object):
  30. """Info collection base class for serial ports"""
  31. def __init__(self, device, skip_link_detection=False):
  32. self.device = device
  33. self.name = os.path.basename(device)
  34. self.description = 'n/a'
  35. self.hwid = 'n/a'
  36. # USB specific data
  37. self.vid = None
  38. self.pid = None
  39. self.serial_number = None
  40. self.location = None
  41. self.manufacturer = None
  42. self.product = None
  43. self.interface = None
  44. # special handling for links
  45. if not skip_link_detection and device is not None and os.path.islink(device):
  46. self.hwid = 'LINK={}'.format(os.path.realpath(device))
  47. def usb_description(self):
  48. """return a short string to name the port based on USB info"""
  49. if self.interface is not None:
  50. return '{} - {}'.format(self.product, self.interface)
  51. elif self.product is not None:
  52. return self.product
  53. else:
  54. return self.name
  55. def usb_info(self):
  56. """return a string with USB related information about device"""
  57. return 'USB VID:PID={:04X}:{:04X}{}{}'.format(
  58. self.vid or 0,
  59. self.pid or 0,
  60. ' SER={}'.format(self.serial_number) if self.serial_number is not None else '',
  61. ' LOCATION={}'.format(self.location) if self.location is not None else '')
  62. def apply_usb_info(self):
  63. """update description and hwid from USB data"""
  64. self.description = self.usb_description()
  65. self.hwid = self.usb_info()
  66. def __eq__(self, other):
  67. return isinstance(other, ListPortInfo) and self.device == other.device
  68. def __hash__(self):
  69. return hash(self.device)
  70. def __lt__(self, other):
  71. if not isinstance(other, ListPortInfo):
  72. raise TypeError('unorderable types: {}() and {}()'.format(
  73. type(self).__name__,
  74. type(other).__name__))
  75. return numsplit(self.device) < numsplit(other.device)
  76. def __str__(self):
  77. return '{} - {}'.format(self.device, self.description)
  78. def __getitem__(self, index):
  79. """Item access: backwards compatible -> (port, desc, hwid)"""
  80. if index == 0:
  81. return self.device
  82. elif index == 1:
  83. return self.description
  84. elif index == 2:
  85. return self.hwid
  86. else:
  87. raise IndexError('{} > 2'.format(index))
  88. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  89. def list_links(devices):
  90. """\
  91. search all /dev devices and look for symlinks to known ports already
  92. listed in devices.
  93. """
  94. links = []
  95. for device in glob.glob('/dev/*'):
  96. if os.path.islink(device) and os.path.realpath(device) in devices:
  97. links.append(device)
  98. return links
  99. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  100. # test
  101. if __name__ == '__main__':
  102. print(ListPortInfo('dummy'))