def SD_setup(self, spi, cs): sd = None # setup SD card try: sd = SDCard(spi, Pin(cs)) except Exception as e: print('Error in SDCard()!!') print(e) return None else: print('SD OK') # mount sd volume utime.sleep(0.1) uos.mount(sd, '/sd') utime.sleep(0.1) uos.listdir('/sd') #utime.sleep(0.1) #ls('/sd') return sd
#classmachine.SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) #SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) Acelx = I2C(scl=Pin(22), sda=Pin(21), freq=100000) Acelx.writeto_mem(MMA8254Q_ADDR, 0x2A, b'\x00') Acelx.writeto_mem(MMA8254Q_ADDR, 0x2A, b'\x01') Acelx.writeto_mem(MMA8254Q_ADDR, 0x0E, b'\x00') Acelx.writeto_mem(MMA8254Q_ADDR, 0x0F, b'\x30') #SD1 = SPI(1, 1000000, sck=Pin(18), mosi=Pin(23), miso=Pin(19)) SD1 = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(32)) sleep_ms(500) SD1.init() # Ensure right baudrate #sd = SDCard(SD1,Pin(05)) # Compatible with PCB sd = SDCard(SD1, Pin(27)) vfs = os.VfsFat(sd) os.mount(vfs, '/fc') in_xAcc1 = 0 in_yAcc1 = 0 in_zAcc1 = 0 xAcc1 = 0 yAcc1 = 0 zAcc1 = 0 in_in_xAcc1 = 0 in_in_yAcc1 = 0 in_in_zAcc1 = 0
def __init__(self, master=None): self.master = master Frame.__init__(self, master, relief=SUNKEN, bd=2) self.gcode = [] self.slicing = False self.printing = False self.connected = False self.monitorTemp = False self.paused = False self.sdpresent = False self.sdlisting = False self.sdchecking = False self.sdprinting = False self.sdpaused = False self.sduploading = False self.sdbytes = 0 self.sdmaxbytes = 0 self.insidelisting = False self.readingFirmware = False self.sdfiles = [] self.bedtemp = float(0) self.bedtarget = float(0) self.exttemp = float(0) self.exttarget = float(0) self.acceleration = 0 self.m114count = 0 self.speedcount = 0 self.location = [0, 0, 0, 0] self.pausePoint = [0, 0, 0, 0] self.percent = 0.0 self.ets = "??" self.gcodeInfo = None self.GCodeFile = None self.StlFile = None self.Profile = None self.printStartLine = 0 self.startTime = 0 self.endTime = 0 self.elapsedTime = 0 self.FanSpeed = 0 self.FeedMultiply = 100 self.ExtrudeMultiply = 100 self.timingReport = None self.filamentReport = None self.measurementsReport = None self.macroButtons = None self.rpt1re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *B:([0-9\.]+)") self.rpt2re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *W:.*") self.locrptre = re.compile("^X:([0-9\.\-]+)Y:([0-9\.\-]+)Z:([0-9\.\-]+)E:([0-9\.\-]+) *Count") self.speedrptre = re.compile("Fan speed:([0-9]+) Feed Multiply:([0-9]+) Extrude Multiply:([0-9]+)") self.sdre = re.compile("SD printing byte *([0-9]+) *\/ *([0-9]+)") self.printer = printcore() self.settings = Settings() self.settings.cmdFolder = cmd_folder self.logger = Logger(self) if self.settings.speedcommand is not None: allow_while_printing.append(self.settings.speedcommand) self.acceleration = self.settings.acceleration self.dataLoggers = {} for d in DLLIST: self.dataLoggers[d] = DataLogger(self, d) self.skeinforge = Skeinforge(self.settings) self.slic3r = Slic3r(self.settings) self.httpServer = RepRapServer(self, self.printer, self.settings, self.logger, self.settings.port) self.menubar = Menu(self) self.filemenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="File", menu=self.filemenu) self.filemenu.add_command(label="Slice", command=self.openSTLFile) self.filemenu.add_command(label="Load GCode", command=self.openGCodeFile) self.slicemenuindex = self.filemenu.index("Slice") self.loadgcodemenuindex = self.filemenu.index("Load GCode") self.filemenu.add_separator() self.filemenu.add_command(label="Exit", command=self.quitApp) self.editmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Edit", menu=self.editmenu) self.editmenu.add_command(label="Settings", command=self.editSettings) self.editmenu.add_command(label="Firmware Settings", command=self.FirmwareSettings) self.editmenu.add_separator() self.editmenu.add_command(label=GCODE_MENU_TEXT, command=self.doGEdit, state=DISABLED) self.slicermenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Slicer", menu=self.slicermenu) self.rbSlicer = StringVar() self.slicermenu.add_radiobutton( label="Skeinforge", command=self.selSlicer, value=SKEINFORGE, variable=self.rbSlicer ) self.slicermenu.add_command(label="Settings", command=self.skeinforgeSettings) self.slicermenu.add_command(label="Choose Profile", command=self.chooseSFProfile) self.SFprofileindex = self.slicermenu.index("Choose Profile") self.setSFProfileMenuText() self.slicermenu.add_command(label="Alterations", command=self.doEditAlterations) self.slicermenu.add_separator() self.slicermenu.add_radiobutton(label="Slic3r", command=self.selSlicer, value=SLIC3R, variable=self.rbSlicer) self.slicermenu.add_command(label="Settings", command=self.slic3rSettings) self.slicermenu.add_command(label="Choose Profile", command=self.chooseS3Profile) self.S3profileindex = self.slicermenu.index("Choose Profile") self.setS3ProfileMenuText() self.rbSlicer.set(self.settings.slicer) self.macromenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Macros", menu=self.macromenu) self.macromenu.add_command(label="New", command=self.doNewMacro) self.macromenu.add_command(label="Edit", command=self.doEditMacro) self.macromenu.add_command(label="Delete", command=self.doDelMacro) self.macromenu.add_separator() self.cbShowMacroButtons = BooleanVar() self.cbShowMacroButtons.set(self.settings.showmacrobuttons) self.macromenu.add_checkbutton( label="Show Macro Buttons", command=self.doShowButtons, onvalue=True, offvalue=False, variable=self.cbShowMacroButtons, ) self.macromenu.add_separator() self.runmacromenu = Menu(self.macromenu, tearoff=0) self.loadMacros() self.macromenu.add_cascade(label="Run", menu=self.runmacromenu) self.reportmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="View", menu=self.reportmenu) self.cbShowPrevious = BooleanVar() self.cbShowPrevious.set(self.settings.showprevious) self.reportmenu.add_checkbutton( label="Show Previous Layer", command=self.toggleShowPrevious, onvalue=True, offvalue=False, variable=self.cbShowPrevious, ) self.cbShowMoves = BooleanVar() self.cbShowMoves.set(self.settings.showmoves) self.reportmenu.add_checkbutton( label="Show Non-extrusion Moves", command=self.toggleShowMoves, onvalue=True, offvalue=False, variable=self.cbShowMoves, ) self.reportmenu.add_separator() self.reportmenu.add_command(label="Show Hours of Usage", command=self.doDataLogReport) self.reportmenu.add_command(label="Reset Hours of Usage", command=self.doDataLogReset) self.reportmenu.add_separator() self.reportmenu.add_command(label="Layer by Layer Timing", command=self.doTimingReport) self.reportmenu.add_command(label="Layer by Layer Filament Usage", command=self.doFilamentReport) self.reportmenu.add_command(label="GCode Measurements", command=self.doMeasurementsReport) self.toolsmenu = Menu(self.menubar, tearoff=0) n = 0 if self.settings.platercmd is not None: n += 1 self.toolsmenu.add_command(label="Plater", command=self.doPlater) if self.settings.gcodeviewcmd is not None: n += 1 self.toolsmenu.add_command(label="GCode Viewer", command=self.doGCodeView) if self.settings.stlviewcmd is not None: n += 1 self.toolsmenu.add_command(label="STL Viewer", command=self.doSTLView) if self.settings.openscadcmd is not None: n += 1 self.toolsmenu.add_command(label="OpenSCAD", command=self.doOpenSCAD) if n > 0: self.menubar.add_cascade(label="Tools", menu=self.toolsmenu) try: self.master.config(menu=self.menubar) except AttributeError: self.master.tk.call(master, "config", "-menu", self.menubar) self.toolbar = ToolBar(self, self.printer, self.settings, self.logger) self.toolbar.grid(row=1, column=1, columnspan=4, sticky=W) self.ctl = MoveControl(self, self.printer, self.settings, self.logger) self.ctl.grid(row=2, column=1, rowspan=3, sticky=N) self.extr = Extruder(self, self.printer, self.settings, self.logger) self.extr.grid(row=2, column=2, rowspan=1, sticky=N + E + W) self.temps = Temperatures(self, self.printer, self.settings, self.logger) self.temps.grid(row=3, column=2, rowspan=2, sticky=N + E + W) self.gc = GcFrame(self, None, [], self.settings, self.logger) self.gc.grid(row=2, column=3, rowspan=3, sticky=N) self.statline = Status(self, self.printer, self.settings, self.logger) self.statline.grid(row=5, column=1, columnspan=4, sticky=E + W) self.logger.grid(row=2, column=4, rowspan=2, sticky=N + E + W) self.sendgcode = SendGCode(self, self.printer, self.settings, self.logger) self.sendgcode.grid(row=4, column=4, sticky=N + E + W) self.printer.errorcb = self.errorcb self.printer.sendcb = self.sendcb self.printer.recvcb = self.recvcb self.sd = SDCard(self, self.printer, self.settings, self.logger) self.firmware = FirmwareParms(self, self.printer, self.settings, self.logger) self.bind(MWM_FIRMWARECOMPLETE, self.firmwareReportComplete) self.bind(MWM_SLICERCOMPLETE, self.sliceComplete) self.bind(MWM_GCODELOADCOMPLETE, self.loadgcodeFinished) self.bind(MWM_GEDITMEASURECOMPLETE, self.geditMeasureComplete) self.bind(MWM_REQUESTPOSITIONREPORT, self.requestPosition) self.doShowButtons()
def mnt(): cs = Pin("P22", mode=Pin.OUT) sd = SDCard(SPI(0), cs) os.mount(sd, '/')
def __init__(self, parent, app, prtname, reprap, history): self.model = None self.cfgString = None self.app = app self.prtsettings = self.app.settings.printersettings[prtname] self.buildarea = self.prtsettings.buildarea self.prtname = prtname self.history = history self.reprap = reprap self.manctl = None self.hassd = self.prtsettings.hassdcard self.filamentdiameter = self.prtsettings.filamentdiam self.sliceTime = "" self.M105pending = False self.M27pending = False self.suspendM105 = False self.cycle = 0 self.skipCycles = 5 self.logger = self.app.logger self.printPos = 0 self.printing = False self.paused = False self.sdpaused = False self.sdprintingfrom = False self.settings = app.settings.printmon wx.Panel.__init__(self, parent, wx.ID_ANY, size=(100, 100)) self.SetBackgroundColour("white") self.knownHeaters = ['HE0', 'HE1', 'HE2', 'Bed'] self.targets = {} self.temps = {} self.tempData = {} for h in self.knownHeaters: self.temps[h] = None self.targets[h] = 0 self.tempData[h] = [] self.startTime = None self.endTime = None self.gcFile = None self.printMode = None self.origEta = None self.countGLines = None self.syncPrint = True self.holdFan = False self.setStatus(PMSTATUS_NOT_READY) self.sdcard = SDCard(self.app, self, self.reprap, self.logger) self.M27Timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onM27Timer, self.M27Timer) self.printingfrom = False self.sizerMain = wx.BoxSizer(wx.HORIZONTAL) self.sizerLeft = wx.BoxSizer(wx.VERTICAL) self.sizerRight = wx.BoxSizer(wx.VERTICAL) self.sizerLeft.AddSpacer((10,10)) self.sizerBtns = wx.BoxSizer(wx.HORIZONTAL) self.sizerBtns.AddSpacer((10,10)) self.images = Images(os.path.join(self.settings.cmdfolder, "images")) self.bPull = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPull, size=BUTTONDIMWIDE) self.sizerBtns.Add(self.bPull) self.bPull.SetToolTipString("Pull model from file preparation") self.Bind(wx.EVT_BUTTON, self.doPull, self.bPull) self.bPull.Enable(self.app.currentPullStatus()) self.sizerBtns.AddSpacer((20, 20)) self.bPrint = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPrint, size=BUTTONDIM) self.setPrintMode(PRINT_MODE_PRINT) self.sizerBtns.Add(self.bPrint) self.Bind(wx.EVT_BUTTON, self.doPrint, self.bPrint) self.bPrint.Enable(False) self.bPause = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPause, size=BUTTONDIM) self.setPauseMode(PAUSE_MODE_PAUSE) self.sizerBtns.Add(self.bPause) self.Bind(wx.EVT_BUTTON, self.doPause, self.bPause) self.bPause.Enable(False) self.sizerBtns.AddSpacer(BUTTONDIM) if self.hassd: self.bSDPrintFrom = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintfrom, size=BUTTONDIMWIDE) self.bSDPrintFrom.SetToolTipString("Print from SD Card") self.sizerBtns.Add(self.bSDPrintFrom) self.Bind(wx.EVT_BUTTON, self.doSDPrintFrom, self.bSDPrintFrom) self.bSDPrintFrom.Enable(True) self.bSDPrintTo = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintto, size=BUTTONDIMWIDE) self.bSDPrintTo.SetToolTipString("Print to SD Card") self.sizerBtns.Add(self.bSDPrintTo) self.Bind(wx.EVT_BUTTON, self.doSDPrintTo, self.bSDPrintTo) self.bSDPrintTo.Enable(False) self.bSDDelete = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSddelete, size=BUTTONDIM) self.bSDDelete.SetToolTipString("Delete a file from SD Card") self.sizerBtns.Add(self.bSDDelete) self.Bind(wx.EVT_BUTTON, self.doSDDelete, self.bSDDelete) self.bSDDelete.Enable(True) self.sizerBtns.AddSpacer(BUTTONDIM) self.bZoomIn = wx.BitmapButton(self, wx.ID_ANY, self.images.pngZoomin, size=BUTTONDIM) self.bZoomIn.SetToolTipString("Zoom the view in") self.sizerBtns.Add(self.bZoomIn) self.Bind(wx.EVT_BUTTON, self.viewZoomIn, self.bZoomIn) self.bZoomOut = wx.BitmapButton(self, wx.ID_ANY, self.images.pngZoomout, size=BUTTONDIM) self.bZoomOut.SetToolTipString("Zoom the view out") self.sizerBtns.Add(self.bZoomOut) self.Bind(wx.EVT_BUTTON, self.viewZoomOut, self.bZoomOut) self.sizerLeft.Add(self.sizerBtns) self.sizerLeft.AddSpacer((10,10)) self.sizerGCM = wx.BoxSizer(wx.HORIZONTAL) self.gcf = GcmFrame(self, self.model, self.settings, self.buildarea) self.sizerGCM.Add(self.gcf) sz = self.buildarea[1] * self.settings.gcodescale self.slideLayer = wx.Slider( self, wx.ID_ANY, 1, 1, 9999, size=(150, sz), style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | wx.SL_LABELS) self.slideLayer.Bind(wx.EVT_SCROLL, self.onSpinLayer) self.slideLayer.SetRange(1, 10) self.slideLayer.SetValue(1) self.slideLayer.SetPageSize(1); self.slideLayer.Disable() self.sizerGCM.Add(self.slideLayer) self.sizerLeft.Add(self.sizerGCM) self.sizerLeft.AddSpacer((10,10)) self.sizerOpts = wx.BoxSizer(wx.HORIZONTAL) self.cbPrevious = wx.CheckBox(self, wx.ID_ANY, "Show Previous Layer") self.cbPrevious.SetToolTipString("Turn on/off drawing of the previous layer in the background") self.Bind(wx.EVT_CHECKBOX, self.checkPrevious, self.cbPrevious) self.cbPrevious.SetValue(self.settings.showprevious) self.sizerOpts.Add(self.cbPrevious) self.sizerOpts.AddSpacer((10, 10)) self.cbMoves = wx.CheckBox(self, wx.ID_ANY, "Show Moves") self.cbMoves.SetToolTipString("Turn on/off the drawing of non-extrusion moves") self.Bind(wx.EVT_CHECKBOX, self.checkMoves, self.cbMoves) self.cbMoves.SetValue(self.settings.showmoves) self.sizerOpts.Add(self.cbMoves) self.sizerOpts.AddSpacer((10, 10)) self.cbToolOnly = wx.CheckBox(self, wx.ID_ANY, "Tool Path Only") self.cbToolOnly.SetToolTipString("Show narrow lines indicating tool path") self.Bind(wx.EVT_CHECKBOX, self.checkToolPathsOnly, self.cbToolOnly) self.cbToolOnly.SetValue(self.settings.toolpathsonly) self.sizerOpts.Add(self.cbToolOnly) self.sizerOpts.AddSpacer((10, 10)) self.cbSync = wx.CheckBox(self, wx.ID_ANY, "Sync with print") self.Bind(wx.EVT_CHECKBOX, self.checkSync, self.cbSync) self.cbSync.SetValue(True) self.sizerOpts.Add(self.cbSync) self.sizerLeft.AddSpacer((5, 5)) self.sizerLeft.Add(self.sizerOpts) self.sizerOpts2 = wx.BoxSizer(wx.HORIZONTAL) self.cbBuffDC = wx.CheckBox(self, wx.ID_ANY, "Use Buffered DC") self.Bind(wx.EVT_CHECKBOX, self.checkBuffDC, self.cbBuffDC) self.cbBuffDC.SetValue(self.settings.usebuffereddc) self.sizerOpts2.Add(self.cbBuffDC) self.sizerOpts2.AddSpacer((10, 10)) self.cbHoldFan = wx.CheckBox(self, wx.ID_ANY, "Hold Fan Speed") self.cbHoldFan.SetToolTipString("Maintain fan speed at its manual setting") self.Bind(wx.EVT_CHECKBOX, self.checkHoldFan, self.cbHoldFan) self.cbHoldFan.SetValue(self.holdFan) self.sizerOpts2.Add(self.cbHoldFan) self.sizerLeft.AddSpacer((5, 5)) self.sizerLeft.Add(self.sizerOpts2) self.sizerLeft.AddSpacer((10,10)) self.sizerRight.AddSpacer((40,40)) self.gTemp = TempGraph(self, self.settings) self.sizerRight.Add(self.gTemp) self.sizerRight.AddSpacer((20, 20)) self.infoPane = InfoPane(self, self.app) self.sizerRight.Add(self.infoPane, flag=wx.EXPAND) self.sizerMain.AddSpacer((50,50)) self.sizerMain.Add(self.sizerLeft) self.sizerMain.Add(self.sizerRight) self.SetSizer(self.sizerMain) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onTimer, self.timer) self.secCounter = 0 self.openFpLog() self.timer.Start(1000) self.reprap.setHoldFan(self.holdFan) self.Bind(EVT_HTTP_PRINTMON, self.httpRequest) self.infoPane.setMode(MODE_NORMAL) self.setSDTargetFile(None)
class App(Frame): def __init__(self, master=None): self.master = master Frame.__init__(self, master, relief=SUNKEN, bd=2) self.gcode = [] self.slicing = False self.printing = False self.connected = False self.monitorTemp = False self.paused = False self.sdpresent = False self.sdlisting = False self.sdchecking = False self.sdprinting = False self.sdpaused = False self.sduploading = False self.sdbytes = 0 self.sdmaxbytes = 0 self.insidelisting = False self.readingFirmware = False self.sdfiles = [] self.bedtemp = float(0) self.bedtarget = float(0) self.exttemp = float(0) self.exttarget = float(0) self.acceleration = 0 self.m114count = 0 self.speedcount = 0 self.location = [0, 0, 0, 0] self.pausePoint = [0, 0, 0, 0] self.percent = 0.0 self.ets = "??" self.gcodeInfo = None self.GCodeFile = None self.StlFile = None self.Profile = None self.printStartLine = 0 self.startTime = 0 self.endTime = 0 self.elapsedTime = 0 self.FanSpeed = 0 self.FeedMultiply = 100 self.ExtrudeMultiply = 100 self.timingReport = None self.filamentReport = None self.measurementsReport = None self.macroButtons = None self.rpt1re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *B:([0-9\.]+)") self.rpt2re = re.compile(" *T:([0-9\.]+) *E:[0-9\.]+ *W:.*") self.locrptre = re.compile("^X:([0-9\.\-]+)Y:([0-9\.\-]+)Z:([0-9\.\-]+)E:([0-9\.\-]+) *Count") self.speedrptre = re.compile("Fan speed:([0-9]+) Feed Multiply:([0-9]+) Extrude Multiply:([0-9]+)") self.sdre = re.compile("SD printing byte *([0-9]+) *\/ *([0-9]+)") self.printer = printcore() self.settings = Settings() self.settings.cmdFolder = cmd_folder self.logger = Logger(self) if self.settings.speedcommand is not None: allow_while_printing.append(self.settings.speedcommand) self.acceleration = self.settings.acceleration self.dataLoggers = {} for d in DLLIST: self.dataLoggers[d] = DataLogger(self, d) self.skeinforge = Skeinforge(self.settings) self.slic3r = Slic3r(self.settings) self.httpServer = RepRapServer(self, self.printer, self.settings, self.logger, self.settings.port) self.menubar = Menu(self) self.filemenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="File", menu=self.filemenu) self.filemenu.add_command(label="Slice", command=self.openSTLFile) self.filemenu.add_command(label="Load GCode", command=self.openGCodeFile) self.slicemenuindex = self.filemenu.index("Slice") self.loadgcodemenuindex = self.filemenu.index("Load GCode") self.filemenu.add_separator() self.filemenu.add_command(label="Exit", command=self.quitApp) self.editmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Edit", menu=self.editmenu) self.editmenu.add_command(label="Settings", command=self.editSettings) self.editmenu.add_command(label="Firmware Settings", command=self.FirmwareSettings) self.editmenu.add_separator() self.editmenu.add_command(label=GCODE_MENU_TEXT, command=self.doGEdit, state=DISABLED) self.slicermenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Slicer", menu=self.slicermenu) self.rbSlicer = StringVar() self.slicermenu.add_radiobutton( label="Skeinforge", command=self.selSlicer, value=SKEINFORGE, variable=self.rbSlicer ) self.slicermenu.add_command(label="Settings", command=self.skeinforgeSettings) self.slicermenu.add_command(label="Choose Profile", command=self.chooseSFProfile) self.SFprofileindex = self.slicermenu.index("Choose Profile") self.setSFProfileMenuText() self.slicermenu.add_command(label="Alterations", command=self.doEditAlterations) self.slicermenu.add_separator() self.slicermenu.add_radiobutton(label="Slic3r", command=self.selSlicer, value=SLIC3R, variable=self.rbSlicer) self.slicermenu.add_command(label="Settings", command=self.slic3rSettings) self.slicermenu.add_command(label="Choose Profile", command=self.chooseS3Profile) self.S3profileindex = self.slicermenu.index("Choose Profile") self.setS3ProfileMenuText() self.rbSlicer.set(self.settings.slicer) self.macromenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Macros", menu=self.macromenu) self.macromenu.add_command(label="New", command=self.doNewMacro) self.macromenu.add_command(label="Edit", command=self.doEditMacro) self.macromenu.add_command(label="Delete", command=self.doDelMacro) self.macromenu.add_separator() self.cbShowMacroButtons = BooleanVar() self.cbShowMacroButtons.set(self.settings.showmacrobuttons) self.macromenu.add_checkbutton( label="Show Macro Buttons", command=self.doShowButtons, onvalue=True, offvalue=False, variable=self.cbShowMacroButtons, ) self.macromenu.add_separator() self.runmacromenu = Menu(self.macromenu, tearoff=0) self.loadMacros() self.macromenu.add_cascade(label="Run", menu=self.runmacromenu) self.reportmenu = Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="View", menu=self.reportmenu) self.cbShowPrevious = BooleanVar() self.cbShowPrevious.set(self.settings.showprevious) self.reportmenu.add_checkbutton( label="Show Previous Layer", command=self.toggleShowPrevious, onvalue=True, offvalue=False, variable=self.cbShowPrevious, ) self.cbShowMoves = BooleanVar() self.cbShowMoves.set(self.settings.showmoves) self.reportmenu.add_checkbutton( label="Show Non-extrusion Moves", command=self.toggleShowMoves, onvalue=True, offvalue=False, variable=self.cbShowMoves, ) self.reportmenu.add_separator() self.reportmenu.add_command(label="Show Hours of Usage", command=self.doDataLogReport) self.reportmenu.add_command(label="Reset Hours of Usage", command=self.doDataLogReset) self.reportmenu.add_separator() self.reportmenu.add_command(label="Layer by Layer Timing", command=self.doTimingReport) self.reportmenu.add_command(label="Layer by Layer Filament Usage", command=self.doFilamentReport) self.reportmenu.add_command(label="GCode Measurements", command=self.doMeasurementsReport) self.toolsmenu = Menu(self.menubar, tearoff=0) n = 0 if self.settings.platercmd is not None: n += 1 self.toolsmenu.add_command(label="Plater", command=self.doPlater) if self.settings.gcodeviewcmd is not None: n += 1 self.toolsmenu.add_command(label="GCode Viewer", command=self.doGCodeView) if self.settings.stlviewcmd is not None: n += 1 self.toolsmenu.add_command(label="STL Viewer", command=self.doSTLView) if self.settings.openscadcmd is not None: n += 1 self.toolsmenu.add_command(label="OpenSCAD", command=self.doOpenSCAD) if n > 0: self.menubar.add_cascade(label="Tools", menu=self.toolsmenu) try: self.master.config(menu=self.menubar) except AttributeError: self.master.tk.call(master, "config", "-menu", self.menubar) self.toolbar = ToolBar(self, self.printer, self.settings, self.logger) self.toolbar.grid(row=1, column=1, columnspan=4, sticky=W) self.ctl = MoveControl(self, self.printer, self.settings, self.logger) self.ctl.grid(row=2, column=1, rowspan=3, sticky=N) self.extr = Extruder(self, self.printer, self.settings, self.logger) self.extr.grid(row=2, column=2, rowspan=1, sticky=N + E + W) self.temps = Temperatures(self, self.printer, self.settings, self.logger) self.temps.grid(row=3, column=2, rowspan=2, sticky=N + E + W) self.gc = GcFrame(self, None, [], self.settings, self.logger) self.gc.grid(row=2, column=3, rowspan=3, sticky=N) self.statline = Status(self, self.printer, self.settings, self.logger) self.statline.grid(row=5, column=1, columnspan=4, sticky=E + W) self.logger.grid(row=2, column=4, rowspan=2, sticky=N + E + W) self.sendgcode = SendGCode(self, self.printer, self.settings, self.logger) self.sendgcode.grid(row=4, column=4, sticky=N + E + W) self.printer.errorcb = self.errorcb self.printer.sendcb = self.sendcb self.printer.recvcb = self.recvcb self.sd = SDCard(self, self.printer, self.settings, self.logger) self.firmware = FirmwareParms(self, self.printer, self.settings, self.logger) self.bind(MWM_FIRMWARECOMPLETE, self.firmwareReportComplete) self.bind(MWM_SLICERCOMPLETE, self.sliceComplete) self.bind(MWM_GCODELOADCOMPLETE, self.loadgcodeFinished) self.bind(MWM_GEDITMEASURECOMPLETE, self.geditMeasureComplete) self.bind(MWM_REQUESTPOSITIONREPORT, self.requestPosition) self.doShowButtons() def doStopAll(self): self.toolbar.doPause() self.temps.doOffBed() self.temps.doOffExt() def requestPosition(self, *arg): self.m114count += 1 self.printer.send_now("M400") # finish all moves self.printer.send_now("M114") def doShowButtons(self): self.settings.showmacrobuttons = self.cbShowMacroButtons.get() == 1 self.settings.setModified() if self.settings.showmacrobuttons: self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger) else: if self.macroButtons: self.macroButtons.close() self.macroButtons = None def toggleShowPrevious(self): self.settings.showprevious = self.cbShowPrevious.get() == 1 self.settings.setModified() self.gc.drawCanvas() def toggleShowMoves(self): self.settings.showmoves = self.cbShowMoves.get() == 1 self.settings.setModified() self.gc.drawCanvas() def selSlicer(self): self.settings.slicer = self.rbSlicer.get() self.settings.setModified() self.toolbar.setSliceText() def macroButtonClose(self): self.settings.showmacrobuttons = False self.settings.setModified() self.cbShowMacroButtons.set(False) def firmwareReportComplete(self, *arg): p = self.firmware.reportComplete() if p is not None: self.acceleration = p["m204_s"].getFlash() print "Retrieved acc value of ", self.acceleration def openSTLFile(self): if self.printing: self.logger.logMsg("Cannot open a new file while printing") return if self.StlFile is None: fn = askopenfilename( filetypes=[("STL files", "*.stl"), ("G Code files", "*.gcode")], initialdir=self.settings.lastdirectory ) else: fn = askopenfilename( filetypes=[("STL files", "*.stl"), ("G Code files", "*.gcode")], initialdir=self.settings.lastdirectory, initialfile=os.path.basename(self.StlFile), ) if fn: self.settings.lastdirectory = os.path.dirname(os.path.abspath(fn)) self.settings.setModified() if fn.lower().endswith(".gcode"): self.StlFile = None self.loadgcode(fn) elif fn.lower().endswith(".stl"): self.StlFile = fn self.doSlice(fn) else: self.logger.logMsg("Invalid file type") def openGCodeFile(self): if self.printing: self.logger.logMsg("Cannot open a new file while printing") return fn = askopenfilename(filetypes=[("G Code files", "*.gcode")], initialdir=self.settings.lastdirectory) if fn: self.settings.lastdirectory = os.path.dirname(os.path.abspath(fn)) self.settings.setModified() if fn.lower().endswith(".gcode"): self.StlFile = None self.loadgcode(fn) else: self.logger.logMsg("Invalid file type") else: self.toolbar.clearCancelMode() def loadgcode(self, fn): self.GCodeFile = fn self.gcodeloadSuccess = True self.toolbar.setLoading(True) self.loader = threading.Thread(target=self.loadgcodeThread) self.loader.daemon = True self.loader.start() def loadgcodeFinished(self, *arg): self.toolbar.setLoading(False) if self.gcodeloadSuccess: self.showMetrics() def loadgcodeThread(self): try: self.gcode = [] l = list(open(self.GCodeFile)) for s in l: self.gcode.append(s.rstrip()) self.logger.logMsg("read %d lines from %s" % (len(self.gcode), os.path.basename(self.GCodeFile))) except: self.logger.logMsg("Problem reading gcode from %s" % self.GCodeFile) self.gcode = [] self.GCodeFile = None if len(self.gcode) != 0: self.logger.logMsg("Processing...") self.gc.loadFile(self.GCodeFile, self.gcode) self.printStartLine = self.gc.getPrintStartLine() self.gcodeInfo = GCode(self.gcode) self.logger.logMsg("Measuring...") self.gcodeInfo.measure(self.acceleration) self.estEta = self.gcodeInfo.totalduration self.timeLayers = self.gcodeInfo.layerdurations else: self.gcodeloadSuccess = False self.event_generate(MWM_GCODELOADCOMPLETE) def replace(self, s, slicer): if slicer == SLIC3R: d = os.path.expandvars(os.path.expanduser(self.settings.s3profiledir)) profile = os.path.join(d, self.slic3r.getProfile() + ".ini") else: profile = self.skeinforge.getProfile() d = {} d["%starttime%"] = time.strftime("%H:%M:%S", time.localtime(self.startTime)) d["%endtime%"] = time.strftime("%H:%M:%S", time.localtime(self.endTime)) d["%elapsed%"] = formatElapsed(self.elapsedTime) d["%profile%"] = profile d["%slicer%"] = self.settings.slicer if self.StlFile is not None: d["%stlbase%"] = os.path.basename(self.StlFile) d["%stl%"] = self.StlFile else: d["%stlbase%"] = "" d["%stl%"] = "" if self.GCodeFile is not None: d["%gcodebase%"] = os.path.basename(self.GCodeFile) d["%gcode%"] = self.GCodeFile else: d["%gcodebase%"] = "" d["%gcode%"] = "" for t in d.keys(): if d[t] is not None: s = s.replace(t, d[t]) s = s.replace('""', "") return s def showMetrics(self): if len(self.gcode) != 0: self.paused = False self.toolbar.initializeToolbar() self.toolbar.checkAllowPrint() self.allowGEdit() self.logger.logMsg( "Width: %f mm (%f -> %f)" % (self.gcodeInfo.width, self.gcodeInfo.xmin, self.gcodeInfo.xmax) ) self.logger.logMsg( "Depth: %f mm (%f -> %f)" % (self.gcodeInfo.depth, self.gcodeInfo.ymin, self.gcodeInfo.ymax) ) self.logger.logMsg( "Height: is %f mm (%f -> %f)" % (self.gcodeInfo.height, self.gcodeInfo.zmin, self.gcodeInfo.zmax) ) self.logger.logMsg("Total extrusion length: %f mm" % self.gcodeInfo.filament_length()) self.logger.logMsg("Estimated print time: %s" % formatElapsed(self.estEta)) def calcEta(self, line, timeThusFar): foundLayer = False for i in range(len(self.timeLayers)): if self.timeLayers[i][0] > line: foundLayer = True break if not foundLayer: return 0 currentLayer = i - 1 if currentLayer < 0: return 0 totalInLayer = self.timeLayers[i][0] - self.timeLayers[currentLayer][0] printedInLayer = line - self.timeLayers[currentLayer][0] pct = printedInLayer / float(totalInLayer) thisLayerTime = (self.timeLayers[currentLayer][1]) * pct ratio = (self.timeLayers[currentLayer][2] - self.timeLayers[currentLayer][1] + thisLayerTime) / float( timeThusFar ) ne = self.estEta / float(ratio) return ne - timeThusFar def doTimingReport(self): if not self.printing: self.logger.logMsg("Only available while printing") return self.timingReport = TimingReport(self, self.printer, self.settings, self.logger) def closeTimingReport(self): if self.timingReport is not None: self.timingReport.cleanup() self.timingReport.destroy() self.timingReport = None def doMeasurementsReport(self): if not self.gcodeInfo: self.logger.logMsg("Only available when GCode loaded") return self.measurementsReport = MeasurementsReport(self, self.printer, self.settings, self.logger) def closeMeasurementsReport(self): if self.measurementsReport is not None: self.measurementsReport.destroy() self.measurementsReport = None def doFilamentReport(self): if not self.gcodeInfo: self.logger.logMsg("Only available when GCode loaded") return if len(self.gcodeInfo.filLayers) == 0: self.logger.logMsg("No filament usage in this gcode") return self.filamentReport = FilamentReport(self, self.printer, self.settings, self.logger) def closeFilamentReport(self): if self.filamentReport is not None: self.filamentReport.destroy() self.filamentReport = None def closeAllReports(self): self.closeTimingReport() self.closeFilamentReport() self.closeMeasurementsReport() def doPlater(self): s = self.replace(self.settings.platercmd, self.settings.slicer) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def doGCodeView(self): s = self.replace(self.settings.gcodeviewcmd, self.settings.slicer) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def doSTLView(self): s = self.replace(self.settings.stlviewcmd, self.settings.slicer) self.logger.logMsg(s) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def doOpenSCAD(self): s = self.replace(self.settings.openscadcmd, self.settings.slicer) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def doSlice(self, fn): self.paused = False self.toolbar.initializeToolbar() self.slicerfn = fn self.slicing = True self.slicerCancel = False self.toolbar.setCancelMode() if self.settings.slicer == SLIC3R: self.GCodeFile = fn.replace(".stl", ".gcode") cmd = self.replace(os.path.expandvars(os.path.expanduser(self.settings.s3cmd)), SLIC3R) else: self.GCodeFile = fn.replace(".stl", "_export.gcode") cmd = self.replace(os.path.expandvars(os.path.expanduser(self.settings.sfcmd)), SKEINFORGE) self.slicer = threading.Thread(target=self.slicerThread, args=(cmd,)) self.slicer.daemon = True self.slicer.start() def slicerThread(self, cmd): args = shlex.split(cmd) p = subprocess.Popen(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE) obuf = "" while not self.slicerCancel: o = p.stdout.read(1) if o == "": break if o == "\r" or o == "\n": self.logger.logMsg(obuf) obuf = "" elif ord(o) < 32: pass else: obuf += o if self.slicerCancel: p.kill() p.wait() self.event_generate(MWM_SLICERCOMPLETE) def sliceComplete(self, *arg): self.slicing = False self.toolbar.clearCancelMode() if self.slicerCancel: self.slicerCancel = False self.logger.logMsg("Slicing was cancelled") return self.logger.logMsg("Slicing has completed successfully") if os.path.exists(self.GCodeFile): self.loadgcode(self.GCodeFile) else: self.logger.logMsg("Unable to find slicer output file: %s" % self.GCodeFile) def allowGEdit(self): self.editmenu.entryconfig(self.editmenu.index(GCODE_MENU_TEXT), state=NORMAL) def allowSliceMenu(self, flag=True): s = NORMAL if not flag: s = DISABLED self.filemenu.entryconfig(self.slicemenuindex, state=s) def allowLoadGCodeMenu(self, flag=True): s = NORMAL if not flag: s = DISABLED self.filemenu.entryconfig(self.loadgcodemenuindex, state=s) def doGEdit(self): GEditor(self, self.gcode, None) def geditMeasureComplete(self, *arg): self.showMetrics() def gEditSave(self, newgcode, fn, editwindow): if fn == None: self.gcode = newgcode self.meas = threading.Thread(target=self.geditMeasureThread) self.meas.daemon = True self.meas.start() return False else: try: f = open(fn, "w") for l in newgcode: f.write(l + "\n") f.close() self.logger.logMsg("Alterations %s successfully saved" % fn) return True except: self.logger.logMsg("Unable to open %s for output" % fn) return False def geditMeasureThread(self): self.logger.logMsg("Processing...") self.gcodeInfo = GCode(self.gcode) self.logger.logMsg("Measuring...") self.gcodeInfo.measure(self.acceleration) self.estEta = self.gcodeInfo.totalduration self.timeLayers = self.gcodeInfo.layerdurations self.event_generate(MWM_GEDITMEASURECOMPLETE) def doSD(self): if not self.sd.isActive(): self.sd.start() def setToolbarSDPrint(self): self.toolbar.setSDPrint() def startUpload(self): self.sduploading = True self.toolbar.doPrint() def printerAvailable(self, silent=False, cmd="xx"): if not self.connected: if not silent: self.logger.logMsg("Unable to comply - printer not on-line") return False if (self.printing or self.sdprinting) and cmd.upper() not in allow_while_printing: if not silent: self.logger.logMsg("Unable to comply - currently printing") return False return True def printerConnected(self, flag): self.sendgcode.activate(flag) self.connected = flag if flag: self.firmware.start(True) def updateScreen(self): if self.printing: self.gc.updatePrintProgress(self.printer.queueindex) def errorcb(self, s): self.logger.logMsg(s.rstrip()) def sendcb(self, s): # self.logger.logMsg("Sent: %s" % s) pass def recvcb(self, s): if self.readingFirmware: if "M92" in s: X = self.parseG(s, "X") Y = self.parseG(s, "Y") Z = self.parseG(s, "Z") E = self.parseG(s, "E") self.firmware.m92(X, Y, Z, E) return elif "M201" in s: X = self.parseG(s, "X") Y = self.parseG(s, "Y") Z = self.parseG(s, "Z") E = self.parseG(s, "E") self.firmware.m201(X, Y, Z, E) return elif "M203" in s: X = self.parseG(s, "X") Y = self.parseG(s, "Y") Z = self.parseG(s, "Z") E = self.parseG(s, "E") self.firmware.m203(X, Y, Z, E) return elif "M204" in s: S = self.parseG(s, "S") T = self.parseG(s, "T") self.firmware.m204(S, T) return elif "M205" in s: S = self.parseG(s, "S") T = self.parseG(s, "T") B = self.parseG(s, "B") X = self.parseG(s, "X") Z = self.parseG(s, "Z") E = self.parseG(s, "E") self.firmware.m205(S, T, B, X, Z, E) return elif "M206" in s: X = self.parseG(s, "X") Y = self.parseG(s, "Y") Z = self.parseG(s, "Z") self.firmware.m206(X, Y, Z) return elif "M301" in s: P = self.parseG(s, "P") I = self.parseG(s, "I") D = self.parseG(s, "D") self.firmware.m301(P, I, D) return elif ( ("Steps per unit" in s) or ("Acceleration:" in s) or ("Maximum Acceleration" in s) or ("Maximum feedrates" in s) or ("Advanced variables" in s) or ("Home offset" in s) or ("PID settings" in s) or ("Stored settings retreived" in s) ): return if self.sdchecking: if "SD card ok" in s: self.sdchecking = False self.sdpresent = True self.sd.sdCheckComplete(True) return elif "SD init fail" in s: self.sdchecking = False self.sdpresent = False self.sd.sdCheckComplete(False) return if self.sdlisting: if "Begin file list" in s: self.insidelisting = True self.sdfiles = [] return elif "End file list" in s: self.sdlisting = False self.insidelisting = False self.sd.sdListComplete(self.sdfiles) return else: if self.insidelisting: self.sdfiles.append(s.strip()) return if "SD printing byte" in s: m = self.sdre.search(s) t = m.groups() if len(t) != 2: return self.sdbytes = int(t[0]) self.sdmaxbytes = int(t[1]) return elif "Done printing file" in s: if self.sdprinting: self.sdprinting = False self.toolbar.clearSDPrint() m = self.speedrptre.search(s) if m: t = m.groups() if len(t) >= 3: if self.settings.forcefanspeed: ns = int(t[0]) if ns != self.FanSpeed: self.logger.logMsg("Asserting fan speed of %d" % self.FanSpeed) self.toolbar.forceFanSpeed(self.FanSpeed) else: self.FanSpeed = int(t[0]) self.FeedMultiply = int(t[1]) self.ExtrudeMultiply = int(t[2]) self.toolbar.syncSpeeds() if self.speedcount > 0: self.speedcount -= 1 return m = self.locrptre.search(s) if m: t = m.groups() if len(t) >= 4: self.location[XAxis] = float(t[0]) self.location[YAxis] = float(t[1]) self.location[ZAxis] = float(t[2]) self.location[EAxis] = float(t[3]) if self.m114count != 0: self.m114count -= 1 if self.m114count < 0: self.m114count = 0 return if s.startswith("ok"): return if s.startswith("echo:"): s = s[5:] m = self.rpt1re.search(s) if m: t = m.groups() if len(t) >= 1: self.exttemp = float(t[0]) if len(t) >= 2: self.bedtemp = float(t[1]) self.temps.updateTempDisplay(self.bedtemp, self.exttemp) m = self.rpt2re.search(s) if m: t = m.groups() if len(t) >= 1: self.exttemp = float(t[0]) self.temps.updateTempDisplay(self.bedtemp, self.exttemp) self.logger.logMsg(s.rstrip()) def parseG(self, s, v): l = s.split() for p in l: if p.startswith(v): try: return float(p[1:]) except: return None return None def editSettings(self): # TO DO pass def slic3rSettings(self): s = self.replace(self.settings.s3config, SLIC3R) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def skeinforgeSettings(self): s = self.replace(self.settings.sfconfig, SKEINFORGE) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) def chooseS3Profile(self): pl = self.slic3r.getProfileOptions() if len(pl) > 0: l = ListBoxChoice( clist=pl.keys(), master=self, title="Choose Slic3r Profile", message="Choose Slic3r profile" ) pn = l.returnValue() if pn: self.slic3r.setProfile(pn) self.setS3ProfileMenuText() self.toolbar.setSliceText() else: self.logger.logMsg("Unable to retrieve available slic3r profiles") def chooseSFProfile(self): pl = self.skeinforge.getProfileOptions() if len(pl) > 0: l = ListBoxChoice( clist=pl.keys(), master=self, title="Choose Skeinforge Profile", message="Choose Skeinforge profile" ) pn = l.returnValue() if pn: self.skeinforge.setProfile(pn) self.setSFProfileMenuText() self.toolbar.setSliceText() else: self.logger.logMsg("Unable to retrieve available skeinforge profiles") def setS3ProfileMenuText(self): self.slicermenu.entryconfig(self.S3profileindex, label="Choose Profile (%s)" % self.slic3r.getProfile()) def setSFProfileMenuText(self): self.slicermenu.entryconfig(self.SFprofileindex, label="Choose Profile (%s)" % self.skeinforge.getProfile()) def quitApp(self): self.cleanUp() self.master.quit() def cleanUp(self): if self.connected: self.printer.disconnect() if self.slicing: self.slicerCancel = True self.httpServer.close() self.statline.cleanUp() self.settings.cleanUp() def doEditMacro(self): idir = os.path.join(self.settings.cmdFolder, "macros") try: l = os.listdir(idir) except: self.logger.logMsg("Unable to get listing from macros directory: " + idir) return r = [] for f in sorted(l): if f.endswith(".macro"): r.append(f) l = ListBoxChoice(master=self, title="Macro Files", message="Choose a macro to edit", clist=r) fn = l.returnValue() if fn: try: fn = os.path.join(idir, fn) with open(fn) as f: text = f.read() self.macroEdit = MacroEdit(self, self.printer, self.settings, self.logger, fn, text) except: self.logger.logMsg("Unable to open %s for input" % fn) def doEditAlterations(self): idir = os.path.expandvars(os.path.expanduser(self.settings.sfalterationsdir)) try: l = os.listdir(idir) except: self.logger.logMsg("Unable to get listing from alterations directory: " + idir) return r = [] for f in sorted(l): if f.endswith(".gcode"): r.append(f) l = ListBoxChoice(master=self, title="Alteration Files", message="Choose an alteration file to edit", clist=r) fn = l.returnValue() if fn: try: fn = os.path.join(idir, fn) text = [line.strip() for line in open(fn)] GEditor(self, text, fn) except: self.logger.logMsg("Unable to open %s for input" % fn) def doNewMacro(self): self.macroEdit = MacroEdit(self, self.printer, self.settings, self.logger, None, "") def doDelMacro(self): idir = os.path.join(self.settings.cmdFolder, "macros") try: l = os.listdir(idir) except: self.logger.logMsg("Unable to get listing from macros directory: " + idir) return r = [] for f in sorted(l): if f.endswith(".macro"): r.append(f) l = ListBoxChoice(master=self, title="Macro Files", message="Choose a macro to delete", clist=r) fn = l.returnValue() if fn: if askyesno("Delete?", "Are you sure you want to delete this macro?", parent=self): try: os.unlink(os.path.join(idir, fn)) self.adjustMacroMenu(fn, True) if self.settings.getMacroList().delMacroByName(fn): self.settings.setModified() if self.settings.showmacrobuttons: self.macroButtons.close() self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger) except: self.logger.logMsg("Unable to delete %s" % fn) def macroEditSave(self, fn, text, btn, editwindow): if fn == None: idir = os.path.join(self.settings.cmdFolder, "macros") try: l = os.listdir(idir) except: self.logger.logMsg("Unable to get listing from macros directory: " + idir) return r = [] for f in sorted(l): if f.endswith(".macro"): r.append(f) l = ListBoxChoice( master=self, title="Macro Files", message="Choose a macro to overwrite", clist=r, newmessage="or enter new file name:", ) fn = l.returnValue() if fn: fn = os.path.join(idir, fn) if not fn.endswith(".macro"): fn += ".macro" if fn is None: return False try: f = open(fn, "w") f.write(text) f.close() self.settings.setModified() if btn != None: if not self.settings.getMacroList().addMacro(btn[0], btn[1], os.path.basename(fn), btn[2]): self.settings.getMacroList().setMacroByName(btn[0], btn[1], os.path.basename(fn), btn[2]) self.settings.setModified() if self.settings.showmacrobuttons: self.macroButtons.close() self.macroButtons = MacroButtons(self, self.printer, self.settings, self.logger) self.adjustMacroMenu(fn) self.logger.logMsg("Macro %s successfully saved" % fn) return True except: self.logger.logMsg("Unable to open %s for output" % fn) return False def macroEditExit(self, fn): pass def loadMacros(self): p = os.path.join(".", "macros") if not os.path.exists(p): os.makedirs(p) self.macroList = {} for filename in sorted(os.listdir(p)): if filename.endswith(".macro"): n = os.path.splitext(filename)[0] self.macroList[n] = 1 self.runmacromenu.add_command(label=n, command=lambda m=n: self.doMacro(m)) def adjustMacroMenu(self, fn, delete=False): mn = os.path.splitext(os.path.basename(fn))[0] if not delete: if mn in self.macroList: # nothing to be done here pass else: self.macroList[mn] = 1 self.runmacromenu.add_command(label=mn, command=lambda m=mn: self.doMacro(name=mn)) else: # delete the menu entry if mn in self.macroList: self.runmacromenu.delete(self.runmacromenu.index(mn)) del self.macroList[mn] else: # huh?? pass def doMacro(self, name=None, fname=None, silent=False): if name: if not silent: self.logger.logMsg("Invoking macro: %s" % name) n = os.path.join(self.settings.cmdFolder, "macros", name + ".macro") elif fname: if not silent: self.logger.logMsg("Invoking macro file: %s" % fname) n = os.path.join(self.settings.cmdFolder, "macros", fname) else: self.logger.logMsg("Error - must provide a macro name or filename") return try: l = list(open(n)) for s in l: sl = s.lower() if sl.startswith("@log "): self.logger.logMsg(self.replace(s[5:].strip(), self.settings.slicer)) elif sl.startswith("@sh "): s = self.replace(sl[4:], self.settings.slicer) args = shlex.split(os.path.expandvars(os.path.expanduser(s))) subprocess.Popen(args, close_fds=True) else: verb = s.split()[0] if self.printerAvailable(cmd=verb): self.printer.send_now(s) else: self.logger.logMsg("Printer not available for %s command" % verb) if not silent: self.logger.logMsg("End of macro") except: self.logger.logMsg("Error attempting to invoke macro file %s" % n) def FirmwareSettings(self): if self.connected: if not self.firmware.isActive(): self.firmware.start() else: self.logger.logMsg("Unable to comply - printer not on-line") def doDataLogReport(self): for d in DLLIST: self.logger.logMsg("%s Usage: %s" % (DLNAMES[d], self.dataLoggers[d].getToNowStr())) def doDataLogReset(self): DataLogReset(self)
class PrintMonitor(wx.Panel): def __init__(self, parent, app, prtname, reprap, history): self.model = None self.cfgString = None self.app = app self.prtsettings = self.app.settings.printersettings[prtname] self.buildarea = self.prtsettings.buildarea self.prtname = prtname self.history = history self.reprap = reprap self.manctl = None self.hassd = self.prtsettings.hassdcard self.filamentdiameter = self.prtsettings.filamentdiam self.sliceTime = "" self.M105pending = False self.M27pending = False self.suspendM105 = False self.cycle = 0 self.skipCycles = 5 self.logger = self.app.logger self.printPos = 0 self.printing = False self.paused = False self.sdpaused = False self.sdprintingfrom = False self.settings = app.settings.printmon wx.Panel.__init__(self, parent, wx.ID_ANY, size=(100, 100)) self.SetBackgroundColour("white") self.knownHeaters = ['HE0', 'HE1', 'HE2', 'Bed'] self.targets = {} self.temps = {} self.tempData = {} for h in self.knownHeaters: self.temps[h] = None self.targets[h] = 0 self.tempData[h] = [] self.startTime = None self.endTime = None self.gcFile = None self.printMode = None self.origEta = None self.countGLines = None self.syncPrint = True self.holdFan = False self.setStatus(PMSTATUS_NOT_READY) self.sdcard = SDCard(self.app, self, self.reprap, self.logger) self.M27Timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onM27Timer, self.M27Timer) self.printingfrom = False self.sizerMain = wx.BoxSizer(wx.HORIZONTAL) self.sizerLeft = wx.BoxSizer(wx.VERTICAL) self.sizerRight = wx.BoxSizer(wx.VERTICAL) self.sizerLeft.AddSpacer((10,10)) self.sizerBtns = wx.BoxSizer(wx.HORIZONTAL) self.sizerBtns.AddSpacer((10,10)) self.images = Images(os.path.join(self.settings.cmdfolder, "images")) self.bPull = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPull, size=BUTTONDIMWIDE) self.sizerBtns.Add(self.bPull) self.bPull.SetToolTipString("Pull model from file preparation") self.Bind(wx.EVT_BUTTON, self.doPull, self.bPull) self.bPull.Enable(self.app.currentPullStatus()) self.sizerBtns.AddSpacer((20, 20)) self.bPrint = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPrint, size=BUTTONDIM) self.setPrintMode(PRINT_MODE_PRINT) self.sizerBtns.Add(self.bPrint) self.Bind(wx.EVT_BUTTON, self.doPrint, self.bPrint) self.bPrint.Enable(False) self.bPause = wx.BitmapButton(self, wx.ID_ANY, self.images.pngPause, size=BUTTONDIM) self.setPauseMode(PAUSE_MODE_PAUSE) self.sizerBtns.Add(self.bPause) self.Bind(wx.EVT_BUTTON, self.doPause, self.bPause) self.bPause.Enable(False) self.sizerBtns.AddSpacer(BUTTONDIM) if self.hassd: self.bSDPrintFrom = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintfrom, size=BUTTONDIMWIDE) self.bSDPrintFrom.SetToolTipString("Print from SD Card") self.sizerBtns.Add(self.bSDPrintFrom) self.Bind(wx.EVT_BUTTON, self.doSDPrintFrom, self.bSDPrintFrom) self.bSDPrintFrom.Enable(True) self.bSDPrintTo = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSdprintto, size=BUTTONDIMWIDE) self.bSDPrintTo.SetToolTipString("Print to SD Card") self.sizerBtns.Add(self.bSDPrintTo) self.Bind(wx.EVT_BUTTON, self.doSDPrintTo, self.bSDPrintTo) self.bSDPrintTo.Enable(False) self.bSDDelete = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSddelete, size=BUTTONDIM) self.bSDDelete.SetToolTipString("Delete a file from SD Card") self.sizerBtns.Add(self.bSDDelete) self.Bind(wx.EVT_BUTTON, self.doSDDelete, self.bSDDelete) self.bSDDelete.Enable(True) self.sizerBtns.AddSpacer(BUTTONDIM) self.bZoomIn = wx.BitmapButton(self, wx.ID_ANY, self.images.pngZoomin, size=BUTTONDIM) self.bZoomIn.SetToolTipString("Zoom the view in") self.sizerBtns.Add(self.bZoomIn) self.Bind(wx.EVT_BUTTON, self.viewZoomIn, self.bZoomIn) self.bZoomOut = wx.BitmapButton(self, wx.ID_ANY, self.images.pngZoomout, size=BUTTONDIM) self.bZoomOut.SetToolTipString("Zoom the view out") self.sizerBtns.Add(self.bZoomOut) self.Bind(wx.EVT_BUTTON, self.viewZoomOut, self.bZoomOut) self.sizerLeft.Add(self.sizerBtns) self.sizerLeft.AddSpacer((10,10)) self.sizerGCM = wx.BoxSizer(wx.HORIZONTAL) self.gcf = GcmFrame(self, self.model, self.settings, self.buildarea) self.sizerGCM.Add(self.gcf) sz = self.buildarea[1] * self.settings.gcodescale self.slideLayer = wx.Slider( self, wx.ID_ANY, 1, 1, 9999, size=(150, sz), style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | wx.SL_LABELS) self.slideLayer.Bind(wx.EVT_SCROLL, self.onSpinLayer) self.slideLayer.SetRange(1, 10) self.slideLayer.SetValue(1) self.slideLayer.SetPageSize(1); self.slideLayer.Disable() self.sizerGCM.Add(self.slideLayer) self.sizerLeft.Add(self.sizerGCM) self.sizerLeft.AddSpacer((10,10)) self.sizerOpts = wx.BoxSizer(wx.HORIZONTAL) self.cbPrevious = wx.CheckBox(self, wx.ID_ANY, "Show Previous Layer") self.cbPrevious.SetToolTipString("Turn on/off drawing of the previous layer in the background") self.Bind(wx.EVT_CHECKBOX, self.checkPrevious, self.cbPrevious) self.cbPrevious.SetValue(self.settings.showprevious) self.sizerOpts.Add(self.cbPrevious) self.sizerOpts.AddSpacer((10, 10)) self.cbMoves = wx.CheckBox(self, wx.ID_ANY, "Show Moves") self.cbMoves.SetToolTipString("Turn on/off the drawing of non-extrusion moves") self.Bind(wx.EVT_CHECKBOX, self.checkMoves, self.cbMoves) self.cbMoves.SetValue(self.settings.showmoves) self.sizerOpts.Add(self.cbMoves) self.sizerOpts.AddSpacer((10, 10)) self.cbToolOnly = wx.CheckBox(self, wx.ID_ANY, "Tool Path Only") self.cbToolOnly.SetToolTipString("Show narrow lines indicating tool path") self.Bind(wx.EVT_CHECKBOX, self.checkToolPathsOnly, self.cbToolOnly) self.cbToolOnly.SetValue(self.settings.toolpathsonly) self.sizerOpts.Add(self.cbToolOnly) self.sizerOpts.AddSpacer((10, 10)) self.cbSync = wx.CheckBox(self, wx.ID_ANY, "Sync with print") self.Bind(wx.EVT_CHECKBOX, self.checkSync, self.cbSync) self.cbSync.SetValue(True) self.sizerOpts.Add(self.cbSync) self.sizerLeft.AddSpacer((5, 5)) self.sizerLeft.Add(self.sizerOpts) self.sizerOpts2 = wx.BoxSizer(wx.HORIZONTAL) self.cbBuffDC = wx.CheckBox(self, wx.ID_ANY, "Use Buffered DC") self.Bind(wx.EVT_CHECKBOX, self.checkBuffDC, self.cbBuffDC) self.cbBuffDC.SetValue(self.settings.usebuffereddc) self.sizerOpts2.Add(self.cbBuffDC) self.sizerOpts2.AddSpacer((10, 10)) self.cbHoldFan = wx.CheckBox(self, wx.ID_ANY, "Hold Fan Speed") self.cbHoldFan.SetToolTipString("Maintain fan speed at its manual setting") self.Bind(wx.EVT_CHECKBOX, self.checkHoldFan, self.cbHoldFan) self.cbHoldFan.SetValue(self.holdFan) self.sizerOpts2.Add(self.cbHoldFan) self.sizerLeft.AddSpacer((5, 5)) self.sizerLeft.Add(self.sizerOpts2) self.sizerLeft.AddSpacer((10,10)) self.sizerRight.AddSpacer((40,40)) self.gTemp = TempGraph(self, self.settings) self.sizerRight.Add(self.gTemp) self.sizerRight.AddSpacer((20, 20)) self.infoPane = InfoPane(self, self.app) self.sizerRight.Add(self.infoPane, flag=wx.EXPAND) self.sizerMain.AddSpacer((50,50)) self.sizerMain.Add(self.sizerLeft) self.sizerMain.Add(self.sizerRight) self.SetSizer(self.sizerMain) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onTimer, self.timer) self.secCounter = 0 self.openFpLog() self.timer.Start(1000) self.reprap.setHoldFan(self.holdFan) self.Bind(EVT_HTTP_PRINTMON, self.httpRequest) self.infoPane.setMode(MODE_NORMAL) self.setSDTargetFile(None) def openFpLog(self): self.fnLog = os.path.join(self.app.settings.lastlogdirectory, "temps" + self.prtname + ".log") self.logger.LogMessage("Log file %s opened for recording %s temperatures" % (self.fnLog, self.prtname)) self.fpLog = open(self.fnLog, "a") self.lastLogDate = "" def newFpLogVersion(self): try: os.unlink(self.fnLog + ".old") self.logger.LogMessage("Old temperature log file (%s.old) deleted" % self.fnLog) except: pass self.fpLog.close() os.rename(self.fnLog, self.fnLog+".old") self.logger.LogMessage("Archiving temperature log %s as %s.old" % (self.fnLog, self.fnLog)) self.openFpLog() def setManCtl(self, mc): self.manctl = mc; def pendantCommand(self, cmd): c = cmd.lower() if c in pendantCmds.keys(): mcmd = pendantCmds[c] if mcmd == "@print": self.emulatePrintButton() elif mcmd == "@pause": self.emulatePauseButton() else: return False # command not handled else: return False # command not handled return True # command handled def assertAllowPulls(self, flag): if not self.isPrinting(): self.bPull.Enable(flag) def tick(self): if self.skipCycles >= 0: self.skipCycles -= 1 return self.cycle += 1 if self.cycle % TEMPINTERVAL == 0: if self.suspendM105: self.M105pending = False elif not self.M105pending: self.M105pending = True self.reprap.send_now("M105", True) if self.cycle % POSITIONINTERVAL == 0: n = self.reprap.getPrintPosition() if n is not None: self.printPosition = n self.updatePrintPosition(n) def suspendTempProbe(self, flag): self.suspendM105 = flag def prtMonEvent(self, evt): if evt.event == SD_PRINT_POSITION: if self.sdprintingfrom: if evt.pos < evt.max: self.infoPane.setSDPrintInfo(evt.pos, evt.max) self.M27Timer.Start(M27Interval, True) return if evt.event == SD_PRINT_COMPLETE: self.history.SDPrintFromComplete(self.prtname) self.endTime = time.time() self.infoPane.setSDPrintComplete() self.sdprintingfrom = False self.printing = False self.paused = False if self.hasFileLoaded(): self.setStatus(PMSTATUS_READY) self.bPrint.Enable(True) else: self.setStatus(PMSTATUS_NOT_READY) self.bPrint.Enable(False) self.reprap.printComplete() self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(False) self.bSDPrintFrom.Enable(True) self.bSDPrintTo.Enable(self.hasFileLoaded()) self.bSDDelete.Enable(True) self.logger.LogMessage("SD Print completed at %s" % time.strftime('%H:%M:%S', time.localtime(self.endTime))) self.logger.LogMessage("Total elapsed time: %s" % formatElapsed(self.endTime - self.sdStartTime)) self.updatePrintPosition(0) return def setStatus(self, s): self.status = s self.app.updatePrintMonStatus(self.prtname, s) def isPrinting(self): return self.printing or self.sdprintingfrom def getStatus(self): if self.printing or self.sdprintingfrom: status = self.infoPane.getStatus() status['printing'] = "True" else: status = {} status['printing'] = "False" return status def hasFileLoaded(self): return self.model is not None def getBedGCode(self): if not self.hasFileLoaded(): return None; i = 0 for l in self.model: if l.raw.startswith("M140 ") or l.raw.startswith("M190 "): if "S" in l.raw: temp = _get_float(l.raw, "S") return temp i += 1 if i >= SCANTHRESHOLD: return None def getHEGCode(self, tool): if not self.hasFileLoaded(): return None; i = 0 for l in self.model: if l.raw.startswith("M104 ") or l.raw.startswith("M109 "): t = 1 if "T" in l.raw: t = _get_float(l.raw, "T") if (t-1) == tool: if "S" in l.raw: temp = _get_float(l.raw, "S") return temp i += 1 if i >= SCANTHRESHOLD: return None def printerReset(self): self.printPos = 0 self.skipCycles = 5 self.M105pending = False self.printing = False self.paused = False self.sdpaused = False self.sdprintingfrom = False self.setStatus(PMSTATUS_READY) self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPrint.Enable(self.hasFileLoaded()) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(False) def clearModel(self): self.gcf.eraseGraph() self.slideLayer.SetValue(1) self.slideLayer.Enable(False) self.infoPane.clearFileInfo() self.infoPane.clearLayerInfo() self.model = None self.cfgString = None 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.setPrintMode(PRINT_MODE_PRINT) self.setStatus(PMSTATUS_PRINTING) self.sdcard.startPrintFromSD() def cancelSDPrintFrom(self): self.sdprintingfrom = False self.printing = False self.paused = False self.setStatus(PMSTATUS_READY) self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPrint.Enable(True) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(False) def resumeSDPrintFrom(self, fn): self.history.SDPrintFromStart("SD:" + fn[1].lower(), self.prtname) self.clearModel() self.reprap.send_now("M23 " + fn[1].lower()) self.reprap.send_now("M24") self.sdprintingfrom = True self.M27Timer.Start(M27Interval, True) self.bPrint.Enable(False) self.bPull.Enable(False) self.bSDPrintFrom.Enable(False) self.bSDPrintTo.Enable(False) self.bSDDelete.Enable(False) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPause.Enable(True) self.sdpaused = False self.infoPane.setMode(MODE_FROM_SD) def doSDPrintTo(self, evt): self.sdcard.startPrintToSD() def resumeSDPrintTo(self, tfn): self.history.SDPrintToStart("SD:" + tfn[1].lower(), self.prtname) self.setSDTargetFile(tfn[1].lower()) self.suspendTempProbe(True) self.reprap.send_now("M28 %s" % self.sdTargetFile) self.printPos = 0 self.startTime = time.time() self.endTime = None self.reprap.startPrint(self.model) self.logger.LogMessage("Print to SD: %s started at %s" % (self.sdTargetFile, time.strftime('%H:%M:%S', time.localtime(self.startTime)))) self.origEta = self.startTime + self.model.duration self.countGLines = len(self.model) self.infoPane.setMode(MODE_TO_SD) self.infoPane.showFileInfo() self.infoPane.setStartTime(self.startTime) self.bPrint.Enable(False) self.bPull.Enable(False) self.bPause.Enable(False) def setSDTargetFile(self, tfn): self.sdTargetFile = tfn self.infoPane.setSDTargetFile(tfn) def doSDDelete(self, evt): self.sdcard.startDeleteFromSD() def reprapEvent(self, evt): if evt.event in [ PRINT_STARTED, PRINT_RESUMED ]: self.printing = True self.setStatus(PMSTATUS_PRINTING) self.paused = False self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPrint.Enable(False) self.bPull.Enable(False) self.bPause.Enable(True) if self.hassd: self.bSDPrintFrom.Enable(False) self.bSDPrintTo.Enable(False) self.bSDDelete.Enable(False) elif evt.event in [PRINT_STOPPED, PRINT_AUTOSTOPPED]: self.paused = True self.setStatus(PMSTATUS_PAUSED) self.printing = False self.reprap.printStopped() self.setPrintMode(PRINT_MODE_RESTART) self.setPauseMode(PAUSE_MODE_RESUME) self.bPrint.Enable(True) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(True) if self.hassd: self.bSDPrintFrom.Enable(True) self.bSDPrintTo.Enable(True) self.bSDDelete.Enable(True) if evt.event == PRINT_AUTOSTOPPED: self.logger.LogMessage(evt.msg) elif evt.event == PRINT_COMPLETE: self.endTime = time.time() self.infoPane.setPrintComplete() if self.sdTargetFile is not None: self.history.SDPrintToComplete(self.prtname) self.reprap.send_now("M29 %s" % self.sdTargetFile) self.suspendTempProbe(False) self.setSDTargetFile(None) else: self.history.PrintComplete(self.prtname) self.printing = False self.paused = False self.setStatus(PMSTATUS_READY) self.reprap.printComplete() self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPrint.Enable(True) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(False) if self.hassd: self.bSDPrintFrom.Enable(True) self.bSDPrintTo.Enable(True) self.bSDDelete.Enable(True) self.logger.LogMessage("Print completed at %s" % time.strftime('%H:%M:%S', time.localtime(self.endTime))) self.logger.LogMessage("Total elapsed time: %s" % formatElapsed(self.endTime - self.startTime)) rs, rq = self.reprap.getCounters() if rs + rq != 0: self.logger.LogMessage("Resend Requests: %d, messages retransmitted: %d" % (rq, rs)) self.updatePrintPosition(0) elif evt.event == PRINT_ERROR: self.logger.LogError(evt.msg) self.app.doPrinterError(self.prtname) elif evt.event == PRINT_MESSAGE: if evt.immediate: self.logger.LogMessage(evt.msg) elif evt.primary: self.logger.LogCMessage(evt.msg) else: self.logger.LogGMessage(evt.msg) elif evt.event == QUEUE_DRAINED: self.logger.LogMessage("Print Queue drained") self.reprap.reprapEvent(evt) else: self.reprap.reprapEvent(evt) def getPrintTimes(self): return self.startTime, self.endTime def onM27Timer(self, evt): if not self.M27pending and not self.sdpaused: self.M27pending = True self.reprap.send_now("M27") def setPrintMode(self, mode): self.printMode = mode if mode == PRINT_MODE_PRINT: self.bPrint.SetToolTipString("Start the print") self.bPrint.SetBitmapLabel(self.images.pngPrint) elif mode == PRINT_MODE_RESTART: self.bPrint.SetToolTipString("Restart the print") self.bPrint.SetBitmapLabel(self.images.pngRestart) def setPauseMode(self, mode): if mode == PAUSE_MODE_PAUSE: self.bPause.SetToolTipString("Pause the print") elif mode == PAUSE_MODE_RESUME: self.bPause.SetToolTipString("Resume the print from the paused point") def emulatePrintButton(self): if self.bPrint.IsEnabled(): if not self.manctl is None: self.manctl.disengageZ() self.doPrint(None) else: self.logger.LogMessage("Print button currently disabled") def doPrint(self, evt): if self.sdpaused: self.reprap.send_now("M26 S0") self.setPauseMode(PAUSE_MODE_PAUSE) self.setPrintMode(PRINT_MODE_PRINT) self.bPrint.Enable(False) self.bPull.Enable(False) self.sdprintingfrom = True self.reprap.send_now("M24") self.infoPane.setSDStartTime(time.time()) self.M27Timer.Start(M27Interval, True) else: self.printPos = 0 self.startTime = time.time() self.endTime = None if self.printMode == PRINT_MODE_RESTART: action = "restarted" self.reprap.restartPrint(self.model) else: self.history.PrintStart(self.gcFile, self.prtname) action = "started" self.reprap.startPrint(self.model) self.logger.LogMessage("Print %s at %s" % (action, time.strftime('%H:%M:%S', time.localtime(self.startTime)))) self.origEta = self.startTime + self.model.duration self.logger.LogMessage("ETA at %s (%s)" % (time.strftime('%H:%M:%S', time.localtime(self.startTime+self.model.duration)), formatElapsed(self.model.duration))) self.countGLines = len(self.model) self.infoPane.setMode(MODE_NORMAL) self.infoPane.setStartTime(self.startTime) self.infoPane.showFileInfo() self.bPrint.Enable(False) self.bPull.Enable(False) self.bPause.Enable(False) self.setSDTargetFile(None) def emulatePauseButton(self): if self.sdTargetFile is not None: self.logger.LogMessage("Unable to pause print to SD - use GUI") elif self.bPause.IsEnabled(): if not self.manctl is None: self.manctl.disengageZ() self.doPause(None) else: self.logger.LogMessage("Pause button currently disabled") def doPause(self, evt): if self.sdTargetFile is not None: msgdlg = wx.MessageDialog(self.app, "Are you sure you want to terminate this job", 'Confirm', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) rc = msgdlg.ShowModal() msgdlg.Destroy() if rc == wx.ID_YES: self.stopPrintToSD() elif self.sdprintingfrom or self.sdpaused: if self.sdpaused: self.reprap.send_now("M24") self.setPauseMode(PAUSE_MODE_PAUSE) self.setPrintMode(PRINT_MODE_PRINT) self.bPrint.Enable(False) self.bPull.Enable(False) self.sdprintingfrom = True self.M27Timer.Start(M27Interval, True) self.setStatus(PMSTATUS_PRINTING) self.sdpaused = False else: self.stopPrintFromSD() self.setStatus(PMSTATUS_PAUSED) else: if self.paused: self.bPause.Enable(False) self.bPrint.Enable(False) self.bPull.Enable(False) self.reprap.resumePrint() else: self.stopPrintNormal() def stopPrintToSD(self): self.reprap.pausePrint() self.reprap.send_now("M29 %s" % self.sdTargetFile) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPause.Enable(False) self.setPrintMode(PRINT_MODE_PRINT) self.bPrint.Enable(self.hasFileLoaded()) self.bPull.Enable(self.app.currentPullStatus()) self.bSDPrintFrom.Enable(True) self.bSDPrintTo.Enable(True) self.bSDDelete.Enable(True) self.setSDTargetFile(None) self.suspendTempProbe(False) def stopPrintFromSD(self): self.reprap.send_now("M25") self.setPauseMode(PAUSE_MODE_RESUME) self.setPrintMode(PRINT_MODE_PRINT) self.bPrint.Enable(False) self.bSDPrintFrom.Enable(True) self.bPull.Enable(self.app.currentPullStatus()) self.sdprintingfrom = False self.sdpaused = True def stopPrintNormal(self): self.bPause.Enable(False) self.bPrint.Enable(False) self.bPull.Enable(False) self.reprap.pausePrint() def stopMotorsAndHeaters(self): self.reprap.send_now("M84") self.reprap.send_now("M106 S0") self.reprap.send_now("M140 S0") for h in self.knownHeaters: if h.startswith("HE"): self.reprap.send_now("M104 S0 T" + h[2]) def updatePrintPosition(self, pos): if self.printing: if pos != self.printPos: self.printPos = pos newLayer = self.gcf.setPrintPosition(self.printPos, self.syncPrint) if newLayer and not self.syncPrint: self.infoPane.updateUntilTime() l = self.model.findLayerByLine(pos) gcl = None lt = None if l is not None: gcl = self.model.layerlines[l] lt = self.model.layer_time[l] self.infoPane.setPrintInfo(pos, l, gcl, lt) def onSpinLayer(self, evt): l = evt.EventObject.GetValue()-1 self.gcf.setLayer(l) self.setLayer(l) def setLayer(self, l): if l >=0 and l < self.layerCount: self.slideLayer.SetValue(l+1) (zh, xymin, xymax, filament, glines, time, filstart) = self.model.getLayerInfo(l) self.infoPane.setLayerInfo(l, zh, xymin, xymax, filament, filstart, time, glines) if self.model.checkPendingPause(l+1): # TODO Pending Pause at start of this layer pass plines = self.model.checkImmediatePause(l+1) if len(plines) > 0: # TODO ct Immediate Pauses on this layer pass def onClose(self, evt): if self.fpLog is not None: self.logger.LogMessage("Log file for %s temperatures closed" % self.prtname) self.fpLog.close() self.fpLog = None self.timer.Stop() self.lastLogDate = "" return True def viewZoomIn(self, evt): self.gcf.zoomIn() def viewZoomOut(self, evt): self.gcf.zoomOut() def checkSync(self, evt): self.syncPrint = evt.IsChecked() def checkBuffDC(self, evt): self.settings.usebuffereddc = evt.IsChecked() self.settings.setModified() self.gcf.redrawCurrentLayer() def checkToolPathsOnly(self, evt): self.settings.toolpathsonly = evt.IsChecked() self.settings.setModified() self.gcf.setToolPathsOnly(self.settings.toolpathsonly) self.gcf.redrawCurrentLayer() def checkHoldFan(self, evt): self.holdFan = evt.IsChecked() self.reprap.setHoldFan(self.holdFan) def checkPrevious(self, evt): self.settings.showprevious = evt.IsChecked() self.settings.setModified() self.gcf.redrawCurrentLayer() def checkMoves(self, evt): self.settings.showmoves = evt.IsChecked() self.settings.setModified() self.gcf.redrawCurrentLayer() def doPull(self, evt): self.setStatus(PMSTATUS_NOT_READY) self.app.pullGCode(self, self.prtsettings.acceleration, self.prtsettings.retractiontime) def forwardModel(self, model, name="", cfg=None, fd=None, tp=None, st=""): self.setSDTargetFile(None) self.setStatus(PMSTATUS_NOT_READY) self.reprap.clearPrint() self.model = model self.name = name self.cfgString = cfg self.modelFilamentDiam = fd self.tempProfile = tp self.sliceTime = st if self.name == TEMPFILELABEL: self.gcFile = None elif len(self.name) > 40: self.gcFile = self.name self.name = os.path.basename(self.gcFile) else: self.gcFile = self.name layer = 0 self.layerCount = self.model.countLayers() self.layerInfo = self.model.getLayerInfo(layer) if self.layerInfo is None: return self.slideLayer.SetRange(1, self.layerCount) n = int(self.layerCount/20) if n<1: n=1 self.slideLayer.SetTickFreq(n, 1) self.slideLayer.SetPageSize(1); self.slideLayer.Enable() self.slideLayer.Refresh() self.gcf.loadModel(self.model, layer=layer) self.enableButtons() self.printPos = 0 self.printing = False self.paused = False self.setPrintMode(PRINT_MODE_PRINT) self.setPauseMode(PAUSE_MODE_PAUSE) self.bPrint.Enable(self.hasFileLoaded()) self.bPull.Enable(self.app.currentPullStatus()) self.bPause.Enable(False) if self.hassd: self.bSDPrintFrom.Enable(True) self.bSDPrintTo.Enable(self.hasFileLoaded()) self.bSDDelete.Enable(True) self.sdprintingfrom = False self.sdpaused = False self.setStatus(PMSTATUS_READY) self.infoPane.setFileInfo(self.name, self.cfgString, self.modelFilamentDiam, self.tempProfile, self.sliceTime, self.model.duration, len(self.model), self.layerCount, self.model.zmax, self.model.total_e, self.model.layer_time) self.setLayer(layer) if self.modelFilamentDiam is None: dlg = wx.MessageDialog(self, "Model sliced with unknown filament\nPrinter filament diameter = %s" % ", ".join(["%.2f" % x for x in self.filamentdiameter]), 'Unknown filament diameter', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: unequal = False if len(self.modelFilamentDiam) != len(self.filamentdiameter): unequal = True else: for i in range(len(self.modelFilamentDiam)): if self.modelFilamentDiam[i] != self.filamentdiameter[i]: unequal = True if unequal: dlg = wx.MessageDialog(self, "Model sliced with diameter = %s\nPrinter filament diameter = %s" % (", ".join(["%.2f" % x for x in self.modelFilamentDiam]), ", ".join(["%.2f" % x for x in self.filamentdiameter])), 'Unequal filament diameters', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def setHETarget(self, tool, temp): key = 'HE' + str(tool) self.targets[key] = temp self.gTemp.setTargets(self.targets) def setHETemp(self, tool, temp): key = 'HE' + str(tool) self.temps[key] = temp def setBedTarget(self, temp): self.targets['Bed'] = temp self.gTemp.setTargets(self.targets) def setBedTemp(self, temp): self.temps['Bed'] = temp def getTemps(self): temps = {} temps['temps'] = self.temps temps['targets'] = self.targets return temps def onTimer(self, evt): for h in self.knownHeaters: if h in self.temps.keys(): self.tempData[h].append(self.temps[h]) else: self.tempData[h].append(None) l = len(self.tempData[h]) if l > MAXX: # 4 minutes data self.tempData[h] = self.tempData[h][l-MAXX:] self.gTemp.setTemps(self.tempData) if self.suspendM105: self.logTempMessage("temperature retrieval suspended\n") return self.secCounter += 1 if self.secCounter >= 60: self.secCounter = 0 self.logTempMessage(repr(self.temps) + '\n') def logTempMessage(self, msg): if self.fpLog is None: return t = time.localtime(time.time()) ymd = time.strftime('%y:%m:%d', t) if ymd != self.lastLogDate: self.fpLog.write("================================: " + ymd + '\n') self.lastLogDate = ymd tm = time.strftime('%H:%M:%S', t) self.fpLog.write(tm + ": " + msg) self.fpLog.flush() sz = self.fpLog.tell() if sz > FILELIMIT: self.newFpLogVersion() def enableButtons(self, flag=True): if flag: if self.model is not None: self.slideLayer.Enable(True) else: self.slideLayer.Enable(False) else: self.slideLayer.Enable(False) def stopPrint(self): evt = HttpEvent(cmd=HTTPPM_STOPPRINT) wx.PostEvent(self, evt) def httpRequest(self, evt): if evt.cmd == HTTPPM_STOPPRINT: if self.sdTargetFile is not None: self.stopPrintToSD() elif self.sdprintingfrom: self.stopPrintFromSD() self.stopMotorsAndHeaters() else: self.stopPrintNormal() self.stopMotorsAndHeaters()
mch = os.uname().machine if 'PCA10028' in mch: sck = Pin.board.P29 miso = Pin.board.P28 mosi = Pin.board.P25 cs = Pin.board.P16 elif 'PCA10040' in mch: sck = Pin.board.P25 miso = Pin.board.P24 mosi = Pin.board.P23 cs = Pin.board.P15 elif 'PCA10056' in mch: sck = Pin.board.P47 mosi = Pin.board.P45 miso = Pin.board.P46 cs = Pin.board.P37 # P1.05 elif 'PCA10090' in mch: sck = Pin.board.P13 miso = Pin.board.P12 mosi = Pin.board.P11 cs = Pin.board.P4 else: raise Exception('Board not supported!') spi = SPI(1, sck=sck, mosi=mosi, miso=miso) sd = SDCard(spi, cs) os.mount(sd, '/') print('testfile.txt' in os.listdir()) print([open("testfile.txt", "r").read()])
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)
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()
def mount_tf(self, mount_point="/"): sd = SDCard(SPI(0), Pin("A15", mode=Pin.OUT)) os.mount(sd, mount_point)