###############################################################################
#  Source https://github.com/strayr/strayr-k-macros/blob/e0807570a66d28735cf05143b105ab4ea6d9798f/mechanical_level_tmc2209.cfg
# 
#  Mechanical Gantry Calibration
#  
#  Requires TMC2209 drivers with UART control, some tuning and perhaps 
#  some printed endstops.
#
#  Based on on (depricated) M915 and now alternate G34 from Marlin
#  I beleive Prusa use this, certainly there's older videos advising to just
#  ram the gantry at full current into the the z-max stops.
#
#  It moves the gantry to the top of the travel, drops the current and then
#  does a force move to force the steppers to stall against the physical end
#  stops, transfering the level of the frame to the gantry. 
#
#  This is the only way to programatically level a multi-stepper single-driver 
#  gantry. It may also help with a dual-driver gantry on a bed-slinger design
#  or where the plane of the bed is less trustworthy than the frame.
#
#  It's particularly risky doing Z_TILT_ADJUST and SCREWS_TILT_CALCULATE
#  without a mechanical reference as if one side of the gantry or bed is prone
#  to droop, over time both bed and gantry will skew excessively but still read
#  as level, so this can help transfer "level" from the frame to the gantry and
#  then to the bed.
#
#  I don't recommend doing this in a START_PRINT, I call this if a 
#  SCREWS_TILT_CALCULATE shows some drift, althoughon an Ender 3 type printer
#  it's prudent to check the v-slot rollers for correct adjustment if drift is
#  observed.
#
#  It's probably best to run this and then do SCREWS_TILT_CALCULATE
#  until the bed is really level. IF you have dual Z steppers you can then
#  use Z_TILT_ADJUST for subsequent leveling of the gantry but make sure you
#  use the same points for gantry level as you use in SCREWS_TILT_CALCULATE
#
#  It may damage your printer if you do this at too high a current, or don't
#  have proper endstops.
#  
#            HERE BE DRAGONS!
#            YOU WERE WARNED!
#
#  Here's a video of this in action
#  https://www.youtube.com/watch?v=aVdIeIIpUAk
#  and the endstops for 2020 v-slot
#  https://www.thingiverse.com/thing:4848479

[gcode_macro MECHANICAL_GANTRY_CALIBRATION]
gcode:
    ### SET THIS DEFAULT CARFULLY - start really low
    {% set my_current = params.CURRENT|default(0.20)|float %} ; adjust crash current on the fly :D
    ###
    {% set oldcurrent = printer.configfile.settings["tmc2209 stepper_z"].run_current %}
    {% set oldhold = printer.configfile.settings["tmc2209 stepper_z"].hold_current %} 
    {% set x_max = printer.toolhead.axis_maximum.x %} 
    {% set y_max = printer.toolhead.axis_maximum.y %} 
    {% set z_max = printer.toolhead.axis_maximum.z %} 
    {% set fast_move_z = printer.configfile.settings["printer"].max_z_velocity %}
    {% set fast_move = printer.configfile.settings["printer"].max_velocity %}
    M117 {printer.homed_axes}
    {% if printer.homed_axes != 'xyz' %}
        G28 ; Home All Axes
    {% endif %}
    G90 ; absolute
    G0 X{x_max / 2} Y{y_max / 2} F{fast_move * 30 } ;put toolhead in the center of the gantry

    G0 Z{z_max -5} F{fast_move_z * 60 } ; go to the Z-max - 5 at speed max z speed ; CHANGED
    
    SET_TMC_CURRENT STEPPER=stepper_z CURRENT={my_current} ; drop current on Z stepper
    
    {% if printer.configfile.settings["stepper_z1"] %} ; test for dual Z
        SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={my_current} ; drop current
    {% endif %}

    CONDITIONAL_BEEP I=1
    G4 P200 ; Probably not necessary, it is here just for sure

    SET_KINEMATIC_POSITION Z={z_max - 25} ; Trick printer into beleiving the gantry is 25mm lower than it is ; CHANGED

    G1 Z{z_max} F{6 * 60} ; based on above figures, there will be 20mm worth of grinding ; CHANGED
    CONDITIONAL_BEEP I=2
    G4 P10000 ; wait 10 seconds
    G1 Z{z_max -6} F{6 * 60} ; move 4mm down
    CONDITIONAL_BEEP I=3
    G4 P200 ; same as the first one
    
    SET_TMC_CURRENT STEPPER=stepper_z CURRENT={oldcurrent} HOLDCURRENT={oldhold}

    {% if printer.configfile.settings["stepper_z1"] %} ; test for dual Z
        SET_TMC_CURRENT STEPPER=stepper_z1 CURRENT={oldcurrent} HOLDCURRENT={oldhold} ; reset current
    {% endif %}

    G1 Z{z_max -30} F{6 * 60} ; move to 30mm below z-max to allow homing movement

    G4 P200 ; same as the first one
    G28 Z ; we MUST home again as the ganty is really in the wrong place.

[gcode_macro G34]
gcode:
    MECHANICAL_GANTRY_CALIBRATION

[menu __main __setup __calib __mech_gantry_calibrate]
type: command
enable: {not printer.idle_timeout.state == "Printing"}
name: G34 Gantry Level
gcode:
    G34

[force_move]
enable_force_move: true ; enable FORCE_MOVE and SET_KINEMATIC_POSITION