From e27519751896025c8d629556755b31d0ea8abf69 Mon Sep 17 00:00:00 2001
From: Paul Arden <paul@migenius.com>
Date: Mon, 20 Jul 2020 20:57:37 +1000
Subject: [PATCH 1/3] Add G10 temperature G-code support for the RepRapFirmware
 flavour.

---
 src/libslic3r/GCode.cpp       | 42 +++++++++++++++++++++++++++++++----
 src/libslic3r/GCodeWriter.cpp | 21 ++++++++++++------
 2 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 7fc531b92..975e15c6c 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -1574,9 +1574,9 @@ std::string GCode::placeholder_parser_process(const std::string &name, const std
     }
 }
 
-// Parse the custom G-code, try to find mcode_set_temp_dont_wait and mcode_set_temp_and_wait inside the custom G-code.
+// Parse the custom G-code, try to find mcode_set_temp_dont_wait and mcode_set_temp_and_wait or optionally G10 with temperature inside the custom G-code.
 // Returns true if one of the temp commands are found, and try to parse the target temperature value into temp_out.
-static bool custom_gcode_sets_temperature(const std::string &gcode, const int mcode_set_temp_dont_wait, const int mcode_set_temp_and_wait, int &temp_out)
+static bool custom_gcode_sets_temperature(const std::string &gcode, const int mcode_set_temp_dont_wait, const int mcode_set_temp_and_wait, const bool include_g10, int &temp_out)
 {
     temp_out = -1;
     if (gcode.empty())
@@ -1619,6 +1619,40 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
                     }
                 }
             }
+        } else if (*ptr == 'G' && include_g10) { // Only check for G10 if requested
+            // Line starts with 'G'.
+            ++ ptr;
+            // Parse the G code value.
+            char *endptr = nullptr;
+            int gcode = int(strtol(ptr, &endptr, 10));
+            if (endptr != nullptr && endptr != ptr && gcode == 10 /* G10 */) {
+                // G10 code found
+                ptr = endptr;
+                // Now try to parse the temperature value.
+                // While not at the end of the line:
+                while (strchr(";\r\n\0", *ptr) == nullptr) {
+                    // Skip whitespaces.
+                    for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
+                    if (*ptr == 'S') {
+                        // Skip whitespaces.
+                        for (++ ptr; *ptr == ' ' || *ptr == '\t'; ++ ptr);
+                        // Parse an int.
+                        endptr = nullptr;
+                        long temp_parsed = strtol(ptr, &endptr, 10);
+                        if (endptr > ptr) {
+                            ptr = endptr;
+                            temp_out = temp_parsed;
+                            // Let the caller know that the custom G-code sets the temperature
+                            // Only do this after successfully parsing temperature since G10
+                            // can be used for other reasons
+                            temp_set_by_gcode = true;
+                        }
+                    } else {
+                        // Skip this word.
+                        for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr);
+                    }
+                }
+            }
         }
         // Skip the rest of the line.
         for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
@@ -1668,7 +1702,7 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s
     int  temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
     // Is the bed temperature set by the provided custom G-code?
     int  temp_by_gcode     = -1;
-    bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode);
+    bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode);
     if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000)
         temp = temp_by_gcode;
     // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
@@ -1686,7 +1720,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
 {
     // Is the bed temperature set by the provided custom G-code?
     int  temp_by_gcode     = -1;
-    if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) {
+    if (custom_gcode_sets_temperature(gcode, 104, 109, true, temp_by_gcode)) {
         // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
         int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
         if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index 38a1c3ebe..98a6ed4a4 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -72,11 +72,15 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
         return "";
     
     std::string code, comment;
-    if (wait && FLAVOR_IS_NOT(gcfTeacup)) {
+    if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRap)) {
         code = "M109";
         comment = "set temperature and wait for it to be reached";
     } else {
-        code = "M104";
+        if (FLAVOR_IS(gcfRepRap)) { // M104 is deprecated on RepRapFirmware
+            code = "G10";
+        } else {
+            code = "M104";
+        }
         comment = "set temperature";
     }
     
@@ -88,14 +92,17 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
         gcode << "S";
     }
     gcode << temperature;
-    if (tool != -1 && 
-        ( (this->multiple_extruders && ! m_single_extruder_multi_material) ||
-          FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
-        gcode << " T" << tool;
+    bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material;
+    if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
+        if (FLAVOR_IS(gcfRepRap)) {
+            gcode << " P" << tool;
+        } else {
+            gcode << " T" << tool;
+        }
     }
     gcode << " ; " << comment << "\n";
     
-    if (FLAVOR_IS(gcfTeacup) && wait)
+    if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRap)) && wait)
         gcode << "M116 ; wait for temperature to be reached\n";
     
     return gcode.str();

From f6d25d0634c0c40855aafce02bad4c3de734eea2 Mon Sep 17 00:00:00 2001
From: Paul Arden <paul@migenius.com>
Date: Fri, 21 Aug 2020 14:07:50 +1000
Subject: [PATCH 2/3] Rework G10 temperature support to be enabled only for a
 new Firmware type `RepRapFirmware` leaving the `RepRap/Sprinter` behaviour
 alone. Rename the enum for `gcfRepRap` to `gcfRepRapSprinter` and add new
 `gcfRepRapFirmware` enum value. Also adds code to only use the G10 searching
 in custom G-code if the flavour is RepRapFirmware.

---
 src/libslic3r/GCode.cpp              |  5 +++--
 src/libslic3r/GCode/WipeTower.cpp    |  4 ++--
 src/libslic3r/GCodeTimeEstimator.cpp |  7 ++++---
 src/libslic3r/GCodeWriter.cpp        | 16 +++++++++++-----
 src/libslic3r/Print.cpp              |  5 +++--
 src/libslic3r/PrintConfig.cpp        |  9 ++++++---
 src/libslic3r/PrintConfig.hpp        |  5 +++--
 7 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 975e15c6c..f863fd3ee 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -500,7 +500,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen)
 
 
     // Disable linear advance for the wipe tower operations.
-        //gcode += (gcodegen.config().gcode_flavor == gcfRepRap ? std::string("M572 D0 S0\n") : std::string("M900 K0\n"));
+        //gcode += (gcodegen.config().gcode_flavor == gcfRepRapSprinter ? std::string("M572 D0 S0\n") : std::string("M900 K0\n"));
 
     for (const WipeTower::ToolChangeResult& tcr : m_priming) {
         if (!tcr.extrusions.empty())
@@ -1720,7 +1720,8 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
 {
     // Is the bed temperature set by the provided custom G-code?
     int  temp_by_gcode     = -1;
-    if (custom_gcode_sets_temperature(gcode, 104, 109, true, temp_by_gcode)) {
+    bool include_g10 = (print.config().gcode_flavor == gcfRepRapFirmware);
+    if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
         // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
         int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
         if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index c0f778687..b2534361f 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -102,7 +102,7 @@ public:
     }
 
     WipeTowerWriter&            disable_linear_advance() {
-        m_gcode += (m_gcode_flavor == gcfRepRap
+        m_gcode += (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware
                         ? (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n")
                         : std::string("M900 K0\n"));
         return *this;
@@ -351,7 +351,7 @@ public:
 	// Set digital trimpot motor
 	WipeTowerWriter& set_extruder_trimpot(int current)
 	{
-        if (m_gcode_flavor == gcfRepRap)
+        if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware)
             m_gcode += "M906 E";
         else
             m_gcode += "M907 E";
diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp
index 9e8137ef0..795fecbeb 100644
--- a/src/libslic3r/GCodeTimeEstimator.cpp
+++ b/src/libslic3r/GCodeTimeEstimator.cpp
@@ -622,7 +622,7 @@ namespace Slic3r {
     void GCodeTimeEstimator::set_default()
     {
         set_units(Millimeters);
-        set_dialect(gcfRepRap);
+        set_dialect(gcfRepRapSprinter);
         set_global_positioning_type(Absolute);
         set_e_local_positioning_type(Absolute);
 
@@ -1201,7 +1201,8 @@ namespace Slic3r {
         if ((dialect == gcfRepetier) ||
             (dialect == gcfMarlin) ||
             (dialect == gcfSmoothie) ||
-            (dialect == gcfRepRap))
+            (dialect == gcfRepRapSprinter) ||
+            (dialect == gcfRepRapFirmware))
         {
             if (line.has_value('S', value))
                 extra_time += value;
@@ -1313,7 +1314,7 @@ namespace Slic3r {
         GCodeFlavor dialect = get_dialect();
 
         // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
-        float factor = ((dialect != gcfRepRap) && (get_units() == GCodeTimeEstimator::Inches)) ? INCHES_TO_MM : 1.0f;
+        float factor = ((dialect != gcfRepRapSprinter && dialect != gcfRepRapFirmware) && (get_units() == GCodeTimeEstimator::Inches)) ? INCHES_TO_MM : 1.0f;
 
         if (line.has_x())
             set_axis_max_acceleration(X, line.x() * factor);
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index 98a6ed4a4..569ae65e5 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -46,7 +46,13 @@ std::string GCodeWriter::preamble()
         gcode << "G21 ; set units to millimeters\n";
         gcode << "G90 ; use absolute coordinates\n";
     }
-    if (FLAVOR_IS(gcfRepRap) || FLAVOR_IS(gcfMarlin) || FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfSmoothie)) {
+    if (FLAVOR_IS(gcfRepRapSprinter) ||
+        FLAVOR_IS(gcfRepRapFirmware) ||
+        FLAVOR_IS(gcfMarlin) ||
+        FLAVOR_IS(gcfTeacup) ||
+        FLAVOR_IS(gcfRepetier) ||
+        FLAVOR_IS(gcfSmoothie))
+    {
         if (this->config.use_relative_e_distances) {
             gcode << "M83 ; use relative distances for extrusion\n";
         } else {
@@ -72,11 +78,11 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
         return "";
     
     std::string code, comment;
-    if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRap)) {
+    if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) {
         code = "M109";
         comment = "set temperature and wait for it to be reached";
     } else {
-        if (FLAVOR_IS(gcfRepRap)) { // M104 is deprecated on RepRapFirmware
+        if (FLAVOR_IS(gcfRepRapFirmware)) { // M104 is deprecated on RepRapFirmware
             code = "G10";
         } else {
             code = "M104";
@@ -94,7 +100,7 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
     gcode << temperature;
     bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material;
     if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
-        if (FLAVOR_IS(gcfRepRap)) {
+        if (FLAVOR_IS(gcfRepRapFirmware)) {
             gcode << " P" << tool;
         } else {
             gcode << " T" << tool;
@@ -102,7 +108,7 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
     }
     gcode << " ; " << comment << "\n";
     
-    if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRap)) && wait)
+    if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRapFirmware)) && wait)
         gcode << "M116 ; wait for temperature to be reached\n";
     
     return gcode.str();
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 0c8a11fcf..878380955 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -1259,8 +1259,9 @@ std::string Print::validate() const
                           "and use filaments of the same diameter.");
         }
 
-        if (m_config.gcode_flavor != gcfRepRap && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin)
-            return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter and Repetier G-code flavors.");
+        if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware &&
+            m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlin)
+            return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.");
         if (! m_config.use_relative_e_distances)
             return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
         if (m_config.ooze_prevention)
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index d6a23d75d..0d7ddeecd 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -953,6 +953,7 @@ void PrintConfigDef::init_fff_params()
                    "The \"No extrusion\" flavor prevents PrusaSlicer from exporting any extrusion value at all.");
     def->enum_keys_map = &ConfigOptionEnum<GCodeFlavor>::get_enum_values();
     def->enum_values.push_back("reprap");
+    def->enum_values.push_back("reprapfirmware");
     def->enum_values.push_back("repetier");
     def->enum_values.push_back("teacup");
     def->enum_values.push_back("makerware");
@@ -963,6 +964,7 @@ void PrintConfigDef::init_fff_params()
     def->enum_values.push_back("smoothie");
     def->enum_values.push_back("no-extrusion");
     def->enum_labels.push_back("RepRap/Sprinter");
+    def->enum_labels.push_back("RepRapFirmware");
     def->enum_labels.push_back("Repetier");
     def->enum_labels.push_back("Teacup");
     def->enum_labels.push_back("MakerWare (MakerBot)");
@@ -973,7 +975,7 @@ void PrintConfigDef::init_fff_params()
     def->enum_labels.push_back("Smoothie");
     def->enum_labels.push_back(L("No extrusion"));
     def->mode = comExpert;
-    def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(gcfRepRap));
+    def->set_default_value(new ConfigOptionEnum<GCodeFlavor>(gcfRepRapSprinter));
 
     def = this->add("gcode_label_objects", coBool);
     def->label = L("Label objects");
@@ -3290,11 +3292,12 @@ std::string FullPrintConfig::validate()
 
     if (this->use_firmware_retraction.value &&
         this->gcode_flavor.value != gcfSmoothie &&
-        this->gcode_flavor.value != gcfRepRap &&
+        this->gcode_flavor.value != gcfRepRapSprinter &&
+        this->gcode_flavor.value != gcfRepRapFirmware &&
         this->gcode_flavor.value != gcfMarlin &&
         this->gcode_flavor.value != gcfMachinekit &&
         this->gcode_flavor.value != gcfRepetier)
-        return "--use-firmware-retraction is only supported by Marlin, Smoothie, Repetier and Machinekit firmware";
+        return "--use-firmware-retraction is only supported by Marlin, Smoothie, RepRapFirmware, Repetier and Machinekit firmware";
 
     if (this->use_firmware_retraction.value)
         for (unsigned char wipe : this->wipe.values)
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index f28ef2a22..0ab51718b 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -25,7 +25,7 @@
 namespace Slic3r {
 
 enum GCodeFlavor : unsigned char {
-    gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
+    gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
     gcfSmoothie, gcfNoExtrusion,
 };
 
@@ -84,7 +84,8 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology
 template<> inline const t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
     static t_config_enum_values keys_map;
     if (keys_map.empty()) {
-        keys_map["reprap"]          = gcfRepRap;
+        keys_map["reprap"]          = gcfRepRapSprinter;
+        keys_map["reprapfirmware"]  = gcfRepRapFirmware;
         keys_map["repetier"]        = gcfRepetier;
         keys_map["teacup"]          = gcfTeacup;
         keys_map["makerware"]       = gcfMakerWare;

From 8cd13803cac8c68f549de1afde845e5d58e58934 Mon Sep 17 00:00:00 2001
From: Lukas Matena <lukasmatena@seznam.cz>
Date: Fri, 23 Oct 2020 13:27:45 +0200
Subject: [PATCH 3/3] Updated the G10 RepRapFirmware pull request to current
 master

---
 src/libslic3r/GCode/GCodeProcessor.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index fb7e83303..665316296 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -689,7 +689,7 @@ void GCodeProcessor::reset()
     m_global_positioning_type = EPositioningType::Absolute;
     m_e_local_positioning_type = EPositioningType::Absolute;
     m_extruder_offsets = std::vector<Vec3f>(Min_Extruder_Count, Vec3f::Zero());
-    m_flavor = gcfRepRap;
+    m_flavor = gcfRepRapSprinter;
 
     m_start_position = { 0.0f, 0.0f, 0.0f, 0.0f };
     m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
@@ -1109,7 +1109,7 @@ bool GCodeProcessor::process_cura_tags(const std::string& comment)
         else if (flavor == "Repetier")
             m_flavor = gcfRepetier;
         else if (flavor == "RepRap")
-            m_flavor = gcfRepRap;
+            m_flavor = gcfRepRapFirmware;
         else if (flavor == "Marlin")
             m_flavor = gcfMarlin;
         else
@@ -1801,7 +1801,7 @@ void GCodeProcessor::process_M201(const GCodeReader::GCodeLine& line)
         return;
 
     // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
-    float factor = (m_flavor != gcfRepRap && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
+    float factor = ((m_flavor != gcfRepRapSprinter && m_flavor != gcfRepRapFirmware) && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
 
     for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count); ++i) {
         if (line.has_x())