# Copyright (C) 2022 Justin Schuh <code@justinschuh.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.

[gcode_macro print_start]
description: Inserted by slicer at start of print.
  Usage: PRINT_START BED=<temp> EXTRUDER=<temp> [CHAMBER=<temp>]
                     [MESH_MIN=<x,y>] [MESH_MAX=<x,y>] [LAYERS=<num>]
                     [NOZZLE_SIZE=<mm>]
gcode:
  CHECK_KM_CONFIG # Need this in case startup errors were missed.

  CLEAR_PAUSE
  {% set BED = params.BED|default(params.BED_TEMP)|float %}
  {% set EXTRUDER = params.EXTRUDER|default(params.EXTRUDER_TEMP)|float %}
  {% set CHAMBER = params.CHAMBER|default(0)|float
                   if "chamber" in printer.heaters.available_heaters else 0.0 %}
  {% set settings = printer["gcode_macro print_start_set"].settings %}
  {% set MESH_MIN = params.MESH_MIN|default(settings.MESH_MIN)|default(None) %}
  {% set MESH_MAX = params.MESH_MAX|default(settings.MESH_MAX)|default(None) %}
  {% set LAYERS = params.LAYERS|default(settings.LAYERS)|default(0)|int %}
  {% set NOZZLE_SIZE = params.NOZZLE_SIZE|default(settings.NOZZLE_SIZE)|
         default(printer.configfile.settings.extruder.nozzle_diameter)|float %}
  {% set km = printer["gcode_macro _km_globals"] %}
  {% set actions_at_temp = km.start_level_bed_at_temp or
                           km.start_quad_gantry_level_at_temp or
                           start_z_tilt_adjust_at_temp %}
  {% set bed_at_target = (BED - printer.heater_bed.temperature)|abs < 0.3 %}
  {% set bed_overshoot = (BED + (km.start_bed_heat_overshoot if
             (BED and not bed_at_target) else 0.0),
           printer.configfile.settings.heater_bed.max_temp ) | min %}

  INIT_LAYER_GCODE LAYERS="{LAYERS}"
  {% if CHAMBER > 0.0 %}
    M141 S{CHAMBER}
  {% endif %}
  # Start bed heating
  M140 S{bed_overshoot}
  {% if actions_at_temp %}
    # If we're going to run a bed level we heat the extruder only part way to
    # avoid oozing all over the bed while probing.
    M104 S{(km.start_extruder_preheat_scale * EXTRUDER)|round(0,'ceil')|int}
  {% else %}
    M104 S{EXTRUDER}
  {% endif %}
  # home all axes
  G28
  G90
  # Skip this if the bed was already at target when START_PRINT was called.
  {% if BED > 0.0 and not bed_at_target %}
    PARK
    # Overshoot the target a bit.
    M190 S{bed_overshoot}
    G4 P{km.start_bed_heat_delay / 2}
    M190 R{BED} # Settle down after the overshoot.
    G4 P{km.start_bed_heat_delay / 2}
  {% endif %}
  {% if CHAMBER > 0.0 %}
    _KM_PARK_IF_NEEDED HEATER="chamber" RANGE=ABOVE
    M191 S{CHAMBER}
  {% endif %}
  {% if actions_at_temp %}
    {% if km.start_extruder_set_target_before_level %}
      M104 S{EXTRUDER} # set the final extruder target temperature
    {% endif %}
    {% if km.start_home_z_at_temp and not bed_at_target %}
      G28 Z # Re-home only the Z axis now that the bed has stabilized.
    {% endif %}
    {% if km.start_z_tilt_adjust_at_temp %}
      Z_TILT_ADJUST
    {% endif %}
    {% if km.start_quad_gantry_level_at_temp %}
      QUAD_GANTRY_LEVEL
    {% endif %}
    {% if km.start_level_bed_at_temp %}
      BED_MESH_CALIBRATE_FAST{% if MESH_MIN %} MESH_MIN={MESH_MIN}{% endif
                           %}{% if MESH_MAX %} MESH_MAX={MESH_MAX}{% endif %}
    {% endif %}
    {% if not km.start_extruder_set_target_before_level %}
      M104 S{EXTRUDER} # set the final extruder target temperature
    {% endif %}
    G4
  {% endif %}
  # Wait for extruder to reach temperature
  _KM_PARK_IF_NEEDED HEATER={printer.toolhead.extruder} RANGE=ABOVE
  M109 S{EXTRUDER}
  M118 checkpoint 1
  # apply Z offset for bed surface (just in case it was reset).
  _APPLY_BED_SURFACE_OFFSET
  {% if km.start_gcode_before_print %}{ km.start_gcode_before_print }{% endif %}
  {% if km.start_purge_length > 0.0 %}
    DRAW_PURGE_LINE WIDTH="{NOZZLE_SIZE * 1.25}" HEIGHT="{NOZZLE_SIZE * 0.625
                    }"{% if MESH_MIN %} PRINT_MIN={MESH_MIN}{% endif
                    %}{% if MESH_MAX %} PRINT_MAX={MESH_MAX}{% endif %}
                    M118 checkpoint 2
  {% endif %}
  M118 Einde gcode_macro print_start

[gcode_macro _km_park_if_needed]
description: Parks the extruder if the current temperature of the supplied heater is not within the specified target range.
  Usage: _KM_PARK_IF_NEEDED HEATER=<heater> RANGE=[<percentage>|ABOVE|BELOW]
gcode:
  # This needs to get called as its own macro to get the current temp evaluated.
  {% set HEATER = params.HEATER %}
  {% set RANGE = (params.RANGE|default(1))|string|upper %}

  {% if printer[HEATER].target %}
    {% if RANGE == "ABOVE" %}
      {% if printer[HEATER].temperature < printer[HEATER].target %}
        M118 checkpoint PARK 01
        PARK
        M118 checkpoint PARK 1
      {% endif %}
    {% elif RANGE == "BELOW" %}
      {% if printer[HEATER].temperature > printer[HEATER].target %}
        M118 checkpoint PARK 02
        PARK
        M118 checkpoint PARK 2
      {% endif %}
    {% elif (printer[HEATER].temperature - printer[HEATER].target)|abs >
             (printer[HEATER].target * RANGE|float * 0.01)|abs %}
      M118 checkpoint PARK 03
      PARK
      M118 checkpoint PARK 3
    {% endif %}
  {% endif %}
  M118 Einde gcode_macro _km_park_if_needed

[gcode_macro print_start_set]
description: Inserted by slicer to set values used by PRINT_START.
  Usage: PRINT_START_SET <VARIABLE>=<value>
variable_settings: {}
gcode:
  {%for k in params %}
    {% set dummy = settings.__setitem__(k|upper, params[k]) %}
  {% endfor %}
  M118 Einde gcode_macro print_start_set

[gcode_macro print_end]
description: Inserted by slicer at end of print.
  Usage: PRINT_END
gcode:
  {% set km = printer["gcode_macro _km_globals"] %}
  {% set toolhead = printer.toolhead %}
  {% set max_x = km.print_max[0] %}
  {% set max_y = km.print_max[1] %}
  {% set max_z = toolhead.axis_maximum.z %}
  {% set x_safe = (max_x - toolhead.position.x, 2.0)|min %}
  {% set y_safe = (max_y - toolhead.position.y, 2.0)|min %}
  {% set z_safe = (max_z - toolhead.position.z, 2.0)|min %}

  # Wipe if we're not cancelling a paused print.
  {% if not printer.pause_resume.is_paused %}
    G91
    G0 Z{z_safe} E-1.0 F{km.travel_speed_z * 2} ; move nozzle up
    G0 X{x_safe} Y{y_safe} E-1.0 F{km.travel_speed_xy} ; remove stringing
  {% endif %}

  # Small retract to prevent ooze
  G92 E0
  G1 E-5.0 F3600
  M400

  {% if km.start_clear_adjustments_at_end != 0 %}
    RESET_HEATER_SCALING
    RESET_FAN_SCALING
    M220 S100
    M221 S100
  {% endif %}
  _RESET_LAYER_GCODE
  _RESET_VELOCITY_LIMITS
  TURN_OFF_HEATERS
  M107; turn off fan
  # Park the toolhead and present the bed
  PARK Y="{km.start_end_park_y}"
  M84 ; disable steppers
  CLEAR_PAUSE
  M118 Einde gcode_macro print_end
