WIP to G-code export parallelization through pipelining:
New class GCodeOutputStream as a G-code consumer. In the following steps the GCodeOutputStream will be pipelined with GCodeProcessor.
This commit is contained in:
parent
32733b7db9
commit
b5a007a683
@ -744,27 +744,27 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
|
|||||||
std::string path_tmp(path);
|
std::string path_tmp(path);
|
||||||
path_tmp += ".tmp";
|
path_tmp += ".tmp";
|
||||||
|
|
||||||
FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb");
|
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"));
|
||||||
if (file == nullptr)
|
if (! file.is_open())
|
||||||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_placeholder_parser_failed_templates.clear();
|
m_placeholder_parser_failed_templates.clear();
|
||||||
this->_do_export(*print, file, thumbnail_cb);
|
this->_do_export(*print, file, thumbnail_cb);
|
||||||
fflush(file);
|
file.flush();
|
||||||
if (ferror(file)) {
|
if (file.is_error()) {
|
||||||
fclose(file);
|
file.close();
|
||||||
boost::nowide::remove(path_tmp.c_str());
|
boost::nowide::remove(path_tmp.c_str());
|
||||||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
|
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
|
||||||
}
|
}
|
||||||
} catch (std::exception & /* ex */) {
|
} catch (std::exception & /* ex */) {
|
||||||
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
|
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
|
||||||
// Close and remove the file.
|
// Close and remove the file.
|
||||||
fclose(file);
|
file.close();
|
||||||
boost::nowide::remove(path_tmp.c_str());
|
boost::nowide::remove(path_tmp.c_str());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
fclose(file);
|
file.close();
|
||||||
|
|
||||||
if (! m_placeholder_parser_failed_templates.empty()) {
|
if (! m_placeholder_parser_failed_templates.empty()) {
|
||||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||||
@ -1046,7 +1046,7 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
|
|||||||
return instances;
|
return instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||||
{
|
{
|
||||||
PROFILE_FUNC();
|
PROFILE_FUNC();
|
||||||
|
|
||||||
@ -1111,10 +1111,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||||
|
|
||||||
// Write information on the generator.
|
// Write information on the generator.
|
||||||
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||||
|
|
||||||
DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
|
DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
|
||||||
[this, file](const char* sz) { this->_write(file, sz); },
|
[&file](const char* sz) { file.write(sz); },
|
||||||
[&print]() { print.throw_if_canceled(); });
|
[&print]() { print.throw_if_canceled(); });
|
||||||
|
|
||||||
// Write notes (content of the Print Settings tab -> Notes)
|
// Write notes (content of the Print Settings tab -> Notes)
|
||||||
@ -1125,10 +1125,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
// Remove the trailing '\r' from the '\r\n' sequence.
|
// Remove the trailing '\r' from the '\r\n' sequence.
|
||||||
if (! line.empty() && line.back() == '\r')
|
if (! line.empty() && line.back() == '\r')
|
||||||
line.pop_back();
|
line.pop_back();
|
||||||
_write_format(file, "; %s\n", line.c_str());
|
file.write_format("; %s\n", line.c_str());
|
||||||
}
|
}
|
||||||
if (! lines.empty())
|
if (! lines.empty())
|
||||||
_write(file, "\n");
|
file.write("\n");
|
||||||
}
|
}
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
@ -1139,22 +1139,22 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
const double first_layer_height = print.config().first_layer_height.value;
|
const double first_layer_height = print.config().first_layer_height.value;
|
||||||
for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
|
for (size_t region_id = 0; region_id < print.num_print_regions(); ++ region_id) {
|
||||||
const PrintRegion ®ion = print.get_print_region(region_id);
|
const PrintRegion ®ion = print.get_print_region(region_id);
|
||||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
|
file.write_format("; external perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frExternalPerimeter, layer_height).width());
|
||||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
|
file.write_format("; perimeters extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, layer_height).width());
|
||||||
_write_format(file, "; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
|
file.write_format("; infill extrusion width = %.2fmm\n", region.flow(*first_object, frInfill, layer_height).width());
|
||||||
_write_format(file, "; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
|
file.write_format("; solid infill extrusion width = %.2fmm\n", region.flow(*first_object, frSolidInfill, layer_height).width());
|
||||||
_write_format(file, "; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
|
file.write_format("; top infill extrusion width = %.2fmm\n", region.flow(*first_object, frTopSolidInfill, layer_height).width());
|
||||||
if (print.has_support_material())
|
if (print.has_support_material())
|
||||||
_write_format(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
file.write_format("; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width());
|
||||||
if (print.config().first_layer_extrusion_width.value > 0)
|
if (print.config().first_layer_extrusion_width.value > 0)
|
||||||
_write_format(file, "; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
|
file.write_format("; first layer extrusion width = %.2fmm\n", region.flow(*first_object, frPerimeter, first_layer_height, true).width());
|
||||||
_write_format(file, "\n");
|
file.write_format("\n");
|
||||||
}
|
}
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
// adds tags for time estimators
|
// adds tags for time estimators
|
||||||
if (print.config().remaining_times.value)
|
if (print.config().remaining_times.value)
|
||||||
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
|
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
|
||||||
|
|
||||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||||
m_placeholder_parser = print.placeholder_parser();
|
m_placeholder_parser = print.placeholder_parser();
|
||||||
@ -1218,7 +1218,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
|
|
||||||
// Disable fan.
|
// Disable fan.
|
||||||
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id))
|
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));
|
file.write(m_writer.set_fan(0, true));
|
||||||
|
|
||||||
// Let the start-up script prime the 1st printing tool.
|
// Let the start-up script prime the 1st printing tool.
|
||||||
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
||||||
@ -1261,10 +1261,10 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
|
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
|
||||||
|
|
||||||
// adds tag for processor
|
// adds tag for processor
|
||||||
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
|
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
|
||||||
|
|
||||||
// Write the custom start G-code
|
// Write the custom start G-code
|
||||||
_writeln(file, start_gcode);
|
file.writeln(start_gcode);
|
||||||
|
|
||||||
// Process filament-specific gcode.
|
// Process filament-specific gcode.
|
||||||
/* if (has_wipe_tower) {
|
/* if (has_wipe_tower) {
|
||||||
@ -1272,14 +1272,14 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
} else {
|
} else {
|
||||||
DynamicConfig config;
|
DynamicConfig config;
|
||||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(initial_extruder_id)));
|
||||||
_writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
file.writeln(this->placeholder_parser_process("start_filament_gcode", print.config().start_filament_gcode.values[initial_extruder_id], initial_extruder_id, &config));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
// Set other general things.
|
// Set other general things.
|
||||||
_write(file, this->preamble());
|
file.write(this->preamble());
|
||||||
|
|
||||||
// Calculate wiping points if needed
|
// Calculate wiping points if needed
|
||||||
DoExport::init_ooze_prevention(print, m_ooze_prevention);
|
DoExport::init_ooze_prevention(print, m_ooze_prevention);
|
||||||
@ -1291,7 +1291,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
|
if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
|
||||||
// Set initial extruder only after custom start G-code.
|
// Set initial extruder only after custom start G-code.
|
||||||
// Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed.
|
// Ugly hack: Do not set the initial extruder if the extruder is primed using the MMU priming towers at the edge of the print bed.
|
||||||
_write(file, this->set_extruder(initial_extruder_id, 0.));
|
file.write(this->set_extruder(initial_extruder_id, 0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do all objects for each layer.
|
// Do all objects for each layer.
|
||||||
@ -1317,8 +1317,8 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
|
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
|
||||||
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
|
m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer
|
||||||
m_avoid_crossing_perimeters.use_external_mp_once();
|
m_avoid_crossing_perimeters.use_external_mp_once();
|
||||||
_write(file, this->retract());
|
file.write(this->retract());
|
||||||
_write(file, this->travel_to(Point(0, 0), erNone, "move to origin position for next object"));
|
file.write(this->travel_to(Point(0, 0), erNone, "move to origin position for next object"));
|
||||||
m_enable_cooling_markers = true;
|
m_enable_cooling_markers = true;
|
||||||
// Disable motion planner when traveling to first object point.
|
// Disable motion planner when traveling to first object point.
|
||||||
m_avoid_crossing_perimeters.disable_once();
|
m_avoid_crossing_perimeters.disable_once();
|
||||||
@ -1330,7 +1330,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
// 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_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);
|
this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
|
||||||
_writeln(file, between_objects_gcode);
|
file.writeln(between_objects_gcode);
|
||||||
}
|
}
|
||||||
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
|
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
|
||||||
m_cooling_buffer->reset();
|
m_cooling_buffer->reset();
|
||||||
@ -1346,7 +1346,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
}
|
}
|
||||||
#ifdef HAS_PRESSURE_EQUALIZER
|
#ifdef HAS_PRESSURE_EQUALIZER
|
||||||
if (m_pressure_equalizer)
|
if (m_pressure_equalizer)
|
||||||
_write(file, m_pressure_equalizer->process("", true));
|
file.write(m_pressure_equalizer->process("", true));
|
||||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||||
++ finished_objects;
|
++ finished_objects;
|
||||||
// Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
|
// Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed.
|
||||||
@ -1361,9 +1361,9 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
// Prusa Multi-Material wipe tower.
|
// Prusa Multi-Material wipe tower.
|
||||||
if (has_wipe_tower && ! layers_to_print.empty()) {
|
if (has_wipe_tower && ! layers_to_print.empty()) {
|
||||||
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
|
m_wipe_tower.reset(new WipeTowerIntegration(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()));
|
||||||
_write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
|
file.write(m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height"));
|
||||||
if (print.config().single_extruder_multi_material_priming) {
|
if (print.config().single_extruder_multi_material_priming) {
|
||||||
_write(file, m_wipe_tower->prime(*this));
|
file.write(m_wipe_tower->prime(*this));
|
||||||
// Verify, whether the print overaps the priming extrusions.
|
// Verify, whether the print overaps the priming extrusions.
|
||||||
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
|
BoundingBoxf bbox_print(get_print_extrusions_extents(print));
|
||||||
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
|
coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON;
|
||||||
@ -1375,15 +1375,15 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
bool overlap = bbox_prime.overlap(bbox_print);
|
bool overlap = bbox_prime.overlap(bbox_print);
|
||||||
|
|
||||||
if (print.config().gcode_flavor == gcfMarlinLegacy || print.config().gcode_flavor == gcfMarlinFirmware) {
|
if (print.config().gcode_flavor == gcfMarlinLegacy || print.config().gcode_flavor == gcfMarlinFirmware) {
|
||||||
_write(file, this->retract());
|
file.write(this->retract());
|
||||||
_write(file, "M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
|
file.write("M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
|
||||||
if (overlap) {
|
if (overlap) {
|
||||||
// Wait for the user to remove the priming extrusions.
|
// Wait for the user to remove the priming extrusions.
|
||||||
_write(file, "M1 Remove priming towers and click button.\n");
|
file.write("M1 Remove priming towers and click button.\n");
|
||||||
} else {
|
} else {
|
||||||
// Just wait for a bit to let the user check, that the priming succeeded.
|
// Just wait for a bit to let the user check, that the priming succeeded.
|
||||||
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
//TODO Add a message explaining what the printer is waiting for. This needs a firmware fix.
|
||||||
_write(file, "M1 S10\n");
|
file.write("M1 S10\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is not Marlin, M1 command is probably not supported.
|
// This is not Marlin, M1 command is probably not supported.
|
||||||
@ -1410,19 +1410,19 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
}
|
}
|
||||||
#ifdef HAS_PRESSURE_EQUALIZER
|
#ifdef HAS_PRESSURE_EQUALIZER
|
||||||
if (m_pressure_equalizer)
|
if (m_pressure_equalizer)
|
||||||
_write(file, m_pressure_equalizer->process("", true));
|
file.write(m_pressure_equalizer->process("", true));
|
||||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||||
if (m_wipe_tower)
|
if (m_wipe_tower)
|
||||||
// Purge the extruder, pull out the active filament.
|
// Purge the extruder, pull out the active filament.
|
||||||
_write(file, m_wipe_tower->finalize(*this));
|
file.write(m_wipe_tower->finalize(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write end commands to file.
|
// Write end commands to file.
|
||||||
_write(file, this->retract());
|
file.write(this->retract());
|
||||||
_write(file, m_writer.set_fan(false));
|
file.write(m_writer.set_fan(false));
|
||||||
|
|
||||||
// adds tag for processor
|
// adds tag for processor
|
||||||
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
|
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
|
||||||
|
|
||||||
// Process filament-specific gcode in extruder order.
|
// Process filament-specific gcode in extruder order.
|
||||||
{
|
{
|
||||||
@ -1434,48 +1434,48 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||||||
// Process the end_filament_gcode for the active filament only.
|
// Process the end_filament_gcode for the active filament only.
|
||||||
int extruder_id = m_writer.extruder()->id();
|
int extruder_id = m_writer.extruder()->id();
|
||||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
|
file.writeln(this->placeholder_parser_process("end_filament_gcode", print.config().end_filament_gcode.get_at(extruder_id), extruder_id, &config));
|
||||||
} else {
|
} else {
|
||||||
for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
|
for (const std::string &end_gcode : print.config().end_filament_gcode.values) {
|
||||||
int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
|
int extruder_id = (unsigned int)(&end_gcode - &print.config().end_filament_gcode.values.front());
|
||||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
config.set_key_value("filament_extruder_id", new ConfigOptionInt(extruder_id));
|
||||||
_writeln(file, this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
|
file.writeln(this->placeholder_parser_process("end_filament_gcode", end_gcode, extruder_id, &config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_writeln(file, this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
|
file.writeln(this->placeholder_parser_process("end_gcode", print.config().end_gcode, m_writer.extruder()->id(), &config));
|
||||||
}
|
}
|
||||||
_write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
|
file.write(m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
|
||||||
_write(file, m_writer.postamble());
|
file.write(m_writer.postamble());
|
||||||
|
|
||||||
// adds tags for time estimators
|
// adds tags for time estimators
|
||||||
if (print.config().remaining_times.value)
|
if (print.config().remaining_times.value)
|
||||||
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
|
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
|
||||||
|
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
// Get filament stats.
|
// Get filament stats.
|
||||||
_write(file, DoExport::update_print_stats_and_format_filament_stats(
|
file.write(DoExport::update_print_stats_and_format_filament_stats(
|
||||||
// Const inputs
|
// Const inputs
|
||||||
has_wipe_tower, print.wipe_tower_data(),
|
has_wipe_tower, print.wipe_tower_data(),
|
||||||
m_writer.extruders(),
|
m_writer.extruders(),
|
||||||
// Modifies
|
// Modifies
|
||||||
print.m_print_statistics));
|
print.m_print_statistics));
|
||||||
_write(file, "\n");
|
file.write("\n");
|
||||||
_write_format(file, "; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
|
file.write_format("; total filament used [g] = %.2lf\n", print.m_print_statistics.total_weight);
|
||||||
_write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
|
file.write_format("; total filament cost = %.2lf\n", print.m_print_statistics.total_cost);
|
||||||
if (print.m_print_statistics.total_toolchanges > 0)
|
if (print.m_print_statistics.total_toolchanges > 0)
|
||||||
_write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
file.write_format("; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
|
||||||
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
|
||||||
|
|
||||||
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
|
// Append full config, delimited by two 'phony' configuration keys prusaslicer_config = begin and prusaslicer_config = end.
|
||||||
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
|
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of PrusaSlicer G-code viewer.
|
||||||
{
|
{
|
||||||
_write(file, "\n; prusaslicer_config = begin\n");
|
file.write("\n; prusaslicer_config = begin\n");
|
||||||
std::string full_config;
|
std::string full_config;
|
||||||
append_full_config(print, full_config);
|
append_full_config(print, full_config);
|
||||||
if (!full_config.empty())
|
if (!full_config.empty())
|
||||||
_write(file, full_config);
|
file.write(full_config);
|
||||||
_write(file, "; prusaslicer_config = end\n");
|
file.write("; prusaslicer_config = end\n");
|
||||||
}
|
}
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
}
|
}
|
||||||
@ -1565,16 +1565,16 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
|
|||||||
|
|
||||||
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
|
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
|
||||||
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
|
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
|
||||||
void GCode::print_machine_envelope(FILE *file, Print &print)
|
void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
|
||||||
{
|
{
|
||||||
if ((print.config().gcode_flavor.value == gcfMarlinLegacy || print.config().gcode_flavor.value == gcfMarlinFirmware)
|
if ((print.config().gcode_flavor.value == gcfMarlinLegacy || print.config().gcode_flavor.value == gcfMarlinFirmware)
|
||||||
&& print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
|
&& print.config().machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) {
|
||||||
fprintf(file, "M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
|
file.write_format("M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
|
||||||
int(print.config().machine_max_acceleration_x.values.front() + 0.5),
|
int(print.config().machine_max_acceleration_x.values.front() + 0.5),
|
||||||
int(print.config().machine_max_acceleration_y.values.front() + 0.5),
|
int(print.config().machine_max_acceleration_y.values.front() + 0.5),
|
||||||
int(print.config().machine_max_acceleration_z.values.front() + 0.5),
|
int(print.config().machine_max_acceleration_z.values.front() + 0.5),
|
||||||
int(print.config().machine_max_acceleration_e.values.front() + 0.5));
|
int(print.config().machine_max_acceleration_e.values.front() + 0.5));
|
||||||
fprintf(file, "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n",
|
file.write_format("M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n",
|
||||||
int(print.config().machine_max_feedrate_x.values.front() + 0.5),
|
int(print.config().machine_max_feedrate_x.values.front() + 0.5),
|
||||||
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
|
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
|
||||||
int(print.config().machine_max_feedrate_z.values.front() + 0.5),
|
int(print.config().machine_max_feedrate_z.values.front() + 0.5),
|
||||||
@ -1587,18 +1587,18 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
|
|||||||
int travel_acc = print.config().gcode_flavor == gcfMarlinLegacy
|
int travel_acc = print.config().gcode_flavor == gcfMarlinLegacy
|
||||||
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
|
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
|
||||||
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
|
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
|
||||||
fprintf(file, "M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
|
file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
|
||||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
||||||
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
|
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
|
||||||
travel_acc);
|
travel_acc);
|
||||||
|
|
||||||
assert(is_decimal_separator_point());
|
assert(is_decimal_separator_point());
|
||||||
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
|
file.write_format("M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
|
||||||
print.config().machine_max_jerk_x.values.front(),
|
print.config().machine_max_jerk_x.values.front(),
|
||||||
print.config().machine_max_jerk_y.values.front(),
|
print.config().machine_max_jerk_y.values.front(),
|
||||||
print.config().machine_max_jerk_z.values.front(),
|
print.config().machine_max_jerk_z.values.front(),
|
||||||
print.config().machine_max_jerk_e.values.front());
|
print.config().machine_max_jerk_e.values.front());
|
||||||
fprintf(file, "M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
|
file.write_format("M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
|
||||||
int(print.config().machine_min_extruding_rate.values.front() + 0.5),
|
int(print.config().machine_min_extruding_rate.values.front() + 0.5),
|
||||||
int(print.config().machine_min_travel_rate.values.front() + 0.5));
|
int(print.config().machine_min_travel_rate.values.front() + 0.5));
|
||||||
}
|
}
|
||||||
@ -1608,7 +1608,7 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
|
|||||||
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
|
||||||
// M140 - Set Extruder Temperature
|
// M140 - Set Extruder Temperature
|
||||||
// M190 - Set Extruder Temperature and Wait
|
// 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)
|
void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||||
{
|
{
|
||||||
// Initial bed temperature based on the first extruder.
|
// Initial bed temperature based on the first extruder.
|
||||||
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
|
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
|
||||||
@ -1621,7 +1621,7 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
|
|||||||
// the custom start G-code emited these.
|
// the custom start G-code emited these.
|
||||||
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
|
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
|
||||||
if (! temp_set_by_gcode)
|
if (! temp_set_by_gcode)
|
||||||
_write(file, set_temp_gcode);
|
file.write(set_temp_gcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write 1st layer extruder temperatures into the G-code.
|
// Write 1st layer extruder temperatures into the G-code.
|
||||||
@ -1629,7 +1629,7 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
|
|||||||
// M104 - Set Extruder Temperature
|
// M104 - Set Extruder Temperature
|
||||||
// M109 - Set Extruder Temperature and Wait
|
// M109 - Set Extruder Temperature and Wait
|
||||||
// RepRapFirmware: G10 Sxx
|
// RepRapFirmware: G10 Sxx
|
||||||
void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||||
{
|
{
|
||||||
// Is the bed temperature set by the provided custom G-code?
|
// Is the bed temperature set by the provided custom G-code?
|
||||||
int temp_by_gcode = -1;
|
int temp_by_gcode = -1;
|
||||||
@ -1646,7 +1646,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
|
|||||||
// Set temperature of the first printing extruder only.
|
// Set temperature of the first printing extruder only.
|
||||||
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
||||||
if (temp > 0)
|
if (temp > 0)
|
||||||
_write(file, m_writer.set_temperature(temp, wait, first_printing_extruder_id));
|
file.write(m_writer.set_temperature(temp, wait, first_printing_extruder_id));
|
||||||
} else {
|
} else {
|
||||||
// Set temperatures of all the printing extruders.
|
// Set temperatures of all the printing extruders.
|
||||||
for (unsigned int tool_id : print.extruders()) {
|
for (unsigned int tool_id : print.extruders()) {
|
||||||
@ -1654,7 +1654,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
|
|||||||
if (print.config().ooze_prevention.value)
|
if (print.config().ooze_prevention.value)
|
||||||
temp += print.config().standby_temperature_delta.value;
|
temp += print.config().standby_temperature_delta.value;
|
||||||
if (temp > 0)
|
if (temp > 0)
|
||||||
_write(file, m_writer.set_temperature(temp, wait, tool_id));
|
file.write(m_writer.set_temperature(temp, wait, tool_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1891,7 +1891,7 @@ namespace Skirt {
|
|||||||
// and performing the extruder specific extrusions together.
|
// and performing the extruder specific extrusions together.
|
||||||
void GCode::process_layer(
|
void GCode::process_layer(
|
||||||
// Write into the output file.
|
// Write into the output file.
|
||||||
FILE *file,
|
GCodeOutputStream &file,
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
const std::vector<LayerToPrint> &layers,
|
const std::vector<LayerToPrint> &layers,
|
||||||
@ -2306,7 +2306,7 @@ void GCode::process_layer(
|
|||||||
// printf("G-code after filter:\n%s\n", out.c_str());
|
// printf("G-code after filter:\n%s\n", out.c_str());
|
||||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||||
|
|
||||||
_write(file, gcode);
|
file.write(gcode);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
|
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
|
||||||
log_memory_info();
|
log_memory_info();
|
||||||
}
|
}
|
||||||
@ -2642,22 +2642,22 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
|
|||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCode::_write(FILE* file, const char *what)
|
void GCode::GCodeOutputStream::write(const char *what)
|
||||||
{
|
{
|
||||||
if (what != nullptr) {
|
if (what != nullptr) {
|
||||||
const char* gcode = what;
|
const char* gcode = what;
|
||||||
// writes string to file
|
// writes string to file
|
||||||
fwrite(gcode, 1, ::strlen(gcode), file);
|
fwrite(gcode, 1, ::strlen(gcode), this->f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCode::_writeln(FILE* file, const std::string &what)
|
void GCode::GCodeOutputStream::writeln(const std::string &what)
|
||||||
{
|
{
|
||||||
if (! what.empty())
|
if (! what.empty())
|
||||||
_write(file, (what.back() == '\n') ? what : (what + '\n'));
|
this->write(what.back() == '\n' ? what : what + '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCode::_write_format(FILE* file, const char* format, ...)
|
void GCode::GCodeOutputStream::write_format(const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
@ -2681,7 +2681,7 @@ void GCode::_write_format(FILE* file, const char* format, ...)
|
|||||||
char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer;
|
char *bufptr = buffer_dynamic ? (char*)malloc(buflen) : buffer;
|
||||||
int res = ::vsnprintf(bufptr, buflen, format, args);
|
int res = ::vsnprintf(bufptr, buflen, format, args);
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
_write(file, bufptr);
|
this->write(bufptr);
|
||||||
|
|
||||||
if (buffer_dynamic)
|
if (buffer_dynamic)
|
||||||
free(bufptr);
|
free(bufptr);
|
||||||
|
@ -184,13 +184,39 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
|
class GCodeOutputStream {
|
||||||
|
public:
|
||||||
|
GCodeOutputStream(FILE *f) : f(f) {}
|
||||||
|
~GCodeOutputStream() { this->close(); }
|
||||||
|
|
||||||
|
bool is_open() const { return f; }
|
||||||
|
bool is_error() const { return ::ferror(f); }
|
||||||
|
|
||||||
|
void flush() { ::fflush(f); }
|
||||||
|
void close() { if (f) ::fclose(f); }
|
||||||
|
|
||||||
|
// Write a string into a file.
|
||||||
|
void write(const std::string& what) { this->write(what.c_str()); }
|
||||||
|
void write(const char* what);
|
||||||
|
|
||||||
|
// Write a string into a file.
|
||||||
|
// Add a newline, if the string does not end with a newline already.
|
||||||
|
// Used to export a custom G-code section processed by the PlaceholderParser.
|
||||||
|
void writeln(const std::string& what);
|
||||||
|
|
||||||
|
// Formats and write into a file the given data.
|
||||||
|
void write_format(const char* format, ...);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *f = nullptr;
|
||||||
|
};
|
||||||
|
void _do_export(Print &print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||||
|
|
||||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||||
void process_layer(
|
void process_layer(
|
||||||
// Write into the output file.
|
// Write into the output file.
|
||||||
FILE *file,
|
GCodeOutputStream &file,
|
||||||
const Print &print,
|
const Print &print,
|
||||||
// Set of object & print layers of the same PrintObject and with the same print_z.
|
// Set of object & print layers of the same PrintObject and with the same print_z.
|
||||||
const std::vector<LayerToPrint> &layers,
|
const std::vector<LayerToPrint> &layers,
|
||||||
@ -358,22 +384,10 @@ private:
|
|||||||
// Processor
|
// Processor
|
||||||
GCodeProcessor m_processor;
|
GCodeProcessor m_processor;
|
||||||
|
|
||||||
// Write a string into a file.
|
|
||||||
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); }
|
|
||||||
void _write(FILE* file, const char *what);
|
|
||||||
|
|
||||||
// Write a string into a file.
|
|
||||||
// Add a newline, if the string does not end with a newline already.
|
|
||||||
// Used to export a custom G-code section processed by the PlaceholderParser.
|
|
||||||
void _writeln(FILE* file, const std::string& what);
|
|
||||||
|
|
||||||
// Formats and write into a file the given data.
|
|
||||||
void _write_format(FILE* file, const char* format, ...);
|
|
||||||
|
|
||||||
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
|
||||||
void print_machine_envelope(FILE *file, Print &print);
|
void print_machine_envelope(GCodeOutputStream &file, Print &print);
|
||||||
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_bed_temperature(GCodeOutputStream &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);
|
void _print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
|
||||||
// On the first printing layer. This flag triggers first layer speeds.
|
// On the first printing layer. This flag triggers first layer speeds.
|
||||||
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
|
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
|
||||||
// To control print speed of 1st object layer over raft interface.
|
// To control print speed of 1st object layer over raft interface.
|
||||||
|
Loading…
Reference in New Issue
Block a user