├── .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 | 8 | .scad 9 | text/plain 10 | <_filetypename>OpenSCAD cookie cutter file (*.scad) 11 | <_filetypetooltip>Export an OpenSCAD cookie cutter file 12 | true 13 | 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 | 92 | .gcode 93 | text/plain 94 | <_filetypename>3-axis gcode plotter (*.gcode) 95 | <_filetypetooltip>Export 3-axis gcode plotter file 96 | true 97 | 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://&