├── .gitignore
├── LICENSE
├── README.md
├── TODO
├── cookiecutter.inx
├── cookiecutterinkscapeplugin.zip
├── cutter
├── gcodeplot.inx
├── gcodeplot.py
├── gcodeplotutils
├── __init__.py
├── anneal.py
├── evaluate.py
├── processoffset.py
├── pyserial27
│ ├── CHANGES.txt
│ ├── LICENSE.txt
│ ├── README.txt
│ └── serial
│ │ ├── .cvsignore
│ │ ├── __init__.py
│ │ ├── rfc2217.py
│ │ ├── serialcli.py
│ │ ├── serialjava.py
│ │ ├── serialposix.py
│ │ ├── serialutil.py
│ │ ├── serialwin32.py
│ │ ├── sermsdos.py
│ │ ├── tools
│ │ ├── __init__.py
│ │ ├── list_ports.py
│ │ ├── list_ports_linux.py
│ │ ├── list_ports_osx.py
│ │ ├── list_ports_posix.py
│ │ ├── list_ports_windows.py
│ │ └── miniterm.py
│ │ ├── urlhandler
│ │ ├── __init__.py
│ │ ├── protocol_hwgrep.py
│ │ ├── protocol_loop.py
│ │ ├── protocol_rfc2217.py
│ │ └── protocol_socket.py
│ │ └── win32.py
├── pyserial3
│ ├── CHANGES.rst
│ ├── LICENSE.txt
│ ├── README.rst
│ └── serial
│ │ ├── __init__.py
│ │ ├── rfc2217.py
│ │ ├── rs485.py
│ │ ├── serialcli.py
│ │ ├── serialjava.py
│ │ ├── serialposix.py
│ │ ├── serialutil.py
│ │ ├── serialwin32.py
│ │ ├── threaded
│ │ └── __init__.py
│ │ ├── tools
│ │ ├── __init__.py
│ │ ├── hexlify_codec.py
│ │ ├── list_ports.py
│ │ ├── list_ports_common.py
│ │ ├── list_ports_linux.py
│ │ ├── list_ports_osx.py
│ │ ├── list_ports_posix.py
│ │ ├── list_ports_windows.py
│ │ └── miniterm.py
│ │ ├── urlhandler
│ │ ├── __init__.py
│ │ ├── protocol_alt.py
│ │ ├── protocol_hwgrep.py
│ │ ├── protocol_loop.py
│ │ ├── protocol_rfc2217.py
│ │ ├── protocol_socket.py
│ │ └── protocol_spy.py
│ │ └── win32.py
└── sendgcode.py
├── heart.svg
├── mpcnc-10-10
├── mpcnc-10-20
├── mpcnc-5-10-overcut1
├── svg2cookiecutter.py
└── svgpath
├── __init__.py
├── parser.py
├── path.py
└── shader.py
/.gitignore:
--------------------------------------------------------------------------------
1 | /svgpath/__pycache__/
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Convert SVG (text is not supported; convert text to paths) and HPGL to gcode for a 3-axis GCode machine,
2 | where the Z-axis controls the pen height.
3 |
4 |
5 | You can also convert the same SVG subset to HPGL.
6 |
7 | Run with no arguments for some help.
8 |
9 | Note on multiple pen usage:
10 |
11 | The pen definition file is one-pen per line, in the format:
12 |
13 | n (x,y) svgcolor comment
14 |
15 | Here, n is the pen number (pen 1 is assumed to be loaded at the start), (x,y) is the offset from the
16 | default pen position (note: gcodeplot.py will correct the offset and will NOT check for clipping at
17 | drawing edges--it is your responsibility to make sure your tool doesn't crash into anything due to
18 | offset), svgcolor is a color specification in svg format, e.g., rgb(255,255,00), #FFFF00 or yellow,
19 | and the comment is a human-readable comment.
20 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | Do not break up long lines when approximating.
2 | transforms.
--------------------------------------------------------------------------------
/cookiecutter.inx:
--------------------------------------------------------------------------------
1 |
2 |
3 | <_name>OpenSCAD Cookie Cutter Export
4 | mobi.omegacentauri.cookiecutter
5 | org.inkscape.output.svg.inkscape
6 | svg2cookiecutter.py
7 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/cookiecutterinkscapeplugin.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arpruss/gcodeplot/dc9ca1eef3b7af4a253de3adfbd0f1cac3da8364/cookiecutterinkscapeplugin.zip
--------------------------------------------------------------------------------
/cutter:
--------------------------------------------------------------------------------
1 | area=10,0,192,120
2 | input-dpi=1016,1016
3 | safe-delta-z=20
4 | lift-delta-z=2.5
5 | work-z=8.55
6 | no-hpgl-out
7 | shading-threshold=1
8 | shading-lightest=3
9 | shading-darkest=0.5
10 | shading-angle=45
11 | no-shading-crosshatch
12 | no-stroke-all
13 | optimization-timeout=30
14 | no-sort
15 | no-pause-at-start
16 | extract-color=all
17 | no-simulation
18 |
--------------------------------------------------------------------------------
/gcodeplot.inx:
--------------------------------------------------------------------------------
1 |
2 |
3 | <_name>GcodePlot
4 | mobi.omegacentauri.gcodeplot
5 | org.inkscape.output.svg.inkscape
6 | gcodeplot.py
7 |
8 |
9 |
10 | - drawing
11 | - cutting
12 | - custom
13 |
14 | 0.05
15 | 0
16 | 0
17 | 200
18 | 200
19 | 15
20 | 4
21 | 20
22 | 40
23 | 35
24 | 5
25 | false
26 |
27 |
28 | - 115200
29 | - 300
30 | - 600
31 | - 1200
32 | - 2400
33 | - 4800
34 | - 9600
35 | - 14400
36 | - 19200
37 | - 28800
38 | - 38400
39 | - 56000
40 | - 57600
41 | - 115200
42 |
43 |
44 |
45 |
46 | - none (needed if tool offset>0)
47 | - fit
48 | - down-only
49 |
50 |
51 | - none
52 | - left
53 | - center
54 | - right
55 |
56 |
57 | - none
58 | - left
59 | - center
60 | - right
61 |
62 |
63 |
64 |
65 | 1
66 | 3
67 | 0.5
68 | 45
69 | 0
70 | 60
71 |
72 | - none
73 | - 0 (positive x)
74 | - 45
75 | - 90 (positive y)
76 | - 45
77 | - 180 (negative x)
78 | - 225
79 | - 270 (negative y)
80 | - 315
81 |
82 |
83 |
84 | 1
85 | 1
86 | 1
87 |
88 |
89 |
90 |
91 |
98 |
101 |
102 |
--------------------------------------------------------------------------------
/gcodeplotutils/__init__.py:
--------------------------------------------------------------------------------
1 | # lib
--------------------------------------------------------------------------------
/gcodeplotutils/anneal.py:
--------------------------------------------------------------------------------
1 | import random
2 | import math
3 | import time
4 | import sys
5 |
6 | def distance(z1,z2):
7 | return math.hypot(z1[0]-z2[0], z1[1]-z2[1])
8 |
9 | def measure(lines, reversals, index):
10 | if index < 0 or index >= len(lines) - 1:
11 | return 0.
12 | z1 = lines[index][0] if reversals[index] else lines[index][-1]
13 | z2 = lines[index+1][-1] if reversals[index+1] else lines[index+1][0]
14 | return distance(z1,z2)
15 |
16 | def energy(lines, reversals):
17 | return sum(measure(lines, reversals, i) for i in range(len(lines)-1))
18 |
19 | def linearTemperature(u):
20 | return 1 - u
21 |
22 | def exponentialTemperature(u):
23 | return .006 ** u
24 |
25 | def optimize(lines, maxSteps=None, k=0.0001, temperature=exponentialTemperature, timeout=30, retries=2, quiet=False):
26 | t00 = time.time()
27 |
28 | if not quiet:
29 | sys.stderr.write("Optimizing...")
30 | sys.stderr.flush()
31 | lastMessagePercent = -100
32 |
33 | N = len(lines)
34 |
35 | if maxSteps == None:
36 | maxSteps = 250*N
37 |
38 | reversals = [False for i in range(N)]
39 |
40 | E = energy(lines, reversals)
41 | E0 = E
42 |
43 | if E == 0:
44 | return lines
45 |
46 | def P(deltaE,T):
47 | try:
48 | return math.exp(-deltaE/(E0*k*T))
49 | except:
50 | return 1 # overflow
51 |
52 | bestE = E
53 | bestLines = lines
54 | bestReversals = reversals
55 |
56 | tryCount = 0
57 |
58 | while tryCount < retries:
59 | t0 = time.time()
60 | step = 0
61 | while step < maxSteps:
62 | T = temperature(step/float(maxSteps))
63 |
64 | i = random.randint(0,N-1)
65 | j = random.randint(i,N-1)
66 | # useless if i==j, but that occurs rarely enough that it's not worth optimizing for
67 |
68 | oldE = measure(lines,reversals,j) + measure(lines,reversals,i-1)
69 |
70 | lines[i],lines[j]=lines[j],lines[i]
71 | reversals[i],reversals[j]=not reversals[j],not reversals[i]
72 |
73 | deltaE = measure(lines,reversals,j) + measure(lines,reversals,i-1) - oldE
74 |
75 | if P(deltaE, T) >= random.random():
76 | i += 1
77 | j -= 1
78 |
79 | while i= lastMessagePercent + 5:
101 | sys.stderr.write("[%.0f%%]" % percent)
102 | sys.stderr.flush()
103 | lastMessagePercent = percent
104 | if time.time() > t0 + timeout:
105 | sys.stderr.write("Timeout!\n")
106 | sys.stderr.flush()
107 | break
108 |
109 | step += 1
110 |
111 | if step < maxSteps and tryCount + 1 < retries:
112 | maxSteps = int(.95 * step)
113 | E = bestE
114 | lines = bestLines
115 | reversals = bestReversals
116 | tryCount += 1
117 | if not quiet:
118 | sys.stderr.write("Retrying.\n")
119 | sys.stderr.flush()
120 | else:
121 | break
122 |
123 | if not quiet:
124 | sys.stderr.write("\nTransport time improvement: %.1f%% (took %.2f seconds).\n" % ((E0-bestE)*100./E0, time.time()-t00))
125 | sys.stderr.flush()
126 |
127 | #print "final", E
128 | #print "best", bestE, energy(bestLines,bestReversals)
129 |
130 | return [list(reversed(bestLines[i])) if reversals[i] else bestLines[i] for i in range(N)]
131 |
132 | if __name__ == '__main__':
133 | lines = []
134 | random.seed(1)
135 |
136 | n = 2000
137 |
138 | for i in range(n):
139 | lines.append([(random.random(),random.random()),(random.random(),random.random())])
140 |
141 | steps = 250*n #int(20*n*math.log(n))
142 | optimize(lines, maxSteps=steps, k=0.0001, temperature=exponentialTemperature, timeout=15, retries=2)
143 |
--------------------------------------------------------------------------------
/gcodeplotutils/evaluate.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | SAFE_EVAL_RE = re.compile(r'^[-+/*()eE0-9.]+$')
4 |
5 | def safeEval(string):
6 | if not SAFE_EVAL_RE.match(string):
7 | raise ValueError()
8 | return eval(string)
9 |
10 | def evaluate(value, variables, formulas, MAX_DEPTH=100):
11 | tryAgain = True
12 | depth = 0
13 | while tryAgain and depth 0: tryAgain = True
18 | for x in variables:
19 | value,n = re.subn(r'\b' + x + r'\b', repr(variables[x]), value)
20 | if n > 0: tryAgain = True
21 | depth += 1
22 | if depth >= MAX_DEPTH:
23 | raise ValueError()
24 | return safeEval(value)
25 |
26 |
--------------------------------------------------------------------------------
/gcodeplotutils/processoffset.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding=utf-8
3 | '''
4 | Copyright (C) 2008 Aaron Spike, aaron@ekips.org
5 | Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de
6 | Copyright (C) 2016 Alexander Pruss
7 |
8 | This program is free software; you can redistribute it and/or modify
9 | it under the terms of the GNU General Public License as published by
10 | the Free Software Foundation; either version 2 of the License, or
11 | (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program; if not, write to the Free Software
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 | '''
22 |
23 | # standard libraries
24 | import math
25 |
26 | class OffsetProcessor:
27 | def __init__(self, toolOffset=1., overcut=0.2, tolerance=0.01):
28 | self.toolOffset = toolOffset
29 | self.overcut = overcut
30 | self.tolerance = tolerance
31 | self.PI = math.pi
32 | self.TWO_PI = 2 * math.pi
33 | if self.toolOffset > 0.0:
34 | self.toolOffsetFlat = self.tolerance / self.toolOffset * 4.5 # scale flatness to offset
35 | else:
36 | self.toolOffsetFlat = 0.0
37 |
38 | @staticmethod
39 | def changeLength(x1, y1, x2, y2, offset):
40 | # change length of line
41 | d = OffsetProcessor.getLength(x1, y1, x2, y2)
42 | if offset < 0:
43 | offset = max( -d, offset)
44 | x = x2 + (x2 - x1) / d * offset
45 | y = y2 + (y2 - y1) / d * offset
46 | return [x, y]
47 |
48 | @staticmethod
49 | def getLength(ax,ay,bx,by):
50 | return math.sqrt((ax-bx)**2+(ay-by)**2)
51 |
52 | def processOffset(self, cmd, posX, posY):
53 | # calculate offset correction (or dont)
54 | if self.toolOffset == 0.0:
55 | self.storePoint(cmd, posX, posY)
56 | else:
57 | # insert data into cache
58 | self.vData.pop(0)
59 | self.vData.insert(3, [cmd, posX, posY])
60 | # decide if enough data is availabe
61 | if self.vData[2][1] != -1.0:
62 | if self.vData[1][1] == -1.0:
63 | self.storePoint(self.vData[2][0], self.vData[2][1], self.vData[2][2])
64 | else:
65 | # perform tool offset correction (It's a *tad* complicated, if you want to understand it draw the data as lines on paper)
66 | if self.vData[2][0] == 'PD': # If the 3rd entry in the cache is a pen down command make the line longer by the tool offset
67 | pointThree = OffsetProcessor.changeLength(self.vData[1][1], self.vData[1][2], self.vData[2][1], self.vData[2][2], self.toolOffset)
68 | self.storePoint('PD', pointThree[0], pointThree[1])
69 | elif self.vData[0][1] != -1.0:
70 | # Elif the 1st entry in the cache is filled with data and the 3rd entry is a pen up command shift
71 | # the 3rd entry by the current tool offset position according to the 2nd command
72 | pointThree = OffsetProcessor.changeLength(self.vData[0][1], self.vData[0][2], self.vData[1][1], self.vData[1][2], self.toolOffset)
73 | pointThree[0] = self.vData[2][1] - (self.vData[1][1] - pointThree[0])
74 | pointThree[1] = self.vData[2][2] - (self.vData[1][2] - pointThree[1])
75 | self.storePoint('PU', pointThree[0], pointThree[1])
76 | else:
77 | # Else just write the 3rd entry
78 | pointThree = [self.vData[2][1], self.vData[2][2]]
79 | self.storePoint('PU', pointThree[0], pointThree[1])
80 | if self.vData[3][0] == 'PD':
81 | # If the 4th entry in the cache is a pen down command guide tool to next line with a circle between the prolonged 3rd and 4th entry
82 | if OffsetProcessor.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2]) >= self.toolOffset:
83 | pointFour = OffsetProcessor.changeLength(self.vData[3][1], self.vData[3][2], self.vData[2][1], self.vData[2][2], - self.toolOffset)
84 | else:
85 | pointFour = OffsetProcessor.changeLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2],
86 | (self.toolOffset - OffsetProcessor.getLength(self.vData[2][1], self.vData[2][2], self.vData[3][1], self.vData[3][2])))
87 | # get angle start and angle vector
88 | angleStart = math.atan2(pointThree[1] - self.vData[2][2], pointThree[0] - self.vData[2][1])
89 | angleVector = math.atan2(pointFour[1] - self.vData[2][2], pointFour[0] - self.vData[2][1]) - angleStart
90 | # switch direction when arc is bigger than 180°
91 | if angleVector > self.PI:
92 | angleVector -= self.TWO_PI
93 | elif angleVector < - self.PI:
94 | angleVector += self.TWO_PI
95 | # draw arc
96 | if angleVector >= 0:
97 | angle = angleStart + self.toolOffsetFlat
98 | while angle < angleStart + angleVector:
99 | self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset)
100 | angle += self.toolOffsetFlat
101 | else:
102 | angle = angleStart - self.toolOffsetFlat
103 | while angle > angleStart + angleVector:
104 | self.storePoint('PD', self.vData[2][1] + math.cos(angle) * self.toolOffset, self.vData[2][2] + math.sin(angle) * self.toolOffset)
105 | angle -= self.toolOffsetFlat
106 | self.storePoint('PD', pointFour[0], pointFour[1])
107 |
108 | def storePoint(self, command, x, y):
109 | # skip when no change in movement
110 | if self.lastPoint[0] == command and self.lastPoint[1] == x and self.lastPoint[2] == y:
111 | return
112 | if command == 'PD':
113 | self.curPath.append((x,y))
114 | elif command == 'PU':
115 | if len(self.curPath) > 1:
116 | self.paths.append(self.curPath)
117 | self.curPath = []
118 | self.curPath.append((x,y))
119 | self.lastPoint = [command, x, y]
120 |
121 | def processPath(self, path):
122 | self.vData = [['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0], ['', -1.0, -1.0]]
123 | self.paths = []
124 | self.curPath = []
125 | self.lastPoint = [0, 0, 0]
126 |
127 | self.processOffset('PU', 0, 0)
128 |
129 | oldPosX = float("inf")
130 | oldPosY = float("inf")
131 | for singlePath in path:
132 | cmd = 'PU'
133 | for singlePathPoint in singlePath:
134 | posX, posY = singlePathPoint
135 | # check if point is repeating, if so, ignore
136 | if OffsetProcessor.getLength(oldPosX,oldPosY,posX,posY) >= self.tolerance:
137 | self.processOffset(cmd, posX, posY)
138 | cmd = 'PD'
139 | oldPosX = posX
140 | oldPosY = posY
141 | # perform overcut
142 | if self.overcut > 0.0:
143 | # check if last and first points are the same, otherwise the path is not closed and no overcut can be performed
144 | if OffsetProcessor.getLength(oldPosX,oldPosY,singlePath[0][0],singlePath[0][1]) <= self.tolerance:
145 | overcutLength = 0
146 | for singlePathPoint in singlePath:
147 | posX, posY = singlePathPoint
148 | # check if point is repeating, if so, ignore
149 | distance = OffsetProcessor.getLength(oldPosX,oldPosY, posX,posY)
150 | if distance >= self.tolerance:
151 | overcutLength += distance
152 | if overcutLength >= self.overcut:
153 | newLength = OffsetProcessor.changeLength(oldPosX, oldPosY, posX, posY, - (overcutLength - self.overcut))
154 | self.processOffset(cmd, newLength[0], newLength[1])
155 | break
156 | else:
157 | self.processOffset(cmd, posX, posY)
158 | oldPosX = posX
159 | oldPosY = posY
160 |
161 | self.processOffset('PU', 0, 0)
162 | if len(self.curPath) > 1:
163 | self.paths.append(self.curPath)
164 | return self.paths
165 |
166 | if __name__ == '__main__':
167 | paths = [[(0,0),(20,0),(20,20),(0,20),(0,0)], [(0,0),(20,0),(20,20),(0,20),(0,0)]]
168 | op = OffsetProcessor()
169 | print(op.processPath(paths))
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2001-2013 Chris Liechti ;
2 | All Rights Reserved.
3 |
4 | This is the Python license. In short, you can use this product in
5 | commercial and non-commercial applications, modify it, redistribute it.
6 | A notification to the author when you use and/or modify it is welcome.
7 |
8 |
9 | TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING THIS SOFTWARE
10 | ===================================================================
11 |
12 | LICENSE AGREEMENT
13 | -----------------
14 |
15 | 1. This LICENSE AGREEMENT is between the copyright holder of this
16 | product, and the Individual or Organization ("Licensee") accessing
17 | and otherwise using this product in source or binary form and its
18 | associated documentation.
19 |
20 | 2. Subject to the terms and conditions of this License Agreement,
21 | the copyright holder hereby grants Licensee a nonexclusive,
22 | royalty-free, world-wide license to reproduce, analyze, test,
23 | perform and/or display publicly, prepare derivative works, distribute,
24 | and otherwise use this product alone or in any derivative version,
25 | provided, however, that copyright holders License Agreement and
26 | copyright holders notice of copyright are retained in this product
27 | alone or in any derivative version prepared by Licensee.
28 |
29 | 3. In the event Licensee prepares a derivative work that is based on
30 | or incorporates this product or any part thereof, and wants to make
31 | the derivative work available to others as provided herein, then
32 | Licensee hereby agrees to include in any such work a brief summary of
33 | the changes made to this product.
34 |
35 | 4. The copyright holder is making this product available to Licensee on
36 | an "AS IS" basis. THE COPYRIGHT HOLDER MAKES NO REPRESENTATIONS OR
37 | WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION,
38 | THE COPYRIGHT HOLDER MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
39 | WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
40 | THAT THE USE OF THIS PRODUCT WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
41 |
42 | 5. THE COPYRIGHT HOLDER SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER
43 | USERS OF THIS PRODUCT FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
44 | DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE
45 | USING THIS PRODUCT, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE
46 | POSSIBILITY THEREOF.
47 |
48 | 6. This License Agreement will automatically terminate upon a material
49 | breach of its terms and conditions.
50 |
51 | 7. Nothing in this License Agreement shall be deemed to create any
52 | relationship of agency, partnership, or joint venture between the
53 | copyright holder and Licensee. This License Agreement does not grant
54 | permission to use trademarks or trade names from the copyright holder
55 | in a trademark sense to endorse or promote products or services of
56 | Licensee, or any third party.
57 |
58 | 8. By copying, installing or otherwise using this product, Licensee
59 | agrees to be bound by the terms and conditions of this License
60 | Agreement.
61 |
62 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/README.txt:
--------------------------------------------------------------------------------
1 | ==========
2 | pySerial
3 | ==========
4 |
5 | Overview
6 | ========
7 | This module encapsulates the access for the serial port. It provides backends
8 | for Python running on Windows, Linux, BSD (possibly any POSIX compliant
9 | system), Jython and IronPython (.NET and Mono). The module named "serial"
10 | automatically selects the appropriate backend.
11 |
12 | - Project Homepage: http://pyserial.sourceforge.net
13 | - Project page on SourceForge: http://sourceforge.net/projects/pyserial/
14 | - SVN repository: http://sourceforge.net/svn/?group_id=46487
15 | - Download Page: http://sourceforge.net/project/showfiles.php?group_id=46487
16 |
17 | BSD license, (C) 2001-2013 Chris Liechti
18 |
19 |
20 | Documentation
21 | =============
22 | For API documentation, usage and examples see files in the "documentation"
23 | directory. The ".rst" files can be read in any text editor or being converted to
24 | HTML or PDF using Sphinx. An online HTML version is at
25 | http://pyserial.sourceforge.net.
26 |
27 |
28 | Examples
29 | ========
30 | Examples and unit tests are in the directory "examples".
31 |
32 |
33 | Installation
34 | ============
35 | Detailed information can be found in "documentation/pyserial.rst".
36 |
37 | The usual setup.py for Python libraries is used for the source distribution.
38 | Windows installers are also available (see download link above).
39 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/.cvsignore:
--------------------------------------------------------------------------------
1 | *.pyc
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # portable serial port access with python
4 | # this is a wrapper module for different platform implementations
5 | #
6 | # (C) 2001-2010 Chris Liechti
7 | # this is distributed under a free software license, see license.txt
8 |
9 | VERSION = '2.7'
10 |
11 | import sys
12 |
13 | if sys.platform == 'cli':
14 | from serial.serialcli import *
15 | else:
16 | import os
17 | # chose an implementation, depending on os
18 | if os.name == 'nt': #sys.platform == 'win32':
19 | from serial.serialwin32 import *
20 | elif os.name == 'posix':
21 | from serial.serialposix import *
22 | elif os.name == 'java':
23 | from serial.serialjava import *
24 | else:
25 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
26 |
27 |
28 | protocol_handler_packages = [
29 | 'serial.urlhandler',
30 | ]
31 |
32 | def serial_for_url(url, *args, **kwargs):
33 | """\
34 | Get an instance of the Serial class, depending on port/url. The port is not
35 | opened when the keyword parameter 'do_not_open' is true, by default it
36 | is. All other parameters are directly passed to the __init__ method when
37 | the port is instantiated.
38 |
39 | The list of package names that is searched for protocol handlers is kept in
40 | ``protocol_handler_packages``.
41 |
42 | e.g. we want to support a URL ``foobar://``. A module
43 | ``my_handlers.protocol_foobar`` is provided by the user. Then
44 | ``protocol_handler_packages.append("my_handlers")`` would extend the search
45 | path so that ``serial_for_url("foobar://"))`` would work.
46 | """
47 | # check remove extra parameter to not confuse the Serial class
48 | do_open = 'do_not_open' not in kwargs or not kwargs['do_not_open']
49 | if 'do_not_open' in kwargs: del kwargs['do_not_open']
50 | # the default is to use the native version
51 | klass = Serial # 'native' implementation
52 | # check port type and get class
53 | try:
54 | url_nocase = url.lower()
55 | except AttributeError:
56 | # it's not a string, use default
57 | pass
58 | else:
59 | if '://' in url_nocase:
60 | protocol = url_nocase.split('://', 1)[0]
61 | for package_name in protocol_handler_packages:
62 | module_name = '%s.protocol_%s' % (package_name, protocol,)
63 | try:
64 | handler_module = __import__(module_name)
65 | except ImportError:
66 | pass
67 | else:
68 | klass = sys.modules[module_name].Serial
69 | break
70 | else:
71 | raise ValueError('invalid URL, protocol %r not known' % (protocol,))
72 | else:
73 | klass = Serial # 'native' implementation
74 | # instantiate and open when desired
75 | instance = klass(None, *args, **kwargs)
76 | instance.port = url
77 | if do_open:
78 | instance.open()
79 | return instance
80 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/serialcli.py:
--------------------------------------------------------------------------------
1 | #! python
2 | # Python Serial Port Extension for Win32, Linux, BSD, Jython and .NET/Mono
3 | # serial driver for .NET/Mono (IronPython), .NET >= 2
4 | # see __init__.py
5 | #
6 | # (C) 2008 Chris Liechti
7 | # this is distributed under a free software license, see license.txt
8 |
9 | import clr
10 | import System
11 | import System.IO.Ports
12 | from serial.serialutil import *
13 |
14 |
15 | def device(portnum):
16 | """Turn a port number into a device name"""
17 | return System.IO.Ports.SerialPort.GetPortNames()[portnum]
18 |
19 |
20 | # must invoke function with byte array, make a helper to convert strings
21 | # to byte arrays
22 | sab = System.Array[System.Byte]
23 | def as_byte_array(string):
24 | return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython
25 |
26 | class IronSerial(SerialBase):
27 | """Serial port implementation for .NET/Mono."""
28 |
29 | BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
30 | 9600, 19200, 38400, 57600, 115200)
31 |
32 | def open(self):
33 | """Open port with current settings. This may throw a SerialException
34 | if the port cannot be opened."""
35 | if self._port is None:
36 | raise SerialException("Port must be configured before it can be used.")
37 | if self._isOpen:
38 | raise SerialException("Port is already open.")
39 | try:
40 | self._port_handle = System.IO.Ports.SerialPort(self.portstr)
41 | except Exception, msg:
42 | self._port_handle = None
43 | raise SerialException("could not open port %s: %s" % (self.portstr, msg))
44 |
45 | self._reconfigurePort()
46 | self._port_handle.Open()
47 | self._isOpen = True
48 | if not self._rtscts:
49 | self.setRTS(True)
50 | self.setDTR(True)
51 | self.flushInput()
52 | self.flushOutput()
53 |
54 | def _reconfigurePort(self):
55 | """Set communication parameters on opened port."""
56 | if not self._port_handle:
57 | raise SerialException("Can only operate on a valid port handle")
58 |
59 | #~ self._port_handle.ReceivedBytesThreshold = 1
60 |
61 | if self._timeout is None:
62 | self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
63 | else:
64 | self._port_handle.ReadTimeout = int(self._timeout*1000)
65 |
66 | # if self._timeout != 0 and self._interCharTimeout is not None:
67 | # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
68 |
69 | if self._writeTimeout is None:
70 | self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
71 | else:
72 | self._port_handle.WriteTimeout = int(self._writeTimeout*1000)
73 |
74 |
75 | # Setup the connection info.
76 | try:
77 | self._port_handle.BaudRate = self._baudrate
78 | except IOError, e:
79 | # catch errors from illegal baudrate settings
80 | raise ValueError(str(e))
81 |
82 | if self._bytesize == FIVEBITS:
83 | self._port_handle.DataBits = 5
84 | elif self._bytesize == SIXBITS:
85 | self._port_handle.DataBits = 6
86 | elif self._bytesize == SEVENBITS:
87 | self._port_handle.DataBits = 7
88 | elif self._bytesize == EIGHTBITS:
89 | self._port_handle.DataBits = 8
90 | else:
91 | raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
92 |
93 | if self._parity == PARITY_NONE:
94 | self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
95 | elif self._parity == PARITY_EVEN:
96 | self._port_handle.Parity = System.IO.Ports.Parity.Even
97 | elif self._parity == PARITY_ODD:
98 | self._port_handle.Parity = System.IO.Ports.Parity.Odd
99 | elif self._parity == PARITY_MARK:
100 | self._port_handle.Parity = System.IO.Ports.Parity.Mark
101 | elif self._parity == PARITY_SPACE:
102 | self._port_handle.Parity = System.IO.Ports.Parity.Space
103 | else:
104 | raise ValueError("Unsupported parity mode: %r" % self._parity)
105 |
106 | if self._stopbits == STOPBITS_ONE:
107 | self._port_handle.StopBits = System.IO.Ports.StopBits.One
108 | elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
109 | self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
110 | elif self._stopbits == STOPBITS_TWO:
111 | self._port_handle.StopBits = System.IO.Ports.StopBits.Two
112 | else:
113 | raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
114 |
115 | if self._rtscts and self._xonxoff:
116 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
117 | elif self._rtscts:
118 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
119 | elif self._xonxoff:
120 | self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
121 | else:
122 | self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
123 |
124 | #~ def __del__(self):
125 | #~ self.close()
126 |
127 | def close(self):
128 | """Close port"""
129 | if self._isOpen:
130 | if self._port_handle:
131 | try:
132 | self._port_handle.Close()
133 | except System.IO.Ports.InvalidOperationException:
134 | # ignore errors. can happen for unplugged USB serial devices
135 | pass
136 | self._port_handle = None
137 | self._isOpen = False
138 |
139 | def makeDeviceName(self, port):
140 | try:
141 | return device(port)
142 | except TypeError, e:
143 | raise SerialException(str(e))
144 |
145 | # - - - - - - - - - - - - - - - - - - - - - - - -
146 |
147 | def inWaiting(self):
148 | """Return the number of characters currently in the input buffer."""
149 | if not self._port_handle: raise portNotOpenError
150 | return self._port_handle.BytesToRead
151 |
152 | def read(self, size=1):
153 | """Read size bytes from the serial port. If a timeout is set it may
154 | return less characters as requested. With no timeout it will block
155 | until the requested number of bytes is read."""
156 | if not self._port_handle: raise portNotOpenError
157 | # must use single byte reads as this is the only way to read
158 | # without applying encodings
159 | data = bytearray()
160 | while size:
161 | try:
162 | data.append(self._port_handle.ReadByte())
163 | except System.TimeoutException, e:
164 | break
165 | else:
166 | size -= 1
167 | return bytes(data)
168 |
169 | def write(self, data):
170 | """Output the given string over the serial port."""
171 | if not self._port_handle: raise portNotOpenError
172 | if not isinstance(data, (bytes, bytearray)):
173 | raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
174 | try:
175 | # must call overloaded method with byte array argument
176 | # as this is the only one not applying encodings
177 | self._port_handle.Write(as_byte_array(data), 0, len(data))
178 | except System.TimeoutException, e:
179 | raise writeTimeoutError
180 | return len(data)
181 |
182 | def flushInput(self):
183 | """Clear input buffer, discarding all that is in the buffer."""
184 | if not self._port_handle: raise portNotOpenError
185 | self._port_handle.DiscardInBuffer()
186 |
187 | def flushOutput(self):
188 | """Clear output buffer, aborting the current output and
189 | discarding all that is in the buffer."""
190 | if not self._port_handle: raise portNotOpenError
191 | self._port_handle.DiscardOutBuffer()
192 |
193 | def sendBreak(self, duration=0.25):
194 | """Send break condition. Timed, returns to idle state after given duration."""
195 | if not self._port_handle: raise portNotOpenError
196 | import time
197 | self._port_handle.BreakState = True
198 | time.sleep(duration)
199 | self._port_handle.BreakState = False
200 |
201 | def setBreak(self, level=True):
202 | """Set break: Controls TXD. When active, to transmitting is possible."""
203 | if not self._port_handle: raise portNotOpenError
204 | self._port_handle.BreakState = bool(level)
205 |
206 | def setRTS(self, level=True):
207 | """Set terminal status line: Request To Send"""
208 | if not self._port_handle: raise portNotOpenError
209 | self._port_handle.RtsEnable = bool(level)
210 |
211 | def setDTR(self, level=True):
212 | """Set terminal status line: Data Terminal Ready"""
213 | if not self._port_handle: raise portNotOpenError
214 | self._port_handle.DtrEnable = bool(level)
215 |
216 | def getCTS(self):
217 | """Read terminal status line: Clear To Send"""
218 | if not self._port_handle: raise portNotOpenError
219 | return self._port_handle.CtsHolding
220 |
221 | def getDSR(self):
222 | """Read terminal status line: Data Set Ready"""
223 | if not self._port_handle: raise portNotOpenError
224 | return self._port_handle.DsrHolding
225 |
226 | def getRI(self):
227 | """Read terminal status line: Ring Indicator"""
228 | if not self._port_handle: raise portNotOpenError
229 | #~ return self._port_handle.XXX
230 | return False #XXX an error would be better
231 |
232 | def getCD(self):
233 | """Read terminal status line: Carrier Detect"""
234 | if not self._port_handle: raise portNotOpenError
235 | return self._port_handle.CDHolding
236 |
237 | # - - platform specific - - - -
238 | # none
239 |
240 |
241 | # assemble Serial class with the platform specific implementation and the base
242 | # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
243 | # library, derive from io.RawIOBase
244 | try:
245 | import io
246 | except ImportError:
247 | # classic version with our own file-like emulation
248 | class Serial(IronSerial, FileLike):
249 | pass
250 | else:
251 | # io library present
252 | class Serial(IronSerial, io.RawIOBase):
253 | pass
254 |
255 |
256 | # Nur Testfunktion!!
257 | if __name__ == '__main__':
258 | import sys
259 |
260 | s = Serial(0)
261 | sys.stdio.write('%s\n' % s)
262 |
263 | s = Serial()
264 | sys.stdio.write('%s\n' % s)
265 |
266 |
267 | s.baudrate = 19200
268 | s.databits = 7
269 | s.close()
270 | s.port = 0
271 | s.open()
272 | sys.stdio.write('%s\n' % s)
273 |
274 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/serialjava.py:
--------------------------------------------------------------------------------
1 | #!jython
2 | #
3 | # Python Serial Port Extension for Win32, Linux, BSD, Jython
4 | # module for serial IO for Jython and JavaComm
5 | # see __init__.py
6 | #
7 | # (C) 2002-2008 Chris Liechti
8 | # this is distributed under a free software license, see license.txt
9 |
10 | from serial.serialutil import *
11 |
12 | def my_import(name):
13 | mod = __import__(name)
14 | components = name.split('.')
15 | for comp in components[1:]:
16 | mod = getattr(mod, comp)
17 | return mod
18 |
19 |
20 | def detect_java_comm(names):
21 | """try given list of modules and return that imports"""
22 | for name in names:
23 | try:
24 | mod = my_import(name)
25 | mod.SerialPort
26 | return mod
27 | except (ImportError, AttributeError):
28 | pass
29 | raise ImportError("No Java Communications API implementation found")
30 |
31 |
32 | # Java Communications API implementations
33 | # http://mho.republika.pl/java/comm/
34 |
35 | comm = detect_java_comm([
36 | 'javax.comm', # Sun/IBM
37 | 'gnu.io', # RXTX
38 | ])
39 |
40 |
41 | def device(portnumber):
42 | """Turn a port number into a device name"""
43 | enum = comm.CommPortIdentifier.getPortIdentifiers()
44 | ports = []
45 | while enum.hasMoreElements():
46 | el = enum.nextElement()
47 | if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
48 | ports.append(el)
49 | return ports[portnumber].getName()
50 |
51 |
52 | class JavaSerial(SerialBase):
53 | """Serial port class, implemented with Java Communications API and
54 | thus usable with jython and the appropriate java extension."""
55 |
56 | def open(self):
57 | """Open port with current settings. This may throw a SerialException
58 | if the port cannot be opened."""
59 | if self._port is None:
60 | raise SerialException("Port must be configured before it can be used.")
61 | if self._isOpen:
62 | raise SerialException("Port is already open.")
63 | if type(self._port) == type(''): # strings are taken directly
64 | portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
65 | else:
66 | portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj
67 | try:
68 | self.sPort = portId.open("python serial module", 10)
69 | except Exception, msg:
70 | self.sPort = None
71 | raise SerialException("Could not open port: %s" % msg)
72 | self._reconfigurePort()
73 | self._instream = self.sPort.getInputStream()
74 | self._outstream = self.sPort.getOutputStream()
75 | self._isOpen = True
76 |
77 | def _reconfigurePort(self):
78 | """Set communication parameters on opened port."""
79 | if not self.sPort:
80 | raise SerialException("Can only operate on a valid port handle")
81 |
82 | self.sPort.enableReceiveTimeout(30)
83 | if self._bytesize == FIVEBITS:
84 | jdatabits = comm.SerialPort.DATABITS_5
85 | elif self._bytesize == SIXBITS:
86 | jdatabits = comm.SerialPort.DATABITS_6
87 | elif self._bytesize == SEVENBITS:
88 | jdatabits = comm.SerialPort.DATABITS_7
89 | elif self._bytesize == EIGHTBITS:
90 | jdatabits = comm.SerialPort.DATABITS_8
91 | else:
92 | raise ValueError("unsupported bytesize: %r" % self._bytesize)
93 |
94 | if self._stopbits == STOPBITS_ONE:
95 | jstopbits = comm.SerialPort.STOPBITS_1
96 | elif stopbits == STOPBITS_ONE_POINT_FIVE:
97 | self._jstopbits = comm.SerialPort.STOPBITS_1_5
98 | elif self._stopbits == STOPBITS_TWO:
99 | jstopbits = comm.SerialPort.STOPBITS_2
100 | else:
101 | raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
102 |
103 | if self._parity == PARITY_NONE:
104 | jparity = comm.SerialPort.PARITY_NONE
105 | elif self._parity == PARITY_EVEN:
106 | jparity = comm.SerialPort.PARITY_EVEN
107 | elif self._parity == PARITY_ODD:
108 | jparity = comm.SerialPort.PARITY_ODD
109 | elif self._parity == PARITY_MARK:
110 | jparity = comm.SerialPort.PARITY_MARK
111 | elif self._parity == PARITY_SPACE:
112 | jparity = comm.SerialPort.PARITY_SPACE
113 | else:
114 | raise ValueError("unsupported parity type: %r" % self._parity)
115 |
116 | jflowin = jflowout = 0
117 | if self._rtscts:
118 | jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
119 | jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
120 | if self._xonxoff:
121 | jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
122 | jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
123 |
124 | self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
125 | self.sPort.setFlowControlMode(jflowin | jflowout)
126 |
127 | if self._timeout >= 0:
128 | self.sPort.enableReceiveTimeout(self._timeout*1000)
129 | else:
130 | self.sPort.disableReceiveTimeout()
131 |
132 | def close(self):
133 | """Close port"""
134 | if self._isOpen:
135 | if self.sPort:
136 | self._instream.close()
137 | self._outstream.close()
138 | self.sPort.close()
139 | self.sPort = None
140 | self._isOpen = False
141 |
142 | def makeDeviceName(self, port):
143 | return device(port)
144 |
145 | # - - - - - - - - - - - - - - - - - - - - - - - -
146 |
147 | def inWaiting(self):
148 | """Return the number of characters currently in the input buffer."""
149 | if not self.sPort: raise portNotOpenError
150 | return self._instream.available()
151 |
152 | def read(self, size=1):
153 | """Read size bytes from the serial port. If a timeout is set it may
154 | return less characters as requested. With no timeout it will block
155 | until the requested number of bytes is read."""
156 | if not self.sPort: raise portNotOpenError
157 | read = bytearray()
158 | if size > 0:
159 | while len(read) < size:
160 | x = self._instream.read()
161 | if x == -1:
162 | if self.timeout >= 0:
163 | break
164 | else:
165 | read.append(x)
166 | return bytes(read)
167 |
168 | def write(self, data):
169 | """Output the given string over the serial port."""
170 | if not self.sPort: raise portNotOpenError
171 | if not isinstance(data, (bytes, bytearray)):
172 | raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
173 | self._outstream.write(data)
174 | return len(data)
175 |
176 | def flushInput(self):
177 | """Clear input buffer, discarding all that is in the buffer."""
178 | if not self.sPort: raise portNotOpenError
179 | self._instream.skip(self._instream.available())
180 |
181 | def flushOutput(self):
182 | """Clear output buffer, aborting the current output and
183 | discarding all that is in the buffer."""
184 | if not self.sPort: raise portNotOpenError
185 | self._outstream.flush()
186 |
187 | def sendBreak(self, duration=0.25):
188 | """Send break condition. Timed, returns to idle state after given duration."""
189 | if not self.sPort: raise portNotOpenError
190 | self.sPort.sendBreak(duration*1000.0)
191 |
192 | def setBreak(self, level=1):
193 | """Set break: Controls TXD. When active, to transmitting is possible."""
194 | if self.fd is None: raise portNotOpenError
195 | raise SerialException("The setBreak function is not implemented in java.")
196 |
197 | def setRTS(self, level=1):
198 | """Set terminal status line: Request To Send"""
199 | if not self.sPort: raise portNotOpenError
200 | self.sPort.setRTS(level)
201 |
202 | def setDTR(self, level=1):
203 | """Set terminal status line: Data Terminal Ready"""
204 | if not self.sPort: raise portNotOpenError
205 | self.sPort.setDTR(level)
206 |
207 | def getCTS(self):
208 | """Read terminal status line: Clear To Send"""
209 | if not self.sPort: raise portNotOpenError
210 | self.sPort.isCTS()
211 |
212 | def getDSR(self):
213 | """Read terminal status line: Data Set Ready"""
214 | if not self.sPort: raise portNotOpenError
215 | self.sPort.isDSR()
216 |
217 | def getRI(self):
218 | """Read terminal status line: Ring Indicator"""
219 | if not self.sPort: raise portNotOpenError
220 | self.sPort.isRI()
221 |
222 | def getCD(self):
223 | """Read terminal status line: Carrier Detect"""
224 | if not self.sPort: raise portNotOpenError
225 | self.sPort.isCD()
226 |
227 |
228 | # assemble Serial class with the platform specific implementation and the base
229 | # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
230 | # library, derive from io.RawIOBase
231 | try:
232 | import io
233 | except ImportError:
234 | # classic version with our own file-like emulation
235 | class Serial(JavaSerial, FileLike):
236 | pass
237 | else:
238 | # io library present
239 | class Serial(JavaSerial, io.RawIOBase):
240 | pass
241 |
242 |
243 | if __name__ == '__main__':
244 | s = Serial(0,
245 | baudrate=19200, # baudrate
246 | bytesize=EIGHTBITS, # number of databits
247 | parity=PARITY_EVEN, # enable parity checking
248 | stopbits=STOPBITS_ONE, # number of stopbits
249 | timeout=3, # set a timeout value, None for waiting forever
250 | xonxoff=0, # enable software flow control
251 | rtscts=0, # enable RTS/CTS flow control
252 | )
253 | s.setRTS(1)
254 | s.setDTR(1)
255 | s.flushInput()
256 | s.flushOutput()
257 | s.write('hello')
258 | sys.stdio.write('%r\n' % s.read(5))
259 | sys.stdio.write('%s\n' % s.inWaiting())
260 | del s
261 |
262 |
263 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/sermsdos.py:
--------------------------------------------------------------------------------
1 | # sermsdos.py
2 | #
3 | # History:
4 | #
5 | # 3rd September 2002 Dave Haynes
6 | # 1. First defined
7 | #
8 | # Although this code should run under the latest versions of
9 | # Python, on DOS-based platforms such as Windows 95 and 98,
10 | # it has been specifically written to be compatible with
11 | # PyDOS, available at:
12 | # http://www.python.org/ftp/python/wpy/dos.html
13 | #
14 | # PyDOS is a stripped-down version of Python 1.5.2 for
15 | # DOS machines. Therefore, in making changes to this file,
16 | # please respect Python 1.5.2 syntax. In addition, please
17 | # limit the width of this file to 60 characters.
18 | #
19 | # Note also that the modules in PyDOS contain fewer members
20 | # than other versions, so we are restricted to using the
21 | # following:
22 | #
23 | # In module os:
24 | # -------------
25 | # environ, chdir, getcwd, getpid, umask, fdopen, close,
26 | # dup, dup2, fstat, lseek, open, read, write, O_RDONLY,
27 | # O_WRONLY, O_RDWR, O_APPEND, O_CREAT, O_EXCL, O_TRUNC,
28 | # access, F_OK, R_OK, W_OK, X_OK, chmod, listdir, mkdir,
29 | # remove, rename, renames, rmdir, stat, unlink, utime,
30 | # execl, execle, execlp, execlpe, execvp, execvpe, _exit,
31 | # system.
32 | #
33 | # In module os.path:
34 | # ------------------
35 | # curdir, pardir, sep, altsep, pathsep, defpath, linesep.
36 | #
37 |
38 | import os
39 | import sys
40 | import string
41 | import serial.serialutil
42 |
43 | BAUD_RATES = {
44 | 110: "11",
45 | 150: "15",
46 | 300: "30",
47 | 600: "60",
48 | 1200: "12",
49 | 2400: "24",
50 | 4800: "48",
51 | 9600: "96",
52 | 19200: "19"}
53 |
54 | (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK,
55 | PARITY_SPACE) = (0, 1, 2, 3, 4)
56 | (STOPBITS_ONE, STOPBITS_ONEANDAHALF,
57 | STOPBITS_TWO) = (1, 1.5, 2)
58 | FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8)
59 | (RETURN_ERROR, RETURN_BUSY, RETURN_RETRY, RETURN_READY,
60 | RETURN_NONE) = ('E', 'B', 'P', 'R', 'N')
61 | portNotOpenError = ValueError('port not open')
62 |
63 | def device(portnum):
64 | return 'COM%d' % (portnum+1)
65 |
66 | class Serial(serialutil.FileLike):
67 | """
68 | port: number of device; numbering starts at
69 | zero. if everything fails, the user can
70 | specify a device string, note that this
71 | isn't portable any more
72 | baudrate: baud rate
73 | bytesize: number of databits
74 | parity: enable parity checking
75 | stopbits: number of stopbits
76 | timeout: set a timeout (None for waiting forever)
77 | xonxoff: enable software flow control
78 | rtscts: enable RTS/CTS flow control
79 | retry: DOS retry mode
80 | """
81 | def __init__(self,
82 | port,
83 | baudrate = 9600,
84 | bytesize = EIGHTBITS,
85 | parity = PARITY_NONE,
86 | stopbits = STOPBITS_ONE,
87 | timeout = None,
88 | xonxoff = 0,
89 | rtscts = 0,
90 | retry = RETURN_RETRY
91 | ):
92 |
93 | if type(port) == type(''):
94 | # strings are taken directly
95 | self.portstr = port
96 | else:
97 | # numbers are transformed to a string
98 | self.portstr = device(port+1)
99 |
100 | self.baud = BAUD_RATES[baudrate]
101 | self.bytesize = str(bytesize)
102 |
103 | if parity == PARITY_NONE:
104 | self.parity = 'N'
105 | elif parity == PARITY_EVEN:
106 | self.parity = 'E'
107 | elif parity == PARITY_ODD:
108 | self.parity = 'O'
109 | elif parity == PARITY_MARK:
110 | self.parity = 'M'
111 | elif parity == PARITY_SPACE:
112 | self.parity = 'S'
113 |
114 | self.stop = str(stopbits)
115 | self.retry = retry
116 | self.filename = "sermsdos.tmp"
117 |
118 | self._config(self.portstr, self.baud, self.parity,
119 | self.bytesize, self.stop, self.retry, self.filename)
120 |
121 | def __del__(self):
122 | self.close()
123 |
124 | def close(self):
125 | pass
126 |
127 | def _config(self, port, baud, parity, data, stop, retry,
128 | filename):
129 | comString = string.join(("MODE ", port, ":"
130 | , " BAUD= ", baud, " PARITY= ", parity
131 | , " DATA= ", data, " STOP= ", stop, " RETRY= ",
132 | retry, " > ", filename ), '')
133 | os.system(comString)
134 |
135 | def setBaudrate(self, baudrate):
136 | self._config(self.portstr, BAUD_RATES[baudrate],
137 | self.parity, self.bytesize, self.stop, self.retry,
138 | self.filename)
139 |
140 | def inWaiting(self):
141 | """returns the number of bytes waiting to be read"""
142 | raise NotImplementedError
143 |
144 | def read(self, num = 1):
145 | """Read num bytes from serial port"""
146 | handle = os.open(self.portstr,
147 | os.O_RDONLY | os.O_BINARY)
148 | rv = os.read(handle, num)
149 | os.close(handle)
150 | return rv
151 |
152 | def write(self, s):
153 | """Write string to serial port"""
154 | handle = os.open(self.portstr,
155 | os.O_WRONLY | os.O_BINARY)
156 | rv = os.write(handle, s)
157 | os.close(handle)
158 | return rv
159 |
160 | def flushInput(self):
161 | raise NotImplementedError
162 |
163 | def flushOutput(self):
164 | raise NotImplementedError
165 |
166 | def sendBreak(self):
167 | raise NotImplementedError
168 |
169 | def setRTS(self,level=1):
170 | """Set terminal status line"""
171 | raise NotImplementedError
172 |
173 | def setDTR(self,level=1):
174 | """Set terminal status line"""
175 | raise NotImplementedError
176 |
177 | def getCTS(self):
178 | """Eead terminal status line"""
179 | raise NotImplementedError
180 |
181 | def getDSR(self):
182 | """Eead terminal status line"""
183 | raise NotImplementedError
184 |
185 | def getRI(self):
186 | """Eead terminal status line"""
187 | raise NotImplementedError
188 |
189 | def getCD(self):
190 | """Eead terminal status line"""
191 | raise NotImplementedError
192 |
193 | def __repr__(self):
194 | return string.join(( ": ", self.portstr
195 | , self.baud, self.parity, self.bytesize, self.stop,
196 | self.retry , self.filename), ' ')
197 |
198 | if __name__ == '__main__':
199 | s = Serial(0)
200 | sys.stdio.write('%s %s\n' % (__name__, s))
201 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arpruss/gcodeplot/dc9ca1eef3b7af4a253de3adfbd0f1cac3da8364/gcodeplotutils/pyserial27/serial/tools/__init__.py
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/list_ports.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # portable serial port access with python
4 | # this is a wrapper module for different platform implementations of the
5 | # port enumeration feature
6 | #
7 | # (C) 2011-2013 Chris Liechti
8 | # this is distributed under a free software license, see license.txt
9 |
10 | """\
11 | This module will provide a function called comports that returns an
12 | iterable (generator or list) that will enumerate available com ports. Note that
13 | on some systems non-existent ports may be listed.
14 |
15 | Additionally a grep function is supplied that can be used to search for ports
16 | based on their descriptions or hardware ID.
17 | """
18 |
19 | import sys, os, re
20 |
21 | # chose an implementation, depending on os
22 | #~ if sys.platform == 'cli':
23 | #~ else:
24 | import os
25 | # chose an implementation, depending on os
26 | if os.name == 'nt': #sys.platform == 'win32':
27 | from serial.tools.list_ports_windows import *
28 | elif os.name == 'posix':
29 | from serial.tools.list_ports_posix import *
30 | #~ elif os.name == 'java':
31 | else:
32 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
33 |
34 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 |
36 | def grep(regexp):
37 | """\
38 | Search for ports using a regular expression. Port name, description and
39 | hardware ID are searched. The function returns an iterable that returns the
40 | same tuples as comport() would do.
41 | """
42 | r = re.compile(regexp, re.I)
43 | for port, desc, hwid in comports():
44 | if r.search(port) or r.search(desc) or r.search(hwid):
45 | yield port, desc, hwid
46 |
47 |
48 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49 | def main():
50 | import optparse
51 |
52 | parser = optparse.OptionParser(
53 | usage = "%prog [options] []",
54 | description = "Miniterm - A simple terminal program for the serial port."
55 | )
56 |
57 | parser.add_option("--debug",
58 | help="print debug messages and tracebacks (development mode)",
59 | dest="debug",
60 | default=False,
61 | action='store_true')
62 |
63 | parser.add_option("-v", "--verbose",
64 | help="show more messages (can be given multiple times)",
65 | dest="verbose",
66 | default=1,
67 | action='count')
68 |
69 | parser.add_option("-q", "--quiet",
70 | help="suppress all messages",
71 | dest="verbose",
72 | action='store_const',
73 | const=0)
74 |
75 | (options, args) = parser.parse_args()
76 |
77 |
78 | hits = 0
79 | # get iteraror w/ or w/o filter
80 | if args:
81 | if len(args) > 1:
82 | parser.error('more than one regexp not supported')
83 | print "Filtered list with regexp: %r" % (args[0],)
84 | iterator = sorted(grep(args[0]))
85 | else:
86 | iterator = sorted(comports())
87 | # list them
88 | for port, desc, hwid in iterator:
89 | print("%-20s" % (port,))
90 | if options.verbose > 1:
91 | print(" desc: %s" % (desc,))
92 | print(" hwid: %s" % (hwid,))
93 | hits += 1
94 | if options.verbose:
95 | if hits:
96 | print("%d ports found" % (hits,))
97 | else:
98 | print("no ports found")
99 |
100 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101 | # test
102 | if __name__ == '__main__':
103 | main()
104 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/list_ports_linux.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # portable serial port access with python
4 | #
5 | # This is a module that gathers a list of serial ports including details on
6 | # GNU/Linux systems
7 | #
8 | # (C) 2011-2013 Chris Liechti
9 | # this is distributed under a free software license, see license.txt
10 |
11 | import glob
12 | import sys
13 | import os
14 | import re
15 |
16 | try:
17 | import subprocess
18 | except ImportError:
19 | def popen(argv):
20 | try:
21 | si, so = os.popen4(' '.join(argv))
22 | return so.read().strip()
23 | except:
24 | raise IOError('lsusb failed')
25 | else:
26 | def popen(argv):
27 | try:
28 | return subprocess.check_output(argv, stderr=subprocess.STDOUT).strip()
29 | except:
30 | raise IOError('lsusb failed')
31 |
32 |
33 | # The comports function is expected to return an iterable that yields tuples of
34 | # 3 strings: port name, human readable description and a hardware ID.
35 | #
36 | # as currently no method is known to get the second two strings easily, they
37 | # are currently just identical to the port name.
38 |
39 | # try to detect the OS so that a device can be selected...
40 | plat = sys.platform.lower()
41 |
42 | def read_line(filename):
43 | """help function to read a single line from a file. returns none"""
44 | try:
45 | f = open(filename)
46 | line = f.readline().strip()
47 | f.close()
48 | return line
49 | except IOError:
50 | return None
51 |
52 | def re_group(regexp, text):
53 | """search for regexp in text, return 1st group on match"""
54 | if sys.version < '3':
55 | m = re.search(regexp, text)
56 | else:
57 | # text is bytes-like
58 | m = re.search(regexp, text.decode('ascii', 'replace'))
59 | if m: return m.group(1)
60 |
61 |
62 | # try to extract descriptions from sysfs. this was done by experimenting,
63 | # no guarantee that it works for all devices or in the future...
64 |
65 | def usb_sysfs_hw_string(sysfs_path):
66 | """given a path to a usb device in sysfs, return a string describing it"""
67 | bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
68 | snr = read_line(sysfs_path+'/serial')
69 | if snr:
70 | snr_txt = ' SNR=%s' % (snr,)
71 | else:
72 | snr_txt = ''
73 | return 'USB VID:PID=%s:%s%s' % (
74 | read_line(sysfs_path+'/idVendor'),
75 | read_line(sysfs_path+'/idProduct'),
76 | snr_txt
77 | )
78 |
79 | def usb_lsusb_string(sysfs_path):
80 | base = os.path.basename(os.path.realpath(sysfs_path))
81 | bus = base.split('-')[0]
82 | try:
83 | dev = int(read_line(os.path.join(sysfs_path, 'devnum')))
84 | desc = popen(['lsusb', '-v', '-s', '%s:%s' % (bus, dev)])
85 | # descriptions from device
86 | iManufacturer = re_group('iManufacturer\s+\w+ (.+)', desc)
87 | iProduct = re_group('iProduct\s+\w+ (.+)', desc)
88 | iSerial = re_group('iSerial\s+\w+ (.+)', desc) or ''
89 | # descriptions from kernel
90 | idVendor = re_group('idVendor\s+0x\w+ (.+)', desc)
91 | idProduct = re_group('idProduct\s+0x\w+ (.+)', desc)
92 | # create descriptions. prefer text from device, fall back to the others
93 | return '%s %s %s' % (iManufacturer or idVendor, iProduct or idProduct, iSerial)
94 | except IOError:
95 | return base
96 |
97 | def describe(device):
98 | """\
99 | Get a human readable description.
100 | For USB-Serial devices try to run lsusb to get a human readable description.
101 | For USB-CDC devices read the description from sysfs.
102 | """
103 | base = os.path.basename(device)
104 | # USB-Serial devices
105 | sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
106 | if os.path.exists(sys_dev_path):
107 | sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
108 | return usb_lsusb_string(sys_usb)
109 | # USB-CDC devices
110 | sys_dev_path = '/sys/class/tty/%s/device/interface' % (base,)
111 | if os.path.exists(sys_dev_path):
112 | return read_line(sys_dev_path)
113 | return base
114 |
115 | def hwinfo(device):
116 | """Try to get a HW identification using sysfs"""
117 | base = os.path.basename(device)
118 | if os.path.exists('/sys/class/tty/%s/device' % (base,)):
119 | # PCI based devices
120 | sys_id_path = '/sys/class/tty/%s/device/id' % (base,)
121 | if os.path.exists(sys_id_path):
122 | return read_line(sys_id_path)
123 | # USB-Serial devices
124 | sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
125 | if os.path.exists(sys_dev_path):
126 | sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
127 | return usb_sysfs_hw_string(sys_usb)
128 | # USB-CDC devices
129 | if base.startswith('ttyACM'):
130 | sys_dev_path = '/sys/class/tty/%s/device' % (base,)
131 | if os.path.exists(sys_dev_path):
132 | return usb_sysfs_hw_string(sys_dev_path + '/..')
133 | return 'n/a' # XXX directly remove these from the list?
134 |
135 | def comports():
136 | devices = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
137 | return [(d, describe(d), hwinfo(d)) for d in devices]
138 |
139 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
140 | # test
141 | if __name__ == '__main__':
142 | for port, desc, hwid in sorted(comports()):
143 | print "%s: %s [%s]" % (port, desc, hwid)
144 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/list_ports_osx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # portable serial port access with python
4 | #
5 | # This is a module that gathers a list of serial ports including details on OSX
6 | #
7 | # code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools
8 | # with contributions from cibomahto, dgs3, FarMcKon, tedbrandston
9 | # and modifications by cliechti
10 | #
11 | # this is distributed under a free software license, see license.txt
12 |
13 |
14 |
15 | # List all of the callout devices in OS/X by querying IOKit.
16 |
17 | # See the following for a reference of how to do this:
18 | # http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD
19 |
20 | # More help from darwin_hid.py
21 |
22 | # Also see the 'IORegistryExplorer' for an idea of what we are actually searching
23 |
24 | import ctypes
25 | from ctypes import util
26 | import re
27 |
28 | iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
29 | cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
30 |
31 | kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
32 | kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
33 |
34 | kCFStringEncodingMacRoman = 0
35 |
36 | iokit.IOServiceMatching.restype = ctypes.c_void_p
37 |
38 | iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
39 | iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p
40 |
41 | iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
42 |
43 | iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32]
44 | iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p
45 |
46 | iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
47 | iokit.IORegistryEntryGetPath.restype = ctypes.c_void_p
48 |
49 | iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
50 | iokit.IORegistryEntryGetName.restype = ctypes.c_void_p
51 |
52 | iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
53 | iokit.IOObjectGetClass.restype = ctypes.c_void_p
54 |
55 | iokit.IOObjectRelease.argtypes = [ctypes.c_void_p]
56 |
57 |
58 | cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32]
59 | cf.CFStringCreateWithCString.restype = ctypes.c_void_p
60 |
61 | cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32]
62 | cf.CFStringGetCStringPtr.restype = ctypes.c_char_p
63 |
64 | cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
65 | cf.CFNumberGetValue.restype = ctypes.c_void_p
66 |
67 | def get_string_property(device_t, property):
68 | """ Search the given device for the specified string property
69 |
70 | @param device_t Device to search
71 | @param property String to search for.
72 | @return Python string containing the value, or None if not found.
73 | """
74 | key = cf.CFStringCreateWithCString(
75 | kCFAllocatorDefault,
76 | property.encode("mac_roman"),
77 | kCFStringEncodingMacRoman
78 | )
79 |
80 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
81 | device_t,
82 | key,
83 | kCFAllocatorDefault,
84 | 0
85 | );
86 |
87 | output = None
88 |
89 | if CFContainer:
90 | output = cf.CFStringGetCStringPtr(CFContainer, 0)
91 |
92 | return output
93 |
94 | def get_int_property(device_t, property):
95 | """ Search the given device for the specified string property
96 |
97 | @param device_t Device to search
98 | @param property String to search for.
99 | @return Python string containing the value, or None if not found.
100 | """
101 | key = cf.CFStringCreateWithCString(
102 | kCFAllocatorDefault,
103 | property.encode("mac_roman"),
104 | kCFStringEncodingMacRoman
105 | )
106 |
107 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
108 | device_t,
109 | key,
110 | kCFAllocatorDefault,
111 | 0
112 | );
113 |
114 | number = ctypes.c_uint16()
115 |
116 | if CFContainer:
117 | output = cf.CFNumberGetValue(CFContainer, 2, ctypes.byref(number))
118 |
119 | return number.value
120 |
121 | def IORegistryEntryGetName(device):
122 | pathname = ctypes.create_string_buffer(100) # TODO: Is this ok?
123 | iokit.IOObjectGetClass(
124 | device,
125 | ctypes.byref(pathname)
126 | )
127 |
128 | return pathname.value
129 |
130 | def GetParentDeviceByType(device, parent_type):
131 | """ Find the first parent of a device that implements the parent_type
132 | @param IOService Service to inspect
133 | @return Pointer to the parent type, or None if it was not found.
134 | """
135 | # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice.
136 | while IORegistryEntryGetName(device) != parent_type:
137 | parent = ctypes.c_void_p()
138 | response = iokit.IORegistryEntryGetParentEntry(
139 | device,
140 | "IOService".encode("mac_roman"),
141 | ctypes.byref(parent)
142 | )
143 |
144 | # If we weren't able to find a parent for the device, we're done.
145 | if response != 0:
146 | return None
147 |
148 | device = parent
149 |
150 | return device
151 |
152 | def GetIOServicesByType(service_type):
153 | """
154 | """
155 | serial_port_iterator = ctypes.c_void_p()
156 |
157 | response = iokit.IOServiceGetMatchingServices(
158 | kIOMasterPortDefault,
159 | iokit.IOServiceMatching(service_type),
160 | ctypes.byref(serial_port_iterator)
161 | )
162 |
163 | services = []
164 | while iokit.IOIteratorIsValid(serial_port_iterator):
165 | service = iokit.IOIteratorNext(serial_port_iterator)
166 | if not service:
167 | break
168 | services.append(service)
169 |
170 | iokit.IOObjectRelease(serial_port_iterator)
171 |
172 | return services
173 |
174 | def comports():
175 | # Scan for all iokit serial ports
176 | services = GetIOServicesByType('IOSerialBSDClient')
177 |
178 | ports = []
179 | for service in services:
180 | info = []
181 |
182 | # First, add the callout device file.
183 | info.append(get_string_property(service, "IOCalloutDevice"))
184 |
185 | # If the serial port is implemented by a
186 | usb_device = GetParentDeviceByType(service, "IOUSBDevice")
187 | if usb_device != None:
188 | info.append(get_string_property(usb_device, "USB Product Name"))
189 |
190 | info.append(
191 | "USB VID:PID=%x:%x SNR=%s"%(
192 | get_int_property(usb_device, "idVendor"),
193 | get_int_property(usb_device, "idProduct"),
194 | get_string_property(usb_device, "USB Serial Number"))
195 | )
196 | else:
197 | info.append('n/a')
198 | info.append('n/a')
199 |
200 | ports.append(info)
201 |
202 | return ports
203 |
204 | # test
205 | if __name__ == '__main__':
206 | for port, desc, hwid in sorted(comports()):
207 | print "%s: %s [%s]" % (port, desc, hwid)
208 |
209 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/list_ports_posix.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # portable serial port access with python
4 |
5 | # This is a module that gathers a list of serial ports on POSIXy systems.
6 | # For some specific implementations, see also list_ports_linux, list_ports_osx
7 | #
8 | # this is a wrapper module for different platform implementations of the
9 | # port enumeration feature
10 | #
11 | # (C) 2011-2013 Chris Liechti
12 | # this is distributed under a free software license, see license.txt
13 |
14 | """\
15 | The ``comports`` function is expected to return an iterable that yields tuples
16 | of 3 strings: port name, human readable description and a hardware ID.
17 |
18 | As currently no method is known to get the second two strings easily, they are
19 | currently just identical to the port name.
20 | """
21 |
22 | import glob
23 | import sys
24 | import os
25 |
26 | # try to detect the OS so that a device can be selected...
27 | plat = sys.platform.lower()
28 |
29 | if plat[:5] == 'linux': # Linux (confirmed)
30 | from serial.tools.list_ports_linux import comports
31 |
32 | elif plat == 'cygwin': # cygwin/win32
33 | def comports():
34 | devices = glob.glob('/dev/com*')
35 | return [(d, d, d) for d in devices]
36 |
37 | elif plat[:7] == 'openbsd': # OpenBSD
38 | def comports():
39 | devices = glob.glob('/dev/cua*')
40 | return [(d, d, d) for d in devices]
41 |
42 | elif plat[:3] == 'bsd' or \
43 | plat[:7] == 'freebsd':
44 |
45 | def comports():
46 | devices = glob.glob('/dev/cuad*')
47 | return [(d, d, d) for d in devices]
48 |
49 | elif plat[:6] == 'darwin': # OS X (confirmed)
50 | from serial.tools.list_ports_osx import comports
51 |
52 | elif plat[:6] == 'netbsd': # NetBSD
53 | def comports():
54 | """scan for available ports. return a list of device names."""
55 | devices = glob.glob('/dev/dty*')
56 | return [(d, d, d) for d in devices]
57 |
58 | elif plat[:4] == 'irix': # IRIX
59 | def comports():
60 | """scan for available ports. return a list of device names."""
61 | devices = glob.glob('/dev/ttyf*')
62 | return [(d, d, d) for d in devices]
63 |
64 | elif plat[:2] == 'hp': # HP-UX (not tested)
65 | def comports():
66 | """scan for available ports. return a list of device names."""
67 | devices = glob.glob('/dev/tty*p0')
68 | return [(d, d, d) for d in devices]
69 |
70 | elif plat[:5] == 'sunos': # Solaris/SunOS
71 | def comports():
72 | """scan for available ports. return a list of device names."""
73 | devices = glob.glob('/dev/tty*c')
74 | return [(d, d, d) for d in devices]
75 |
76 | elif plat[:3] == 'aix': # AIX
77 | def comports():
78 | """scan for available ports. return a list of device names."""
79 | devices = glob.glob('/dev/tty*')
80 | return [(d, d, d) for d in devices]
81 |
82 | else:
83 | # platform detection has failed...
84 | sys.stderr.write("""\
85 | don't know how to enumerate ttys on this system.
86 | ! I you know how the serial ports are named send this information to
87 | ! the author of this module:
88 |
89 | sys.platform = %r
90 | os.name = %r
91 | pySerial version = %s
92 |
93 | also add the naming scheme of the serial ports and with a bit luck you can get
94 | this module running...
95 | """ % (sys.platform, os.name, serial.VERSION))
96 | raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
97 |
98 | # test
99 | if __name__ == '__main__':
100 | for port, desc, hwid in sorted(comports()):
101 | print "%s: %s [%s]" % (port, desc, hwid)
102 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/tools/list_ports_windows.py:
--------------------------------------------------------------------------------
1 | import ctypes
2 | import re
3 |
4 | def ValidHandle(value, func, arguments):
5 | if value == 0:
6 | raise ctypes.WinError()
7 | return value
8 |
9 | import serial
10 | from serial.win32 import ULONG_PTR, is_64bit
11 | from ctypes.wintypes import HANDLE
12 | from ctypes.wintypes import BOOL
13 | from ctypes.wintypes import HWND
14 | from ctypes.wintypes import DWORD
15 | from ctypes.wintypes import WORD
16 | from ctypes.wintypes import LONG
17 | from ctypes.wintypes import ULONG
18 | from ctypes.wintypes import LPCSTR
19 | from ctypes.wintypes import HKEY
20 | from ctypes.wintypes import BYTE
21 |
22 | NULL = 0
23 | HDEVINFO = ctypes.c_void_p
24 | PCTSTR = ctypes.c_char_p
25 | PTSTR = ctypes.c_void_p
26 | CHAR = ctypes.c_char
27 | LPDWORD = PDWORD = ctypes.POINTER(DWORD)
28 | #~ LPBYTE = PBYTE = ctypes.POINTER(BYTE)
29 | LPBYTE = PBYTE = ctypes.c_void_p # XXX avoids error about types
30 |
31 | ACCESS_MASK = DWORD
32 | REGSAM = ACCESS_MASK
33 |
34 |
35 | def byte_buffer(length):
36 | """Get a buffer for a string"""
37 | return (BYTE*length)()
38 |
39 | def string(buffer):
40 | s = []
41 | for c in buffer:
42 | if c == 0: break
43 | s.append(chr(c & 0xff)) # "& 0xff": hack to convert signed to unsigned
44 | return ''.join(s)
45 |
46 |
47 | class GUID(ctypes.Structure):
48 | _fields_ = [
49 | ('Data1', DWORD),
50 | ('Data2', WORD),
51 | ('Data3', WORD),
52 | ('Data4', BYTE*8),
53 | ]
54 | def __str__(self):
55 | return "{%08x-%04x-%04x-%s-%s}" % (
56 | self.Data1,
57 | self.Data2,
58 | self.Data3,
59 | ''.join(["%02x" % d for d in self.Data4[:2]]),
60 | ''.join(["%02x" % d for d in self.Data4[2:]]),
61 | )
62 |
63 | class SP_DEVINFO_DATA(ctypes.Structure):
64 | _fields_ = [
65 | ('cbSize', DWORD),
66 | ('ClassGuid', GUID),
67 | ('DevInst', DWORD),
68 | ('Reserved', ULONG_PTR),
69 | ]
70 | def __str__(self):
71 | return "ClassGuid:%s DevInst:%s" % (self.ClassGuid, self.DevInst)
72 | PSP_DEVINFO_DATA = ctypes.POINTER(SP_DEVINFO_DATA)
73 |
74 | PSP_DEVICE_INTERFACE_DETAIL_DATA = ctypes.c_void_p
75 |
76 | setupapi = ctypes.windll.LoadLibrary("setupapi")
77 | SetupDiDestroyDeviceInfoList = setupapi.SetupDiDestroyDeviceInfoList
78 | SetupDiDestroyDeviceInfoList.argtypes = [HDEVINFO]
79 | SetupDiDestroyDeviceInfoList.restype = BOOL
80 |
81 | SetupDiClassGuidsFromName = setupapi.SetupDiClassGuidsFromNameA
82 | SetupDiClassGuidsFromName.argtypes = [PCTSTR, ctypes.POINTER(GUID), DWORD, PDWORD]
83 | SetupDiClassGuidsFromName.restype = BOOL
84 |
85 | SetupDiEnumDeviceInfo = setupapi.SetupDiEnumDeviceInfo
86 | SetupDiEnumDeviceInfo.argtypes = [HDEVINFO, DWORD, PSP_DEVINFO_DATA]
87 | SetupDiEnumDeviceInfo.restype = BOOL
88 |
89 | SetupDiGetClassDevs = setupapi.SetupDiGetClassDevsA
90 | SetupDiGetClassDevs.argtypes = [ctypes.POINTER(GUID), PCTSTR, HWND, DWORD]
91 | SetupDiGetClassDevs.restype = HDEVINFO
92 | SetupDiGetClassDevs.errcheck = ValidHandle
93 |
94 | SetupDiGetDeviceRegistryProperty = setupapi.SetupDiGetDeviceRegistryPropertyA
95 | SetupDiGetDeviceRegistryProperty.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD]
96 | SetupDiGetDeviceRegistryProperty.restype = BOOL
97 |
98 | SetupDiGetDeviceInstanceId = setupapi.SetupDiGetDeviceInstanceIdA
99 | SetupDiGetDeviceInstanceId.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD]
100 | SetupDiGetDeviceInstanceId.restype = BOOL
101 |
102 | SetupDiOpenDevRegKey = setupapi.SetupDiOpenDevRegKey
103 | SetupDiOpenDevRegKey.argtypes = [HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM]
104 | SetupDiOpenDevRegKey.restype = HKEY
105 |
106 | advapi32 = ctypes.windll.LoadLibrary("Advapi32")
107 | RegCloseKey = advapi32.RegCloseKey
108 | RegCloseKey.argtypes = [HKEY]
109 | RegCloseKey.restype = LONG
110 |
111 | RegQueryValueEx = advapi32.RegQueryValueExA
112 | RegQueryValueEx.argtypes = [HKEY, LPCSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD]
113 | RegQueryValueEx.restype = LONG
114 |
115 |
116 | DIGCF_PRESENT = 2
117 | DIGCF_DEVICEINTERFACE = 16
118 | INVALID_HANDLE_VALUE = 0
119 | ERROR_INSUFFICIENT_BUFFER = 122
120 | SPDRP_HARDWAREID = 1
121 | SPDRP_FRIENDLYNAME = 12
122 | DICS_FLAG_GLOBAL = 1
123 | DIREG_DEV = 0x00000001
124 | KEY_READ = 0x20019
125 |
126 | # workaround for compatibility between Python 2.x and 3.x
127 | Ports = serial.to_bytes([80, 111, 114, 116, 115]) # "Ports"
128 | PortName = serial.to_bytes([80, 111, 114, 116, 78, 97, 109, 101]) # "PortName"
129 |
130 | def comports():
131 | GUIDs = (GUID*8)() # so far only seen one used, so hope 8 are enough...
132 | guids_size = DWORD()
133 | if not SetupDiClassGuidsFromName(
134 | Ports,
135 | GUIDs,
136 | ctypes.sizeof(GUIDs),
137 | ctypes.byref(guids_size)):
138 | raise ctypes.WinError()
139 |
140 | # repeat for all possible GUIDs
141 | for index in range(guids_size.value):
142 | g_hdi = SetupDiGetClassDevs(
143 | ctypes.byref(GUIDs[index]),
144 | None,
145 | NULL,
146 | DIGCF_PRESENT) # was DIGCF_PRESENT|DIGCF_DEVICEINTERFACE which misses CDC ports
147 |
148 | devinfo = SP_DEVINFO_DATA()
149 | devinfo.cbSize = ctypes.sizeof(devinfo)
150 | index = 0
151 | while SetupDiEnumDeviceInfo(g_hdi, index, ctypes.byref(devinfo)):
152 | index += 1
153 |
154 | # get the real com port name
155 | hkey = SetupDiOpenDevRegKey(
156 | g_hdi,
157 | ctypes.byref(devinfo),
158 | DICS_FLAG_GLOBAL,
159 | 0,
160 | DIREG_DEV, # DIREG_DRV for SW info
161 | KEY_READ)
162 | port_name_buffer = byte_buffer(250)
163 | port_name_length = ULONG(ctypes.sizeof(port_name_buffer))
164 | RegQueryValueEx(
165 | hkey,
166 | PortName,
167 | None,
168 | None,
169 | ctypes.byref(port_name_buffer),
170 | ctypes.byref(port_name_length))
171 | RegCloseKey(hkey)
172 |
173 | # unfortunately does this method also include parallel ports.
174 | # we could check for names starting with COM or just exclude LPT
175 | # and hope that other "unknown" names are serial ports...
176 | if string(port_name_buffer).startswith('LPT'):
177 | continue
178 |
179 | # hardware ID
180 | szHardwareID = byte_buffer(250)
181 | # try to get ID that includes serial number
182 | if not SetupDiGetDeviceInstanceId(
183 | g_hdi,
184 | ctypes.byref(devinfo),
185 | ctypes.byref(szHardwareID),
186 | ctypes.sizeof(szHardwareID) - 1,
187 | None):
188 | # fall back to more generic hardware ID if that would fail
189 | if not SetupDiGetDeviceRegistryProperty(
190 | g_hdi,
191 | ctypes.byref(devinfo),
192 | SPDRP_HARDWAREID,
193 | None,
194 | ctypes.byref(szHardwareID),
195 | ctypes.sizeof(szHardwareID) - 1,
196 | None):
197 | # Ignore ERROR_INSUFFICIENT_BUFFER
198 | if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
199 | raise ctypes.WinError()
200 | # stringify
201 | szHardwareID_str = string(szHardwareID)
202 |
203 | # in case of USB, make a more readable string, similar to that form
204 | # that we also generate on other platforms
205 | if szHardwareID_str.startswith('USB'):
206 | m = re.search(r'VID_([0-9a-f]{4})&PID_([0-9a-f]{4})(\\(\w+))?', szHardwareID_str, re.I)
207 | if m:
208 | if m.group(4):
209 | szHardwareID_str = 'USB VID:PID=%s:%s SNR=%s' % (m.group(1), m.group(2), m.group(4))
210 | else:
211 | szHardwareID_str = 'USB VID:PID=%s:%s' % (m.group(1), m.group(2))
212 |
213 | # friendly name
214 | szFriendlyName = byte_buffer(250)
215 | if not SetupDiGetDeviceRegistryProperty(
216 | g_hdi,
217 | ctypes.byref(devinfo),
218 | SPDRP_FRIENDLYNAME,
219 | #~ SPDRP_DEVICEDESC,
220 | None,
221 | ctypes.byref(szFriendlyName),
222 | ctypes.sizeof(szFriendlyName) - 1,
223 | None):
224 | # Ignore ERROR_INSUFFICIENT_BUFFER
225 | #~ if ctypes.GetLastError() != ERROR_INSUFFICIENT_BUFFER:
226 | #~ raise IOError("failed to get details for %s (%s)" % (devinfo, szHardwareID.value))
227 | # ignore errors and still include the port in the list, friendly name will be same as port name
228 | yield string(port_name_buffer), 'n/a', szHardwareID_str
229 | else:
230 | yield string(port_name_buffer), string(szFriendlyName), szHardwareID_str
231 |
232 | SetupDiDestroyDeviceInfoList(g_hdi)
233 |
234 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235 | # test
236 | if __name__ == '__main__':
237 | import serial
238 |
239 | for port, desc, hwid in sorted(comports()):
240 | print "%s: %s [%s]" % (port, desc, hwid)
241 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/urlhandler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arpruss/gcodeplot/dc9ca1eef3b7af4a253de3adfbd0f1cac3da8364/gcodeplotutils/pyserial27/serial/urlhandler/__init__.py
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/urlhandler/protocol_hwgrep.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # Python Serial Port Extension for Win32, Linux, BSD, Jython
4 | # see __init__.py
5 | #
6 | # This module implements a special URL handler that uses the port listing to
7 | # find ports by searching the string descriptions.
8 | #
9 | # (C) 2011 Chris Liechti
10 | # this is distributed under a free software license, see license.txt
11 | #
12 | # URL format: hwgrep://regexp
13 |
14 | import serial
15 | import serial.tools.list_ports
16 |
17 | class Serial(serial.Serial):
18 | """Just inherit the native Serial port implementation and patch the open function."""
19 |
20 | def setPort(self, value):
21 | """translate port name before storing it"""
22 | if isinstance(value, basestring) and value.startswith('hwgrep://'):
23 | serial.Serial.setPort(self, self.fromURL(value))
24 | else:
25 | serial.Serial.setPort(self, value)
26 |
27 | def fromURL(self, url):
28 | """extract host and port from an URL string"""
29 | if url.lower().startswith("hwgrep://"): url = url[9:]
30 | # use a for loop to get the 1st element from the generator
31 | for port, desc, hwid in serial.tools.list_ports.grep(url):
32 | return port
33 | else:
34 | raise serial.SerialException('no ports found matching regexp %r' % (url,))
35 |
36 | # override property
37 | port = property(serial.Serial.getPort, setPort, doc="Port setting")
38 |
39 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40 | if __name__ == '__main__':
41 | #~ s = Serial('hwgrep://ttyS0')
42 | s = Serial(None)
43 | s.port = 'hwgrep://ttyS0'
44 | print s
45 |
46 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/urlhandler/protocol_loop.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # Python Serial Port Extension for Win32, Linux, BSD, Jython
4 | # see __init__.py
5 | #
6 | # This module implements a loop back connection receiving itself what it sent.
7 | #
8 | # The purpose of this module is.. well... You can run the unit tests with it.
9 | # and it was so easy to implement ;-)
10 | #
11 | # (C) 2001-2011 Chris Liechti
12 | # this is distributed under a free software license, see license.txt
13 | #
14 | # URL format: loop://[option[/option...]]
15 | # options:
16 | # - "debug" print diagnostic messages
17 |
18 | from serial.serialutil import *
19 | import threading
20 | import time
21 | import logging
22 |
23 | # map log level names to constants. used in fromURL()
24 | LOGGER_LEVELS = {
25 | 'debug': logging.DEBUG,
26 | 'info': logging.INFO,
27 | 'warning': logging.WARNING,
28 | 'error': logging.ERROR,
29 | }
30 |
31 |
32 | class LoopbackSerial(SerialBase):
33 | """Serial port implementation that simulates a loop back connection in plain software."""
34 |
35 | BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
36 | 9600, 19200, 38400, 57600, 115200)
37 |
38 | def open(self):
39 | """Open port with current settings. This may throw a SerialException
40 | if the port cannot be opened."""
41 | if self._isOpen:
42 | raise SerialException("Port is already open.")
43 | self.logger = None
44 | self.buffer_lock = threading.Lock()
45 | self.loop_buffer = bytearray()
46 | self.cts = False
47 | self.dsr = False
48 |
49 | if self._port is None:
50 | raise SerialException("Port must be configured before it can be used.")
51 | # not that there is anything to open, but the function applies the
52 | # options found in the URL
53 | self.fromURL(self.port)
54 |
55 | # not that there anything to configure...
56 | self._reconfigurePort()
57 | # all things set up get, now a clean start
58 | self._isOpen = True
59 | if not self._rtscts:
60 | self.setRTS(True)
61 | self.setDTR(True)
62 | self.flushInput()
63 | self.flushOutput()
64 |
65 | def _reconfigurePort(self):
66 | """Set communication parameters on opened port. for the loop://
67 | protocol all settings are ignored!"""
68 | # not that's it of any real use, but it helps in the unit tests
69 | if not isinstance(self._baudrate, (int, long)) or not 0 < self._baudrate < 2**32:
70 | raise ValueError("invalid baudrate: %r" % (self._baudrate))
71 | if self.logger:
72 | self.logger.info('_reconfigurePort()')
73 |
74 | def close(self):
75 | """Close port"""
76 | if self._isOpen:
77 | self._isOpen = False
78 | # in case of quick reconnects, give the server some time
79 | time.sleep(0.3)
80 |
81 | def makeDeviceName(self, port):
82 | raise SerialException("there is no sensible way to turn numbers into URLs")
83 |
84 | def fromURL(self, url):
85 | """extract host and port from an URL string"""
86 | if url.lower().startswith("loop://"): url = url[7:]
87 | try:
88 | # process options now, directly altering self
89 | for option in url.split('/'):
90 | if '=' in option:
91 | option, value = option.split('=', 1)
92 | else:
93 | value = None
94 | if not option:
95 | pass
96 | elif option == 'logging':
97 | logging.basicConfig() # XXX is that good to call it here?
98 | self.logger = logging.getLogger('pySerial.loop')
99 | self.logger.setLevel(LOGGER_LEVELS[value])
100 | self.logger.debug('enabled logging')
101 | else:
102 | raise ValueError('unknown option: %r' % (option,))
103 | except ValueError, e:
104 | raise SerialException('expected a string in the form "[loop://][option[/option...]]": %s' % e)
105 |
106 | # - - - - - - - - - - - - - - - - - - - - - - - -
107 |
108 | def inWaiting(self):
109 | """Return the number of characters currently in the input buffer."""
110 | if not self._isOpen: raise portNotOpenError
111 | if self.logger:
112 | # attention the logged value can differ from return value in
113 | # threaded environments...
114 | self.logger.debug('inWaiting() -> %d' % (len(self.loop_buffer),))
115 | return len(self.loop_buffer)
116 |
117 | def read(self, size=1):
118 | """Read size bytes from the serial port. If a timeout is set it may
119 | return less characters as requested. With no timeout it will block
120 | until the requested number of bytes is read."""
121 | if not self._isOpen: raise portNotOpenError
122 | if self._timeout is not None:
123 | timeout = time.time() + self._timeout
124 | else:
125 | timeout = None
126 | data = bytearray()
127 | while size > 0:
128 | self.buffer_lock.acquire()
129 | try:
130 | block = to_bytes(self.loop_buffer[:size])
131 | del self.loop_buffer[:size]
132 | finally:
133 | self.buffer_lock.release()
134 | data += block
135 | size -= len(block)
136 | # check for timeout now, after data has been read.
137 | # useful for timeout = 0 (non blocking) read
138 | if timeout and time.time() > timeout:
139 | break
140 | return bytes(data)
141 |
142 | def write(self, data):
143 | """Output the given string over the serial port. Can block if the
144 | connection is blocked. May raise SerialException if the connection is
145 | closed."""
146 | if not self._isOpen: raise portNotOpenError
147 | # ensure we're working with bytes
148 | data = to_bytes(data)
149 | # calculate aprox time that would be used to send the data
150 | time_used_to_send = 10.0*len(data) / self._baudrate
151 | # when a write timeout is configured check if we would be successful
152 | # (not sending anything, not even the part that would have time)
153 | if self._writeTimeout is not None and time_used_to_send > self._writeTimeout:
154 | time.sleep(self._writeTimeout) # must wait so that unit test succeeds
155 | raise writeTimeoutError
156 | self.buffer_lock.acquire()
157 | try:
158 | self.loop_buffer += data
159 | finally:
160 | self.buffer_lock.release()
161 | return len(data)
162 |
163 | def flushInput(self):
164 | """Clear input buffer, discarding all that is in the buffer."""
165 | if not self._isOpen: raise portNotOpenError
166 | if self.logger:
167 | self.logger.info('flushInput()')
168 | self.buffer_lock.acquire()
169 | try:
170 | del self.loop_buffer[:]
171 | finally:
172 | self.buffer_lock.release()
173 |
174 | def flushOutput(self):
175 | """Clear output buffer, aborting the current output and
176 | discarding all that is in the buffer."""
177 | if not self._isOpen: raise portNotOpenError
178 | if self.logger:
179 | self.logger.info('flushOutput()')
180 |
181 | def sendBreak(self, duration=0.25):
182 | """Send break condition. Timed, returns to idle state after given
183 | duration."""
184 | if not self._isOpen: raise portNotOpenError
185 |
186 | def setBreak(self, level=True):
187 | """Set break: Controls TXD. When active, to transmitting is
188 | possible."""
189 | if not self._isOpen: raise portNotOpenError
190 | if self.logger:
191 | self.logger.info('setBreak(%r)' % (level,))
192 |
193 | def setRTS(self, level=True):
194 | """Set terminal status line: Request To Send"""
195 | if not self._isOpen: raise portNotOpenError
196 | if self.logger:
197 | self.logger.info('setRTS(%r) -> state of CTS' % (level,))
198 | self.cts = level
199 |
200 | def setDTR(self, level=True):
201 | """Set terminal status line: Data Terminal Ready"""
202 | if not self._isOpen: raise portNotOpenError
203 | if self.logger:
204 | self.logger.info('setDTR(%r) -> state of DSR' % (level,))
205 | self.dsr = level
206 |
207 | def getCTS(self):
208 | """Read terminal status line: Clear To Send"""
209 | if not self._isOpen: raise portNotOpenError
210 | if self.logger:
211 | self.logger.info('getCTS() -> state of RTS (%r)' % (self.cts,))
212 | return self.cts
213 |
214 | def getDSR(self):
215 | """Read terminal status line: Data Set Ready"""
216 | if not self._isOpen: raise portNotOpenError
217 | if self.logger:
218 | self.logger.info('getDSR() -> state of DTR (%r)' % (self.dsr,))
219 | return self.dsr
220 |
221 | def getRI(self):
222 | """Read terminal status line: Ring Indicator"""
223 | if not self._isOpen: raise portNotOpenError
224 | if self.logger:
225 | self.logger.info('returning dummy for getRI()')
226 | return False
227 |
228 | def getCD(self):
229 | """Read terminal status line: Carrier Detect"""
230 | if not self._isOpen: raise portNotOpenError
231 | if self.logger:
232 | self.logger.info('returning dummy for getCD()')
233 | return True
234 |
235 | # - - - platform specific - - -
236 | # None so far
237 |
238 |
239 | # assemble Serial class with the platform specific implementation and the base
240 | # for file-like behavior. for Python 2.6 and newer, that provide the new I/O
241 | # library, derive from io.RawIOBase
242 | try:
243 | import io
244 | except ImportError:
245 | # classic version with our own file-like emulation
246 | class Serial(LoopbackSerial, FileLike):
247 | pass
248 | else:
249 | # io library present
250 | class Serial(LoopbackSerial, io.RawIOBase):
251 | pass
252 |
253 |
254 | # simple client test
255 | if __name__ == '__main__':
256 | import sys
257 | s = Serial('loop://')
258 | sys.stdout.write('%s\n' % s)
259 |
260 | sys.stdout.write("write...\n")
261 | s.write("hello\n")
262 | s.flush()
263 | sys.stdout.write("read: %s\n" % s.read(5))
264 |
265 | s.close()
266 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial27/serial/urlhandler/protocol_rfc2217.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # Python Serial Port Extension for Win32, Linux, BSD, Jython
4 | # see ../__init__.py
5 | #
6 | # This is a thin wrapper to load the rfc2271 implementation.
7 | #
8 | # (C) 2011 Chris Liechti
9 | # this is distributed under a free software license, see license.txt
10 |
11 | from serial.rfc2217 import Serial
12 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2001-2016 Chris Liechti
2 | All Rights Reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | ---------------------------------------------------------------------------
33 | Note:
34 | Individual files contain the following tag instead of the full license text.
35 |
36 | SPDX-License-Identifier: BSD-3-Clause
37 |
38 | This enables machine processing of license information based on the SPDX
39 | License Identifiers that are here available: http://spdx.org/licenses/
40 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/README.rst:
--------------------------------------------------------------------------------
1 | =================================
2 | pySerial |build-status| |docs|
3 | =================================
4 |
5 | Overview
6 | ========
7 | This module encapsulates the access for the serial port. It provides backends
8 | for Python_ running on Windows, OSX, Linux, BSD (possibly any POSIX compliant
9 | system) and IronPython. The module named "serial" automatically selects the
10 | appropriate backend.
11 |
12 | - Project Homepage: https://github.com/pyserial/pyserial
13 | - Download Page: https://pypi.python.org/pypi/pyserial
14 |
15 | BSD license, (C) 2001-2016 Chris Liechti
16 |
17 |
18 | Documentation
19 | =============
20 | For API documentation, usage and examples see files in the "documentation"
21 | directory. The ".rst" files can be read in any text editor or being converted to
22 | HTML or PDF using Sphinx_. A HTML version is online at
23 | https://pythonhosted.org/pyserial/
24 |
25 | Examples
26 | ========
27 | Examples and unit tests are in the directory examples_.
28 |
29 |
30 | Installation
31 | ============
32 | ``pip install pyserial`` should work for most users.
33 |
34 | Detailed information can be found in `documentation/pyserial.rst`_.
35 |
36 | The usual setup.py for Python_ libraries is used for the source distribution.
37 | Windows installers are also available (see download link above).
38 |
39 | .. _`documentation/pyserial.rst`: https://github.com/pyserial/pyserial/blob/master/documentation/pyserial.rst#installation
40 | .. _examples: https://github.com/pyserial/pyserial/blob/master/examples
41 | .. _Python: http://python.org/
42 | .. _Sphinx: http://sphinx-doc.org/
43 | .. |build-status| image:: https://travis-ci.org/pyserial/pyserial.svg?branch=master
44 | :target: https://travis-ci.org/pyserial/pyserial
45 | :alt: Build status
46 | .. |docs| image:: https://readthedocs.org/projects/pyserial/badge/?version=latest
47 | :target: http://pyserial.readthedocs.io/
48 | :alt: Documentation
49 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a wrapper module for different platform implementations
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2001-2016 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | import sys
11 | import importlib
12 |
13 | from serial.serialutil import *
14 | #~ SerialBase, SerialException, to_bytes, iterbytes
15 |
16 | __version__ = '3.2.1'
17 |
18 | VERSION = __version__
19 |
20 | # pylint: disable=wrong-import-position
21 | if sys.platform == 'cli':
22 | from serial.serialcli import Serial
23 | else:
24 | import os
25 | # chose an implementation, depending on os
26 | if os.name == 'nt': # sys.platform == 'win32':
27 | from serial.serialwin32 import Serial
28 | elif os.name == 'posix':
29 | from serial.serialposix import Serial, PosixPollSerial, VTIMESerial # noqa
30 | elif os.name == 'java':
31 | from serial.serialjava import Serial
32 | else:
33 | raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
34 |
35 |
36 | protocol_handler_packages = [
37 | 'serial.urlhandler',
38 | ]
39 |
40 |
41 | def serial_for_url(url, *args, **kwargs):
42 | """\
43 | Get an instance of the Serial class, depending on port/url. The port is not
44 | opened when the keyword parameter 'do_not_open' is true, by default it
45 | is. All other parameters are directly passed to the __init__ method when
46 | the port is instantiated.
47 |
48 | The list of package names that is searched for protocol handlers is kept in
49 | ``protocol_handler_packages``.
50 |
51 | e.g. we want to support a URL ``foobar://``. A module
52 | ``my_handlers.protocol_foobar`` is provided by the user. Then
53 | ``protocol_handler_packages.append("my_handlers")`` would extend the search
54 | path so that ``serial_for_url("foobar://"))`` would work.
55 | """
56 | # check and remove extra parameter to not confuse the Serial class
57 | do_open = not kwargs.pop('do_not_open', False)
58 | # the default is to use the native implementation
59 | klass = Serial
60 | try:
61 | url_lowercase = url.lower()
62 | except AttributeError:
63 | # it's not a string, use default
64 | pass
65 | else:
66 | # if it is an URL, try to import the handler module from the list of possible packages
67 | if '://' in url_lowercase:
68 | protocol = url_lowercase.split('://', 1)[0]
69 | module_name = '.protocol_{}'.format(protocol)
70 | for package_name in protocol_handler_packages:
71 | try:
72 | importlib.import_module(package_name)
73 | handler_module = importlib.import_module(module_name, package_name)
74 | except ImportError:
75 | continue
76 | else:
77 | if hasattr(handler_module, 'serial_class_for_url'):
78 | url, klass = handler_module.serial_class_for_url(url)
79 | else:
80 | klass = handler_module.Serial
81 | break
82 | else:
83 | raise ValueError('invalid URL, protocol {!r} not known'.format(protocol))
84 | # instantiate and open when desired
85 | instance = klass(None, *args, **kwargs)
86 | instance.port = url
87 | if do_open:
88 | instance.open()
89 | return instance
90 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/rs485.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # RS485 support
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | """\
11 | The settings for RS485 are stored in a dedicated object that can be applied to
12 | serial ports (where supported).
13 | NOTE: Some implementations may only support a subset of the settings.
14 | """
15 |
16 | import time
17 | import serial
18 |
19 |
20 | class RS485Settings(object):
21 | def __init__(
22 | self,
23 | rts_level_for_tx=True,
24 | rts_level_for_rx=False,
25 | loopback=False,
26 | delay_before_tx=None,
27 | delay_before_rx=None):
28 | self.rts_level_for_tx = rts_level_for_tx
29 | self.rts_level_for_rx = rts_level_for_rx
30 | self.loopback = loopback
31 | self.delay_before_tx = delay_before_tx
32 | self.delay_before_rx = delay_before_rx
33 |
34 |
35 | class RS485(serial.Serial):
36 | """\
37 | A subclass that replaces the write method with one that toggles RTS
38 | according to the RS485 settings.
39 |
40 | NOTE: This may work unreliably on some serial ports (control signals not
41 | synchronized or delayed compared to data). Using delays may be
42 | unreliable (varying times, larger than expected) as the OS may not
43 | support very fine grained delays (no smaller than in the order of
44 | tens of milliseconds).
45 |
46 | NOTE: Some implementations support this natively. Better performance
47 | can be expected when the native version is used.
48 |
49 | NOTE: The loopback property is ignored by this implementation. The actual
50 | behavior depends on the used hardware.
51 |
52 | Usage:
53 |
54 | ser = RS485(...)
55 | ser.rs485_mode = RS485Settings(...)
56 | ser.write(b'hello')
57 | """
58 |
59 | def __init__(self, *args, **kwargs):
60 | super(RS485, self).__init__(*args, **kwargs)
61 | self._alternate_rs485_settings = None
62 |
63 | def write(self, b):
64 | """Write to port, controlling RTS before and after transmitting."""
65 | if self._alternate_rs485_settings is not None:
66 | # apply level for TX and optional delay
67 | self.setRTS(self._alternate_rs485_settings.rts_level_for_tx)
68 | if self._alternate_rs485_settings.delay_before_tx is not None:
69 | time.sleep(self._alternate_rs485_settings.delay_before_tx)
70 | # write and wait for data to be written
71 | super(RS485, self).write(b)
72 | super(RS485, self).flush()
73 | # optional delay and apply level for RX
74 | if self._alternate_rs485_settings.delay_before_rx is not None:
75 | time.sleep(self._alternate_rs485_settings.delay_before_rx)
76 | self.setRTS(self._alternate_rs485_settings.rts_level_for_rx)
77 | else:
78 | super(RS485, self).write(b)
79 |
80 | # redirect where the property stores the settings so that underlying Serial
81 | # instance does not see them
82 | @property
83 | def rs485_mode(self):
84 | """\
85 | Enable RS485 mode and apply new settings, set to None to disable.
86 | See serial.rs485.RS485Settings for more info about the value.
87 | """
88 | return self._alternate_rs485_settings
89 |
90 | @rs485_mode.setter
91 | def rs485_mode(self, rs485_settings):
92 | self._alternate_rs485_settings = rs485_settings
93 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/serialcli.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # Backend for .NET/Mono (IronPython), .NET >= 2
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2008-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | import System
11 | import System.IO.Ports
12 | from serial.serialutil import *
13 |
14 | # must invoke function with byte array, make a helper to convert strings
15 | # to byte arrays
16 | sab = System.Array[System.Byte]
17 |
18 |
19 | def as_byte_array(string):
20 | return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython
21 |
22 |
23 | class Serial(SerialBase):
24 | """Serial port implementation for .NET/Mono."""
25 |
26 | BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
27 | 9600, 19200, 38400, 57600, 115200)
28 |
29 | def open(self):
30 | """\
31 | Open port with current settings. This may throw a SerialException
32 | if the port cannot be opened.
33 | """
34 | if self._port is None:
35 | raise SerialException("Port must be configured before it can be used.")
36 | if self.is_open:
37 | raise SerialException("Port is already open.")
38 | try:
39 | self._port_handle = System.IO.Ports.SerialPort(self.portstr)
40 | except Exception as msg:
41 | self._port_handle = None
42 | raise SerialException("could not open port %s: %s" % (self.portstr, msg))
43 |
44 | # if RTS and/or DTR are not set before open, they default to True
45 | if self._rts_state is None:
46 | self._rts_state = True
47 | if self._dtr_state is None:
48 | self._dtr_state = True
49 |
50 | self._reconfigure_port()
51 | self._port_handle.Open()
52 | self.is_open = True
53 | if not self._dsrdtr:
54 | self._update_dtr_state()
55 | if not self._rtscts:
56 | self._update_rts_state()
57 | self.reset_input_buffer()
58 |
59 | def _reconfigure_port(self):
60 | """Set communication parameters on opened port."""
61 | if not self._port_handle:
62 | raise SerialException("Can only operate on a valid port handle")
63 |
64 | #~ self._port_handle.ReceivedBytesThreshold = 1
65 |
66 | if self._timeout is None:
67 | self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
68 | else:
69 | self._port_handle.ReadTimeout = int(self._timeout * 1000)
70 |
71 | # if self._timeout != 0 and self._interCharTimeout is not None:
72 | # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:]
73 |
74 | if self._write_timeout is None:
75 | self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout
76 | else:
77 | self._port_handle.WriteTimeout = int(self._write_timeout * 1000)
78 |
79 | # Setup the connection info.
80 | try:
81 | self._port_handle.BaudRate = self._baudrate
82 | except IOError as e:
83 | # catch errors from illegal baudrate settings
84 | raise ValueError(str(e))
85 |
86 | if self._bytesize == FIVEBITS:
87 | self._port_handle.DataBits = 5
88 | elif self._bytesize == SIXBITS:
89 | self._port_handle.DataBits = 6
90 | elif self._bytesize == SEVENBITS:
91 | self._port_handle.DataBits = 7
92 | elif self._bytesize == EIGHTBITS:
93 | self._port_handle.DataBits = 8
94 | else:
95 | raise ValueError("Unsupported number of data bits: %r" % self._bytesize)
96 |
97 | if self._parity == PARITY_NONE:
98 | self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k
99 | elif self._parity == PARITY_EVEN:
100 | self._port_handle.Parity = System.IO.Ports.Parity.Even
101 | elif self._parity == PARITY_ODD:
102 | self._port_handle.Parity = System.IO.Ports.Parity.Odd
103 | elif self._parity == PARITY_MARK:
104 | self._port_handle.Parity = System.IO.Ports.Parity.Mark
105 | elif self._parity == PARITY_SPACE:
106 | self._port_handle.Parity = System.IO.Ports.Parity.Space
107 | else:
108 | raise ValueError("Unsupported parity mode: %r" % self._parity)
109 |
110 | if self._stopbits == STOPBITS_ONE:
111 | self._port_handle.StopBits = System.IO.Ports.StopBits.One
112 | elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
113 | self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive
114 | elif self._stopbits == STOPBITS_TWO:
115 | self._port_handle.StopBits = System.IO.Ports.StopBits.Two
116 | else:
117 | raise ValueError("Unsupported number of stop bits: %r" % self._stopbits)
118 |
119 | if self._rtscts and self._xonxoff:
120 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff
121 | elif self._rtscts:
122 | self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend
123 | elif self._xonxoff:
124 | self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff
125 | else:
126 | self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k
127 |
128 | #~ def __del__(self):
129 | #~ self.close()
130 |
131 | def close(self):
132 | """Close port"""
133 | if self.is_open:
134 | if self._port_handle:
135 | try:
136 | self._port_handle.Close()
137 | except System.IO.Ports.InvalidOperationException:
138 | # ignore errors. can happen for unplugged USB serial devices
139 | pass
140 | self._port_handle = None
141 | self.is_open = False
142 |
143 | # - - - - - - - - - - - - - - - - - - - - - - - -
144 |
145 | @property
146 | def in_waiting(self):
147 | """Return the number of characters currently in the input buffer."""
148 | if not self.is_open:
149 | raise portNotOpenError
150 | return self._port_handle.BytesToRead
151 |
152 | def read(self, size=1):
153 | """\
154 | Read size bytes from the serial port. If a timeout is set it may
155 | return less characters as requested. With no timeout it will block
156 | until the requested number of bytes is read.
157 | """
158 | if not self.is_open:
159 | raise portNotOpenError
160 | # must use single byte reads as this is the only way to read
161 | # without applying encodings
162 | data = bytearray()
163 | while size:
164 | try:
165 | data.append(self._port_handle.ReadByte())
166 | except System.TimeoutException:
167 | break
168 | else:
169 | size -= 1
170 | return bytes(data)
171 |
172 | def write(self, data):
173 | """Output the given string over the serial port."""
174 | if not self.is_open:
175 | raise portNotOpenError
176 | #~ if not isinstance(data, (bytes, bytearray)):
177 | #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
178 | try:
179 | # must call overloaded method with byte array argument
180 | # as this is the only one not applying encodings
181 | self._port_handle.Write(as_byte_array(data), 0, len(data))
182 | except System.TimeoutException:
183 | raise writeTimeoutError
184 | return len(data)
185 |
186 | def reset_input_buffer(self):
187 | """Clear input buffer, discarding all that is in the buffer."""
188 | if not self.is_open:
189 | raise portNotOpenError
190 | self._port_handle.DiscardInBuffer()
191 |
192 | def reset_output_buffer(self):
193 | """\
194 | Clear output buffer, aborting the current output and
195 | discarding all that is in the buffer.
196 | """
197 | if not self.is_open:
198 | raise portNotOpenError
199 | self._port_handle.DiscardOutBuffer()
200 |
201 | def _update_break_state(self):
202 | """
203 | Set break: Controls TXD. When active, to transmitting is possible.
204 | """
205 | if not self.is_open:
206 | raise portNotOpenError
207 | self._port_handle.BreakState = bool(self._break_state)
208 |
209 | def _update_rts_state(self):
210 | """Set terminal status line: Request To Send"""
211 | if not self.is_open:
212 | raise portNotOpenError
213 | self._port_handle.RtsEnable = bool(self._rts_state)
214 |
215 | def _update_dtr_state(self):
216 | """Set terminal status line: Data Terminal Ready"""
217 | if not self.is_open:
218 | raise portNotOpenError
219 | self._port_handle.DtrEnable = bool(self._dtr_state)
220 |
221 | @property
222 | def cts(self):
223 | """Read terminal status line: Clear To Send"""
224 | if not self.is_open:
225 | raise portNotOpenError
226 | return self._port_handle.CtsHolding
227 |
228 | @property
229 | def dsr(self):
230 | """Read terminal status line: Data Set Ready"""
231 | if not self.is_open:
232 | raise portNotOpenError
233 | return self._port_handle.DsrHolding
234 |
235 | @property
236 | def ri(self):
237 | """Read terminal status line: Ring Indicator"""
238 | if not self.is_open:
239 | raise portNotOpenError
240 | #~ return self._port_handle.XXX
241 | return False # XXX an error would be better
242 |
243 | @property
244 | def cd(self):
245 | """Read terminal status line: Carrier Detect"""
246 | if not self.is_open:
247 | raise portNotOpenError
248 | return self._port_handle.CDHolding
249 |
250 | # - - platform specific - - - -
251 | # none
252 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/serialjava.py:
--------------------------------------------------------------------------------
1 | #!jython
2 | #
3 | # Backend Jython with JavaComm
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2002-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | from serial.serialutil import *
11 |
12 |
13 | def my_import(name):
14 | mod = __import__(name)
15 | components = name.split('.')
16 | for comp in components[1:]:
17 | mod = getattr(mod, comp)
18 | return mod
19 |
20 |
21 | def detect_java_comm(names):
22 | """try given list of modules and return that imports"""
23 | for name in names:
24 | try:
25 | mod = my_import(name)
26 | mod.SerialPort
27 | return mod
28 | except (ImportError, AttributeError):
29 | pass
30 | raise ImportError("No Java Communications API implementation found")
31 |
32 |
33 | # Java Communications API implementations
34 | # http://mho.republika.pl/java/comm/
35 |
36 | comm = detect_java_comm([
37 | 'javax.comm', # Sun/IBM
38 | 'gnu.io', # RXTX
39 | ])
40 |
41 |
42 | def device(portnumber):
43 | """Turn a port number into a device name"""
44 | enum = comm.CommPortIdentifier.getPortIdentifiers()
45 | ports = []
46 | while enum.hasMoreElements():
47 | el = enum.nextElement()
48 | if el.getPortType() == comm.CommPortIdentifier.PORT_SERIAL:
49 | ports.append(el)
50 | return ports[portnumber].getName()
51 |
52 |
53 | class Serial(SerialBase):
54 | """\
55 | Serial port class, implemented with Java Communications API and
56 | thus usable with jython and the appropriate java extension.
57 | """
58 |
59 | def open(self):
60 | """\
61 | Open port with current settings. This may throw a SerialException
62 | if the port cannot be opened.
63 | """
64 | if self._port is None:
65 | raise SerialException("Port must be configured before it can be used.")
66 | if self.is_open:
67 | raise SerialException("Port is already open.")
68 | if type(self._port) == type(''): # strings are taken directly
69 | portId = comm.CommPortIdentifier.getPortIdentifier(self._port)
70 | else:
71 | portId = comm.CommPortIdentifier.getPortIdentifier(device(self._port)) # numbers are transformed to a comport id obj
72 | try:
73 | self.sPort = portId.open("python serial module", 10)
74 | except Exception as msg:
75 | self.sPort = None
76 | raise SerialException("Could not open port: %s" % msg)
77 | self._reconfigurePort()
78 | self._instream = self.sPort.getInputStream()
79 | self._outstream = self.sPort.getOutputStream()
80 | self.is_open = True
81 |
82 | def _reconfigurePort(self):
83 | """Set communication parameters on opened port."""
84 | if not self.sPort:
85 | raise SerialException("Can only operate on a valid port handle")
86 |
87 | self.sPort.enableReceiveTimeout(30)
88 | if self._bytesize == FIVEBITS:
89 | jdatabits = comm.SerialPort.DATABITS_5
90 | elif self._bytesize == SIXBITS:
91 | jdatabits = comm.SerialPort.DATABITS_6
92 | elif self._bytesize == SEVENBITS:
93 | jdatabits = comm.SerialPort.DATABITS_7
94 | elif self._bytesize == EIGHTBITS:
95 | jdatabits = comm.SerialPort.DATABITS_8
96 | else:
97 | raise ValueError("unsupported bytesize: %r" % self._bytesize)
98 |
99 | if self._stopbits == STOPBITS_ONE:
100 | jstopbits = comm.SerialPort.STOPBITS_1
101 | elif self._stopbits == STOPBITS_ONE_POINT_FIVE:
102 | jstopbits = comm.SerialPort.STOPBITS_1_5
103 | elif self._stopbits == STOPBITS_TWO:
104 | jstopbits = comm.SerialPort.STOPBITS_2
105 | else:
106 | raise ValueError("unsupported number of stopbits: %r" % self._stopbits)
107 |
108 | if self._parity == PARITY_NONE:
109 | jparity = comm.SerialPort.PARITY_NONE
110 | elif self._parity == PARITY_EVEN:
111 | jparity = comm.SerialPort.PARITY_EVEN
112 | elif self._parity == PARITY_ODD:
113 | jparity = comm.SerialPort.PARITY_ODD
114 | elif self._parity == PARITY_MARK:
115 | jparity = comm.SerialPort.PARITY_MARK
116 | elif self._parity == PARITY_SPACE:
117 | jparity = comm.SerialPort.PARITY_SPACE
118 | else:
119 | raise ValueError("unsupported parity type: %r" % self._parity)
120 |
121 | jflowin = jflowout = 0
122 | if self._rtscts:
123 | jflowin |= comm.SerialPort.FLOWCONTROL_RTSCTS_IN
124 | jflowout |= comm.SerialPort.FLOWCONTROL_RTSCTS_OUT
125 | if self._xonxoff:
126 | jflowin |= comm.SerialPort.FLOWCONTROL_XONXOFF_IN
127 | jflowout |= comm.SerialPort.FLOWCONTROL_XONXOFF_OUT
128 |
129 | self.sPort.setSerialPortParams(self._baudrate, jdatabits, jstopbits, jparity)
130 | self.sPort.setFlowControlMode(jflowin | jflowout)
131 |
132 | if self._timeout >= 0:
133 | self.sPort.enableReceiveTimeout(int(self._timeout*1000))
134 | else:
135 | self.sPort.disableReceiveTimeout()
136 |
137 | def close(self):
138 | """Close port"""
139 | if self.is_open:
140 | if self.sPort:
141 | self._instream.close()
142 | self._outstream.close()
143 | self.sPort.close()
144 | self.sPort = None
145 | self.is_open = False
146 |
147 | # - - - - - - - - - - - - - - - - - - - - - - - -
148 |
149 | @property
150 | def in_waiting(self):
151 | """Return the number of characters currently in the input buffer."""
152 | if not self.sPort:
153 | raise portNotOpenError
154 | return self._instream.available()
155 |
156 | def read(self, size=1):
157 | """\
158 | Read size bytes from the serial port. If a timeout is set it may
159 | return less characters as requested. With no timeout it will block
160 | until the requested number of bytes is read.
161 | """
162 | if not self.sPort:
163 | raise portNotOpenError
164 | read = bytearray()
165 | if size > 0:
166 | while len(read) < size:
167 | x = self._instream.read()
168 | if x == -1:
169 | if self.timeout >= 0:
170 | break
171 | else:
172 | read.append(x)
173 | return bytes(read)
174 |
175 | def write(self, data):
176 | """Output the given string over the serial port."""
177 | if not self.sPort:
178 | raise portNotOpenError
179 | if not isinstance(data, (bytes, bytearray)):
180 | raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data)))
181 | self._outstream.write(data)
182 | return len(data)
183 |
184 | def reset_input_buffer(self):
185 | """Clear input buffer, discarding all that is in the buffer."""
186 | if not self.sPort:
187 | raise portNotOpenError
188 | self._instream.skip(self._instream.available())
189 |
190 | def reset_output_buffer(self):
191 | """\
192 | Clear output buffer, aborting the current output and
193 | discarding all that is in the buffer.
194 | """
195 | if not self.sPort:
196 | raise portNotOpenError
197 | self._outstream.flush()
198 |
199 | def send_break(self, duration=0.25):
200 | """Send break condition. Timed, returns to idle state after given duration."""
201 | if not self.sPort:
202 | raise portNotOpenError
203 | self.sPort.sendBreak(duration*1000.0)
204 |
205 | def _update_break_state(self):
206 | """Set break: Controls TXD. When active, to transmitting is possible."""
207 | if self.fd is None:
208 | raise portNotOpenError
209 | raise SerialException("The _update_break_state function is not implemented in java.")
210 |
211 | def _update_rts_state(self):
212 | """Set terminal status line: Request To Send"""
213 | if not self.sPort:
214 | raise portNotOpenError
215 | self.sPort.setRTS(self._rts_state)
216 |
217 | def _update_dtr_state(self):
218 | """Set terminal status line: Data Terminal Ready"""
219 | if not self.sPort:
220 | raise portNotOpenError
221 | self.sPort.setDTR(self._dtr_state)
222 |
223 | @property
224 | def cts(self):
225 | """Read terminal status line: Clear To Send"""
226 | if not self.sPort:
227 | raise portNotOpenError
228 | self.sPort.isCTS()
229 |
230 | @property
231 | def dsr(self):
232 | """Read terminal status line: Data Set Ready"""
233 | if not self.sPort:
234 | raise portNotOpenError
235 | self.sPort.isDSR()
236 |
237 | @property
238 | def ri(self):
239 | """Read terminal status line: Ring Indicator"""
240 | if not self.sPort:
241 | raise portNotOpenError
242 | self.sPort.isRI()
243 |
244 | @property
245 | def cd(self):
246 | """Read terminal status line: Carrier Detect"""
247 | if not self.sPort:
248 | raise portNotOpenError
249 | self.sPort.isCD()
250 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/threaded/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Working with threading and pySerial
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015-2016 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 | """\
10 | Support threading with serial ports.
11 | """
12 | import serial
13 | import threading
14 |
15 |
16 | class Protocol(object):
17 | """\
18 | Protocol as used by the ReaderThread. This base class provides empty
19 | implementations of all methods.
20 | """
21 |
22 | def connection_made(self, transport):
23 | """Called when reader thread is started"""
24 |
25 | def data_received(self, data):
26 | """Called with snippets received from the serial port"""
27 |
28 | def connection_lost(self, exc):
29 | """\
30 | Called when the serial port is closed or the reader loop terminated
31 | otherwise.
32 | """
33 | if isinstance(exc, Exception):
34 | raise exc
35 |
36 |
37 | class Packetizer(Protocol):
38 | """
39 | Read binary packets from serial port. Packets are expected to be terminated
40 | with a TERMINATOR byte (null byte by default).
41 |
42 | The class also keeps track of the transport.
43 | """
44 |
45 | TERMINATOR = b'\0'
46 |
47 | def __init__(self):
48 | self.buffer = bytearray()
49 | self.transport = None
50 |
51 | def connection_made(self, transport):
52 | """Store transport"""
53 | self.transport = transport
54 |
55 | def connection_lost(self, exc):
56 | """Forget transport"""
57 | self.transport = None
58 | super(Packetizer, self).connection_lost(exc)
59 |
60 | def data_received(self, data):
61 | """Buffer received data, find TERMINATOR, call handle_packet"""
62 | self.buffer.extend(data)
63 | while self.TERMINATOR in self.buffer:
64 | packet, self.buffer = self.buffer.split(self.TERMINATOR, 1)
65 | self.handle_packet(packet)
66 |
67 | def handle_packet(self, packet):
68 | """Process packets - to be overridden by subclassing"""
69 | raise NotImplementedError('please implement functionality in handle_packet')
70 |
71 |
72 | class FramedPacket(Protocol):
73 | """
74 | Read binary packets. Packets are expected to have a start and stop marker.
75 |
76 | The class also keeps track of the transport.
77 | """
78 |
79 | START = b'('
80 | STOP = b')'
81 |
82 | def __init__(self):
83 | self.packet = bytearray()
84 | self.in_packet = False
85 | self.transport = None
86 |
87 | def connection_made(self, transport):
88 | """Store transport"""
89 | self.transport = transport
90 |
91 | def connection_lost(self, exc):
92 | """Forget transport"""
93 | self.transport = None
94 | self.in_packet = False
95 | del self.packet[:]
96 | super(FramedPacket, self).connection_lost(exc)
97 |
98 | def data_received(self, data):
99 | """Find data enclosed in START/STOP, call handle_packet"""
100 | for byte in serial.iterbytes(data):
101 | if byte == self.START:
102 | self.in_packet = True
103 | elif byte == self.STOP:
104 | self.in_packet = False
105 | self.handle_packet(bytes(self.packet)) # make read-only copy
106 | del self.packet[:]
107 | elif self.in_packet:
108 | self.packet.extend(byte)
109 | else:
110 | self.handle_out_of_packet_data(byte)
111 |
112 | def handle_packet(self, packet):
113 | """Process packets - to be overridden by subclassing"""
114 | raise NotImplementedError('please implement functionality in handle_packet')
115 |
116 | def handle_out_of_packet_data(self, data):
117 | """Process data that is received outside of packets"""
118 | pass
119 |
120 |
121 | class LineReader(Packetizer):
122 | """
123 | Read and write (Unicode) lines from/to serial port.
124 | The encoding is applied.
125 | """
126 |
127 | TERMINATOR = b'\r\n'
128 | ENCODING = 'utf-8'
129 | UNICODE_HANDLING = 'replace'
130 |
131 | def handle_packet(self, packet):
132 | self.handle_line(packet.decode(self.ENCODING, self.UNICODE_HANDLING))
133 |
134 | def handle_line(self, line):
135 | """Process one line - to be overridden by subclassing"""
136 | raise NotImplementedError('please implement functionality in handle_line')
137 |
138 | def write_line(self, text):
139 | """
140 | Write text to the transport. ``text`` is a Unicode string and the encoding
141 | is applied before sending ans also the newline is append.
142 | """
143 | # + is not the best choice but bytes does not support % or .format in py3 and we want a single write call
144 | self.transport.write(text.encode(self.ENCODING, self.UNICODE_HANDLING) + self.TERMINATOR)
145 |
146 |
147 | class ReaderThread(threading.Thread):
148 | """\
149 | Implement a serial port read loop and dispatch to a Protocol instance (like
150 | the asyncio.Protocol) but do it with threads.
151 |
152 | Calls to close() will close the serial port but it is also possible to just
153 | stop() this thread and continue the serial port instance otherwise.
154 | """
155 |
156 | def __init__(self, serial_instance, protocol_factory):
157 | """\
158 | Initialize thread.
159 |
160 | Note that the serial_instance' timeout is set to one second!
161 | Other settings are not changed.
162 | """
163 | super(ReaderThread, self).__init__()
164 | self.daemon = True
165 | self.serial = serial_instance
166 | self.protocol_factory = protocol_factory
167 | self.alive = True
168 | self._lock = threading.Lock()
169 | self._connection_made = threading.Event()
170 | self.protocol = None
171 |
172 | def stop(self):
173 | """Stop the reader thread"""
174 | self.alive = False
175 | if hasattr(self.serial, 'cancel_read'):
176 | self.serial.cancel_read()
177 | self.join(2)
178 |
179 | def run(self):
180 | """Reader loop"""
181 | if not hasattr(self.serial, 'cancel_read'):
182 | self.serial.timeout = 1
183 | self.protocol = self.protocol_factory()
184 | try:
185 | self.protocol.connection_made(self)
186 | except Exception as e:
187 | self.alive = False
188 | self.protocol.connection_lost(e)
189 | self._connection_made.set()
190 | return
191 | error = None
192 | self._connection_made.set()
193 | while self.alive and self.serial.is_open:
194 | try:
195 | # read all that is there or wait for one byte (blocking)
196 | data = self.serial.read(self.serial.in_waiting or 1)
197 | except serial.SerialException as e:
198 | # probably some I/O problem such as disconnected USB serial
199 | # adapters -> exit
200 | error = e
201 | break
202 | else:
203 | if data:
204 | # make a separated try-except for called used code
205 | try:
206 | self.protocol.data_received(data)
207 | except Exception as e:
208 | error = e
209 | break
210 | self.alive = False
211 | self.protocol.connection_lost(error)
212 | self.protocol = None
213 |
214 | def write(self, data):
215 | """Thread safe writing (uses lock)"""
216 | with self._lock:
217 | self.serial.write(data)
218 |
219 | def close(self):
220 | """Close the serial port and exit reader thread (uses lock)"""
221 | # use the lock to let other threads finish writing
222 | with self._lock:
223 | # first stop reading, so that closing can be done on idle port
224 | self.stop()
225 | self.serial.close()
226 |
227 | def connect(self):
228 | """
229 | Wait until connection is set up and return the transport and protocol
230 | instances.
231 | """
232 | if self.alive:
233 | self._connection_made.wait()
234 | if not self.alive:
235 | raise RuntimeError('connection_lost already called')
236 | return (self, self.protocol)
237 | else:
238 | raise RuntimeError('already stopped')
239 |
240 | # - - context manager, returns protocol
241 |
242 | def __enter__(self):
243 | """\
244 | Enter context handler. May raise RuntimeError in case the connection
245 | could not be created.
246 | """
247 | self.start()
248 | self._connection_made.wait()
249 | if not self.alive:
250 | raise RuntimeError('connection_lost already called')
251 | return self.protocol
252 |
253 | def __exit__(self, exc_type, exc_val, exc_tb):
254 | """Leave context: close port"""
255 | self.close()
256 |
257 |
258 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
259 | # test
260 | if __name__ == '__main__':
261 | # pylint: disable=wrong-import-position
262 | import sys
263 | import time
264 | import traceback
265 |
266 | #~ PORT = 'spy:///dev/ttyUSB0'
267 | PORT = 'loop://'
268 |
269 | class PrintLines(LineReader):
270 | def connection_made(self, transport):
271 | super(PrintLines, self).connection_made(transport)
272 | sys.stdout.write('port opened\n')
273 | self.write_line('hello world')
274 |
275 | def handle_line(self, data):
276 | sys.stdout.write('line received: {!r}\n'.format(data))
277 |
278 | def connection_lost(self, exc):
279 | if exc:
280 | traceback.print_exc(exc)
281 | sys.stdout.write('port closed\n')
282 |
283 | ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1)
284 | with ReaderThread(ser, PrintLines) as protocol:
285 | protocol.write_line('hello')
286 | time.sleep(2)
287 |
288 | # alternative usage
289 | ser = serial.serial_for_url(PORT, baudrate=115200, timeout=1)
290 | t = ReaderThread(ser, PrintLines)
291 | t.start()
292 | transport, protocol = t.connect()
293 | protocol.write_line('hello')
294 | time.sleep(2)
295 | t.close()
296 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arpruss/gcodeplot/dc9ca1eef3b7af4a253de3adfbd0f1cac3da8364/gcodeplotutils/pyserial3/serial/tools/__init__.py
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/hexlify_codec.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This is a codec to create and decode hexdumps with spaces between characters. used by miniterm.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2015-2016 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 | """\
10 | Python 'hex' Codec - 2-digit hex with spaces content transfer encoding.
11 |
12 | Encode and decode may be a bit missleading at first sight...
13 |
14 | The textual representation is a hex dump: e.g. "40 41"
15 | The "encoded" data of this is the binary form, e.g. b"@A"
16 |
17 | Therefore decoding is binary to text and thus converting binary data to hex dump.
18 |
19 | """
20 |
21 | import codecs
22 | import serial
23 |
24 |
25 | try:
26 | unicode
27 | except (NameError, AttributeError):
28 | unicode = str # for Python 3, pylint: disable=redefined-builtin,invalid-name
29 |
30 |
31 | HEXDIGITS = '0123456789ABCDEF'
32 |
33 |
34 | # Codec APIs
35 |
36 | def hex_encode(data, errors='strict'):
37 | """'40 41 42' -> b'@ab'"""
38 | return (serial.to_bytes([int(h, 16) for h in data.split()]), len(data))
39 |
40 |
41 | def hex_decode(data, errors='strict'):
42 | """b'@ab' -> '40 41 42'"""
43 | return (unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data))), len(data))
44 |
45 |
46 | class Codec(codecs.Codec):
47 | def encode(self, data, errors='strict'):
48 | """'40 41 42' -> b'@ab'"""
49 | return serial.to_bytes([int(h, 16) for h in data.split()])
50 |
51 | def decode(self, data, errors='strict'):
52 | """b'@ab' -> '40 41 42'"""
53 | return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
54 |
55 |
56 | class IncrementalEncoder(codecs.IncrementalEncoder):
57 | """Incremental hex encoder"""
58 |
59 | def __init__(self, errors='strict'):
60 | self.errors = errors
61 | self.state = 0
62 |
63 | def reset(self):
64 | self.state = 0
65 |
66 | def getstate(self):
67 | return self.state
68 |
69 | def setstate(self, state):
70 | self.state = state
71 |
72 | def encode(self, data, final=False):
73 | """\
74 | Incremental encode, keep track of digits and emit a byte when a pair
75 | of hex digits is found. The space is optional unless the error
76 | handling is defined to be 'strict'.
77 | """
78 | state = self.state
79 | encoded = []
80 | for c in data.upper():
81 | if c in HEXDIGITS:
82 | z = HEXDIGITS.index(c)
83 | if state:
84 | encoded.append(z + (state & 0xf0))
85 | state = 0
86 | else:
87 | state = 0x100 + (z << 4)
88 | elif c == ' ': # allow spaces to separate values
89 | if state and self.errors == 'strict':
90 | raise UnicodeError('odd number of hex digits')
91 | state = 0
92 | else:
93 | if self.errors == 'strict':
94 | raise UnicodeError('non-hex digit found: {!r}'.format(c))
95 | self.state = state
96 | return serial.to_bytes(encoded)
97 |
98 |
99 | class IncrementalDecoder(codecs.IncrementalDecoder):
100 | """Incremental decoder"""
101 | def decode(self, data, final=False):
102 | return unicode(''.join('{:02X} '.format(ord(b)) for b in serial.iterbytes(data)))
103 |
104 |
105 | class StreamWriter(Codec, codecs.StreamWriter):
106 | """Combination of hexlify codec and StreamWriter"""
107 |
108 |
109 | class StreamReader(Codec, codecs.StreamReader):
110 | """Combination of hexlify codec and StreamReader"""
111 |
112 |
113 | def getregentry():
114 | """encodings module API"""
115 | return codecs.CodecInfo(
116 | name='hexlify',
117 | encode=hex_encode,
118 | decode=hex_decode,
119 | incrementalencoder=IncrementalEncoder,
120 | incrementaldecoder=IncrementalDecoder,
121 | streamwriter=StreamWriter,
122 | streamreader=StreamReader,
123 | #~ _is_text_encoding=True,
124 | )
125 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/list_ports.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Serial port enumeration. Console tool and backend selection.
4 | #
5 | # This file is part of pySerial. https://github.com/pyserial/pyserial
6 | # (C) 2011-2015 Chris Liechti
7 | #
8 | # SPDX-License-Identifier: BSD-3-Clause
9 |
10 | """\
11 | This module will provide a function called comports that returns an
12 | iterable (generator or list) that will enumerate available com ports. Note that
13 | on some systems non-existent ports may be listed.
14 |
15 | Additionally a grep function is supplied that can be used to search for ports
16 | based on their descriptions or hardware ID.
17 | """
18 |
19 | import sys
20 | import os
21 | import re
22 |
23 | # chose an implementation, depending on os
24 | #~ if sys.platform == 'cli':
25 | #~ else:
26 | if os.name == 'nt': # sys.platform == 'win32':
27 | from serial.tools.list_ports_windows import comports
28 | elif os.name == 'posix':
29 | from serial.tools.list_ports_posix import comports
30 | #~ elif os.name == 'java':
31 | else:
32 | raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
33 |
34 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 |
36 |
37 | def grep(regexp):
38 | """\
39 | Search for ports using a regular expression. Port name, description and
40 | hardware ID are searched. The function returns an iterable that returns the
41 | same tuples as comport() would do.
42 | """
43 | r = re.compile(regexp, re.I)
44 | for info in comports():
45 | port, desc, hwid = info
46 | if r.search(port) or r.search(desc) or r.search(hwid):
47 | yield info
48 |
49 |
50 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51 | def main():
52 | import argparse
53 |
54 | parser = argparse.ArgumentParser(description='Serial port enumeration')
55 |
56 | parser.add_argument(
57 | 'regexp',
58 | nargs='?',
59 | help='only show ports that match this regex')
60 |
61 | parser.add_argument(
62 | '-v', '--verbose',
63 | action='store_true',
64 | help='show more messages')
65 |
66 | parser.add_argument(
67 | '-q', '--quiet',
68 | action='store_true',
69 | help='suppress all messages')
70 |
71 | parser.add_argument(
72 | '-n',
73 | type=int,
74 | help='only output the N-th entry')
75 |
76 | args = parser.parse_args()
77 |
78 | hits = 0
79 | # get iteraror w/ or w/o filter
80 | if args.regexp:
81 | if not args.quiet:
82 | sys.stderr.write("Filtered list with regexp: {!r}\n".format(args.regexp))
83 | iterator = sorted(grep(args.regexp))
84 | else:
85 | iterator = sorted(comports())
86 | # list them
87 | for n, (port, desc, hwid) in enumerate(iterator, 1):
88 | if args.n is None or args.n == n:
89 | sys.stdout.write("{:20}\n".format(port))
90 | if args.verbose:
91 | sys.stdout.write(" desc: {}\n".format(desc))
92 | sys.stdout.write(" hwid: {}\n".format(hwid))
93 | hits += 1
94 | if not args.quiet:
95 | if hits:
96 | sys.stderr.write("{} ports found\n".format(hits))
97 | else:
98 | sys.stderr.write("no ports found\n")
99 |
100 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101 | # test
102 | if __name__ == '__main__':
103 | main()
104 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/list_ports_common.py:
--------------------------------------------------------------------------------
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
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | import re
11 |
12 |
13 | def numsplit(text):
14 | """\
15 | Convert string into a list of texts and numbers in order to support a
16 | natural sorting.
17 | """
18 | result = []
19 | for group in re.split(r'(\d+)', text):
20 | if group:
21 | try:
22 | group = int(group)
23 | except ValueError:
24 | pass
25 | result.append(group)
26 | return result
27 |
28 |
29 | class ListPortInfo(object):
30 | """Info collection base class for serial ports"""
31 |
32 | def __init__(self, device=None):
33 | self.device = device
34 | self.name = None
35 | self.description = 'n/a'
36 | self.hwid = 'n/a'
37 | # USB specific data
38 | self.vid = None
39 | self.pid = None
40 | self.serial_number = None
41 | self.location = None
42 | self.manufacturer = None
43 | self.product = None
44 | self.interface = None
45 |
46 | def usb_description(self):
47 | """return a short string to name the port based on USB info"""
48 | if self.interface is not None:
49 | return '{} - {}'.format(self.product, self.interface)
50 | elif self.product is not None:
51 | return self.product
52 | else:
53 | return self.name
54 |
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 |
63 | def apply_usb_info(self):
64 | """update description and hwid from USB data"""
65 | self.description = self.usb_description()
66 | self.hwid = self.usb_info()
67 |
68 | def __eq__(self, other):
69 | return self.device == other.device
70 |
71 | def __lt__(self, other):
72 | return numsplit(self.device) < numsplit(other.device)
73 |
74 | def __str__(self):
75 | return '{} - {}'.format(self.device, self.description)
76 |
77 | def __getitem__(self, index):
78 | """Item access: backwards compatible -> (port, desc, hwid)"""
79 | if index == 0:
80 | return self.device
81 | elif index == 1:
82 | return self.description
83 | elif index == 2:
84 | return self.hwid
85 | else:
86 | raise IndexError('{} > 2'.format(index))
87 |
88 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89 | # test
90 | if __name__ == '__main__':
91 | print(ListPortInfo('dummy'))
92 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/list_ports_linux.py:
--------------------------------------------------------------------------------
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
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 |
11 | import glob
12 | import os
13 | from serial.tools import list_ports_common
14 |
15 |
16 | class SysFS(list_ports_common.ListPortInfo):
17 | """Wrapper for easy sysfs access and device info"""
18 |
19 | def __init__(self, device):
20 | super(SysFS, self).__init__(device)
21 | self.name = os.path.basename(device)
22 | self.usb_device_path = None
23 | if os.path.exists('/sys/class/tty/{}/device'.format(self.name)):
24 | self.device_path = os.path.realpath('/sys/class/tty/{}/device'.format(self.name))
25 | self.subsystem = os.path.basename(os.path.realpath(os.path.join(self.device_path, 'subsystem')))
26 | else:
27 | self.device_path = None
28 | self.subsystem = None
29 | # check device type
30 | if self.subsystem == 'usb-serial':
31 | self.usb_device_path = os.path.dirname(os.path.dirname(self.device_path))
32 | elif self.subsystem == 'usb':
33 | self.usb_device_path = os.path.dirname(self.device_path)
34 | else:
35 | self.usb_device_path = None
36 | # fill-in info for USB devices
37 | if self.usb_device_path is not None:
38 | self.vid = int(self.read_line(self.usb_device_path, 'idVendor'), 16)
39 | self.pid = int(self.read_line(self.usb_device_path, 'idProduct'), 16)
40 | self.serial_number = self.read_line(self.usb_device_path, 'serial')
41 | self.location = os.path.basename(self.usb_device_path)
42 | self.manufacturer = self.read_line(self.usb_device_path, 'manufacturer')
43 | self.product = self.read_line(self.usb_device_path, 'product')
44 | self.interface = self.read_line(self.device_path, 'interface')
45 |
46 | if self.subsystem in ('usb', 'usb-serial'):
47 | self.apply_usb_info()
48 | #~ elif self.subsystem in ('pnp', 'amba'): # PCI based devices, raspi
49 | elif self.subsystem == 'pnp': # PCI based devices
50 | self.description = self.name
51 | self.hwid = self.read_line(self.device_path, 'id')
52 | elif self.subsystem == 'amba': # raspi
53 | self.description = self.name
54 | self.hwid = os.path.basename(self.device_path)
55 |
56 | def read_line(self, *args):
57 | """\
58 | Helper function to read a single line from a file.
59 | One or more parameters are allowed, they are joined with os.path.join.
60 | Returns None on errors..
61 | """
62 | try:
63 | with open(os.path.join(*args)) as f:
64 | line = f.readline().strip()
65 | return line
66 | except IOError:
67 | return None
68 |
69 |
70 | def comports():
71 | devices = glob.glob('/dev/ttyS*') # built-in serial ports
72 | devices.extend(glob.glob('/dev/ttyUSB*')) # usb-serial with own driver
73 | devices.extend(glob.glob('/dev/ttyACM*')) # usb-serial with CDC-ACM profile
74 | devices.extend(glob.glob('/dev/ttyAMA*')) # ARM internal port (raspi)
75 | devices.extend(glob.glob('/dev/rfcomm*')) # BT serial devices
76 | return [info
77 | for info in [SysFS(d) for d in devices]
78 | if info.subsystem != "platform"] # hide non-present internal serial ports
79 |
80 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81 | # test
82 | if __name__ == '__main__':
83 | for port, desc, hwid in sorted(comports()):
84 | print("{}: {} [{}]".format(port, desc, hwid))
85 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/list_ports_osx.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a module that gathers a list of serial ports including details on OSX
4 | #
5 | # code originally from https://github.com/makerbot/pyserial/tree/master/serial/tools
6 | # with contributions from cibomahto, dgs3, FarMcKon, tedbrandston
7 | # and modifications by cliechti, hoihu, hardkrash
8 | #
9 | # This file is part of pySerial. https://github.com/pyserial/pyserial
10 | # (C) 2013-2015
11 | #
12 | # SPDX-License-Identifier: BSD-3-Clause
13 |
14 |
15 | # List all of the callout devices in OS/X by querying IOKit.
16 |
17 | # See the following for a reference of how to do this:
18 | # http://developer.apple.com/library/mac/#documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/SerialDevices.html#//apple_ref/doc/uid/TP30000384-CIHGEAFD
19 |
20 | # More help from darwin_hid.py
21 |
22 | # Also see the 'IORegistryExplorer' for an idea of what we are actually searching
23 |
24 | import ctypes
25 | import ctypes.util
26 |
27 | from serial.tools import list_ports_common
28 |
29 | iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
30 | cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
31 |
32 | kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
33 | kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
34 |
35 | kCFStringEncodingMacRoman = 0
36 |
37 | iokit.IOServiceMatching.restype = ctypes.c_void_p
38 |
39 | iokit.IOServiceGetMatchingServices.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
40 | iokit.IOServiceGetMatchingServices.restype = ctypes.c_void_p
41 |
42 | iokit.IORegistryEntryGetParentEntry.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
43 |
44 | iokit.IORegistryEntryCreateCFProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint32]
45 | iokit.IORegistryEntryCreateCFProperty.restype = ctypes.c_void_p
46 |
47 | iokit.IORegistryEntryGetPath.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
48 | iokit.IORegistryEntryGetPath.restype = ctypes.c_void_p
49 |
50 | iokit.IORegistryEntryGetName.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
51 | iokit.IORegistryEntryGetName.restype = ctypes.c_void_p
52 |
53 | iokit.IOObjectGetClass.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
54 | iokit.IOObjectGetClass.restype = ctypes.c_void_p
55 |
56 | iokit.IOObjectRelease.argtypes = [ctypes.c_void_p]
57 |
58 |
59 | cf.CFStringCreateWithCString.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32]
60 | cf.CFStringCreateWithCString.restype = ctypes.c_void_p
61 |
62 | cf.CFStringGetCStringPtr.argtypes = [ctypes.c_void_p, ctypes.c_uint32]
63 | cf.CFStringGetCStringPtr.restype = ctypes.c_char_p
64 |
65 | cf.CFNumberGetValue.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_void_p]
66 | cf.CFNumberGetValue.restype = ctypes.c_void_p
67 |
68 | # void CFRelease ( CFTypeRef cf );
69 | cf.CFRelease.argtypes = [ctypes.c_void_p]
70 | cf.CFRelease.restype = None
71 |
72 | # CFNumber type defines
73 | kCFNumberSInt8Type = 1
74 | kCFNumberSInt16Type = 2
75 | kCFNumberSInt32Type = 3
76 | kCFNumberSInt64Type = 4
77 |
78 |
79 | def get_string_property(device_type, property):
80 | """
81 | Search the given device for the specified string property
82 |
83 | @param device_type Type of Device
84 | @param property String to search for
85 | @return Python string containing the value, or None if not found.
86 | """
87 | key = cf.CFStringCreateWithCString(
88 | kCFAllocatorDefault,
89 | property.encode("mac_roman"),
90 | kCFStringEncodingMacRoman)
91 |
92 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
93 | device_type,
94 | key,
95 | kCFAllocatorDefault,
96 | 0)
97 | output = None
98 |
99 | if CFContainer:
100 | output = cf.CFStringGetCStringPtr(CFContainer, 0)
101 | if output is not None:
102 | output = output.decode('mac_roman')
103 | cf.CFRelease(CFContainer)
104 | return output
105 |
106 |
107 | def get_int_property(device_type, property, cf_number_type):
108 | """
109 | Search the given device for the specified string property
110 |
111 | @param device_type Device to search
112 | @param property String to search for
113 | @param cf_number_type CFType number
114 |
115 | @return Python string containing the value, or None if not found.
116 | """
117 | key = cf.CFStringCreateWithCString(
118 | kCFAllocatorDefault,
119 | property.encode("mac_roman"),
120 | kCFStringEncodingMacRoman)
121 |
122 | CFContainer = iokit.IORegistryEntryCreateCFProperty(
123 | device_type,
124 | key,
125 | kCFAllocatorDefault,
126 | 0)
127 |
128 | if CFContainer:
129 | if (cf_number_type == kCFNumberSInt32Type):
130 | number = ctypes.c_uint32()
131 | elif (cf_number_type == kCFNumberSInt16Type):
132 | number = ctypes.c_uint16()
133 | cf.CFNumberGetValue(CFContainer, cf_number_type, ctypes.byref(number))
134 | cf.CFRelease(CFContainer)
135 | return number.value
136 | return None
137 |
138 |
139 | def IORegistryEntryGetName(device):
140 | pathname = ctypes.create_string_buffer(100) # TODO: Is this ok?
141 | iokit.IOObjectGetClass(device, ctypes.byref(pathname))
142 | return pathname.value
143 |
144 |
145 | def GetParentDeviceByType(device, parent_type):
146 | """ Find the first parent of a device that implements the parent_type
147 | @param IOService Service to inspect
148 | @return Pointer to the parent type, or None if it was not found.
149 | """
150 | # First, try to walk up the IOService tree to find a parent of this device that is a IOUSBDevice.
151 | parent_type = parent_type.encode('mac_roman')
152 | while IORegistryEntryGetName(device) != parent_type:
153 | parent = ctypes.c_void_p()
154 | response = iokit.IORegistryEntryGetParentEntry(
155 | device,
156 | "IOService".encode("mac_roman"),
157 | ctypes.byref(parent))
158 | # If we weren't able to find a parent for the device, we're done.
159 | if response != 0:
160 | return None
161 | device = parent
162 | return device
163 |
164 |
165 | def GetIOServicesByType(service_type):
166 | """
167 | returns iterator over specified service_type
168 | """
169 | serial_port_iterator = ctypes.c_void_p()
170 |
171 | iokit.IOServiceGetMatchingServices(
172 | kIOMasterPortDefault,
173 | iokit.IOServiceMatching(service_type.encode('mac_roman')),
174 | ctypes.byref(serial_port_iterator))
175 |
176 | services = []
177 | while iokit.IOIteratorIsValid(serial_port_iterator):
178 | service = iokit.IOIteratorNext(serial_port_iterator)
179 | if not service:
180 | break
181 | services.append(service)
182 | iokit.IOObjectRelease(serial_port_iterator)
183 | return services
184 |
185 |
186 | def location_to_string(locationID):
187 | """
188 | helper to calculate port and bus number from locationID
189 | """
190 | loc = ['{}-'.format(locationID >> 24)]
191 | while locationID & 0xf00000:
192 | if len(loc) > 1:
193 | loc.append('.')
194 | loc.append('{}'.format((locationID >> 20) & 0xf))
195 | locationID <<= 4
196 | return ''.join(loc)
197 |
198 |
199 | class SuitableSerialInterface(object):
200 | pass
201 |
202 |
203 | def scan_interfaces():
204 | """
205 | helper function to scan USB interfaces
206 | returns a list of SuitableSerialInterface objects with name and id attributes
207 | """
208 | interfaces = []
209 | for service in GetIOServicesByType('IOSerialBSDClient'):
210 | device = get_string_property(service, "IOCalloutDevice")
211 | if device:
212 | usb_device = GetParentDeviceByType(service, "IOUSBInterface")
213 | if usb_device:
214 | name = get_string_property(usb_device, "USB Interface Name") or None
215 | locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type) or ''
216 | i = SuitableSerialInterface()
217 | i.id = locationID
218 | i.name = name
219 | interfaces.append(i)
220 | return interfaces
221 |
222 |
223 | def search_for_locationID_in_interfaces(serial_interfaces, locationID):
224 | for interface in serial_interfaces:
225 | if (interface.id == locationID):
226 | return interface.name
227 | return None
228 |
229 |
230 | def comports():
231 | # Scan for all iokit serial ports
232 | services = GetIOServicesByType('IOSerialBSDClient')
233 | ports = []
234 | serial_interfaces = scan_interfaces()
235 | for service in services:
236 | # First, add the callout device file.
237 | device = get_string_property(service, "IOCalloutDevice")
238 | if device:
239 | info = list_ports_common.ListPortInfo(device)
240 | # If the serial port is implemented by IOUSBDevice
241 | usb_device = GetParentDeviceByType(service, "IOUSBDevice")
242 | if usb_device:
243 | # fetch some useful informations from properties
244 | info.vid = get_int_property(usb_device, "idVendor", kCFNumberSInt16Type)
245 | info.pid = get_int_property(usb_device, "idProduct", kCFNumberSInt16Type)
246 | info.serial_number = get_string_property(usb_device, "USB Serial Number")
247 | info.product = get_string_property(usb_device, "USB Product Name") or 'n/a'
248 | info.manufacturer = get_string_property(usb_device, "USB Vendor Name")
249 | locationID = get_int_property(usb_device, "locationID", kCFNumberSInt32Type)
250 | info.location = location_to_string(locationID)
251 | info.interface = search_for_locationID_in_interfaces(serial_interfaces, locationID)
252 | info.apply_usb_info()
253 | ports.append(info)
254 | return ports
255 |
256 | # test
257 | if __name__ == '__main__':
258 | for port, desc, hwid in sorted(comports()):
259 | print("{}: {} [{}]".format(port, desc, hwid))
260 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/tools/list_ports_posix.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # This is a module that gathers a list of serial ports on POSIXy systems.
4 | # For some specific implementations, see also list_ports_linux, list_ports_osx
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2011-2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 |
11 | """\
12 | The ``comports`` function is expected to return an iterable that yields tuples
13 | of 3 strings: port name, human readable description and a hardware ID.
14 |
15 | As currently no method is known to get the second two strings easily, they are
16 | currently just identical to the port name.
17 | """
18 |
19 | import glob
20 | import sys
21 | import os
22 | from serial.tools import list_ports_common
23 |
24 | # try to detect the OS so that a device can be selected...
25 | plat = sys.platform.lower()
26 |
27 | if plat[:5] == 'linux': # Linux (confirmed) # noqa
28 | from serial.tools.list_ports_linux import comports
29 |
30 | elif plat[:6] == 'darwin': # OS X (confirmed)
31 | from serial.tools.list_ports_osx import comports
32 |
33 | elif plat == 'cygwin': # cygwin/win32
34 | # cygwin accepts /dev/com* in many contexts
35 | # (such as 'open' call, explicit 'ls'), but 'glob.glob'
36 | # and bare 'ls' do not; so use /dev/ttyS* instead
37 | def comports():
38 | devices = glob.glob('/dev/ttyS*')
39 | return [list_ports_common.ListPortInfo(d) for d in devices]
40 |
41 | elif plat[:7] == 'openbsd': # OpenBSD
42 | def comports():
43 | devices = glob.glob('/dev/cua*')
44 | return [list_ports_common.ListPortInfo(d) for d in devices]
45 |
46 | elif plat[:3] == 'bsd' or plat[:7] == 'freebsd':
47 | def comports():
48 | devices = glob.glob('/dev/cua*[!.init][!.lock]')
49 | return [list_ports_common.ListPortInfo(d) for d in devices]
50 |
51 | elif plat[:6] == 'netbsd': # NetBSD
52 | def comports():
53 | """scan for available ports. return a list of device names."""
54 | devices = glob.glob('/dev/dty*')
55 | return [list_ports_common.ListPortInfo(d) for d in devices]
56 |
57 | elif plat[:4] == 'irix': # IRIX
58 | def comports():
59 | """scan for available ports. return a list of device names."""
60 | devices = glob.glob('/dev/ttyf*')
61 | return [list_ports_common.ListPortInfo(d) for d in devices]
62 |
63 | elif plat[:2] == 'hp': # HP-UX (not tested)
64 | def comports():
65 | """scan for available ports. return a list of device names."""
66 | devices = glob.glob('/dev/tty*p0')
67 | return [list_ports_common.ListPortInfo(d) for d in devices]
68 |
69 | elif plat[:5] == 'sunos': # Solaris/SunOS
70 | def comports():
71 | """scan for available ports. return a list of device names."""
72 | devices = glob.glob('/dev/tty*c')
73 | return [list_ports_common.ListPortInfo(d) for d in devices]
74 |
75 | elif plat[:3] == 'aix': # AIX
76 | def comports():
77 | """scan for available ports. return a list of device names."""
78 | devices = glob.glob('/dev/tty*')
79 | return [list_ports_common.ListPortInfo(d) for d in devices]
80 |
81 | else:
82 | # platform detection has failed...
83 | import serial
84 | sys.stderr.write("""\
85 | don't know how to enumerate ttys on this system.
86 | ! I you know how the serial ports are named send this information to
87 | ! the author of this module:
88 |
89 | sys.platform = {!r}
90 | os.name = {!r}
91 | pySerial version = {}
92 |
93 | also add the naming scheme of the serial ports and with a bit luck you can get
94 | this module running...
95 | """.format(sys.platform, os.name, serial.VERSION))
96 | raise ImportError("Sorry: no implementation for your platform ('{}') available".format(os.name))
97 |
98 | # test
99 | if __name__ == '__main__':
100 | for port, desc, hwid in sorted(comports()):
101 | print("{}: {} [{}]".format(port, desc, hwid))
102 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/urlhandler/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arpruss/gcodeplot/dc9ca1eef3b7af4a253de3adfbd0f1cac3da8364/gcodeplotutils/pyserial3/serial/urlhandler/__init__.py
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/urlhandler/protocol_alt.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This module implements a special URL handler that allows selecting an
4 | # alternate implementation provided by some backends.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | #
11 | # URL format: alt://port[?option[=value][&option[=value]]]
12 | # options:
13 | # - class=X used class named X instead of Serial
14 | #
15 | # example:
16 | # use poll based implementation on Posix (Linux):
17 | # python -m serial.tools.miniterm alt:///dev/ttyUSB0?class=PosixPollSerial
18 |
19 | try:
20 | import urlparse
21 | except ImportError:
22 | import urllib.parse as urlparse
23 |
24 | import serial
25 |
26 |
27 | def serial_class_for_url(url):
28 | """extract host and port from an URL string"""
29 | parts = urlparse.urlsplit(url)
30 | if parts.scheme != 'alt':
31 | raise serial.SerialException(
32 | 'expected a string in the form "alt://port[?option[=value][&option[=value]]]": '
33 | 'not starting with alt:// ({!r})'.format(parts.scheme))
34 | class_name = 'Serial'
35 | try:
36 | for option, values in urlparse.parse_qs(parts.query, True).items():
37 | if option == 'class':
38 | class_name = values[0]
39 | else:
40 | raise ValueError('unknown option: {!r}'.format(option))
41 | except ValueError as e:
42 | raise serial.SerialException(
43 | 'expected a string in the form '
44 | '"alt://port[?option[=value][&option[=value]]]": {!r}'.format(e))
45 | if not hasattr(serial, class_name):
46 | raise ValueError('unknown class: {!r}'.format(class_name))
47 | cls = getattr(serial, class_name)
48 | if not issubclass(cls, serial.Serial):
49 | raise ValueError('class {!r} is not an instance of Serial'.format(class_name))
50 | return (''.join([parts.netloc, parts.path]), cls)
51 |
52 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53 | if __name__ == '__main__':
54 | s = serial.serial_for_url('alt:///dev/ttyS0?class=PosixPollSerial')
55 | print(s)
56 |
--------------------------------------------------------------------------------
/gcodeplotutils/pyserial3/serial/urlhandler/protocol_hwgrep.py:
--------------------------------------------------------------------------------
1 | #! python
2 | #
3 | # This module implements a special URL handler that uses the port listing to
4 | # find ports by searching the string descriptions.
5 | #
6 | # This file is part of pySerial. https://github.com/pyserial/pyserial
7 | # (C) 2011-2015 Chris Liechti
8 | #
9 | # SPDX-License-Identifier: BSD-3-Clause
10 | #
11 | # URL format: hwgrep://&