<commit_before>//Copyright (c) 2013 <NAME>
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H

#include <stdio.h>
#include <deque> // for extrusionAmountAtPreviousRetractions
#include <sstream> // for stream.str()

#include "settings/settings.h"
#include "utils/intpoint.h"
#include "utils/NoCopy.h"
#include "timeEstimate.h"
#include "MeshGroup.h"
#include "commandSocket.h"
#include "RetractionConfig.h"

namespace cura {

/*!
 * Coasting configuration used during printing.
 * Can differ per extruder.
 * 
 * Might be used in the future to have different coasting per feature, e.g. outer wall only.
 */
struct CoastingConfig
{
    bool coasting_enable; //!< Whether coasting is enabled on the extruder to which this config is attached 
    double coasting_volume; //!< The volume leeked when printing without feeding
    double coasting_speed; //!< A modifier (0-1) on the last used travel speed to move slower during coasting
    double coasting_min_volume;  //!< The minimal volume printed to build up enough pressure to leek the coasting_volume
};


//The GCodeExport class writes the actual GCode. This is the only class that knows how GCode looks and feels.
//  Any customizations on GCodes flavors are done in this class.
class GCodeExport : public NoCopy
{
private:
    struct ExtruderTrainAttributes
    {
        Point3 prime_pos; //!< The location this nozzle is primed before printing
        bool prime_pos_is_abs; //!< Whether the prime position is absolute, rather than relative to the last given position
        bool is_primed; //!< Whether this extruder has currently already been primed in this print

        bool is_used; //!< Whether this extruder train is actually used during the printing of all meshgroups
        int nozzle_size; //!< The nozzle size label of the nozzle (e.g. 0.4mm; irrespective of tolerances)
        Point nozzle_offset;
        char extruderCharacter;
        std::string material_guid; //!< The GUID for the material used by this extruder

        std::string start_code;
        std::string end_code;
        double filament_area; //!< in mm^2 for non-volumetric, cylindrical filament

        double totalFilament; //!< total filament used per extruder in mm^3
        int currentTemperature;
        int initial_temp; //!< Temperature this nozzle needs to be at the start of the print.

        double retraction_e_amount_current; //!< The current retracted amount (in mm or mm^3), or zero(i.e. false) if it is not currently retracted (positive values mean retracted amount, so negative impact on E values)
        double retraction_e_amount_at_e_start; //!< The ExtruderTrainAttributes::retraction_amount_current value at E0, i.e. the offset (in mm or mm^3) from E0 to the situation where the filament is at the tip of the nozzle.

        double prime_volume; //!< Amount of material (in mm^3) to be primed after an unretration (due to oozing and/or coasting)
        double last_retraction_prime_speed; //!< The last prime speed (in mm/s) of the to-be-primed amount

        std::deque<double> extruded_volume_at_previous_n_retractions; // in mm^3

        ExtruderTrainAttributes()
        : prime_pos(0, 0, 0)
        , prime_pos_is_abs(false)
        , is_primed(false)
        , is_used(false)
        , nozzle_offset(0,0)
        , extruderCharacter(0)
        , start_code("")
        , end_code("")
        , filament_area(0)
        , totalFilament(0)
        , currentTemperature(0)
        , initial_temp(0)
        , retraction_e_amount_current(0.0)
        , retraction_e_amount_at_e_start(0.0)
        , prime_volume(0.0)
        , last_retraction_prime_speed(0.0)
        { }
    };
    ExtruderTrainAttributes extruder_attr[MAX_EXTRUDERS];
    unsigned int extruder_count;
    bool use_extruder_offset_to_offset_coords;
    Point3 machine_dimensions;
    std::string machine_name;

    std::ostream* output_stream;
    std::string new_line;

    double current_e_value; //!< The last E value written to gcode (in mm or mm^3)
    Point3 currentPosition;
    double currentSpeed; //!< The current speed (F values / 60) in mm/s
    double current_acceleration; //!< The current acceleration in the XY direction (in mm/s^2)
    double current_jerk; //!< The current jerk in the XY direction (in mm/s^3)
    double current_max_z_feedrate; //!< The current max z speed

    AABB3D total_bounding_box; //!< The bounding box of all g-code.

    /*!
     * The z position to be used on the next xy move, if the head wasn't in the correct z position yet.
     * 
     * \see GCodeExport::writeMove(Point, double, double)
     * 
     * \note After GCodeExport::writeMove(Point, double, double) has been called currentPosition.z coincides with this value
     */
    int current_layer_z;
    int isZHopped; //!< The amount by which the print head is currently z hopped, or zero if it is not z hopped. (A z hop is used during travel moves to avoid collision with other layer parts)

    int current_extruder;
    int currentFanSpeed;
    EGCodeFlavor flavor;

    double totalPrintTime; //!< The total estimated print time in seconds
    TimeEstimateCalculator estimateCalculator;
    
    bool is_volumatric;
    bool firmware_retract; //!< whether retractions are done in the firmware, or hardcoded in E values.

    unsigned int layer_nr; //!< for sending travel data

    int initial_bed_temp; //!< bed temperature at the beginning of the print.
protected:
    /*!
     * Convert an E value to a value in mm (if it wasn't already in mm) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param e the value to convert
     * \return the value converted to mm
     */
    double eToMm(double e);

    /*!
     * Convert a volume value to an E value (which might be volumetric as well) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param mm3 the value to convert
     * \return the value converted to mm or mm3 depending on whether the E axis is volumetric
     */
    double mm3ToE(double mm3);

    /*!
     * Convert a distance value to an E value (which might be linear/distance based as well) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param mm the value to convert
     * \return the value converted to mm or mm3 depending on whether the E axis is volumetric
     */
    double mmToE(double mm);

    /*!
     * \brief Write a move in the E-direction such that the filament is
     * retracted or unretracted to the specified distance.
     *
     * No checks are made for the maximum number of retractions.
     *
     * \param config The configuration from which to get the distance and speed.
     * \param new_retraction_distance The distance from the tip of the nozzle
     * where the filament is supposed to end up.
     * \param extruder_switch Whether this move is part of the extruder
     * switching procedure, which causes it to select different speeds.
     */
    void writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance, const bool extruder_switch);

public:
    
    GCodeExport();
    ~GCodeExport();

    /*!
     * Get the gcode file header (e.g. ";FLAVOR:UltiGCode\n")
     * 
     * \param print_time The total print time in seconds of the whole gcode (if known)
     * \param filament_used The total mm^3 filament used for each extruder or a vector of the wrong size of unknown
     * \param mat_ids The material GUIDs for each material.
     * \return The string representing the file header
     */
    std::string getFileHeader(const double* print_time = nullptr, const std::vector<double>& filament_used = std::vector<double>(), const std::vector<std::string>& mat_ids = std::vector<std::string>());

    void setLayerNr(unsigned int layer_nr);
    
    void setOutputStream(std::ostream* stream);

    bool getExtruderIsUsed(const int extruder_nr) const; //!< Returns whether the extruder with the given index is used up until the current meshgroup

    int getNozzleSize(const int extruder_nr) const;

    Point getExtruderOffset(const int id) const;

    std::string getMaterialGUID(const int extruder_nr) const; //!< returns the GUID of the material used for the nozzle with id \p extruder_nr

    Point getGcodePos(const int64_t x, const int64_t y, const int extruder_train) const;
    
    void setFlavor(EGCodeFlavor flavor);
    EGCodeFlavor getFlavor();
    
    void setZ(int z);
    
    void addLastCoastedVolume(double last_coasted_volume) 
    {
        extruder_attr[current_extruder].prime_volume += last_coasted_volume; 
    }
    
    Point3 getPosition();
    
    Point getPositionXY();

    int getPositionZ();

    int getExtruderNr();
    
    void setFilamentDiameter(unsigned int n, int diameter);
    
    double getCurrentExtrudedVolume();

    /*!
     * Get the total extruded volume for a specific extruder in mm^3
     * 
     * Retractions and unretractions don't contribute to this.
     * 
     * \param extruder_nr The extruder number for which to get the total netto extruded volume
     * \return total filament printed in mm^3
     */
    double getTotalFilamentUsed(int extruder_nr);

    /*!
     * Get the total estimated print time in seconds
     * 
     * \return total print time in seconds
     */
    double getTotalPrintTime();
    void updateTotalPrintTime();
    void resetTotalPrintTimeAndFilament();
    
    void writeComment(std::string comment);
    void writeTypeComment(PrintFeatureType type);

    /*!
     * Write a comment saying what (estimated) time has passed up to this point
     * 
     * \param time The time passed up till this point
     */
    void writeTimeComment(const double time);
    void writeLayerComment(int layer_nr);
    void writeLayerCountComment(int layer_count);
    
    void writeLine(const char* line);
    
    /*!
     * Reset the current_e_value to prevent too high E values.
     * 
     * The current extruded volume is added to the current extruder_attr.
     */
    void resetExtrusionValue();
    
    void writeDelay(double timeAmount);
    
    void writeMove(Point p, double speed, double extrusion_mm3_per_mm);
    
    void writeMove(Point3 p, double speed, double extrusion_mm3_per_mm);
private:
    void writeMove(int x, int y, int z, double speed, double extrusion_mm3_per_mm);
    /*!
     * The writeMove when flavor == BFB
     */
    void writeMoveBFB(int x, int y, int z, double speed, double extrusion_mm3_per_mm);
public:
    void writeRetraction(const RetractionConfig& config, bool force = false, bool extruder_switch = false);

    /*!
     * Start a z hop with the given \p hop_height
     * 
     * \param hop_height The height to move above the current layer
     */
    void writeZhopStart(int hop_height);

    /*!
     * End a z hop: go back to the layer height
     * 
     */
    void writeZhopEnd();

    /*!
     * Start the new_extruder: 
     * - set new extruder
     * - zero E value
     * - write extruder start gcode
     * 
     * \param new_extruder The extruder to start with
     */
    void startExtruder(int new_extruder);

    /*!
     * Switch to the new_extruder: 
     * - perform neccesary retractions
     * - fiddle with E-values
     * - write extruder end gcode
     * - set new extruder
     * - write extruder start gcode
     * 
     * \param new_extruder The extruder to switch to
     * \param retraction_config_old_extruder The extruder switch retraction config of the old extruder, to perform the extruder switch retraction with.
     * \param turn_off_extruder Should the old extruder be turned off
     * completely?
     */
    void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder = false);

    void writeCode(const char* str);
    
    /*!
     * Write the gcode for priming the current extruder train so that it can be used.
     * 
     * \param travel_speed The travel speed when priming involves a movement
     */
    void writePrimeTrain(double travel_speed);
    
    void writeFanCommand(double speed);
    
    void writeTemperatureCommand(int extruder, double temperature, bool wait = false);
    void writeBedTemperatureCommand(double temperature, bool wait = false);

    /*!
     * Write the command for setting the acceleration to a specific value
     */
    void writeAcceleration(double acceleration);

    /*!
     * Write the command for setting the jerk to a specific value
     */
    void writeJerk(double jerk);

    /*!
     * Write the command for setting the maximum z feedrate to a specific value
     */
    void writeMaxZFeedrate(double max_z_feedrate);

    /*!
     * Get the last set max z feedrate value sent in the gcode.
     * 
     * Returns a value <= 0 when no value is set.
     */
    double getCurrentMaxZFeedrate();

    /*!
     * Set member variables using the settings in \p settings
     * 
     * \param settings The meshgroup to get the global bed temp from and to get the extruder trains from which to get the nozzle temperatures
     */
    void preSetup(const MeshGroup* settings);

    /*!
     * Handle the initial (bed/nozzle) temperatures before any gcode is processed.
     * These temperatures are set in the pre-print setup in the firmware.
     * 
     * See FffGcodeWriter::processStartingCode
     * 
     * \param settings The meshgroup to get the global bed temp from and to get the extruder trains from which to get the nozzle temperatures
     */
    void setInitialTemps(const MeshGroup& settings);

    /*!
     * Override or set an initial nozzle temperature as written by GCodeExport::setInitialTemps
     * This is used primarily during better specification of temperatures in LayerPlanBuffer::insertPreheatCommand
     * 
     * \param extruder_nr The extruder number for which to better specify the temp
     * \param temp The temp at which the nozzle should be at startup
     */
    void setInitialTemp(int extruder_nr, double temp);

    /*!
     * Finish the gcode: turn fans off, write end gcode and flush all gcode left in the buffer.
     * 
     * \param endCode The end gcode to be appended at the very end.
     */
    void finalize(const char* endCode);

};

}

#endif//GCODEEXPORT_H

<commit_msg>Correct documentation of extruder_switch parameter<commit_after>//Copyright (c) 2013 <NAME>
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H

#include <stdio.h>
#include <deque> // for extrusionAmountAtPreviousRetractions
#include <sstream> // for stream.str()

#include "settings/settings.h"
#include "utils/intpoint.h"
#include "utils/NoCopy.h"
#include "timeEstimate.h"
#include "MeshGroup.h"
#include "commandSocket.h"
#include "RetractionConfig.h"

namespace cura {

/*!
 * Coasting configuration used during printing.
 * Can differ per extruder.
 * 
 * Might be used in the future to have different coasting per feature, e.g. outer wall only.
 */
struct CoastingConfig
{
    bool coasting_enable; //!< Whether coasting is enabled on the extruder to which this config is attached 
    double coasting_volume; //!< The volume leeked when printing without feeding
    double coasting_speed; //!< A modifier (0-1) on the last used travel speed to move slower during coasting
    double coasting_min_volume;  //!< The minimal volume printed to build up enough pressure to leek the coasting_volume
};


//The GCodeExport class writes the actual GCode. This is the only class that knows how GCode looks and feels.
//  Any customizations on GCodes flavors are done in this class.
class GCodeExport : public NoCopy
{
private:
    struct ExtruderTrainAttributes
    {
        Point3 prime_pos; //!< The location this nozzle is primed before printing
        bool prime_pos_is_abs; //!< Whether the prime position is absolute, rather than relative to the last given position
        bool is_primed; //!< Whether this extruder has currently already been primed in this print

        bool is_used; //!< Whether this extruder train is actually used during the printing of all meshgroups
        int nozzle_size; //!< The nozzle size label of the nozzle (e.g. 0.4mm; irrespective of tolerances)
        Point nozzle_offset;
        char extruderCharacter;
        std::string material_guid; //!< The GUID for the material used by this extruder

        std::string start_code;
        std::string end_code;
        double filament_area; //!< in mm^2 for non-volumetric, cylindrical filament

        double totalFilament; //!< total filament used per extruder in mm^3
        int currentTemperature;
        int initial_temp; //!< Temperature this nozzle needs to be at the start of the print.

        double retraction_e_amount_current; //!< The current retracted amount (in mm or mm^3), or zero(i.e. false) if it is not currently retracted (positive values mean retracted amount, so negative impact on E values)
        double retraction_e_amount_at_e_start; //!< The ExtruderTrainAttributes::retraction_amount_current value at E0, i.e. the offset (in mm or mm^3) from E0 to the situation where the filament is at the tip of the nozzle.

        double prime_volume; //!< Amount of material (in mm^3) to be primed after an unretration (due to oozing and/or coasting)
        double last_retraction_prime_speed; //!< The last prime speed (in mm/s) of the to-be-primed amount

        std::deque<double> extruded_volume_at_previous_n_retractions; // in mm^3

        ExtruderTrainAttributes()
        : prime_pos(0, 0, 0)
        , prime_pos_is_abs(false)
        , is_primed(false)
        , is_used(false)
        , nozzle_offset(0,0)
        , extruderCharacter(0)
        , start_code("")
        , end_code("")
        , filament_area(0)
        , totalFilament(0)
        , currentTemperature(0)
        , initial_temp(0)
        , retraction_e_amount_current(0.0)
        , retraction_e_amount_at_e_start(0.0)
        , prime_volume(0.0)
        , last_retraction_prime_speed(0.0)
        { }
    };
    ExtruderTrainAttributes extruder_attr[MAX_EXTRUDERS];
    unsigned int extruder_count;
    bool use_extruder_offset_to_offset_coords;
    Point3 machine_dimensions;
    std::string machine_name;

    std::ostream* output_stream;
    std::string new_line;

    double current_e_value; //!< The last E value written to gcode (in mm or mm^3)
    Point3 currentPosition;
    double currentSpeed; //!< The current speed (F values / 60) in mm/s
    double current_acceleration; //!< The current acceleration in the XY direction (in mm/s^2)
    double current_jerk; //!< The current jerk in the XY direction (in mm/s^3)
    double current_max_z_feedrate; //!< The current max z speed

    AABB3D total_bounding_box; //!< The bounding box of all g-code.

    /*!
     * The z position to be used on the next xy move, if the head wasn't in the correct z position yet.
     * 
     * \see GCodeExport::writeMove(Point, double, double)
     * 
     * \note After GCodeExport::writeMove(Point, double, double) has been called currentPosition.z coincides with this value
     */
    int current_layer_z;
    int isZHopped; //!< The amount by which the print head is currently z hopped, or zero if it is not z hopped. (A z hop is used during travel moves to avoid collision with other layer parts)

    int current_extruder;
    int currentFanSpeed;
    EGCodeFlavor flavor;

    double totalPrintTime; //!< The total estimated print time in seconds
    TimeEstimateCalculator estimateCalculator;
    
    bool is_volumatric;
    bool firmware_retract; //!< whether retractions are done in the firmware, or hardcoded in E values.

    unsigned int layer_nr; //!< for sending travel data

    int initial_bed_temp; //!< bed temperature at the beginning of the print.
protected:
    /*!
     * Convert an E value to a value in mm (if it wasn't already in mm) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param e the value to convert
     * \return the value converted to mm
     */
    double eToMm(double e);

    /*!
     * Convert a volume value to an E value (which might be volumetric as well) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param mm3 the value to convert
     * \return the value converted to mm or mm3 depending on whether the E axis is volumetric
     */
    double mm3ToE(double mm3);

    /*!
     * Convert a distance value to an E value (which might be linear/distance based as well) for the current extruder.
     * 
     * E values are either in mm or in mm^3
     * The current extruder is used to determine the filament area to make the conversion.
     * 
     * \param mm the value to convert
     * \return the value converted to mm or mm3 depending on whether the E axis is volumetric
     */
    double mmToE(double mm);

    /*!
     * \brief Write a move in the E-direction such that the filament is
     * retracted or unretracted to the specified distance.
     *
     * No checks are made for the maximum number of retractions.
     *
     * \param config The configuration from which to get the distance and speed.
     * \param new_retraction_distance The distance from the tip of the nozzle
     * where the filament is supposed to end up.
     * \param extruder_switch Whether this move is part of the extruder
     * switching procedure, which results in different retract commands for
     * machines that retract in firmware.
     */
    void writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance, const bool extruder_switch);

public:
    
    GCodeExport();
    ~GCodeExport();

    /*!
     * Get the gcode file header (e.g. ";FLAVOR:UltiGCode\n")
     * 
     * \param print_time The total print time in seconds of the whole gcode (if known)
     * \param filament_used The total mm^3 filament used for each extruder or a vector of the wrong size of unknown
     * \param mat_ids The material GUIDs for each material.
     * \return The string representing the file header
     */
    std::string getFileHeader(const double* print_time = nullptr, const std::vector<double>& filament_used = std::vector<double>(), const std::vector<std::string>& mat_ids = std::vector<std::string>());

    void setLayerNr(unsigned int layer_nr);
    
    void setOutputStream(std::ostream* stream);

    bool getExtruderIsUsed(const int extruder_nr) const; //!< Returns whether the extruder with the given index is used up until the current meshgroup

    int getNozzleSize(const int extruder_nr) const;

    Point getExtruderOffset(const int id) const;

    std::string getMaterialGUID(const int extruder_nr) const; //!< returns the GUID of the material used for the nozzle with id \p extruder_nr

    Point getGcodePos(const int64_t x, const int64_t y, const int extruder_train) const;
    
    void setFlavor(EGCodeFlavor flavor);
    EGCodeFlavor getFlavor();
    
    void setZ(int z);
    
    void addLastCoastedVolume(double last_coasted_volume) 
    {
        extruder_attr[current_extruder].prime_volume += last_coasted_volume; 
    }
    
    Point3 getPosition();
    
    Point getPositionXY();

    int getPositionZ();

    int getExtruderNr();
    
    void setFilamentDiameter(unsigned int n, int diameter);
    
    double getCurrentExtrudedVolume();

    /*!
     * Get the total extruded volume for a specific extruder in mm^3
     * 
     * Retractions and unretractions don't contribute to this.
     * 
     * \param extruder_nr The extruder number for which to get the total netto extruded volume
     * \return total filament printed in mm^3
     */
    double getTotalFilamentUsed(int extruder_nr);

    /*!
     * Get the total estimated print time in seconds
     * 
     * \return total print time in seconds
     */
    double getTotalPrintTime();
    void updateTotalPrintTime();
    void resetTotalPrintTimeAndFilament();
    
    void writeComment(std::string comment);
    void writeTypeComment(PrintFeatureType type);

    /*!
     * Write a comment saying what (estimated) time has passed up to this point
     * 
     * \param time The time passed up till this point
     */
    void writeTimeComment(const double time);
    void writeLayerComment(int layer_nr);
    void writeLayerCountComment(int layer_count);
    
    void writeLine(const char* line);
    
    /*!
     * Reset the current_e_value to prevent too high E values.
     * 
     * The current extruded volume is added to the current extruder_attr.
     */
    void resetExtrusionValue();
    
    void writeDelay(double timeAmount);
    
    void writeMove(Point p, double speed, double extrusion_mm3_per_mm);
    
    void writeMove(Point3 p, double speed, double extrusion_mm3_per_mm);
private:
    void writeMove(int x, int y, int z, double speed, double extrusion_mm3_per_mm);
    /*!
     * The writeMove when flavor == BFB
     */
    void writeMoveBFB(int x, int y, int z, double speed, double extrusion_mm3_per_mm);
public:
    void writeRetraction(const RetractionConfig& config, bool force = false, bool extruder_switch = false);

    /*!
     * Start a z hop with the given \p hop_height
     * 
     * \param hop_height The height to move above the current layer
     */
    void writeZhopStart(int hop_height);

    /*!
     * End a z hop: go back to the layer height
     * 
     */
    void writeZhopEnd();

    /*!
     * Start the new_extruder: 
     * - set new extruder
     * - zero E value
     * - write extruder start gcode
     * 
     * \param new_extruder The extruder to start with
     */
    void startExtruder(int new_extruder);

    /*!
     * Switch to the new_extruder: 
     * - perform neccesary retractions
     * - fiddle with E-values
     * - write extruder end gcode
     * - set new extruder
     * - write extruder start gcode
     * 
     * \param new_extruder The extruder to switch to
     * \param retraction_config_old_extruder The extruder switch retraction config of the old extruder, to perform the extruder switch retraction with.
     * \param turn_off_extruder Should the old extruder be turned off
     * completely?
     */
    void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder = false);

    void writeCode(const char* str);
    
    /*!
     * Write the gcode for priming the current extruder train so that it can be used.
     * 
     * \param travel_speed The travel speed when priming involves a movement
     */
    void writePrimeTrain(double travel_speed);
    
    void writeFanCommand(double speed);
    
    void writeTemperatureCommand(int extruder, double temperature, bool wait = false);
    void writeBedTemperatureCommand(double temperature, bool wait = false);

    /*!
     * Write the command for setting the acceleration to a specific value
     */
    void writeAcceleration(double acceleration);

    /*!
     * Write the command for setting the jerk to a specific value
     */
    void writeJerk(double jerk);

    /*!
     * Write the command for setting the maximum z feedrate to a specific value
     */
    void writeMaxZFeedrate(double max_z_feedrate);

    /*!
     * Get the last set max z feedrate value sent in the gcode.
     * 
     * Returns a value <= 0 when no value is set.
     */
    double getCurrentMaxZFeedrate();

    /*!
     * Set member variables using the settings in \p settings
     * 
     * \param settings The meshgroup to get the global bed temp from and to get the extruder trains from which to get the nozzle temperatures
     */
    void preSetup(const MeshGroup* settings);

    /*!
     * Handle the initial (bed/nozzle) temperatures before any gcode is processed.
     * These temperatures are set in the pre-print setup in the firmware.
     * 
     * See FffGcodeWriter::processStartingCode
     * 
     * \param settings The meshgroup to get the global bed temp from and to get the extruder trains from which to get the nozzle temperatures
     */
    void setInitialTemps(const MeshGroup& settings);

    /*!
     * Override or set an initial nozzle temperature as written by GCodeExport::setInitialTemps
     * This is used primarily during better specification of temperatures in LayerPlanBuffer::insertPreheatCommand
     * 
     * \param extruder_nr The extruder number for which to better specify the temp
     * \param temp The temp at which the nozzle should be at startup
     */
    void setInitialTemp(int extruder_nr, double temp);

    /*!
     * Finish the gcode: turn fans off, write end gcode and flush all gcode left in the buffer.
     * 
     * \param endCode The end gcode to be appended at the very end.
     */
    void finalize(const char* endCode);

};

}

#endif//GCODEEXPORT_H


{'fraction_non_alphanumeric': 0.07171789373361925, 'fraction_numerical': 0.004765308553728854, 'mean_word_length': 2.9142019717559284, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1022446', 'n_tokens_mistral': 8721, 'n_tokens_neox': 8162, 'n_words': 3291}