Ejemplo n.º 1
0
def parse_gcode():
    cur_z = -999
    cur_tool = 0
    retract = 0.6
    layer = -1
    toolchange = 0
    emptygrid = 0

    v.block_classification = CLS_NORMAL
    v.previous_block_classification = CLS_NORMAL
    total_line_count = len(v.input_gcode)

    index = 0
    for line in v.input_gcode:

        gui.progress_string(4 + 46 * index // total_line_count)

        specifier = 0
        code = gcode.GCodeCommand(line)
        v.parsedgcode.append(code)

        classupdate = False

        if line.startswith(';'):

            ## P2PP SPECIFIC SETP COMMANDS
            ########################################################
            if line.startswith(";P2PP"):
                parameters.check_config_parameters(line)

            if line.startswith(";P2PP MATERIAL_"):
                algorithm_process_material_configuration(line[15:])

            ## LAYER DISCRIMINATION COMMANDS
            ########################################################

            if line.startswith(";LAYER"):
                layer = 0
                try:
                    layer = int(line[7:])
                except ValueError:
                    fields = line[7:].split(" ")
                    for field in fields:
                        try:
                            layer = int(field)
                            break
                        except ValueError:
                            pass

                v.parsedlayer = layer
                if layer > 0:
                    v.skippable_layer.append((emptygrid > 0)
                                             and (toolchange == 0))
                toolchange = 0
                emptygrid = 0

            ## Update block class from comments information
            #########################################################
            classupdate = update_class(line)
        #
        # if line.startswith('T'):
        #     classupdate = update_class(line)

        if classupdate:

            if v.block_classification == CLS_TOOL_START:
                toolchange += 1

            if v.block_classification == CLS_EMPTY:
                emptygrid += 1

        ## Z-HOPS detection
        ###################
        if code.has_E() and code.is_movement_command():

            to_z = code.get_parameter("Z", 0)
            delta = (to_z - cur_z)

            if abs(delta - retract) < 0.0001:
                specifier |= SPEC_HOPUP

                if v.block_classification == CLS_TONORMAL:
                    v.previous_block_classification = v.block_classification = CLS_NORMAL

            if abs(-delta - retract) < 0.0001:
                specifier |= SPEC_HOPDOWN

            cur_z = to_z

        ## retract detections
        #####################
        if code.is_retract_command():
            specifier |= SPEC_RETRACTS

        ## tool change detection
        ########################
        if code.Command == 'T':
            cur_tool = int(code.Command_value)
            retract = v.retract_lift[cur_tool]
            specifier |= SPEC_TOOLCHANGE

        if v.tower_measure:
            if code.is_movement_command():
                if code.X is not None:
                    v.wipe_tower_info['minx'] = min(v.wipe_tower_info['minx'],
                                                    code.X)
                    v.wipe_tower_info['maxx'] = max(v.wipe_tower_info['maxx'],
                                                    code.X)
                if code.Y is not None:
                    v.wipe_tower_info['miny'] = min(v.wipe_tower_info['miny'],
                                                    code.Y)
                    v.wipe_tower_info['maxy'] = max(v.wipe_tower_info['maxy'],
                                                    code.Y)

        ## Extend block backwards towards last hop up
        #############################################

        if v.block_classification in [
                CLS_TOOL_START, CLS_TOOL_UNLOAD, CLS_EMPTY, CLS_BRIM
        ]:  # and not v.full_purge_reduction:
            backpass(v.block_classification)

        if v.block_classification in [CLS_ENDGRID, CLS_ENDPURGE]:
            if code.fullcommand == "G1":
                if code.has_X() and code.has_Y():
                    specifier |= SPEC_INTOWER

        if CLS_ENDGRID:
            code = v.parsedgcode[-1]
            if code.has_X and code.has_Y():
                if not coordinate_in_tower(code.X, code.Y):
                    v.block_classification = CLS_NORMAL
            # if v.parsedgcode[-1].fullcommand == "G1" and v.parsedgcode[-1].Z:
            #     v.block_classification = CLS_NORMAL
        else:
            if flagset(specifier, SPEC_RETRACTS):
                v.block_classification = CLS_NORMAL

        ## Put obtained values in global variables
        ##########################################
        v.gcodeclass.append(v.block_classification)
        v.layernumber.append(layer)
        v.linetool.append(cur_tool)
        v.parsecomment.append(specifier)
        v.classupdates.append(
            v.block_classification != v.previous_block_classification)
        v.previous_block_classification = v.block_classification
        index = index + 1

        if v.block_classification == CLS_BRIM_END:
            v.block_classification = CLS_NORMAL
Ejemplo n.º 2
0
def generate(input_file, output_file, printer_profile, splice_offset, silent):
    starttime = time.time()
    v.printer_profile_string = printer_profile
    basename = os.path.basename(input_file)
    _taskName = os.path.splitext(basename)[0].replace(" ", "_")
    _taskName = _taskName.replace(".mcf", "")

    v.splice_offset = splice_offset

    try:
        # python 3.x
        opf = open(input_file, encoding='utf-8')
    except TypeError:
        try:
            # python 2.x
            opf = open(input_file)
        except IOError:
            if v.gui:
                gui.user_error(
                    "P2PP - Error Occurred",
                    "Could not read input file\n'{}'".format(input_file))
            else:
                print("Could not read input file\n'{}".format(input_file))
            return
    except IOError:
        if v.gui:
            gui.user_error(
                "P2PP - Error Occurred",
                "Could not read input file\n'{}'".format(input_file))
        else:
            print("Could not read input file\n'{}".format(input_file))
        return

    gui.setfilename(input_file)
    gui.set_printer_id(v.printer_profile_string)
    gui.create_logitem("Reading File " + input_file)
    gui.progress_string(1)

    v.input_gcode = opf.readlines()
    opf.close()

    v.input_gcode = [item.strip() for item in v.input_gcode]

    gui.create_logitem("Analyzing slicer parameters")
    gui.progress_string(2)
    parse_slic3r_config()

    gui.create_logitem("Pre-parsing GCode")
    gui.progress_string(4)
    parse_gcode()
    if v.palette_plus:
        if v.palette_plus_ppm == -9:
            gui.log_warning(
                "P+ parameter P+PPM not set correctly in startup GCODE")
        if v.palette_plus_loading_offset == -9:
            gui.log_warning(
                "P+ parameter P+LOADINGOFFSET not set correctly in startup GCODE"
            )

    v.side_wipe = not coordinate_on_bed(v.wipetower_posx, v.wipetower_posy)
    v.tower_delta = v.max_tower_z_delta > 0

    if v.side_wipe:
        gui.create_logitem("Side wipe activated", "blue")
        if v.full_purge_reduction:
            gui.log_warning(
                "Full Purge Reduction is not compatible with Side Wipe, performing Side Wipe"
            )
            v.full_purge_reduction = False

    if v.full_purge_reduction:
        v.side_wipe = False
        gui.create_logitem("Full Tower Reduction activated", "blue")
        if v.tower_delta:
            gui.log_warning(
                "Full Purge Reduction is not compatible with Tower Delta, performing Full Purge Reduction"
            )
            v.tower_delta = False

    v.pathprocessing = (v.tower_delta or v.full_purge_reduction or v.side_wipe)

    if v.tower_delta:
        optimize_tower_skip(v.max_tower_z_delta, v.layer_height)

    if v.side_wipe:
        optimize_tower_skip(999, v.layer_height)

    gui.create_logitem("Generate processed GCode")

    total_line_count = len(v.input_gcode)
    v.retraction = 0
    for process_line_count in range(total_line_count):
        gcode_parseline(process_line_count)
        gui.progress_string(50 + 50 * process_line_count // total_line_count)

    v.processtime = time.time() - starttime

    gcode_process_toolchange(-1, v.total_material_extruded, 0)
    omega_result = header_generate_omega(_taskName)
    header = omega_result['header'] + omega_result['summary'] + omega_result[
        'warnings']

    if v.absolute_extruder and v.gcode_has_relative_e:
        gui.create_logitem("Converting to absolute extrusion")
        convert_to_absolute()

    # write the output file
    ######################

    if not output_file:
        output_file = input_file
    gui.create_logitem("Generating GCODE file: " + output_file)
    opf = open(output_file, "w")
    if not v.accessory_mode:
        opf.writelines(header)
        opf.write("\n\n;--------- START PROCESSED GCODE ----------\n\n")
    if v.accessory_mode:
        opf.write("M0\n")
        opf.write("T0\n")

    if v.splice_offset == 0:
        gui.log_warning("SPLICE_OFFSET not defined")
    opf.writelines(v.processed_gcode)
    opf.close()

    if v.accessory_mode:

        pre, ext = os.path.splitext(output_file)
        if v.palette_plus:
            maffile = pre + ".msf"
        else:
            maffile = pre + ".maf"
        gui.create_logitem("Generating PALETTE MAF/MSF file: " + maffile)
        opf = open(maffile, "w")
        for i in range(len(header)):
            if not header[i].startswith(";"):
                opf.write(header[i])

    gui.print_summary(omega_result['summary'])

    gui.progress_string(100)
    if (len(v.process_warnings) > 0
            and not v.ignore_warnings) or v.consolewait:
        gui.close_button_enable()
Ejemplo n.º 3
0
def generate(input_file, output_file, printer_profile, splice_offset, silent):
    starttime = time.time()
    v.printer_profile_string = printer_profile
    basename = os.path.basename(input_file)
    _taskName = os.path.splitext(basename)[0].replace(" ", "_")
    _taskName = _taskName.replace(".mcf", "")

    v.splice_offset = splice_offset

    try:
        # python 3.x
        opf = open(input_file, encoding='utf-8')
    except TypeError:
        try:
            # python 2.x
            opf = open(input_file)
        except IOError:
            if v.gui:
                gui.user_error("P2PP - Error Occurred", "Could not read input file\n'{}'".format(input_file))
            else:
                print ("Could not read input file\n'{}".format(input_file))
            return
    except IOError:
        if v.gui:
            gui.user_error("P2PP - Error Occurred", "Could not read input file\n'{}'".format(input_file))
        else:
            print ("Could not read input file\n'{}".format(input_file))
        return

    gui.setfilename(input_file)
    gui.set_printer_id(v.printer_profile_string)
    gui.create_logitem("Reading File " + input_file)
    gui.progress_string(1)

    v.input_gcode = opf.readlines()
    opf.close()

    v.input_gcode = [item.strip() for item in v.input_gcode]

    gui.create_logitem("Analyzing slicer parameters")
    gui.progress_string(2)
    parse_slic3r_config()

    gui.create_logitem("Pre-parsing GCode")
    gui.progress_string(4)
    parse_gcode()

    if v.tower_delta or v.full_purge_reduction:
        if v.variable_layer:
            gui.log_warning("Variable layers are not compatible with fullpruge/tower delta")

    if v.process_temp and v.side_wipe:
        gui.log_warning("TEMPERATURECONTROL and Side Wipe / BigBrain3D are not compatible")

    if v.palette_plus:
        if v.palette_plus_ppm == -9:
            gui.log_warning("P+ parameter P+PPM not set correctly in startup GCODE")
        if v.palette_plus_loading_offset == -9:
            gui.log_warning("P+ parameter P+LOADINGOFFSET not set correctly in startup GCODE")

    v.side_wipe = not coordinate_on_bed(v.wipetower_posx, v.wipetower_posy)
    v.tower_delta = v.max_tower_z_delta > 0

    gui.create_logitem("Creating tool usage information")
    m4c.calculate_loadscheme()


    if v.side_wipe:

        if v.skirts and v.ps_version > "2.2":
            gui.log_warning("SIDEWIPE and SKIRTS are NOT compatible in PS2.2 or later")
            gui.log_warning("THIS FILE WILL NOT PRINT CORRECTLY")

        if v.wipe_remove_sparse_layers:
            gui.log_warning("SIDE WIPE mode not compatible with sparse wipe tower in PS")
            gui.log_warning("THIS FILE WILL NOT PRINT CORRECTLY")

        gui.create_logitem("Side wipe activated", "blue")
        if v.full_purge_reduction:
            gui.log_warning("Full Purge Reduction is not compatible with Side Wipe, performing Side Wipe")
            v.full_purge_reduction = False



    if v.full_purge_reduction:
        v.side_wipe = False
        gui.create_logitem("Full Tower Reduction activated", "blue")
        if v.tower_delta:
            gui.log_warning("Full Purge Reduction is not compatible with Tower Delta, performing Full Purge Reduction")
            v.tower_delta = False

    v.pathprocessing = (v.tower_delta or v.full_purge_reduction or v.side_wipe)

    if v.autoaddsplice and not v.full_purge_reduction and not v.side_wipe:
        gui.log_warning("AUTOEDDPURGE only works with side wipe and fullpurgereduction at this moment")

    if (len(v.skippable_layer) == 0) and v.pathprocessing:
        gui.log_warning("LAYER configuration is missing. NO OUTPUT FILE GENERATED.")
        gui.log_warning("Check the P2PP documentation for furhter info.")
    else:

        if v.tower_delta:
            optimize_tower_skip(v.max_tower_z_delta, v.layer_height)

        if v.side_wipe:
            optimize_tower_skip(999, v.layer_height)

        gui.create_logitem("Generate processed GCode")

        total_line_count = len(v.input_gcode)
        v.retraction = 0
        for process_line_count in range(total_line_count):
            gcode_parseline(process_line_count)
            gui.progress_string(50 + 50 * process_line_count // total_line_count)

        v.processtime = time.time() - starttime

        gcode_process_toolchange(-1, v.total_material_extruded, 0)
        omega_result = header_generate_omega(_taskName)
        header = omega_result['header'] + omega_result['summary'] + omega_result['warnings']

        if v.absolute_extruder and v.gcode_has_relative_e:
            gui.create_logitem("Converting to absolute extrusion")
            convert_to_absolute()

        # write the output file
        ######################

        if not output_file:
            output_file = input_file
        gui.create_logitem("Generating GCODE file: " + output_file)
        opf = open(output_file, "w")
        if not v.accessory_mode:
            opf.writelines(header)
            opf.write("\n\n;--------- START PROCESSED GCODE ----------\n\n")
        if v.accessory_mode:
            opf.write("M0\n")
            opf.write("T0\n")

        if v.splice_offset == 0:
            gui.log_warning("SPLICE_OFFSET not defined")
        opf.writelines(v.processed_gcode)
        opf.close()

        if v.accessory_mode:

            pre, ext = os.path.splitext(output_file)
            if v.palette_plus:
                maffile = pre + ".msf"
            else:
                maffile = pre + ".maf"
            gui.create_logitem("Generating PALETTE MAF/MSF file: " + maffile)


            maf = open(maffile, 'w')

            for h in header:
                h = h.strip('\r\n')
                maf.write(unicode(h))
                maf.write('\r\n')
            maf.close()
            #
            # with io.open(maffile, 'w', newline='\r\n') as maf:
            #
            #     for i in range(len(header)):
            #         h = header[i].strip('\n\r') + "\n"
            #         if not h.startswith(";"):
            #             try:
            #                 maf.write(unicode(h))
            #             except:
            #                 maf.write(h)


        gui.print_summary(omega_result['summary'])

    gui.progress_string(100)
    if (len(v.process_warnings) > 0 and not v.ignore_warnings) or v.consolewait:
        gui.close_button_enable()
Ejemplo n.º 4
0
def parse_gcode():
    cur_tool = 0
    toolchange = 0
    emptygrid = 0

    v.block_classification = CLS_NORMAL
    v.previous_block_classification = CLS_NORMAL
    total_line_count = len(v.input_gcode)

    index = 0
    for line in v.input_gcode:

        gui.progress_string(4 + 46 * index // total_line_count)


        if line.startswith(';'):

            m = v.regex_p2pp.match(line)
            if m:
                parameters.check_config_parameters(m.group(1), m.group(2))


            if line.startswith(";P2PP MATERIAL_"):
                algorithm_process_material_configuration(line[15:])

            layer = -1
            # if not supports are printed or layers are synced, there is no need to look at the layerheight,
            # otherwise look at the layerheight to determine the layer progress

            lm = layer_regex.match(line)
            if lm is not None:
                llm = len(lm.group(1))
                lmv = float(lm.group(2))
                if v.synced_support or not v.prints_support:
                    if llm == 5:  # LAYER
                        layer = int(lmv)
                else:
                    if llm == 11:  # LAYERHEIGHT
                        layer = int((lmv - v.first_layer_height + 0.005) / v.layer_height)

            if layer == v.parsedlayer:
                layer = -1

            if layer >= 0:
                v.parsedlayer = layer

            if layer > 0:
                v.skippable_layer.append((emptygrid > 0) and (toolchange == 0))
                toolchange = 0
                emptygrid = 0

            update_class(line)

        code = gcode.GCodeCommand(line)

        if code.Command == 'T':
            cur_tool = int(code.Command_value)
            v.set_tool = cur_tool
            v.m4c_toolchanges.append(cur_tool)
            v.m4c_toolchange_source_positions.append(len(v.parsed_gcode))


        code.Tool = cur_tool
        code.Class = v.block_classification


        # code.add_comment("[{}]".format(v.classes[v.block_classification]))
        v.parsed_gcode.append(code)

        if v.block_classification != v.previous_block_classification:

            if v.block_classification == CLS_TOOL_START:
                toolchange += 1

            if v.block_classification == CLS_EMPTY:
                emptygrid += 1

            if v.block_classification == CLS_BRIM or v.block_classification == CLS_TOOL_START or v.block_classification == CLS_TOOL_UNLOAD or v.block_classification == CLS_EMPTY:
                backpass(v.block_classification)

        if v.tower_measure:
            calculate_tower(code.X, code.Y)

        if v.block_classification == CLS_ENDGRID or v.block_classification == CLS_ENDPURGE:
            if code.has_X() and code.has_Y():
                if not coordinate_in_tower(code.X, code.Y):
                    v.parsed_gcode[-1].Class = CLS_NORMAL
                    v.block_classification = CLS_NORMAL

        if v.block_classification == CLS_BRIM_END:
            v.block_classification = CLS_NORMAL

        index += 1
Ejemplo n.º 5
0
def parse_gcode_second_pass():
    idx = 0
    intower = False
    purge = False
    total_line_count = len(v.parsed_gcode)
    v.retraction = 0
    v.last_parsed_layer = -1
    v.previous_block_classification = v.parsed_gcode[0][gcode.CLASS]

    # include firmware purge length accounting
    v.total_material_extruded = v.firmwarepurge
    v.material_extruded_per_color[v.current_tool] = v.firmwarepurge

    for process_line_count in range(total_line_count):

        try:
            if process_line_count >= v.layer_end[0]:
                v.last_parsed_layer += 1
                v.layer_end.pop(0)
                v.current_layer_is_skippable = v.skippable_layer[
                    v.last_parsed_layer] and not v.last_parsed_layer == 0
                if v.current_layer_is_skippable:
                    if v.last_parsed_layer == 0:
                        v.cur_tower_z_delta += v.first_layer_height
                    else:
                        v.cur_tower_z_delta += v.layer_height
        except IndexError:
            pass

        g = v.parsed_gcode[idx]

        idx = idx + 1

        # ----- MEMORY MANAGEMENT - when 100K lines are processed, remove the top of the list

        if idx > 100000:
            v.parsed_gcode = v.parsed_gcode[idx:]
            idx = 0

        if process_line_count % 10000 == 0:
            gui.progress_string(50 +
                                50 * process_line_count // total_line_count)

        current_block_class = g[gcode.CLASS]

        # ---- FIRST SECTION HANDLES DELAYED TEMPERATURE COMMANDS ----

        if current_block_class not in [
                CLS_TOOL_PURGE, CLS_TOOL_START, CLS_TOOL_UNLOAD
        ] and v.current_temp != v.new_temp:
            gcode.issue_code(v.temp1_stored_command)
            v.temp1_stored_command = ""

        # BLOCK Added 27/11/2021 - PS2.4 - P3 - showinf lines between print and tower
        if current_block_class != v.previous_block_classification and not v.side_wipe and not v.full_purge_reduction:
            if v.previous_block_classification == CLS_TOOL_UNLOAD:
                if v.restore_move_point:
                    v.restore_move_point = False
                    gcode.issue_code(
                        "G1 X{:0.3f} Y{:0.3f} F8640 ; P2PP positional alignment"
                        .format(v.current_position_x, v.current_position_y))
        # BLOCK END

        # ---- SECOND SECTION HANDLES COMMENTS AND NONE-MOVEMENT COMMANDS ----

        if g[gcode.COMMAND] is None:
            if v.disable_z and g[gcode.COMMENT].endswith("END"):
                v.disable_z = False

            if v.needpurgetower and g[gcode.COMMENT].endswith("BRIM END"):
                v.needpurgetower = False
                purgetower.purge_create_layers(v.wipe_tower_info_minx,
                                               v.wipe_tower_info_miny,
                                               v.wipe_tower_xsize,
                                               v.wipe_tower_ysize)
                purgetower.purge_generate_brim()
                v.toolchange_processed = False
            gcode.issue_command(g)
            continue

        elif g[gcode.MOVEMENT] == 0:

            if g[gcode.COMMAND].startswith('T'):

                if v.manual_filament_swap and not (
                        v.side_wipe or v.full_purge_reduction
                        or v.tower_delta) and (v.current_tool != -1):
                    swap.swap_pause("M25")
                    swap.swap_unpause()

                gcode_process_toolchange(int(g[gcode.COMMAND][1:]))
                if not v.debug_leaveToolCommands:
                    gcode.move_to_comment(g, "--P2PP-- Color Change")

                v.toolchange_processed = (current_block_class != CLS_NORMAL)

            elif v.klipper and g[gcode.COMMAND] == "ACTIVATE_EXTRUDER":

                extruder = g[gcode.OTHER].strip()

                if extruder.startswith("EXTRUDER=extruder"):
                    if len(extruder) == 17:
                        extruder_num = 0
                    else:
                        try:
                            extruder_num = int(extruder[17:])
                        except (ValueError, IndexError):
                            extruder_num = None
                            gui.log_warning(
                                "KLIPPER - Named extruders are not supported ({})"
                                .format(extruder))

                    if extruder_num is not None:
                        gcode_process_toolchange(extruder_num)

                    if not v.debug_leaveToolCommands:
                        gcode.move_to_comment(g, "--P2PP-- Color Change")
                        v.toolchange_processed = True
                else:
                    gui.log_warning(
                        "KLIPPER - Named extruders are not supported ({})".
                        format(extruder))
            else:
                if current_block_class == CLS_TOOL_UNLOAD:
                    if g[gcode.COMMAND] in ["G4", "M900", "M400"]:
                        gcode.move_to_comment(g, "--P2PP-- tool unload")

                if g[gcode.COMMAND] is not None and g[
                        gcode.COMMAND].startswith('M'):
                    try:
                        command_num = int(g[gcode.COMMAND][1:])
                    except (ValueError, KeyError):
                        command_num = 0

                    if command_num in [104, 109]:
                        if v.process_temp:
                            if current_block_class not in [
                                    CLS_TOOL_PURGE, CLS_TOOL_START,
                                    CLS_TOOL_UNLOAD
                            ]:
                                g[gcode.COMMENT] += " Unprocessed temp "
                                v.new_temp = gcode.get_parameter(
                                    g, gcode.S, v.current_temp)
                                v.current_temp = v.new_temp
                            else:
                                v.new_temp = gcode.get_parameter(
                                    g, gcode.S, v.current_temp)
                                if v.new_temp >= v.current_temp:
                                    g[gcode.COMMAND] = "M109"
                                    v.temp2_stored_command = gcode.create_commandstring(
                                        g)
                                    gcode.move_to_comment(
                                        g,
                                        "--P2PP-- delayed temp rise until after purge {}-->{}"
                                        .format(v.current_temp, v.new_temp))
                                    v.current_temp = v.new_temp

                                else:
                                    v.temp1_stored_command = gcode.create_commandstring(
                                        g)
                                    gcode.move_to_comment(
                                        g,
                                        "--P2PP-- delayed temp drop until after purge {}-->{}"
                                        .format(v.current_temp, v.new_temp))
                    elif command_num == 107:
                        v.saved_fanspeed = 0

                    elif command_num == 106:
                        v.saved_fanspeed = gcode.get_parameter(
                            g, gcode.S, v.saved_fanspeed)

                    elif command_num == 221:
                        v.extrusion_multiplier = float(
                            gcode.get_parameter(
                                g, gcode.S,
                                v.extrusion_multiplier * 100.0)) / 100.0

                    elif command_num == 220:
                        gcode.move_to_comment(
                            g, "--P2PP-- Feed Rate Adjustments are removed")

                    elif command_num == 572:
                        for i in range(1, v.filament_count):
                            g[gcode.OTHER] = g[gcode.OTHER].replace(
                                "D{}".format(i), "D0")

                    elif not v.generate_M0 and g[gcode.COMMAND] == "M0":
                        gcode.move_to_comment(g, "--P2PP-- remove M0 command")

            gcode.issue_command(g)
            continue

        classupdate = not current_block_class == v.previous_block_classification
        v.previous_block_classification = current_block_class

        # ---- AS OF HERE ONLY MOVEMENT COMMANDS ----

        if g[gcode.MOVEMENT] & 1:
            v.previous_purge_keep_x = v.purge_keep_x
            v.purge_keep_x = g[gcode.X]
            v.current_position_x = g[gcode.X]

        if g[gcode.MOVEMENT] & 2:
            v.previous_purge_keep_y = v.purge_keep_y
            v.purge_keep_y = g[gcode.Y]
            v.current_position_y = g[gcode.Y]

        if g[gcode.MOVEMENT] & 4:
            if v.disable_z:
                gcode.move_to_comment(g,
                                      "-- P2PP - invalid move in delta tower")
                gcode.issue_command(g)
                continue
            else:
                v.current_position_z = g[gcode.Z]

        if g[gcode.MOVEMENT] & 16:
            v.keep_speed = g[gcode.F]

        # this goes for all situations: START and UNLOAD are not needed
        if current_block_class in [CLS_TOOL_START, CLS_TOOL_UNLOAD]:
            # BLOCK Added 27/11/2021 - PS2.4 - P3 - showinf lines between print and tower
            if not (v.side_wipe or v.full_purge_reduction):
                v.restore_move_point = True
            # BLOCK END
            gcode.move_to_comment(g, "--P2PP-- tool unload")
            gcode.issue_command(g)
            continue

        # --------------------- TOWER DELTA PROCESSING
        if v.tower_delta:

            if classupdate:

                if current_block_class == CLS_TOOL_PURGE:
                    gcode.issue_command(g)
                    entertower(v.last_parsed_layer * v.layer_height +
                               v.first_layer_height)
                    continue

                if current_block_class == CLS_EMPTY and not v.towerskipped:

                    v.towerskipped = (
                        g[gcode.MOVEMENT] & gcode.INTOWER
                    ) == gcode.INTOWER and v.current_layer_is_skippable

                    if not v.towerskipped:
                        gcode.issue_command(g)
                        entertower(v.last_parsed_layer * v.layer_height +
                                   v.first_layer_height)
                        continue

                if current_block_class == CLS_NORMAL:
                    if v.towerskipped:
                        gcode.issue_code("G1 Z{:.2f} F10810".format(
                            v.current_position_z))
                        v.towerskipped = False

            if current_block_class == CLS_TOOL_PURGE:
                speed_limiter(g)

            if current_block_class == CLS_TOOL_PURGE:
                if g[gcode.F] is not None and g[
                        gcode.F] > v.purgetopspeed and g[gcode.E]:
                    g[gcode.F] = v.purgetopspeed
                    g[gcode.COMMENT] += " prugespeed topped"

            if v.towerskipped:
                gcode.move_to_comment(g, "--P2PP-- tower skipped")
                gcode.issue_command(g)
                continue
        # --------------------- SIDE WIPE PROCESSING
        elif v.side_wipe:

            if classupdate:

                if current_block_class == CLS_BRIM:
                    v.towerskipped = True
                    v.side_wipe_state = 0

            if not v.towerskipped and (g[gcode.MOVEMENT] & 3) != 0:
                if (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER:
                    v.towerskipped = True
                    v.side_wipe_state = 1 if (current_block_class
                                              == CLS_TOOL_PURGE) else 0

            if v.towerskipped and current_block_class == CLS_NORMAL and (
                    g[gcode.MOVEMENT] & 3) == 3:
                if (v.bed_origin_x <= g[gcode.X] <= v.bed_max_x) and (
                        v.bed_origin_y <= g[gcode.Y] <= v.bed_max_y):
                    v.towerskipped = False
                    v.side_wipe_state = 0
                    if v.toolchange_processed and v.side_wipe_length:
                        create_side_wipe()
                        v.toolchange_processed = False

            if v.towerskipped:
                inc = "NO_E"
                if current_block_class in [
                        CLS_TOOL_PURGE, CLS_ENDPURGE
                ] or (current_block_class == CLS_EMPTY
                      and v.side_wipe_state == 1):
                    if g[gcode.EXTRUDE]:
                        v.side_wipe_length += g[gcode.E]
                        inc = "INC_E"

                gcode.move_to_comment(
                    g, "--P2PP-- side wipe skipped ({})".format(inc))
                gcode.issue_command(g)
                continue

            # for PS2.4
            # before first extrusion prime the nozzle
            if not v.mechpurge_hasprimed and g[gcode.EXTRUDE]:
                if v.bigbrain3d_purge_enabled or v.blobster_purge_enabled:
                    create_side_wipe(v.mechpurge_prime_blobs *
                                     v.mechpurge_blob_size)
                v.mechpurge_hasprimed = True

        # --------------------- FULL PURGE PROCESSING
        elif v.full_purge_reduction:

            if (g[gcode.MOVEMENT] & 3) > 0:  # if there is a movement
                intower = (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER

            if classupdate:

                if current_block_class == CLS_NORMAL:
                    v.towerskipped = False
                    purge = False

                if current_block_class == CLS_TOOL_PURGE:
                    purge = True

            if not v.towerskipped and current_block_class == CLS_EMPTY and v.current_layer_is_skippable:
                v.towerskipped = (g[gcode.MOVEMENT]
                                  & gcode.INTOWER) == gcode.INTOWER

            if v.towerskipped or current_block_class in [
                    CLS_BRIM, CLS_ENDGRID
            ]:
                gcode.move_to_comment(
                    g, "--P2PP-- full purge skipped [Excluded]")
                gcode.issue_command(g)
                continue

            if current_block_class in [
                    CLS_TOOL_PURGE, CLS_ENDPURGE, CLS_EMPTY
            ]:
                if purge and g[gcode.EXTRUDE]:
                    v.side_wipe_length += g[gcode.E]
                    gcode.move_to_comment(
                        g, "--P2PP-- full purge skipped [Included]")
                else:
                    gcode.move_to_comment(
                        g, "--P2PP-- full purge skipped [Excluded]")
                gcode.issue_command(g)
                continue

            if v.toolchange_processed and current_block_class == CLS_NORMAL:
                if v.side_wipe_length and (
                        g[gcode.MOVEMENT]
                        & 3) == 3 and not (g[gcode.MOVEMENT]
                                           & gcode.INTOWER) == gcode.INTOWER:
                    purgetower.purge_generate_sequence()
                    v.toolchange_processed = False
                    # do not issue code here as the next code might require further processing such as retractioncorrection
                else:
                    gcode.move_to_comment(g, "--P2PP-- full purge skipped")
                    gcode.issue_command(g)
                    continue

            if v.expect_retract and (g[gcode.MOVEMENT] & 3):
                v.expect_retract = False
                if v.retraction >= 0 and g[gcode.RETRACT]:
                    purgetower.retract(v.current_tool)

            if v.retract_move and g[gcode.RETRACT]:
                g[gcode.X] = v.retract_x
                g[gcode.Y] = v.retract_y
                g[gcode.MOVEMENT] |= 3
                v.retract_move = False

                if v.retraction <= -v.retract_length[v.current_tool]:
                    gcode.move_to_comment(g, "--P2PP-- Double Retract")
                else:
                    v.retraction += g[gcode.E]

            if intower:
                gcode.move_to_comment(
                    g, "--P2PP-- full purge skipped [Excluded]")
                gcode.issue_command(g)
                continue

        # --------------------- NO TOWER PROCESSING
        else:

            if current_block_class in [CLS_TOOL_PURGE, CLS_EMPTY
                                       ] and g[gcode.E]:
                if v.acc_ping_left <= 0:
                    pings.check_accessorymode_first()
                    v.enterpurge = True

            # TOEE - Added to limit the speed of the extrusions during purge to defined WIPEFEEDRATE
            if current_block_class == CLS_TOOL_PURGE:
                speed_limiter(g)

            if v.toolchange_processed:
                if v.temp2_stored_command != "":
                    wait_location = calculate_temp_wait_position()
                    gcode.issue_code(
                        "G1 X{:.3f} Y{:.3f} F8640; temp wait position\n".
                        format(wait_location[0], wait_location[0]))
                    gcode.issue_code(v.temp2_stored_command)
                    v.temp2_stored_command = ""

                gcode.issue_code("G1 F8640 ; correct speed")
                gcode.issue_command(g)
                if v.wipe_remove_sparse_layers:
                    gcode.issue_code(
                        "G1 X{}  Y{} F8640 ;P2PP Position XY to avoid tower crash"
                        .format(v.current_position_x, v.current_position_y))
                v.z_correction = "G1 Z{} F10800 ;P2PP correct z-moves".format(
                    v.current_position_z)

                v.toolchange_processed = False
                continue

            if current_block_class == CLS_TOOL_PURGE:
                if g[gcode.F] is not None and g[
                        gcode.F] > v.purgetopspeed and g[gcode.E]:
                    g[gcode.F] = v.purgetopspeed
                    g[gcode.COMMENT] += " prugespeed topped"

        # --------------------- GLOBAL PROCEDDING

        if g[gcode.UNRETRACT]:
            g[gcode.E] = min(-v.retraction, g[gcode.E])
            v.retraction += g[gcode.E]
        elif g[gcode.RETRACT]:
            v.retraction += g[gcode.E]
        elif (g[gcode.MOVEMENT] & 3) and g[gcode.EXTRUDE]:
            if v.z_correction is not None or v.retraction < -0.01:
                if current_block_class != CLS_TOOL_START:
                    gcode.issue_code(";P2PP START Z/E alignment processing")
                    if v.z_correction is not None:
                        gcode.issue_code(v.z_correction)
                        v.z_correction = None
                    if v.retraction < -0.01:
                        purgetower.unretract(v.retraction, -1,
                                             ";--- P2PP --- fixup retracts")
                    gcode.issue_code(";P2PP END Z/E alignment processing")
                else:
                    gcode.issue_command(g)
                    gcode.issue_code(";P2PP START Z/E alignment processing")
                    if v.z_correction is not None:
                        gcode.issue_code(v.z_correction)
                        v.z_correction = None
                    if v.retraction < -0.01:
                        purgetower.unretract(v.retraction, -1,
                                             ";--- P2PP --- fixup retracts")
                    g = gcode.create_command(
                        ";P2PP END Z/E alignment processing")

        # --------------------- PING PROCESSING

        if v.accessory_mode and g[gcode.EXTRUDE]:
            if not pings.check_accessorymode_second(g[gcode.E]):
                gcode.issue_command(g)
        else:
            gcode.issue_command(g)
            if g[gcode.EXTRUDE] and v.side_wipe_length == 0:
                pings.check_connected_ping()

        v.previous_position_x = v.current_position_x
        v.previous_position_y = v.current_position_y

    # LAST STEP IS ADDING AN EXTRA TOOL UNLOAD TO DETERMINE THE LENGTH OF THE LAST SPLICE
    gcode_process_toolchange(-1)
Ejemplo n.º 6
0
def parse_gcode_first_pass():
    v.layer_toolchange_counter = 0
    v.layer_emptygrid_counter = 0

    v.block_classification = CLS_NORMAL
    v.previous_block_classification = CLS_NORMAL
    total_line_count = len(v.input_gcode)

    flh = int(v.first_layer_height * 100)
    olh = int(v.layer_height * 100)

    backpass_line = -1
    jndex = 0

    find_alternative_tower()

    for index in range(total_line_count):

        v.previous_block_classification = v.block_classification

        # memory management, reduce size of data structures when data is processed
        line = v.input_gcode[jndex]
        jndex += 1
        if jndex == 100000:
            gui.progress_string(4 + 46 * index // total_line_count)
            v.input_gcode = v.input_gcode[jndex:]
            jndex = 0

        # actual line processing, starting with comments processing
        if line.startswith(';'):

            is_comment = True

            # extract thumbnail from gcode file
            if not v.p3_processing_thumbnail_end:
                if line.startswith("; thumbnail"):
                    v.p3_thumbnail = not v.p3_thumbnail
                    if not v.p3_thumbnail:
                        v.p3_processing_thumbnail_end = True
                        v.p3_thumbnail_data = v.p3_thumbnail_data.replace(
                            "; ", "")
                elif v.p3_thumbnail:
                    v.p3_thumbnail_data += line

            # extract the main gcode building blocks
            if line.startswith(
                    '; CP'
            ):  # code block assignment, based on Prusa Slicer injected CP comments
                update_class(hash(line[5:]))

            # determine the layerheight at which we're printing
            elif line.startswith(
                    ';LAYERHEIGHT'
            ):  # Layer instructions, used to calculate the layer number
                fields = line.split(' ')
                try:
                    lv = float(fields[1])
                    lv = int((lv + 0.001) * 100) - flh
                    if lv % olh == 0:
                        process_layer(int(lv / olh), index)
                except (ValueError, IndexError):
                    pass

        else:

            is_comment = False

            try:
                if line[0] == 'T':
                    if v.set_tool == -1:  # ignore the first tool setting for purging
                        v.block_classification = CLS_NORMAL
                    else:
                        v.block_classification = CLS_TOOL_PURGE
                    cur_tool = int(line[1])
                    v.set_tool = cur_tool
            except (TypeError, ValueError):
                gui.log_warning("Unknown T-command: {}".format(line))
            except IndexError:  # in case there is an empty line there will be no line[0]
                pass

        code = gcode.create_command(line, is_comment, v.block_classification)
        v.parsed_gcode.append(code)

        if v.block_classification != v.previous_block_classification:

            if v.block_classification in [
                    CLS_TOOL_START, CLS_TOOL_UNLOAD, CLS_EMPTY, CLS_BRIM
            ]:
                for idx in range(backpass_line, len(v.parsed_gcode)):
                    v.parsed_gcode[idx][gcode.CLASS] = v.block_classification

        # determine tower size - old method
        if v.tower_measure:
            code[gcode.MOVEMENT] += gcode.INTOWER
            if code[gcode.X]:
                v.wipe_tower_info_minx = min(
                    v.wipe_tower_info_minx,
                    code[gcode.X] - 2 * v.extrusion_width)
                v.wipe_tower_info_maxx = max(
                    v.wipe_tower_info_maxx,
                    code[gcode.X] + 2 * v.extrusion_width)
            if code[gcode.Y]:
                v.wipe_tower_info_miny = min(
                    v.wipe_tower_info_miny,
                    code[gcode.Y] - 4 * 2 * v.extrusion_width)
                v.wipe_tower_info_maxy = max(
                    v.wipe_tower_info_maxy,
                    code[gcode.Y] + 4 * 2 * v.extrusion_width)

        if v.bedtrace:
            if (code[gcode.MOVEMENT] &
                (gcode.X + gcode.Y)) and v.bed is not None:
                if code[gcode.EXTRUDE]:
                    v.bed.line(code[gcode.X], code[gcode.Y])
                else:
                    v.bed.position(code[gcode.X], code[gcode.Y])

        # determine block separators by looking at the last full XY positioning move
        if (code[gcode.MOVEMENT] & 3) == 3:
            if (code[gcode.MOVEMENT] & 12) == 0:
                backpass_line = len(v.parsed_gcode) - 1

            # add
            if v.side_wipe_towerdefined:
                if ((v.wipe_tower_info_minx <= code[gcode.X] <=
                     v.wipe_tower_info_maxx)
                        and (v.wipe_tower_info_miny <= code[gcode.Y] <=
                             v.wipe_tower_info_maxy)):
                    code[gcode.MOVEMENT] += gcode.INTOWER

            if v.block_classification in [CLS_ENDGRID, CLS_ENDPURGE]:
                if not (code[gcode.MOVEMENT] & gcode.INTOWER):
                    v.parsed_gcode[-1][gcode.CLASS] = CLS_NORMAL
                    v.block_classification = CLS_NORMAL

        if v.block_classification == CLS_BRIM_END:
            v.block_classification = CLS_NORMAL

    v.input_gcode = None
Ejemplo n.º 7
0
def p2pp_process_file(input_file, output_file):
    starttime = time.time()

    if output_file is None:
        output_file = input_file

    # get the base name from the environment variable if available....
    # check for P3 that output is written to file at this point.
    # check for P3 that the output file is named mcfx

    try:
        basename = os.environ["SLIC3R_PP_OUTPUT_NAME"]
        pathname = os.path.dirname(os.environ["SLIC3R_PP_OUTPUT_NAME"])
        maffile = basename
        mybasename = os.path.basename(basename)

        if v.palette3 and not os.environ["SLIC3R_PP_HOST"].startswith("File"):
            gui.log_warning("Palette 3 File uploading currently not supported")

        if v.palette3 and not os.environ["SLIC3R_PP_HOST"].endswith(".mcfx"):
            gui.log_warning("Palette 3 files should have a .mcfx extension")

    # if any the retrieval of this information fails, the good old way is used

    except KeyError:
        maffile = output_file
        basename = os.path.basename(input_file)
        mybasename = basename
        pathname = os.path.dirname(input_file)

    gui.setfilename(basename)

    # Determine the task name for this print form the filename without any extensions.
    _task_name = os.path.splitext(mybasename)[0].replace(" ", "_")
    _task_name = _task_name.replace(".mcfx", "")
    _task_name = _task_name.replace(".mcf", "")
    _task_name = _task_name.replace(".gcode", "")

    gui.app.sync()

    # Read the input file
    try:
        opf = open(input_file, encoding='utf-8')
        gui.create_logitem("Reading File " + input_file)
        gui.progress_string(1)
        v.input_gcode = opf.readlines()
        opf.close()
        v.input_gcode = [item.strip() for item in v.input_gcode]

    except (IOError, MemoryError):
        gui.log_warning("Error Reading: '{}'".format(input_file))
        return

    gui.create_logitem("Analyzing Prusa Slicer Configuration")
    gui.progress_string(2)

    parse_config_parameters(
    )  # Parse the Prusa Slicer  and P2PP Config Parameters

    # Write the unprocessed file
    if v.save_unprocessed:
        pre, ext = os.path.splitext(input_file)
        of = pre + "_unprocessed" + ext
        gui.create_logitem("Saving unpocessed code to: " + of)
        opf = open(of, "wb")
        for line in v.input_gcode:
            opf.write(line.encode('utf8'))
            opf.write("\n" "".encode('utf8'))
        opf.close()

    gui.progress_string(4)
    gui.create_logitem("GCode Analysis ... Pass 1")
    parse_gcode_first_pass()

    if config_checks() == -1:
        return

    gui.create_logitem("Gcode Analysis ... Pass 2")
    parse_gcode_second_pass()

    v.processtime = time.time() - starttime

    omega_result = header_generate_omega(_task_name)
    header = omega_result['header'] + omega_result['summary'] + omega_result[
        'warnings']

    # write the output file
    ######################

    path, _ = os.path.split(output_file)

    if v.palette3 and not v.accessory_mode:
        opf = open(os.path.join(path, "print.gcode"), "wb")
        gui.create_logitem("Generating MCFX file: " + output_file)
    else:
        opf = open(output_file, "wb")
        gui.create_logitem(
            "Generating GCODE file: (temp location, PS will move) " +
            output_file)

    if not v.accessory_mode and not v.palette3:
        for line in header:
            opf.write(line.encode('utf8'))
        opf.write(
            ("\n\n;--------- THIS CODE HAS BEEN PROCESSED BY P2PP v{} --- \n\n"
             .format(version.Version)).encode('utf8'))
        if v.generate_M0:
            header.append("M0\n")
        opf.write("T0\n".encode('utf8'))
    else:
        opf.write(
            ("\n\n;--------- THIS CODE HAS BEEN PROCESSED BY P2PP v{} --- \n\n"
             .format(version.Version)).encode('utf8'))

    if v.splice_offset == 0:
        gui.log_warning("SPLICE_OFFSET not defined")
    for line in v.processed_gcode:
        try:
            opf.write(line.encode('utf8'))
        except IOError:
            gui.log_warning(
                "Line : {} could not be written to output".format(line))
        opf.write("\n".encode('utf8'))
    opf.close()

    if v.palette3:
        meta, palette = header_generate_omega_palette3(None)

        meta_file = os.path.join(path, "meta.json")
        palette_file = os.path.join(path, "palette.json")
        im_file = os.path.join(path, "thumbnail.png")

        # 22/02/2022 added accessory mode for palette 3
        if v.accessory_mode:
            gcode_file = os.path.join(path, output_file)
        else:
            gcode_file = os.path.join(path, "print.gcode")

        gui.create_logitem("Generating Palette 3 output files")
        mf = open(meta_file, 'wb')
        mf.write(meta.__str__().encode('ascii'))
        mf.close()

        pa = open(palette_file, 'wb')
        pa.write(palette.__str__().encode('ascii'))
        pa.close()

        im = open(im_file, "wb")
        if len(v.p3_thumbnail_data) == 0:
            gui.log_warning(
                "Thumbnail Info missing (Printer Settings/General/Firmware/G-Code Thumbnail"
            )

        im.write(base64.b64decode(v.p3_thumbnail_data))
        im.close()

        # 22/02/2022 added accessory mode for palette 3
        if v.accessory_mode:
            maffile = maffile + ".mafx"
            maffile = maffile.replace(".gcode", "")
            gui.create_logitem("Generating PALETTE MAFX file: " + maffile)
            zipf = zipfile.ZipFile(maffile, 'w', zipfile.ZIP_DEFLATED)
            zipf.write(meta_file, "meta.json")
            zipf.write(palette_file, "palette.json")
            zipf.write(im_file, "thumbnail.png")
            zipf.close()
        else:
            zipf = zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED)
            zipf.write(meta_file, "meta.json")
            zipf.write(palette_file, "palette.json")
            zipf.write(gcode_file, "print.gcode")
            zipf.write(im_file, "thumbnail.png")
            zipf.close()
            os.remove(os.path.join(path, "print.gcode"))

        os.remove(meta_file)
        os.remove(palette_file)
        os.remove(im_file)

    # 22/02/2022 added accessory mode for palette 3
    if v.accessory_mode and not v.palette3:

        pre, ext = os.path.splitext(maffile)
        if v.palette_plus:
            maffile = pre + ".msf"
        else:
            maffile = pre + ".maf"

        maffile = os.path.basename(maffile)
        maffile = os.path.join(pathname, maffile)

        gui.create_logitem("Generating PALETTE MAF/MSF file: " + maffile)

        maf = open(maffile, 'wb')

        for h in header:
            h = str(h).strip("\r\n")
            maf.write(h.encode('ascii'))
            maf.write("\r\n".encode('ascii'))

        maf.close()

    gui.print_summary(omega_result['summary'])

    gui.progress_string(101)

    if v.palette3:
        gui.create_logitem(
            "===========================================================================================",
            "green")
        gui.create_logitem(
            "Go to https://github.com/tomvandeneede/p2pp/wiki for more information on P2PP Configuration",
            "green")
        gui.create_logitem(
            "===========================================================================================",
            "green")

    if v.uploadfile:

        try:  # get the correct output filename from the PS environment variable
            filename = os.path.basename(os.environ["SLIC3R_PP_OUTPUT_NAME"])
            if filename.endswith(".gcode"):
                filename = filename.replace(".gcode", ".mcfx")

            filename = filename.replace(" ", "_")
        except (TypeError,
                KeyError):  # regardsless of the error, use this filename
            filename = "output.mcfx"

        upload.uploadfile(output_file, filename)

    if (len(v.process_warnings) > 0
            and not v.ignore_warnings) or v.consolewait:

        gui.close_button_enable()