def addExtruder(self, nExtr): sizerExtrude = wx.BoxSizer(wx.VERTICAL) sizerExtrude.AddSpacer((10,10)) self.font12bold = wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) self.font16 = wx.Font(16, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) t = wx.StaticText(self, wx.ID_ANY, "Hot End(s)", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) sizerExtrude.Add(t, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) self.heWin = HotEnd(self, self.app, self.reprap, name=("Hot End 0", "Hot End 1", "Hot End 2"), shortname=snHotEnds, target=(self.standardHeTemp, self.standardHeTemp, self.standardHeTemp), trange=((20, 250), (20, 250), (20, 250)), nextr=nExtr) sizerExtrude.Add(self.heWin, flag=wx.LEFT | wx.EXPAND) sizerExtrude.AddSpacer((10,10)) t = wx.StaticText(self, wx.ID_ANY, "Extruder", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) sizerExtrude.Add(t, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) self.extWin = Extruder(self, self.app, self.reprap) sizerExtrude.Add(self.extWin, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) return sizerExtrude
def get_extruders(self): """ Populate extruder list :return: """ for i in range(len(self.extruder_name)): t = self.extruder_tool[i] name = self.extruder_name[i] ext = Extruder(t, name=name) ext.nozzle = self.extruder_diameter[i] if self.extruder_use_retract[i]: ext.retract = self.extruder_retract_dist[i] ext.retract_speed = self.extruder_retract_speed[i] ext.z_hop = self.extruder_zhop[i] if self.extruder_use_coasting[i]: ext.coasting = self.extruder_coasting[i] if self.extruder_use_wipe[i]: ext.wipe = self.extruder_wipe[i] ext.feed_rate_multiplier = self.extruder_multiplier[i] ext.extrusion_width = self.extruder_widths[i] self.extruders[t] = ext # go through the temperature names and try to assign them to extruders temp_setpoint_index = 0 for i in range(len(self.temperature_names)): t = self.temperature_numbers[i] if self.temperature_heated_bed[i] == 0: ext = self.extruders[t] ext.temperature_nr = t else: ext = None # need to parse all setpoints to keep proper indexing even with bed for j in range(self.temperature_setpoints[i]): if ext: layer_nr = self.temperature_setpoint_layers[temp_setpoint_index] ext.temperature_setpoints[layer_nr] = self.temperature_setpoint_temps[temp_setpoint_index] temp_setpoint_index += 1 # find proper setpoint temp last_setpoints = None for e in self.extruders: # setpoints if self.extruders[e].temperature_setpoints: last_setpoints = self.extruders[e].temperature_setpoints break # if not found, bad config if not last_setpoints: raise ValueError("Could not find valid temperature settings for extruder(s). Please check S3D profile") warning = False for e in self.extruders: if not self.extruders[e].temperature_setpoints: self.extruders[e].temperature_setpoints = last_setpoints warning = True # temp nr. Use tool number if not defined if self.extruders[e].temperature_nr is None: self.extruders[e].temperature_nr = self.extruders[e].tool # debug # for e in self.extruders: # print(self.extruders[e].temperature_nr, self.extruders[e].temperature_setpoints) if warning: self.log.info("Not all extruders have valid temperature definitions, using previous extruder values. Please check profile temperature settings")
def get_extruders(self): """ Populate extruder list :return: """ for i in range(len(self.extruder_name)): t = self.extruder_tool[i] name = self.extruder_name[i] ext = Extruder(t, name=name) ext.nozzle = self.extruder_diameter[i] if self.extruder_use_retract[i]: ext.retract = self.extruder_retract_dist[i] ext.retract_speed = self.extruder_retract_speed[i] ext.z_hop = self.extruder_zhop[i] if self.extruder_use_coasting[i]: ext.coasting = self.extruder_coasting[i] if self.extruder_use_wipe[i]: ext.wipe = self.extruder_wipe[i] ext.feed_rate_multiplier = self.extruder_multiplier[i] ext.temperature_nr = self.temperature_numbers[i] for j in range(self.temperature_setpoints[i]): index = self.temperature_setpoints[i] * i + j layer_nr = self.temperature_setpoint_layers[index] ext.temperature_setpoints[ layer_nr] = self.temperature_setpoint_temps[index] self.extruders[t] = ext
def parse_header(self): """ Parse Prusa Slic3r header and stuff for print settings :return: none """ z_offset = 0 brim = -1 for layer in self.layers: for cmd, comment in layer.lines: if cmd: continue if b" generated by Slic3r" in comment: # parse version try: m = self.VERSION_RE.match(comment) self.version = (int(m.groups()[0]), int(m.groups()[1]), int(m.groups()[2])) except Exception as e: self.log.exception("Version parsing exception: %s" % e) elif b" bed_shape =" in comment: #; bed_shape = 0x0,145x0,145x148,0x148 values = comment.split(b' = ')[1].split(b",") if len(values) == 4: self.settings.machine_type = TYPE_CARTESIAN self.settings.origin_offset_x = -float( values[0].split(b"x")[0]) self.settings.origin_offset_y = -float( values[0].split(b"x")[1]) self.settings.stroke_x = float(values[2].split( b"x")[0]) + self.settings.origin_offset_x self.settings.stroke_y = float(values[2].split( b"x")[1]) + self.settings.origin_offset_y else: self.settings.machine_type = TYPE_DELTA x = [] y = [] for v in values: vals = v.split(b"x") x.append(float(vals[0])) y.append(float(vals[1])) self.settings.stroke_x = max(x) - min(x) self.settings.stroke_y = max(y) - min(y) self.settings.origin_offset_x = self.settings.stroke_x / 2 self.settings.origin_offset_y = self.settings.stroke_y / 2 elif b" extrusion_multiplier =" in comment: values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].feed_rate_multiplier = float(d) tool += 1 elif b" external_perimeter_extrusion_width" in comment: # ; external_perimeter_extrusion_width = 0.45 self.settings.extrusion_width = float( comment.split(b" = ")[1]) # elif b"perimeters extrusion width" in comment: # self.perimeter_widths.append(float(comment.split(b"=")[1:].strip())) # elif b"infill extrusion width" in comment: # self.infill_widths.append(float(comment.split(b"=")[1:].strip())) # elif b"solid infill extrusion width" in comment: # self.solid_infill_widths.append(float(comment.split(b"=")[1:].strip())) # elif b"top infill extrusion width" in comment: # self.top_infill_widths.append(float(comment.split(b"=")[1:].strip())) elif b" filament_type =" in comment: # ; filament_type = PLA;PLA;PLA;PLA values = comment.split(b' = ')[1] tool = 0 for d in values.split(b";"): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].filament_type = d tool += 1 elif b" retract_length =" in comment: # ; retract_length = 3,3,3,3 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].retract = float(d) tool += 1 elif b" retract_lift =" in comment: # ; retract_lift = 0.5,0.5,0.5,0.5 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].z_hop = float(d) tool += 1 elif b" retract_speed =" in comment: # ; retract_speed = 80,80,80,80 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].retract_speed = 60 * float(d) tool += 1 elif b" use_relative_e_distances =" in comment: # ; use_relative_e_distances = 1 if comment.split(b' = ')[1] != b"1": raise ValueError( "Relative E distances not enabled! Filaswitch won't work without relative E distances" ) elif b" wipe = " in comment: # ; wipe = 1,1,1,1 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) if d == b"1": self.extruders[ tool].wipe = 4 # TODO: figure a way to read wipe length tool += 1 elif b" perimeter_speed =" in comment: # ; perimeter_speed = 40 self.settings.default_speed = float( comment.split(b' = ')[1]) * 60 elif b" external_perimeter_speed =" in comment: # ; external_perimeter_speed = 30 self.settings.outer_perimeter_speed = float( comment.split(b' = ')[1]) * 60 elif b" z_offset =" in comment: # ; z_offset = 0 self.settings.z_offset = float(comment.split(b' = ')[1]) elif b" first_layer_speed =" in comment: # ; first_layer_speed = 70% self.settings.first_layer_speed = float( comment.split(b' = ')[1].strip(b"%")) elif b" nozzle_diameter = " in comment: # ; nozzle_diameter = 0.4,0.4,0.4,0.4 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].nozzle = float(d) tool += 1 elif b" travel_speed =" in comment: # ; travel_speed = 120 self.settings.travel_xy_speed = float( comment.split(b' = ')[1]) * 60 elif b" layer_height =" in comment: # ; layer_height = 0.2 self.layer_height = float(comment.split(b' = ')[1]) elif b" first_layer_temperature =" in comment: # ; first_layer_temperature = 215,195,215,215 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].temperature_nr = tool self.extruders[tool].temperature_setpoints[1] = int(d) tool += 1 elif b" temperature =" in comment: # ; temperature = 215,195,215,215 values = comment.split(b' = ')[1] tool = 0 for d in values.split(b","): if tool not in self.extruders: self.extruders[tool] = Extruder(tool) self.extruders[tool].temperature_setpoints[2] = int(d) tool += 1 elif b" brim_width =" in comment: # ; brim_width = 3 brim = int(comment.split(b" = ")[1]) if not self.version: self.log.warning( "Could not detect Slic3r version. Use at your own risk!") else: self.log.info("Slic3r version %d.%d.%d" % self.version) self.settings.first_layer_speed = ( self.settings.first_layer_speed / 100) * self.settings.outer_perimeter_speed for t in self.extruders: self.extruders[t].z_offset = z_offset self.extruders[t].extrusion_width = self.settings.extrusion_width self.settings.travel_z_speed = self.settings.travel_xy_speed if self.settings.brim_auto and brim != -1: # Slic3r brim is in mm, convert to lines self.settings.brim = int(brim / self.settings.extrusion_width)
def parse_gcode_pass1(self): self._layers = OrderedDict() current_z = 0 last_print_z = 0 last_up_z_index = 0 head_move_index = None current_x = 0 current_y = 0 last_extrusion_x = None last_extrusion_y = None current_tool = None current_tool_temp = None tool_index = 0 add_tool = False self._retracts = {} self._z_speeds = [] self._travel_speeds = [] self._temperatures = {} e_pos = 0 e_speed = 0 layer_nr = 0 # find z-heights and tool changes index = 0 while True: try: cmd, comment = self.lines[index] except IndexError: break if comment: if comment.strip() == b"END SCRIPT START": break elif comment.strip() == b"START SCRIPT END": self.start_gcode_end = index last_up_z_index = index index += 1 self.insert_line(index, ActionPoint(ActionPoint.PREPRIME, None)) elif comment.strip() == b"START SCRIPT START": self.start_gcode_start = index # need command and one that's not in start gcode section if cmd is None: index += 1 continue elif self.start_gcode_start is not None and self.start_gcode_end is None: in_start_gcode = True else: in_start_gcode = False # temperature parsing if (gcode.is_temp_nowait(cmd) or gcode.is_temp_nowait_tool(cmd) or gcode.is_temp_wait(cmd) or gcode.is_temp_wait_tool(cmd)): if gcode.last_match[0] == 0: # remove temperature changes to 0 during print. Cura does # these, not good for single nozzle setups self.lines.pop(index) continue try: tool = gcode.last_match[1] except IndexError: tool = current_tool or 0 if tool not in self._temperatures: self._temperatures[tool] = {} self._temperatures[tool][layer_nr] = gcode.last_match[0] # find linear advance/pressure advance commands elif gcode.is_lin_advance(cmd) and gcode.last_match != 0: self.settings.linear_advance = gcode.last_match elif gcode.is_pressure_advance(cmd) and gcode.last_match[1] != 0: self.settings.pressure_advance = gcode.last_match if in_start_gcode: # skip rest of the parsing if in start gcode index += 1 continue # tool change elif gcode.is_tool_change(cmd) is not None: current_tool = gcode.last_match add_tool = True tool_index = index # reset e position e_pos = 0 # get z position elif gcode.is_z_move(cmd): prev_z = current_z current_z = round(gcode.last_match[0], 5) if round(current_z - prev_z, 5) > 0: # if z move is up, store index last_up_z_index = index if gcode.last_match[1]: # store speed to list self._z_speeds.append(round(gcode.last_match[1], 5)) # get extruder position elif gcode.is_extruder_move(cmd): e_speed = gcode.last_match[1] if e_speed is not None: e_pos = self._get_retract_position(e_pos, gcode.last_match[0]) # head move. Check z position and store extruder position to retract list elif gcode.is_head_move(cmd): # also check z from head move if gcode.last_match[2] is not None: prev_z = current_z current_z = round(gcode.last_match[2], 5) if round(current_z - prev_z, 5) > 0: last_up_z_index = index current_x = gcode.last_match[0] current_y = gcode.last_match[1] if gcode.last_match[3]: self._travel_speeds.append(round(gcode.last_match[3])) # add negative e position list and reset e position if e_pos < 0: if not current_tool in self._retracts: self._retracts[current_tool] = [] self._retracts[current_tool].append((e_pos, e_speed)) e_pos = 0 head_move_index = index # extrusion i.e. print move if gcode.is_extrusion_move(cmd): # check z argument if gcode.last_match[2] is not None: prev_z = current_z current_z = round(gcode.last_match[2], 5) if round(current_z - prev_z, 5) > 0: # if z move is up, store index last_up_z_index = index # TODO: parse z speed # print move defines the actual z-height for tool if current_z not in self._layers: self._layers[current_z] = [] if last_up_z_index is not None: self.insert_line( last_up_z_index, ActionPoint(ActionPoint.LAYER_CHANGE, (layer_nr, current_z)), ) index += 1 layer_nr += 1 if tool_index and tool_index > last_up_z_index: tool_index += 1 if len(self._layers ) > 1 and self.settings.sparse_layers: # add infill action with previous layer height self.insert_line( last_up_z_index + 1, ActionPoint(ActionPoint.INFILL, last_print_z), ) self.infill_checks.append(last_print_z) index += 1 if tool_index and tool_index > last_up_z_index: tool_index += 1 last_up_z_index = None last_print_z = current_z # add tool to layer list if flag is set if add_tool: if current_tool not in self.extruders: # add new extruder instance, if one doesn't exist already self.extruders[current_tool] = Extruder(current_tool) self.extruders[ current_tool].nozzle = self.settings.get_hw_config_float_value( "tool.nozzle.diameter") self.extruders[ current_tool].z_hop = self.settings.get_hw_config_float_value( "tool.tower.zhop") # replace line with z and tool, if not the first extruder if len(self.extruders.keys()) > 1: self._layers[last_print_z].append(current_tool) self.tool_switch_heights[current_tool] = last_print_z self.lines[tool_index] = ( ActionPoint(ActionPoint.TOOL_CHANGE, (last_print_z, current_tool)), None, ) add_tool = False e_pos = self._get_retract_position(e_pos, gcode.last_match[3]) # update x and y pos (not used at the moment) if gcode.last_match[0] is not None: current_x = gcode.last_match[0] if gcode.last_match[1] is not None: current_y = gcode.last_match[1] if (last_extrusion_x is not None and last_extrusion_y is not None and current_tool): path_len = gcode.calculate_path_length( (last_extrusion_x, last_extrusion_y), (current_x, current_y)) e_rate = gcode.calculate_feed_rate(path_len, gcode.last_match[3]) # e rate calculation not used currently # current_tool.e_rates.append(e_rate) if gcode.last_match[0] is not None: last_extrusion_x = gcode.last_match[0] if gcode.last_match[1] is not None: last_extrusion_y = gcode.last_match[1] index += 1 if self.start_gcode_end is None: raise ValueError( "Cannot find 'START SCRIPT END'-comment. Please add it to your Slicer's config" ) self.last_switch_height = max(self.tool_switch_heights.values()) self._calculate_values() # update extruder coasting value try: coasting = self.settings.get_hw_config_float_value( "post.tower.coast") if coasting: for e in self.extruders: self.extruders[e].coasting += coasting except ValueError: pass
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()
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 ManualControl(wx.Panel): def __init__(self, parent, app, prtname, reprap): self.model = None self.parent = parent self.app = app self.logger = self.app.logger self.appsettings = app.settings self.settings = app.settings.manualctl self.prtName = prtname self.prtSettings = self.app.settings.printersettings[prtname] self.speedcommand = self.prtSettings.speedcommand self.reprap = reprap self.firmware = None self.firmwareName = self.prtSettings.firmware self.reprap.setFirmware(self.firmwareName) self.prtmon = None self.currentTool = 0 self.macroActive = False self.nextr = self.app.settings.printersettings[prtname].nextr self.standardBedTemp = [ 0, self.prtSettings.standardbedlo, self.prtSettings.standardbedhi] self.standardHeTemp = [0, self.prtSettings.standardhelo, self.prtSettings.standardhehi] self.zEngaged = False if self.speedcommand is not None: self.reprap.addToAllowedCommands(self.speedcommand) wx.Panel.__init__(self, parent, wx.ID_ANY, size=(100, 100)) self.SetBackgroundColour("white") self.images = Images(os.path.join(self.settings.cmdfolder, "images")) self.slFeedTimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onFeedSpeedChanged, self.slFeedTimer) self.slFanTimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onFanSpeedChanged, self.slFanTimer) self.moveAxis = MoveAxis(self, self.app, self.reprap) self.sizerMove = wx.BoxSizer(wx.VERTICAL) self.sizerMove.AddSpacer((20,20)) self.sizerMove.Add(self.moveAxis) self.sizerExtrude = self.addExtruder(self.nextr) self.sizerBed = self.addBed() self.sizerSpeed = self.addSpeedControls() self.sizerGCode = self.addGCEntry() self.sizerMain = wx.BoxSizer(wx.HORIZONTAL) sizerLeft = wx.BoxSizer(wx.VERTICAL) sizerRight = wx.BoxSizer(wx.VERTICAL) sizerLeft.AddSpacer((20,20)) sizerLeft.Add(self.sizerMove) sizerLeft.Add(self.sizerGCode) sizerRight.AddSpacer((20, 20)) sizerRight.Add(self.sizerExtrude) sizerBedSpd = wx.BoxSizer(wx.HORIZONTAL) sizerBedSpd.Add(self.sizerBed) sizerBedSpd.AddSpacer((10, 10)) sizerBedSpd.Add(self.sizerSpeed) sizerRight.Add(sizerBedSpd) sizerBtn = wx.BoxSizer(wx.HORIZONTAL) self.bZEngage = wx.BitmapButton(self, wx.ID_ANY, self.images.pngEngagez, size=BUTTONDIM) self.zEngaged = False self.setZEngage() sizerBtn.Add(self.bZEngage) self.Bind(wx.EVT_BUTTON, self.onEngageZ, self.bZEngage) sizerBtn.AddSpacer((20, 20)) if self.firmwareName in [ "MARLIN" ]: from firmwaremarlin import FirmwareMarlin self.firmware = FirmwareMarlin(self.app, self.reprap) self.bFirmware = wx.BitmapButton(self, wx.ID_ANY, self.images.pngFirmware, size=BUTTONDIM) self.bFirmware.SetToolTipString("Manage Firmware settings") sizerBtn.Add(self.bFirmware) self.Bind(wx.EVT_BUTTON, self.doFirmware, self.bFirmware) sizerBtn.AddSpacer((20, 20)) self.bRunMacro = wx.BitmapButton(self, wx.ID_ANY, self.images.pngRunmacro, size=BUTTONDIM) self.bRunMacro.SetToolTipString("Run a macro") sizerBtn.Add(self.bRunMacro) self.Bind(wx.EVT_BUTTON, self.doRunMacro, self.bRunMacro) sizerRight.Add(sizerBtn) self.sizerMain.AddSpacer((20, 20)) self.sizerMain.Add(sizerLeft) self.sizerMain.AddSpacer((20, 20)) self.sizerMain.Add(sizerRight) self.sizerMain.AddSpacer((20, 20)) self.SetSizer(self.sizerMain) self.Layout() self.Fit() def setZEngage(self): if self.zEngaged: self.bZEngage.SetToolTipString("Disengage Z Axis") self.bZEngage.SetBitmapLabel(self.images.pngDisengagez) else: self.bZEngage.SetToolTipString("Engage Z Axis") self.bZEngage.SetBitmapLabel(self.images.pngEngagez) def onEngageZ(self, evt): if not self.zEngaged: if self.reprap.isPrinting(): dlg = wx.MessageDialog(self, "Disallowed while printing", 'Printer Busy', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() self.Destroy() else: self.zEngaged = True self.zdir = True self.ztimer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onZTimer, self.ztimer) self.ztimer.Start(10000) else: self.zEngaged = False self.ztimer.Stop() self.setZEngage() def leavePage(self): if self.zEngaged: self.logger.LogMessage("Disengaging Z axis") self.disengageZ() def disengageZ(self): if self.zEngaged: self.ztimer.Stop() self.zEngaged = False self.setZEngage() def onZTimer(self, evt): self.reprap.send_now("G91") if self.zdir: self.reprap.send_now("G1 Z0.1 F300") else: self.reprap.send_now("G1 Z-0.1 F300") self.reprap.send_now("G90") self.zdir = not self.zdir def setPrtMon(self, pm): self.prtmon = pm def doFirmware(self, evt): self.firmware.show() def doRunMacro(self, evt): self.bRunMacro.Enable(False) self.dlgMacro = MacroDialog(self, self.reprap) self.dlgMacro.CenterOnScreen() self.dlgMacro.Show(True) self.macroActive = True def onMacroExit(self, respawn=False): self.bRunMacro.Enable(True) self.dlgMacro.Destroy() self.macroActive = False if respawn: self.doRunMacro(None) def closeMacro(self): if self.macroActive: self.dlgMacro.Destroy() self.macroActive = False self.bRunMacro.Enable(True) def setBedTarget(self, temp): self.bedWin.setHeatTarget(temp) def setHETarget(self, tool, temp): self.heWin.setHeatTarget(tool, temp) def setBedTemp(self, temp): self.bedWin.setHeatTemp(temp) def setHETemp(self, tool, temp): self.heWin.setHeatTemp(tool, temp) def getBedGCode(self): if self.prtmon is None: return None return self.prtmon.getBedGCode() def getHEGCode(self, tool): if self.prtmon is None: return None return self.prtmon.getHEGCode(tool) def setActiveTool(self, tool): self.heWin.setActiveTool(tool) def addExtruder(self, nExtr): sizerExtrude = wx.BoxSizer(wx.VERTICAL) sizerExtrude.AddSpacer((10,10)) self.font12bold = wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) self.font16 = wx.Font(16, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) t = wx.StaticText(self, wx.ID_ANY, "Hot End(s)", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) sizerExtrude.Add(t, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) self.heWin = HotEnd(self, self.app, self.reprap, name=("Hot End 0", "Hot End 1", "Hot End 2"), shortname=snHotEnds, target=(self.standardHeTemp, self.standardHeTemp, self.standardHeTemp), trange=((20, 250), (20, 250), (20, 250)), nextr=nExtr) sizerExtrude.Add(self.heWin, flag=wx.LEFT | wx.EXPAND) sizerExtrude.AddSpacer((10,10)) t = wx.StaticText(self, wx.ID_ANY, "Extruder", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) sizerExtrude.Add(t, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) self.extWin = Extruder(self, self.app, self.reprap) sizerExtrude.Add(self.extWin, flag=wx.LEFT) sizerExtrude.AddSpacer((10,10)) return sizerExtrude def addBed(self): sizerBed = wx.BoxSizer(wx.VERTICAL) sizerBed.AddSpacer((10,10)) t = wx.StaticText(self, wx.ID_ANY, "Heated Print Bed", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) sizerBed.Add(t, flag=wx.LEFT) sizerBed.AddSpacer((10,10)) self.bedWin = HotBed(self, self.app, self.reprap, name="Heated Print Bed", shortname=snBed, target=self.standardBedTemp, trange=[20, 150]) sizerBed.Add(self.bedWin) sizerBed.AddSpacer((10,10)) return sizerBed def addSpeedControls(self): sizerSpeed = wx.BoxSizer(wx.VERTICAL) sizerSpeed.AddSpacer((10, 10)) if self.firmwareName in [ "MARLIN" ]: t = wx.StaticText(self, wx.ID_ANY, "Feed Speed", style=wx.ALIGN_CENTER, size=(-1, -1)) t.SetFont(self.font12bold) sizerSpeed.Add(t, flag=wx.ALL) self.slFeedSpeed = wx.Slider( self, wx.ID_ANY, 100, 50, 200, size=(320, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) self.slFeedSpeed.SetTickFreq(5, 1) self.slFeedSpeed.SetPageSize(1) self.slFeedSpeed.Bind(wx.EVT_SCROLL_CHANGED, self.onFeedSpeedChanged) self.slFeedSpeed.Bind(wx.EVT_MOUSEWHEEL, self.onFeedSpeedWheel) sizerSpeed.Add(self.slFeedSpeed) sizerSpeed.AddSpacer((10, 10)) t = wx.StaticText(self, wx.ID_ANY, "Fan Speed", style=wx.ALIGN_CENTER, size=(-1, -1)) t.SetFont(self.font12bold) sizerSpeed.Add(t, flag=wx.ALL) self.slFanSpeed = wx.Slider( self, wx.ID_ANY, 0, 0, 255, size=(320, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) self.slFanSpeed.SetTickFreq(5, 1) self.slFanSpeed.SetPageSize(1) self.slFanSpeed.Bind(wx.EVT_SCROLL_CHANGED, self.onFanSpeedChanged) self.slFanSpeed.Bind(wx.EVT_MOUSEWHEEL, self.onFanSpeedWheel) sizerSpeed.Add(self.slFanSpeed) if self.speedcommand is not None: self.bSpeedQuery = wx.BitmapButton(self, wx.ID_ANY, self.images.pngSpeedquery, size=BUTTONDIMWIDE) self.bSpeedQuery.SetToolTipString("Retrieve current feed and fan speeds from printer") sizerSpeed.Add(self.bSpeedQuery, flag=wx.ALIGN_CENTER | wx.ALL, border=10) self.Bind(wx.EVT_BUTTON, self.doSpeedQuery, self.bSpeedQuery) return sizerSpeed def doSpeedQuery(self, evt): self.reprap.send_now(self.speedcommand) def updateSpeeds(self, fan, feed, flow): if feed is not None: self.slFeedSpeed.SetValue(feed) if fan is not None: self.slFanSpeed.SetValue(fan) def onFeedSpeedChanged(self, evt): self.setFeedSpeed(self.slFeedSpeed.GetValue()) def onFeedSpeedWheel(self, evt): self.slFeedTimer.Start(500, True) l = self.slFeedSpeed.GetValue() if evt.GetWheelRotation() < 0: l -= 1 else: l += 1 if l >= 50 and l <= 200: self.slFeedSpeed.SetValue(l) def setFeedSpeed(self, spd): self.reprap.send_now("M220 S%d" % spd) def onFanSpeedChanged(self, evt): self.setFanSpeed(self.slFanSpeed.GetValue()) def onFanSpeedWheel(self, evt): self.slFanTimer.Start(500, True) l = self.slFanSpeed.GetValue() if evt.GetWheelRotation() < 0: l -= 1 else: l += 1 if l >= 0 and l <= 255: self.slFanSpeed.SetValue(l) def setFanSpeed(self, spd): self.reprap.send_now("M106 S%d" % spd) def addGCEntry(self): sizerGCode = wx.BoxSizer(wx.VERTICAL) sizerGCode.AddSpacer((20,20)) t = wx.StaticText(self, wx.ID_ANY, "G Code", style=wx.ALIGN_LEFT, size=(200, -1)) t.SetFont(self.font12bold) self.GCELabel = t sizerGCode.Add(t, flag=wx.LEFT) sizerGCode.AddSpacer((10,10)) self.GCEntry = GCodeEntry(self, self.app) sizerGCode.Add(self.GCEntry) return sizerGCode def onClose(self, evt): return True def setHeaters(self, heaters): for htr, temp, orig in heaters: htrl = htr.lower() if temp is None: self.logger.LogMessage("Invalid temperature (%s) specified for heater %s" % (orig, htr)) else: if htrl == snBed.lower(): self.bedWin.heaterTemp(temp) else: found = False for i in range(self.nextr): if htrl == snHotEnds[i].lower(): self.heWin.heaterTemp(i, temp) found = True break if not found: self.logger.LogMessage("Requested set heater on non-existent heater: %s" % htr) def pendantCommand(self, cmd): c = cmd.lower() if c in pendantMoves.keys(): axis = pendantMoves[c] if axis.startswith("Z"): speed = "F%s" % str(self.settings.zspeed) else: speed = "F%s" % str(self.settings.xyspeed) self.reprap.send_now("G91") self.reprap.send_now("G1 %s %s" % (axis, speed)) self.reprap.send_now("G90") elif c in pendantHomes.keys(): self.reprap.send_now(pendantHomes[c]) elif c == "extrude": self.extWin.doExtrude() elif c == "retract": self.extWin.doRetract() elif c.startswith("temp"): target = c[4:7] try: temp = int(c[7]) if temp < 0 or temp > 2: temp = None except: temp = None if temp is not None: if target == "bed": self.bedWin.heaterTemp(self.standardBedTemp[temp]) elif target.startswith("he"): try: tool = int(target[2]) if tool < 0 or tool >= self.nextr: tool = None except: tool = None if tool is not None: self.heWin.heaterTemp(tool, self.standardHeTemp[temp]) else: self.logger.LogMessage("Pendant temp command has invalid tool number: " + cmd) return False else: self.logger.LogMessage("Pendant temp command has invalid target: " + cmd) return False else: self.logger.LogMessage("Pendant temp command has invalid temp index: " + cmd) return False else: return False # command not handled return True # command handled
def parse_header(self): """ Parse KISS header and stuff for print settings :return: none """ current_tool = None ext_re = re.compile(b".*Material Settings for Extruder (\d+)") for layer in self.layers: for cmd, comment in layer.lines: if cmd: continue elif b" bed_size_x_mm =" in comment: #; bed_size_x_mm = 145 self.settings.stroke_x = float(comment.split(b' = ')[1]) elif b" bed_size_y_mm =" in comment: #; bed_size_y_mm = 145 self.settings.stroke_y = float(comment.split(b' = ')[1]) elif b" bed_offset_x_mm =" in comment: #; bed_offset_x_mm = 72.5 self.settings.origin_offset_x = float(comment.split(b' = ')[1]) elif b" bed_offset_y_mm =" in comment: #; bed_offset_y_mm = 72.5 self.settings.origin_offset_y = float(comment.split(b' = ')[1]) elif b" bed_offset_z_mm =" in comment: #; bed_offset_z_mm = 0 self.settings.z_offset = float(comment.split(b' = ')[1]) elif b" round_bed =" in comment: # ; round_bed = 0 self.settings.machine_type = int(comment.split(b' = ')[1]) elif b" travel_speed_mm_per_s =" in comment: # ; travel_speed_mm_per_s = 100 speed = float(comment.split(b' = ')[1]) * 60 self.settings.travel_xy_speed = speed self.settings.travel_z_speed = speed elif b" num_extruders = " in comment: # ; num_extruders = 4 for t in range(int(comment.split(b' = ')[1])): if t not in self.extruders: self.extruders[t] = Extruder(t) self.extruders[t].temperature_nr = t elif b" nozzle_dia" in comment: # ; nozzle_dia_1 = 0.4 parts = comment.split(b" = ") dia = float(parts[1]) t_num = int(parts[0].split(b"_")[2]) - 1 if t_num not in self.extruders: self.extruders[t_num] = Extruder(t_num) self.extruders[t_num].nozzle = dia elif b" first_layer_speed_mm_per_s =" in comment: # ; first_layer_speed_mm_per_s = 25 self.settings.first_layer_speed = float(comment.split(b' = ')[1]) * 60 elif b" Perimeter Speed =" in comment: # ; Perimeter Speed = 32.50 self.settings.outer_perimeter_speed = float(comment.split(b' = ')[1]) * 60 elif b" Loops Speed =" in comment: # ; Loops Speed = 45.50 self.settings.default_speed = float(comment.split(b' = ')[1]) * 60 elif b" extrusion_width =" in comment: # ; extrusion_width = 0.45 self.settings.extrusion_width = float(comment.split(b' = ')[1]) elif b" *** Material Settings for Extruder" in comment: # ; *** Material Settings for Extruder 2 *** m = ext_re.match(comment) current_tool = int(m.groups()[0]) - 1 elif current_tool is not None and b" destring_length =" in comment: # ; destring_length = 3 self.extruders[current_tool].retract = float(comment.split(b' = ')[1]) elif current_tool is not None and b" destring_speed_mm_per_s =" in comment: # ; destring_speed_mm_per_s = 80 self.extruders[current_tool].retract_speed = float(comment.split(b' = ')[1]) * 60 elif current_tool is not None and b" Z_lift_mm =" in comment: # ; Z_lift_mm = 0 self.extruders[current_tool].z_hop = float(comment.split(b' = ')[1]) elif current_tool is not None and b" wipe_mm =" in comment: # ; wipe_mm = 5 self.extruders[current_tool].wipe = float(comment.split(b' = ')[1]) elif current_tool is not None and b" flowrate_tweak =" in comment: # ; flowrate_tweak = 1 self.extruders[current_tool].feed_rate_multiplier = float(comment.split(b' = ')[1]) elif current_tool is not None and b" g_code_matl =" in comment: # ; g_code_matl = NULL self.extruders[current_tool].filament_type = comment.split(b' = ')[1] elif current_tool is not None and b" first_layer_C =" in comment: # ; first_layer_C = 235 self.extruders[current_tool].temperature_setpoints[1] = int(comment.split(b' = ')[1]) elif current_tool is not None and b" temperature_C =" in comment: # ; temperature_C = 242 self.extruders[current_tool].temperature_setpoints[2] = int(comment.split(b' = ')[1]) elif b" firmware_type =" in comment: # ; firmware_type = 1 if comment.split(b' = ')[1] != b"1": raise ValueError("Relative E distances not enabled! Filaswitch won't work without relative E distances") elif b"; force_joint_layers =" in comment: # ; force_joint_layers = 0 if comment.split(b' = ')[1] != b"1": self.log.warning("KISS joint layer division is not enabled. This might cause unexpected behaviour with tower size") if not self.version: self.log.warning("Could not detect KISSlicer version. Use at your own risk!") else: self.log.info("KISSlicer version %s" % self._version_to_string()) for t in self.extruders: self.extruders[t].z_offset = self.settings.z_offset self.extruders[t].extrusion_width = self.settings.extrusion_width if self.settings.machine_type == 0: # fix KISS xy offsets self.settings.origin_offset_x = self.settings.origin_offset_x - self.settings.stroke_x/2 self.settings.origin_offset_y = self.settings.origin_offset_y - self.settings.stroke_y/2 # correct the layer height to value that doesn't have the z-offset if self.settings.z_offset != 0: for l in self.layers: l.z -= self.settings.z_offset
def move_to_point(cls, **kwargs): x_lt, x_rt, y_lo = 0, 0, 0 if kwargs['G'] == 80: cls.init_calibration( ) # Calculate start point hypotenuses, TBD change format of calling that kind fun stps_l = int(round(MathCalc.steps_amt(cls.DATA['HYP_L']))) stps_r = int(round(MathCalc.steps_amt(cls.DATA['HYP_R']))) if START_POINT == 'begin': cls.set_position('stp', 0, 0, stps_l, stps_r) if START_POINT == 'middle': cls.set_position('stp', 500, 0, stps_l, stps_r) cls.MOT_L.set_pos(stps_l) cls.MOT_R.set_pos(stps_r) cls.summary_tab.add_row([ 'HYPEN', f'{cls.DATA["HYP_L"]}|{int(round(MathCalc.steps_amt(cls.DATA["HYP_L"])))}', f'{cls.DATA["HYP_R"]}|{int(round(MathCalc.steps_amt(cls.DATA["HYP_R"])))}' ]) logger['P_INF'].info(f'\r\n{cls.summary_tab}') cls.summary_tab.clear_rows() return 0 if kwargs['X'] > -1: # if START_POINT == 'middle': # x_lt = WALL_X / 2 - kwargs['X'] # x_rt = WALL_X / 2 + kwargs['X'] # # if START_POINT == 'begin': x_lt = kwargs['X'] x_rt = WALL_X - kwargs['X'] if kwargs['Y'] > -1: y_lo = WALL_Y - kwargs['Y'] if kwargs['E'] > -1: Extruder.extrude_marker(int(kwargs['E'])) print(kwargs['E']) else: sys.exit('Value of GCODE can not be negative') hyp_diff_l = abs(MathCalc.get_hypotenuse2(x_lt, y_lo)) - cls.DATA['HYP_L'] hyp_diff_r = abs(MathCalc.get_hypotenuse2(x_rt, y_lo)) - cls.DATA['HYP_R'] # Hypotenuses calc (output value in the same unit as WALL_X and WALL_Y -> mm for now) cls.DATA['HYP_L'] = abs(MathCalc.get_hypotenuse2(x_lt, y_lo)) cls.DATA['HYP_R'] = abs(MathCalc.get_hypotenuse2(x_rt, y_lo)) cls.DATA['STPS_AMT']['L'] = int(round(MathCalc.steps_amt(hyp_diff_l))) cls.DATA['STPS_AMT']['R'] = int(round(MathCalc.steps_amt(hyp_diff_r))) cls.initial_tab.add_row([ 'MOV NEEDED', f"{hyp_diff_l}|{cls.DATA['STPS_AMT']['L']}", f"{hyp_diff_r}|{cls.DATA['STPS_AMT']['R']}" ]) logger['P_INF'].info(f'\r\n{cls.initial_tab}') cls.initial_tab.clear_rows() # logger['P_INF'].info(f"I have to move: " # f"MOT_L: {hyp_diff_l}[mm]|{cls.DATA['STPS_AMT']['L']}[steps] && " # f"MOT_R: {hyp_diff_r}[mm]|{cls.DATA['STPS_AMT']['R']}[steps]\n") # Steps time calc cls.DATA['STPS_TIM'] = max( MathCalc.steps_tim(abs(amt)) for amt in cls.DATA['STPS_AMT'].values()) # FULLY SOFTWARE TESTING LOW LEVEL FUNCTIONS if MODEL == 'SIL': cls.start_motor_thread() if MODEL == 'HIL': cls.MOT_L.mov_mtr(cls.DATA['STPS_AMT']['L'], cls.DATA['STPS_TIM']) cls.MOT_R.mov_mtr(cls.DATA['STPS_AMT']['R'], cls.DATA['STPS_TIM']) time.sleep(cls.DATA['STPS_TIM']) # print(' ') # logger['P_INF'].info(f'END POSITIONS FOR: @MOT_L -> {cls.MOT_L.get_pos()}[stp] && ' # f'@MOT_R -> {cls.MOT_R.get_pos()}[stp]\n') cls.set_position('stp', kwargs['X'], kwargs['Y'], cls.MOT_L.get_pos(), cls.MOT_R.get_pos()) cls.summary_tab.add_row([ 'HYPEN', f"{cls.DATA['HYP_L']}|{int(round(MathCalc.steps_amt(cls.DATA['HYP_L'])))}", f"{cls.DATA['HYP_R']}|{int(round(MathCalc.steps_amt(cls.DATA['HYP_R'])))}" ]) logger['P_INF'].info(f'\r\n{cls.summary_tab}') cls.summary_tab.clear_rows() return 0