blob: 9b3a082f1acc532824f994a54cf0e9b2c541f9bb [file] [log] [blame]
cliechti6fa19112011-08-19 01:50:49 +00001#! python
2#
cliechti6fa19112011-08-19 01:50:49 +00003# This module implements a special URL handler that uses the port listing to
4# find ports by searching the string descriptions.
5#
Chris Liechti3e02f702015-12-16 23:06:04 +01006# This file is part of pySerial. https://github.com/pyserial/pyserial
Chris Liechti5fe3bdd2015-08-07 00:02:44 +02007# (C) 2011-2015 Chris Liechti <cliechti@gmx.net>
Chris Liechtifbdd8a02015-08-09 02:37:45 +02008#
9# SPDX-License-Identifier: BSD-3-Clause
cliechti6fa19112011-08-19 01:50:49 +000010#
Chris Liechti757d3ed2015-12-22 22:30:10 +010011# URL format: hwgrep://<regexp>&<option>
12#
13# where <regexp> is a Python regexp according to the re module
14#
15# violating the normal definition for URLs, the charachter `&` is used to
16# separate parameters from the arguments (instead of `?`, but the question mark
17# is heavily used in regexp'es)
18#
19# options:
20# n=<N> pick the N'th entry instead of the first one (numbering starts at 1)
Chris Liechti9df194c2015-12-23 20:12:17 +010021# skip_busy tries to open port to check if it is busy, fails on posix as ports are not locked!
cliechti6fa19112011-08-19 01:50:49 +000022
23import serial
24import serial.tools.list_ports
25
Chris Liechti5fe3bdd2015-08-07 00:02:44 +020026try:
27 basestring
28except NameError:
Chris Liechti409e10b2016-02-10 22:40:34 +010029 basestring = str # python 3 pylint: disable=redefined-builtin
cliechti6fa19112011-08-19 01:50:49 +000030
Chris Liechti033f17c2015-08-30 21:28:04 +020031
Chris Liechti5fe3bdd2015-08-07 00:02:44 +020032class Serial(serial.Serial):
33 """Just inherit the native Serial port implementation and patch the port property."""
Chris Liechti409e10b2016-02-10 22:40:34 +010034 # pylint: disable=no-member
Chris Liechti5fe3bdd2015-08-07 00:02:44 +020035
36 @serial.Serial.port.setter
37 def port(self, value):
cliechti6fa19112011-08-19 01:50:49 +000038 """translate port name before storing it"""
cliechti9a3809e2011-08-19 23:43:10 +000039 if isinstance(value, basestring) and value.startswith('hwgrep://'):
Chris Liechti3ad62fb2015-08-29 21:53:32 +020040 serial.Serial.port.__set__(self, self.from_url(value))
cliechti6fa19112011-08-19 01:50:49 +000041 else:
Chris Liechti5fe3bdd2015-08-07 00:02:44 +020042 serial.Serial.port.__set__(self, value)
cliechti6fa19112011-08-19 01:50:49 +000043
Chris Liechti3ad62fb2015-08-29 21:53:32 +020044 def from_url(self, url):
cliechti6fa19112011-08-19 01:50:49 +000045 """extract host and port from an URL string"""
Chris Liechtifbdd8a02015-08-09 02:37:45 +020046 if url.lower().startswith("hwgrep://"):
47 url = url[9:]
Chris Liechti757d3ed2015-12-22 22:30:10 +010048 n = 0
Chris Liechti9df194c2015-12-23 20:12:17 +010049 test_open = False
Chris Liechti757d3ed2015-12-22 22:30:10 +010050 args = url.split('&')
51 regexp = args.pop(0)
52 for arg in args:
53 if '=' in arg:
54 option, value = arg.split('=', 1)
55 else:
56 option = arg
57 value = None
58 if option == 'n':
59 # pick n'th element
60 n = int(value) - 1
61 if n < 1:
62 raise ValueError('option "n" expects a positive integer larger than 1: %r' % (value,))
Chris Liechti9df194c2015-12-23 20:12:17 +010063 elif option == 'skip_busy':
64 # open to test if port is available. not the nicest way..
65 test_open = True
Chris Liechti757d3ed2015-12-22 22:30:10 +010066 else:
67 raise ValueError('unknown option: %r' % (option,))
cliechti6fa19112011-08-19 01:50:49 +000068 # use a for loop to get the 1st element from the generator
Chris Liechti757d3ed2015-12-22 22:30:10 +010069 for port, desc, hwid in sorted(serial.tools.list_ports.grep(regexp)):
Chris Liechti9df194c2015-12-23 20:12:17 +010070 if test_open:
71 try:
72 s = serial.Serial(port)
73 except serial.SerialException:
74 # it has some error, skip this one
75 continue
76 else:
77 s.close()
Chris Liechti757d3ed2015-12-22 22:30:10 +010078 if n:
79 n -= 1
80 continue
cliechti6fa19112011-08-19 01:50:49 +000081 return port
82 else:
cliechti9a3809e2011-08-19 23:43:10 +000083 raise serial.SerialException('no ports found matching regexp %r' % (url,))
cliechti6fa19112011-08-19 01:50:49 +000084
cliechti6fa19112011-08-19 01:50:49 +000085# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86if __name__ == '__main__':
cliechti6fa19112011-08-19 01:50:49 +000087 s = Serial(None)
88 s.port = 'hwgrep://ttyS0'
Chris Liechti68340d72015-08-03 14:15:48 +020089 print(s)