def header_generate_omega(job_name): if v.printer_profile_string == '': v.printer_profile_string = v.default_printerprofile if v.palette3: v.printer_profile_string = v.default_printerprofile + v.default_printerprofile else: v.printer_profile_string = v.default_printerprofile gui.log_warning( "The PRINTERPROFILE identifier is missing, Default will be used {} \n" .format(v.printer_profile_string)) v.printer_profile_string = v.default_printerprofile if len(v.splice_extruder_position) == 0 and not v.palette3: gui.log_warning("This does not look like a multi-colour file.\n") if v.palette3: return { 'header': [], 'summary': generatesummary(), 'warnings': generatewarnings() } algorithm_create_table() if not v.palette_plus: return header_generate_omega_palette2(job_name) else: return header_generate_omega_paletteplus()
def purge_create_layers(x, y, w, h): global solidlayer, emptylayer, filllayer solidlayer = [] emptylayer = [] filllayer = [] ew = v.extrusion_width if ew == 0: ew = 0.45 gui.log_warning("Extrusion Width of 0 detected, using default 0.45mm") w = int(w / ew) * ew h = int(h / ew) * ew solidlayer.append(gcode.create_command(";---- SOLID WIPE -------")) generate_rectangle(solidlayer, x, y, w, h) emptylayer.append(gcode.create_command(";---- EMPTY WIPE -------")) generate_rectangle(emptylayer, x, y, w, h) filllayer.append(gcode.create_command(";---- FILL LAYER -------")) generate_rectangle(filllayer, x, y, w, h) _purge_create_sequence(solidlayer, "G1 X{:.3f} Y{:.3f} F%SPEED%", x, y, w, h, ew) _purge_create_sequence(emptylayer, "G1 Y{:.3f} X{:.3f} F%SPEED%", y, x, h, w, 2) _purge_create_sequence(filllayer, "G1 Y{:.3f} X{:.3f} F%SPEED%", y, x, h, w, 15) _purge_generate_tower_brim(x, y, w, h) _purge_calculate_sequences_length() v.purge_sequence_x = x v.purge_sequence_y = y
def generatesummary(): summary = [ ";Splice Information:\n", ";-------------------\n", "; Splice Offset = {:-8.2f}mm\n".format(v.splice_offset), "; Autoloading Offset = {:-8.2f}mm\n\n".format( v.autoloadingoffset) ] for i in range(len(v.splice_extruder_position)): if i == 0: pos = 0 else: pos = v.splice_extruder_position[i - 1] summary.append( ";{:04} Input: {} Location: {:-8.2f}mm length {:-8.2f}mm \n". format(i + 1, v.splice_used_tool[i] + 1, pos, v.splice_length[i])) summary.append("\n") summary.append(";Ping Information:\n") summary.append(";-----------------\n") for i in range(len(v.ping_extruder_position)): pingtext = ";Ping {:04} at {:-8.2f}mm\n".format( i + 1, v.ping_extruder_position[i]) summary.append(pingtext) if v.side_wipe and v.side_wipe_loc == "" and not v.bigbrain3d_purge_enabled and not v.blobster_purge_enabled: gui.log_warning("Using sidewipe with undefined SIDEWIPELOC!!!") return summary
def header_generate_omega(job_name): if v.printer_profile_string == '': gui.log_warning( "The PRINTERPROFILE identifier is missing, Please add:\n" + ";P2PP PRINTERPROFILE=<your printer profile ID>\n" + "to your Printers Start GCODE.\n") if len(v.splice_extruder_position) == 0: gui.log_warning("This does not look like a multi-colour file.\n") if v.gui: if gui.ask_yes_no( 'Not a Multi-Colour file?', "This doesn't look like a multi-colour file. Skip processing?" ): exit(1) else: if yes_or_no( "This does not look like a multi-colour file.. Skip P2PP Processing?\n" ): exit(1) algorithm_create_table() if not v.palette_plus: return header_generate_omega_palette2(job_name) else: return header_generate_omega_paletteplus()
def optimize_tower_skip(skipmax, layersize): skipped = 0.0 skipped_num = 0 if v.side_wipe or v.bigbrain3d_purge_enabled: base = -1 else: base = 0 for idx in range(len(v.skippable_layer) - 1, base, -1): if skipped + 0.005 >= skipmax: v.skippable_layer[idx] = False elif v.skippable_layer[idx]: skipped = skipped + layersize skipped_num += 1 if v.tower_delta: if skipped > 0: gui.log_warning( "Warning: Purge Tower delta in effect: {} Layers or {:-6.2f}mm".format(skipped_num, skipped)) else: gui.create_logitem("Tower Purge Delta could not be applied to this print") for idx in range(len(v.skippable_layer)): v.skippable_layer[idx] = False v.tower_delta = False if not v.side_wipe and not v.bigbrain3d_purge_enabled: v.skippable_layer[0] = False
def generate_blobster_advanced_blob(count): issue_code("\n;---- BLOBSTER ADVANCED BLOB {}".format(count + 1), True) setfanspeed(0) if count > 0: issue_code("G4 P2000 ; Interblob wait") issue_code("G1 X{:.3f} F1000 ; go to the actual wiping position".format( v.mechpurge_x_position)) # takes 2.5 seconds issue_code("G4 P{} ; Wait for Blobster to engage before purging".format( v.blobster_engagetime)) if v.retraction < 0: purgetower.largeunretract() try: for i in range(len(v.blobster_advanced_speed)): setfanspeed(v.blobster_advanced_fan[i]) issue_code("G1 E{:6.3f} F{} ; Purge Part {} ".format( v.blobster_advanced_length[i], v.blobster_advanced_speed[i], i + 1)) except IndexError: if not v.blobsterwarning: gui.log_warning( "BLOBSTER ERROR: THIS FILE WILL NOT PRING AS EXPECTED!!!") v.blobsterwarning = True purgetower.largeretract(v.mechpurge_retract) setfanspeed(255) issue_code("G4 S{0:.0f} ; blob {0}s cooling time".format( v.mechpurge_blob_cooling_time)) issue_code( "G1 X{:.3f} F10800 ; activate flicker".format(v.mechpurge_x_position - v.bigbrain3d_left * 30))
def algorithm_process_material_configuration(splice_info): # 22/02/2022 - Added check for correctness of the parameters error = True fields = splice_info.split("_") if fields[0] == "DEFAULT" and len(fields) == 4: try: check = float(fields[1]) + float(fields[2]) + float(fields[3]) v.default_splice_algorithm = algorithm_create_process_string( fields[1], fields[2], fields[3]) error = False except ValueError: pass if len(fields) == 5: key = "{}{}".format(fields[0], fields[1]) try: check = float(fields[2]) + float(fields[3]) + float(fields[4]) error = False v.splice_algorithm_dictionary[ key] = algorithm_create_process_string(fields[2], fields[3], fields[4]) except ValueError: pass if error: gui.log_warning("Error splice info: {}".format(splice_info))
def generatesummary(): summary = [ ";---------------------\n", "; - SPLICE INFORMATION-\n", ";---------------------\n", "; Splice Offset = {:-8.2f}mm\n\n".format(v.splice_offset) ] for i in range(len(v.splice_extruder_position)): if i == 0: pos = 0 else: pos = v.splice_extruder_position[i - 1] summary.append( ";{:04} Tool: {} Location: {:-8.2f}mm length {:-8.2f}mm ({})\n" .format(i + 1, v.splice_used_tool[i], pos, v.splice_length[i], hexify_float(pos))) summary.append("\n") summary.append(";-------------------\n") summary.append("; - PING INFORMATION-\n") summary.append(";-------------------\n") for i in range(len(v.ping_extruder_position)): pingtext = ";Ping {:04} at {:-8.2f}mm ({})\n".format( i + 1, v.ping_extruder_position[i], hexify_float(v.ping_extruder_position[i])) summary.append(pingtext) if v.side_wipe and v.side_wipe_loc == "": gui.log_warning("Using sidewipe with undefined SIDEWIPELOC!!!") return summary
def generatesummary(): summary = [] summary.append(";---------------------\n") summary.append("; - COLORS DEFINED -\n") summary.append(";---------------------\n") summary.append(";Number of extruders defined in PrusaSlicer: {}\n".format( v.m4c_numberoffilaments)) summary.append(";Number of color swaps in this print: {}\n".format( len(v.m4c_late_warning))) summary.append(";Filament defined for this print:\n") for i in range(v.m4c_numberoffilaments): try: id = v.filament_ids[i] except IndexError: id = "" summary.append(";. Filament {} - Color Code {} - {:20} {}\n".format( i + 1, v.filament_color_code[i], find_nearest_colour(v.filament_color_code[i].strip("\n")), id)) summary.append("\n") summary.append(";---------------------\n") summary.append("; - SPLICE INFORMATION-\n") summary.append(";---------------------\n") summary.append("; Splice Offset = {:-8.2f}mm\n".format( v.splice_offset)) summary.append("; Autoloading Offset = {:-8.2f}mm\n\n".format( v.autoloadingoffset)) for i in range(len(v.splice_extruder_position)): if i == 0: pos = 0 else: pos = v.splice_extruder_position[i - 1] summary.append( ";{:04} Input: {} Location: {:-8.2f}mm length {:-8.2f}mm ({})\n" .format(i + 1, v.splice_used_tool[i] + 1, pos, v.splice_length[i], hexify_float(pos))) summary.append("\n") summary.append(";-------------------\n") summary.append("; - PING INFORMATION-\n") summary.append(";-------------------\n") for i in range(len(v.ping_extruder_position)): pingtext = ";Ping {:04} at {:-8.2f}mm ({})\n".format( i + 1, v.ping_extruder_position[i], hexify_float(v.ping_extruder_position[i])) summary.append(pingtext) if v.side_wipe and v.side_wipe_loc == "" and not v.bigbrain3d_purge_enabled: gui.log_warning("Using sidewipe with undefined SIDEWIPELOC!!!") return summary
def swap_pause(command): global warning if v.z_maxheight > 0: lift = min(v.current_position_z + 20, v.z_maxheight) else: lift = v.current_position_z + 20 if warning: gui.log_warning("Manual swap lift of 20 without constraint!!") gc.issue_code(";MANUAL SWAP PAUSE SEQUENCE") gc.issue_code("G1 Z{:.2f} F10800".format(lift)) gc.issue_code(command)
def gcode_process_toolchange(new_tool, location, current_layer): # some commands are generated at the end to unload filament, # they appear as a reload of current filament - messing up things if new_tool == v.current_tool: return location += v.splice_offset if new_tool == -1: location += v.extra_runout_filament v.material_extruded_per_color[v.current_tool] += v.extra_runout_filament v.total_material_extruded += v.extra_runout_filament else: v.palette_inputs_used[new_tool] = True length = location - v.previous_toolchange_location if v.current_tool != -1: v.splice_extruder_position.append(location) v.splice_length.append(length) v.splice_used_tool.append(v.current_tool) v.autoadded_purge = 0 if len(v.splice_extruder_position) == 1: if v.splice_length[0] < v.min_start_splice_length: if v.autoaddsplice and (v.full_purge_reduction or v.side_wipe): v.autoadded_purge = v.min_start_splice_length - length else: gui.log_warning("Warning : Short first splice (<{}mm) Length:{:-3.2f}".format(length, v.min_start_splice_length)) filamentshortage = v.min_start_splice_length - v.splice_length[0] v.filament_short[new_tool] = max(v.filament_short[new_tool], filamentshortage) else: if v.splice_length[-1] < v.min_splice_length: if v.autoaddsplice and (v.full_purge_reduction or v.side_wipe): v.autoadded_purge = v.min_splice_length - v.splice_length[-1] else: gui.log_warning("Warning: Short splice (<{}mm) Length:{:-3.2f} Layer:{} Input:{}". format(v.min_splice_length, length, current_layer, v.current_tool + 1)) filamentshortage = v.min_splice_length - v.splice_length[-1] v.filament_short[new_tool] = max(v.filament_short[new_tool], filamentshortage) v.side_wipe_length += v.autoadded_purge v.splice_extruder_position[-1] += v.autoadded_purge v.splice_length[-1] += v.autoadded_purge v.previous_toolchange_location = v.splice_extruder_position[-1] v.previous_tool = v.current_tool v.current_tool = new_tool
def optimize_tower_skip(skipmax, layersize): skipped = 0.0 skipped_num = 0 for idx in range(len(v.skippable_layer) - 1, 0, -1): if skipped >= skipmax: v.skippable_layer[idx] = False elif v.skippable_layer[idx]: skipped = skipped + layersize skipped_num += 1 if v.tower_delta and skipped > 0: gui.log_warning( "Warning: Purge Tower delta in effect: {} Layers or {:-6.2f}mm". format(skipped_num, skipped)) else: gui.create_logitem( "Tower Purge Delta could not be applied to this print")
def update_class(gcode_line): v.previous_block_classification = v.block_classification if gcode_line[0] == "T": v.block_classification = CLS_TOOL_PURGE if gcode_line.startswith("; CP"): if "PRIMING START" in gcode_line: gui.log_warning("Extruder Primimng will not work with P2PP") if "TOOLCHANGE START" in gcode_line: v.block_classification = CLS_TOOL_START if "TOOLCHANGE UNLOAD" in gcode_line: v.block_classification = CLS_TOOL_UNLOAD if "TOOLCHANGE WIPE" in gcode_line: v.block_classification = CLS_TOOL_PURGE if "TOOLCHANGE END" in gcode_line: if v.previous_block_classification == CLS_TOOL_UNLOAD: v.block_classification = CLS_NORMAL else: v.block_classification = CLS_TONORMAL if "WIPE TOWER FIRST LAYER BRIM START" in gcode_line: v.block_classification = CLS_BRIM v.tower_measure = True if "WIPE TOWER FIRST LAYER BRIM END" in gcode_line: v.tower_measure = False v.block_classification = CLS_BRIM_END if "EMPTY GRID START" in gcode_line: v.block_classification = CLS_EMPTY if "EMPTY GRID END" in gcode_line: v.block_classification = CLS_ENDGRID if v.block_classification == CLS_TONORMAL and v.previous_block_classification == CLS_TOOL_PURGE: v.block_classification = CLS_ENDPURGE return
def algorithm_create_table(): splice_list = [] for i in range(4): for j in range(4): if i == j: continue try: algo_key = "{}{}".format( v.used_filament_types.index(v.filament_type[i]) + 1, v.used_filament_types.index(v.filament_type[j]) + 1) if algo_key in splice_list: continue except (IndexError, KeyError): continue if not algorithm_transition_used(i, j): continue splice_list.append(algo_key) try: algo = v.splice_algorithm_dictionary["{}{}".format( v.filament_type[i], v.filament_type[j])] except (IndexError, KeyError): gui.log_warning( "WARNING: No Algorithm defined for transitioning" + " {} to {}. Using Default".format(v.filament_type[i], v.filament_type[j])) if v.default_splice_algorithm is None: if v.palette_plus: algo = "0,0,0" else: algo = "D0000 D0000 D0000" else: algo = v.default_splice_algorithm if v.palette_plus: v.splice_algorithm_table.append("({},{})".format( algo_key, algo).replace("-", "")) else: v.splice_algorithm_table.append("D{} {}".format( algo_key, algo))
def __str__(self): p = "" # use the same formatting as prusa to ease file compares (X, Y, Z, E, F) sorted_keys = "XYZE" if self.is_movement_command(): for key in sorted_keys: if key in self.Parameters: form = "" if key in "XYZ": form = "{}{:0.3f} " if key == "E": form = "{}{:0.5f} " value = self.Parameters[key] if value == None: gui.log_warning( "GCode error detected, file might not print correctly" ) value = "" p = p + form.format(key, value) for key in self.Parameters: if not self.is_movement_command() or key not in sorted_keys: value = self.Parameters[key] if value == None: value = "" p = p + "{}{} ".format(key, value) c = self.fullcommand if not c: c = "" if not self.Comment: co = "" else: co = ";" + self.Comment return ("{} {} {}".format(c, p, co)).strip() + "\n"
def check_config_parameters(keyword, value): keyword = keyword.upper() if value is None: value = "" if keyword == "TEMPERATURECONTROL": v.process_temp = True if keyword == "PRINTERPROFILE": if len(value) != 16: gui.log_warning("Invalid Printer profile! - Has invalid length (expect 16) - [{}]" .format(value)) value = "" if not all(char in set("0123456789ABCDEFabcdef") for char in value): gui.log_warning("Invalid Printer profile! - Invalid characters (expect 0123456789abcdef) - [{}]" .format(value)) value = "" if len(value) == 16: v.printer_profile_string = value gui.set_printer_id(v.printer_profile_string) return if keyword == "ACCESSORYMODE_MAF": v.accessory_mode = True gui.create_logitem("Config: Palette2 Accessory Mode Selected") return if keyword == "ACCESSORYMODE_MSF": v.accessory_mode = True v.palette_plus = True gui.create_logitem("Config: Palette+ Accessory Mode Selected") return if keyword == "P+LOADINGOFFSET": v.palette_plus_loading_offset = int(value) return if keyword == "P+PPM": v.palette_plus_ppm = intparameter(value) return if keyword == "SPLICEOFFSET": v.splice_offset = floatparameter(value) gui.create_logitem("Splice Offset set tofiloverride {:-5.2f}mm".format(v.splice_offset)) return if keyword == "PROFILETYPEOVERRIDE": v.filament_type[v.set_tool] = value v.used_filament_types.append(v.filament_type[v.set_tool]) v.used_filament_types = list(dict.fromkeys(v.used_filament_types)) return if keyword == "EXTRUSIONMULTIPLIERCORRECTION": v.filament_type[v.current_tool] = floatparameter(value) return if keyword == "EXTRAENDFILAMENT": v.extra_runout_filament = floatparameter(value) gui.create_logitem("Extra filament at end of print {:-8.2f}mm".format(v.extra_runout_filament)) return if keyword == "BEFORESIDEWIPEGCODE": v.before_sidewipe_gcode.append(value) return if keyword == "AFTERSIDEWIPEGCODE": v.after_sidewipe_gcode.append(value) return if keyword == "AUTOLOADINGOFFSET": v.autoloadingoffset = floatparameter(value) return if keyword == "AUTOADDPURGE": v.autoaddsplice = True return if keyword == "MINSTARTSPLICE": v.min_start_splice_length = floatparameter(value) if v.min_start_splice_length < 100: v.min_start_splice_length = 100 gui.log_warning("Minimal first slice length adjusted to 100mm") return if keyword == "BEDSIZEX": v.bed_size_x = floatparameter(value) return if keyword == "BEDSIZEY": v.bed_size_y = floatparameter(value) return if keyword == "BEDORIGINX": v.bed_origin_x = floatparameter(value) return if keyword == "BEDORIGINY": v.bed_origin_y = floatparameter(value) return if keyword == "BIGBRAIN3D_BLOBSIZE": v.bigbrain3d_blob_size = intparameter(value) return if keyword == "BIGBRAIN3D_BLOBSPEED": v.bigbrain3d_blob_speed = intparameter(value) return if keyword == "BIGBRAIN3D_COOLINGTIME": v.bigbrain3d_blob_cooling_time = intparameter(value) return if keyword == "BIGBRAIN3D_PURGEPOSITION": v.bigbrain3d_x_position = floatparameter(value) return if keyword == "BIGBRAIN3D_PURGEYPOSITION": v.bigbrain3d_y_position = floatparameter(value) return if keyword == "BIGBRAIN3D_MOTORPOWER_HIGH": v.bigbrain3d_motorpower_high = intparameter(value) return if keyword == "BIGBRAIN3D_MOTORPOWER_NORMAL": v.bigbrain3d_motorpower_normal = intparameter(value) return if keyword == "BIGBRAIN3D_NUMBER_OF_WHACKS": v.bigbrain3d_whacks = intparameter(value) return if keyword == "BIGBRAIN3D_PRIME_BLOBS": v.bigbrain3d_prime = intparameter(value) return if keyword == "BIGBRAIN3D_FAN_OFF_PAUSE": v.bigbrain3d_fanoffdelay = intparameter(value) return if keyword == "BIGBRAIN3D_LEFT_SIDE": v.bigbrain3d_left = -1 return if keyword == "BIGBRAIN3D_ENABLE": if not v.wipe_remove_sparse_layers: v.bigbrain3d_purge_enabled = True gui.log_warning("BIGBRAIN3D Will only work with installed hardware on a Prusa Printer") else: gui.log_warning("BIGBRAIN3D mode not compatible with sparse wipe tower in PS") return if keyword == "BIGBRAIN3D_SMARTFAN": v.bigbrain3d_smartfan = True return if keyword == "MINSPLICE": v.min_splice_length = floatparameter(value) if v.min_splice_length < 70: v.min_splice_length = 70 gui.log_warning("Minimal slice length adjusted to 70mm") return # LINEAR PING removed if keyword == "LINEARPINGLENGTH": v.ping_interval = floatparameter(value) v.ping_length_multiplier = 1.0 if v.ping_interval < 300: v.ping_interval = 300 gui.log_warning("Minimal Linear Ping distance is 300mm! Your config stated: {}".format(line)) gui.create_logitem("Linear Ping interval of {:-6.2f}mm".format(v.ping_interval)) return # SIDE TRANSITIONING if keyword == "SIDEWIPELOC": v.side_wipe_loc = value return if keyword == "PURGETOPSPEED": v.purgetopspeed = int(floatparameter(value)) gui.create_logitem("Purge Max speed set to {:.0f}mm/min ({}mm/s)".format(v.purgetopspeed, v.purgetopspeed / 60)) return if keyword == "WIPEFEEDRATE": v.wipe_feedrate = floatparameter(value) return if keyword == "SIDEWIPEMINY": v.sidewipe_miny = floatparameter(value) return if keyword == "SIDEWIPEMAXY": v.sidewipe_maxy = floatparameter(value) return if keyword == "SIDEWIPECORRECTION": v.sidewipe_correction = floatparameter(value) if v.sidewipe_correction < 0.9 or v.sidewipe_correction > 1.10: v.sidewipe_correction = 1.0 return if keyword == "PURGETOWERDELTA": parm = abs(floatparameter(value)) if parm > 0.001 and v.wipe_remove_sparse_layers: gui.log_warning("TOWER DELTA feature mode not compatible with sparse wipe tower in PS") v.max_tower_delta = 0.0 else: if parm != float(0): v.max_tower_z_delta = abs(floatparameter(value)) gui.create_logitem("Max Purge Tower Delta set to {:-2.2f}mm".format(v.max_tower_z_delta)) return if keyword == "FULLPURGEREDUCTION": if not v.wipe_remove_sparse_layers: gui.create_logitem("Full purge reduction configured") v.full_purge_reduction = True else: gui.log_warning("FULL PURGE TOWER REDUCTION feature mode not compatible with sparse wipe tower in PS") v.full_purge_reduction = False return if keyword == "CHECKVERSION": import p2pp.checkversion as cv import version latest = cv.get_version(cv.MASTER) if latest > version.Version: gui.create_logitem("New development version of P2PP available ({})".format(latest), "red", False, "2.0") else: if (latest < version.Version): latest = cv.get_version(cv.DEV) if (latest > version.Version): gui.create_logitem("New development version of P2PP available ({})".format(latest), "red", False, "2.0") # Program parameters if keyword == "NOGUI": v.gui = False return if keyword == "CONSOLEWAIT": v.consolewait = True return if keyword == "IGNOREWARNINGS": v.ignore_warnings = True return if keyword == "ABSOLUTEEXTRUDER": v.absolute_extruder = True gui.create_logitem("Convert to absolute extrusion parameters") return if keyword == "DEBUGTCOMMAND": v.debug_leaveToolCommands = True gui.log_warning("DEBUGTCOMMAND ACTIVE - File will not print correctly!!") return
def check_config_parameters(line): # BASIC SETUP (material setup handled in mcf.py # -p takes precedence over printer defined in file if "PRINTERPROFILE" in line: tmp_string = stringparameter(line) if len(tmp_string) != 16: gui.log_warning( "Invalid Printer profile! - Has invalid length (expect 16) - [{}]" .format(tmp_string)) tmp_string = "" if not all(char in set("0123456789ABCDEFabcdef") for char in tmp_string): gui.log_warning( "Invalid Printer profile! - Invalid characters (expect 0123456789abcdef) - [{}]" .format(tmp_string)) tmp_string = "" if len(tmp_string) == 16: v.printer_profile_string = tmp_string gui.set_printer_id(v.printer_profile_string) return if "ACCESSORYMODE_MAF" in line: v.accessory_mode = True gui.create_logitem("Config: Palette2 Accessory Mode Selected") if "ACCESSORYMODE_MSF" in line: v.accessory_mode = True v.palette_plus = True gui.create_logitem("Config: Palette+ Accessory Mode Selected") if "P+LOADINGOFFSET" in line: v.palette_plus_loading_offset = int(floatparameter(line)) if "P+PPM" in line: v.palette_plus_ppm = int(floatparameter(line)) if "SPLICEOFFSET" in line: v.splice_offset = floatparameter(line) gui.create_logitem("Splice Offset set to {:-5.2f}mm".format( v.splice_offset)) return if "PROFILETYPEOVERRIDE" in line: v.filament_type[v.current_tool] = stringparameter(line) v.used_filament_types.append(v.filament_type[v.current_tool]) v.used_filament_types = list(dict.fromkeys(v.used_filament_types)) return if "EXTRUSIONMULTIPLIERCORRECTION" in line: v.filament_type[v.current_tool] = floatparameter(line) return if "EXTRAENDFILAMENT" in line: v.extra_runout_filament = floatparameter(line) gui.create_logitem("Extra filament at end of print {:-8.2f}mm".format( v.extra_runout_filament)) return if "BEFORESIDEWIPEGCODE" in line: v.before_sidewipe_gcode.append(stringparameter(line)) return if "AFTERSIDEWIPEGCODE" in line: v.after_sidewipe_gcode.append(stringparameter(line)) return if "MINSTARTSPLICE" in line: v.min_start_splice_length = floatparameter(line) if v.min_start_splice_length < 100: v.min_start_splice_length = 100 gui.log_warning("Minimal first slice length adjusted to 100mm") return if "BEDSIZEX" in line: v.bed_size_x = floatparameter(line) return if "BEDSIZEY" in line: v.bed_size_y = floatparameter(line) return if "BEDORIGINX" in line: v.bed_origin_x = floatparameter(line) return if "BEDORIGINY" in line: v.bed_origin_y = floatparameter(line) return if "BIGBRAIN3D_BLOBSIZE" in line: v.bigbrain3d_blob_size = int(floatparameter(line)) if "BIGBRAIN3D_COOLINGTIME" in line: v.bigbrain3d_blob_cooling_time = int(floatparameter(line)) if "BIGBRAIN3D_PURGEPOSITION" in line: v.bigbrain3d_x_position = floatparameter(line) if "BIGBRAIN3D_MOTORPOWER_HIGH" in line: v.bigbrain3d_motorpower_high = int(floatparameter(line)) if "BIGBRAIN3D_MOTORPOWER_NORMAL" in line: v.bigbrain3d_motorpower_normal = int(floatparameter(line)) if "BIGBRAIN3D_ENABLE" in line: v.bigbrain3d_purge_enabled = True gui.log_warning( "BIGBRAIN3D Will only work with installed hardware on a Prusa Printer" ) if "BIGBRAIN3D_SMARTFAN" in line: v.bigbrain3d_smartfan = True if "MINSPLICE" in line: v.min_splice_length = floatparameter(line) if v.min_splice_length < 70: v.min_splice_length = 70 gui.log_warning("Minimal slice length adjusted to 70mm") return # LINEAR PING removed if "LINEARPINGLENGTH" in line: v.ping_interval = floatparameter(line) v.ping_length_multiplier = 1.0 if v.ping_interval < 300: v.ping_interval = 300 gui.log_warning( "Minimal Linear Ping distance is 300mm! Your config stated: {}" .format(line)) gui.create_logitem("Linear Ping interval of {:-6.2f}mm".format( v.ping_interval)) return if line.endswith("LINEARPING"): gui.log_warning( "LINEARPING deprecated, use LINEARPINGLENGTH parameter instead") return # SIDE TRANSITIONING if "SIDEWIPELOC" in line: v.side_wipe_loc = stringparameter(line) return if "WIPEFEEDRATE" in line: v.wipe_feedrate = floatparameter(line) return if "SIDEWIPEMINY" in line: v.sidewipe_miny = floatparameter(line) return if "SIDEWIPEMAXY" in line: v.sidewipe_maxy = floatparameter(line) return if "SIDEWIPECORRECTION" in line: v.sidewipe_correction = floatparameter(line) if v.sidewipe_correction < 0.9 or v.sidewipe_correction > 1.10: v.sidewipe_correction = 1.0 return if "PURGETOWERDELTA" in line: if abs(floatparameter(line)) != abs(float(0)): v.max_tower_z_delta = abs(floatparameter(line)) gui.create_logitem( "Max Purge Tower Delta set to {:-2.2f}mm".format( v.max_tower_z_delta)) return if "FULLPURGEREDUCTION" in line: gui.create_logitem("Full purge reduction configured") v.full_purge_reduction = True if line.endswith("CHECKVERSION"): import p2pp.checkversion as cv import version latest = cv.get_version(cv.MASTER) if latest > version.Version: gui.create_logitem( "New development version of P2PP available ({})".format( latest), "red", False, "2.0") else: if (latest < version.Version): latest = cv.get_version(cv.DEV) if (latest > version.Version): gui.create_logitem( "New development version of P2PP available ({})". format(latest), "red", False, "2.0") # REPRAP COMPATIBILITY if "REPRAPCOMPATIBLE" in line: v.reprap_compatible = True return # Program parameters if "NOGUI" in line: v.gui = False return if "CONSOLEWAIT" in line: v.consolewait = True if "IGNOREWARNINGS" in line: v.ignore_warnings = True if "ABSOLUTEEXTRUDER" in line: v.absolute_extruder = True gui.create_logitem("Convert to absolute extrusion parameters")
def config_checks(): # CHECK BED SIZE PARAMETERS if v.bed_size_x == -9999 or v.bed_size_y == -9999 or v.bed_origin_x == -9999 or v.bed_origin_y == -9999: gui.log_warning("Bedsize nor or incorrectly defined.") v.bed_max_x = v.bed_origin_x + v.bed_size_x v.bed_max_y = v.bed_origin_y + v.bed_size_y # CHECK EXTRUSION WIDTH if v.extrusion_width == 0: gui.create_logitem("Extrusionwidth set to 0, defaulted back to 0.45") v.extrusion_width = 0.45 if v.process_temp and v.side_wipe: gui.log_warning( "TEMPERATURECONTROL and SIDEWIPE / BigBrain3D are incompatible (TEMPERATURECONTROL disabled" ) v.process_temp = False if v.palette_plus: if v.palette_plus_ppm == -9: gui.log_warning( "P+ parameter P+PPM incorrectly set up in startup GCODE - Processing Halted" ) return -1 if v.palette_plus_loading_offset == -9: gui.log_warning( "P+ parameter P+LOADINGOFFSET incorrectly set up in startup GCODE - Processing Halted" ) return -1 v.side_wipe = not ((v.bed_origin_x <= v.wipe_tower_posx <= v.bed_max_x) and (v.bed_origin_y <= v.wipe_tower_posy <= v.bed_max_y)) v.tower_delta = v.max_tower_z_delta > 0 if (v.tower_delta or v.full_purge_reduction) and v.variable_layer: gui.log_warning( "Variable layers may cause issues with FULLPURGE / TOWER DELTA") gui.log_warning( "This warning could be caused by support that will print on variable layer offsets" ) # sidewipe option compatibility test if v.side_wipe: if v.full_purge_reduction: gui.log_warning( "FULLURGEREDUCTION is incompatible with SIDEWIPE, parameter ignored" ) v.full_purge_reduction = False if v.skirts: if v.ps_version >= "2.2": gui.log_warning( "SIDEWIPE and SKIRTS are NOT compatible in PS2.2 or later") if v.wipe_remove_sparse_layers: gui.log_warning( "SIDE WIPE mode not compatible with sparse wipe tower in PS - Processing Halted" ) return -1 gui.create_logitem("Side wipe activated", "blue") # fullpurge option compatibility test if v.full_purge_reduction: if v.skirts: gui.log_warning( "FULLPURGE and SKIRTS are NOT compatible. Overlaps may occur") if v.tower_delta: gui.log_warning( "FULLPURGEREDUCTION is incompatible with TOWERDELTA") v.tower_delta = False gui.create_logitem("FULLPURGEREDUCTION activated", "blue") # auto add splice length only works with full purge reeduction / sidewipe if v.autoaddsplice: if not v.full_purge_reduction and not v.side_wipe: gui.log_warning( "AUTOADDPURGE only works with SIDEWIPE and FULLPURGEREDUCTION") else: gui.create_logitem("Automatic Splice length increase activated", "blue") if len(v.skippable_layer) == 0: gui.log_warning("P2PP Layer Configuration is missing!!") return -1 skippable = optimize_tower_skip(int(v.max_tower_z_delta / v.layer_height)) if v.tower_delta: v.skippable_layer[0] = False if skippable > 0: gui.log_warning( "TOWERDELTA in effect for {} Layers or {:.2f}mm".format( skippable, skippable * v.layer_height)) else: gui.create_logitem("TOWERDELTA could not be applied to this print") v.tower_delta = False return 0
def check_config_parameters(keyword, value): keyword = keyword.upper().strip() if value is None: value = "" # allows for delaying the change of temperature until after the putge block # not sure if this should stay in future releases. To be evaluated # low complexity, but it adds a waiting position calculation which moves off the regular path. if keyword == "TEMPERATURECONTROL": v.process_temp = True # saves the unprocessed file, so it can be sent for processing simulation in case of errors if keyword == "SAVEUNPROCESSED": v.save_unprocessed = True # enable the preheat function on the Palette 3 if keyword == "P3_PROCESSPREHEAT": v.p3_process_preheat = True # defines the printer profile for config storage on the Palette hardware if keyword == "PRINTERPROFILE": value = value.strip(" ") _idlen = 16 if v.palette3: _idlen = 32 if len(value) != _idlen: gui.log_warning( "Invalid Printer profile! - Has invalid length (expect {}) - [{}]" .format(_idlen, value)) value = "" if not all(char in set("0123456789ABCDEFabcdef") for char in value): gui.log_warning( "Invalid Printer profile! - Invalid characters (expect 0123456789abcdef) - [{}]" .format(value)) value = "" if len(value) <= _idlen: v.printer_profile_string = value return # toggles hardware to Palette 3 - sets the number of inputs, output format. if keyword == "PALETTE3": if len(v.printer_profile_string) == 16: gui.log_warning( "Invalid Printer profile! - P3 printer profile should be 32 characters ({})" .format(v.printer_profile_string)) v.palette3 = True v.colors = 4 # Min first splice length for P3 == 130 v.min_start_splice_length = max(v.min_start_splice_length, v.min_first_splice_p3) v.min_splice_length = max(v.min_splice_length, v.min_splice_p3) check_splice_table() return # toggles hardware to Palette 3 Pro - sets the number of inputs, output format. if keyword == "PALETTE3_PRO": if len(v.printer_profile_string) == 16: gui.log_warning( "Invalid Printer profile! - P3 printer profile should be 32 characters" ) v.palette3 = True v.colors = 8 # Min first splice length for P3 == 130 v.min_start_splice_length = max(v.min_start_splice_length, v.min_first_splice_p3) v.min_splice_length = max(v.min_splice_length, v.min_splice_p3) check_splice_table() return if keyword == "P3_HOSTNAME": v.p3_hostname = value if keyword == "P3_PROFILENAME": v.p3_printername = value if keyword == "P3_UPLOADFILE": v.uploadfile = True if keyword == "P3_SHOWPRINTERPAGE": v.showwebbrowser = True # toggles Palette 3 accessory mode = added 22/02/2022 if keyword == "ACCESSORYMODE_MAFX": v.accessory_mode = True gui.create_logitem("Config: Palette3 Accessory Mode Selected") return # toggles Palette 2 accessory mode if keyword == "ACCESSORYMODE_MAF": v.accessory_mode = True v.colors = 4 gui.create_logitem("Config: Palette2 Accessory Mode Selected") check_splice_table() return # toggles Palette + Accessory Mode if keyword == "ACCESSORYMODE_MSF": v.accessory_mode = True v.palette_plus = True v.colors = 4 gui.create_logitem("Config: Palette+ Accessory Mode Selected") check_splice_table() return # Loading Offset - Required for the P+ configuration, take from existing print after callibration with Chroma if keyword == "P+LOADINGOFFSET": v.palette_plus_loading_offset = int(float(value)) return # PPM - Required for the P+ configuration, take from existing print after callibration with Chroma if keyword == "P+PPM": v.palette_plus_ppm = floatparameter(value) return # Splice offset defines how much the start of the toolchange is located after the position of the toolchange. # in general, you want this value as small as possible BUT this value is the buffer you need when material is consumed # at a too high rate, so putting it very low may result in early transition if keyword == "SPLICEOFFSET": v.splice_offset = floatparameter(value) gui.create_logitem("SPLICE OFFSET: {:-5.2f}mm".format(v.splice_offset)) return # This parameter sets the amount of extra filament that is generated at the end of the print, to allow for the filament to still # engage with the motor gears. This should be at least the plength of the path from the nozzel to the gears of the extruder motor if keyword == "EXTRAENDFILAMENT": v.extra_runout_filament = floatparameter(value) gui.create_logitem("Extra filament at end of print {:-8.2f}mm".format( v.extra_runout_filament)) return # This parameter specified the minimal amount of total filament USE ??? if keyword == "P3_MINIMALTOTALFILAMENT": v.minimaltotal_filament = floatparameter(value) gui.create_logitem("Minimal ilament length {:-8.2f}mm".format( v.minimaltotal_filament)) return # Specially Added for Manmeet - Not documented if keyword == "MANUAL_SWAP": v.manual_filament_swap = True gui.create_logitem("Manual filament swap in place.") return # May be removed ?? if keyword == "BEFORESIDEWIPEGCODE": v.before_sidewipe_gcode.append(value) return # May be removed ?? if keyword == "AFTERSIDEWIPEGCODE": v.after_sidewipe_gcode.append(value) return # unused ??? if keyword == "AUTOLOADINGOFFSET": v.autoloadingoffset = floatparameter(value) return # autmoaticall adds purge in case of short splices when fullpruereduction is applied if keyword == "AUTOADDPURGE": v.autoaddsplice = True return # special reauest feature - not documents - allows for pings shorter than 300 mm if keyword == "POWERCHAOS": # Special feature request to allow sub 300 mm pings v.powerchaos = True return # sets the minimal first splice length (100 / 130 for P2/P3 resp) if keyword == "MINSTARTSPLICE": v.min_start_splice_length = floatparameter(value) if v.palette3: if v.min_start_splice_length < v.min_first_splice_p3: gui.log_warning( "Minimal first slice length adjusted to {}mm for palette 3" .format(v.min_first_splice_p3)) v.min_start_splice_length = v.min_first_splice_p3 if v.min_start_splice_length < 100: v.min_start_splice_length = 100 gui.log_warning("Minimal first slice length adjusted to 100mm") return # firmware purge support if keyword == "FIRMWARE_PURGE_LENGTH": v.firmwarepurge = intparameter(value) return # SECTION BLOBSTER and BB3D # BB3D/BLOBSTER config parm if keyword in ["BIGBRAIN3D_BLOBSIZE", "BLOBSTER_BLOBSIZE"]: v.mechpurge_blob_size = intparameter(value) return # BLOBSTER config parm if keyword in ["BLOBSTER_ENGAGETIME"]: v.blobster_engagetime = intparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_SINGLEBLOB": v.single_blob = True return # BB3D/blobster config parm if keyword in ["BIGBRAIN3D_BLOBSPEED", "BLOBSTER_BLOBSPEED"]: v.mechpurge_blob_speed = intparameter(value) return # BB3D/blobster config parm if keyword in ["BIGBRAIN3D_COOLINGTIME", "BLOBSTER_COOLINGTIME"]: v.mechpurge_blob_cooling_time = intparameter(value) return # BB3D/blobster config parm if keyword in ["BIGBRAIN3D_PURGEPOSITION", "BLOBSTER_PURGEPOSITION"]: v.mechpurge_x_position = floatparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_PURGEYPOSITION": v.bigbrain3d_y_position = floatparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_MOTORPOWER_HIGH": v.bigbrain3d_motorpower_high = intparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_MOTORPOWER_NORMAL": v.bigbrain3d_motorpower_normal = intparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_NUMBER_OF_WHACKS": v.bigbrain3d_whacks = intparameter(value) return # BB3D config parm if keyword in ["BIGBRAIN3D_PRIME_BLOBS", "BLOBSTER_PRIME_BLOBS"]: v.mechpurge_prime_blobs = intparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_FAN_OFF_PAUSE": v.bigbrain3d_fanoffdelay = intparameter(value) return # BB3D config parm if keyword == "BIGBRAIN3D_LEFT_SIDE": v.bigbrain3d_left = -1 return # BB3D/BLOBSTER config parm if keyword in ["BIGBRAIN3D_CLEARANCE_MM", "BLOBSTER_CLEARANCE_MM"]: v.mechpurge_minimalclearenceheight = floatparameter(value) return # BB3D/BLBSTER config parm if keyword in ["BIGBRAIN3D_RETRACT", "BLOBSTER_RETRACT"]: v.mechpurge_retract = floatparameter(value) return # BB3D/BLOBSTER config parm if keyword == "BIGBRAIN3D_ENABLE": if not v.wipe_remove_sparse_layers: v.bigbrain3d_purge_enabled = True gui.create_logitem( "<b>BIGBRAIN3D Will only work with installed hardware on a Prusa Printer</b>" ) else: gui.log_warning( "<b>BIGBRAIN3D mode not compatible with sparse wipe tower in PS</b>" ) return if keyword == "BLOBSTER_ADVANCED": v.blobster_advanced = True gui.create_logitem("<b>BLOBSTER ADVANCED MODE ENABLED</b>") return if keyword == "BLOBSTER_ADVANCED_LENGTH": v.blobster_advanced_length = [] fields = value.split(",") for i in fields: try: v.blobster_advanced_length.append(abs(int(i))) except ValueError: gui.log_warning( "BLOBSTER_ADVANCED_LENGTH parameter accepts a list of interger values (length in mm)" ) return if keyword == "BLOBSTER_ADVANCED_SPEED": v.blobster_advanced_speed = [] fields = value.split(",") for i in fields: try: v.blobster_advanced_speed.append(abs(int(i))) except ValueError: gui.log_warning( "BLOBSTER_ADVANCED_SPEEDH parameter accepts a list of interger values (length in mm)" ) return if keyword == "BLOBSTER_ADVANCED_FAN": v.blobster_advanced_fan = [] fields = value.split(",") for i in fields: try: v.blobster_advanced_fan.append( int(min(abs(int(i)), 100) * 2.55)) except ValueError: gui.log_warning( "BLOBSTER_ADVANCED_FAN parameter accepts a list of interger values (percentage 0-100)" ) return # BB3D/BLOBSTER config parm if keyword == "BLOBSTER_ENABLE": if not v.wipe_remove_sparse_layers: v.blobster_purge_enabled = True v.mechpurge_blob_size = 180 v.mechpurge_minimalclearenceheight = 30 v.mechpurge_blob_cooling_time = 60 gui.create_logitem( "<b>BLOBSTER Will only work with installed hardware on a Prusa Printer</b>" ) else: gui.log_warning( "<b>BLOBSTER mode not compatible with sparse wipe tower in PS</b>" ) return # BB3D/BLOBSTER config parm if keyword in ["BIGBRAIN3D_SMARTFAN", "BLOBSTER_SMARTFAN"]: v.mechpurge_smartfan = True return # defines the minimal splice length ( this is the safe length to make sure a splice is only heated once (70/90 for P2/P3 resp) if keyword == "MINSPLICE": v.min_splice_length = floatparameter(value) if v.palette3: if v.min_splice_length < v.min_splice_p3: gui.log_warning( "Minimal slice length adjusted to {}mm for palette 3". format(v.min_splice_p3)) v.min_splice_length = v.min_splice_p3 if v.min_splice_length < 70: v.min_splice_length = 70 gui.log_warning("Minimal slice length adjusted to 70mm") return # LINEAR PING removed # set the distance between pings (same length every time), instead of increasing ping lengths if keyword == "LINEARPINGLENGTH": v.ping_interval = floatparameter(value) v.ping_length_multiplier = 1.0 if not v.powerchaos: if v.ping_interval < 100: v.ping_interval = 100 gui.log_warning( "Minimal Linear Ping distance is 300mm! Your config stated: {}" .format(value)) gui.create_logitem("Linear Ping interval of {:-6.2f}mm".format( v.ping_interval)) return # Set the location for the side wipes if keyword == "SIDEWIPELOC": v.side_wipe_loc = value return # define a Z-Hop for jumps to the wipe location if keyword == "SIDEWIPEZHOP": v.addzop = floatparameter(value) gui.create_logitem("Side Wipe ZHOP of {:3.2f}mm".format(v.addzop)) # maybe removed?? if keyword == "SIDEWIPEZHOP_SKIPRETURN": v.sidewipe_delay_zreturn = True # set the highest top speed for purging if keyword == "PURGETOPSPEED": v.purgetopspeed = int(floatparameter(value)) # if parameter specified is below 200 then the value is assumed mm/sec and is converted to mm/min if v.purgetopspeed < 200: v.purgetopspeed = v.purgetopspeed * 60 gui.create_logitem( "Purge Max speed set to {:.0f}mm/min ({}mm/s)".format( v.purgetopspeed, v.purgetopspeed / 60)) return # set the wipe feedrate if keyword == "WIPEFEEDRATE": v.wipe_feedrate = floatparameter(value) return # define the sidewipe minimal and macimal Y position if keyword == "SIDEWIPEMINY": v.sidewipe_miny = floatparameter(value) return # define the sidewipe minimal and macimal Y position if keyword == "SIDEWIPEMAXY": v.sidewipe_maxy = floatparameter(value) return # define a extrusion multiplier for sidewipe. needed??? if keyword == "SIDEWIPECORRECTION": v.sidewipe_correction = floatparameter(value) if v.sidewipe_correction < 0.9 or v.sidewipe_correction > 1.10: v.sidewipe_correction = 1.0 return # apply delta (similar to sparse layer removal in PS2.4 if keyword == "PURGETOWERDELTA": parm = abs(floatparameter(value)) if parm > 0.001 and v.wipe_remove_sparse_layers: gui.log_warning( "TOWER DELTA feature mode not compatible with sparse wipe tower in PS" ) v.max_tower_delta = 0.0 else: if parm != float(0): v.max_tower_z_delta = abs(floatparameter(value)) gui.create_logitem( "Max Purge Tower Delta set to {:-2.2f}mm".format( v.max_tower_z_delta)) return # simlir to tower delta but rather reduces the base of the tower to make it growmore evenly with the print if keyword == "FULLPURGEREDUCTION": if not v.wipe_remove_sparse_layers: gui.create_logitem("Full purge reduction configured") v.full_purge_reduction = True v.needpurgetower = True else: gui.log_warning( "FULL PURGE TOWER REDUCTION feature mode not compatible with sparse wipe tower in PS" ) v.full_purge_reduction = False return # chech the version of P2PP on startup (requires an internet connection) if keyword == "CHECKVERSION": import p2pp.checkversion as cv import version latest = cv.get_version(cv.MASTER) if latest: if latest > version.Version: gui.create_logitem( "New version of P2PP available ({})".format(latest), "red", False, "2.0") # co be removed ? if keyword == "DO_NOT_GENERATE_M0": v.generate_M0 = False return # wait for user feedback at the ned of processing if keyword == "CONSOLEWAIT": v.consolewait = True return if keyword == "FINISH_MOVES_M400": v.finish_moves = "M400" v.replace_G4S0 = True # process toolchanges the KLIPPER way if keyword == "KLIPPER_TOOLCHANGE": v.klipper = True return # close and continue even if there are warnings if keyword == "IGNOREWARNINGS": v.ignore_warnings = True return # p2pp_process_file a gcode file with absolute extrusios instead of relative ones if keyword == "ABSOLUTEEXTRUDER": v.absolute_extruder = True gui.create_logitem("Convert to absolute extrusion parameters") return # unused !!! to be removed. if keyword == "DEBUGTCOMMAND": v.debug_leaveToolCommands = True gui.log_warning( "DEBUGTCOMMAND ACTIVE - File will not print correctly!!") return
def check_splice_table(): if len(v.splice_algorithm_table) > 0: gui.log_warning( "Algorithm definitions should appear AFTER Palette Model selection (PALETTE3/PALETTE3_PRO/ACCESSORYMODE_MAF/ACCESSORYMODE_MSF)" )
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()
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)
def header_generate_omega_palette2(job_name): header = [] summary = [] warnings = [] header.append('O21 ' + hexify_short(20) + "\n") # MSF2.0 if v.printer_profile_string == '': v.printer_profile_string = v.default_printerprofile gui.log_warning( "No or Invalid Printer profile ID specified\nusing default P2PP printer profile ID {}" .format(v.default_printerprofile)) header.append('O22 D' + v.printer_profile_string.strip("\n") + "\n") # PRINTERPROFILE used in Palette2 header.append('O23 D0001' + "\n") # unused header.append('O24 D0000' + "\n") # unused str = "O25" initools = v.m4c_loadedinputs[0] if len(initools) < 4: if v.m4c_numberoffilaments == 4: initools = [0, 1, 2, 3] for i in range(4): if not v.palette_inputs_used[i]: initools[i] = -1 else: while len(initools) < 4: initools.append(-1) for i in initools: if i != -1: str += " D{}{}{}{}".format( v.used_filament_types.index(v.filament_type[i]) + 1, v.filament_color_code[i].strip("\n"), find_nearest_colour(v.filament_color_code[i].strip("\n")), v.filament_type[i].strip("\n")) else: str += (" D0") header.append(str + "\n") header.append('O26 ' + hexify_short(len(v.splice_extruder_position)) + "\n") header.append('O27 ' + hexify_short(len(v.ping_extruder_position)) + "\n") if len(v.splice_algorithm_table) > 9: header.append("O28 D{:0>4d}\n".format(len(v.splice_algorithm_table))) else: header.append('O28 ' + hexify_short(len(v.splice_algorithm_table)) + "\n") header.append('O29 ' + hexify_short(v.hotswap_count) + "\n") for i in range(len(v.splice_extruder_position)): if v.accessory_mode: header.append("O30 D{:0>1d} {}\n".format( v.splice_used_tool[i], hexify_float(v.splice_extruder_position[i]))) else: header.append("O30 D{:0>1d} {}\n".format( v.splice_used_tool[i], hexify_float(v.splice_extruder_position[i] + v.autoloadingoffset))) if v.accessory_mode: for i in range(len(v.ping_extruder_position)): header.append("O31 {} {}\n".format( hexify_float(v.ping_extruder_position[i]), hexify_float(v.ping_extrusion_between_pause[i]))) for i in range(len(v.splice_algorithm_table)): header.append("O32 {}\n".format(v.splice_algorithm_table[i])) if v.m4c_numberoffilaments > 4: v.m4c_headerinfo = m4c.generate_warninglist() for i in v.m4c_headerinfo: header.append(i + "\n") if v.autoloadingoffset > 0: header.append("O40 D{}".format(v.autoloadingoffset)) else: v.autoloadingoffset = 0 if not v.accessory_mode: if len(v.splice_extruder_position) > 0: header.append("O1 D{} {}\n".format( job_name, hexify_long( int(v.splice_extruder_position[-1] + 0.5 + v.autoloadingoffset)))) else: header.append("O1 D{} {}\n".format( job_name, hexify_long( int(v.total_material_extruded + 0.5 + v.autoloadingoffset)))) header.append("M0\n") header.append("T0\n") summary = generatesummary() warnings = generatewarnings() return {'header': header, 'summary': summary, 'warnings': warnings}
def parse_config_parameters(): # TODO - get this information from the environment parameters # TODO - need to find out as from what version of PS this is working for idx in range(len(v.input_gcode) - 1, -1, -1): gcode_line = v.input_gcode[idx] if gcode_line.startswith("; estimated printing time"): try: fields = gcode_line.split("=") fields = fields[-1].split(" ") for i in range(len(fields)): fields[i] = "0" + fields[i].strip('hms') if len(fields) > 2: h = int(fields[-3]) else: h = 0 if len(fields) > 1: m = int(fields[-2]) else: m = 0 if len(fields) > 0: s = int(fields[-1]) else: s = 0 v.printing_time = h * 3600 + m * 60 + s except (ValueError, IndexError): pass return if gcode_line.startswith("; filament_settings_id"): v.filament_ids = split_csv_strings(gcode_line) if "generated by PrusaSlicer" in gcode_line: try: s1 = gcode_line.split("+") s2 = s1[0].split(" ") v.ps_version = s2[-1] gui.create_logitem( "File was created with PS version:{}".format(v.ps_version)) if v.ps_version < "2.2": gui.create_logitem( "<b>This version of P2PP is optimized to work with PS2.2 and higher!<b>" ) except (ValueError, IndexError): pass continue if gcode_line.startswith("; single_extruder_multi_material_priming"): parameter_start = gcode_line.find("=") if parameter_start != -1: try: if int(gcode_line[parameter_start + 1:].strip()) == 1: gui.log_warning( "[Print Settings][Multiple Extruders][Wipe Tower]Prime all printing extruders MUST be turned off" ) gui.log_warning("THIS FILE WILL NOT PRINT CORRECTLY") except (ValueError, IndexError): pass continue if gcode_line.startswith("; wipe_tower_no_sparse_layers"): parameter_start = gcode_line.find("=") if parameter_start != -1: try: v.wipe_remove_sparse_layers = (int( gcode_line[parameter_start + 1:].strip()) == 1) except (ValueError, IndexError): pass continue if gcode_line.startswith("; variable_layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.variable_layer = int(gcode_line[parameter_start + 1:].strip()) == 1 continue if gcode_line.startswith("; bed_shape") and not v.bed_shape_warning: get_bedshape(gcode_line) if gcode_line.startswith("; first_layer_temperature"): parameter_start = gcode_line.find("=") if parameter_start != -1: try: temps = gcode_line[parameter_start + 1:].strip().split(",") v.p3_printtemp = [] for i in range(len(temps)): v.p3_printtemp.append(int(temps[i])) except (IndexError, ValueError): v.p3_printtemp = [0, 0, 0, 0, 0, 0, 0, 0] if gcode_line.startswith("; first_layer_bed_temperature"): parameter_start = gcode_line.find("=") if parameter_start != -1: try: temps = gcode_line[parameter_start + 1:].strip().split(",") v.p3_bedtemp = [] for i in range(len(temps)): v.p3_bedtemp.append(int(temps[i])) except (IndexError, ValueError): v.p3_bedtemp = [0, 0, 0, 0, 0, 0, 0, 0] if gcode_line.startswith("; max_print_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.z_maxheight = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; wipe_tower_x"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipe_tower_posx = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; min_skirt_length"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.skirtsize = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; skirts"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.skirts = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; wipe_tower_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipe_tower_width = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; wipe_tower_y"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipe_tower_posy = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; extrusion_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: parm = gcode_line[parameter_start + 1:].strip() if len(parm) == 0: gui.log_warning( "extrusion width parameter does not contain any values FULL PURGE REDUCTION will not work" ) gui.log_warning( "Please manually set the values for default extrusion (Print Settings/Advanced/Extrusion Width to resolve" ) continue if parm[-1] == "%": parm = parm.replace("%", "").strip() tmpval = float(parm) v.extrusion_width = v.nozzle_diameter * tmpval / 100.0 else: v.extrusion_width = float(gcode_line[parameter_start + 1:].strip()) v.tx_offset = 2 + 4 * v.extrusion_width v.yy_offset = 2 + 8 * v.extrusion_width continue if gcode_line.startswith("; infill_speed"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.infill_speed = float( gcode_line[parameter_start + 1:].strip()) * 60 continue if gcode_line.startswith("; layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.layer_height = float(gcode_line[parameter_start + 1:].strip()) continue # this next function assumes that the parameters are stored in alphabetical order # so layer_height is defined BEFORE first layer height when parsing back to front if gcode_line.startswith("; first_layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: value = gcode_line[parameter_start + 1:].strip() if value[-1] == "%": v.first_layer_height = float( value[:-1]) / 100.0 * v.layer_height else: v.first_layer_height = float(value) continue if gcode_line.startswith("; support_material_synchronize_layers"): parameter_start = gcode_line.find("=") if parameter_start != -1: tmp = float(gcode_line[parameter_start + 1:].strip()) v.synced_support = tmp == 1 continue if gcode_line.startswith("; support_material "): parameter_start = gcode_line.find("=") if parameter_start != -1: tmp = float(gcode_line[parameter_start + 1:].strip()) v.support_material = tmp == 1 continue if gcode_line.startswith("; nozzle_diameter "): parameter_start = gcode_line.find("=") if parameter_start != -1: tmp = gcode_line[parameter_start + 1:].strip().split(",") tmp = float(tmp[0]) v.nozzle_diameter = tmp continue if gcode_line.startswith("; start_filament_gcode "): parameter_start = gcode_line.find("=") gcode_value = gcode_line[parameter_start + 2:].strip() fields = split_csv_strings(gcode_value) for i in range(len(fields)): lines = fields[0].split("\\n") for line in lines: if line.startswith(";P2PP PROFILETYPEOVERRIDE="): value = line[26:] v.filament_type[i] = value v.used_filament_types.append(v.filament_type[i]) v.used_filament_types = list( dict.fromkeys(v.used_filament_types)) continue if gcode_line.startswith("; start_gcode "): parameter_start = gcode_line.find("=") gcode_value = gcode_line[parameter_start + 2:].strip() lines = gcode_value.split("\\n") for line in lines: m = v.regex_p2pp.match(line) if m: if m.group(1).startswith("MATERIAL"): algorithm_process_material_configuration( m.group(1)[9:]) else: parameters.check_config_parameters( m.group(1), m.group(2)) if v.blobster_advanced: if len(v.blobster_advanced_speed) == 0: gui.log_warning( "BLOBSTER - Advanced mode required BLOBSTER_ADVANCED_SPEED parameter" ) if len(v.blobster_advanced_fan) == 0: gui.log_warning( "BLOBSTER - Advanced mode required BLOBSTER_ADVANCED_FAN parameter" ) if len(v.blobster_advanced_length) == 0: gui.log_warning( "BLOBSTER - Advanced mode required BLOBSTER_ADVANCED_LENGTH parameter" ) if len(v.blobster_advanced_speed) != len( v.blobster_advanced_fan) or len( v.blobster_advanced_speed) != len( v.blobster_advanced_length): gui.log_warning( "BLOBSTER - Advanced mode - BLOBSTER_ADVANCED_LENGTH/FAN/SPEED parameter must have same number of parameters" ) if gcode_line.startswith("; extruder_colour") or gcode_line.startswith( "; filament_colour"): filament_colour = '' parameter_start = gcode_line.find("=") gcode_line = gcode_line[parameter_start + 1:].strip() parameter_start = gcode_line.find("#") if parameter_start != -1: filament_colour = gcode_line.split(";") v.filament_count = len(filament_colour) for i in range(v.filament_count): v.filament_color_code[i] = filament_colour[i][1:] if gcode_line.startswith("; filament_diameter"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_diameters = gcode_line[parameter_start + 1:].strip(" ").split(",") v.filament_diameter = [1.75] * max(len(filament_diameters), 4) for i in range(len(filament_diameters)): v.filament_diameter[i] = float(filament_diameters[i]) continue if gcode_line.startswith("; filament_type"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_string = gcode_line[parameter_start + 1:].strip(" ").split(";") for i in range(len(filament_string)): if v.filament_type[i] != "": filament_string[i] = v.filament_type[i] v.filament_type = filament_string v.used_filament_types = list(set(filament_string)) continue if gcode_line.startswith("; retract_length = "): retract_error = False parameter_start = gcode_line.find("=") if parameter_start != -1: retracts = gcode_line[parameter_start + 1:].strip(" ").split(",") v.retract_length = [0.8] * max(len(retracts), v.colors) for i in range(len(retracts)): v.retract_length[i] = float(retracts[i]) - 0.02 if v.retract_length[i] < 0.0: retract_error = True gui.log_warning( "[Printer Settings]->[Extruders 1 -> {}]->[Retraction Length] should not be set to zero." .format(i)) if retract_error: gui.log_warning( "Generated file might not print correctly") continue if gcode_line.startswith("; gcode_flavor"): if "reprap" in gcode_line: v.isReprap_Mode = True continue if "use_firmware_retraction" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" in gcode_line: gui.log_warning("Hardware retraction no longer supported") continue if "use_relative_e_distances" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" not in gcode_line: gui.log_warning( "P2PP requires input file with RELATIVE extrusion") continue if gcode_line.startswith("; wiping_volumes_matrix"): wiping_info = [] _warning = False parameter_start = gcode_line.find("=") if parameter_start != -1: wiping_info = gcode_line[parameter_start + 1:].strip(" ").split(",") _warning = True for i in range(len(wiping_info)): if int(wiping_info[i]) != 140 and int(wiping_info[i]) != 0: _warning = False wiping_info[i] = float(wiping_info[i]) v.max_wipe = max(wiping_info) v.bigbrain3d_matrix_blobs = v.max_wipe < 20 if not v.bigbrain3d_matrix_blobs: map(filament_volume_to_length, wiping_info) else: gui.create_emptyline() gui.create_logitem("BigBrain3D BLOB transitions detected") color_table_size = int(math.sqrt(len(wiping_info))) header = "<table><tr><th>From\\To</th>" data = "" for i in range(color_table_size): header = header + "<th> Input {} </th>".format(i) data = data + "<tr><th>Input {} </th>".format(i) for j in range(color_table_size): data = data + ("<td align=center>{}</td>".format( int(wiping_info[j * color_table_size + i]))) data = data + "</tr>" header = header + "</tr>" data = data + "</table>" gui.create_logitem(header + data) gui.create_emptyline() v.wiping_info = wiping_info if _warning: gui.create_logitem( "<b>All purge lenghths 70/70 OR 140. Purge lengths may not have been set correctly.</b>" ) continue
def gcode_process_toolchange(new_tool): if new_tool == v.current_tool: return location = v.total_material_extruded + v.splice_offset v.bigbrain3d_last_toolchange = v.current_tool * 10 + new_tool if new_tool == -1: # LAST SLICE PROCESSING v.bigbrain3d_last_toolchange = -abs(v.bigbrain3d_last_toolchange) location += v.extra_runout_filament v.material_extruded_per_color[ v.current_tool] += v.extra_runout_filament v.total_material_extruded += v.extra_runout_filament filldiff = v.minimaltotal_filament - v.total_material_extruded if filldiff > 0: gui.log_warning( "Minimum print size not met - adding {:-5.2f}.. of filament". format(filldiff)) location += filldiff v.material_extruded_per_color[v.current_tool] += filldiff v.total_material_extruded += filldiff else: v.palette_inputs_used[new_tool] = True length = location - v.previous_toolchange_location if v.current_tool != -1: # FIRST SLICE PROCESSING v.splice_extruder_position.append(location) v.splice_length.append(length) v.splice_used_tool.append(v.current_tool) if len(v.splice_extruder_position) == 1: min_length = v.min_start_splice_length gui_format = "SHORT FIRST SPLICE (min {}mm) Length:{:-3.2f} Input {}" else: min_length = v.min_splice_length gui_format = "SHORT SPLICE (min {}mm) Length:{:-3.2f} Layer:{} Input:{}" if v.splice_length[-1] < min_length: if v.autoaddsplice and (v.full_purge_reduction or v.side_wipe): v.autoadded_purge = v.min_start_splice_length - length v.side_wipe_length += v.autoadded_purge v.splice_extruder_position[ -1] += v.autoadded_purge * v.extrusion_multiplier v.splice_length[-1] += v.autoadded_purge else: gui.log_warning( gui_format.format(min_length, length, v.last_parsed_layer, v.current_tool + 1)) v.filament_short[new_tool] = max( v.filament_short[new_tool], v.min_start_splice_length - v.splice_length[-1]) v.previous_toolchange_location = v.splice_extruder_position[-1] v.previous_tool = v.current_tool v.current_tool = new_tool
def parse_slic3r_config(): for idx in range(len(v.input_gcode) - 1, -1, -1): gcode_line = v.input_gcode[idx] if gcode_line.startswith("G1"): break if gcode_line.startswith("; wipe_tower_x"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_posx = float(gcode_line[parameter_start + 1:].strip()) if gcode_line.startswith("; wipe_tower_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_width = float(gcode_line[parameter_start + 1:].strip()) if gcode_line.startswith("; wipe_tower_y"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_posy = float(gcode_line[parameter_start + 1:].strip()) if gcode_line.startswith("; extrusion_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.extrusion_width = float(gcode_line[parameter_start + 1:].strip()) if gcode_line.startswith("; infill_speed"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.infill_speed = float( gcode_line[parameter_start + 1:].strip()) * 60 if gcode_line.startswith("; layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.layer_height = float(gcode_line[parameter_start + 1:].strip()) if gcode_line.startswith("; extruder_colour") or gcode_line.startswith( "; filament_colour"): filament_colour = '' parameter_start = gcode_line.find("=") gcode_line = gcode_line[parameter_start + 1:].strip() parameter_start = gcode_line.find("#") if parameter_start != -1: filament_colour = gcode_line.split(";") if len(filament_colour) == 4: for i in range(4): if filament_colour[i] == "": filament_colour[i] = v.filament_color_code[i] else: v.filament_color_code[i] = filament_colour[i][1:] if gcode_line.startswith("; filament_diameter"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_diameters = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(filament_diameters) == 4: for i in range(4): v.filament_diameter[i] = float(filament_diameters[i]) if gcode_line.startswith("; filament_type"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_string = gcode_line[parameter_start + 1:].strip(" ").split(";") if len(filament_string) == 4: v.filament_type = filament_string v.used_filament_types = list(set(filament_string)) continue if gcode_line.startswith("; retract_lift = "): if v.filament_list: continue lift_error = False parameter_start = gcode_line.find("=") if parameter_start != -1: retracts = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(retracts) == 4: for i in range(4): v.retract_lift[i] = float(retracts[i]) if v.retract_lift[i] == 0: lift_error = True continue if gcode_line.startswith("; retract_length = "): retract_error = False parameter_start = gcode_line.find("=") if parameter_start != -1: retracts = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(retracts) == 4: for i in range(4): v.retract_length[i] = float(retracts[i]) if v.retract_length[i] == 0.0: retract_error = True if retract_error: gui.log_warning( "[Printer Settings]->[Extruders 1/2/3/4]->[Retraction Length] should not be set to zero." ) continue if gcode_line.startswith("; gcode_flavor"): if "reprap" in gcode_line: v.isReprap_Mode = True if "use_firmware_retraction" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" in gcode_line: v.use_firmware_retraction = True else: v.use_firmware_retraction = False if "use_relative_e_distances" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" in gcode_line: v.gcode_has_relative_e = True else: v.gcode_has_relative_e = False if gcode_line.startswith("; wiping_volumes_matrix"): wiping_info = [] parameter_start = gcode_line.find("=") if parameter_start != -1: wiping_info = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(wiping_info) != 16: continue for i in range(len(wiping_info)): wiping_info[i] = filament_volume_to_length( float(wiping_info[i])) v.max_wipe = max(wiping_info) if len(wiping_info) == 16: v.wiping_info = wiping_info continue
def uploadfile(localfile, p3file): global total_bytes _error = None v.retry_state = True # read file # check the size of the file to be sent: try: file_size = os.path.getsize(localfile) if file_size > 1 << 30: #1GB gui.log_warning( "Filesize ({}) exceeds 1GB. This file cannot be uploaded.". format(file_size)) gui.log_warning( "Please use a memory stick to transfer files >1GB.") return except OSError: gui.log_warning( "Upload file does not seems to be ready for uploading (does not exists of is inaccessible)" ) gui.log_warning("Please try uploading using a memory stick.") return while v.p3_hostname == "": form.label_5.setText( "Please specify hostname or IP.\nP3_HOSTNAME config parameter missing." ) form.RetryButton.setText("Upload") window.show() gui.app.exec() v.p3_hostname = form.hostname.text() else: form.hostname.setText(v.p3_hostname) form.RetryButton.setText("Retry") gui.create_logitem( "Sending file {} to P3 ({})".format(p3file, v.p3_hostname), "blue", True) gui.app.sync() while v.retry_state: try: with open(localfile, "rb") as mcfx_file: gui.create_logitem("Uploading {}".format(p3file), "blue", True) encoder = MultipartEncoder({ 'printFile': (p3file, mcfx_file, "application/octet-stream"), }) data = MultipartEncoderMonitor(encoder, callback) gui.create_logitem("|" + '.' * 50 + "|", "blue", True) total_bytes = encoder.len # data = {'printFile': (p3file, mcfx_file, "application/octet-stream")} url = "http://{}:5000/print-file".format(v.p3_hostname) response = requests.post( url, data=data, headers={'Content-Type': data.content_type}) if response.ok: _error = None v.retry_state = False gui.create_logitem("Upload completed".format(p3file), "blue", True) else: _error = "Error [{}] {} ".format(response.status_code, response.reason) except Exception as e: print(e) gui.log_warning("Could not send file ({}) to P3 ({})".format( p3file, v.p3_hostname)) gui.app.sync() _error = "Connection Error occurred!" if v.showwebbrowser and _error is None: try: tgtName = "http://{}:5000".format(v.p3_hostname) webform.webBrowser.load(QtCore.QUrl(tgtName)) webwindow.show() gui.app.exec() except Exception as e: gui.logexception(e) if v.retry_state and _error is not None: form.label_5.setText(_error) window.show() gui.app.exec() v.p3_hostname = form.hostname.text() gui.close_button_enable()
def generate_palette(): if v.accessory_mode: palette = { "version": "3.0", "drives": [], "splices": [], "pings": [], "pingCount": len(v.ping_extruder_position), "algorithms": [] } else: palette = { "version": "3.0", "drives": [], "splices": [], "pingCount": len(v.ping_extruder_position), "algorithms": [] } if len(v.splice_extruder_position) < 2: try: drive_used = v.splice_used_tool[0] + 1 except IndexError: drive_used = 1 palette["splices"] = [{ "id": drive_used, "length": round(v.total_material_extruded + v.autoloadingoffset, 4) }] if v.colors == 4: palette["drives"] = [0, 0, 0, 0] else: palette["drives"] = [0, 0, 0, 0, 0, 0, 0, 0] palette["drives"][drive_used - 1] = drive_used palette["algorithms"].append({ "ingoingId": drive_used, "outgoingId": drive_used, "heat": 0, "compression": 0, "cooling": 0 }) else: for i in range(len(v.splice_extruder_position)): palette["splices"].append({ "id": v.splice_used_tool[i] + 1, "length": round(v.splice_extruder_position[i] + v.autoloadingoffset, 4) }) splice_list = [] palette["drives"] = [] for i in range(v.colors): f_idx = 0 if v.palette_inputs_used[i]: f_idx = i + 1 palette["drives"].append(f_idx) for j in range(v.colors): if i == j: continue try: algo_key = "{}{}".format( v.used_filament_types.index(v.filament_type[i]) + 1, v.used_filament_types.index(v.filament_type[j]) + 1) if algo_key in splice_list: continue except (IndexError, KeyError): continue if not algorithm_transition_used(i, j): continue splice_list.append(algo_key) try: algo = v.splice_algorithm_dictionary["{}{}".format( v.filament_type[i], v.filament_type[j])] except (IndexError, KeyError): algo = v.default_splice_algorithm gui.log_warning( "WARNING: No Algorithm defined for transitioning" + " {} to {}. Using Default Splice Algorithm".format( v.filament_type[i], v.filament_type[j])) try: algin = int(algo_key[0]) except ValueError: algin = 0 try: algout = int(algo_key[1]) except ValueError: algout = 0 palette["algorithms"].append({ "ingoingId": algin, "outgoingId": algout, "heat": algo[0], "compression": algo[1], "cooling": algo[2] }) if v.accessory_mode: for i in range(len(v.ping_extruder_position)): palette["pings"].append({ "length": v.ping_extruder_position[i], "extrusion": v.ping_extrusion_between_pause[i] }) return json.dumps(palette, indent=2)
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()
def parse_slic3r_config(): for idx in range(len(v.input_gcode) - 1, -1, -1): gcode_line = v.input_gcode[idx] if gcode_line.startswith("; filament_settings_id"): v.filament_ids = split_csv_strings(gcode_line) if ("generated by PrusaSlicer") in gcode_line: try: s1 = gcode_line.split("+") s2 = s1[0].split(" ") v.ps_version = s2[-1] gui.create_logitem( "File was created with PS version:{}".format(v.ps_version)) if v.ps_version < "2.2": gui.log_warning( "This version of P2PP is optimized to work with PS2.2!" ) except: pass continue if gcode_line.startswith("; wipe_tower_no_sparse_layers"): parameter_start = gcode_line.find("=") if parameter_start != -1: try: v.wipe_remove_sparse_layers = (int( gcode_line[parameter_start + 1:].strip()) == 1) except: pass continue if gcode_line.startswith("; wipe_tower_x"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_posx = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; min_skirt_length"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.skirtsize = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; skirts"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.skirts = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; wipe_tower_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_width = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; wipe_tower_y"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.wipetower_posy = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; extrusion_width"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.extrusion_width = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; infill_speed"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.infill_speed = float( gcode_line[parameter_start + 1:].strip()) * 60 continue if gcode_line.startswith("; layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.layer_height = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; first_layer_height"): parameter_start = gcode_line.find("=") if parameter_start != -1: v.first_layer_height = float(gcode_line[parameter_start + 1:].strip()) continue if gcode_line.startswith("; support_material_synchronize_layers"): parameter_start = gcode_line.find("=") if parameter_start != -1: tmp = float(gcode_line[parameter_start + 1:].strip()) if tmp == 0: v.synced_support = False else: v.synced_support = True continue if gcode_line.startswith("; support_material "): parameter_start = gcode_line.find("=") if parameter_start != -1: tmp = float(gcode_line[parameter_start + 1:].strip()) if tmp == 0: v.support_material = False else: v.support_material = True continue # TVDE: needs to be expanded to be able to support more than 4 colors if gcode_line.startswith("; extruder_colour") or gcode_line.startswith( "; filament_colour"): filament_colour = '' parameter_start = gcode_line.find("=") gcode_line = gcode_line[parameter_start + 1:].strip() parameter_start = gcode_line.find("#") if parameter_start != -1: filament_colour = gcode_line.split(";") if len(filament_colour) >= 4: for i in range(len(filament_colour)): if filament_colour[i] == "": filament_colour[i] = v.filament_color_code[i] else: v.filament_color_code[i] = filament_colour[i][1:] continue if gcode_line.startswith("; filament_diameter"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_diameters = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(filament_diameters) >= 4: for i in range(4): v.filament_diameter[i] = float(filament_diameters[i]) continue # TVDE: needs to be expanded to be able to support more than 4 colors # only check that is needed is that if nore than 4 colors exist, all must be of same type if gcode_line.startswith("; filament_type"): parameter_start = gcode_line.find("=") if parameter_start != -1: filament_string = gcode_line[parameter_start + 1:].strip(" ").split(";") v.m4c_numberoffilaments = len(filament_string) if v.m4c_numberoffilaments == 4: v.filament_type = filament_string v.used_filament_types = list(set(filament_string)) elif v.m4c_numberoffilaments >= 4: v.used_filament_types = list(set(filament_string)) if len(v.used_filament_types) > 1: gui.log_warning( "Prints with more than 4 colors should be of one filament type only!" ) gui.log_warning("This file will not print correctly") v.filament_type = filament_string[:4] if v.m4c_numberoffilaments > 4: gui.log_warning( "Number of inputs defined in print: {}. Swaps may be required!!!" .format(v.m4c_numberoffilaments)) continue # TVDE: needs to be expanded to be able to support more than 4 colors # if more than 4, just retain the first four (check is done at other level, but for not all settings should be the same) if gcode_line.startswith("; retract_lift = "): if v.filament_list: continue lift_error = False parameter_start = gcode_line.find("=") if parameter_start != -1: retracts = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(retracts) >= 4: for i in range(4): v.retract_lift[i] = float(retracts[i]) if v.retract_lift[i] == 0: lift_error = True if lift_error: gui.log_warning( "[Printer Settings]->[Extruders 1 -> {}]->[Retraction]->[Lift Z] should not be set to zero." .format(len(retracts))) gui.log_warning("Generated file might not print correctly") continue # TVDE: needs to be expanded to be able to support more than 4 colors # if more than 4, just retain the first four (check is done at other level, but for not all settings should be the same) if gcode_line.startswith("; retract_length = "): retract_error = False parameter_start = gcode_line.find("=") if parameter_start != -1: retracts = gcode_line[parameter_start + 1:].strip(" ").split(",") if len(retracts) >= 4: for i in range(4): v.retract_length[i] = float(retracts[i]) if v.retract_length[i] == 0.0: retract_error = True if retract_error: gui.log_warning( "[Printer Settings]->[Extruders 1 -> {} 4]->[Retraction Length] should not be set to zero." .format(len(retracts))) continue if gcode_line.startswith("; gcode_flavor"): if "reprap" in gcode_line: v.isReprap_Mode = True continue if "use_firmware_retraction" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" in gcode_line: v.use_firmware_retraction = True else: v.use_firmware_retraction = False continue if "use_relative_e_distances" in gcode_line: parameter_start = gcode_line.find("=") if parameter_start != -1: gcode_line = gcode_line[parameter_start + 1:].replace(";", "") if "1" in gcode_line: v.gcode_has_relative_e = True else: v.gcode_has_relative_e = False continue # TVDE: needs to be expanded to be able to support more than 4 colors # this should be expanded to nxn filaments where n = the number of filaments used. # needs to be a perfect square, calculate from there. if gcode_line.startswith("; wiping_volumes_matrix"): wiping_info = [] parameter_start = gcode_line.find("=") if parameter_start != -1: wiping_info = gcode_line[parameter_start + 1:].strip(" ").split(",") _warning = True for i in range(len(wiping_info)): if int(wiping_info[i]) != 140 and int(wiping_info[i]) != 0: _warning = False wiping_info[i] = filament_volume_to_length( float(wiping_info[i])) v.max_wipe = max(wiping_info) v.wiping_info = wiping_info if _warning: gui.log_warning( "All purge lenghts 70/70 OR 140. Purge lenghts may not have been set correctly." ) continue