From 9ee7602ace4e775bdcacdaa21e0b2a46de62034c Mon Sep 17 00:00:00 2001 From: fsantini Date: Mon, 11 Mar 2013 22:10:22 +0100 Subject: [PATCH 1/9] Creation of GCodeAnalyzer.py Imported and translated from RepetierHost First commit unfinished implementation --- GCodeAnalyzer.py | 112 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 GCodeAnalyzer.py diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py new file mode 100644 index 0000000..d29a107 --- /dev/null +++ b/GCodeAnalyzer.py @@ -0,0 +1,112 @@ +# This file is part of the Printrun suite. +# +# Copyright 2013 Francesco Santini francesco.santini@gmail.com +# +# Printrun is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Printrun is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Printrun. If not, see . +# +# This code is imported from RepetierHost - Original copyright and license: +# Copyright 2011 repetier repetierdev@gmail.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re + +class GCodeAnalyzer(): + def __init__(self): + self.x = 0 + self.y = 0 + self.z = 0 + self.e = 0 + self.emax = 0 + self.f = 1000 + self.lastX = 0 + self.lastY = 0 + self.lastZ = 0 + self.lastE = 0 + self.xOffset = 0 + self.yOffset = 0 + self.zOffset = 0 + self.eOffset = 0 + self.lastZPrint = 0 + self.layerZ = 0 + self.relative = False + self.eRelative = False + + + # find a code in a gstring line + def findCode(self, gcode, codeStr): + pattern = re.compile(codeStr + "s*([\d.]*)",re.I) + m=re.match(pattern, gcode) + if m == None: + return None + else + return m.group(1) + + def Analyze(self, gcode): + code_g = self.findCode(gcode, "G") + + # we have a g_code + if code_g != None: + code_g = int(code_g) + + #get movement codes + if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3: + eChanged = false; + code_f = self.findCode(gcode, "F") + if code_f != None: + self.f=float(code_f) + + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode. "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") + + if self.relative: + if code_x != None: self.x += float(code_x) + if code_y != None: self.y += float(code_y) + if code_z != None: self.z += float(code_z) + if code_e != None: + e = float(code_e) + if e != 0: + eChanged = True + self.e += e + else: + #absolute coordinates + if code_x != None: self.x = self.xOffset + float(code_x) + if code_y != None: self.y = self.yOffset + float(code_y) + if code_z != None: self.z = self.zOffset + float(code_z) + if code_e != None: + e = float(code_e) + if self.eRelative: + if e != 0: + eChanged = True + self.e += e + else: + # e is absolute. Is it changed? + if self.e != self.eOffset + e: + eChanged = True + self.e = self.eOffset + e + #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now + + elif code_g == 28 or code_g == 161: \ No newline at end of file From 60158d5e39530767f086425b3ffc40684a06303d Mon Sep 17 00:00:00 2001 From: Francesco Santini Date: Tue, 12 Mar 2013 18:04:28 +0100 Subject: [PATCH 2/9] More implementation (still unusable) --- GCodeAnalyzer.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index d29a107..97c0cd5 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -52,6 +52,12 @@ class GCodeAnalyzer(): self.layerZ = 0 self.relative = False self.eRelative = False + self.homeX = 0 + self.homeY = 0 + self.homeZ = 0 + self.maxX = 150 + self.maxY = 150 + self.maxZ = 150 # find a code in a gstring line @@ -109,4 +115,11 @@ class GCodeAnalyzer(): self.e = self.eOffset + e #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now - elif code_g == 28 or code_g == 161: \ No newline at end of file + elif code_g == 28 or code_g == 161: + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") + homeAll = False + if code_x == None and code_y == None and code_z == None: homeAll = True + \ No newline at end of file From b335a4cf77af82a187dddac975d5835f2fd4b4fd Mon Sep 17 00:00:00 2001 From: fsantini Date: Tue, 12 Mar 2013 20:58:00 +0100 Subject: [PATCH 3/9] G-codes and relevant M-codes implemented (check for tabs/spaces) --- GCodeAnalyzer.py | 68 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index 97c0cd5..aa2a5bc 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -60,21 +60,22 @@ class GCodeAnalyzer(): self.maxZ = 150 - # find a code in a gstring line - def findCode(self, gcode, codeStr): + # find a code in a gstring line + def findCode(self, gcode, codeStr): pattern = re.compile(codeStr + "s*([\d.]*)",re.I) m=re.match(pattern, gcode) if m == None: - return None + return None else - return m.group(1) + return m.group(1) - def Analyze(self, gcode): + def Analyze(self, gcode): code_g = self.findCode(gcode, "G") + code_m = self.findCode(gcode, "M") # we have a g_code if code_g != None: - code_g = int(code_g) + code_g = int(code_g) #get movement codes if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3: @@ -97,7 +98,7 @@ class GCodeAnalyzer(): if e != 0: eChanged = True self.e += e - else: + else: #absolute coordinates if code_x != None: self.x = self.xOffset + float(code_x) if code_y != None: self.y = self.yOffset + float(code_y) @@ -122,4 +123,55 @@ class GCodeAnalyzer(): code_e = self.findCode(gcode, "E") homeAll = False if code_x == None and code_y == None and code_z == None: homeAll = True - \ No newline at end of file + if code_x != None or homeAll: + self.xOffset = 0 + self.x = self.homeX + if code_y != None or homeAll: + self.yOffset = 0 + self.y = self.homeY + if code_z != None or homeAll: + self.zOffset = 0 + self.z = self.homeZ + if code_e != None: + self.eOffset = 0 + self.e = 0 + elif code_g == 162: + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + homeAll = False + if code_x == None and code_y == None and code_z == None: homeAll = True + if code_x != None or homeAll: + self.xOffset = 0 + self.x = self.maxX + if code_y != None or homeAll: + self.yOffset = 0 + self.y = self.maxY + if code_z != None or homeAll: + self.zOffset = 0 + self.z = self.maxZ + elif code_g == 90: self.relative = False + elif code_g == 91: self.relative = True + elif code_g == 92: + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") + if code_x != None: + self.xOffset = self.x - float(code_x) + self.x = self.xOffset + if code_y != None: + self.yOffset = self.y - float(code_y) + self.y = self.yOffset + if code_z != None: + self.zOffset = self.z - float(code_z) + self.z = self.zOffset + if code_e != None: + self.xOffset = self.e - float(code_e) + self.e = self.eOffset + #End code_g != None + if code_m != None: + code_m = int(code_m) + if code_m == 82: self.eRelative = False + elif code_m == 83: self.eRelative = True + \ No newline at end of file From 6cf08006c2e0f753608f1394a6b159de35801f51 Mon Sep 17 00:00:00 2001 From: fsantini Date: Thu, 14 Mar 2013 07:35:17 +0100 Subject: [PATCH 4/9] Indentation fixes, start pronterface modification --- GCodeAnalyzer.py | 280 +++++++++++++++++++++++++---------------------- printcore.py | 4 + 2 files changed, 154 insertions(+), 130 deletions(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index aa2a5bc..8a69557 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -33,32 +33,35 @@ import re class GCodeAnalyzer(): - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - self.e = 0 - self.emax = 0 - self.f = 1000 - self.lastX = 0 - self.lastY = 0 - self.lastZ = 0 - self.lastE = 0 - self.xOffset = 0 - self.yOffset = 0 - self.zOffset = 0 - self.eOffset = 0 - self.lastZPrint = 0 - self.layerZ = 0 - self.relative = False - self.eRelative = False - self.homeX = 0 - self.homeY = 0 - self.homeZ = 0 - self.maxX = 150 - self.maxY = 150 - self.maxZ = 150 - + def __init__(self): + self.x = 0 + self.y = 0 + self.z = 0 + self.e = 0 + self.emax = 0 + self.f = 1000 + self.lastX = 0 + self.lastY = 0 + self.lastZ = 0 + self.lastE = 0 + self.xOffset = 0 + self.yOffset = 0 + self.zOffset = 0 + self.eOffset = 0 + self.lastZPrint = 0 + self.layerZ = 0 + self.relative = False + self.eRelative = False + self.homeX = 0 + self.homeY = 0 + self.homeZ = 0 + self.maxX = 150 + self.maxY = 150 + self.maxZ = 150 + self.hasHomeX = False + self.hasHomeY = False + self.hasHomeZ = False + # find a code in a gstring line def findCode(self, gcode, codeStr): @@ -66,112 +69,129 @@ class GCodeAnalyzer(): m=re.match(pattern, gcode) if m == None: return None - else + else: return m.group(1) - + def Analyze(self, gcode): - code_g = self.findCode(gcode, "G") - code_m = self.findCode(gcode, "M") + code_g = self.findCode(gcode, "G") + code_m = self.findCode(gcode, "M") + # we have a g_code + if code_g != None: + code_g = int(code_g) + + #get movement codes + if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3: + self.lastX = self.x + self.lastY = self.y + self.lastZ = self.z + self.lastE = self.e + eChanged = false; + code_f = self.findCode(gcode, "F") + if code_f != None: + self.f=float(code_f) + + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") - # we have a g_code - if code_g != None: - code_g = int(code_g) - - #get movement codes - if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3: - eChanged = false; - code_f = self.findCode(gcode, "F") - if code_f != None: - self.f=float(code_f) - - code_x = self.findCode(gcode, "X") - code_y = self.findCode(gcode. "Y") - code_z = self.findCode(gcode, "Z") - code_e = self.findCode(gcode, "E") - - if self.relative: - if code_x != None: self.x += float(code_x) - if code_y != None: self.y += float(code_y) - if code_z != None: self.z += float(code_z) - if code_e != None: - e = float(code_e) - if e != 0: - eChanged = True - self.e += e - else: - #absolute coordinates - if code_x != None: self.x = self.xOffset + float(code_x) - if code_y != None: self.y = self.yOffset + float(code_y) - if code_z != None: self.z = self.zOffset + float(code_z) - if code_e != None: - e = float(code_e) - if self.eRelative: - if e != 0: - eChanged = True - self.e += e - else: - # e is absolute. Is it changed? - if self.e != self.eOffset + e: - eChanged = True - self.e = self.eOffset + e - #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now - - elif code_g == 28 or code_g == 161: - code_x = self.findCode(gcode, "X") - code_y = self.findCode(gcode, "Y") - code_z = self.findCode(gcode, "Z") - code_e = self.findCode(gcode, "E") - homeAll = False - if code_x == None and code_y == None and code_z == None: homeAll = True - if code_x != None or homeAll: - self.xOffset = 0 - self.x = self.homeX - if code_y != None or homeAll: - self.yOffset = 0 - self.y = self.homeY - if code_z != None or homeAll: - self.zOffset = 0 - self.z = self.homeZ - if code_e != None: - self.eOffset = 0 - self.e = 0 - elif code_g == 162: - code_x = self.findCode(gcode, "X") - code_y = self.findCode(gcode, "Y") - code_z = self.findCode(gcode, "Z") - homeAll = False - if code_x == None and code_y == None and code_z == None: homeAll = True - if code_x != None or homeAll: - self.xOffset = 0 - self.x = self.maxX - if code_y != None or homeAll: - self.yOffset = 0 - self.y = self.maxY - if code_z != None or homeAll: - self.zOffset = 0 - self.z = self.maxZ - elif code_g == 90: self.relative = False - elif code_g == 91: self.relative = True - elif code_g == 92: - code_x = self.findCode(gcode, "X") - code_y = self.findCode(gcode, "Y") - code_z = self.findCode(gcode, "Z") - code_e = self.findCode(gcode, "E") - if code_x != None: - self.xOffset = self.x - float(code_x) - self.x = self.xOffset - if code_y != None: - self.yOffset = self.y - float(code_y) - self.y = self.yOffset - if code_z != None: - self.zOffset = self.z - float(code_z) - self.z = self.zOffset - if code_e != None: - self.xOffset = self.e - float(code_e) - self.e = self.eOffset + if self.relative: + if code_x != None: self.x += float(code_x) + if code_y != None: self.y += float(code_y) + if code_z != None: self.z += float(code_z) + if code_e != None: + e = float(code_e) + if e != 0: + eChanged = True + self.e += e + else: + #absolute coordinates + if code_x != None: self.x = self.xOffset + float(code_x) + if code_y != None: self.y = self.yOffset + float(code_y) + if code_z != None: self.z = self.zOffset + float(code_z) + if code_e != None: + e = float(code_e) + if self.eRelative: + if e != 0: + eChanged = True + self.e += e + else: + # e is absolute. Is it changed? + if self.e != self.eOffset + e: + eChanged = True + self.e = self.eOffset + e + #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now + elif code_g == 28 or code_g == 161: + self.lastX = self.x + self.lastY = self.y + self.lastZ = self.z + self.lastE = self.e + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") + homeAll = False + if code_x == None and code_y == None and code_z == None: homeAll = True + if code_x != None or homeAll: + self.hasHomeX = True + self.xOffset = 0 + self.x = self.homeX + if code_y != None or homeAll: + self.hasHomeY = True + self.yOffset = 0 + self.y = self.homeY + if code_z != None or homeAll: + self.hasHomeZ = True + self.zOffset = 0 + self.z = self.homeZ + if code_e != None: + self.eOffset = 0 + self.e = 0 + elif code_g == 162: + self.lastX = self.x + self.lastY = self.y + self.lastZ = self.z + self.lastE = self.e + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + homeAll = False + if code_x == None and code_y == None and code_z == None: homeAll = True + if code_x != None or homeAll: + self.hasHomeX = True + self.xOffset = 0 + self.x = self.maxX + if code_y != None or homeAll: + self.hasHomeY = True + self.yOffset = 0 + self.y = self.maxY + if code_z != None or homeAll: + self.hasHomeZ = True + self.zOffset = 0 + self.z = self.maxZ + elif code_g == 90: self.relative = False + elif code_g == 91: self.relative = True + elif code_g == 92: + code_x = self.findCode(gcode, "X") + code_y = self.findCode(gcode, "Y") + code_z = self.findCode(gcode, "Z") + code_e = self.findCode(gcode, "E") + if code_x != None: + self.xOffset = self.x - float(code_x) + self.x = self.xOffset + if code_y != None: + self.yOffset = self.y - float(code_y) + self.y = self.yOffset + if code_z != None: + self.zOffset = self.z - float(code_z) + self.z = self.zOffset + if code_e != None: + self.xOffset = self.e - float(code_e) + self.e = self.eOffset #End code_g != None if code_m != None: - code_m = int(code_m) - if code_m == 82: self.eRelative = False - elif code_m == 83: self.eRelative = True - \ No newline at end of file + code_m = int(code_m) + if code_m == 82: self.eRelative = False + elif code_m == 83: self.eRelative = True + + \ No newline at end of file diff --git a/printcore.py b/printcore.py index bb6501c..a96e004 100755 --- a/printcore.py +++ b/printcore.py @@ -20,6 +20,7 @@ from threading import Thread from select import error as SelectError import time, getopt, sys import platform, os +from GCodeAnalyzer import GCodeAnalyzer def control_ttyhup(port, disable_hup): """Controls the HUPCL""" @@ -70,6 +71,8 @@ class printcore(): if port is not None and baud is not None: self.connect(port, baud) + self.analyzer = GCodeAnalyzer() + def disconnect(self): """Disconnects from printer and pauses the print """ @@ -335,6 +338,7 @@ class printcore(): self.sentlines[lineno] = command if self.printer: self.sent.append(command) + self.analyzer.Analyze(command) # run the command through the analyzer if self.loud: print "SENT: ", command if self.sendcb: From 00f1306f08a063ef041d274017e76079307e9c82 Mon Sep 17 00:00:00 2001 From: fsantini Date: Sat, 6 Apr 2013 18:22:56 +0200 Subject: [PATCH 5/9] Bugfixes in the analyzer Pause code (Ported from RepetierHost, untested) --- GCodeAnalyzer.py | 26 ++++++++++++++++++++------ printcore.py | 31 ++++++++++++++++++++++++++++++- pronterface.py | 17 +++++++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index 8a69557..bb1c526 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -58,6 +58,9 @@ class GCodeAnalyzer(): self.maxX = 150 self.maxY = 150 self.maxZ = 150 + self.minX = 0 + self.minY = 0 + self.minZ = 0 self.hasHomeX = False self.hasHomeY = False self.hasHomeZ = False @@ -65,8 +68,8 @@ class GCodeAnalyzer(): # find a code in a gstring line def findCode(self, gcode, codeStr): - pattern = re.compile(codeStr + "s*([\d.]*)",re.I) - m=re.match(pattern, gcode) + pattern = re.compile(codeStr + "\\s*([\d.-]*)",re.I) + m=re.search(pattern, gcode) if m == None: return None else: @@ -85,7 +88,7 @@ class GCodeAnalyzer(): self.lastY = self.y self.lastZ = self.z self.lastE = self.e - eChanged = false; + eChanged = False; code_f = self.findCode(gcode, "F") if code_f != None: self.f=float(code_f) @@ -94,7 +97,7 @@ class GCodeAnalyzer(): code_y = self.findCode(gcode, "Y") code_z = self.findCode(gcode, "Z") code_e = self.findCode(gcode, "E") - + if self.relative: if code_x != None: self.x += float(code_x) if code_y != None: self.y += float(code_y) @@ -120,7 +123,15 @@ class GCodeAnalyzer(): if self.e != self.eOffset + e: eChanged = True self.e = self.eOffset + e - #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now + #limit checking + if self.x < self.minX: self.x = self.minX + if self.y < self.minY: self.y = self.minY + if self.z < self.minZ: self.z = self.minZ + + if self.x > self.maxX: self.x = self.maxX + if self.y > self.maxY: self.y = self.maxY + if self.z > self.maxZ: self.z = self.maxZ + #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now elif code_g == 28 or code_g == 161: self.lastX = self.x self.lastY = self.y @@ -193,5 +204,8 @@ class GCodeAnalyzer(): code_m = int(code_m) if code_m == 82: self.eRelative = False elif code_m == 83: self.eRelative = True - + + def print_status(self): + attrs = vars(self) + print '\n'.join("%s: %s" % item for item in attrs.items()) \ No newline at end of file diff --git a/printcore.py b/printcore.py index a96e004..beec243 100755 --- a/printcore.py +++ b/printcore.py @@ -70,8 +70,9 @@ class printcore(): self.print_thread = None if port is not None and baud is not None: self.connect(port, baud) - self.analyzer = GCodeAnalyzer() + self.xy_feedrate = None + self.z_feedrate = None def disconnect(self): """Disconnects from printer and pauses the print @@ -229,10 +230,38 @@ class printcore(): self.printing = False self.print_thread.join() self.print_thread = None + + # saves the status + self.pauseX = analyzer.x-analyzer.xOffset; + self.pauseY = analyzer.y-analyzer.yOffset; + self.pauseZ = analyzer.z-analyzer.zOffset; + self.pauseE = analyzer.e-analyzer.eOffset; + self.pauseF = analyzer.f; + self.pauseRelative = analyzer.relative; + + def resume(self): """Resumes a paused print. """ + + if self.paused: + #restores the status + self.send("G90") # go to absolute coordinates + + xyFeedString = "" + zFeedString = "" + if self.xy_feedrate != None: xyFeedString = " F" + str(self.xy_feedrate) + if self.z_feedrate != None: zFeedString = " F" + str(self.z_feedrate) + + self.send("G1 X" + str(self.pauseX) + " Y" + str(self.pauseY) + xyFeedString) + self.send("G1 Z" + str(self.pauseZ) + zFeedString) + self.send("G92 E" + str(self.pauseE)) + + if self.pauseRelative: self.send("G91") # go back to relative if needed + #reset old feed rate + self.send("G1 F" + str(self.pauseF)) + self.paused = False self.printing = True self.print_thread = Thread(target = self._print) diff --git a/pronterface.py b/pronterface.py index 89536eb..4fd7466 100755 --- a/pronterface.py +++ b/pronterface.py @@ -128,6 +128,23 @@ class PronterWindow(MainWindow, pronsole.pronsole): self.btndict = {} self.parse_cmdline(sys.argv[1:]) self.build_dimensions_list = self.get_build_dimensions(self.settings.build_dimensions) + + #initialize the code analyzer with the correct sizes. There must be a more general way to do so + self.p.analyzer.maxX = self.build_dimensions_list[0]; + self.p.analyzer.maxY = self.build_dimensions_list[1]; + self.p.analyzer.maxZ = self.build_dimensions_list[2]; + + self.p.analyzer.homeX = self.build_dimensions_list[3]; + self.p.analyzer.homeY = self.build_dimensions_list[4]; + self.p.analyzer.homeZ = self.build_dimensions_list[5]; + + self.p.analyzer.print_status() + + #set feedrates in printcore for pause/resume + self.p.xy_feedrate = self.settings.xy_feedrate + self.p.z_feedrate = self.settings.z_feedrate + + self.panel.SetBackgroundColour(self.settings.bgcolor) customdict = {} try: From 360b4f60e44dafce5475be122de3eb16179617a9 Mon Sep 17 00:00:00 2001 From: fsantini Date: Sun, 7 Apr 2013 19:45:45 +0200 Subject: [PATCH 6/9] Pause code working; implemented the @pause gcode host command (and a small framework for host commands) --- GCodeAnalyzer.py | 1 + gcoder.py | 4 +++ printcore.py | 68 +++++++++++++++++++++++++++++++++++++----------- pronterface.py | 39 ++++++++++++++++++--------- 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index bb1c526..f0f8c12 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -76,6 +76,7 @@ class GCodeAnalyzer(): return m.group(1) def Analyze(self, gcode): + gcode = gcode[:gcode.find(";")] # remove comments code_g = self.findCode(gcode, "G") code_m = self.findCode(gcode, "M") # we have a g_code diff --git a/gcoder.py b/gcoder.py index 79c95bc..a62efb8 100755 --- a/gcoder.py +++ b/gcoder.py @@ -30,6 +30,10 @@ class Line(object): self.imperial = False self.relative = False + #ignore host commands + if "@" in self.raw: + self.raw = "" + if ";" in self.raw: self.raw = self.raw.split(";")[0] diff --git a/printcore.py b/printcore.py index beec243..02c5361 100755 --- a/printcore.py +++ b/printcore.py @@ -73,6 +73,7 @@ class printcore(): self.analyzer = GCodeAnalyzer() self.xy_feedrate = None self.z_feedrate = None + self.pronterface = None def disconnect(self): """Disconnects from printer and pauses the print @@ -223,23 +224,45 @@ class printcore(): self.print_thread.start() return True + # run a simple script if it exists, no multithreading + def runSmallScript(self, filename): + if filename == None: return + f = None + try: + f = open(filename) + except: + pass + + if f != None: + for i in f: + l = i.replace("\n", "") + l = l[:l.find(";")] #remove comment + self.send_now(l) + f.close() + def pause(self): """Pauses the print, saving the current position. """ self.paused = True self.printing = False - self.print_thread.join() + + # try joining the print thread: enclose it in try/except because we might be calling it from the thread itself + + try: + self.print_thread.join() + except: pass + self.print_thread = None # saves the status - self.pauseX = analyzer.x-analyzer.xOffset; - self.pauseY = analyzer.y-analyzer.yOffset; - self.pauseZ = analyzer.z-analyzer.zOffset; - self.pauseE = analyzer.e-analyzer.eOffset; - self.pauseF = analyzer.f; - self.pauseRelative = analyzer.relative; - - + self.pauseX = self.analyzer.x-self.analyzer.xOffset; + self.pauseY = self.analyzer.y-self.analyzer.yOffset; + self.pauseZ = self.analyzer.z-self.analyzer.zOffset; + self.pauseE = self.analyzer.e-self.analyzer.eOffset; + self.pauseF = self.analyzer.f; + self.pauseRelative = self.analyzer.relative; + + def resume(self): """Resumes a paused print. @@ -247,20 +270,20 @@ class printcore(): if self.paused: #restores the status - self.send("G90") # go to absolute coordinates + self.send_now("G90") # go to absolute coordinates xyFeedString = "" zFeedString = "" if self.xy_feedrate != None: xyFeedString = " F" + str(self.xy_feedrate) if self.z_feedrate != None: zFeedString = " F" + str(self.z_feedrate) - self.send("G1 X" + str(self.pauseX) + " Y" + str(self.pauseY) + xyFeedString) - self.send("G1 Z" + str(self.pauseZ) + zFeedString) - self.send("G92 E" + str(self.pauseE)) + self.send_now("G1 X" + str(self.pauseX) + " Y" + str(self.pauseY) + xyFeedString) + self.send_now("G1 Z" + str(self.pauseZ) + zFeedString) + self.send_now("G92 E" + str(self.pauseE)) - if self.pauseRelative: self.send("G91") # go back to relative if needed + if self.pauseRelative: self.send_now("G91") # go back to relative if needed #reset old feed rate - self.send("G1 F" + str(self.pauseF)) + self.send_now("G1 F" + str(self.pauseF)) self.paused = False self.printing = True @@ -324,6 +347,14 @@ class printcore(): try: self.endcb() except: pass + #now only "pause" is implemented as host command + def processHostCommand(self, command): + if command == "@pause": + if self.pronterface != None: + self.pronterface.pause(None) + else: + self.pause() + def _sendnext(self): if not self.printer: return @@ -344,6 +375,13 @@ class printcore(): return if self.printing and self.queueindex < len(self.mainqueue): tline = self.mainqueue[self.queueindex] + #check for host command + if tline.startswith("@"): + #it is a host command: pop it from the list + self.mainqueue.pop(self.queueindex) + self.processHostCommand(tline) + return + tline = tline.split(";")[0] if len(tline) > 0: self._send(tline, self.lineno, True) diff --git a/pronterface.py b/pronterface.py index 4fd7466..82c84a6 100755 --- a/pronterface.py +++ b/pronterface.py @@ -85,7 +85,7 @@ class Tee(object): class PronterWindow(MainWindow, pronsole.pronsole): def __init__(self, filename = None, size = winsize): pronsole.pronsole.__init__(self) - self.settings.build_dimensions = '200x200x100+0+0+0' #default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed + self.settings.build_dimensions = '200x200x100+0+0+0+0+0+0' #default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed self.settings.last_bed_temperature = 0.0 self.settings.last_file_path = "" self.settings.last_temperature = 0.0 @@ -93,7 +93,11 @@ class PronterWindow(MainWindow, pronsole.pronsole): self.settings.preview_grid_step1 = 10. self.settings.preview_grid_step2 = 50. self.settings.bgcolor = "#FFFFFF" - self.helpdict["build_dimensions"] = _("Dimensions of Build Platform\n & optional offset of origin\n\nExamples:\n XXXxYYY\n XXX,YYY,ZZZ\n XXXxYYYxZZZ+OffX+OffY+OffZ") + + self.pauseScript = "pause.gcode" + self.endScript = "end.gcode" + + self.helpdict["build_dimensions"] = _("Dimensions of Build Platform\n & optional offset of origin\n & optional switch position\n\nExamples:\n XXXxYYY\n XXX,YYY,ZZZ\n XXXxYYYxZZZ+OffX+OffY+OffZ\nXXXxYYYxZZZ+OffX+OffY+OffZ+HomeX+HomeY+HomeZ") self.helpdict["last_bed_temperature"] = _("Last Set Temperature for the Heated Print Bed") self.helpdict["last_file_path"] = _("Folder of last opened file") self.helpdict["last_temperature"] = _("Last Temperature of the Hot End") @@ -130,20 +134,24 @@ class PronterWindow(MainWindow, pronsole.pronsole): self.build_dimensions_list = self.get_build_dimensions(self.settings.build_dimensions) #initialize the code analyzer with the correct sizes. There must be a more general way to do so - self.p.analyzer.maxX = self.build_dimensions_list[0]; - self.p.analyzer.maxY = self.build_dimensions_list[1]; - self.p.analyzer.maxZ = self.build_dimensions_list[2]; + self.p.analyzer.maxX = self.build_dimensions_list[0] if self.build_dimensions_list[0] >= self.build_dimensions_list[6] else self.build_dimensions_list[6] # maximum x is maximum x if maximum X > home X, else it is home X + self.p.analyzer.maxY = self.build_dimensions_list[1] if self.build_dimensions_list[1] >= self.build_dimensions_list[7] else self.build_dimensions_list[7] + self.p.analyzer.maxZ = self.build_dimensions_list[2] if self.build_dimensions_list[2] >= self.build_dimensions_list[8] else self.build_dimensions_list[8] - self.p.analyzer.homeX = self.build_dimensions_list[3]; - self.p.analyzer.homeY = self.build_dimensions_list[4]; - self.p.analyzer.homeZ = self.build_dimensions_list[5]; - - self.p.analyzer.print_status() + self.p.analyzer.minX = self.build_dimensions_list[3] + self.p.analyzer.minY = self.build_dimensions_list[4] + self.p.analyzer.minZ = self.build_dimensions_list[5] + self.p.analyzer.homeX = self.build_dimensions_list[6] + self.p.analyzer.homeY = self.build_dimensions_list[7] + self.p.analyzer.homeZ = self.build_dimensions_list[8] + #set feedrates in printcore for pause/resume self.p.xy_feedrate = self.settings.xy_feedrate self.p.z_feedrate = self.settings.z_feedrate + #make printcore aware of me + self.p.pronterface = self self.panel.SetBackgroundColour(self.settings.bgcolor) customdict = {} @@ -215,6 +223,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): wx.CallAfter(self.pausebtn.Disable) wx.CallAfter(self.printbtn.SetLabel, _("Print")) + self.p.runSmallScript(self.endScript) + param = self.settings.final_command if not param: return @@ -1405,7 +1415,9 @@ class PronterWindow(MainWindow, pronsole.pronsole): #print "Not printing, cannot pause." return self.p.pause() + self.p.runSmallScript(self.pauseScript) self.paused = True + #self.p.runSmallScript(self.pauseScript) self.extra_print_time += int(time.time() - self.starttime) wx.CallAfter(self.pausebtn.SetLabel, _("Resume")) else: @@ -1544,9 +1556,12 @@ class PronterWindow(MainWindow, pronsole.pronsole): "[^\d+-]*(\d+)?" + # Z build size "[^\d+-]*([+-]\d+)?" + # X corner coordinate "[^\d+-]*([+-]\d+)?" + # Y corner coordinate - "[^\d+-]*([+-]\d+)?" # Z corner coordinate + "[^\d+-]*([+-]\d+)?" + # Z corner coordinate + "[^\d+-]*([+-]\d+)?" + # X endstop + "[^\d+-]*([+-]\d+)?" + # Y endstop + "[^\d+-]*([+-]\d+)?" # Z endstop ,bdim).groups() - defaults = [200, 200, 100, 0, 0, 0] + defaults = [200, 200, 100, 0, 0, 0, 0, 0, 0] bdl_float = [float(value) if value else defaults[i] for i, value in enumerate(bdl)] return bdl_float From 5a059961fae86413eb6aa4f9244dbb7155aa0458 Mon Sep 17 00:00:00 2001 From: Francesco Santini Date: Mon, 8 Apr 2013 13:06:31 +0200 Subject: [PATCH 7/9] Indentation fixes, limit calculations --- GCodeAnalyzer.py | 5 +++-- gcoder.py | 2 +- printcore.py | 46 ++++++++++++++++++++++++---------------------- pronterface.py | 11 +++++++---- 4 files changed, 35 insertions(+), 29 deletions(-) diff --git a/GCodeAnalyzer.py b/GCodeAnalyzer.py index f0f8c12..0332701 100644 --- a/GCodeAnalyzer.py +++ b/GCodeAnalyzer.py @@ -68,7 +68,7 @@ class GCodeAnalyzer(): # find a code in a gstring line def findCode(self, gcode, codeStr): - pattern = re.compile(codeStr + "\\s*([\d.-]*)",re.I) + pattern = re.compile(codeStr + "\\s*(-?[\d.]*)",re.I) m=re.search(pattern, gcode) if m == None: return None @@ -76,7 +76,8 @@ class GCodeAnalyzer(): return m.group(1) def Analyze(self, gcode): - gcode = gcode[:gcode.find(";")] # remove comments + gcode = gcode[:gcode.find(";")].lstrip() # remove comments + if gcode.startswith("@"): return # code is a host command code_g = self.findCode(gcode, "G") code_m = self.findCode(gcode, "M") # we have a g_code diff --git a/gcoder.py b/gcoder.py index a62efb8..e2182e8 100755 --- a/gcoder.py +++ b/gcoder.py @@ -31,7 +31,7 @@ class Line(object): self.relative = False #ignore host commands - if "@" in self.raw: + if self.raw.startswith("@"): self.raw = "" if ";" in self.raw: diff --git a/printcore.py b/printcore.py index 02c5361..fa01258 100755 --- a/printcore.py +++ b/printcore.py @@ -229,16 +229,16 @@ class printcore(): if filename == None: return f = None try: - f = open(filename) + f = open(filename) except: - pass - - if f != None: - for i in f: - l = i.replace("\n", "") - l = l[:l.find(";")] #remove comment - self.send_now(l) - f.close() + pass + + if f != None: + for i in f: + l = i.replace("\n", "") + l = l[:l.find(";")] #remove comment + self.send_now(l) + f.close() def pause(self): """Pauses the print, saving the current position. @@ -249,9 +249,10 @@ class printcore(): # try joining the print thread: enclose it in try/except because we might be calling it from the thread itself try: - self.print_thread.join() - except: pass - + self.print_thread.join() + except: + pass + self.print_thread = None # saves the status @@ -349,11 +350,12 @@ class printcore(): #now only "pause" is implemented as host command def processHostCommand(self, command): + command = command.lstrip() if command == "@pause": - if self.pronterface != None: - self.pronterface.pause(None) - else: - self.pause() + if self.pronterface != None: + self.pronterface.pause(None) + else: + self.pause() def _sendnext(self): if not self.printer: @@ -376,12 +378,12 @@ class printcore(): if self.printing and self.queueindex < len(self.mainqueue): tline = self.mainqueue[self.queueindex] #check for host command - if tline.startswith("@"): - #it is a host command: pop it from the list - self.mainqueue.pop(self.queueindex) - self.processHostCommand(tline) - return - + if tline.lstrip().startswith("@"): + #it is a host command: pop it from the list + self.mainqueue.pop(self.queueindex) + self.processHostCommand(tline) + return + tline = tline.split(";")[0] if len(tline) > 0: self._send(tline, self.lineno, True) diff --git a/pronterface.py b/pronterface.py index 82c84a6..4a84772 100755 --- a/pronterface.py +++ b/pronterface.py @@ -134,14 +134,17 @@ class PronterWindow(MainWindow, pronsole.pronsole): self.build_dimensions_list = self.get_build_dimensions(self.settings.build_dimensions) #initialize the code analyzer with the correct sizes. There must be a more general way to do so - self.p.analyzer.maxX = self.build_dimensions_list[0] if self.build_dimensions_list[0] >= self.build_dimensions_list[6] else self.build_dimensions_list[6] # maximum x is maximum x if maximum X > home X, else it is home X - self.p.analyzer.maxY = self.build_dimensions_list[1] if self.build_dimensions_list[1] >= self.build_dimensions_list[7] else self.build_dimensions_list[7] - self.p.analyzer.maxZ = self.build_dimensions_list[2] if self.build_dimensions_list[2] >= self.build_dimensions_list[8] else self.build_dimensions_list[8] - + + # minimum = offset self.p.analyzer.minX = self.build_dimensions_list[3] self.p.analyzer.minY = self.build_dimensions_list[4] self.p.analyzer.minZ = self.build_dimensions_list[5] + #max = offset + bedsize + self.p.analyzer.maxX = self.build_dimensions_list[3] + self.build_dimensions_list[0] + self.p.analyzer.maxY = self.build_dimensions_list[4] + self.build_dimensions_list[1] + self.p.analyzer.maxZ = self.build_dimensions_list[5] + self.build_dimensions_list[2] + self.p.analyzer.homeX = self.build_dimensions_list[6] self.p.analyzer.homeY = self.build_dimensions_list[7] self.p.analyzer.homeZ = self.build_dimensions_list[8] From a6abdbb74f6bd202ebac273f0824ef58377ae4b2 Mon Sep 17 00:00:00 2001 From: fsantini Date: Mon, 8 Apr 2013 18:49:33 +0200 Subject: [PATCH 8/9] Host commands start with ;@ --- gcoder.py | 4 ---- printcore.py | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/gcoder.py b/gcoder.py index e2182e8..79c95bc 100755 --- a/gcoder.py +++ b/gcoder.py @@ -30,10 +30,6 @@ class Line(object): self.imperial = False self.relative = False - #ignore host commands - if self.raw.startswith("@"): - self.raw = "" - if ";" in self.raw: self.raw = self.raw.split(";")[0] diff --git a/printcore.py b/printcore.py index fa01258..b6d0ea9 100755 --- a/printcore.py +++ b/printcore.py @@ -351,7 +351,7 @@ class printcore(): #now only "pause" is implemented as host command def processHostCommand(self, command): command = command.lstrip() - if command == "@pause": + if command.startswith(";@pause"): if self.pronterface != None: self.pronterface.pause(None) else: @@ -378,11 +378,11 @@ class printcore(): if self.printing and self.queueindex < len(self.mainqueue): tline = self.mainqueue[self.queueindex] #check for host command - if tline.lstrip().startswith("@"): + if tline.lstrip().startswith(";@"): #it is a host command: pop it from the list self.mainqueue.pop(self.queueindex) self.processHostCommand(tline) - return + return tline = tline.split(";")[0] if len(tline) > 0: From 025a5a7bd6c0a97ca46fdac00c2c39850bb94731 Mon Sep 17 00:00:00 2001 From: fsantini Date: Mon, 8 Apr 2013 19:13:30 +0200 Subject: [PATCH 9/9] Fix exception with join thread in print --- printcore.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/printcore.py b/printcore.py index d677803..acc981d 100755 --- a/printcore.py +++ b/printcore.py @@ -344,7 +344,9 @@ class printcore(): self.sentlines = {} self.log = [] self.sent = [] - self.print_thread.join() + try: + self.print_thread.join() + except: pass self.print_thread = None if self.endcb: #callback for printing done