blob: 824e6a81d1396751a50aa49619b52dd8a6b146b2 [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:
29 basestring = str # python 3
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."""
34
35 @serial.Serial.port.setter
36 def port(self, value):
cliechti6fa19112011-08-19 01:50:49 +000037 """translate port name before storing it"""
cliechti9a3809e2011-08-19 23:43:10 +000038 if isinstance(value, basestring) and value.startswith('hwgrep://'):
Chris Liechti3ad62fb2015-08-29 21:53:32 +020039 serial.Serial.port.__set__(self, self.from_url(value))
cliechti6fa19112011-08-19 01:50:49 +000040 else:
Chris Liechti5fe3bdd2015-08-07 00:02:44 +020041 serial.Serial.port.__set__(self, value)
cliechti6fa19112011-08-19 01:50:49 +000042
Chris Liechti3ad62fb2015-08-29 21:53:32 +020043 def from_url(self, url):
cliechti6fa19112011-08-19 01:50:49 +000044 """extract host and port from an URL string"""
Chris Liechtifbdd8a02015-08-09 02:37:45 +020045 if url.lower().startswith("hwgrep://"):
46 url = url[9:]
Chris Liechti757d3ed2015-12-22 22:30:10 +010047 n = 0
Chris Liechti9df194c2015-12-23 20:12:17 +010048 test_open = False
Chris Liechti757d3ed2015-12-22 22:30:10 +010049 args = url.split('&')
50 regexp = args.pop(0)
51 for arg in args:
52 if '=' in arg:
53 option, value = arg.split('=', 1)
54 else:
55 option = arg
56 value = None
57 if option == 'n':
58 # pick n'th element
59 n = int(value) - 1
60 if n < 1:
61 raise ValueError('option "n" expects a positive integer larger than 1: %r' % (value,))
Chris Liechti9df194c2015-12-23 20:12:17 +010062 elif option == 'skip_busy':
63 # open to test if port is available. not the nicest way..
64 test_open = True
Chris Liechti757d3ed2015-12-22 22:30:10 +010065 else:
66 raise ValueError('unknown option: %r' % (option,))
cliechti6fa19112011-08-19 01:50:49 +000067 # use a for loop to get the 1st element from the generator
Chris Liechti757d3ed2015-12-22 22:30:10 +010068 for port, desc, hwid in sorted(serial.tools.list_ports.grep(regexp)):
Chris Liechti9df194c2015-12-23 20:12:17 +010069 if test_open:
70 try:
71 s = serial.Serial(port)
72 except serial.SerialException:
73 # it has some error, skip this one
74 continue
75 else:
76 s.close()
Chris Liechti757d3ed2015-12-22 22:30:10 +010077 if n:
78 n -= 1
79 continue
cliechti6fa19112011-08-19 01:50:49 +000080 return port
81 else:
cliechti9a3809e2011-08-19 23:43:10 +000082 raise serial.SerialException('no ports found matching regexp %r' % (url,))
cliechti6fa19112011-08-19 01:50:49 +000083
cliechti6fa19112011-08-19 01:50:49 +000084# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85if __name__ == '__main__':
cliechti6fa19112011-08-19 01:50:49 +000086 s = Serial(None)
87 s.port = 'hwgrep://ttyS0'
Chris Liechti68340d72015-08-03 14:15:48 +020088 print(s)