diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index a5d5eaf53..5790965ff 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1600,7 +1600,7 @@ sub print_info_box_show { my ($self, $show) = @_; my $scrolled_window_panel = $self->{scrolled_window_panel}; my $scrolled_window_sizer = $self->{scrolled_window_sizer}; - return if $scrolled_window_sizer->IsShown(2) == $show; + return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show)); if ($show) { my $print_info_sizer = $self->{print_info_sizer}; @@ -1836,6 +1836,8 @@ sub update { $self->resume_background_process; } + $self->print_info_box_show(0); + # $self->{canvas}->reload_scene if $self->{canvas}; my $selections = $self->collect_selections; Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections); diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index 9d214ce40..b122a13c5 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,5 +1,9 @@ min_slic3r_version = 1.41.0-alpha -0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost, +0.2.0-alpha7 Fixed the *MK3* references +0.2.0-alpha6 +0.2.0-alpha5 Bumped up firmware versions for MK2.5/MK3 to 3.3.1, disabled priming areas for MK3MMU2 +0.2.0-alpha4 Extended the custom start/end G-codes of the MMU2.0 printers for no priming towers. +0.2.0-alpha3 Adjusted machine limits for time estimates, added filament density and cost 0.2.0-alpha2 Renamed the key MK3SMMU to MK3MMU2, added a generic PLA MMU2 material 0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0 0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 6817c8712..27ba179ad 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the Slic3r configuration to be downgraded. -config_version = 0.2.0-alpha3 +config_version = 0.2.0-alpha7 # Where to get the updates from? config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ @@ -95,6 +95,7 @@ print_settings_id = raft_layers = 0 resolution = 0 seam_position = nearest +single_extruder_multi_material_priming = 1 skirts = 1 skirt_distance = 2 skirt_height = 3 @@ -136,6 +137,10 @@ wipe_tower_x = 200 wipe_tower_y = 155 xy_size_compensation = 0 +[print:*MK3*] +fill_pattern = grid +single_extruder_multi_material_priming = 0 + # Print parameters common to a 0.25mm diameter nozzle. [print:*0.25nozzle*] external_perimeter_extrusion_width = 0.25 @@ -211,9 +216,8 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and infill_extrusion_width = 0.5 [print:0.05mm ULTRADETAIL MK3] -inherits = *0.05mm* +inherits = *0.05mm*; *MK3* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material -fill_pattern = grid top_infill_extrusion_width = 0.4 [print:0.05mm ULTRADETAIL 0.25 nozzle] @@ -228,9 +232,8 @@ solid_infill_speed = 20 support_material_speed = 20 [print:0.05mm ULTRADETAIL 0.25 nozzle MK3] -inherits = *0.05mm*; *0.25nozzle* +inherits = *0.05mm*; *0.25nozzle*; *MK3* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 -fill_pattern = grid # XXXXXXXXXXXXXXXXXXXX # XXX--- 0.10mm ---XXX @@ -255,11 +258,10 @@ perimeter_speed = 50 solid_infill_speed = 50 [print:0.10mm DETAIL MK3] -inherits = *0.10mm* +inherits = *0.10mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -282,11 +284,10 @@ solid_infill_speed = 40 top_solid_infill_speed = 30 [print:0.10mm DETAIL 0.25 nozzle MK3] -inherits = *0.10mm*; *0.25nozzle* +inherits = *0.10mm*; *0.25nozzle*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -295,11 +296,10 @@ solid_infill_speed = 200 top_solid_infill_speed = 50 [print:0.10mm DETAIL 0.6 nozzle MK3] -inherits = *0.10mm*; *0.6nozzle* +inherits = *0.10mm*; *0.6nozzle*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -361,11 +361,10 @@ inherits = *0.15mm*; *0.6nozzle* compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 [print:0.15mm OPTIMAL MK3] -inherits = *0.15mm* +inherits = *0.15mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -393,11 +392,10 @@ support_material_with_sheath = 0 support_material_xy_spacing = 80% [print:0.15mm OPTIMAL 0.25 nozzle MK3] -inherits = *0.15mm*; *0.25nozzle* +inherits = *0.15mm*; *0.25nozzle*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -419,11 +417,10 @@ top_infill_extrusion_width = 0.4 top_solid_layers = 5 [print:0.15mm OPTIMAL 0.6 nozzle MK3] -inherits = *0.15mm*; *0.6nozzle* +inherits = *0.15mm*; *0.6nozzle*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -448,11 +445,10 @@ support_material_speed = 60 top_solid_infill_speed = 70 [print:0.20mm FAST MK3] -inherits = *0.20mm* +inherits = *0.20mm*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -486,11 +482,10 @@ support_material_with_sheath = 0 support_material_xy_spacing = 80% [print:0.20mm FAST 0.6 nozzle MK3] -inherits = *0.20mm*; *0.6nozzle* +inherits = *0.20mm*; *0.6nozzle*; *MK3* bridge_speed = 30 compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6 external_perimeter_speed = 35 -fill_pattern = grid infill_acceleration = 1250 infill_speed = 200 max_print_speed = 200 @@ -1069,7 +1064,7 @@ end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes. extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259 nozzle_diameter = 0.4,0.4,0.4,0.4 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN -start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_single_extruder_multi_material_priming}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 variable_layer_height = 0 default_print_profile = 0.15mm OPTIMAL @@ -1129,17 +1124,17 @@ default_print_profile = 0.20mm NORMAL 0.6 nozzle [printer:Original Prusa i3 MK2.5] inherits = Original Prusa i3 MK2 printer_model = MK2.5 -start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.25 nozzle] inherits = Original Prusa i3 MK2 0.25 nozzle printer_model = MK2.5 -start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 [printer:Original Prusa i3 MK2.5 0.6 nozzle] inherits = Original Prusa i3 MK2 0.6 nozzle printer_model = MK2.5 -start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 # XXXXXXXXXXXXXXXXX # XXX--- MK3 ---XXX @@ -1168,7 +1163,7 @@ silent_mode = 1 printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n retract_lift_below = 209 max_print_height = 210 -start_gcode = M115 U3.3.0 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} +start_gcode = M115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} printer_model = MK3 default_print_profile = 0.15mm OPTIMAL MK3 @@ -1203,7 +1198,7 @@ default_filament_profile = Prusa PLA MMU2 [printer:Original Prusa i3 MK3 MMU2 Single] inherits = *mm2* -start_gcode = M107\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n ; go outside print area\nG1 Y-3.0 F1000.0 \nG1 Z0.4 F1000\n; select extruder\nT?\n; initial load\nG1 X50 E15 F1073\nG1 X100 E10 F2000\nG1 Z0.3 F1000\n\nG92 E0.0\nG1 X240.0 E15.0 F2400.0 \nG1 Y-2.0 F1000.0\nG1 X100.0 E10 F1400.0 \nG1 Z0.20 F1000\nG1 X0.0 E4 F1000.0\n\nG92 E0.0\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +start_gcode = M107\nM115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT?\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors [printer:Original Prusa i3 MK3 MMU2] @@ -1213,8 +1208,8 @@ inherits = *mm2* # to be defined explicitely. nozzle_diameter = 0.4,0.4,0.4,0.4,0.4 extruder_colour = #FF8000;#0080FF;#00FFFF;#FF4F4F;#9FFF9F -start_gcode = M107\n\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\n\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n -end_gcode = G1 E-15.0000 F3000\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +start_gcode = M107\nM115 U3.3.1 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\n;M221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n +end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n # The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer. [obsolete_presets] diff --git a/xs/src/avrdude/avrdude-slic3r.cpp b/xs/src/avrdude/avrdude-slic3r.cpp index 4a7f22d6e..0577fe6d0 100644 --- a/xs/src/avrdude/avrdude-slic3r.cpp +++ b/xs/src/avrdude/avrdude-slic3r.cpp @@ -35,8 +35,9 @@ struct AvrDude::priv { std::string sys_config; std::deque> args; - size_t current_args_set = 0; bool cancelled = false; + int exit_code = 0; + size_t current_args_set = 0; RunFn run_fn; MessageFn message_fn; ProgressFn progress_fn; @@ -146,15 +147,15 @@ AvrDude::Ptr AvrDude::run() int res = -1; if (self->p->run_fn) { - self->p->run_fn(*self); + self->p->run_fn(); } if (! self->p->cancelled) { - res = self->p->run(); + self->p->exit_code = self->p->run(); } if (self->p->complete_fn) { - self->p->complete_fn(res, self->p->current_args_set); + self->p->complete_fn(); } }); @@ -179,5 +180,20 @@ void AvrDude::join() } } +bool AvrDude::cancelled() +{ + return p ? p->cancelled : false; +} + +int AvrDude::exit_code() +{ + return p ? p->exit_code : 0; +} + +size_t AvrDude::last_args_set() +{ + return p ? p->current_args_set : 0; +} + } diff --git a/xs/src/avrdude/avrdude-slic3r.hpp b/xs/src/avrdude/avrdude-slic3r.hpp index 399df2358..86e097034 100644 --- a/xs/src/avrdude/avrdude-slic3r.hpp +++ b/xs/src/avrdude/avrdude-slic3r.hpp @@ -12,10 +12,10 @@ class AvrDude { public: typedef std::shared_ptr Ptr; - typedef std::function RunFn; + typedef std::function RunFn; typedef std::function MessageFn; typedef std::function ProgressFn; - typedef std::function CompleteFn; + typedef std::function CompleteFn; // Main c-tor, sys_config is the location of avrdude's main configuration file AvrDude(std::string sys_config); @@ -54,6 +54,10 @@ public: void cancel(); void join(); + + bool cancelled(); // Whether avrdude run was cancelled + int exit_code(); // The exit code of the last invocation + size_t last_args_set(); // Index of the last argument set that was processsed private: struct priv; std::unique_ptr p; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 94634f4e4..308b1ea04 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -608,15 +608,18 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1) break; } - } - else { + } else { // Find tool ordering for all the objects at once, and the initial extruder ID. // If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it. tool_ordering = print.m_tool_ordering.empty() ? ToolOrdering(print, initial_extruder_id) : print.m_tool_ordering; - initial_extruder_id = tool_ordering.first_extruder(); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); + initial_extruder_id = (has_wipe_tower && ! print.config.single_extruder_multi_material_priming) ? + // The priming towers will be skipped. + tool_ordering.all_extruders().back() : + // Don't skip the priming towers. + tool_ordering.first_extruder(); } if (initial_extruder_id == (unsigned int)-1) { // Nothing to print! @@ -644,6 +647,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) m_placeholder_parser.set("current_object_idx", 0); // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); + m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config.single_extruder_multi_material_priming); std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id); // Set bed temperature if the start G-code does not contain any bed temp control G-codes. @@ -724,8 +728,11 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) } } - // Set initial extruder only after custom start G-code. - _write(file, this->set_extruder(initial_extruder_id)); + if (! (has_wipe_tower && print.config.single_extruder_multi_material_priming)) { + // Set initial extruder only after custom start G-code. + // Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed. + _write(file, this->set_extruder(initial_extruder_id)); + } // Do all objects for each layer. if (print.config.complete_objects.value) { @@ -803,27 +810,29 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) if (has_wipe_tower && ! layers_to_print.empty()) { m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); _write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height")); - _write(file, m_wipe_tower->prime(*this)); - // Verify, whether the print overaps the priming extrusions. - BoundingBoxf bbox_print(get_print_extrusions_extents(print)); - coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : printable_objects) - bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); - bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); - BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); - bbox_prime.offset(0.5f); - // Beep for 500ms, tone 800Hz. Yet better, play some Morse. - _write(file, this->retract()); - _write(file, "M300 S800 P500\n"); - if (bbox_prime.overlap(bbox_print)) { - // Wait for the user to remove the priming extrusions, otherwise they would - // get covered by the print. - _write(file, "M1 Remove priming towers and click button.\n"); - } - else { - // Just wait for a bit to let the user check, that the priming succeeded. - //TODO Add a message explaining what the printer is waiting for. This needs a firmware fix. - _write(file, "M1 S10\n"); + if (print.config.single_extruder_multi_material_priming) { + _write(file, m_wipe_tower->prime(*this)); + // Verify, whether the print overaps the priming extrusions. + BoundingBoxf bbox_print(get_print_extrusions_extents(print)); + coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; + for (const PrintObject *print_object : printable_objects) + bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); + bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); + BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); + bbox_prime.offset(0.5f); + // Beep for 500ms, tone 800Hz. Yet better, play some Morse. + _write(file, this->retract()); + _write(file, "M300 S800 P500\n"); + if (bbox_prime.overlap(bbox_print)) { + // Wait for the user to remove the priming extrusions, otherwise they would + // get covered by the print. + _write(file, "M1 Remove priming towers and click button.\n"); + } + else { + // Just wait for a bit to let the user check, that the priming succeeded. + //TODO Add a message explaining what the printer is waiting for. This needs a firmware fix. + _write(file, "M1 S10\n"); + } } } // Extrude the layers. diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 24e34d75b..bceeea258 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -771,9 +771,23 @@ void ModelObject::scale(const Pointf3 &versor) void ModelObject::rotate(float angle, const Axis &axis) { + float min_z = FLT_MAX; for (ModelVolume *v : this->volumes) + { v->mesh.rotate(angle, axis); - this->origin_translation = Pointf3(0,0,0); + min_z = std::min(min_z, v->mesh.stl.stats.min.z); + } + + if (min_z != 0.0f) + { + // translate the object so that its minimum z lays on the bed + for (ModelVolume *v : this->volumes) + { + v->mesh.translate(0.0f, 0.0f, -min_z); + } + } + + this->origin_translation = Pointf3(0, 0, 0); this->invalidate_bounding_box(); } diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index e08ae1fc4..8c91eb192 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -155,6 +155,7 @@ bool Print::invalidate_state_by_config_options(const std::vectorplaceholder_parser.update_timestamp(); @@ -1225,7 +1222,6 @@ void Print::set_status(int percent, const std::string &message) printf("Print::status %d => %s\n", percent, message.c_str()); } - // Returns extruder this eec should be printed with, according to PrintRegion config int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion ®ion) { @@ -1233,5 +1229,4 @@ int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion std::max(region.config.perimeter_extruder.value - 1, 0); } - } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 7064e19fe..d80347a4d 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1623,6 +1623,12 @@ PrintConfigDef::PrintConfigDef() def->cli = "single-extruder-multi-material!"; def->default_value = new ConfigOptionBool(false); + def = this->add("single_extruder_multi_material_priming", coBool); + def->label = L("Prime all printing extruders"); + def->tooltip = L("If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print."); + def->cli = "single-extruder-multi-material-priming!"; + def->default_value = new ConfigOptionBool(true); + def = this->add("support_material", coBool); def->label = L("Generate support material"); def->category = L("Support material"); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index c530868a1..3848ba55b 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -553,6 +553,7 @@ public: ConfigOptionString start_gcode; ConfigOptionStrings start_filament_gcode; ConfigOptionBool single_extruder_multi_material; + ConfigOptionBool single_extruder_multi_material_priming; ConfigOptionString toolchange_gcode; ConfigOptionFloat travel_speed; ConfigOptionBool use_firmware_retraction; @@ -612,6 +613,7 @@ protected: OPT_PTR(retract_restart_extra_toolchange); OPT_PTR(retract_speed); OPT_PTR(single_extruder_multi_material); + OPT_PTR(single_extruder_multi_material_priming); OPT_PTR(start_gcode); OPT_PTR(start_filament_gcode); OPT_PTR(toolchange_gcode); diff --git a/xs/src/slic3r/GUI/BedShapeDialog.cpp b/xs/src/slic3r/GUI/BedShapeDialog.cpp index 3dd60ef88..d52535589 100644 --- a/xs/src/slic3r/GUI/BedShapeDialog.cpp +++ b/xs/src/slic3r/GUI/BedShapeDialog.cpp @@ -9,6 +9,8 @@ #include "Model.hpp" #include "boost/nowide/iostream.hpp" +#include + namespace Slic3r { namespace GUI { @@ -146,21 +148,18 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points) if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) { // okay, it's a rectangle // find origin - // the || 0 hack prevents "-0" which might confuse the user - int x_min, x_max, y_min, y_max; - x_max = x_min = points->values[0].x; + coordf_t x_min, x_max, y_min, y_max; + x_max = x_min = points->values[0].x; y_max = y_min = points->values[0].y; - for (auto pt : points->values){ - if (x_min > pt.x) x_min = pt.x; - if (x_max < pt.x) x_max = pt.x; - if (y_min > pt.y) y_min = pt.y; - if (y_max < pt.y) y_max = pt.y; - } - if (x_min < 0) x_min = 0; - if (x_max < 0) x_max = 0; - if (y_min < 0) y_min = 0; - if (y_max < 0) y_max = 0; - auto origin = new ConfigOptionPoints{ Pointf(-x_min, -y_min) }; + for (auto pt : points->values) + { + x_min = std::min(x_min, pt.x); + x_max = std::max(x_max, pt.x); + y_min = std::min(y_min, pt.y); + y_max = std::max(y_max, pt.y); + } + + auto origin = new ConfigOptionPoints{ Pointf(-x_min, -y_min) }; m_shape_options_book->SetSelection(SHAPE_RECTANGULAR); auto optgroup = m_optgroups[SHAPE_RECTANGULAR]; diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp index 36a1c396f..0885e041b 100644 --- a/xs/src/slic3r/GUI/Field.cpp +++ b/xs/src/slic3r/GUI/Field.cpp @@ -95,9 +95,10 @@ namespace Slic3r { namespace GUI { wxString tooltip_text(""); wxString tooltip = _(m_opt.tooltip); if (tooltip.length() > 0) - tooltip_text = tooltip + "(" + _(L("default")) + ": " + - (boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + - default_string + ")"; + tooltip_text = tooltip + "\n " + _(L("default value")) + "\t: " + + (boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + default_string + + (boost::iends_with(m_opt_id, "_gcode") ? "" : "\n") + "\n " + + _(L("variable name")) + "\t: " + m_opt_id; return tooltip_text; } diff --git a/xs/src/slic3r/GUI/FirmwareDialog.cpp b/xs/src/slic3r/GUI/FirmwareDialog.cpp index 30339e3cb..77e70c49b 100644 --- a/xs/src/slic3r/GUI/FirmwareDialog.cpp +++ b/xs/src/slic3r/GUI/FirmwareDialog.cpp @@ -1,12 +1,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "libslic3r/Utils.hpp" #include "avrdude/avrdude-slic3r.hpp" @@ -32,11 +34,13 @@ #include #include #include +#include namespace fs = boost::filesystem; namespace asio = boost::asio; using boost::system::error_code; +using boost::optional; namespace Slic3r { @@ -46,19 +50,31 @@ using Utils::SerialPortInfo; using Utils::Serial; +// USB IDs used to perform device lookup +enum { + USB_VID_PRUSA = 0x2c99, + USB_PID_MK2 = 1, + USB_PID_MK3 = 2, + USB_PID_MMU_BOOT = 3, + USB_PID_MMU_APP = 4, +}; + // This enum discriminates the kind of information in EVT_AVRDUDE, // it's stored in the ExtraLong field of wxCommandEvent. enum AvrdudeEvent { AE_MESSAGE, AE_PROGRESS, + AE_STATUS, AE_EXIT, - AE_ERROR, }; wxDECLARE_EVENT(EVT_AVRDUDE, wxCommandEvent); wxDEFINE_EVENT(EVT_AVRDUDE, wxCommandEvent); +wxDECLARE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); +wxDEFINE_EVENT(EVT_ASYNC_DIALOG, wxCommandEvent); + // Private @@ -66,15 +82,17 @@ struct FirmwareDialog::priv { enum AvrDudeComplete { + AC_NONE, AC_SUCCESS, AC_FAILURE, - AC_CANCEL, + AC_USER_CANCELLED, }; FirmwareDialog *q; // PIMPL back pointer ("Q-Pointer") + // GUI elements wxComboBox *port_picker; - std::vector ports; + wxStaticText *port_autodetect; wxFilePickerCtrl *hex_picker; wxStaticText *txt_status; wxGauge *progressbar; @@ -85,43 +103,66 @@ struct FirmwareDialog::priv wxButton *btn_flash; wxString btn_flash_label_ready; wxString btn_flash_label_flashing; + wxString label_status_flashing; wxTimer timer_pulse; + // Async modal dialog during flashing + std::mutex mutex; + int modal_response; + std::condition_variable response_cv; + + // Data + std::vector ports; + optional port; + HexFile hex_file; + // This is a shared pointer holding the background AvrDude task // also serves as a status indication (it is set _iff_ the background task is running, otherwise it is reset). AvrDude::Ptr avrdude; std::string avrdude_config; unsigned progress_tasks_done; unsigned progress_tasks_bar; - bool cancelled; + bool user_cancelled; const bool extra_verbose; // For debugging priv(FirmwareDialog *q) : q(q), btn_flash_label_ready(_(L("Flash!"))), btn_flash_label_flashing(_(L("Cancel"))), + label_status_flashing(_(L("Flashing in progress. Please do not disconnect the printer!"))), timer_pulse(q), avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()), progress_tasks_done(0), progress_tasks_bar(0), - cancelled(false), + user_cancelled(false), extra_verbose(false) {} void find_serial_ports(); + void fit_no_shrink(); + void set_txt_status(const wxString &label); void flashing_start(unsigned tasks); void flashing_done(AvrDudeComplete complete); - void check_model_id(const HexFile &metadata, const SerialPortInfo &port); + void enable_port_picker(bool enable); + void load_hex_file(const wxString &path); + void queue_status(wxString message); + void queue_error(const wxString &message); - void prepare_common(AvrDude &, const SerialPortInfo &port, const std::string &filename); - void prepare_mk2(AvrDude &, const SerialPortInfo &port, const std::string &filename); - void prepare_mk3(AvrDude &, const SerialPortInfo &port, const std::string &filename); - void prepare_mm_control(AvrDude &, const SerialPortInfo &port, const std::string &filename); + bool ask_model_id_mismatch(const std::string &printer_model); + bool check_model_id(); + void wait_for_mmu_bootloader(unsigned retries); + void mmu_reboot(const SerialPortInfo &port); + void lookup_port_mmu(); + void prepare_common(); + void prepare_mk2(); + void prepare_mk3(); + void prepare_mm_control(); void perform_upload(); - void cancel(); + void user_cancel(); void on_avrdude(const wxCommandEvent &evt); + void on_async_dialog(const wxCommandEvent &evt); void ensure_joined(); }; @@ -146,10 +187,32 @@ void FirmwareDialog::priv::find_serial_ports() } } +void FirmwareDialog::priv::fit_no_shrink() +{ + // Ensure content fits into window and window is not shrinked + const auto old_size = q->GetSize(); + q->Layout(); + q->Fit(); + const auto new_size = q->GetSize(); + const auto new_width = std::max(old_size.GetWidth(), new_size.GetWidth()); + const auto new_height = std::max(old_size.GetHeight(), new_size.GetHeight()); + q->SetSize(new_width, new_height); +} + +void FirmwareDialog::priv::set_txt_status(const wxString &label) +{ + const auto width = txt_status->GetSize().GetWidth(); + txt_status->SetLabel(label); + txt_status->Wrap(width); + + fit_no_shrink(); +} + void FirmwareDialog::priv::flashing_start(unsigned tasks) { + modal_response = wxID_NONE; txt_stdout->Clear(); - txt_status->SetLabel(_(L("Flashing in progress. Please do not disconnect the printer!"))); + set_txt_status(label_status_flashing); txt_status->SetForegroundColour(GUI::get_label_clr_modified()); port_picker->Disable(); btn_rescan->Disable(); @@ -160,7 +223,7 @@ void FirmwareDialog::priv::flashing_start(unsigned tasks) progressbar->SetValue(0); progress_tasks_done = 0; progress_tasks_bar = 0; - cancelled = false; + user_cancelled = false; timer_pulse.Start(50); } @@ -177,54 +240,190 @@ void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete) progressbar->SetValue(progressbar->GetRange()); switch (complete) { - case AC_SUCCESS: txt_status->SetLabel(_(L("Flashing succeeded!"))); break; - case AC_FAILURE: txt_status->SetLabel(_(L("Flashing failed. Please see the avrdude log below."))); break; - case AC_CANCEL: txt_status->SetLabel(_(L("Flashing cancelled."))); break; + case AC_SUCCESS: set_txt_status(_(L("Flashing succeeded!"))); break; + case AC_FAILURE: set_txt_status(_(L("Flashing failed. Please see the avrdude log below."))); break; + case AC_USER_CANCELLED: set_txt_status(_(L("Flashing cancelled."))); break; + default: break; } } -void FirmwareDialog::priv::check_model_id(const HexFile &metadata, const SerialPortInfo &port) +void FirmwareDialog::priv::enable_port_picker(bool enable) { - if (metadata.model_id.empty()) { - // No data to check against - return; + port_picker->Show(enable); + btn_rescan->Show(enable); + port_autodetect->Show(! enable); + q->Layout(); + fit_no_shrink(); +} + +void FirmwareDialog::priv::load_hex_file(const wxString &path) +{ + hex_file = HexFile(path.wx_str()); + enable_port_picker(hex_file.device != HexFile::DEV_MM_CONTROL); +} + +void FirmwareDialog::priv::queue_status(wxString message) +{ + auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); + evt->SetExtraLong(AE_STATUS); + evt->SetString(std::move(message)); + wxQueueEvent(this->q, evt); +} + +void FirmwareDialog::priv::queue_error(const wxString &message) +{ + auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); + evt->SetExtraLong(AE_STATUS); + evt->SetString(wxString::Format(_(L("Flashing failed: %s")), message)); + + wxQueueEvent(this->q, evt); avrdude->cancel(); +} + +bool FirmwareDialog::priv::ask_model_id_mismatch(const std::string &printer_model) +{ + // model_id in the hex file doesn't match what the printer repoted. + // Ask the user if it should be flashed anyway. + + std::unique_lock lock(mutex); + + auto evt = new wxCommandEvent(EVT_ASYNC_DIALOG, this->q->GetId()); + evt->SetString(wxString::Format(_(L( + "This firmware hex file does not match the printer model.\n" + "The hex file is intended for: %s\n" + "Printer reported: %s\n\n" + "Do you want to continue and flash this hex file anyway?\n" + "Please only continue if you are sure this is the right thing to do.")), + hex_file.model_id, printer_model + )); + wxQueueEvent(this->q, evt); + + response_cv.wait(lock, [this]() { return this->modal_response != wxID_NONE; }); + + if (modal_response == wxID_YES) { + return true; + } else { + user_cancel(); + return false; } +} - asio::io_service io; - Serial serial(io, port.port, 115200); - serial.printer_setup(); +bool FirmwareDialog::priv::check_model_id() +{ + // XXX: The implementation in Serial doesn't currently work reliably enough to be used. + // Therefore, regretably, so far the check cannot be used and we just return true here. + // TODO: Rewrite Serial using more platform-native code. + return true; + + // if (hex_file.model_id.empty()) { + // // No data to check against, assume it's ok + // return true; + // } + // asio::io_service io; + // Serial serial(io, port->port, 115200); + // serial.printer_setup(); + + // enum { + // TIMEOUT = 2000, + // RETREIES = 5, + // }; + + // if (! serial.printer_ready_wait(RETREIES, TIMEOUT)) { + // queue_error(wxString::Format(_(L("Could not connect to the printer at %s")), port->port)); + // return false; + // } + + // std::string line; + // error_code ec; + // serial.printer_write_line("PRUSA Rev"); + // while (serial.read_line(TIMEOUT, line, ec)) { + // if (ec) { + // queue_error(wxString::Format(_(L("Could not connect to the printer at %s")), port->port)); + // return false; + // } + + // if (line == "ok") { continue; } + + // if (line == hex_file.model_id) { + // return true; + // } else { + // return ask_model_id_mismatch(line); + // } + + // line.clear(); + // } + + // return false; +} + +void FirmwareDialog::priv::wait_for_mmu_bootloader(unsigned retries) +{ enum { - TIMEOUT = 1000, - RETREIES = 3, + SLEEP_MS = 500, }; - if (! serial.printer_ready_wait(RETREIES, TIMEOUT)) { - throw wxString::Format(_(L("Could not connect to the printer at %s")), port.port); - } + for (unsigned i = 0; i < retries && !user_cancelled; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_MS)); - std::string line; - error_code ec; - serial.printer_write_line("PRUSA Rev"); - while (serial.read_line(TIMEOUT, line, ec)) { - if (ec) { throw wxString::Format(_(L("Could not connect to the printer at %s")), port.port); } - if (line == "ok") { continue; } + auto ports = Utils::scan_serial_ports_extended(); + ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { + return port.id_vendor != USB_VID_PRUSA && port.id_product != USB_PID_MMU_BOOT; + }), ports.end()); - if (line == metadata.model_id) { + if (ports.size() == 1) { + port = ports[0]; + return; + } else if (ports.size() > 1) { + BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; + queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); return; - } else { - throw wxString::Format(_(L( - "The firmware hex file does not match the printer model.\n" - "The hex file is intended for:\n %s\n" - "Printer reports:\n %s" - )), metadata.model_id, line); } - - line.clear(); } } -void FirmwareDialog::priv::prepare_common(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename) +void FirmwareDialog::priv::mmu_reboot(const SerialPortInfo &port) +{ + asio::io_service io; + Serial serial(io, port.port, 1200); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); +} + +void FirmwareDialog::priv::lookup_port_mmu() +{ + BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ..."; + + auto ports = Utils::scan_serial_ports_extended(); + ports.erase(std::remove_if(ports.begin(), ports.end(), [=](const SerialPortInfo &port ) { + return port.id_vendor != USB_VID_PRUSA && + port.id_product != USB_PID_MMU_BOOT && + port.id_product != USB_PID_MMU_APP; + }), ports.end()); + + if (ports.size() == 0) { + BOOST_LOG_TRIVIAL(info) << "MMU 2.0 device not found, asking the user to press Reset and waiting for the device to show up ..."; + + queue_status(_(L( + "The Multi Material Control device was not found.\n" + "If the device is connected, please press the Reset button next to the USB connector ..." + ))); + + wait_for_mmu_bootloader(30); + } else if (ports.size() > 1) { + BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found"; + queue_error(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing."))); + } else { + if (ports[0].id_product == USB_PID_MMU_APP) { + // The device needs to be rebooted into the bootloader mode + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % ports[0].port; + mmu_reboot(ports[0]); + wait_for_mmu_bootloader(10); + } else { + port = ports[0]; + } + } +} + +void FirmwareDialog::priv::prepare_common() { std::vector args {{ extra_verbose ? "-vvvvv" : "-v", @@ -233,10 +432,10 @@ void FirmwareDialog::priv::prepare_common(AvrDude &avrdude, const SerialPortInfo // The Prusa's avrdude is patched to never send semicolons inside the data packets, as the USB to serial chip // is flashed with a buggy firmware. "-c", "wiring", - "-P", port.port, - "-b", "115200", // TODO: Allow other rates? Ditto below. + "-P", port->port, + "-b", "115200", // TODO: Allow other rates? Ditto elsewhere. "-D", - "-U", (boost::format("flash:w:0:%1%:i") % filename).str(), + "-U", (boost::format("flash:w:0:%1%:i") % hex_file.path.string()).str(), }}; BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: " @@ -244,97 +443,75 @@ void FirmwareDialog::priv::prepare_common(AvrDude &avrdude, const SerialPortInfo return a + ' ' + b; }); - avrdude.push_args(std::move(args)); + avrdude->push_args(std::move(args)); } -void FirmwareDialog::priv::prepare_mk2(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename) +void FirmwareDialog::priv::prepare_mk2() { - prepare_common(avrdude, port, filename); + if (! port) { return; } + + if (! check_model_id()) { + avrdude->cancel(); + return; + } + + prepare_common(); } -void FirmwareDialog::priv::prepare_mk3(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename) +void FirmwareDialog::priv::prepare_mk3() { - prepare_common(avrdude, port, filename); + if (! port) { return; } + + if (! check_model_id()) { + avrdude->cancel(); + return; + } + + prepare_common(); // The hex file also contains another section with l10n data to be flashed into the external flash on MK3 (Einsy) // This is done via another avrdude invocation, here we build arg list for that: - std::vector args_l10n {{ + std::vector args {{ extra_verbose ? "-vvvvv" : "-v", "-p", "atmega2560", // Using the "Arduino" mode to program Einsy's external flash with languages, using the STK500 protocol (not the STK500v2). // The Prusa's avrdude is patched again to never send semicolons inside the data packets. "-c", "arduino", - "-P", port.port, + "-P", port->port, "-b", "115200", "-D", "-u", // disable safe mode - "-U", (boost::format("flash:w:1:%1%:i") % filename).str(), + "-U", (boost::format("flash:w:1:%1%:i") % hex_file.path.string()).str(), }}; BOOST_LOG_TRIVIAL(info) << "Invoking avrdude for external flash flashing, arguments: " - << std::accumulate(std::next(args_l10n.begin()), args_l10n.end(), args_l10n[0], [](std::string a, const std::string &b) { + << std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, const std::string &b) { return a + ' ' + b; }); - avrdude.push_args(std::move(args_l10n)); + avrdude->push_args(std::move(args)); } -void FirmwareDialog::priv::prepare_mm_control(AvrDude &avrdude, const SerialPortInfo &port_in, const std::string &filename) +void FirmwareDialog::priv::prepare_mm_control() { - // Check if the port has the PID/VID of 0x2c99/3 - // If not, check if it is the MMU (0x2c99/4) and reboot the by opening @ 1200 bauds - BOOST_LOG_TRIVIAL(info) << "Flashing MMU 2.0, looking for VID/PID 0x2c99/3 or 0x2c99/4 ..."; - SerialPortInfo port = port_in; - if (! port.id_match(0x2c99, 3)) { - if (! port.id_match(0x2c99, 4)) { - // This is not a Prusa MMU 2.0 device - BOOST_LOG_TRIVIAL(error) << boost::format("Not a Prusa MMU 2.0 device: `%1%`") % port.port; - throw wxString::Format(_(L("The device at `%s` is not am Original Prusa i3 MMU 2.0 device")), port.port); - } - - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/4 at `%1%`, rebooting the device ...") % port.port; - - { - asio::io_service io; - Serial serial(io, port.port, 1200); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } - - // Wait for the bootloader to show up - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - - // Look for the rebooted device - BOOST_LOG_TRIVIAL(info) << "... looking for VID/PID 0x2c99/3 ..."; - auto new_ports = Utils::scan_serial_ports_extended(); - unsigned hits = 0; - for (auto &&new_port : new_ports) { - if (new_port.id_match(0x2c99, 3)) { - hits++; - port = std::move(new_port); - } - } - - if (hits == 0) { - BOOST_LOG_TRIVIAL(error) << "No VID/PID 0x2c99/3 device found after rebooting the MMU 2.0"; - throw wxString::Format(_(L("Failed to reboot the device at `%s` for programming")), port.port); - } else if (hits > 1) { - // We found multiple 0x2c99/3 devices, this is bad, because there's no way to find out - // which one is the one user wants to flash. - BOOST_LOG_TRIVIAL(error) << "Several VID/PID 0x2c99/3 devices found after rebooting the MMU 2.0"; - throw wxString::Format(_(L("Multiple Original Prusa i3 MMU 2.0 devices found. Please only connect one at a time for flashing.")), port.port); - } + port = boost::none; + lookup_port_mmu(); + if (! port) { + queue_error(_(L("The device could not have been found"))); + return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port.port; + BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port->port; + queue_status(label_status_flashing); std::vector args {{ extra_verbose ? "-vvvvv" : "-v", "-p", "atmega32u4", "-c", "avr109", - "-P", port.port, + "-P", port->port, "-b", "57600", "-D", - "-U", (boost::format("flash:w:0:%1%:i") % filename).str(), + "-U", (boost::format("flash:w:0:%1%:i") % hex_file.path.string()).str(), }}; BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: " @@ -342,7 +519,7 @@ void FirmwareDialog::priv::prepare_mm_control(AvrDude &avrdude, const SerialPort return a + ' ' + b; }); - avrdude.push_args(std::move(args)); + avrdude->push_args(std::move(args)); } @@ -351,20 +528,21 @@ void FirmwareDialog::priv::perform_upload() auto filename = hex_picker->GetPath(); if (filename.IsEmpty()) { return; } - int selection = port_picker->GetSelection(); - if (selection == wxNOT_FOUND) { return; } + load_hex_file(filename); // Might already be loaded, but we want to make sure it's fresh - const SerialPortInfo &port = this->ports[selection]; - // Verify whether the combo box list selection equals to the combo box edit value. - if (wxString::FromUTF8(this->ports[selection].friendly_name.data()) != port_picker->GetValue()) { - return; + int selection = port_picker->GetSelection(); + if (selection != wxNOT_FOUND) { + port = this->ports[selection]; + + // Verify whether the combo box list selection equals to the combo box edit value. + if (wxString::FromUTF8(port->friendly_name.data()) != port_picker->GetValue()) { + return; + } } const bool extra_verbose = false; // For debugging - HexFile metadata(filename.wx_str()); - const std::string filename_utf8(filename.utf8_str().data()); - flashing_start(metadata.device == HexFile::DEV_MK3 ? 2 : 1); + flashing_start(hex_file.device == HexFile::DEV_MK3 ? 2 : 1); // Init the avrdude object AvrDude avrdude(avrdude_config); @@ -374,36 +552,23 @@ void FirmwareDialog::priv::perform_upload() auto q = this->q; this->avrdude = avrdude - .on_run([=](AvrDude &avrdude) { - auto queue_error = [&](wxString message) { - avrdude.cancel(); - - auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); - evt->SetExtraLong(AE_ERROR); - evt->SetString(std::move(message)); - wxQueueEvent(this->q, evt); - }; - + .on_run([this]() { try { - switch (metadata.device) { + switch (this->hex_file.device) { case HexFile::DEV_MK3: - this->check_model_id(metadata, port); - this->prepare_mk3(avrdude, port, filename_utf8); + this->prepare_mk3(); break; case HexFile::DEV_MM_CONTROL: - this->check_model_id(metadata, port); - this->prepare_mm_control(avrdude, port, filename_utf8); + this->prepare_mm_control(); break; default: - this->prepare_mk2(avrdude, port, filename_utf8); + this->prepare_mk2(); break; } - } catch (const wxString &message) { - queue_error(message); } catch (const std::exception &ex) { - queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port.port, ex.what())); + queue_error(wxString::Format(_(L("Error accessing port at %s: %s")), port->port, ex.what())); } }) .on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) { @@ -423,20 +588,19 @@ void FirmwareDialog::priv::perform_upload() evt->SetInt(progress); wxQueueEvent(q, evt); })) - .on_complete(std::move([q](int status, size_t /* args_id */) { - auto evt = new wxCommandEvent(EVT_AVRDUDE, q->GetId()); + .on_complete(std::move([this]() { + auto evt = new wxCommandEvent(EVT_AVRDUDE, this->q->GetId()); evt->SetExtraLong(AE_EXIT); - evt->SetInt(status); - wxQueueEvent(q, evt); + evt->SetInt(this->avrdude->exit_code()); + wxQueueEvent(this->q, evt); })) .run(); } -void FirmwareDialog::priv::cancel() +void FirmwareDialog::priv::user_cancel() { if (avrdude) { - cancelled = true; - txt_status->SetLabel(_(L("Cancelling..."))); + user_cancelled = true; avrdude->cancel(); } } @@ -474,19 +638,17 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt) case AE_EXIT: BOOST_LOG_TRIVIAL(info) << "avrdude exit code: " << evt.GetInt(); - complete_kind = cancelled ? AC_CANCEL : (evt.GetInt() == 0 ? AC_SUCCESS : AC_FAILURE); + // Figure out the exit state + if (user_cancelled) { complete_kind = AC_USER_CANCELLED; } + else if (avrdude->cancelled()) { complete_kind = AC_NONE; } // Ie. cancelled programatically + else { complete_kind = evt.GetInt() == 0 ? AC_SUCCESS : AC_FAILURE; } + flashing_done(complete_kind); ensure_joined(); break; - case AE_ERROR: - txt_stdout->AppendText(evt.GetString()); - flashing_done(AC_FAILURE); - ensure_joined(); - { - GUI::ErrorDialog dlg(this->q, evt.GetString()); - dlg.ShowModal(); - } + case AE_STATUS: + set_txt_status(evt.GetString()); break; default: @@ -494,6 +656,16 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt) } } +void FirmwareDialog::priv::on_async_dialog(const wxCommandEvent &evt) +{ + wxMessageDialog dlg(this->q, evt.GetString(), wxMessageBoxCaptionStr, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); + { + std::lock_guard lock(mutex); + modal_response = dlg.ShowModal(); + } + response_cv.notify_all(); +} + void FirmwareDialog::priv::ensure_joined() { // Make sure the background thread is collected and the AvrDude object reset @@ -521,44 +693,50 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : wxFont mono_font(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)); mono_font.MakeSmaller(); + // Create GUI components and layout + auto *panel = new wxPanel(this); wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL); panel->SetSizer(vsizer); + auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:"))); + p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY); + auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:"))); p->port_picker = new wxComboBox(panel, wxID_ANY); + p->port_autodetect = new wxStaticText(panel, wxID_ANY, _(L("Autodetected"))); p->btn_rescan = new wxButton(panel, wxID_ANY, _(L("Rescan"))); auto *port_sizer = new wxBoxSizer(wxHORIZONTAL); port_sizer->Add(p->port_picker, 1, wxEXPAND | wxRIGHT, SPACING); port_sizer->Add(p->btn_rescan, 0); + port_sizer->Add(p->port_autodetect, 1, wxEXPAND); + p->enable_port_picker(true); - auto *label_hex_picker = new wxStaticText(panel, wxID_ANY, _(L("Firmware image:"))); - p->hex_picker = new wxFilePickerCtrl(panel, wxID_ANY); + auto *label_progress = new wxStaticText(panel, wxID_ANY, _(L("Progress:"))); + p->progressbar = new wxGauge(panel, wxID_ANY, 1, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL | wxGA_SMOOTH); auto *label_status = new wxStaticText(panel, wxID_ANY, _(L("Status:"))); p->txt_status = new wxStaticText(panel, wxID_ANY, _(L("Ready"))); p->txt_status->SetFont(status_font); - auto *label_progress = new wxStaticText(panel, wxID_ANY, _(L("Progress:"))); - p->progressbar = new wxGauge(panel, wxID_ANY, 1, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL | wxGA_SMOOTH); - auto *grid = new wxFlexGridSizer(2, SPACING, SPACING); grid->AddGrowableCol(1); - grid->Add(label_port_picker, 0, wxALIGN_CENTER_VERTICAL); - grid->Add(port_sizer, 0, wxEXPAND); grid->Add(label_hex_picker, 0, wxALIGN_CENTER_VERTICAL); grid->Add(p->hex_picker, 0, wxEXPAND); - grid->Add(label_status, 0, wxALIGN_CENTER_VERTICAL); - grid->Add(p->txt_status, 0, wxEXPAND); + grid->Add(label_port_picker, 0, wxALIGN_CENTER_VERTICAL); + grid->Add(port_sizer, 0, wxEXPAND); grid->Add(label_progress, 0, wxALIGN_CENTER_VERTICAL); grid->Add(p->progressbar, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL); + grid->Add(label_status, 0, wxALIGN_CENTER_VERTICAL); + grid->Add(p->txt_status, 0, wxEXPAND); + vsizer->Add(grid, 0, wxEXPAND | wxTOP | wxBOTTOM, SPACING); - p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: avrdude output log"))); + p->spoiler = new wxCollapsiblePane(panel, wxID_ANY, _(L("Advanced: avrdude output log")), wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE); auto *spoiler_pane = p->spoiler->GetPane(); auto *spoiler_sizer = new wxBoxSizer(wxVERTICAL); p->txt_stdout = new wxTextCtrl(spoiler_pane, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY); @@ -571,6 +749,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : p->btn_close = new wxButton(panel, wxID_CLOSE); p->btn_flash = new wxButton(panel, wxID_ANY, p->btn_flash_label_ready); + p->btn_flash->Disable(); auto *bsizer = new wxBoxSizer(wxHORIZONTAL); bsizer->Add(p->btn_close); bsizer->AddStretchSpacer(); @@ -585,16 +764,26 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : SetSize(std::max(size.GetWidth(), static_cast(MIN_WIDTH)), std::max(size.GetHeight(), static_cast(MIN_HEIGHT))); Layout(); + // Bind events + + p->hex_picker->Bind(wxEVT_FILEPICKER_CHANGED, [this](wxFileDirPickerEvent& evt) { + if (wxFileExists(evt.GetPath())) { + this->p->load_hex_file(evt.GetPath()); + this->p->btn_flash->Enable(); + } + }); + p->spoiler->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [this](wxCollapsiblePaneEvent &evt) { - // Dialog size gets screwed up by wxCollapsiblePane, we need to fix it here if (evt.GetCollapsed()) { this->SetMinSize(wxSize(MIN_WIDTH, MIN_HEIGHT)); + const auto new_height = this->GetSize().GetHeight() - this->p->txt_stdout->GetSize().GetHeight(); + this->SetSize(this->GetSize().GetWidth(), new_height); } else { this->SetMinSize(wxSize(MIN_WIDTH, MIN_HEIGHT_EXPANDED)); } - this->Fit(); this->Layout(); + this->p->fit_no_shrink(); }); p->btn_close->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { this->Close(); }); @@ -608,7 +797,8 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : _(L("Confirmation")), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); if (dlg.ShowModal() == wxID_YES) { - this->p->cancel(); + this->p->set_txt_status(_(L("Cancelling..."))); + this->p->user_cancel(); } } else { // Start a flashing task @@ -619,6 +809,7 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : Bind(wxEVT_TIMER, [this](wxTimerEvent &evt) { this->p->progressbar->Pulse(); }); Bind(EVT_AVRDUDE, [this](wxCommandEvent &evt) { this->p->on_avrdude(evt); }); + Bind(EVT_ASYNC_DIALOG, [this](wxCommandEvent &evt) { this->p->on_async_dialog(evt); }); Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &evt) { if (this->p->avrdude) { diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 46bcf4f44..f8dd94fd4 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1941,12 +1941,23 @@ void GLCanvas3D::set_model(Model* model) void GLCanvas3D::set_bed_shape(const Pointfs& shape) { - m_bed.set_shape(shape); + bool new_shape = (shape != m_bed.get_shape()); + if (new_shape) + m_bed.set_shape(shape); // Set the origin and size for painting of the coordinate system axes. m_axes.origin = Pointf3(0.0, 0.0, (coordf_t)GROUND_Z); set_axes_length(0.3f * (float)m_bed.get_bounding_box().max_size()); + if (new_shape) + { + // forces the selection of the proper camera target + if (m_volumes.volumes.empty()) + zoom_to_bed(); + else + zoom_to_volumes(); + } + m_dirty = true; } diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 49e235146..de9b59a95 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -303,8 +303,8 @@ const std::vector& Preset::print_options() "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "compatible_printers", - "compatible_printers_condition","inherits" + "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming", + "compatible_printers", "compatible_printers_condition","inherits" }; return s_opts; } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index 187030f31..70f3bf8be 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -919,6 +919,7 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_width"); optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("single_extruder_multi_material_priming"); optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("interface_shells"); diff --git a/xs/src/slic3r/Utils/HexFile.cpp b/xs/src/slic3r/Utils/HexFile.cpp index ed26ddf37..282c647bd 100644 --- a/xs/src/slic3r/Utils/HexFile.cpp +++ b/xs/src/slic3r/Utils/HexFile.cpp @@ -46,8 +46,7 @@ static size_t hex_num_sections(fs::ifstream &file) } HexFile::HexFile(fs::path path) : - path(std::move(path)), - device(DEV_GENERIC) + path(std::move(path)) { fs::ifstream file(this->path); if (! file.good()) { diff --git a/xs/src/slic3r/Utils/HexFile.hpp b/xs/src/slic3r/Utils/HexFile.hpp index d8d1e09ab..1201d23a4 100644 --- a/xs/src/slic3r/Utils/HexFile.hpp +++ b/xs/src/slic3r/Utils/HexFile.hpp @@ -19,9 +19,10 @@ struct HexFile }; boost::filesystem::path path; - DeviceKind device; + DeviceKind device = DEV_GENERIC; std::string model_id; + HexFile() {} HexFile(boost::filesystem::path path); }; diff --git a/xs/src/slic3r/Utils/Serial.cpp b/xs/src/slic3r/Utils/Serial.cpp index c3c16b314..183119b44 100644 --- a/xs/src/slic3r/Utils/Serial.cpp +++ b/xs/src/slic3r/Utils/Serial.cpp @@ -373,7 +373,7 @@ void Serial::set_DTR(bool on) void Serial::reset_line_num() { // See https://github.com/MarlinFirmware/Marlin/wiki/M110 - printer_write_line("M110 N0", 0); + write_string("M110 N0\n"); m_line_num = 0; } @@ -390,9 +390,9 @@ bool Serial::read_line(unsigned timeout, std::string &line, error_code &ec) asio::async_read(*this, boost::asio::buffer(&c, 1), [&](const error_code &read_ec, size_t size) { if (ec || size == 0) { fail = true; - ec = read_ec; + ec = read_ec; // FIXME: only if operation not aborted } - timer.cancel(); + timer.cancel(); // FIXME: ditto }); if (timeout > 0) { @@ -444,6 +444,7 @@ bool Serial::printer_ready_wait(unsigned retries, unsigned timeout) } line.clear(); } + line.clear(); } @@ -469,7 +470,7 @@ void Serial::printer_reset() this->set_DTR(true); std::this_thread::sleep_for(std::chrono::milliseconds(200)); this->set_DTR(false); - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } std::string Serial::printer_format_line(const std::string &line, unsigned line_num) diff --git a/xs/src/slic3r/Utils/Serial.hpp b/xs/src/slic3r/Utils/Serial.hpp index d15f249c0..e4a28de09 100644 --- a/xs/src/slic3r/Utils/Serial.hpp +++ b/xs/src/slic3r/Utils/Serial.hpp @@ -51,12 +51,13 @@ public: // Reads a line or times out, the timeout is in milliseconds bool read_line(unsigned timeout, std::string &line, boost::system::error_code &ec); - // Perform setup for communicating with a printer + // Perform an initial setup for communicating with a printer void printer_setup(); // Write data from a string size_t write_string(const std::string &str); - + + // Attempts to reset the line numer and waits until the printer says "ok" bool printer_ready_wait(unsigned retries, unsigned timeout); // Write Marlin-formatted line, with a line number and a checksum