#5538 - Validation of custom g-code against gcode processor reserved keywords
This commit is contained in:
parent
aec39aaba6
commit
86d7e1fb90
@ -170,7 +170,11 @@ namespace Slic3r {
|
||||
// subdivide the retraction in segments
|
||||
if (!wipe_path.empty()) {
|
||||
// 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";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
for (const Line& line : wipe_path.lines()) {
|
||||
double segment_length = line.length();
|
||||
/* 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
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n";
|
||||
#else
|
||||
gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
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() ?
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
#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();
|
||||
|
||||
// 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
|
||||
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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||
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);
|
||||
|
||||
// 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());
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
// Write the custom start G-code
|
||||
_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));
|
||||
|
||||
// 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());
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
// 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
|
||||
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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
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);
|
||||
if (print.m_print_statistics.total_toolchanges > 0)
|
||||
_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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
// Append full config.
|
||||
_write(file, "\n");
|
||||
@ -1631,7 +1728,11 @@ namespace ProcessLayer
|
||||
assert(m600_extruder_before_layer >= 0);
|
||||
// Color Change or Tool Change as Color Change.
|
||||
// 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";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer
|
||||
// && !MMU1
|
||||
@ -1646,21 +1747,27 @@ namespace ProcessLayer
|
||||
gcode += "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (gcode_type == CustomGCode::PausePrint) // Pause print
|
||||
{
|
||||
// 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";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
//! FIXME_in_fw show message during print pause
|
||||
if (!pause_print_msg.empty())
|
||||
gcode += "M117 " + pause_print_msg + "\n";
|
||||
gcode += config.pause_print_gcode;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// 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";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
|
||||
gcode += config.template_custom_gcode;
|
||||
else // custom Gcode
|
||||
@ -1807,14 +1914,22 @@ void GCode::process_layer(
|
||||
std::string gcode;
|
||||
|
||||
// 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";
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
// export layer z
|
||||
char buf[64];
|
||||
sprintf(buf, ";Z:%g\n", print_z);
|
||||
gcode += buf;
|
||||
// export layer height
|
||||
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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
gcode += buf;
|
||||
// update caches
|
||||
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) {
|
||||
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());
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
gcode += buf;
|
||||
}
|
||||
|
||||
if (last_was_wipe_tower || 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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
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) {
|
||||
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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
gcode += buf;
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,31 @@
|
||||
|
||||
static const float INCHES_TO_MM = 25.4f;
|
||||
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
|
||||
|
||||
static const float DEFAULT_ACCELERATION = 1500.0f; // Prusa Firmware 1_75mm_MK2
|
||||
|
||||
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::Wipe_Start_Tag = "WIPE_START";
|
||||
const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END";
|
||||
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::Color_Change_Tag = "COLOR_CHANGE";
|
||||
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::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_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_Height = 0.05f;
|
||||
|
||||
const std::string GCodeProcessor::Width_Tag = "WIDTH:";
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
const std::string GCodeProcessor::Mm3_Per_Mm_Tag = "MM3_PER_MM:";
|
||||
#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 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)) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++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) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = machines[i];
|
||||
PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i);
|
||||
if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) {
|
||||
char buf[128];
|
||||
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
get_time_dhms(machine.time).c_str());
|
||||
ret += buf;
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = machines[i];
|
||||
PrintEstimatedTimeStatistics::ETimeMode mode = static_cast<PrintEstimatedTimeStatistics::ETimeMode>(i);
|
||||
if (mode == PrintEstimatedTimeStatistics::ETimeMode::Normal || machine.enabled) {
|
||||
char buf[128];
|
||||
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedTimeStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
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);
|
||||
};
|
||||
@ -541,6 +576,64 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
|
||||
|
||||
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()
|
||||
{
|
||||
reset();
|
||||
@ -847,7 +940,11 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr
|
||||
if (cmd.length() == 0) {
|
||||
const std::string_view comment = line.comment();
|
||||
if (comment.length() > 1 && detect_producer(comment))
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_parser.quit_parsing();
|
||||
#else
|
||||
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)
|
||||
{
|
||||
size_t tag_len = tag.size();
|
||||
return comment.size() >= tag_len && comment.substr(0, tag_len) == tag;
|
||||
}
|
||||
#endif // !ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
#if __has_include(<charconv>)
|
||||
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))
|
||||
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
|
||||
if (starts_with(comment, Extrusion_Role_Tag)) {
|
||||
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;
|
||||
return;
|
||||
}
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
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
|
||||
if (starts_with(comment, Height_Tag)) {
|
||||
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 << ").";
|
||||
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
|
||||
if (starts_with(comment, Color_Change_Tag)) {
|
||||
unsigned char extruder_id = 0;
|
||||
@ -1181,6 +1362,13 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
return;
|
||||
}
|
||||
|
||||
// layer change tag
|
||||
if (comment == Layer_Change_Tag) {
|
||||
++m_layer_id;
|
||||
return;
|
||||
}
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
// mm3_per_mm print tag
|
||||
if (starts_with(comment, Mm3_Per_Mm_Tag)) {
|
||||
@ -1189,12 +1377,6 @@ void GCodeProcessor::process_tags(const std::string_view comment)
|
||||
return;
|
||||
}
|
||||
#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)
|
||||
|
@ -69,7 +69,34 @@ namespace Slic3r {
|
||||
|
||||
class GCodeProcessor
|
||||
{
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
static const std::vector<std::string> Reserved_Tags;
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
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 Wipe_Start_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 Last_Line_M73_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_Height;
|
||||
|
||||
static const std::string Width_Tag;
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
static const std::string Mm3_Per_Mm_Tag;
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
@ -42,9 +42,15 @@ public:
|
||||
{
|
||||
// adds tag for analyzer:
|
||||
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
|
||||
m_gcode += buf;
|
||||
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;
|
||||
change_analyzer_line_width(line_width);
|
||||
}
|
||||
@ -52,7 +58,11 @@ public:
|
||||
WipeTowerWriter& change_analyzer_line_width(float line_width) {
|
||||
// adds tag for analyzer:
|
||||
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);
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
}
|
||||
|
@ -116,8 +116,13 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
|
||||
{
|
||||
boost::nowide::ifstream f(file);
|
||||
std::string line;
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_parsing = true;
|
||||
while (m_parsing && std::getline(f, line))
|
||||
#else
|
||||
m_parsing_file = true;
|
||||
while (m_parsing_file && std::getline(f, line))
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
this->parse_line(line, callback);
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,12 @@ public:
|
||||
{
|
||||
const char *ptr = buffer.c_str();
|
||||
GCodeLine gline;
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
m_parsing = true;
|
||||
while (m_parsing && *ptr != 0) {
|
||||
#else
|
||||
while (*ptr != 0) {
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
gline.reset();
|
||||
ptr = this->parse_line(ptr, gline, callback);
|
||||
}
|
||||
@ -108,7 +113,11 @@ public:
|
||||
{ GCodeLine gline; this->parse_line(line.c_str(), gline, 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; }
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
|
||||
float& x() { return m_position[X]; }
|
||||
float x() const { return m_position[X]; }
|
||||
@ -147,7 +156,11 @@ private:
|
||||
char m_extrusion_axis;
|
||||
float m_position[NUM_AXES];
|
||||
bool m_verbose;
|
||||
#if ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
bool m_parsing{ false };
|
||||
#else
|
||||
bool m_parsing_file{ false };
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
@ -114,6 +114,7 @@
|
||||
#define ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS (1 && ENABLE_SPLITTED_VERTEX_BUFFER)
|
||||
#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_VALIDATE_CUSTOM_GCODE (1 && ENABLE_2_3_1_ALPHA1)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
Loading…
Reference in New Issue
Block a user