Exemple #1
0
	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
Exemple #2
0
    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")
Exemple #3
0
    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
Exemple #4
0
    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)
Exemple #5
0
    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
Exemple #6
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()
Exemple #7
0
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)
Exemple #8
0
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
Exemple #10
0
    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