Merge remote-tracking branch 'origin/master' into feature_arrange_with_libnest2d

This commit is contained in:
tamasmeszaros 2018-07-27 17:37:33 +02:00
commit 4e901a9db7
39 changed files with 5598 additions and 3029 deletions

View file

@ -128,8 +128,8 @@ sub new {
}
$_->set_scaling_factor($scale) for @{ $model_object->instances };
$self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
$object->transform_thumbnail($self->{model}, $obj_idx);
$self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
# $object->transform_thumbnail($self->{model}, $obj_idx);
#update print and start background processing
$self->{print}->add_model_object($model_object, $obj_idx);
@ -203,18 +203,19 @@ sub new {
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); });
}
# Initialize 2D preview canvas
$self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config});
$self->{preview_notebook}->AddPage($self->{canvas}, L('2D'));
$self->{canvas}->on_select_object($on_select_object);
$self->{canvas}->on_double_click($on_double_click);
$self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); });
$self->{canvas}->on_instances_moved($on_instances_moved);
# # Initialize 2D preview canvas
# $self->{canvas} = Slic3r::GUI::Plater::2D->new($self->{preview_notebook}, wxDefaultSize, $self->{objects}, $self->{model}, $self->{config});
# $self->{preview_notebook}->AddPage($self->{canvas}, L('2D'));
# $self->{canvas}->on_select_object($on_select_object);
# $self->{canvas}->on_double_click($on_double_click);
# $self->{canvas}->on_right_click(sub { $on_right_click->($self->{canvas}, @_); });
# $self->{canvas}->on_instances_moved($on_instances_moved);
# Initialize 3D toolpaths preview
if ($Slic3r::GUI::have_OpenGL) {
$self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1);
Slic3r::GUI::_3DScene::enable_dynamic_background($self->{preview3D}->canvas, 1);
Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); });
$self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview'));
$self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1;
@ -312,6 +313,9 @@ sub new {
my ($list, $event) = @_;
if ($event->GetKeyCode == WXK_TAB) {
$list->Navigate($event->ShiftDown ? &Wx::wxNavigateBackward : &Wx::wxNavigateForward);
} elsif ($event->GetKeyCode == WXK_DELETE ||
($event->GetKeyCode == WXK_BACK && &Wx::wxMAC) ) {
$self->remove;
} else {
$event->Skip;
}
@ -401,7 +405,8 @@ sub new {
$_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self))
for grep defined($_),
$self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list};
$self, $self->{canvas3D}, $self->{preview3D}, $self->{list};
# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list};
EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub {
my ($self, $event) = @_;
@ -432,7 +437,7 @@ sub new {
});
}
$self->{canvas}->update_bed_size;
# $self->{canvas}->update_bed_size;
if ($self->{canvas3D}) {
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape);
Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D});
@ -847,8 +852,8 @@ sub load_model_objects {
$self->{list}->SetItem($obj_idx, 1, $model_object->instances_count);
$self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
$self->reset_thumbnail($obj_idx);
# $self->reset_thumbnail($obj_idx);
}
$self->arrange if $need_arrange;
$self->update;
@ -1057,7 +1062,7 @@ sub rotate {
$inst->set_rotation($rotation);
Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
}
$object->transform_thumbnail($self->{model}, $obj_idx);
# $object->transform_thumbnail($self->{model}, $obj_idx);
} else {
# rotation around X and Y needs to be performed on mesh
# so we first apply any Z rotation
@ -1067,9 +1072,9 @@ sub rotate {
}
$model_object->rotate(deg2rad($angle), $axis);
# realign object to Z = 0
$model_object->center_around_origin;
$self->reset_thumbnail($obj_idx);
# # realign object to Z = 0
# $model_object->center_around_origin;
# $self->reset_thumbnail($obj_idx);
}
# update print and start background processing
@ -1097,9 +1102,9 @@ sub mirror {
$model_object->mirror($axis);
# realign object to Z = 0
$model_object->center_around_origin;
$self->reset_thumbnail($obj_idx);
# # realign object to Z = 0
# $model_object->center_around_origin;
# $self->reset_thumbnail($obj_idx);
# update print and start background processing
$self->stop_background_process;
@ -1149,7 +1154,7 @@ sub changescale {
#FIXME Scale the layer height profile when $axis == Z?
#FIXME Scale the layer height ranges $axis == Z?
# object was already aligned to Z = 0, so no need to realign it
$self->reset_thumbnail($obj_idx);
# $self->reset_thumbnail($obj_idx);
} else {
my $scale;
if ($tosize) {
@ -1173,7 +1178,7 @@ sub changescale {
$range->[1] *= $variation;
}
$_->set_scaling_factor($scale) for @{ $model_object->instances };
$object->transform_thumbnail($self->{model}, $obj_idx);
# $object->transform_thumbnail($self->{model}, $obj_idx);
}
# update print and start background processing
@ -1804,10 +1809,10 @@ sub _get_export_file {
return $output_file;
}
sub reset_thumbnail {
my ($self, $obj_idx) = @_;
$self->{objects}[$obj_idx]->thumbnail(undef);
}
#sub reset_thumbnail {
# my ($self, $obj_idx) = @_;
# $self->{objects}[$obj_idx]->thumbnail(undef);
#}
# this method gets called whenever print center is changed or the objects' bounding box changes
# (i.e. when an object is added/removed/moved/rotated/scaled)
@ -1831,7 +1836,7 @@ sub update {
$self->resume_background_process;
}
$self->{canvas}->reload_scene if $self->{canvas};
# $self->{canvas}->reload_scene if $self->{canvas};
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
@ -1888,7 +1893,7 @@ sub on_config_change {
foreach my $opt_key (@{$self->{config}->diff($config)}) {
$self->{config}->set($opt_key, $config->get($opt_key));
if ($opt_key eq 'bed_shape') {
$self->{canvas}->update_bed_size;
# $self->{canvas}->update_bed_size;
Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D};
Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
$update_scheduled = 1;
@ -1948,7 +1953,7 @@ sub list_item_deselected {
$self->{_lecursor} = Wx::BusyCursor->new();
if ($self->{list}->GetFirstSelected == -1) {
$self->select_object(undef);
$self->{canvas}->Refresh;
# $self->{canvas}->Refresh;
Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D};
Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D};
}
@ -1961,7 +1966,7 @@ sub list_item_selected {
$self->{_lecursor} = Wx::BusyCursor->new();
my $obj_idx = $event->GetIndex;
$self->select_object($obj_idx);
$self->{canvas}->Refresh;
# $self->{canvas}->Refresh;
if ($self->{canvas3D}) {
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
@ -2058,19 +2063,19 @@ sub object_settings_dialog {
$self->pause_background_process;
$dlg->ShowModal;
# update thumbnail since parts may have changed
if ($dlg->PartsChanged) {
# recenter and re-align to Z = 0
$model_object->center_around_origin;
$self->reset_thumbnail($obj_idx);
}
# # update thumbnail since parts may have changed
# if ($dlg->PartsChanged) {
# # recenter and re-align to Z = 0
# $model_object->center_around_origin;
# $self->reset_thumbnail($obj_idx);
# }
# update print
if ($dlg->PartsChanged || $dlg->PartSettingsChanged) {
$self->stop_background_process;
$self->{print}->reload_object($obj_idx);
$self->schedule_background_process;
$self->{canvas}->reload_scene if $self->{canvas};
# $self->{canvas}->reload_scene if $self->{canvas};
my $selections = $self->collect_selections;
Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
@ -2356,48 +2361,48 @@ package Slic3r::GUI::Plater::Object;
use Moo;
has 'name' => (is => 'rw', required => 1);
has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms
has 'transformed_thumbnail' => (is => 'rw');
has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
#has 'thumbnail' => (is => 'rw'); # ExPolygon::Collection in scaled model units with no transforms
#has 'transformed_thumbnail' => (is => 'rw');
#has 'instance_thumbnails' => (is => 'ro', default => sub { [] }); # array of ExPolygon::Collection objects, each one representing the actual placed thumbnail of each instance in pixel units
has 'selected' => (is => 'rw', default => sub { 0 });
sub make_thumbnail {
my ($self, $model, $obj_idx) = @_;
# make method idempotent
$self->thumbnail->clear;
# raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
my $mesh = $model->objects->[$obj_idx]->raw_mesh;
#FIXME The "correct" variant could be extremely slow.
# if ($mesh->facets_count <= 5000) {
# # remove polygons with area <= 1mm
# my $area_threshold = Slic3r::Geometry::scale 1;
# $self->thumbnail->append(
# grep $_->area >= $area_threshold,
# @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons
# );
# $self->thumbnail->simplify(0.5);
# } else {
my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull);
$self->thumbnail->append($convex_hull);
# }
return $self->thumbnail;
}
sub transform_thumbnail {
my ($self, $model, $obj_idx) = @_;
return unless defined $self->thumbnail;
my $model_object = $model->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
# the order of these transformations MUST be the same everywhere, including
# in Slic3r::Print->add_model_object()
my $t = $self->thumbnail->clone;
$t->rotate($model_instance->rotation, Slic3r::Point->new(0,0));
$t->scale($model_instance->scaling_factor);
$self->transformed_thumbnail($t);
}
#sub make_thumbnail {
# my ($self, $model, $obj_idx) = @_;
# # make method idempotent
# $self->thumbnail->clear;
# # raw_mesh is the non-transformed (non-rotated, non-scaled, non-translated) sum of non-modifier object volumes.
# my $mesh = $model->objects->[$obj_idx]->raw_mesh;
##FIXME The "correct" variant could be extremely slow.
## if ($mesh->facets_count <= 5000) {
## # remove polygons with area <= 1mm
## my $area_threshold = Slic3r::Geometry::scale 1;
## $self->thumbnail->append(
## grep $_->area >= $area_threshold,
## @{ $mesh->horizontal_projection }, # horizontal_projection returns scaled expolygons
## );
## $self->thumbnail->simplify(0.5);
## } else {
# my $convex_hull = Slic3r::ExPolygon->new($mesh->convex_hull);
# $self->thumbnail->append($convex_hull);
## }
# return $self->thumbnail;
#}
#
#sub transform_thumbnail {
# my ($self, $model, $obj_idx) = @_;
#
# return unless defined $self->thumbnail;
#
# my $model_object = $model->objects->[$obj_idx];
# my $model_instance = $model_object->instances->[0];
#
# # the order of these transformations MUST be the same everywhere, including
# # in Slic3r::Print->add_model_object()
# my $t = $self->thumbnail->clone;
# $t->rotate($model_instance->rotation, Slic3r::Point->new(0,0));
# $t->scale($model_instance->scaling_factor);
#
# $self->transformed_thumbnail($t);
#}
1;

View file

@ -25,6 +25,7 @@ sub new {
# init GUI elements
my $canvas = Slic3r::GUI::3DScene->new($self);
Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
Slic3r::GUI::_3DScene::set_config($canvas, $config);
$self->canvas($canvas);
my $slider_low = Wx::Slider->new(
$self, -1,
@ -365,16 +366,8 @@ sub load_print {
if ($self->gcode_preview_data->empty) {
# load skirt and brim
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
Slic3r::GUI::_3DScene::load_print_toolpaths($self->canvas);
Slic3r::GUI::_3DScene::load_wipe_tower_toolpaths($self->canvas, \@colors);
foreach my $object (@{$self->print->objects}) {
Slic3r::GUI::_3DScene::load_print_object_toolpaths($self->canvas, $object, \@colors);
# Show the objects in very transparent color.
#my @volume_ids = $self->canvas->load_object($object->model_object);
#$self->canvas->volumes->[$_]->color->[3] = 0.2 for @volume_ids;
}
Slic3r::GUI::_3DScene::load_preview($self->canvas, \@colors);
$self->show_hide_ui_elements('simple');
Slic3r::GUI::_3DScene::reset_legend_texture();
} else {
$self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0);
Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
min_slic3r_version = 1.41.0-alpha
0.2.0-alpha3
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

View file

@ -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-alpha2
config_version = 0.2.0-alpha3
# Where to get the updates from?
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
@ -14,26 +14,27 @@ config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/ma
#TODO: One day we may differentiate variants of the nozzles / hot ends,
#for example by the melt zone size, or whether the nozzle is hardened.
# Printer model name will be shown by the installation wizard.
[printer_model:MK3]
name = Original Prusa i3 MK3
variants = 0.4; 0.25; 0.6
[printer_model:MK2S]
name = Original Prusa i3 MK2S
variants = 0.4; 0.25; 0.6
[printer_model:MK2.5]
name = Original Prusa i3 MK2.5
variants = 0.4; 0.25; 0.6
[printer_model:MK2SMM]
name = Original Prusa i3 MK2S Multi Material Upgrade
variants = 0.4; 0.6
[printer_model:MK2S]
name = Original Prusa i3 MK2/S
variants = 0.4; 0.25; 0.6
[printer_model:MK3MM2]
name = Original Prusa i3 MK3 Multi Material Upgrade 2.0
[printer_model:MK3MMU2]
name = Original Prusa i3 MK3 MMU 2.0
variants = 0.4
[printer_model:MK2SMM]
name = Original Prusa i3 MK2/S MMU 1.0
variants = 0.4; 0.6
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
@ -85,7 +86,7 @@ notes =
overhangs = 0
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = [input_filename_base].gcode
output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}.gcode
perimeters = 2
perimeter_extruder = 1
perimeter_extrusion_width = 0.45
@ -131,8 +132,8 @@ wipe_tower = 1
wipe_tower_bridging = 10
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
wipe_tower_x = 200
wipe_tower_y = 155
xy_size_compensation = 0
# Print parameters common to a 0.25mm diameter nozzle.
@ -259,7 +260,7 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -286,7 +287,7 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -299,7 +300,7 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -362,10 +363,10 @@ compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and
[print:0.15mm OPTIMAL MK3]
inherits = *0.15mm*
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
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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -397,7 +398,7 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -408,7 +409,7 @@ inherits = *common*
bottom_solid_layers = 4
bridge_flow_ratio = 0.95
external_perimeter_speed = 40
infill_acceleration = 2000
infill_acceleration = 1250
infill_speed = 60
layer_height = 0.2
perimeter_acceleration = 800
@ -423,39 +424,13 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
solid_infill_speed = 200
top_solid_infill_speed = 50
[print:0.15mm OPTIMAL MK3 MMU2]
inherits = 0.15mm OPTIMAL MK3
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
bottom_solid_layers = 4
external_perimeter_speed = 40
fill_density = 10%
infill_overlap = 15%
perimeter_speed = 60
small_perimeter_speed = 20
support_material_threshold = 20
top_solid_layers = 5
[print:0.20mm FAST MK3 MMU2]
inherits = 0.20mm FAST MK3
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
bridge_flow_ratio = 0.8
external_perimeter_speed = 40
fill_density = 15%
infill_overlap = 35%
infill_speed = 150
perimeter_speed = 50
small_perimeter_speed = 20
solid_infill_speed = 150
wipe_tower_x = 169
wipe_tower_y = 137
# XXXXXXXXXXXXXXXXXXXX
# XXX--- 0.20mm ---XXX
# XXXXXXXXXXXXXXXXXXXX
@ -475,10 +450,10 @@ top_solid_infill_speed = 70
[print:0.20mm FAST MK3]
inherits = *0.20mm*
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
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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -516,7 +491,7 @@ 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 = 1500
infill_acceleration = 1250
infill_speed = 200
max_print_speed = 200
perimeter_speed = 45
@ -680,6 +655,8 @@ inherits = *PLA*
# For now, all but selected filaments are disabled for the MMU 2.0
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
extrusion_multiplier = 1.2
filament_cost = 80.65
filament_density = 4
filament_colour = #804040
filament_max_volumetric_speed = 10
@ -700,12 +677,16 @@ temperature = 270
[filament:ColorFabb PLA-PHA]
inherits = *PLA*
filament_cost = 55.5
filament_density = 1.24
[filament:ColorFabb Woodfil]
inherits = *PLA*
# For now, all but selected filaments are disabled for the MMU 2.0
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
extrusion_multiplier = 1.2
filament_cost = 62.9
filament_density = 1.15
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 200
@ -714,7 +695,9 @@ temperature = 200
[filament:ColorFabb XT]
inherits = *PET*
filament_type = PLA
filament_type = PET
filament_cost = 62.9
filament_density = 1.27
first_layer_bed_temperature = 90
first_layer_temperature = 260
temperature = 270
@ -722,6 +705,8 @@ temperature = 270
[filament:ColorFabb XT-CF20]
inherits = *PET*
extrusion_multiplier = 1.2
filament_cost = 80.65
filament_density = 1.35
filament_colour = #804040
filament_max_volumetric_speed = 1
first_layer_bed_temperature = 90
@ -731,6 +716,8 @@ temperature = 260
[filament:ColorFabb nGen]
inherits = *PET*
filament_cost = 21.2
filament_density = 1.2
bridge_fan_speed = 40
fan_always_on = 0
fan_below_layer_time = 10
@ -741,6 +728,8 @@ min_fan_speed = 20
[filament:ColorFabb nGen flex]
inherits = *FLEX*
filament_cost = 0
filament_density = 1
bed_temperature = 85
bridge_fan_speed = 40
cooling = 1
@ -756,26 +745,36 @@ temperature = 260
[filament:E3D Edge]
inherits = *PET*
filament_cost = 0
filament_density = 1.26
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:E3D PC-ABS]
inherits = *ABS*
filament_cost = 0
filament_density = 1.05
first_layer_temperature = 270
temperature = 270
[filament:Fillamentum ABS]
inherits = *ABS*
filament_cost = 0
filament_density = 1.04
first_layer_temperature = 240
temperature = 240
[filament:Fillamentum ASA]
inherits = *ABS*
filament_cost = 0
filament_density = 1.04
fan_always_on = 1
first_layer_temperature = 265
temperature = 265
[filament:Fillamentum CPE HG100 HM100]
inherits = *PET*
filament_cost = 0
filament_density = 1.25
filament_notes = "CPE HG100 , CPE HM100"
first_layer_bed_temperature = 90
first_layer_temperature = 275
@ -788,6 +787,8 @@ inherits = *PLA*
# For now, all but selected filaments are disabled for the MMU 2.0
compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
extrusion_multiplier = 1.2
filament_cost = 0
filament_density = 1.15
filament_colour = #804040
filament_max_volumetric_speed = 10
first_layer_temperature = 190
@ -796,14 +797,20 @@ temperature = 190
[filament:Generic ABS]
inherits = *ABS*
filament_cost = 0
filament_density = 1.04
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:Generic PET]
inherits = *PET*
filament_cost = 0
filament_density = 1.24
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:Generic PLA]
inherits = *PLA*
filament_cost = 0
filament_density = 1.27
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:Polymaker PC-Max]
@ -830,8 +837,25 @@ temperature = 195
[filament:Prusa ABS]
inherits = *ABS*
filament_cost = 27.82
filament_density = 1.08
filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS"
[filament:*ABS MMU2*]
inherits = Prusa ABS
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material
filament_cooling_final_speed = 50
filament_cooling_initial_speed = 10
filament_cooling_moves = 5
filament_loading_speed = 14
filament_ramming_parameters = "120 110 5.32258 5.45161 5.67742 6 6.48387 7.12903 7.90323 8.70968 9.3871 9.83871 10.0968 10.2258| 0.05 5.30967 0.45 5.50967 0.95 6.1871 1.45 7.39677 1.95 9.05484 2.45 10 2.95 10.3098 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6";
[filament:Generic ABS MMU2]
inherits = *ABS MMU2*
[filament:Prusa ABS MMU2]
inherits = *ABS MMU2*
[filament:Prusa HIPS]
inherits = *ABS*
bridge_fan_speed = 50
@ -850,10 +874,14 @@ temperature = 220
[filament:Prusa PET]
inherits = *PET*
filament_cost = 27.82
filament_density = 1.27
filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG"
[filament:Prusa PLA]
inherits = *PLA*
filament_cost = 25.4
filament_density = 1.24
filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:*PLA MMU2*]
@ -873,6 +901,8 @@ inherits = *PLA MMU2*
[filament:SemiFlex or Flexfill 98A]
inherits = *FLEX*
filament_cost = 0
filament_density = 1.22
[filament:Taulman Bridge]
inherits = *common*
@ -956,7 +986,7 @@ extruder_offset = 0x0
gcode_flavor = marlin
silent_mode = 0
machine_max_acceleration_e = 10000
machine_max_acceleration_extruding = 1500
machine_max_acceleration_extruding = 2000
machine_max_acceleration_retracting = 1500
machine_max_acceleration_x = 9000
machine_max_acceleration_y = 9000
@ -1118,11 +1148,11 @@ start_gcode = M115 U3.2.1 ; tell printer latest fw version\nM83 ; extruder rela
[printer:Original Prusa i3 MK3]
inherits = *common*
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\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
machine_max_acceleration_e = 9000,9000
machine_max_acceleration_extruding = 1250,960
machine_max_acceleration_e = 5000,5000
machine_max_acceleration_extruding = 1250,1250
machine_max_acceleration_retracting = 1250,1250
machine_max_acceleration_x = 1000,1000
machine_max_acceleration_y = 1000,1000
machine_max_acceleration_x = 1000,960
machine_max_acceleration_y = 1000,960
machine_max_acceleration_z = 1000,1000
machine_max_feedrate_e = 120,120
machine_max_feedrate_x = 200,172
@ -1167,8 +1197,8 @@ cooling_tube_retraction = 30
parking_pos_retraction = 85
retract_length_toolchange = 3
extra_loading_move = -13
printer_model = MK3MM2
default_print_profile = 0.15mm OPTIMAL MK3 MMU2
printer_model = MK3MMU2
default_print_profile = 0.15mm OPTIMAL MK3
default_filament_profile = Prusa PLA MMU2
[printer:Original Prusa i3 MK3 MMU2 Single]
@ -1182,11 +1212,11 @@ inherits = *mm2*
# (for example the retract values) are duplicaed from the first value, so they do not need
# to be defined explicitely.
nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
extruder_colour = #FFFF00;#FFFFFF;#804040;#0000FF;#C0C0C0
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
# 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]
print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3"
print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2"
filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"

View file

@ -26,7 +26,7 @@ include_directories(${LIBDIR}/libslic3r)
if(WIN32)
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB)
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601)
# -D_ITERATOR_DEBUG_LEVEL)
if(WIN10SDK_PATH)
message("Building with Win10 Netfabb STL fixing service support")
@ -258,6 +258,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/Utils/PresetUpdater.hpp
${LIBDIR}/slic3r/Utils/Time.cpp
${LIBDIR}/slic3r/Utils/Time.hpp
${LIBDIR}/slic3r/Utils/HexFile.cpp
${LIBDIR}/slic3r/Utils/HexFile.hpp
${LIBDIR}/slic3r/IProgressIndicator.hpp
${LIBDIR}/slic3r/AppController.hpp
${LIBDIR}/slic3r/AppController.cpp

View file

@ -1,3 +1,4 @@
cmake_minimum_required(VERSION 3.0)
add_definitions(-D_BSD_SOURCE -D_DEFAULT_SOURCE) # To enable various useful macros and functions on Unices
@ -13,67 +14,74 @@ endif()
set(AVRDUDE_SOURCES
${LIBDIR}/avrdude/arduino.c
${LIBDIR}/avrdude/avr.c
# ${LIBDIR}/avrdude/avrftdi.c
# ${LIBDIR}/avrdude/avrftdi_tpi.c
${LIBDIR}/avrdude/avrpart.c
${LIBDIR}/avrdude/avr910.c
${LIBDIR}/avrdude/bitbang.c
${LIBDIR}/avrdude/buspirate.c
${LIBDIR}/avrdude/butterfly.c
${LIBDIR}/avrdude/config.c
${LIBDIR}/avrdude/config_gram.c
# ${LIBDIR}/avrdude/confwin.c
${LIBDIR}/avrdude/crc16.c
# ${LIBDIR}/avrdude/dfu.c
${LIBDIR}/avrdude/fileio.c
# ${LIBDIR}/avrdude/flip1.c
# ${LIBDIR}/avrdude/flip2.c
# ${LIBDIR}/avrdude/ft245r.c
# ${LIBDIR}/avrdude/jtagmkI.c
# ${LIBDIR}/avrdude/jtagmkII.c
# ${LIBDIR}/avrdude/jtag3.c
${LIBDIR}/avrdude/lexer.c
${LIBDIR}/avrdude/linuxgpio.c
${LIBDIR}/avrdude/lists.c
# ${LIBDIR}/avrdude/par.c
${LIBDIR}/avrdude/pgm.c
${LIBDIR}/avrdude/pgm_type.c
${LIBDIR}/avrdude/pickit2.c
${LIBDIR}/avrdude/pindefs.c
# ${LIBDIR}/avrdude/ppi.c
# ${LIBDIR}/avrdude/ppiwin.c
${LIBDIR}/avrdude/safemode.c
${LIBDIR}/avrdude/ser_avrdoper.c
${LIBDIR}/avrdude/serbb_posix.c
${LIBDIR}/avrdude/serbb_win32.c
${LIBDIR}/avrdude/ser_posix.c
${LIBDIR}/avrdude/ser_win32.c
${LIBDIR}/avrdude/stk500.c
${LIBDIR}/avrdude/stk500generic.c
${LIBDIR}/avrdude/stk500v2.c
${LIBDIR}/avrdude/term.c
${LIBDIR}/avrdude/update.c
# ${LIBDIR}/avrdude/usbasp.c
# ${LIBDIR}/avrdude/usb_hidapi.c
# ${LIBDIR}/avrdude/usb_libusb.c
# ${LIBDIR}/avrdude/usbtiny.c
${LIBDIR}/avrdude/wiring.c
arduino.c
avr.c
# avrftdi.c
# avrftdi_tpi.c
avrpart.c
avr910.c
bitbang.c
buspirate.c
butterfly.c
config.c
config_gram.c
# confwin.c
crc16.c
# dfu.c
fileio.c
# flip1.c
# flip2.c
# ft245r.c
# jtagmkI.c
# jtagmkII.c
# jtag3.c
lexer.c
linuxgpio.c
lists.c
# par.c
pgm.c
pgm_type.c
pickit2.c
pindefs.c
# ppi.c
# ppiwin.c
safemode.c
ser_avrdoper.c
serbb_posix.c
serbb_win32.c
ser_posix.c
ser_win32.c
stk500.c
stk500generic.c
stk500v2.c
term.c
update.c
# usbasp.c
# usb_hidapi.c
# usb_libusb.c
# usbtiny.c
wiring.c
${LIBDIR}/avrdude/main.c
${LIBDIR}/avrdude/avrdude-slic3r.hpp
${LIBDIR}/avrdude/avrdude-slic3r.cpp
main.c
avrdude-slic3r.hpp
avrdude-slic3r.cpp
)
if (WIN32)
set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES}
${LIBDIR}/avrdude/windows/unistd.cpp
${LIBDIR}/avrdude/windows/getopt.c
windows/unistd.cpp
windows/getopt.c
)
endif()
add_library(avrdude STATIC ${AVRDUDE_SOURCES})
set(STANDALONE_SOURCES
main-standalone.c
)
add_executable(avrdude-slic3r ${STANDALONE_SOURCES})
target_link_libraries(avrdude-slic3r avrdude)
set_target_properties(avrdude-slic3r PROPERTIES EXCLUDE_FROM_ALL TRUE)
if (WIN32)
target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1)
target_include_directories(avrdude SYSTEM PRIVATE ${LIBDIR}/avrdude/windows) # So that sources find the getopt.h windows drop-in
target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in
endif()

View file

@ -0,0 +1,54 @@
TARGET = avrdude-slic3r
SOURCES = \
arduino.c \
avr.c \
avrpart.c \
avr910.c \
bitbang.c \
buspirate.c \
butterfly.c \
config.c \
config_gram.c \
crc16.c \
fileio.c \
lexer.c \
linuxgpio.c \
lists.c \
pgm.c \
pgm_type.c \
pickit2.c \
pindefs.c \
safemode.c \
ser_avrdoper.c \
serbb_posix.c \
serbb_win32.c \
ser_posix.c \
ser_win32.c \
stk500.c \
stk500generic.c \
stk500v2.c \
term.c \
update.c \
wiring.c \
main.c \
main-standalone.c
OBJECTS = $(SOURCES:.c=.o)
CFLAGS = -std=c99 -Wall -D_BSD_SOURCE -D_DEFAULT_SOURCE -O3 -DNDEBUG -fPIC
LDFLAGS = -lm
CC = gcc
RM = rm
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(CC) -o ./$@ $(OBJECTS) $(LDFLAGS)
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
clean:
$(RM) -f $(OBJECTS) $(TARGET)

View file

@ -36,6 +36,7 @@ struct AvrDude::priv
std::string sys_config;
std::deque<std::vector<std::string>> args;
size_t current_args_set = 0;
bool cancelled = false;
RunFn run_fn;
MessageFn message_fn;
ProgressFn progress_fn;
@ -141,11 +142,16 @@ AvrDude::Ptr AvrDude::run()
if (self->p) {
auto avrdude_thread = std::thread([self]() {
bool cancel = false;
int res = -1;
if (self->p->run_fn) {
self->p->run_fn();
self->p->run_fn(*self);
}
auto res = self->p->run();
if (! self->p->cancelled) {
res = self->p->run();
}
if (self->p->complete_fn) {
self->p->complete_fn(res, self->p->current_args_set);
@ -160,7 +166,10 @@ AvrDude::Ptr AvrDude::run()
void AvrDude::cancel()
{
::avrdude_cancel();
if (p) {
p->cancelled = true;
::avrdude_cancel();
}
}
void AvrDude::join()

View file

@ -12,7 +12,7 @@ class AvrDude
{
public:
typedef std::shared_ptr<AvrDude> Ptr;
typedef std::function<void()> RunFn;
typedef std::function<void(AvrDude&)> RunFn;
typedef std::function<void(const char * /* msg */, unsigned /* size */)> MessageFn;
typedef std::function<void(const char * /* task */, unsigned /* progress */)> ProgressFn;
typedef std::function<void(int /* exit status */, size_t /* args_id */)> CompleteFn;
@ -31,7 +31,8 @@ public:
AvrDude& push_args(std::vector<std::string> args);
// Set a callback to be called just after run() before avrdude is ran
// This can be used to perform any needed setup tasks from the background thread.
// This can be used to perform any needed setup tasks from the background thread,
// and, optionally, to cancel by writing true to the `cancel` argument.
// This has no effect when using run_sync().
AvrDude& on_run(RunFn fn);

View file

@ -98,11 +98,11 @@ static int fileio_num(struct fioparms * fio,
char * filename, FILE * f, AVRMEM * mem, int size,
FILEFMT fmt);
static int fmt_autodetect(char * fname, size_t offset);
static int fmt_autodetect(char * fname, unsigned section);
static FILE *fopen_and_seek(const char *filename, const char *mode, size_t offset)
static FILE *fopen_and_seek(const char *filename, const char *mode, unsigned section)
{
FILE *file;
// On Windows we need to convert the filename to UTF-16
@ -118,16 +118,38 @@ static FILE *fopen_and_seek(const char *filename, const char *mode, size_t offse
file = fopen(filename, mode);
#endif
if (file != NULL) {
// Some systems allow seeking past the end of file, so we need check for that first and disallow
if (fseek(file, 0, SEEK_END) != 0
|| offset >= ftell(file)
|| fseek(file, offset, SEEK_SET) != 0
) {
fclose(file);
file = NULL;
errno = EINVAL;
if (file == NULL) {
return NULL;
}
// Seek to the specified 'section'
static const char *hex_terminator = ":00000001FF\r";
unsigned terms_seen = 0;
char buffer[MAX_LINE_LEN + 1];
while (terms_seen < section && fgets(buffer, MAX_LINE_LEN, file) != NULL) {
size_t len = strlen(buffer);
if (buffer[len - 1] == '\n') {
len--;
buffer[len] = 0;
}
if (buffer[len - 1] != '\r') {
buffer[len] = '\r';
len++;
buffer[len] = 0;
}
if (strcmp(buffer, hex_terminator) == 0) {
// Found a section terminator
terms_seen++;
}
}
if (feof(file)) {
// Section not found
fclose(file);
return NULL;
}
return file;
@ -1392,7 +1414,7 @@ int fileio_setparms(int op, struct fioparms * fp,
static int fmt_autodetect(char * fname, size_t offset)
static int fmt_autodetect(char * fname, unsigned section)
{
FILE * f;
unsigned char buf[MAX_LINE_LEN];
@ -1402,9 +1424,9 @@ static int fmt_autodetect(char * fname, size_t offset)
int first = 1;
#if defined(WIN32NATIVE)
f = fopen_and_seek(fname, "r", offset);
f = fopen_and_seek(fname, "r", section);
#else
f = fopen_and_seek(fname, "rb", offset);
f = fopen_and_seek(fname, "rb", section);
#endif
if (f == NULL) {
@ -1480,7 +1502,7 @@ static int fmt_autodetect(char * fname, size_t offset)
int fileio(int op, char * filename, FILEFMT format,
struct avrpart * p, char * memtype, int size, size_t offset)
struct avrpart * p, char * memtype, int size, unsigned section)
{
int rc;
FILE * f;
@ -1539,7 +1561,7 @@ int fileio(int op, char * filename, FILEFMT format,
return -1;
}
format_detect = fmt_autodetect(fname, offset);
format_detect = fmt_autodetect(fname, section);
if (format_detect < 0) {
avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n",
progname, fname);
@ -1570,7 +1592,7 @@ int fileio(int op, char * filename, FILEFMT format,
if (format != FMT_IMM) {
if (!using_stdio) {
f = fopen_and_seek(fname, fio.mode, offset);
f = fopen_and_seek(fname, fio.mode, section);
if (f == NULL) {
avrdude_message(MSG_INFO, "%s: can't open %s file %s: %s\n",
progname, fio.iodesc, fname, strerror(errno));

View file

@ -821,7 +821,7 @@ extern "C" {
char * fmtstr(FILEFMT format);
int fileio(int op, char * filename, FILEFMT format,
struct avrpart * p, char * memtype, int size, size_t offset);
struct avrpart * p, char * memtype, int size, unsigned section);
#ifdef __cplusplus
}
@ -870,7 +870,7 @@ enum updateflags {
typedef struct update_t {
char * memtype;
int op;
size_t offset;
unsigned section;
char * filename;
int format;
} UPDATE;
@ -882,7 +882,7 @@ extern "C" {
extern UPDATE * parse_op(char * s);
extern UPDATE * dup_update(UPDATE * upd);
extern UPDATE * new_update(int op, char * memtype, int filefmt,
char * filename, size_t offset);
char * filename, unsigned section);
extern void free_update(UPDATE * upd);
extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
enum updateflags flags);

View file

@ -0,0 +1,9 @@
#include "avrdude.h"
static const char* SYS_CONFIG = "/etc/avrdude-slic3r.conf";
int main(int argc, char *argv[])
{
return avrdude_main(argc, argv, SYS_CONFIG);
}

View file

@ -194,7 +194,7 @@ static void usage(void)
" -F Override invalid signature check.\n"
" -e Perform a chip erase.\n"
" -O Perform RC oscillator calibration (see AVR053). \n"
" -U <memtype>:r|w|v:<offset>:<filename>[:format]\n"
" -U <memtype>:r|w|v:<section>:<filename>[:format]\n"
" Memory operation specification.\n"
" Multiple -U options are allowed, each request\n"
" is performed in the order specified.\n"

View file

@ -311,8 +311,10 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
static void ser_close(union filedescriptor *fd)
{
if (serial_over_ethernet) {
#ifdef HAVE_LIBWS2_32
closesocket(fd->ifd);
WSACleanup();
#endif
} else {
HANDLE hComPort=(HANDLE)fd->pfd;
if (hComPort != INVALID_HANDLE_VALUE)

View file

@ -101,22 +101,22 @@ UPDATE * parse_op(char * s)
p++;
// Extension: Parse file contents offset
size_t offset = 0;
// Extension: Parse file section number
unsigned section = 0;
for (; *p != ':'; p++) {
if (*p >= '0' && *p <= '9') {
offset *= 10;
offset += *p - 0x30;
section *= 10;
section += *p - 0x30;
} else {
avrdude_message(MSG_INFO, "%s: invalid update specification: offset is not a number\n", progname);
avrdude_message(MSG_INFO, "%s: invalid update specification: <section> is not a number\n", progname);
free(upd->memtype);
free(upd);
return NULL;
}
}
upd->offset = offset;
upd->section = section;
p++;
/*
@ -194,7 +194,7 @@ UPDATE * dup_update(UPDATE * upd)
return u;
}
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename, size_t offset)
UPDATE * new_update(int op, char * memtype, int filefmt, char * filename, unsigned section)
{
UPDATE * u;
@ -208,7 +208,7 @@ UPDATE * new_update(int op, char * memtype, int filefmt, char * filename, size_t
u->filename = strdup(filename);
u->op = op;
u->format = filefmt;
u->offset = offset;
u->section = section;
return u;
}
@ -286,7 +286,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
progname,
strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
}
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset);
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->section);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
progname, upd->filename);
@ -351,7 +351,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f
progname, mem->desc, upd->filename);
}
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset);
rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->section);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n",
progname, upd->filename);

View file

@ -2,6 +2,7 @@
#include <iostream>
#include <istream>
#include <string>
#include <thread>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
@ -568,16 +569,12 @@ GCodeSender::set_DTR(bool on)
void
GCodeSender::reset()
{
this->set_DTR(false);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
this->set_DTR(true);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
this->set_DTR(false);
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
{
boost::lock_guard<boost::mutex> l(this->queue_mutex);
this->can_send = true;
}
set_DTR(false);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
set_DTR(true);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
set_DTR(false);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
} // namespace Slic3r

View file

@ -611,14 +611,13 @@ bool arrange(Model &model, coordf_t dist, const Slic3r::BoundingBoxf* bb,
// The score is a weighted sum of the distance from pile center
// and the pile size
score = GRAVITY_RATIO * dist + DENSITY_RATIO * density;
std::cout << "big " << std::endl;
} else if(itemnormarea < BIG_ITEM_TRESHOLD && bigs.empty()) {
// If there are no big items, only small, we should consider the
// density here as well to not get silly results
auto bindist = pl::distance(ibb.center(), bin.center()) / norm;
auto density = std::sqrt(fullbb.width()*fullbb.height()) / norm;
score = GRAVITY_RATIO* bindist + DENSITY_RATIO * density;
score = GRAVITY_RATIO * bindist + DENSITY_RATIO * density;
} else {
// Here there are the small items that should be placed around the
// already processed bigger items.

View file

@ -210,11 +210,12 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, selected(false)
, is_active(true)
, zoom_to_volumes(true)
, outside_printer_detection_enabled(true)
, shader_outside_printer_detection_enabled(false)
, is_outside(false)
, hover(false)
, is_modifier(false)
, is_wipe_tower(false)
, is_extrusion_path(false)
, tverts_range(0, size_t(-1))
, qverts_range(0, size_t(-1))
{
@ -250,7 +251,7 @@ void GLVolume::set_render_color()
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
else if (hover)
set_render_color(HOVER_COLOR, 4);
else if (is_outside)
else if (is_outside && shader_outside_printer_detection_enabled)
set_render_color(OUTSIDE_COLOR, 4);
else
set_render_color(color, 4);
@ -441,7 +442,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
if (detection_id != -1)
::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0);
::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
if (worldmatrix_id != -1)
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
@ -460,7 +461,7 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
if (detection_id != -1)
::glUniform1i(detection_id, outside_printer_detection_enabled ? 1 : 0);
::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
if (worldmatrix_id != -1)
::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
@ -633,7 +634,7 @@ std::vector<int> GLVolumeCollection::load_object(
v.extruder_id = extruder_id;
}
v.is_modifier = model_volume->modifier;
v.outside_printer_detection_enabled = !model_volume->modifier;
v.shader_outside_printer_detection_enabled = !model_volume->modifier;
v.set_origin(Pointf3(instance->offset.x, instance->offset.y, 0.0));
v.set_angle_z(instance->rotation);
v.set_scale_factor(instance->scaling_factor);
@ -1786,6 +1787,11 @@ void _3DScene::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable)
s_canvas_mgr.enable_force_zoom_to_bed(canvas, enable);
}
void _3DScene::enable_dynamic_background(wxGLCanvas* canvas, bool enable)
{
s_canvas_mgr.enable_dynamic_background(canvas, enable);
}
void _3DScene::allow_multisample(wxGLCanvas* canvas, bool allow)
{
s_canvas_mgr.allow_multisample(canvas, allow);
@ -1968,26 +1974,16 @@ void _3DScene::reload_scene(wxGLCanvas* canvas, bool force)
s_canvas_mgr.reload_scene(canvas, force);
}
void _3DScene::load_print_toolpaths(wxGLCanvas* canvas)
{
s_canvas_mgr.load_print_toolpaths(canvas);
}
void _3DScene::load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& str_tool_colors)
{
s_canvas_mgr.load_print_object_toolpaths(canvas, print_object, str_tool_colors);
}
void _3DScene::load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors)
{
s_canvas_mgr.load_wipe_tower_toolpaths(canvas, str_tool_colors);
}
void _3DScene::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors)
{
s_canvas_mgr.load_gcode_preview(canvas, preview_data, str_tool_colors);
}
void _3DScene::load_preview(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors)
{
s_canvas_mgr.load_preview(canvas, str_tool_colors);
}
void _3DScene::reset_legend_texture()
{
s_canvas_mgr.reset_legend_texture();

View file

@ -289,8 +289,8 @@ public:
bool is_active;
// Whether or not to use this volume when applying zoom_to_volumes()
bool zoom_to_volumes;
// Wheter or not this volume is enabled for outside print volume detection.
bool outside_printer_detection_enabled;
// Wheter or not this volume is enabled for outside print volume detection in shader.
bool shader_outside_printer_detection_enabled;
// Wheter or not this volume is outside print volume.
bool is_outside;
// Boolean: Is mouse over this object?
@ -299,6 +299,8 @@ public:
bool is_modifier;
// Wheter or not this volume has been generated from the wipe tower
bool is_wipe_tower;
// Wheter or not this volume has been generated from an extrusion path
bool is_extrusion_path;
// Interleaved triangles & normals with indexed triangles & quads.
GLIndexedVertexArray indexed_vertex_array;
@ -497,6 +499,7 @@ public:
static void enable_gizmos(wxGLCanvas* canvas, bool enable);
static void enable_shader(wxGLCanvas* canvas, bool enable);
static void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
static void enable_dynamic_background(wxGLCanvas* canvas, bool enable);
static void allow_multisample(wxGLCanvas* canvas, bool allow);
static void zoom_to_bed(wxGLCanvas* canvas);
@ -536,10 +539,8 @@ public:
static void reload_scene(wxGLCanvas* canvas, bool force);
static void load_print_toolpaths(wxGLCanvas* canvas);
static void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& str_tool_colors);
static void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
static void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
static void load_preview(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
static void reset_legend_texture();

View file

@ -1,12 +1,23 @@
#include "FirmwareDialog.hpp"
#include <numeric>
#include <algorithm>
#include <thread>
#include <stdexcept>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/log/trivial.hpp>
#include "libslic3r/Utils.hpp"
#include "avrdude/avrdude-slic3r.hpp"
#include "GUI.hpp"
#include "MsgDialog.hpp"
#include "../Utils/HexFile.hpp"
#include "../Utils/Serial.hpp"
// wx includes need to come after asio because of the WinSock.h problem
#include "FirmwareDialog.hpp"
#include <wx/app.h>
#include <wx/event.h>
#include <wx/sizer.h>
@ -22,16 +33,18 @@
#include <wx/collpane.h>
#include <wx/msgdlg.h>
#include "libslic3r/Utils.hpp"
#include "avrdude/avrdude-slic3r.hpp"
#include "GUI.hpp"
#include "../Utils/Serial.hpp"
namespace fs = boost::filesystem;
namespace asio = boost::asio;
using boost::system::error_code;
namespace Slic3r {
using Utils::HexFile;
using Utils::SerialPortInfo;
using Utils::Serial;
// This enum discriminates the kind of information in EVT_AVRDUDE,
// it's stored in the ExtraLong field of wxCommandEvent.
@ -40,6 +53,7 @@ enum AvrdudeEvent
AE_MESSAGE,
AE_PROGRESS,
AE_EXIT,
AE_ERROR,
};
wxDECLARE_EVENT(EVT_AVRDUDE, wxCommandEvent);
@ -52,7 +66,6 @@ struct FirmwareDialog::priv
{
enum AvrDudeComplete
{
AC_NONE,
AC_SUCCESS,
AC_FAILURE,
AC_CANCEL,
@ -61,7 +74,7 @@ struct FirmwareDialog::priv
FirmwareDialog *q; // PIMPL back pointer ("Q-Pointer")
wxComboBox *port_picker;
std::vector<Utils::SerialPortInfo> ports;
std::vector<SerialPortInfo> ports;
wxFilePickerCtrl *hex_picker;
wxStaticText *txt_status;
wxGauge *progressbar;
@ -80,7 +93,9 @@ struct FirmwareDialog::priv
AvrDude::Ptr avrdude;
std::string avrdude_config;
unsigned progress_tasks_done;
unsigned progress_tasks_bar;
bool cancelled;
const bool extra_verbose; // For debugging
priv(FirmwareDialog *q) :
q(q),
@ -89,16 +104,25 @@ struct FirmwareDialog::priv
timer_pulse(q),
avrdude_config((fs::path(::Slic3r::resources_dir()) / "avrdude" / "avrdude.conf").string()),
progress_tasks_done(0),
cancelled(false)
progress_tasks_bar(0),
cancelled(false),
extra_verbose(false)
{}
void find_serial_ports();
void flashing_start(bool flashing_l10n);
void flashing_start(unsigned tasks);
void flashing_done(AvrDudeComplete complete);
size_t hex_lang_offset(const wxString &path);
void check_model_id(const HexFile &metadata, const SerialPortInfo &port);
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);
void perform_upload();
void cancel();
void on_avrdude(const wxCommandEvent &evt);
void ensure_joined();
};
void FirmwareDialog::priv::find_serial_ports()
@ -108,7 +132,7 @@ void FirmwareDialog::priv::find_serial_ports()
this->ports = new_ports;
port_picker->Clear();
for (const auto &port : this->ports)
port_picker->Append(port.friendly_name);
port_picker->Append(wxString::FromUTF8(port.friendly_name.data()));
if (ports.size() > 0) {
int idx = port_picker->GetValue().IsEmpty() ? 0 : -1;
for (int i = 0; i < (int)this->ports.size(); ++ i)
@ -122,7 +146,7 @@ void FirmwareDialog::priv::find_serial_ports()
}
}
void FirmwareDialog::priv::flashing_start(bool flashing_l10n)
void FirmwareDialog::priv::flashing_start(unsigned tasks)
{
txt_stdout->Clear();
txt_status->SetLabel(_(L("Flashing in progress. Please do not disconnect the printer!")));
@ -132,9 +156,10 @@ void FirmwareDialog::priv::flashing_start(bool flashing_l10n)
hex_picker->Disable();
btn_close->Disable();
btn_flash->SetLabel(btn_flash_label_flashing);
progressbar->SetRange(flashing_l10n ? 500 : 200); // See progress callback below
progressbar->SetRange(200 * tasks); // See progress callback below
progressbar->SetValue(0);
progress_tasks_done = 0;
progress_tasks_bar = 0;
cancelled = false;
timer_pulse.Start(50);
}
@ -158,63 +183,49 @@ void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete)
}
}
size_t FirmwareDialog::priv::hex_lang_offset(const wxString &path)
void FirmwareDialog::priv::check_model_id(const HexFile &metadata, const SerialPortInfo &port)
{
fs::ifstream file(fs::path(path.wx_str()));
if (! file.good()) {
return 0;
if (metadata.model_id.empty()) {
// No data to check against
return;
}
asio::io_service io;
Serial serial(io, port.port, 115200);
serial.printer_setup();
enum {
TIMEOUT = 1000,
RETREIES = 3,
};
if (! serial.printer_ready_wait(RETREIES, TIMEOUT)) {
throw wxString::Format(_(L("Could not connect to the printer at %s")), port.port);
}
static const char *hex_terminator = ":00000001FF\r";
size_t res = 0;
std::string line;
while (getline(file, line, '\n').good()) {
// Account for LF vs CRLF
if (!line.empty() && line.back() != '\r') {
line.push_back('\r');
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; }
if (line == metadata.model_id) {
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);
}
if (line == hex_terminator) {
if (res == 0) {
// This is the first terminator seen, save the position
res = file.tellg();
} else {
// We've found another terminator, return the offset just after the first one
// which is the start of the second 'section'.
return res;
}
}
line.clear();
}
return 0;
}
void FirmwareDialog::priv::perform_upload()
void FirmwareDialog::priv::prepare_common(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename)
{
auto filename = hex_picker->GetPath();
std::string port = port_picker->GetValue().ToStdString();
int selection = port_picker->GetSelection();
if (selection != -1) {
// Verify whether the combo box list selection equals to the combo box edit value.
if (this->ports[selection].friendly_name == port)
port = this->ports[selection].port;
}
if (filename.IsEmpty() || port.empty()) { return; }
const bool extra_verbose = false; // For debugging
const auto lang_offset = hex_lang_offset(filename);
const auto filename_utf8 = filename.utf8_str();
flashing_start(lang_offset > 0);
// It is ok here to use the q-pointer to the FirmwareDialog
// because the dialog ensures it doesn't exit before the background thread is done.
auto q = this->q;
// Init the avrdude object
AvrDude avrdude(avrdude_config);
// Build argument list(s)
std::vector<std::string> args {{
extra_verbose ? "-vvvvv" : "-v",
"-p", "atmega2560",
@ -222,11 +233,10 @@ void FirmwareDialog::priv::perform_upload()
// 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,
"-P", port.port,
"-b", "115200", // TODO: Allow other rates? Ditto below.
"-D",
// XXX: Safe mode?
"-U", (boost::format("flash:w:0:%1%:i") % filename_utf8.data()).str(),
"-U", (boost::format("flash:w:0:%1%:i") % filename).str(),
}};
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: "
@ -235,32 +245,167 @@ void FirmwareDialog::priv::perform_upload()
});
avrdude.push_args(std::move(args));
if (lang_offset > 0) {
// 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<std::string> args_l10n {{
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,
"-b", "115200",
"-D",
"-u", // disable safe mode
"-U", (boost::format("flash:w:%1%:%2%:i") % lang_offset % filename_utf8.data()).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) {
return a + ' ' + b;
});
void FirmwareDialog::priv::prepare_mk2(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename)
{
prepare_common(avrdude, port, filename);
}
avrdude.push_args(std::move(args_l10n));
void FirmwareDialog::priv::prepare_mk3(AvrDude &avrdude, const SerialPortInfo &port, const std::string &filename)
{
prepare_common(avrdude, port, filename);
// 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<std::string> args_l10n {{
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,
"-b", "115200",
"-D",
"-u", // disable safe mode
"-U", (boost::format("flash:w:1:%1%:i") % filename).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) {
return a + ' ' + b;
});
avrdude.push_args(std::move(args_l10n));
}
void FirmwareDialog::priv::prepare_mm_control(AvrDude &avrdude, const SerialPortInfo &port_in, const std::string &filename)
{
// 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);
}
}
BOOST_LOG_TRIVIAL(info) << boost::format("Found VID/PID 0x2c99/3 at `%1%`, flashing ...") % port.port;
std::vector<std::string> args {{
extra_verbose ? "-vvvvv" : "-v",
"-p", "atmega32u4",
"-c", "avr109",
"-P", port.port,
"-b", "57600",
"-D",
"-U", (boost::format("flash:w:0:%1%:i") % filename).str(),
}};
BOOST_LOG_TRIVIAL(info) << "Invoking avrdude, arguments: "
<< 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));
}
void FirmwareDialog::priv::perform_upload()
{
auto filename = hex_picker->GetPath();
if (filename.IsEmpty()) { return; }
int selection = port_picker->GetSelection();
if (selection == wxNOT_FOUND) { return; }
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;
}
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);
// Init the avrdude object
AvrDude avrdude(avrdude_config);
// It is ok here to use the q-pointer to the FirmwareDialog
// because the dialog ensures it doesn't exit before the background thread is done.
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);
};
try {
switch (metadata.device) {
case HexFile::DEV_MK3:
this->check_model_id(metadata, port);
this->prepare_mk3(avrdude, port, filename_utf8);
break;
case HexFile::DEV_MM_CONTROL:
this->check_model_id(metadata, port);
this->prepare_mm_control(avrdude, port, filename_utf8);
break;
default:
this->prepare_mk2(avrdude, port, filename_utf8);
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()));
}
})
.on_message(std::move([q, extra_verbose](const char *msg, unsigned /* size */) {
if (extra_verbose) {
BOOST_LOG_TRIVIAL(debug) << "avrdude: " << msg;
@ -313,12 +458,15 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt)
// and then display overall progress during the latter tasks.
if (progress_tasks_done > 0) {
progressbar->SetValue(progress_tasks_done - 100 + evt.GetInt());
progressbar->SetValue(progress_tasks_bar + evt.GetInt());
}
if (evt.GetInt() == 100) {
timer_pulse.Stop();
progress_tasks_done += 100;
if (progress_tasks_done % 3 != 0) {
progress_tasks_bar += 100;
}
progress_tasks_done++;
}
break;
@ -328,11 +476,17 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt)
complete_kind = cancelled ? AC_CANCEL : (evt.GetInt() == 0 ? AC_SUCCESS : AC_FAILURE);
flashing_done(complete_kind);
ensure_joined();
break;
// Make sure the background thread is collected and the AvrDude object reset
if (avrdude) { avrdude->join(); }
avrdude.reset();
case AE_ERROR:
txt_stdout->AppendText(evt.GetString());
flashing_done(AC_FAILURE);
ensure_joined();
{
GUI::ErrorDialog dlg(this->q, evt.GetString());
dlg.ShowModal();
}
break;
default:
@ -340,6 +494,13 @@ void FirmwareDialog::priv::on_avrdude(const wxCommandEvent &evt)
}
}
void FirmwareDialog::priv::ensure_joined()
{
// Make sure the background thread is collected and the AvrDude object reset
if (avrdude) { avrdude->join(); }
avrdude.reset();
}
// Public

File diff suppressed because it is too large Load diff

View file

@ -449,6 +449,7 @@ private:
bool m_picking_enabled;
bool m_moving_enabled;
bool m_shader_enabled;
bool m_dynamic_background_enabled;
bool m_multisample_allowed;
std::string m_color_by;
@ -539,6 +540,7 @@ public:
void enable_gizmos(bool enable);
void enable_shader(bool enable);
void enable_force_zoom_to_bed(bool enable);
void enable_dynamic_background(bool enable);
void allow_multisample(bool allow);
void zoom_to_bed();
@ -559,16 +561,8 @@ public:
void reload_scene(bool force);
// Create 3D thick extrusion lines for a skirt and brim.
// Adds a new Slic3r::GUI::3DScene::Volume to volumes.
void load_print_toolpaths();
// Create 3D thick extrusion lines for object forming extrusions.
// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
// one for perimeters, one for infill and one for supports.
void load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors);
// Create 3D thick extrusion lines for wipe tower extrusions
void load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors);
void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors);
void load_preview(const std::vector<std::string>& str_tool_colors);
void register_on_viewport_changed_callback(void* callback);
void register_on_double_click_callback(void* callback);
@ -650,7 +644,17 @@ private:
void _stop_timer();
int _get_first_selected_object_id() const;
int _get_first_selected_volume_id() const;
int _get_first_selected_volume_id(int object_id) const;
// Create 3D thick extrusion lines for a skirt and brim.
// Adds a new Slic3r::GUI::3DScene::Volume to volumes.
void _load_print_toolpaths();
// Create 3D thick extrusion lines for object forming extrusions.
// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
// one for perimeters, one for infill and one for supports.
void _load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors);
// Create 3D thick extrusion lines for wipe tower extrusions
void _load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors);
// generates gcode extrusion paths geometry
void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
@ -667,6 +671,8 @@ private:
void _load_shells();
// sets gcode geometry visibility according to user selection
void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data);
void _update_toolpath_volumes_outside_state();
void _show_warning_texture_if_needed();
void _on_move(const std::vector<int>& volume_idxs);
void _on_select(int volume_idx);
@ -678,6 +684,8 @@ private:
void _generate_warning_texture(const std::string& msg);
void _reset_warning_texture();
bool _is_any_volume_outside() const;
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
};

View file

@ -418,6 +418,13 @@ void GLCanvas3DManager::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable
it->second->enable_force_zoom_to_bed(enable);
}
void GLCanvas3DManager::enable_dynamic_background(wxGLCanvas* canvas, bool enable)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->enable_dynamic_background(enable);
}
void GLCanvas3DManager::allow_multisample(wxGLCanvas* canvas, bool allow)
{
CanvasesMap::iterator it = _get_canvas(canvas);
@ -516,30 +523,6 @@ void GLCanvas3DManager::reload_scene(wxGLCanvas* canvas, bool force)
it->second->reload_scene(force);
}
void GLCanvas3DManager::load_print_toolpaths(wxGLCanvas* canvas)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->load_print_toolpaths();
}
void GLCanvas3DManager::load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& tool_colors)
{
if (print_object == nullptr)
return;
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->load_print_object_toolpaths(*print_object, tool_colors);
}
void GLCanvas3DManager::load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->load_wipe_tower_toolpaths(str_tool_colors);
}
void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors)
{
if (preview_data == nullptr)
@ -550,6 +533,13 @@ void GLCanvas3DManager::load_gcode_preview(wxGLCanvas* canvas, const GCodePrevie
it->second->load_gcode_preview(*preview_data, str_tool_colors);
}
void GLCanvas3DManager::load_preview(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->load_preview(str_tool_colors);
}
void GLCanvas3DManager::reset_legend_texture()
{
for (CanvasesMap::value_type& canvas : m_canvases)

View file

@ -112,6 +112,7 @@ public:
void enable_gizmos(wxGLCanvas* canvas, bool enable);
void enable_shader(wxGLCanvas* canvas, bool enable);
void enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable);
void enable_dynamic_background(wxGLCanvas* canvas, bool enable);
void allow_multisample(wxGLCanvas* canvas, bool allow);
void zoom_to_bed(wxGLCanvas* canvas);
@ -132,10 +133,8 @@ public:
void reload_scene(wxGLCanvas* canvas, bool force);
void load_print_toolpaths(wxGLCanvas* canvas);
void load_print_object_toolpaths(wxGLCanvas* canvas, const PrintObject* print_object, const std::vector<std::string>& tool_colors);
void load_wipe_tower_toolpaths(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
void load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors);
void load_preview(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors);
void reset_legend_texture();

View file

@ -250,6 +250,7 @@ bool select_language(wxArrayString & names,
g_wxLocale->AddCatalogLookupPathPrefix(wxPathOnly(localization_dir()));
g_wxLocale->AddCatalog(g_wxApp->GetAppName());
wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified();
return true;
}
return false;
@ -275,6 +276,7 @@ bool load_language()
g_wxLocale->AddCatalogLookupPathPrefix(wxPathOnly(localization_dir()));
g_wxLocale->AddCatalog(g_wxApp->GetAppName());
wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified();
return true;
}
}

View file

@ -146,6 +146,11 @@ const std::string& Preset::suffix_modified()
{
return g_suffix_modified;
}
void Preset::update_suffix_modified()
{
g_suffix_modified = (" (" + _(L("modified")) + ")").ToUTF8().data();
}
// Remove an optional "(modified)" suffix from a name.
// This converts a UI name to a unique preset identifier.
std::string Preset::remove_suffix_modified(const std::string &name)

View file

@ -167,6 +167,7 @@ public:
static const std::vector<std::string>& printer_options();
// Nozzle options of the printer options.
static const std::vector<std::string>& nozzle_options();
static void update_suffix_modified();
protected:
friend class PresetCollection;
@ -260,7 +261,7 @@ public:
// used to update preset_choice from Tab
const std::deque<Preset>& get_presets() { return m_presets; }
int get_idx_selected() { return m_idx_selected; }
const std::string& get_suffix_modified();
static const std::string& get_suffix_modified();
// Return a preset possibly with modifications.
Preset& default_preset() { return m_presets.front(); }

View file

@ -552,6 +552,8 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
std::string &inherits = Preset::inherits(config);
compatible_printers_condition_values.resize(num_extruders + 2, std::string());
inherits_values.resize(num_extruders + 2, std::string());
// The "default_filament_profile" will be later extracted into the printer profile.
config.option<ConfigOptionStrings>("default_filament_profile", true)->values.resize(num_extruders, std::string());
// 1) Create a name from the file name.
// Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles.
@ -576,7 +578,6 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
// 3) Now load the filaments. If there are multiple filament presets, split them and load them.
auto old_filament_profile_names = config.option<ConfigOptionStrings>("filament_settings_id", true);
old_filament_profile_names->values.resize(num_extruders, std::string());
config.option<ConfigOptionStrings>("default_filament_profile", true)->values.resize(num_extruders, std::string());
if (num_extruders <= 1) {
// Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.

View file

@ -2728,7 +2728,7 @@ void SavePresetWindow::accept()
const char* unusable_symbols = "<>:/\\|?*\"";
bool is_unusable_symbol = false;
bool is_unusable_postfix = false;
const std::string unusable_postfix = "(modified)";
const std::string unusable_postfix = PresetCollection::get_suffix_modified();//"(modified)";
for (size_t i = 0; i < std::strlen(unusable_symbols); i++){
if (m_chosen_name.find_first_of(unusable_symbols[i]) != std::string::npos){
is_unusable_symbol = true;
@ -2743,8 +2743,9 @@ void SavePresetWindow::accept()
_(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
}
else if (is_unusable_postfix){
show_error(this, _(L("The supplied name is not valid;")) + "\n" +
_(L("the following postfix are not allowed:")) + "\n\t" + unusable_postfix);
show_error(this,_(L("The supplied name is not valid;")) + "\n" +
_(L("the following postfix are not allowed:")) + "\n\t" + //unusable_postfix);
wxString::FromUTF8(unusable_postfix.c_str()));
}
else if (m_chosen_name.compare("- default -") == 0) {
show_error(this, _(L("The supplied name is not available.")));

View file

@ -0,0 +1,107 @@
#include "HexFile.hpp"
#include <sstream>
#include <boost/filesystem/fstream.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
namespace Slic3r {
namespace Utils {
static HexFile::DeviceKind parse_device_kind(const std::string &str)
{
if (str == "mk2") { return HexFile::DEV_MK2; }
else if (str == "mk3") { return HexFile::DEV_MK3; }
else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; }
else { return HexFile::DEV_GENERIC; }
}
static size_t hex_num_sections(fs::ifstream &file)
{
file.seekg(0);
if (! file.good()) {
return 0;
}
static const char *hex_terminator = ":00000001FF\r";
size_t res = 0;
std::string line;
while (getline(file, line, '\n').good()) {
// Account for LF vs CRLF
if (!line.empty() && line.back() != '\r') {
line.push_back('\r');
}
if (line == hex_terminator) {
res++;
}
}
return res;
}
HexFile::HexFile(fs::path path) :
path(std::move(path)),
device(DEV_GENERIC)
{
fs::ifstream file(this->path);
if (! file.good()) {
return;
}
std::string line;
std::stringstream header_ini;
while (std::getline(file, line, '\n').good()) {
if (line.empty()) {
continue;
}
// Account for LF vs CRLF
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
if (line.front() == ';') {
line.front() = ' ';
header_ini << line << std::endl;
} else if (line.front() == ':') {
break;
}
}
pt::ptree ptree;
try {
pt::read_ini(header_ini, ptree);
} catch (std::exception &e) {
return;
}
bool has_device_meta = false;
const auto device = ptree.find("device");
if (device != ptree.not_found()) {
this->device = parse_device_kind(device->second.data());
has_device_meta = true;
}
const auto model_id = ptree.find("model_id");
if (model_id != ptree.not_found()) {
this->model_id = model_id->second.data();
}
if (! has_device_meta) {
// No device metadata, look at the number of 'sections'
if (hex_num_sections(file) == 2) {
// Looks like a pre-metadata l10n firmware for the MK3, assume that's the case
this->device = DEV_MK3;
}
}
}
}
}

View file

@ -0,0 +1,32 @@
#ifndef slic3r_Hex_hpp_
#define slic3r_Hex_hpp_
#include <string>
#include <boost/filesystem/path.hpp>
namespace Slic3r {
namespace Utils {
struct HexFile
{
enum DeviceKind {
DEV_GENERIC,
DEV_MK2,
DEV_MK3,
DEV_MM_CONTROL,
};
boost::filesystem::path path;
DeviceKind device;
std::string model_id;
HexFile(boost::filesystem::path path);
};
}
}
#endif

View file

@ -3,17 +3,22 @@
#include <algorithm>
#include <string>
#include <vector>
#include <chrono>
#include <thread>
#include <fstream>
#include <stdexcept>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/optional.hpp>
#if _WIN32
#include <Windows.h>
#include <Setupapi.h>
#include <initguid.h>
#include <devguid.h>
#include <regex>
// Undefine min/max macros incompatible with the standard library
// For example, std::numeric_limits<std::streamsize>::max()
// produces some weird errors
@ -34,6 +39,23 @@
#include <sys/syslimits.h>
#endif
#ifndef _WIN32
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/select.h>
#endif
#if defined(__APPLE__) || defined(__OpenBSD__)
#include <termios.h>
#elif defined __linux__
#include <fcntl.h>
#include <asm-generic/ioctls.h>
#endif
using boost::optional;
namespace Slic3r {
namespace Utils {
@ -42,15 +64,43 @@ static bool looks_like_printer(const std::string &friendly_name)
return friendly_name.find("Original Prusa") != std::string::npos;
}
#ifdef __linux__
static std::string get_tty_friendly_name(const std::string &path, const std::string &name)
#if _WIN32
void parse_hardware_id(const std::string &hardware_id, SerialPortInfo &spi)
{
const auto sysfs_product = (boost::format("/sys/class/tty/%1%/device/../product") % name).str();
std::ifstream file(sysfs_product);
std::string product;
unsigned vid, pid;
std::regex pattern("USB\\\\.*VID_([[:xdigit:]]+)&PID_([[:xdigit:]]+).*");
std::smatch matches;
if (std::regex_match(hardware_id, matches, pattern)) {
try {
vid = std::stoul(matches[1].str(), 0, 16);
pid = std::stoul(matches[2].str(), 0, 16);
spi.id_vendor = vid;
spi.id_product = pid;
}
catch (...) {}
}
}
#endif
std::getline(file, product);
return file.good() ? (boost::format("%1% (%2%)") % product % path).str() : path;
#ifdef __linux__
optional<std::string> sysfs_tty_prop(const std::string &tty_dev, const std::string &name)
{
const auto prop_path = (boost::format("/sys/class/tty/%1%/device/../%2%") % tty_dev % name).str();
std::ifstream file(prop_path);
std::string res;
std::getline(file, res);
if (file.good()) { return res; }
else { return boost::none; }
}
optional<unsigned long> sysfs_tty_prop_hex(const std::string &tty_dev, const std::string &name)
{
auto prop = sysfs_tty_prop(tty_dev, name);
if (!prop) { return boost::none; }
try { return std::stoul(*prop, 0, 16); }
catch (...) { return boost::none; }
}
#endif
@ -80,6 +130,7 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
if (port_info.port.empty())
continue;
}
// Find the size required to hold the device info.
DWORD regDataType;
DWORD reqSize = 0;
@ -88,7 +139,8 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
// Now store it in a buffer.
if (! SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, (BYTE*)hardware_id.data(), reqSize, nullptr))
continue;
port_info.hardware_id = boost::nowide::narrow(hardware_id.data());
parse_hardware_id(boost::nowide::narrow(hardware_id.data()), port_info);
// Find the size required to hold the friendly name.
reqSize = 0;
SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
@ -120,6 +172,8 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
if (result) {
SerialPortInfo port_info;
port_info.port = path;
// Attempt to read out the device friendly name
if ((cf_property = IORegistryEntrySearchCFProperty(port, kIOServicePlane,
CFSTR("USB Interface Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
@ -141,6 +195,23 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
}
if (port_info.friendly_name.empty())
port_info.friendly_name = port_info.port;
// Attempt to read out the VID & PID
int vid, pid;
auto cf_vendor = IORegistryEntrySearchCFProperty(port, kIOServicePlane, CFSTR("idVendor"),
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
auto cf_product = IORegistryEntrySearchCFProperty(port, kIOServicePlane, CFSTR("idProduct"),
kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
if (cf_vendor && cf_product) {
if (CFNumberGetValue((CFNumberRef)cf_vendor, kCFNumberIntType, &vid) &&
CFNumberGetValue((CFNumberRef)cf_product, kCFNumberIntType, &pid)) {
port_info.id_vendor = vid;
port_info.id_product = pid;
}
}
if (cf_vendor) { CFRelease(cf_vendor); }
if (cf_product) { CFRelease(cf_product); }
output.emplace_back(std::move(port_info));
}
}
@ -158,9 +229,15 @@ std::vector<SerialPortInfo> scan_serial_ports_extended()
const auto path = dir_entry.path().string();
SerialPortInfo spi;
spi.port = path;
spi.hardware_id = path;
#ifdef __linux__
spi.friendly_name = get_tty_friendly_name(path, name);
auto friendly_name = sysfs_tty_prop(name, "product");
spi.friendly_name = friendly_name ? (boost::format("%1% (%2%)") % *friendly_name % path).str() : path;
auto vid = sysfs_tty_prop_hex(name, "idVendor");
auto pid = sysfs_tty_prop_hex(name, "idProduct");
if (vid && pid) {
spi.id_vendor = *vid;
spi.id_product = *pid;
}
#else
spi.friendly_name = path;
#endif
@ -189,5 +266,224 @@ std::vector<std::string> scan_serial_ports()
return output;
}
// Class Serial
namespace asio = boost::asio;
using boost::system::error_code;
Serial::Serial(asio::io_service& io_service) :
asio::serial_port(io_service)
{}
Serial::Serial(asio::io_service& io_service, const std::string &name, unsigned baud_rate) :
asio::serial_port(io_service, name)
{
set_baud_rate(baud_rate);
}
Serial::~Serial() {}
void Serial::set_baud_rate(unsigned baud_rate)
{
try {
// This does not support speeds > 115200
set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
} catch (boost::system::system_error &) {
auto handle = native_handle();
auto handle_errno = [](int retval) {
if (retval != 0) {
throw std::runtime_error(
(boost::format("Could not set baud rate: %1%") % strerror(errno)).str()
);
}
};
#if __APPLE__
termios ios;
handle_errno(::tcgetattr(handle, &ios));
handle_errno(::cfsetspeed(&ios, baud_rate));
speed_t newSpeed = baud_rate;
handle_errno(::ioctl(handle, IOSSIOSPEED, &newSpeed));
handle_errno(::tcsetattr(handle, TCSANOW, &ios));
#elif __linux
/* The following definitions are kindly borrowed from:
/usr/include/asm-generic/termbits.h
Unfortunately we cannot just include that one because
it would redefine the "struct termios" already defined
the <termios.h> already included by Boost.ASIO. */
#define K_NCCS 19
struct termios2 {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[K_NCCS];
speed_t c_ispeed;
speed_t c_ospeed;
};
#define BOTHER CBAUDEX
termios2 ios;
handle_errno(::ioctl(handle, TCGETS2, &ios));
ios.c_ispeed = ios.c_ospeed = baud_rate;
ios.c_cflag &= ~CBAUD;
ios.c_cflag |= BOTHER | CLOCAL | CREAD;
ios.c_cc[VMIN] = 1; // Minimum of characters to read, prevents eof errors when 0 bytes are read
ios.c_cc[VTIME] = 1;
handle_errno(::ioctl(handle, TCSETS2, &ios));
#elif __OpenBSD__
struct termios ios;
handle_errno(::tcgetattr(handle, &ios));
handle_errno(::cfsetspeed(&ios, baud_rate));
handle_errno(::tcsetattr(handle, TCSAFLUSH, &ios));
#else
throw std::runtime_error("Custom baud rates are not currently supported on this OS");
#endif
}
}
void Serial::set_DTR(bool on)
{
auto handle = native_handle();
#if defined(_WIN32) && !defined(__SYMBIAN32__)
if (! EscapeCommFunction(handle, on ? SETDTR : CLRDTR)) {
throw std::runtime_error("Could not set serial port DTR");
}
#else
int status;
if (::ioctl(handle, TIOCMGET, &status) == 0) {
on ? status |= TIOCM_DTR : status &= ~TIOCM_DTR;
if (::ioctl(handle, TIOCMSET, &status) == 0) {
return;
}
}
throw std::runtime_error(
(boost::format("Could not set serial port DTR: %1%") % strerror(errno)).str()
);
#endif
}
void Serial::reset_line_num()
{
// See https://github.com/MarlinFirmware/Marlin/wiki/M110
printer_write_line("M110 N0", 0);
m_line_num = 0;
}
bool Serial::read_line(unsigned timeout, std::string &line, error_code &ec)
{
auto &io_service = get_io_service();
asio::deadline_timer timer(io_service);
char c = 0;
bool fail = false;
while (true) {
io_service.reset();
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;
}
timer.cancel();
});
if (timeout > 0) {
timer.expires_from_now(boost::posix_time::milliseconds(timeout));
timer.async_wait([&](const error_code &ec) {
// Ignore timer aborts
if (!ec) {
fail = true;
this->cancel();
}
});
}
io_service.run();
if (fail) {
return false;
} else if (c != '\n') {
line += c;
} else {
return true;
}
}
}
void Serial::printer_setup()
{
printer_reset();
write_string("\r\r\r\r\r\r\r\r\r\r"); // Gets rid of line noise, if any
}
size_t Serial::write_string(const std::string &str)
{
// TODO: might be wise to timeout here as well
return asio::write(*this, asio::buffer(str));
}
bool Serial::printer_ready_wait(unsigned retries, unsigned timeout)
{
std::string line;
error_code ec;
for (; retries > 0; retries--) {
reset_line_num();
while (read_line(timeout, line, ec)) {
if (line == "ok") {
return true;
}
line.clear();
}
line.clear();
}
return false;
}
size_t Serial::printer_write_line(const std::string &line, unsigned line_num)
{
const auto formatted_line = Utils::Serial::printer_format_line(line, line_num);
return write_string(formatted_line);
}
size_t Serial::printer_write_line(const std::string &line)
{
m_line_num++;
return printer_write_line(line, m_line_num);
}
void Serial::printer_reset()
{
this->set_DTR(false);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
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::string Serial::printer_format_line(const std::string &line, unsigned line_num)
{
const auto line_num_str = std::to_string(line_num);
unsigned checksum = 'N';
for (auto c : line_num_str) { checksum ^= c; }
checksum ^= ' ';
for (auto c : line) { checksum ^= c; }
return (boost::format("N%1% %2%*%3%\n") % line_num_str % line % checksum).str();
}
} // namespace Utils
} // namespace Slic3r

View file

@ -1,31 +1,80 @@
#ifndef slic3r_GUI_Utils_Serial_hpp_
#define slic3r_GUI_Utils_Serial_hpp_
#include <memory>
#include <vector>
#include <string>
#include <vector>
#include <boost/system/error_code.hpp>
#include <boost/asio.hpp>
namespace Slic3r {
namespace Utils {
struct SerialPortInfo {
std::string port;
std::string hardware_id;
unsigned id_vendor = -1;
unsigned id_product = -1;
std::string friendly_name;
bool is_printer = false;
bool is_printer = false;
bool id_match(unsigned id_vendor, unsigned id_product) const { return id_vendor == this->id_vendor && id_product == this->id_product; }
};
inline bool operator==(const SerialPortInfo &sp1, const SerialPortInfo &sp2)
inline bool operator==(const SerialPortInfo &sp1, const SerialPortInfo &sp2)
{
return sp1.port == sp2.port &&
sp1.hardware_id == sp2.hardware_id &&
sp1.is_printer == sp2.is_printer;
return
sp1.port == sp2.port &&
sp1.id_vendor == sp2.id_vendor &&
sp1.id_product == sp2.id_product &&
sp1.is_printer == sp2.is_printer;
}
extern std::vector<std::string> scan_serial_ports();
extern std::vector<SerialPortInfo> scan_serial_ports_extended();
class Serial : public boost::asio::serial_port
{
public:
Serial(boost::asio::io_service &io_service);
Serial(boost::asio::io_service &io_service, const std::string &name, unsigned baud_rate);
Serial(const Serial &) = delete;
Serial &operator=(const Serial &) = delete;
~Serial();
void set_baud_rate(unsigned baud_rate);
void set_DTR(bool on);
// Resets the line number both internally as well as with the firmware using M110
void reset_line_num();
// 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
void printer_setup();
// Write data from a string
size_t write_string(const std::string &str);
bool printer_ready_wait(unsigned retries, unsigned timeout);
// Write Marlin-formatted line, with a line number and a checksum
size_t printer_write_line(const std::string &line, unsigned line_num);
// Same as above, but with internally-managed line number
size_t printer_write_line(const std::string &line);
// Toggles DTR to reset the printer
void printer_reset();
// Formats a line Marlin-style, ie. with a sequential number and a checksum
static std::string printer_format_line(const std::string &line, unsigned line_num);
private:
unsigned m_line_num = 0;
};
} // Utils
} // Slic3r

View file

@ -430,6 +430,13 @@ enable_force_zoom_to_bed(canvas, enable)
CODE:
_3DScene::enable_force_zoom_to_bed((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
void
enable_dynamic_background(canvas, enable)
SV *canvas;
bool enable;
CODE:
_3DScene::enable_dynamic_background((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), enable);
void
allow_multisample(canvas, allow)
SV *canvas;
@ -657,27 +664,6 @@ reload_scene(canvas, force)
CODE:
_3DScene::reload_scene((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), force);
void
load_print_toolpaths(canvas)
SV *canvas;
CODE:
_3DScene::load_print_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"));
void
load_print_object_toolpaths(canvas, print_object, tool_colors)
SV *canvas;
PrintObject *print_object;
std::vector<std::string> tool_colors;
CODE:
_3DScene::load_print_object_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), print_object, tool_colors);
void
load_wipe_tower_toolpaths(canvas, tool_colors)
SV *canvas;
std::vector<std::string> tool_colors;
CODE:
_3DScene::load_wipe_tower_toolpaths((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), tool_colors);
void
load_gcode_preview(canvas, preview_data, str_tool_colors)
SV *canvas;
@ -685,5 +671,12 @@ load_gcode_preview(canvas, preview_data, str_tool_colors)
std::vector<std::string> str_tool_colors;
CODE:
_3DScene::load_gcode_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), preview_data, str_tool_colors);
void
load_preview(canvas, str_tool_colors)
SV *canvas;
std::vector<std::string> str_tool_colors;
CODE:
_3DScene::load_preview((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), str_tool_colors);
%}