#5538 - Validation of custom g-code against gcode processor reserved keywords

This commit is contained in:
enricoturri1966 2021-02-18 14:34:40 +01:00
parent aec39aaba6
commit 86d7e1fb90
7 changed files with 389 additions and 23 deletions

View File

@ -170,7 +170,11 @@ namespace Slic3r {
// subdivide the retraction in segments // subdivide the retraction in segments
if (!wipe_path.empty()) { if (!wipe_path.empty()) {
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n";
#else
gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n"; gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
for (const Line& line : wipe_path.lines()) { for (const Line& line : wipe_path.lines()) {
double segment_length = line.length(); double segment_length = line.length();
/* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one /* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one
@ -186,7 +190,11 @@ namespace Slic3r {
); );
} }
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n";
#else
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n"; gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcodegen.set_last_pos(wipe_path.points.back()); gcodegen.set_last_pos(wipe_path.points.back());
} }
@ -610,6 +618,59 @@ namespace DoExport {
print_statistics.estimated_silent_print_time = processor.is_stealth_time_estimator_enabled() ? print_statistics.estimated_silent_print_time = processor.is_stealth_time_estimator_enabled() ?
get_time_dhms(result.time_statistics.modes[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].time) : "N/A"; get_time_dhms(result.time_statistics.modes[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].time) : "N/A";
} }
#if ENABLE_VALIDATE_CUSTOM_GCODE
// if any reserved keyword is found, returns a std::vector containing the first MAX_COUNT keywords found
// into pairs containing:
// first: source
// second: keyword
// to be shown in the warning notification
// The returned vector is empty if no keyword has been found
static std::vector<std::pair<std::string, std::string>> validate_custom_gcode(const Print& print) {
const unsigned int MAX_COUNT = 5;
std::vector<std::pair<std::string, std::string>> ret;
auto check = [&ret, MAX_COUNT](const std::string& source, const std::string& gcode) {
std::vector<std::string> tags;
if (GCodeProcessor::contains_reserved_tags(gcode, MAX_COUNT, tags)) {
if (!tags.empty()) {
size_t i = 0;
while (ret.size() < MAX_COUNT && i < tags.size()) {
ret.push_back({ source, tags[i] });
++i;
}
}
}
};
const GCodeConfig& config = print.config();
check(_(L("Start G-code")), config.start_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("End G-code")), config.end_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Before layer change G-code")), config.before_layer_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("After layer change G-code")), config.layer_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value);
if (ret.size() < MAX_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
if (ret.size() < MAX_COUNT) {
for (const std::string& value : config.start_filament_gcode.values) {
check(_(L("Filament Start G-code")), value);
if (ret.size() == MAX_COUNT)
break;
}
}
if (ret.size() < MAX_COUNT) {
for (const std::string& value : config.end_filament_gcode.values) {
check(_(L("Filament End G-code")), value);
if (ret.size() == MAX_COUNT)
break;
}
}
return ret;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
} // namespace DoExport } // namespace DoExport
void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb) void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
@ -622,6 +683,22 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
print->set_started(psGCodeExport); print->set_started(psGCodeExport);
#if ENABLE_VALIDATE_CUSTOM_GCODE
// check if any custom gcode contains keywords used by the gcode processor to
// produce time estimation and gcode toolpaths
std::vector<std::pair<std::string, std::string>> validation_res = DoExport::validate_custom_gcode(*print);
if (!validation_res.empty()) {
std::string reports;
for (const auto& [source, keyword] : validation_res) {
reports += source + ": \"" + keyword + "\"\n";
}
print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
_(L("Found reserved keyword(s) into custom g-code:")) + "\n" +
reports +
_(L("This may cause problems in g-code visualization and printing time estimation.")));
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info(); BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
// Remove the old g-code if it exists. // Remove the old g-code if it exists.
@ -1034,7 +1111,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// adds tags for time estimators // adds tags for time estimators
if (print.config().remaining_times.value) if (print.config().remaining_times.value)
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::First_Line_M73_Placeholder_Tag); _writeln(file, GCodeProcessor::First_Line_M73_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// 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();
@ -1140,7 +1221,11 @@ 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
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); _write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Write the custom start G-code // Write the custom start G-code
_writeln(file, start_gcode); _writeln(file, start_gcode);
@ -1301,7 +1386,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write(file, m_writer.set_fan(false)); _write(file, m_writer.set_fan(false));
// adds tag for processor // adds tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#else
_write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); _write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Process filament-specific gcode in extruder order. // Process filament-specific gcode in extruder order.
{ {
@ -1328,7 +1417,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
// adds tags for time estimators // adds tags for time estimators
if (print.config().remaining_times.value) if (print.config().remaining_times.value)
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::Last_Line_M73_Placeholder_Tag); _writeln(file, GCodeProcessor::Last_Line_M73_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
print.throw_if_canceled(); print.throw_if_canceled();
@ -1344,7 +1437,11 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
_write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost); _write_format(file, "; 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); _write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges);
#if ENABLE_VALIDATE_CUSTOM_GCODE
_write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str());
#else
_writeln(file, GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag); _writeln(file, GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// Append full config. // Append full config.
_write(file, "\n"); _write(file, "\n");
@ -1631,7 +1728,11 @@ namespace ProcessLayer
assert(m600_extruder_before_layer >= 0); assert(m600_extruder_before_layer >= 0);
// Color Change or Tool Change as Color Change. // Color Change or Tool Change as Color Change.
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#else
gcode += ";" + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; gcode += ";" + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
// && !MMU1 // && !MMU1
@ -1646,21 +1747,27 @@ namespace ProcessLayer
gcode += "\n"; gcode += "\n";
} }
} }
else else {
{
if (gcode_type == CustomGCode::PausePrint) // Pause print if (gcode_type == CustomGCode::PausePrint) // Pause print
{ {
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n";
#else
gcode += ";" + GCodeProcessor::Pause_Print_Tag + "\n"; gcode += ";" + GCodeProcessor::Pause_Print_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
//! FIXME_in_fw show message during print pause //! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty()) if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n"; gcode += "M117 " + pause_print_msg + "\n";
gcode += config.pause_print_gcode; gcode += config.pause_print_gcode;
} }
else else {
{
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n";
#else
gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n"; gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
gcode += config.template_custom_gcode; gcode += config.template_custom_gcode;
else // custom Gcode else // custom Gcode
@ -1807,14 +1914,22 @@ void GCode::process_layer(
std::string gcode; std::string gcode;
// add tag for processor // add tag for processor
#if ENABLE_VALIDATE_CUSTOM_GCODE
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change) + "\n";
#else
gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n"; gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
// export layer z // export layer z
char buf[64]; char buf[64];
sprintf(buf, ";Z:%g\n", print_z); sprintf(buf, ";Z:%g\n", print_z);
gcode += buf; gcode += buf;
// export layer height // export layer height
float height = first_layer ? static_cast<float>(print_z) : static_cast<float>(print_z) - m_last_layer_z; float height = first_layer ? static_cast<float>(print_z) : static_cast<float>(print_z) - m_last_layer_z;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), height);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), height); sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), height);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf; gcode += buf;
// update caches // update caches
m_last_layer_z = static_cast<float>(print_z); m_last_layer_z = static_cast<float>(print_z);
@ -2635,13 +2750,21 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
if (path.role() != m_last_processor_extrusion_role) { if (path.role() != m_last_processor_extrusion_role) {
m_last_processor_extrusion_role = path.role(); m_last_processor_extrusion_role = path.role();
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
#else
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str()); sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf; gcode += buf;
} }
if (last_was_wipe_tower || m_last_width != path.width) { if (last_was_wipe_tower || m_last_width != path.width) {
m_last_width = path.width; m_last_width = path.width;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), m_last_width);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width); sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf; gcode += buf;
} }
@ -2655,7 +2778,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) { if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) {
m_last_height = path.height; m_last_height = path.height;
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_last_height);
#else
sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height); sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gcode += buf; gcode += buf;
} }

View File

@ -19,15 +19,31 @@
static const float INCHES_TO_MM = 25.4f; static const float INCHES_TO_MM = 25.4f;
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f; static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2 static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
namespace Slic3r { namespace Slic3r {
#if ENABLE_VALIDATE_CUSTOM_GCODE
const std::vector<std::string> GCodeProcessor::Reserved_Tags = {
"TYPE:",
"WIPE_START",
"WIPE_END",
"HEIGHT:",
"WIDTH:",
"LAYER_CHANGE",
"COLOR_CHANGE",
"PAUSE_PRINT",
"CUSTOM_GCODE",
"_GP_FIRST_LINE_M73_PLACEHOLDER",
"_GP_LAST_LINE_M73_PLACEHOLDER",
"_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"
};
#else
const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:"; const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:";
const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START"; const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START";
const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END"; const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END";
const std::string GCodeProcessor::Height_Tag = "HEIGHT:"; const std::string GCodeProcessor::Height_Tag = "HEIGHT:";
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE"; const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE";
const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE"; const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE";
const std::string GCodeProcessor::Pause_Print_Tag = "PAUSE_PRINT"; const std::string GCodeProcessor::Pause_Print_Tag = "PAUSE_PRINT";
@ -36,11 +52,11 @@ const std::string GCodeProcessor::Custom_Code_Tag = "CUSTOM_GCODE";
const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _GP_FIRST_LINE_M73_PLACEHOLDER"; const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _GP_FIRST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER"; const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER";
const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"; const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER";
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
const float GCodeProcessor::Wipe_Width = 0.05f; const float GCodeProcessor::Wipe_Width = 0.05f;
const float GCodeProcessor::Wipe_Height = 0.05f; const float GCodeProcessor::Wipe_Height = 0.05f;
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:"; const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
@ -365,7 +381,22 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
std::string line = gcode_line.substr(0, gcode_line.length() - 1); std::string line = gcode_line.substr(0, gcode_line.length() - 1);
std::string ret; std::string ret;
#if ENABLE_VALIDATE_CUSTOM_GCODE
if (line.length() > 1) {
line = line.substr(1);
if (export_remaining_time_enabled &&
(line == reserved_tag(ETags::First_Line_M73_Placeholder) || line == reserved_tag(ETags::Last_Line_M73_Placeholder))) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i];
if (machine.enabled) {
ret += format_line_M73(machine.line_m73_mask.c_str(),
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
}
}
}
else if (line == reserved_tag(ETags::Estimated_Printing_Time_Placeholder)) {
#else
if (export_remaining_time_enabled && (line == First_Line_M73_Placeholder_Tag || line == Last_Line_M73_Placeholder_Tag)) { if (export_remaining_time_enabled && (line == First_Line_M73_Placeholder_Tag || line == Last_Line_M73_Placeholder_Tag)) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
const TimeMachine& machine = machines[i]; const TimeMachine& machine = machines[i];
@ -377,18 +408,22 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename)
} }
} }
else if (line == Estimated_Printing_Time_Placeholder_Tag) { else if (line == Estimated_Printing_Time_Placeholder_Tag) {
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) { #endif // ENABLE_VALIDATE_CUSTOM_GCODE
const TimeMachine& machine = machines[i]; for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i); const TimeMachine& machine = machines[i];
if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) { PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i);
char buf[128]; if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) {
sprintf(buf, "; estimated printing time (%s mode) = %s\n", char buf[128];
(mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent", sprintf(buf, "; estimated printing time (%s mode) = %s\n",
get_time_dhms(machine.time).c_str()); (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent",
ret += buf; get_time_dhms(machine.time).c_str());
ret += buf;
}
} }
} }
#if ENABLE_VALIDATE_CUSTOM_GCODE
} }
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
return std::make_pair(!ret.empty(), ret.empty() ? gcode_line : ret); return std::make_pair(!ret.empty(), ret.empty() ? gcode_line : ret);
}; };
@ -541,6 +576,64 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
unsigned int GCodeProcessor::s_result_id = 0; unsigned int GCodeProcessor::s_result_id = 0;
#if ENABLE_VALIDATE_CUSTOM_GCODE
static inline bool starts_with(const std::string_view comment, const std::string_view tag)
{
size_t tag_len = tag.size();
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
}
bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string& found_tag)
{
bool ret = false;
GCodeReader parser;
parser.parse_buffer(gcode, [&ret, &found_tag](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) {
if (starts_with(comment, s)) {
ret = true;
found_tag = comment;
parser.quit_parsing();
return;
}
}
}
});
return ret;
}
bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag)
{
max_count = std::max(max_count, 1U);
bool ret = false;
GCodeReader parser;
parser.parse_buffer(gcode, [&ret, &found_tag, max_count](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
std::string comment = line.raw();
if (comment.length() > 2 && comment.front() == ';') {
comment = comment.substr(1);
for (const std::string& s : Reserved_Tags) {
if (starts_with(comment, s)) {
ret = true;
found_tag.push_back(comment);
if (found_tag.size() == max_count) {
parser.quit_parsing();
return;
}
}
}
}
});
return ret;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
GCodeProcessor::GCodeProcessor() GCodeProcessor::GCodeProcessor()
{ {
reset(); reset();
@ -847,7 +940,11 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
if (cmd.length() == 0) { if (cmd.length() == 0) {
const std::string_view comment = line.comment(); const std::string_view comment = line.comment();
if (comment.length() > 1 && detect_producer(comment)) if (comment.length() > 1 && detect_producer(comment))
#if ENABLE_VALIDATE_CUSTOM_GCODE
m_parser.quit_parsing();
#else
m_parser.quit_parsing_file(); m_parser.quit_parsing_file();
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
} }
}); });
@ -1051,11 +1148,13 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line)
} }
} }
#if !ENABLE_VALIDATE_CUSTOM_GCODE
static inline bool starts_with(const std::string_view comment, const std::string_view tag) static inline bool starts_with(const std::string_view comment, const std::string_view tag)
{ {
size_t tag_len = tag.size(); size_t tag_len = tag.size();
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag; return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
} }
#endif // !ENABLE_VALIDATE_CUSTOM_GCODE
#if __has_include(<charconv>) #if __has_include(<charconv>)
template <typename T, typename = void> template <typename T, typename = void>
@ -1108,6 +1207,25 @@ void GCodeProcessor::process_tags(const std::string_view comment)
if (m_producers_enabled && process_producers_tags(comment)) if (m_producers_enabled && process_producers_tags(comment))
return; return;
#if ENABLE_VALIDATE_CUSTOM_GCODE
// extrusion role tag
if (starts_with(comment, reserved_tag(ETags::Role))) {
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()));
return;
}
// wipe start tag
if (starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
m_wiping = true;
return;
}
// wipe end tag
if (starts_with(comment, reserved_tag(ETags::Wipe_End))) {
m_wiping = false;
return;
}
#else
// extrusion role tag // extrusion role tag
if (starts_with(comment, Extrusion_Role_Tag)) { if (starts_with(comment, Extrusion_Role_Tag)) {
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length())); m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length()));
@ -1125,8 +1243,23 @@ void GCodeProcessor::process_tags(const std::string_view comment)
m_wiping = false; m_wiping = false;
return; return;
} }
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) { if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) {
#if ENABLE_VALIDATE_CUSTOM_GCODE
// height tag
if (starts_with(comment, reserved_tag(ETags::Height))) {
if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
return;
}
// width tag
if (starts_with(comment, reserved_tag(ETags::Width))) {
if (!parse_number(comment.substr(reserved_tag(ETags::Width).size()), m_forced_width))
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return;
}
#else
// height tag // height tag
if (starts_with(comment, Height_Tag)) { if (starts_with(comment, Height_Tag)) {
if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height)) if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height))
@ -1139,8 +1272,56 @@ void GCodeProcessor::process_tags(const std::string_view comment)
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
return; return;
} }
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
} }
#if ENABLE_VALIDATE_CUSTOM_GCODE
// color change tag
if (starts_with(comment, reserved_tag(ETags::Color_Change))) {
unsigned char extruder_id = 0;
if (starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) {
int eid;
if (!parse_number(comment.substr(reserved_tag(ETags::Color_Change).size() + 2), eid) || eid < 0 || eid > 255) {
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
return;
}
extruder_id = static_cast<unsigned char>(eid);
}
m_extruder_colors[extruder_id] = static_cast<unsigned char>(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview
++m_cp_color.counter;
if (m_cp_color.counter == UCHAR_MAX)
m_cp_color.counter = 0;
if (m_extruder_id == extruder_id) {
m_cp_color.current = m_extruder_colors[extruder_id];
store_move_vertex(EMoveType::Color_change);
}
process_custom_gcode_time(CustomGCode::ColorChange);
return;
}
// pause print tag
if (comment == reserved_tag(ETags::Pause_Print)) {
store_move_vertex(EMoveType::Pause_Print);
process_custom_gcode_time(CustomGCode::PausePrint);
return;
}
// custom code tag
if (comment == reserved_tag(ETags::Custom_Code)) {
store_move_vertex(EMoveType::Custom_GCode);
return;
}
// layer change tag
if (comment == reserved_tag(ETags::Layer_Change)) {
++m_layer_id;
return;
}
#else
// color change tag // color change tag
if (starts_with(comment, Color_Change_Tag)) { if (starts_with(comment, Color_Change_Tag)) {
unsigned char extruder_id = 0; unsigned char extruder_id = 0;
@ -1181,6 +1362,13 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return; return;
} }
// layer change tag
if (comment == Layer_Change_Tag) {
++m_layer_id;
return;
}
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
// mm3_per_mm print tag // mm3_per_mm print tag
if (starts_with(comment, Mm3_Per_Mm_Tag)) { if (starts_with(comment, Mm3_Per_Mm_Tag)) {
@ -1189,12 +1377,6 @@ void GCodeProcessor::process_tags(const std::string_view comment)
return; return;
} }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// layer change tag
if (comment == Layer_Change_Tag) {
++m_layer_id;
return;
}
} }
bool GCodeProcessor::process_producers_tags(const std::string_view comment) bool GCodeProcessor::process_producers_tags(const std::string_view comment)

View File

@ -69,7 +69,34 @@ namespace Slic3r {
class GCodeProcessor class GCodeProcessor
{ {
#if ENABLE_VALIDATE_CUSTOM_GCODE
static const std::vector<std::string> Reserved_Tags;
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
public: public:
#if ENABLE_VALIDATE_CUSTOM_GCODE
enum class ETags : unsigned char
{
Role,
Wipe_Start,
Wipe_End,
Height,
Width,
Layer_Change,
Color_Change,
Pause_Print,
Custom_Code,
First_Line_M73_Placeholder,
Last_Line_M73_Placeholder,
Estimated_Printing_Time_Placeholder
};
static const std::string& reserved_tag(ETags tag) { return Reserved_Tags[static_cast<unsigned char>(tag)]; }
// checks the given gcode for reserved tags and returns true when finding the 1st (which is returned into found_tag)
static bool contains_reserved_tag(const std::string& gcode, std::string& found_tag);
// checks the given gcode for reserved tags and returns true when finding any
// (the first max_count found tags are returned into found_tag)
static bool contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag);
#else
static const std::string Extrusion_Role_Tag; static const std::string Extrusion_Role_Tag;
static const std::string Wipe_Start_Tag; static const std::string Wipe_Start_Tag;
static const std::string Wipe_End_Tag; static const std::string Wipe_End_Tag;
@ -81,11 +108,12 @@ namespace Slic3r {
static const std::string First_Line_M73_Placeholder_Tag; static const std::string First_Line_M73_Placeholder_Tag;
static const std::string Last_Line_M73_Placeholder_Tag; static const std::string Last_Line_M73_Placeholder_Tag;
static const std::string Estimated_Printing_Time_Placeholder_Tag; static const std::string Estimated_Printing_Time_Placeholder_Tag;
static const std::string Width_Tag;
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
static const float Wipe_Width; static const float Wipe_Width;
static const float Wipe_Height; static const float Wipe_Height;
static const std::string Width_Tag;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING #if ENABLE_GCODE_VIEWER_DATA_CHECKING
static const std::string Mm3_Per_Mm_Tag; static const std::string Mm3_Per_Mm_Tag;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING

View File

@ -42,9 +42,15 @@ public:
{ {
// adds tag for analyzer: // adds tag for analyzer:
char buf[64]; char buf[64];
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf;
sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
#else
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
m_gcode += buf; m_gcode += buf;
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str()); sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
m_gcode += buf; m_gcode += buf;
change_analyzer_line_width(line_width); change_analyzer_line_width(line_width);
} }
@ -52,7 +58,11 @@ public:
WipeTowerWriter& change_analyzer_line_width(float line_width) { WipeTowerWriter& change_analyzer_line_width(float line_width) {
// adds tag for analyzer: // adds tag for analyzer:
char buf[64]; char buf[64];
#if ENABLE_VALIDATE_CUSTOM_GCODE
sprintf(buf, ";%s%f\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), line_width);
#else
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width); sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width);
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
m_gcode += buf; m_gcode += buf;
return *this; return *this;
} }

View File

@ -116,8 +116,13 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
{ {
boost::nowide::ifstream f(file); boost::nowide::ifstream f(file);
std::string line; std::string line;
#if ENABLE_VALIDATE_CUSTOM_GCODE
m_parsing = true;
while (m_parsing && std::getline(f, line))
#else
m_parsing_file = true; m_parsing_file = true;
while (m_parsing_file && std::getline(f, line)) while (m_parsing_file && std::getline(f, line))
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
this->parse_line(line, callback); this->parse_line(line, callback);
} }

View File

@ -84,7 +84,12 @@ public:
{ {
const char *ptr = buffer.c_str(); const char *ptr = buffer.c_str();
GCodeLine gline; GCodeLine gline;
#if ENABLE_VALIDATE_CUSTOM_GCODE
m_parsing = true;
while (m_parsing && *ptr != 0) {
#else
while (*ptr != 0) { while (*ptr != 0) {
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
gline.reset(); gline.reset();
ptr = this->parse_line(ptr, gline, callback); ptr = this->parse_line(ptr, gline, callback);
} }
@ -108,7 +113,11 @@ public:
{ GCodeLine gline; this->parse_line(line.c_str(), gline, callback); } { GCodeLine gline; this->parse_line(line.c_str(), gline, callback); }
void parse_file(const std::string &file, callback_t callback); void parse_file(const std::string &file, callback_t callback);
#if ENABLE_VALIDATE_CUSTOM_GCODE
void quit_parsing() { m_parsing = false; }
#else
void quit_parsing_file() { m_parsing_file = false; } void quit_parsing_file() { m_parsing_file = false; }
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
float& x() { return m_position[X]; } float& x() { return m_position[X]; }
float x() const { return m_position[X]; } float x() const { return m_position[X]; }
@ -147,7 +156,11 @@ private:
char m_extrusion_axis; char m_extrusion_axis;
float m_position[NUM_AXES]; float m_position[NUM_AXES];
bool m_verbose; bool m_verbose;
#if ENABLE_VALIDATE_CUSTOM_GCODE
bool m_parsing{ false };
#else
bool m_parsing_file{ false }; bool m_parsing_file{ false };
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
}; };
} /* namespace Slic3r */ } /* namespace Slic3r */

View File

@ -114,6 +114,7 @@
#define ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS (1 && ENABLE_SPLITTED_VERTEX_BUFFER) #define ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS (1 && ENABLE_SPLITTED_VERTEX_BUFFER)
#define ENABLE_WARNING_TEXTURE_REMOVAL (1 && ENABLE_2_3_1_ALPHA1) #define ENABLE_WARNING_TEXTURE_REMOVAL (1 && ENABLE_2_3_1_ALPHA1)
#define ENABLE_GCODE_LINES_ID_IN_H_SLIDER (1 && ENABLE_2_3_1_ALPHA1) #define ENABLE_GCODE_LINES_ID_IN_H_SLIDER (1 && ENABLE_2_3_1_ALPHA1)
#define ENABLE_VALIDATE_CUSTOM_GCODE (1 && ENABLE_2_3_1_ALPHA1)
#endif // _prusaslicer_technologies_h_ #endif // _prusaslicer_technologies_h_