class GCodeDlg(wx.Frame): def __init__(self, parent, server, gcode, filenm, pname, settings, images, cbexit): wx.Frame.__init__(self, None, wx.ID_ANY, self.formatTitle(pname, filenm)) self.SetBackgroundColour("white") self.Bind(wx.EVT_CLOSE, self.onClose) self.parent = parent self.server = server self.gcode = gcode self.filenm = filenm self.pname = pname self.settings = settings self.images = images self.exitDlg = cbexit self.nExtr = self.parent.nExtr self.layerCount = 0 if self.gcode: self.sTotalTime = " / " + formatElapsed(self.gcode.getPrintTime()) self.filament = self.gcode.getFilament() else: self.sTotalTime = "" self.filament = [[0.0, 0.0]] self.printPosition = 0 self.followPrint = True self.lx = 0 lbFont = wx.Font(10, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) self.gcf = GcFrame(self, self.pname, self.gcode, self.settings) self.stHeight = wx.StaticText(self, wx.ID_ANY, "") self.stHeight.SetFont(lbFont) self.stTime = wx.StaticText(self, wx.ID_ANY, "") self.stTime.SetFont(lbFont) self.stFilament = wx.StaticText(self, wx.ID_ANY, "") self.stFilament.SetFont(lbFont) self.slLayer = wx.Slider(self, wx.ID_ANY, 1, 1, 10, style=wx.SL_VERTICAL+wx.SL_LABELS+wx.SL_INVERSE) self.Bind(wx.EVT_SLIDER, self.onSlLayer, self.slLayer) self.bUp = wx.BitmapButton(self, wx.ID_ANY, self.images.pngUp, size=BTNDIM, style=wx.NO_BORDER) self.bUp.SetBackgroundColour("white") self.Bind(wx.EVT_BUTTON, self.onBUp, self.bUp) self.bDown = wx.BitmapButton(self, wx.ID_ANY, self.images.pngDown, size=BTNDIM, style=wx.NO_BORDER) self.bDown.SetBackgroundColour("white") self.Bind(wx.EVT_BUTTON, self.onBDown, self.bDown) self.setSliderRange() self.cbSync = wx.CheckBox(self, wx.ID_ANY, "Sync with print") self.cbSync.SetValue(True) self.Bind(wx.EVT_CHECKBOX, self.onCbSync, self.cbSync) self.cbPrintedOnly = wx.CheckBox(self, wx.ID_ANY, "Only show printed") self.cbPrintedOnly.SetValue(self.settings.getSetting("showprintedonly", self.pname, "False")) self.Bind(wx.EVT_CHECKBOX, self.onCbShowPrintedOnly, self.cbPrintedOnly) self.cbShowPrev = wx.CheckBox(self, wx.ID_ANY, "Show previous layer") self.cbShowPrev.SetValue(self.settings.getSetting("showprevious", self.pname, "False")) self.Bind(wx.EVT_CHECKBOX, self.onCbShowPrev, self.cbShowPrev) self.cbShowMoves = wx.CheckBox(self, wx.ID_ANY, "Show moves") self.cbShowMoves.SetValue(self.settings.getSetting("showmoves", self.pname, "False")) self.Bind(wx.EVT_CHECKBOX, self.onCbShowMoves, self.cbShowMoves) self.cbShowRetr = wx.CheckBox(self, wx.ID_ANY, "Show retractions") self.cbShowRetr.SetValue(self.settings.getSetting("showretractions", self.pname, "False")) self.Bind(wx.EVT_CHECKBOX, self.onCbShowRetr, self.cbShowRetr) self.cbShowRevRetr = wx.CheckBox(self, wx.ID_ANY, "Show reverse retractions") self.cbShowRevRetr.SetValue(self.settings.getSetting("showrevretractions", self.pname, "False")) self.Bind(wx.EVT_CHECKBOX, self.onCbShowRevRetr, self.cbShowRevRetr) sznavgc = wx.BoxSizer(wx.VERTICAL) sznavgc.Add(self.bUp, 0, wx.LEFT, 12 if os.name == 'posix' else 25) sznavgc.Add(self.slLayer, 1, wx.GROW) sznavgc.Add(self.bDown, 0, wx.LEFT, 12 if os.name == 'posix' else 25) szgcf = wx.BoxSizer(wx.VERTICAL) szgcf.Add(self.gcf) szgcf.AddSpacer(5) szgcf.Add(self.stHeight, 0, wx.ALIGN_CENTER) szgcf.AddSpacer(5) szgcf.Add(self.stTime, 0, wx.ALIGN_CENTER) szgcf.AddSpacer(5) szgcf.Add(self.stFilament, 0, wx.ALIGN_CENTER) szgc = wx.BoxSizer(wx.HORIZONTAL) szgc.AddSpacer(15) szgc.Add(szgcf) if os.name == 'posix': szgc.AddSpacer(10) szgc.Add(sznavgc, 1, wx.GROW) szgc.AddSpacer(15) szopt1 = wx.BoxSizer(wx.VERTICAL) szopt1.Add(self.cbSync, 1, wx.EXPAND) szopt1.Add(self.cbPrintedOnly, 1, wx.EXPAND) szopt2 = wx.BoxSizer(wx.VERTICAL) szopt2.Add(self.cbShowPrev, 1, wx.EXPAND) szopt2.Add(self.cbShowMoves, 1, wx.EXPAND) szopt3 = wx.BoxSizer(wx.VERTICAL) szopt3.Add(self.cbShowRetr, 1, wx.EXPAND) szopt3.Add(self.cbShowRevRetr, 1, wx.EXPAND) szoptions = wx.BoxSizer(wx.HORIZONTAL) szoptions.AddSpacer(20) szoptions.Add(szopt1, 1, wx.EXPAND) szoptions.AddSpacer(5) szoptions.Add(szopt2, 1, wx.EXPAND) szoptions.AddSpacer(5) szoptions.Add(szopt3, 1, wx.EXPAND) szoptions.AddSpacer(10) sz = wx.BoxSizer(wx.VERTICAL) sz.AddSpacer(10) sz.Add(szgc) sz.AddSpacer(5) sz.Add(szoptions) sz.AddSpacer(10) self.showLayerInfo() self.SetSizer(sz) self.Fit() self.Layout() @staticmethod def formatTitle(pname, filenm): if filenm is None: return "%s - GCode Monitor - (no file loaded)" % pname else: return "%s - GCode monitor - %s" % (pname, filenm) def reloadGCode(self, gcode, filenm): self.filenm = filenm self.SetTitle(self.formatTitle(self.pname, filenm)) self.gcode = gcode if self.gcode: self.sTotalTime = " / " + formatElapsed(self.gcode.getPrintTime()) self.filament = self.gcode.getFilament() else: self.sTotalTime = "" self.filament = 0.0 self.setSliderRange() # send new gcode to gcf self.printPosition = 0 self.gcf.loadGCode(gcode) self.showLayerInfo() def setSliderRange(self): n = self.gcode.layerCount() self.slLayer.SetRange(1, 10 if n == 0 else n) self.slLayer.SetValue(1) self.slLayer.Enable(n != 0) self.bUp.Enable(n != 0) self.bDown.Enable(n != 0) self.layerCount = n def setPrintPosition(self, pos): if pos is None: return False, None, None self.printPosition = 0 if pos is None else pos self.gcf.setPrintPosition(self.printPosition) pLayer, lpct = self.gcode.findLayerByOffset(self.printPosition) cLayer = self.gcf.getCurrentLayerNum() if not self.followPrint: return cLayer != pLayer, pLayer, lpct if cLayer != pLayer: self.gcf.setLayer(pLayer) self.slLayer.SetValue(pLayer+1) self.showLayerInfo() return True, pLayer, lpct return False, pLayer, lpct def showLayerInfo(self): l = self.gcf.getCurrentLayer() if l is None: lblHt = "" lblTime = "" lblFilament = "" else: lx = self.gcf.getCurrentLayerNum() lblHt, lblTime, lblFilament = self.formatLayerInfo(l, lx) self.stHeight.SetLabel(lblHt) self.stTime.SetLabel(lblTime) self.stFilament.SetLabel(lblFilament) def formatLayerInfo(self, l, lx): sHt = "Height: {:.2f} Layer: {:d} / {:d}".format(l.getHeight(), lx+1, self.layerCount) sTm = " Print time: {:s}{:s}".format(formatElapsed(l.getLayerTime()), self.sTotalTime) o = l.getOffsets() if self.printPosition < o[0]: lyrs = self.gcode.getLayersBetweenOffsets(self.printPosition, o[0]) untilTime = 0.0 for ly in lyrs: untilTime += ly.getLayerTime() sTm += " ({:s} until)".format(formatElapsed(untilTime)) sFi = " Filament: " lf = l.getFilament() for i in range(self.nExtr): if i > 0: sFi += " / " if self.nExtr > 1: if i > 0: sFi += " - " sFi += "{:d}: ".format(i) sFi += "{:.2f}mm ({:.2f}cm3) / {:.2f}mm".format(lf[i][0], lf[i][1], self.filament[i][0]) return sHt, sTm, sFi def onSlLayer(self, _): self.followPrintOff() v = self.slLayer.GetValue()-1 self.gcf.setLayer(v) self.showLayerInfo() def onBUp(self, _): v = self.slLayer.GetValue() if v < self.gcode.layerCount(): self.followPrintOff() v += 1 self.slLayer.SetValue(v) self.gcf.setLayer(v-1) self.showLayerInfo() def onBDown(self, _): v = self.slLayer.GetValue() if v > 1: self.followPrintOff() v -= 1 self.slLayer.SetValue(v) self.gcf.setLayer(v-1) self.showLayerInfo() def followPrintOff(self): if self.followPrint: self.cbSync.SetValue(False) self.followPrint = False self.gcf.setFollowPrint(False) def onCbSync(self, _): self.followPrint = self.cbSync.GetValue() self.gcf.setFollowPrint(self.followPrint) def onCbShowPrintedOnly(self, _): v = self.cbPrintedOnly.GetValue() self.settings.setSetting("showprintedonly", str(v), self.pname) self.gcf.setShowPrintedOnly(v) def onCbShowPrev(self, _): v = self.cbShowPrev.GetValue() self.settings.setSetting("showprevious", str(v), self.pname) self.gcf.setShowPrevious(v) def onCbShowMoves(self, _): v = self.cbShowMoves.GetValue() self.settings.setSetting("showmoves", str(v), self.pname) self.gcf.setShowMoves(v) def onCbShowRetr(self, _): v = self.cbShowRetr.GetValue() self.settings.setSetting("showretractions", str(v), self.pname) self.gcf.setShowRetractions(v) def onCbShowRevRetr(self, _): v = self.cbShowRevRetr.GetValue() self.settings.setSetting("showrevretractions", str(v), self.pname) self.gcf.setShowRevRetractions(v) def onClose(self, _): self.exitDlg()
class PrintMonitorDlg(wx.Frame): def __init__(self, parent, wparent, reprap, prtName): self.parent = parent self.wparent = wparent self.log = self.parent.log self.history = wparent.history self.reprap = reprap self.settings = self.parent.settings self.images = self.parent.images self.state = PrintState.idle self.oldState = None self.gcodeLoaded = False self.gcodeFile = None self.printerName = prtName self.layerMap = [] self.okToImport = False self.importFile = None self.currentLayer = 0 self.maxTool = 0 self.eUsed = [0.0, 0.0, 0.0, 0.0] self.totalTime = 0 self.totalTimeStr = "" self.layerTimes = [] self.layerTimeStr = [] self.layerRange = (0, 0) self.gObj = None self.printLayer = 0 self.printPosition = None title = self.buildTitle() wx.Frame.__init__(self, wparent, wx.ID_ANY, title=title) self.Show() ico = wx.Icon(os.path.join(cmdFolder, "images", "printmon.png"), wx.BITMAP_TYPE_PNG) self.SetIcon(ico) if self.settings.hassdcard: self.sdcard = SDCard(self.parent, self, self.reprap, self.log) else: self.sdcard = None self.gcf = GcFrame(self, self.gObj, self.settings) self.stLayerText = wx.StaticText(self, wx.ID_ANY, "Layer Height: 0.00") ht = self.gcf.GetSize().Get()[1] - BUTTONDIM[1] * 2 - 20 self.slLayers = wx.Slider(self, wx.ID_ANY, 0, 0, 1000, size=(-1, ht), style=wx.SL_VERTICAL | wx.SL_AUTOTICKS | wx.SL_LABELS | wx.SL_INVERSE) self.Bind(wx.EVT_SCROLL, self.onLayerScroll, self.slLayers) self.slLayers.Enable(False) self.cbShowMoves = wx.CheckBox(self, wx.ID_ANY, "Show moves") self.cbShowMoves.SetValue(self.settings.showmoves) self.Bind(wx.EVT_CHECKBOX, self.onShowMoves, self.cbShowMoves) self.cbShowPrevious = wx.CheckBox(self, wx.ID_ANY, "Show previous layer") self.cbShowPrevious.SetValue(self.settings.showprevious) self.Bind(wx.EVT_CHECKBOX, self.onShowPrevious, self.cbShowPrevious) self.cbToolPathOnly = wx.CheckBox(self, wx.ID_ANY, "Show tool paths only") self.cbToolPathOnly.SetValue(self.settings.toolpathonly) self.Bind(wx.EVT_CHECKBOX, self.onToolPathOnly, self.cbToolPathOnly) self.cbSyncPrint = wx.CheckBox(self, wx.ID_ANY, "Sync with print") self.cbSyncPrint.SetValue(True) self.Bind(wx.EVT_CHECKBOX, self.onSyncPrint, self.cbSyncPrint) self.bImport = wx.BitmapButton(self, wx.ID_ANY, self.images.pngImport, size=BUTTONDIM) self.bImport.SetToolTip("Import G Code file from toolbox") self.Bind(wx.EVT_BUTTON, self.onImport, self.bImport) self.bImportQ = wx.BitmapButton(self, wx.ID_ANY, self.images.pngNext, size=BUTTONDIM) self.Bind(wx.EVT_BUTTON, self.onImportFromQueue, self.bImportQ) self.bOpen = wx.BitmapButton(self, wx.ID_ANY, self.images.pngFileopen, size=BUTTONDIM) self.bOpen.SetToolTip("Open a G Code file") self.Bind(wx.EVT_BUTTON, self.onOpenFile, self.bOpen) self.Bind(wx.EVT_CLOSE, self.onClose) self.bPrint = PrintButton(self, self.images) self.bPrint.Enable(False) self.Bind(wx.EVT_BUTTON, self.onPrint, self.bPrint) self.bPause = PauseButton(self, self.images) self.bPause.Enable(False) self.Bind(wx.EVT_BUTTON, self.onPause, self.bPause) self.bSdPrintTo = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintto, size=(BUTTONDIMWIDE)) self.bSdPrintTo.Enable(False) self.Bind(wx.EVT_BUTTON, self.onSdPrintTo, self.bSdPrintTo) self.bSdPrintFrom = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintfrom, size=(BUTTONDIMWIDE)) self.bSdPrintFrom.Enable(False) self.Bind(wx.EVT_BUTTON, self.onSdPrintFrom, self.bSdPrintFrom) self.bSdDelete = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSddelete, size=(BUTTONDIM)) self.bSdDelete.Enable(False) self.Bind(wx.EVT_BUTTON, self.onSdDelete, self.bSdDelete) self.bUp = wx.BitmapButton(self, wx.ID_ANY, self.images.pngUp, size=BUTTONDIM) self.bUp.SetToolTip("Move up one layer") self.Bind(wx.EVT_BUTTON, self.onUp, self.bUp) self.bUp.Enable(False) self.bDown = wx.BitmapButton(self, wx.ID_ANY, self.images.pngDown, size=BUTTONDIM) self.bDown.SetToolTip("Move down one layer") self.Bind(wx.EVT_BUTTON, self.onDown, self.bDown) self.bDown.Enable(False) szGcf = wx.BoxSizer(wx.HORIZONTAL) szGcf.AddSpacer(10) szGcf.Add(self.gcf) szGcf.Add(self.stLayerText, 1, wx.ALIGN_CENTER_HORIZONTAL, 1) szGcf.AddSpacer(10) szNav = wx.BoxSizer(wx.VERTICAL) szNav.Add(self.bUp, 1, wx.ALIGN_CENTER_HORIZONTAL, 1) szNav.AddSpacer(10) szNav.Add(self.slLayers) szNav.AddSpacer(10) szNav.Add(self.bDown, 1, wx.ALIGN_CENTER_HORIZONTAL, 1) szGcf.Add(szNav) szGcf.AddSpacer(10) szOpts = wx.BoxSizer(wx.HORIZONTAL) szOpts.AddSpacer(10) szOpts.Add(self.cbShowMoves) szOpts.AddSpacer(10) szOpts.Add(self.cbShowPrevious) szOpts.AddSpacer(10) szOpts.Add(self.cbToolPathOnly) szOpts.AddSpacer(10) szOpts.Add(self.cbSyncPrint) szOpts.AddSpacer(10) szBtn = wx.BoxSizer(wx.HORIZONTAL) szBtn.AddSpacer(10) szBtn.Add(self.bImport) szBtn.AddSpacer(10) szBtn.Add(self.bImportQ) szBtn.AddSpacer(10) szBtn.Add(self.bOpen) szBtn.AddSpacer(20) szBtn.Add(self.bPrint) szBtn.AddSpacer(10) szBtn.Add(self.bPause) if self.sdcard: szBtn.AddSpacer(20) szBtn.Add(self.bSdPrintTo) szBtn.AddSpacer(10) szBtn.Add(self.bSdPrintFrom) szBtn.AddSpacer(10) szBtn.Add(self.bSdDelete) szBtn.AddSpacer(10) szDlg = wx.BoxSizer(wx.VERTICAL) szDlg.AddSpacer(10) szDlg.Add(szGcf) szDlg.AddSpacer(10) szDlg.Add(szOpts) szDlg.AddSpacer(10) szDlg.Add(szBtn) szDlg.AddSpacer(10) self.SetSizer(szDlg) self.Fit() self.Layout() self.propDlg = PropertiesDlg(self, wparent, self.printerName) self.propDlg.Show() if not self.settings.propposition is None: self.propDlg.SetPosition(self.settings.propposition) self.enableButtonsByState() self.reprap.registerPositionHandler(self.updatePrintPosition) self.reprap.registerEventHandler(self.reprapEvent) self.reprap.registerSdEventHandler(self.sdcard) def show(self): self.Show() self.Raise() self.propDlg.Show() self.propDlg.Raise() def setLayerText(self, ht): if ht is None: htv = 0.0 else: htv = ht self.stLayerText.SetLabel("Layer Height: %0.3f" % htv) def getStatusReport(self): r = self.propDlg.getStatusReport() r["PrintStatus"] = PrintState.label[self.state] return r def buildTitle(self): t = "%s print monitor" % self.printerName if self.gcodeLoaded: if len(self.gcodeFile) > 45: t += " - %s" % os.path.basename(self.gcodeFile) else: t += " - %s" % self.gcodeFile return t def rememberPositions(self): self.settings.propposition = self.propDlg.GetPosition() def isPrinting(self): return self.state in [ PrintState.printing, PrintState.sdprintingto, PrintState.sdprintingfrom ] def onClose(self, evt): if self.isPrinting(): dlg = wx.MessageDialog(self, 'Cannot exit with printing active', "Printer is active", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() return self.terminate() def terminate(self): self.reprap.registerPositionHandler(None) self.reprap.registerEventHandler(None) self.parent.closePrintMon() self.propDlg.Destroy() self.Destroy() def onShowMoves(self, evt): v = self.cbShowMoves.GetValue() self.settings.showmoves = v self.gcf.setShowMoves(v) def onShowPrevious(self, evt): v = self.cbShowPrevious.GetValue() self.settings.showprevious = v self.gcf.setShowPrevious(v) def onToolPathOnly(self, evt): v = self.cbToolPathOnly.GetValue() self.settings.toolpathonly = v self.gcf.setToolPathsOnly(v) def onSyncPrint(self, evt): v = self.cbSyncPrint.GetValue() self.gcf.setSyncWithPrint(v) def onLayerScroll(self, evt): v = self.slLayers.GetValue() if v == self.currentLayer: return self.gcf.setLayer(v) self.changeLayer(v) def onUp(self, evt): lmax = self.slLayers.GetRange()[1] if self.currentLayer >= lmax: return v = self.currentLayer + 1 self.gcf.setLayer(v) self.changeLayer(v) def onDown(self, evt): if self.currentLayer <= 0: return v = self.currentLayer - 1 self.gcf.setLayer(v) self.changeLayer(v) def onImport(self, evt): fn = self.wparent.importGcFile() if fn is None: return self.loadGFile(fn) def onImportFromQueue(self, evt): fn = self.wparent.importGcFromQueue() if fn is None: return self.loadGFile(fn) def setImportButton(self, msg): if msg is None: self.okToImport = False self.bImportQ.SetToolTip("") self.bImportQ.Enable(False) else: self.okToImport = True self.bImportQ.SetToolTip(msg) self.bImportQ.Enable(self.bOpen.IsEnabled()) def setImportFile(self, fn): self.importFile = fn if fn is None: self.bImport.Enable(False) self.bImport.SetToolTip("") else: self.bImport.Enable(self.bOpen.IsEnabled()) self.bImport.SetToolTip("Import G Code file (%s)" % fn) def onOpenFile(self, evt): wildcard = "GCode (*.gcode)|*.gcode;*.GCODE|" \ "All files (*.*)|*.*" dlg = wx.FileDialog(self, message="Choose a GCode file", defaultDir=self.settings.lastdirectory, defaultFile="", wildcard=wildcard, style=wx.FD_OPEN) rc = dlg.ShowModal() if rc == wx.ID_OK: path = dlg.GetPath().encode('ascii', 'ignore') dlg.Destroy() if rc != wx.ID_OK: return self.loadGFile(path) def loadGFile(self, path): self.settings.lastdirectory = os.path.dirname(path) self.loadGCode(path) if self.gObj is None: lmax = 1 self.slLayers.Enable(False) self.bUp.Enable(False) self.bDown.Enable(False) else: lmax = self.gObj.layerCount() - 1 self.slLayers.Enable(True) self.bUp.Enable(True) self.bDown.Enable(True) self.slLayers.SetRange(0, lmax) self.slLayers.SetPageSize(int(lmax / 10)) self.gcf.loadModel(self.gObj) self.changeLayer(0) self.state = PrintState.idle self.oldState = None self.enableButtonsByState() t = self.buildTitle() self.SetTitle(t) self.propDlg.setPrintStatus(PrintState.idle) def loadGCode(self, fn): def gnormal(s): if ";" in s: return s.split(";")[0].rstrip() else: return s.rstrip() self.gcodeFile = None self.gcodeLoaded = False self.gcode = [] self.gObj = None self.maxLine = 0 self.totalTime = 0 self.totalTimeStr = "" self.layerTimes = [] self.layerTimeStr = [] self.propDlg.clearAllProperties() self.reprap.clearPrint() if fn is None: return try: gc = list(open(fn)) except: self.log("Error opening file %s" % fn) self.gcode = [] self.gObj = None self.gcodeLoaded = False return self.gcode = [s for s in map(gnormal, gc) if s.strip() != ""] self.gObj = self.buildModel() self.maxLine = self.gObj.getMaxLine() self.eUsed = self.gObj.getFilament() self.gcodeLoaded = True self.gcodeFile = pfn = fn if len(pfn) > 45: pfn = os.path.basename(fn) self.propDlg.setProperty(PropertyEnum.fileName, pfn) ftime = time.strftime('%y/%m/%d-%H:%M:%S', time.localtime(os.path.getmtime(fn))) self.propDlg.setProperty(PropertyEnum.sliceTime, ftime) self.propDlg.setProperty(PropertyEnum.printEstimate, self.totalTimeStr) if self.settings.nextruders < self.maxTool + 1: self.log( "G Code file uses more tools (%d) than printer is equipped with (%d)" % (self.maxTool + 1, self.settings.nextruders)) slCfg, filSiz, tempsHE, tempsBed = parseGCSuffix(gc) if tempsBed == "??": tBed = 0 else: try: tBed = int(float(tempsBed)) except: tBed = 0 if tempsHE == "??": tHe = [0] * self.settings.nextruders else: try: x = [int(float(x)) for x in re.split(", *", tempsHE) ] + [0] * self.settings.nextruders tHe = x[:self.settings.nextruders] except: tHe = [0] * self.settings.nextruders self.parent.registerGCodeTemps(tHe, tBed) self.propDlg.setProperty(PropertyEnum.slicerCfg, slCfg) self.propDlg.setProperty(PropertyEnum.filamentSize, filSiz) self.propDlg.setProperty(PropertyEnum.temperatures, "HE:%s BED:%s" % (tempsHE, tempsBed)) def updatePrintPosition(self, position): self.printLayer = self.getLayerByPosition(position) self.printPosition = position if self.state in [PrintState.printing, PrintState.sdprintingto]: posString = "%d/%d" % (position, self.maxLine) if self.maxLine != 0: pct = float(position) / float(self.maxLine) * 100.0 posString += " (%.1f%%)" % pct self.propDlg.setProperty(PropertyEnum.position, posString) self.gcf.setPrintPosition(position) lx = self.gcf.getCurrentLayer() if lx != self.currentLayer: self.changeLayer(lx) layersSplit = self.sumLayerTimes(self.printLayer) layerSplit = self.partialPrintingLayer() self.elapsed = time.time() - self.startTime expected = layersSplit[0] + layerSplit[0] elapsedStr = "%s (expected: %s)" % (formatElapsed( self.elapsed), formatElapsed(expected)) self.propDlg.setProperty(PropertyEnum.elapsed, elapsedStr) self.remaining = layersSplit[1] + layerSplit[1] self.propDlg.setProperty(PropertyEnum.remaining, formatElapsed(self.remaining)) #TODO - probably don't need all the various time estimates when printing TO CD # BUT IT MAY BREAK LOGIC BELOW (update time until) that rely on these values newEta = time.time() + self.remaining revisedStr = time.strftime('%H:%M:%S', time.localtime(newEta)) tdiff = newEta - self.origEta if tdiff < 0: revisedStr += " (%s ahead of estimate)" % formatElapsed( -tdiff) elif tdiff > 0: revisedStr += " (%s behind estimate)" % formatElapsed(tdiff) self.propDlg.setProperty(PropertyEnum.revisedEta, revisedStr) self.updateTimeUntil() elif self.state == PrintState.sdprintingfrom: #TODO Need to convey print position when printing from SD card pass def getLayerByPosition(self, pos): for lx in range(len(self.layerMap)): if self.layerMap[lx][0] <= pos and pos <= self.layerMap[lx][1]: return lx return 0 def partialPrintingLayer(self): f, l = self.gObj.getGCodeLines(self.printLayer) if f <= self.printPosition and self.printPosition <= l: done = self.printPosition - f todo = l - self.printPosition + 1 total = l - f + 1 lt = self.layerTimes[self.printLayer] pctDone = float(done) / float(total) pctToDo = float(todo) / float(total) return (pctDone * lt, pctToDo * lt) else: return (0.0, 0.0) def sumLayerTimes(self, lx): tBefore = sum(self.layerTimes[:lx]) tAfter = sum(self.layerTimes[lx + 1:]) return (tBefore, tAfter) def sumLayerRangeTime(self, slx, elx): return sum(self.layerTimes[slx:elx]) def changeLayer(self, lx): self.currentLayer = lx self.slLayers.SetValue(lx) ht = self.gObj.getLayerHeight(lx) self.setLayerText(ht) if ht is None: self.propDlg.setProperty(PropertyEnum.layerNum, "%d / %d" % (lx, self.gObj.layerCount())) else: self.propDlg.setProperty( PropertyEnum.layerNum, "%d / %d (%.2f mm) " % (lx, self.gObj.layerCount(), ht)) f, l = self.gObj.getGCodeLines(lx) if f is None: self.propDlg.setProperty(PropertyEnum.gCodeRange, "") self.layerRange = (0, 0) else: self.propDlg.setProperty(PropertyEnum.gCodeRange, "%d - %d" % (f, l)) self.layerRange = (f, l) x0, y0, xn, yn = self.gObj.getLayerMinMaxXY(lx) if x0 is None: self.propDlg.setProperty(PropertyEnum.minMaxXY, "") else: self.propDlg.setProperty( PropertyEnum.minMaxXY, "(%.2f, %.2f) - (%.2f, %.2f)" % (x0, y0, xn, yn)) le, prior, after = self.gObj.getLayerFilament(lx) s = [] for i in range(self.settings.nextruders): s.append("%.2f/%.2f <: %.2f >: %.2f" % (le[i], self.eUsed[i], prior[i], after[i])) self.propDlg.setProperty(PropertyEnum.filamentUsed, s) self.propDlg.setProperty( PropertyEnum.layerPrintTime, "%s / %s" % (self.layerTimeStr[lx], self.totalTimeStr)) self.updateTimeUntil() def updateTimeUntil(self): if self.currentLayer <= self.printLayer: self.propDlg.setProperty(PropertyEnum.timeUntil, "") elif self.printPosition is None: t = sum(self.layerTimes[:self.currentLayer]) self.propDlg.setProperty(PropertyEnum.timeUntil, formatElapsed(t)) else: t = sum(self.layerTimes[self.printLayer + 1:self.currentLayer] ) + self.partialPrintingLayer()[1] self.propDlg.setProperty(PropertyEnum.timeUntil, formatElapsed(t)) def reprapEvent(self, evt): if evt.event == RepRapEventEnum.PRINT_COMPLETE: # TODO - do I need special consideration here for print FROM SD if self.state == PrintState.sdprintingto: self.reprap.sendNow("M29 %s" % self.sdTargetFile) self.reprap.suspendTempProbe(False) self.setSDTargetFile(None) if self.state == PrintState.printing: self.history.addEvent( PrintCompleted(self.history.addFile(self.gcodeFile), "")) self.state = PrintState.idle self.oldState = None self.propDlg.setPrintStatus(PrintState.idle) self.gcf.setPrintPosition(-1) self.printPosition = None self.printLayer = 0 self.enableButtonsByState() self.elapsed = time.time() - self.startTime cmpTime = time.time() expCmpTime = self.origEta - self.startTime cmpTimeStr = time.strftime('%H:%M:%S', time.localtime(cmpTime)) self.log("Print completed at %s" % (cmpTimeStr)) self.log("Total print time of %s - expected print time %s" % (formatElapsed(self.elapsed), formatElapsed(expCmpTime))) self.reprap.printComplete() elif evt.event == RepRapEventEnum.PRINT_STOPPED: if self.state != PrintState.paused: self.oldState = self.state self.state = PrintState.paused self.propDlg.setPrintStatus(PrintState.paused) self.enableButtonsByState() self.reprap.printStopped() elif evt.event == RepRapEventEnum.PRINT_STARTED: pass elif evt.event == RepRapEventEnum.PRINT_RESUMED: pass elif evt.event == RepRapEventEnum.PRINT_ERROR: self.log("Error communicating with printer") elif evt.event == RepRapEventEnum.PRINT_SENDGCODE: self.log(evt.msg) else: self.log("unknown reprap event: %s" % str(evt.event)) def buildModel(self): cnc = CNC(self.settings.acceleration, self.settings.layerheight) if RECORD_TIMES: self.log("recording g code times in /tmp/gcodeTimes") fp = open("/tmp/gcodeTimes", "w") ln = -1 for gl in self.gcode: ln += 1 p = re.split("\\s+", gl, 1) params = {} if not (p[0].strip() in ["M117", "m117"]): if len(p) >= 2: self.paramStr = p[1] if "X" in self.paramStr: params["X"] = self._get_float("X") if "Y" in self.paramStr: params["Y"] = self._get_float("Y") if "Z" in self.paramStr: params["Z"] = self._get_float("Z") if "E" in self.paramStr: params["E"] = self._get_float("E") if "F" in self.paramStr: params["F"] = self._get_float("F") if "S" in self.paramStr: params["S"] = self._get_float("S") if "P" in self.paramStr: params["P"] = self._get_float("P") t = cnc.execute(p[0], params, ln) if RECORD_TIMES: fp.write("(%s) (%.3f)\n" % (gl, t)) if RECORD_TIMES: fp.close() gobj = cnc.getGObject() gobj.setMaxLine(ln) self.maxTool = cnc.getMaxTool() self.totalTime, self.layerTimes = cnc.getTimes() self.layerMap = [] for lx in range(len(gobj)): self.layerMap.append(gobj.getGCodeLines(lx)) self.totalTimeStr = formatElapsed(self.totalTime) self.layerTimeStr = [formatElapsed(s) for s in self.layerTimes] return gobj def _get_float(self, which): try: return float(gcRegex.findall(self.paramStr.split(which)[1])[0]) except: self.log("unable to parse float from (%s)" % self.paramStr) def enableButtonsByState(self): if self.state == PrintState.idle: self.bOpen.Enable(True) self.setImportFile(self.importFile) self.bImportQ.Enable(self.okToImport) if self.sdcard: self.bSdPrintTo.Enable(self.gcodeLoaded) self.bSdPrintFrom.Enable() self.bSdDelete.Enable() if self.gcodeLoaded: self.bPrint.Enable(True) self.bPrint.setPrint() self.bPause.Enable(False) self.bPause.setPause() else: self.bPrint.Enable(False) self.bPause.Enable(False) elif self.state in [PrintState.printing, PrintState.sdprintingto]: self.bImport.Enable(False) self.bImportQ.Enable(False) self.bOpen.Enable(False) self.bPrint.Enable(False) self.bPrint.setPrint() self.bPause.Enable(True) self.bPause.setPause() if self.sdcard: self.bSdPrintTo.Enable(False) self.bSdPrintFrom.Enable(False) self.bSdDelete.Enable(False) elif self.state == PrintState.sdprintingfrom: #TODO - what makes sense here pass elif self.state == PrintState.paused: self.bOpen.Enable(True) self.setImportFile(self.importFile) self.bImportQ.Enable(self.okToImport) self.bPrint.Enable(True) self.bPrint.setRestart() self.bPause.Enable(True) self.bPause.setResume() if self.sdcard: self.bSdPrintTo.Enable(self.gcodeLoaded) self.bSdPrintFrom.Enable() self.bSdDelete.Enable() def emulatePrintButton(self): if self.state in [ PrintState.printing, PrintState.sdprintingto, PrintState.sdprintingfrom ]: self.log("Already printing") elif not self.bPrint.IsEnabled(): self.log("Unable to print right now") else: self.onPrint(None) def reset(self): #TODO - cleanup if was sdprintingfrom self.state = PrintState.idle self.oldState = None self.reprap.suspendTempProbe(False) self.setSDTargetFile(None) self.propDlg.setPrintStatus(PrintState.idle) self.enableButtonsByState() def onPrint(self, evt): oldState = self.state self.state = PrintState.printing self.propDlg.setPrintStatus(PrintState.printing) self.enableButtonsByState() self.printPos = 0 self.startTime = time.time() self.endTime = None self.origEta = self.startTime + self.totalTime self.elapsed = 0 self.remaining = self.totalTime if oldState == PrintState.paused: action = "restarted" self.reprap.restartPrint(self.gcode) else: action = "started" self.reprap.startPrint(self.gcode) self.history.addEvent( PrintStarted(self.history.addFile(self.gcodeFile), "")) stime = time.strftime('%H:%M:%S', time.localtime(self.startTime)) self.propDlg.setProperty(PropertyEnum.startTime, stime) self.propDlg.setProperty( PropertyEnum.origEta, time.strftime('%H:%M:%S', time.localtime(self.origEta))) self.propDlg.setProperty(PropertyEnum.elapsed, formatElapsed(self.elapsed)) self.propDlg.setProperty(PropertyEnum.remaining, formatElapsed(self.remaining)) self.propDlg.setProperty(PropertyEnum.revisedEta, "") self.log("Print %s at %s" % (action, stime)) def onSdPrintFrom(self, evt): print "sd print from" def doSDPrintFrom(self, evt): self.printing = False self.paused = False self.sdpaused = False self.sdprintingfrom = True self.sdStartTime = time.time() #self.infoPane.setSDStartTime(self.sdStartTime) self.state = PrintState.printing #self.propDlg.setPrintStatus(PrintState.printing) self.enableButtonsByState() self.sdcard.startPrintFromSD() def cancelSDPrintFrom(self): self.sdprintingfrom = False self.printing = False self.paused = False self.state = PrintState.idle #self.propDlg.setPrintStatus(PrintState.printing) self.enableButtonsByState() def resumeSDPrintFrom(self, fn): #self.clearModel() self.reprap.sendNow("M23 " + fn[1].lower()) self.reprap.sendNow("M24") self.sdprintingfrom = True #self.M27Timer.Start(M27Interval, True) self.sdpaused = False #self.infoPane.setMode(MODE_FROM_SD) self.enableButtonsByState() def onSdPrintTo(self, evt): self.sdcard.startPrintToSD() def resumeSDPrintTo(self, tfn): self.setSDTargetFile(tfn[1].lower()) self.reprap.suspendTempProbe(True) self.reprap.sendNow("M28 %s" % self.sdTargetFile) self.printPos = 0 self.startTime = time.time() self.endTime = None self.reprap.startPrint(self.gcode) self.origEta = self.startTime + self.totalTime self.elapsed = 0 self.remaining = self.totalTime self.state = PrintState.sdprintingto stime = time.strftime('%H:%M:%S', time.localtime(self.startTime)) self.propDlg.setProperty(PropertyEnum.startTime, stime) self.propDlg.setProperty( PropertyEnum.origEta, time.strftime('%H:%M:%S', time.localtime(self.origEta))) self.propDlg.setProperty(PropertyEnum.elapsed, formatElapsed(self.elapsed)) self.propDlg.setProperty(PropertyEnum.remaining, formatElapsed(self.remaining)) self.propDlg.setProperty(PropertyEnum.revisedEta, "") self.log("Print to SD: %s started at %s" % (self.sdTargetFile, stime)) self.enableButtonsByState() def setSDTargetFile(self, tfn): self.sdTargetFile = tfn self.propDlg.setSDTargetFile(tfn) def onSdDelete(self, evt): self.sdcard.startDeleteFromSD() def emulatePauseButton(self): if not self.bPause.IsEnabled(): self.log("Unable to pause right now") else: self.onPause(None) def onPause(self, evt): if self.state == PrintState.paused: self.state = self.oldState if self.state is None: self.state = PrintState.printing self.propDlg.setPrintStatus(self.state) self.enableButtonsByState() self.reprap.resumePrint() else: self.oldState = self.state self.state = PrintState.paused self.propDlg.setPrintStatus(PrintState.paused) self.enableButtonsByState() self.reprap.pausePrint()