Ported the between_objects_gcode custom G-code blocks,
thanks @lordofhyphens, https://github.com/alexrj/Slic3r/pull/3275 Improved handling of custom G-code blocks: Slic3r will try to extract the target extruder and bed temperatures from the custom G-code blocks.
This commit is contained in:
parent
f58b217369
commit
672194b475
8 changed files with 207 additions and 100 deletions
|
@ -1467,6 +1467,15 @@ sub build {
|
|||
$option->height(150);
|
||||
$optgroup->append_single_option_line($option);
|
||||
}
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Between objects G-code (for sequential printing)',
|
||||
label_width => 0,
|
||||
);
|
||||
my $option = $optgroup->get_option('between_objects_gcode');
|
||||
$option->full_width(1);
|
||||
$option->height(150);
|
||||
$optgroup->append_single_option_line($option);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use Test::More tests => 40;
|
||||
use Test::More tests => 41;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
|
@ -210,4 +210,13 @@ use Slic3r::Test;
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('complete_objects', 1);
|
||||
$config->set('between_objects_gcode', '_MY_CUSTOM_GCODE_');
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 3);
|
||||
my $gcode = Slic3r::Test::gcode($print);
|
||||
is scalar(() = $gcode =~ /^_MY_CUSTOM_GCODE_/gm), 2, 'between_objects_gcode is applied correctly';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
|
|
@ -538,29 +538,23 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||
// Disable fan.
|
||||
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
|
||||
write(file, m_writer.set_fan(0, true));
|
||||
|
||||
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
|
||||
{
|
||||
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
|
||||
// the custom start G-code emited these.
|
||||
//FIXME Should one parse the custom G-code to initialize the "current" bed temp state at m_writer?
|
||||
std::string gcode = m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id), true);
|
||||
if (boost::ifind_first(print.config.start_gcode.value, std::string("M140")).empty() &&
|
||||
boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty())
|
||||
write(file, gcode);
|
||||
}
|
||||
|
||||
// Set extruder(s) temperature before and after start G-code.
|
||||
this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, false);
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
||||
m_placeholder_parser.set("initial_extruder", initial_extruder_id);
|
||||
m_placeholder_parser.set("current_extruder", initial_extruder_id);
|
||||
writeln(file, m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id));
|
||||
std::string start_gcode = m_placeholder_parser.process(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.
|
||||
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
|
||||
// Set extruder(s) temperature before and after start G-code.
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
|
||||
// Write the custom start G-code
|
||||
writeln(file, start_gcode);
|
||||
// Process filament-specific gcode in extruder order.
|
||||
for (const std::string &start_gcode : print.config.start_filament_gcode.values)
|
||||
writeln(file, m_placeholder_parser.process(start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front())));
|
||||
this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, true);
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||
|
||||
// Set other general things.
|
||||
write(file, this->preamble());
|
||||
|
@ -650,9 +644,11 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||
// Ff we are printing the bottom layer of an object, and we have already finished
|
||||
// another one, set first layer temperatures. This happens before the Z move
|
||||
// is triggered, so machine has more time to reach such temperatures.
|
||||
write(file, m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id)));
|
||||
// Set first layer extruder.
|
||||
this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, false);
|
||||
std::string between_objects_gcode = m_placeholder_parser.process(print.config.between_objects_gcode.value, initial_extruder_id);
|
||||
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
||||
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
|
||||
this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
|
||||
writeln(file, between_objects_gcode);
|
||||
}
|
||||
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
|
||||
m_cooling_buffer->reset();
|
||||
|
@ -774,15 +770,96 @@ bool GCode::_do_export(Print &print, FILE *file)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Parse the custom G-code, try to find mcode_set_temp_dont_wait and mcode_set_temp_and_wait inside the custom G-code.
|
||||
// Returns true if one of the temp commands are found, and try to parse the target temperature value into temp_out.
|
||||
static bool custom_gcode_sets_temperature(const std::string &gcode, const int mcode_set_temp_dont_wait, const int mcode_set_temp_and_wait, int &temp_out)
|
||||
{
|
||||
temp_out = -1;
|
||||
if (gcode.empty())
|
||||
return false;
|
||||
|
||||
const char *ptr = gcode.data();
|
||||
bool temp_set_by_gcode = false;
|
||||
while (*ptr != 0) {
|
||||
// Skip whitespaces.
|
||||
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
||||
if (*ptr == 'M') {
|
||||
// Line starts with 'M'. It is a machine command.
|
||||
++ ptr;
|
||||
// Parse the M code value.
|
||||
char *endptr = nullptr;
|
||||
int mcode = int(strtol(ptr, &endptr, 10));
|
||||
if (endptr != nullptr && endptr != ptr && (mcode == mcode_set_temp_dont_wait || mcode == mcode_set_temp_and_wait)) {
|
||||
// M104/M109 or M140/M190 found.
|
||||
ptr = endptr;
|
||||
// Let the caller know that the custom G-code sets the temperature.
|
||||
temp_set_by_gcode = true;
|
||||
// Now try to parse the temperature value.
|
||||
// While not at the end of the line:
|
||||
while (strchr(";\r\n\0", *ptr) == nullptr) {
|
||||
// Skip whitespaces.
|
||||
for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
||||
if (*ptr == 'S') {
|
||||
// Skip whitespaces.
|
||||
for (++ ptr; *ptr == ' ' || *ptr == '\t'; ++ ptr);
|
||||
// Parse an int.
|
||||
endptr = nullptr;
|
||||
long temp_parsed = strtol(ptr, &endptr, 10);
|
||||
if (endptr > ptr) {
|
||||
ptr = endptr;
|
||||
temp_out = temp_parsed;
|
||||
}
|
||||
} else {
|
||||
// Skip this word.
|
||||
for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Skip the rest of the line.
|
||||
for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
|
||||
// Skip the end of line indicators.
|
||||
for (; *ptr == '\r' || *ptr == '\n'; ++ ptr);
|
||||
}
|
||||
return temp_set_by_gcode;
|
||||
}
|
||||
|
||||
// Write 1st layer bed temperatures into the G-code.
|
||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||
// M140 - Set Extruder Temperature
|
||||
// M190 - Set Extruder Temperature and Wait
|
||||
void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||
{
|
||||
// Initial bed temperature based on the first extruder.
|
||||
int temp = print.config.first_layer_bed_temperature.get_at(first_printing_extruder_id);
|
||||
// Is the bed temperature set by the provided custom G-code?
|
||||
int temp_by_gcode = -1;
|
||||
bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode);
|
||||
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
temp = temp_by_gcode;
|
||||
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
|
||||
// the custom start G-code emited these.
|
||||
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
|
||||
if (! temp_by_gcode)
|
||||
write(file, set_temp_gcode);
|
||||
}
|
||||
|
||||
// Write 1st layer extruder temperatures into the G-code.
|
||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||
// FIXME this does not work correctly for multi-extruder, single heater configuration as it emits multiple preheat commands for the same heater.
|
||||
// M104 - Set Extruder Temperature
|
||||
// M109 - Set Extruder Temperature and Wait
|
||||
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait)
|
||||
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||
{
|
||||
if (boost::ifind_first(print.config.start_gcode.value, std::string("M104")).empty() &&
|
||||
boost::ifind_first(print.config.start_gcode.value, std::string("M109")).empty()) {
|
||||
// Is the bed temperature set by the provided custom G-code?
|
||||
int temp_by_gcode = -1;
|
||||
if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) {
|
||||
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
|
||||
int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
|
||||
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
temp = temp_by_gcode;
|
||||
m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id);
|
||||
} else {
|
||||
// Custom G-code does not set the extruder temperature. Do it now.
|
||||
if (print.config.single_extruder_multi_material.value) {
|
||||
// Set temperature of the first printing extruder only.
|
||||
int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
|
||||
|
|
|
@ -268,7 +268,8 @@ protected:
|
|||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
|
||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
||||
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||
// this flag triggers first layer speeds
|
||||
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
|
||||
|
||||
|
|
|
@ -81,80 +81,80 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|
||||
// Cache the plenty of parameters, which influence the G-code generator only,
|
||||
// or they are only notes not influencing the generated G-code.
|
||||
static std::unordered_set<std::string> steps_ignore;
|
||||
if (steps_ignore.empty()) {
|
||||
steps_ignore.insert("avoid_crossing_perimeters");
|
||||
steps_ignore.insert("bed_shape");
|
||||
steps_ignore.insert("bed_temperature");
|
||||
steps_ignore.insert("before_layer_gcode");
|
||||
steps_ignore.insert("bridge_acceleration");
|
||||
steps_ignore.insert("bridge_fan_speed");
|
||||
steps_ignore.insert("cooling");
|
||||
steps_ignore.insert("default_acceleration");
|
||||
steps_ignore.insert("deretract_speed");
|
||||
steps_ignore.insert("disable_fan_first_layers");
|
||||
steps_ignore.insert("duplicate_distance");
|
||||
steps_ignore.insert("end_gcode");
|
||||
steps_ignore.insert("end_filament_gcode");
|
||||
steps_ignore.insert("extrusion_axis");
|
||||
steps_ignore.insert("extruder_clearance_height");
|
||||
steps_ignore.insert("extruder_clearance_radius");
|
||||
steps_ignore.insert("extruder_colour");
|
||||
steps_ignore.insert("extruder_offset");
|
||||
steps_ignore.insert("extrusion_multiplier");
|
||||
steps_ignore.insert("fan_always_on");
|
||||
steps_ignore.insert("fan_below_layer_time");
|
||||
steps_ignore.insert("filament_colour");
|
||||
steps_ignore.insert("filament_diameter");
|
||||
steps_ignore.insert("filament_density");
|
||||
steps_ignore.insert("filament_notes");
|
||||
steps_ignore.insert("filament_cost");
|
||||
steps_ignore.insert("filament_max_volumetric_speed");
|
||||
steps_ignore.insert("first_layer_acceleration");
|
||||
steps_ignore.insert("first_layer_bed_temperature");
|
||||
steps_ignore.insert("first_layer_speed");
|
||||
steps_ignore.insert("gcode_comments");
|
||||
steps_ignore.insert("gcode_flavor");
|
||||
steps_ignore.insert("infill_acceleration");
|
||||
steps_ignore.insert("infill_first");
|
||||
steps_ignore.insert("layer_gcode");
|
||||
steps_ignore.insert("min_fan_speed");
|
||||
steps_ignore.insert("max_fan_speed");
|
||||
steps_ignore.insert("min_print_speed");
|
||||
steps_ignore.insert("max_print_speed");
|
||||
steps_ignore.insert("max_volumetric_speed");
|
||||
steps_ignore.insert("max_volumetric_extrusion_rate_slope_positive");
|
||||
steps_ignore.insert("max_volumetric_extrusion_rate_slope_negative");
|
||||
steps_ignore.insert("notes");
|
||||
steps_ignore.insert("only_retract_when_crossing_perimeters");
|
||||
steps_ignore.insert("output_filename_format");
|
||||
steps_ignore.insert("perimeter_acceleration");
|
||||
steps_ignore.insert("post_process");
|
||||
steps_ignore.insert("printer_notes");
|
||||
steps_ignore.insert("retract_before_travel");
|
||||
steps_ignore.insert("retract_before_wipe");
|
||||
steps_ignore.insert("retract_layer_change");
|
||||
steps_ignore.insert("retract_length");
|
||||
steps_ignore.insert("retract_length_toolchange");
|
||||
steps_ignore.insert("retract_lift");
|
||||
steps_ignore.insert("retract_lift_above");
|
||||
steps_ignore.insert("retract_lift_below");
|
||||
steps_ignore.insert("retract_restart_extra");
|
||||
steps_ignore.insert("retract_restart_extra_toolchange");
|
||||
steps_ignore.insert("retract_speed");
|
||||
steps_ignore.insert("slowdown_below_layer_time");
|
||||
steps_ignore.insert("standby_temperature_delta");
|
||||
steps_ignore.insert("start_gcode");
|
||||
steps_ignore.insert("start_filament_gcode");
|
||||
steps_ignore.insert("toolchange_gcode");
|
||||
steps_ignore.insert("threads");
|
||||
steps_ignore.insert("travel_speed");
|
||||
steps_ignore.insert("use_firmware_retraction");
|
||||
steps_ignore.insert("use_relative_e_distances");
|
||||
steps_ignore.insert("use_volumetric_e");
|
||||
steps_ignore.insert("variable_layer_height");
|
||||
steps_ignore.insert("wipe");
|
||||
}
|
||||
static std::unordered_set<std::string> steps_ignore = {
|
||||
"avoid_crossing_perimeters",
|
||||
"bed_shape",
|
||||
"bed_temperature",
|
||||
"before_layer_gcode",
|
||||
"between_objects_gcode",
|
||||
"bridge_acceleration",
|
||||
"bridge_fan_speed",
|
||||
"cooling",
|
||||
"default_acceleration",
|
||||
"deretract_speed",
|
||||
"disable_fan_first_layers",
|
||||
"duplicate_distance",
|
||||
"end_gcode",
|
||||
"end_filament_gcode",
|
||||
"extrusion_axis",
|
||||
"extruder_clearance_height",
|
||||
"extruder_clearance_radius",
|
||||
"extruder_colour",
|
||||
"extruder_offset",
|
||||
"extrusion_multiplier",
|
||||
"fan_always_on",
|
||||
"fan_below_layer_time",
|
||||
"filament_colour",
|
||||
"filament_diameter",
|
||||
"filament_density",
|
||||
"filament_notes",
|
||||
"filament_cost",
|
||||
"filament_max_volumetric_speed",
|
||||
"first_layer_acceleration",
|
||||
"first_layer_bed_temperature",
|
||||
"first_layer_speed",
|
||||
"gcode_comments",
|
||||
"gcode_flavor",
|
||||
"infill_acceleration",
|
||||
"infill_first",
|
||||
"layer_gcode",
|
||||
"min_fan_speed",
|
||||
"max_fan_speed",
|
||||
"min_print_speed",
|
||||
"max_print_speed",
|
||||
"max_volumetric_speed",
|
||||
"max_volumetric_extrusion_rate_slope_positive",
|
||||
"max_volumetric_extrusion_rate_slope_negative",
|
||||
"notes",
|
||||
"only_retract_when_crossing_perimeters",
|
||||
"output_filename_format",
|
||||
"perimeter_acceleration",
|
||||
"post_process",
|
||||
"printer_notes",
|
||||
"retract_before_travel",
|
||||
"retract_before_wipe",
|
||||
"retract_layer_change",
|
||||
"retract_length",
|
||||
"retract_length_toolchange",
|
||||
"retract_lift",
|
||||
"retract_lift_above",
|
||||
"retract_lift_below",
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_speed",
|
||||
"slowdown_below_layer_time",
|
||||
"standby_temperature_delta",
|
||||
"start_gcode",
|
||||
"start_filament_gcode",
|
||||
"toolchange_gcode",
|
||||
"threads",
|
||||
"travel_speed",
|
||||
"use_firmware_retraction",
|
||||
"use_relative_e_distances",
|
||||
"use_volumetric_e",
|
||||
"variable_layer_height",
|
||||
"wipe"
|
||||
};
|
||||
|
||||
std::vector<PrintStep> steps;
|
||||
std::vector<PrintObjectStep> osteps;
|
||||
|
|
|
@ -48,6 +48,15 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->height = 50;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("between_objects_gcode", coString);
|
||||
def->label = "Between objects G-code";
|
||||
def->tooltip = "This code is inserted between objects when using sequential printing. By default extruder and bed temperature are reset using non-wait command; however if M104, M109, M140 or M190 are detected in this custom code, Slic3r will not add temperature commands. Note that you can use placeholder variables for all Slic3r settings, so you can put a \"M109 S[first_layer_temperature]\" command wherever you want.";
|
||||
def->cli = "between-objects-gcode=s";
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 120;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("bottom_solid_layers", coInt);
|
||||
def->label = "Bottom";
|
||||
def->category = "Layers and Perimeters";
|
||||
|
|
|
@ -452,6 +452,7 @@ class GCodeConfig : public StaticPrintConfig
|
|||
STATIC_PRINT_CONFIG_CACHE(GCodeConfig)
|
||||
public:
|
||||
ConfigOptionString before_layer_gcode;
|
||||
ConfigOptionString between_objects_gcode;
|
||||
ConfigOptionFloats deretract_speed;
|
||||
ConfigOptionString end_gcode;
|
||||
ConfigOptionStrings end_filament_gcode;
|
||||
|
@ -500,6 +501,7 @@ protected:
|
|||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||
{
|
||||
OPT_PTR(before_layer_gcode);
|
||||
OPT_PTR(between_objects_gcode);
|
||||
OPT_PTR(deretract_speed);
|
||||
OPT_PTR(end_gcode);
|
||||
OPT_PTR(end_filament_gcode);
|
||||
|
|
|
@ -204,8 +204,8 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
s_opts = {
|
||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"octoprint_host", "octoprint_apikey", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"printer_notes"
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_notes"
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue