Commit 91622f84 authored by D1plo1d's avatar D1plo1d

Merge branch 'master' of github.com:kliment/Printrun

parents 007cb0a1 19179d50
......@@ -20,7 +20,7 @@ from select import error as SelectError
from threading import Thread, Lock
from Queue import Queue, Empty as QueueEmpty
import time, getopt, sys
import platform, os, traceback
import platform, os, traceback, errno
import socket
import re
from functools import wraps
......@@ -94,7 +94,8 @@ class printcore():
self.xy_feedrate = None
self.z_feedrate = None
self.pronterface = None
@locked
def disconnect(self):
"""Disconnects from printer and pauses the print
"""
......@@ -111,6 +112,8 @@ class printcore():
self.printer.close()
except socket.error:
pass
except OSError:
pass
self.printer = None
self.online = False
self.printing = False
......@@ -208,6 +211,8 @@ class printcore():
print "Can't read from printer (disconnected?) (Socket error {0}): {1}".format(e.errno, e.strerror)
return None
except OSError as e:
if e.errno == errno.EAGAIN: # Not a real error, no data was available
return ""
print "Can't read from printer (disconnected?) (OS Error {0}): {1}".format(e.errno, e.strerror)
return None
......@@ -325,11 +330,12 @@ class printcore():
if not gcode.lines:
return True
self.clear = False
self.print_thread = Thread(target = self._print)
resuming = (startindex != 0)
self.print_thread = Thread(target = self._print, kwargs = {"resuming": resuming})
self.print_thread.start()
return True
# run a simple script if it exists, no multithreading
# run a simple script if it exists, no multithreading
def runSmallScript(self, filename):
if filename == None: return
f = None
......@@ -344,22 +350,22 @@ class printcore():
l = l[:l.find(";")] #remove comment
self.send_now(l)
f.close()
def pause(self):
"""Pauses the print, saving the current position.
"""
if not self.printing: return False
self.paused = True
self.printing = False
# 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 = self.analyzer.x-self.analyzer.xOffset;
self.pauseY = self.analyzer.y-self.analyzer.yOffset;
......@@ -375,7 +381,7 @@ class printcore():
if self.paused:
#restores the status
self.send_now("G90") # go to absolute coordinates
xyFeedString = ""
zFeedString = ""
if self.xy_feedrate != None: xyFeedString = " F" + str(self.xy_feedrate)
......@@ -384,11 +390,11 @@ class printcore():
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_now("G91") # go back to relative if needed
#reset old feed rate
self.send_now("G1 F" + str(self.pauseF))
self.paused = False
self.printing = True
self.print_thread = Thread(target = self._print, kwargs = {"resuming": True})
......@@ -449,7 +455,7 @@ class printcore():
self.pronterface.pause(None)
else:
self.pause()
def _sendnext(self):
if not self.printer:
return
......@@ -493,7 +499,7 @@ class printcore():
self.queueindex += 1
self.clear = True
return
tline = tline.split(";")[0]
if len(tline) > 0:
self._send(tline, self.lineno, True)
......
......@@ -32,6 +32,9 @@ from .gl.panel import wxGLPanel
from .gl.trackball import trackball, mulquat, build_rotmatrix
from .gl.libtatlin import actors
from printrun_utils import imagefile, install_locale
install_locale('pronterface')
class GcodeViewPanel(wxGLPanel):
def __init__(self, parent, id = wx.ID_ANY, build_dimensions = None, realparent = None):
......@@ -189,6 +192,7 @@ class GcodeViewPanel(wxGLPanel):
def fit(self):
if not self.parent.model or not self.parent.model.loaded:
return
self.canvas.SetCurrent(self.context)
dims = self.parent.model.dims
self.reset_mview(1.0)
center_x = (dims[0][0] + dims[0][1]) / 2
......@@ -199,6 +203,7 @@ class GcodeViewPanel(wxGLPanel):
ratio = float(self.dist) / max(dims[0][2], dims[1][2])
glScalef(ratio, ratio, 1)
glTranslatef(center_x, center_y, 0)
wx.CallAfter(self.Refresh)
def keypress(self, event):
"""gets keypress events and moves/rotates acive shape"""
......@@ -219,9 +224,9 @@ class GcodeViewPanel(wxGLPanel):
self.layerdown()
x, y, _ = self.mouse_to_3d(self.width / 2, self.height / 2)
if key in kzi:
self.zoom(step, (x, y))
self.zoom_to_center(step)
if key in kzo:
self.zoom(1 / step, (x, y))
self.zoom_to_center(1 / step)
if key in kfit:
self.fit()
if key in kshowcurrent:
......@@ -229,9 +234,13 @@ class GcodeViewPanel(wxGLPanel):
return
self.parent.model.only_current = not self.parent.model.only_current
if key in kreset:
self.reset_mview(0.9)
self.basequat = [0, 0, 0, 1]
self.resetview()
event.Skip()
def resetview(self):
self.canvas.SetCurrent(self.context)
self.reset_mview(0.9)
self.basequat = [0, 0, 0, 1]
wx.CallAfter(self.Refresh)
class GCObject(object):
......@@ -300,7 +309,30 @@ class GcodeViewFrame(wx.Frame):
else:
self.model = None
self.objects = [GCObject(self.platform), GCObject(None)]
self.glpanel = GcodeViewPanel(self, build_dimensions = build_dimensions)
panel = wx.Panel(self, -1)
self.glpanel = GcodeViewPanel(panel, build_dimensions = build_dimensions,
realparent = self)
vbox = wx.BoxSizer(wx.VERTICAL)
toolbar = wx.ToolBar(panel, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_HORZ_TEXT)
toolbar.AddSimpleTool(1, wx.Image(imagefile('zoom_in.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom In [+]"), '')
toolbar.AddSimpleTool(2, wx.Image(imagefile('zoom_out.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom Out [-]"), '')
toolbar.AddSeparator()
toolbar.AddSimpleTool(3, wx.Image(imagefile('arrow_up.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Up a Layer [U]"), '')
toolbar.AddSimpleTool(4, wx.Image(imagefile('arrow_down.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Down a Layer [D]"), '')
toolbar.AddLabelTool(5, " " + _("Reset view"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset view [R]"), longHelp = '')
toolbar.AddLabelTool(6, " " + _("Fit to plate"), wx.Image(imagefile('fit.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Fit to plate [F]"), longHelp = '')
toolbar.Realize()
self.toolbar = toolbar
vbox.Add(toolbar, 0, border = 5)
vbox.Add(self.glpanel, 1, wx.EXPAND)
panel.SetSizer(vbox)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1.2), id = 1)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1/1.2), id = 2)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerup(), id = 3)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerdown(), id = 4)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.resetview(), id = 5)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.fit(), id = 6)
def set_current_gline(self, gline):
if gline.is_move and self.model and self.model.loaded:
......
......@@ -199,3 +199,8 @@ class wxGLPanel(wx.Panel):
if to:
glTranslatef(-delta_x, -delta_y, 0)
wx.CallAfter(self.Refresh)
def zoom_to_center(self, factor):
self.canvas.SetCurrent(self.context)
x, y, _ = self.mouse_to_3d(self.width / 2, self.height / 2)
self.zoom(factor, (x, y))
......@@ -44,6 +44,15 @@ def make_sized_button(*args):
def make_autosize_button(*args):
return make_button(*args, size = (-1, buttonSize[1]), style = wx.BU_EXACTFIT)
def make_custom_button(root, parentpanel, i):
btn = make_button(parentpanel, i.label, root.procbutton, i.tooltip)
btn.SetBackgroundColour(i.background)
btn.SetForegroundColour("black")
btn.properties = i
root.btndict[i.command] = btn
root.printerControls.append(btn)
return btn
class XYZControlsSizer(wx.GridBagSizer):
def __init__(self, root, parentpanel = None):
......@@ -67,12 +76,12 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
self.Add(root.monitorbox, pos = (base_line + 1, 5))
root.monitorbox.Bind(wx.EVT_CHECKBOX, root.setmonitor)
self.Add(wx.StaticText(parentpanel,-1, _("Heat:")), pos = (base_line + 0, 0), span = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
self.Add(wx.StaticText(parentpanel,-1, _("Heat:")), pos = (base_line + 0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
htemp_choices = [root.temps[i]+" ("+i+")" for i in sorted(root.temps.keys(), key = lambda x:root.temps[x])]
root.settoff = make_button(parentpanel, _("Off"), lambda e: root.do_settemp("off"), _("Switch Hotend Off"), size = (36,-1), style = wx.BU_EXACTFIT)
root.settoff = make_button(parentpanel, _("Off"), lambda e: root.do_settemp("off"), _("Switch Hotend Off"), size = (38,-1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.settoff)
self.Add(root.settoff, pos = (base_line + 0, 1), span = (1, 1))
self.Add(root.settoff, pos = (base_line + 0, 2), span = (1, 1))
if root.settings.last_temperature not in map(float, root.temps.values()):
htemp_choices = [str(root.settings.last_temperature)] + htemp_choices
......@@ -81,17 +90,17 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
root.htemp.SetToolTip(wx.ToolTip("Select Temperature for Hotend"))
root.htemp.Bind(wx.EVT_COMBOBOX, root.htemp_change)
self.Add(root.htemp, pos = (base_line + 0, 2), span = (1, 2))
self.Add(root.htemp, pos = (base_line + 0, 3), span = (1, 1))
root.settbtn = make_button(parentpanel, _("Set"), root.do_settemp, _("Switch Hotend On"), size = (38, -1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.settbtn)
self.Add(root.settbtn, pos = (base_line + 0, 4), span = (1, 1))
self.Add(wx.StaticText(parentpanel,-1, _("Bed:")), pos = (base_line + 1, 0), span = (1, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
self.Add(wx.StaticText(parentpanel,-1, _("Bed:")), pos = (base_line + 1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
btemp_choices = [root.bedtemps[i]+" ("+i+")" for i in sorted(root.bedtemps.keys(), key = lambda x:root.temps[x])]
root.setboff = make_button(parentpanel, _("Off"), lambda e:root.do_bedtemp("off"), _("Switch Heated Bed Off"), size = (36,-1), style = wx.BU_EXACTFIT)
root.setboff = make_button(parentpanel, _("Off"), lambda e:root.do_bedtemp("off"), _("Switch Heated Bed Off"), size = (38,-1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.setboff)
self.Add(root.setboff, pos = (base_line + 1, 1), span = (1, 1))
self.Add(root.setboff, pos = (base_line + 1, 2), span = (1, 1))
if root.settings.last_bed_temperature not in map(float, root.bedtemps.values()):
btemp_choices = [str(root.settings.last_bed_temperature)] + btemp_choices
......@@ -99,7 +108,7 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
choices = btemp_choices, style = wx.CB_DROPDOWN, size = (80,-1))
root.btemp.SetToolTip(wx.ToolTip("Select Temperature for Heated Bed"))
root.btemp.Bind(wx.EVT_COMBOBOX, root.btemp_change)
self.Add(root.btemp, pos = (base_line + 1, 2), span = (1, 2))
self.Add(root.btemp, pos = (base_line + 1, 3), span = (1, 1))
root.setbbtn = make_button(parentpanel, _("Set"), root.do_bedtemp, ("Switch Heated Bed On"), size = (38, -1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.setbbtn)
......@@ -125,21 +134,31 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
root.htemp.SetValue(root.htemp.Value + ' (user)')
root.tempdisp = wx.StaticText(parentpanel,-1, "")
root.edist = wx.SpinCtrl(parentpanel,-1, "5", min = 0, max = 1000, size = (70,-1))
if not extra_buttons:
ebuttonspanel = root.newPanel(parentpanel)
ebuttonssizer = wx.BoxSizer(wx.HORIZONTAL)
ebuttonspanel.SetSizer(ebuttonssizer)
self.Add(ebuttonspanel, pos = (base_line + 2, 0), span = (1, 5), flag = wx.EXPAND)
esettingspanel = root.newPanel(parentpanel)
esettingssizer = wx.BoxSizer(wx.HORIZONTAL)
root.edist = wx.SpinCtrl(esettingspanel,-1, "5", min = 0, max = 1000, size = (70,-1))
root.edist.SetBackgroundColour((225, 200, 200))
root.edist.SetForegroundColour("black")
self.Add(root.edist, pos = (base_line + 3, 0), span = (1, 1), flag = wx.EXPAND | wx.RIGHT, border = 5)
self.Add(wx.StaticText(parentpanel, -1, _("mm")), pos = (base_line + 3, 1), span = (1, 1))
esettingssizer.Add(root.edist, flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
esettingssizer.Add(wx.StaticText(esettingspanel, -1, _("mm @")), flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
root.edist.SetToolTip(wx.ToolTip("Amount to Extrude or Retract (mm)"))
root.efeedc = wx.SpinCtrl(parentpanel,-1, str(root.settings.e_feedrate), min = 0, max = 50000, size = (70,-1))
root.efeedc = wx.SpinCtrl(esettingspanel,-1, str(root.settings.e_feedrate), min = 0, max = 50000, size = (70,-1))
root.efeedc.SetToolTip(wx.ToolTip("Extrude / Retract speed (mm/min)"))
root.efeedc.SetBackgroundColour((225, 200, 200))
root.efeedc.SetForegroundColour("black")
root.efeedc.Bind(wx.EVT_SPINCTRL, root.setfeeds)
root.efeedc.Bind(wx.EVT_TEXT, root.setfeeds)
self.Add(root.efeedc, pos = (base_line + 3, 2), span = (1, 2), flag = wx.EXPAND | wx.RIGHT, border = 5)
self.Add(wx.StaticText(parentpanel, -1, _("mm/\nmin")), pos = (base_line + 3, 4), span = (2, 1))
esettingssizer.Add(root.efeedc, flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
esettingssizer.Add(wx.StaticText(esettingspanel, -1, _("mm/\nmin")), flag = wx.ALIGN_CENTER)
esettingspanel.SetSizer(esettingssizer)
self.Add(esettingspanel, pos = (base_line + 3, 0), span = (1, 5))
gauges_base_line = base_line + 8 if standalone_mode else base_line + 5
if root.display_gauges:
......@@ -187,6 +206,12 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
for i in extra_buttons:
btn = extra_buttons[i]
self.Add(btn, pos = pos_mapping[i.pos], span = span_mapping[i.pos], flag = wx.EXPAND)
else:
for i in root.cpbuttons:
if not i.pos or i.pos[0] != 4:
continue
btn = make_custom_button(root, ebuttonspanel, i)
ebuttonssizer.Add(btn, 1, flag = wx.EXPAND)
class LeftPane(wx.GridBagSizer):
......@@ -199,13 +224,11 @@ class LeftPane(wx.GridBagSizer):
self.Add(self.xyzsizer, pos = (1, 0), span = (1, 6), flag = wx.ALIGN_CENTER)
self.extra_buttons = {}
ebuttons = []
for i in root.cpbuttons:
btn = make_button(parentpanel, i.label, root.procbutton, i.tooltip)
btn.SetBackgroundColour(i.background)
btn.SetForegroundColour("black")
btn.properties = i
root.btndict[i.command] = btn
root.printerControls.append(btn)
if not standalone_mode and i.pos and i.pos[0] == 4:
continue
btn = make_custom_button(root, parentpanel, i)
if i.pos == None:
if i.span == 0:
llts.Add(btn)
......@@ -350,13 +373,13 @@ def MainToolbar(root, parentpanel = None, use_wrapsizer = False):
root.resetbtn = make_autosize_button(parentpanel, _("Reset"), root.reset, _("Reset the printer"), self)
root.loadbtn = make_autosize_button(parentpanel, _("Load file"), root.loadfile, _("Load a 3D model file"), self)
root.platebtn = make_autosize_button(parentpanel, _("Compose"), root.plate, _("Simple Plater System"), self)
root.sdbtn = make_autosize_button(parentpanel, _("SD"), root.sdmenu, _("SD Card Printing"), self)
root.printerControls.append(root.sdbtn)
root.printbtn = make_sized_button(parentpanel, _("Print"), root.printfile, _("Start Printing Loaded File"), self)
root.printbtn.Disable()
root.pausebtn = make_sized_button(parentpanel, _("Pause"), root.pause, _("Pause Current Print"), self)
root.recoverbtn = make_sized_button(parentpanel, _("Recover"), root.recover, _("Recover previous Print"), self)
root.offbtn = make_sized_button(parentpanel, _("Off"), root.off, _("Turn printer off"), self)
root.printerControls.append(root.offbtn)
return self
class MainWindow(wx.Frame):
......
......@@ -27,6 +27,7 @@ import pyglet
pyglet.options['debug_gl'] = True
from pyglet.gl import *
from pyglet import gl
from .gl.panel import wxGLPanel
from .gl.trackball import trackball, mulquat, build_rotmatrix
......
......@@ -911,6 +911,9 @@ class pronsole(cmd.Cmd):
def help_pause(self):
self.log(_("Pauses a running print"))
def pause(self, event):
return self.do_pause(None)
def do_resume(self, l):
if not self.paused:
self.logError(_("Not paused, unable to resume. Start a print first."))
......@@ -1417,6 +1420,23 @@ class pronsole(cmd.Cmd):
self.log(_("home e - set extruder position to zero (Using G92)"))
self.log(_("home xyze - homes all axes and zeroes the extruder (Using G28 and G92)"))
def do_off(self, l):
self.off()
def off(self):
if self.p.online:
if self.p.printing: self.pause(None)
self.onecmd("M84; motors off")
self.onecmd("M104 S0; extruder off")
self.onecmd("M140 S0; heatbed off")
self.onecmd("M107; fan off")
self.onecmd("M81; power supply off")
else:
self.logError(_("Printer is not online. Unable to turn it off."))
def help_off(self):
self.log(_("Turns off everything on the printer"))
def add_cmdline_arguments(self, parser):
parser.add_argument('-c','--conf','--config', help = _("load this file on startup instead of .pronsolerc ; you may chain config files, if so settings auto-save will use the last specified file"), action = "append", default = [])
parser.add_argument('-e','--execute', help = _("executes command after configuration/.pronsolerc is loaded ; macros/settings from these commands are not autosaved"), action = "append", default = [])
......
......@@ -579,12 +579,22 @@ class PronterWindow(MainWindow, pronsole.pronsole):
# File menu
m = wx.Menu()
self.Bind(wx.EVT_MENU, self.loadfile, m.Append(-1, _("&Open..."), _(" Opens file")))
self.Bind(wx.EVT_MENU, self.do_editgcode, m.Append(-1, _("&Edit..."), _(" Edit open file")))
self.Bind(wx.EVT_MENU, self.clearOutput, m.Append(-1, _("Clear console"), _(" Clear output console")))
self.Bind(wx.EVT_MENU, self.exclude, m.Append(-1, _("Excluder"), _(" Exclude parts of the bed from being printed")))
self.Bind(wx.EVT_MENU, self.project, m.Append(-1, _("Projector"), _(" Project slices")))
self.Bind(wx.EVT_MENU, self.OnExit, m.Append(wx.ID_EXIT, _("E&xit"), _(" Closes the Window")))
self.menustrip.Append(m, _("&File"))
m = wx.Menu()
self.Bind(wx.EVT_MENU, self.do_editgcode, m.Append(-1, _("&Edit..."), _(" Edit open file")))
self.Bind(wx.EVT_MENU, self.plate, m.Append(-1, _("Plater"), _(" Compose 3D models into a single plate")))
self.Bind(wx.EVT_MENU, self.exclude, m.Append(-1, _("Excluder"), _(" Exclude parts of the bed from being printed")))
self.Bind(wx.EVT_MENU, self.project, m.Append(-1, _("Projector"), _(" Project slices")))
self.menustrip.Append(m, _("&Tools"))
m = wx.Menu()
self.recoverbtn = m.Append(-1, _("Recover"), _(" Recover previous print after a disconnect (homes X, Y, restores Z and E status)"))
self.recoverbtn.Disable = lambda *a: self.recoverbtn.Enable(False)
self.Bind(wx.EVT_MENU, self.recover, self.recoverbtn)
self.menustrip.Append(m, _("&Advanced"))
# Settings menu
m = wx.Menu()
......@@ -1127,9 +1137,9 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.xyb.repeatLast()
def parseusercmd(self, line):
if line.startswith("M114"):
if line.upper().startswith("M114"):
self.userm114 += 1
elif line.startswith("M105"):
elif line.upper().startswith("M105"):
self.userm105 += 1
def procbutton(self, e):
......@@ -1307,10 +1317,19 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.p.send_now("M27")
self.p.send_now("M105")
cur_time = time.time()
while time.time() < cur_time + self.monitor_interval:
wait_time = 0
while time.time() < cur_time + self.monitor_interval - 0.25:
if not self.statuscheck:
break
time.sleep(0.25)
# Safeguard: if system time changes and goes back in the past,
# we could get stuck almost forever
wait_time += 0.25
if wait_time > self.monitor_interval - 0.25:
break
# Always sleep at least a bit, if something goes wrong with the
# system time we'll avoid freezing the whole app this way
time.sleep(0.25)
try:
while not self.sentlines.empty():
gc = self.sentlines.get_nowait()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment