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

[gcode_macro _check_fan_params]
gcode:
  {% set MAXIMUM = params.MAXIMUM|default(
      printer["gcode_macro set_fan_scaling"].maximum)|int %}
  {% set MINIMUM = params.MINIMUM|default(
      printer["gcode_macro set_fan_scaling"].minimum)|int %}

  {% if params.SCALE and params.SCALE|float <= 0 %}
    { action_raise_error("SCALE must be a positive value.") }
  {% elif MINIMUM < 0 or MINIMUM > 255 %}
    { action_raise_error("MINIMUM must be between 0 and 255.") }
  {% elif MAXIMUM < 0 or MAXIMUM > 255 %}
    { action_raise_error("MAXIMUM must be between 0 and 255.") }
  {% elif params.SPEED and (params.SPEED|int < 0 or params.SPEED|int > 255) %}
    { action_raise_error("SPEED must be between 0 and 255.") }
  {% elif params.BOOST and (params.BOOST|int < 0 or params.BOOST|int > 255) %}
    { action_raise_error("BOOST must be between 0 and 255.") }
  {% elif MINIMUM > MAXIMUM %}
    { action_raise_error("MINIMUM must be less than or equal to MAXIMUM.") }
  {% endif %}

# Sets optional scaling factor, minimum, and maximum applied to M106 commmand.
# If a MINIMUM greater than 0 is specified the fan will not stop unless an
# M107 command is issued. SET_FAN_SCALING always displays the current paramaters
# if scaling is active. SET_FAN_SCALING without any arguments will display the
# current scaling parameters without changing them.
[gcode_macro set_fan_scaling]
description: Sets fan scaling factors applied to M106 command. If a speed is
  provided it will be adjusted according to the scaling parameters.
  Usage: SET_FAN_SCALING [SCALE=<scale>] [BOOST=<boost>] [MAXIMUM=<max>]
                         [MINIMUM=<min>] [SPEED=<speed>]
variable_scale: 1.0
variable_boost: 0
variable_minimum: 0
variable_maximum: 255
variable_real_speed: 0
gcode:
  _CHECK_FAN_PARAMS{% for k in params %}{' '~k~'='~params[k]}{% endfor %}
  {% set SCALE = params.SCALE|default(scale)|float %}
  {% set BOOST = params.BOOST|default(boost)|float %}
  {% set MAXIMUM = params.MAXIMUM|default(maximum)|int %}
  {% set MINIMUM = params.MINIMUM|default(minimum)|int %}
  {% set SPEED = params.SPEED|default(real_speed)|int %}

  {% if SCALE != 1.0 or BOOST != 0 or MAXIMUM != 255 or MINIMUM != 0 %}
    {action_respond_info("Fan: Scale: %.2f Minimum:%i Maximum: %i Speed: %i"|
                         format(SCALE, MINIMUM, MAXIMUM, SPEED))}
  {% endif %}

  # Update parameters on change.
  {% if params|length > 0 %}
    SET_GCODE_VARIABLE MACRO=set_fan_scaling VARIABLE=scale VALUE="{SCALE}"
    SET_GCODE_VARIABLE MACRO=set_fan_scaling VARIABLE=boost VALUE="{BOOST}"
    SET_GCODE_VARIABLE MACRO=set_fan_scaling VARIABLE=minimum VALUE="{MINIMUM}"
    SET_GCODE_VARIABLE MACRO=set_fan_scaling VARIABLE=maximum VALUE="{MAXIMUM}"
    # Run fan at adusted speed
    M106 S{SPEED}
  {% endif %}
  # Dummy argument block for Mainsail
  {% set dummy = None if True else "
  {% set dummy = params.SCALE|default(1.0)|float %}
  {% set dummy = params.BUMP|default(0)|int %}
  {% set dummy = params.MAXIMUM|default(255)|int %}
  {% set dummy = params.MINIMUM|default(0)|int %}
  {% set dummy = params.SPEED|default(current speed)|int %}
  " %} # End argument block for Mainsail

[gcode_macro reset_fan_scaling]
description: Clears all fan scaling factors.
  Usage: RESET_FAN_SCALING
gcode:
  SET_FAN_SCALING SCALE=1.0 BOOST=0 MAXIMUM=255 MINIMUM=0

[gcode_macro m106]
description: Wraps M106 to implement scaling overrides.
rename_existing: M106.6245197
gcode:
  {% set S = params.S|default(255)|int %}
  {% set scale = printer["gcode_macro set_fan_scaling"] %}
  SET_GCODE_VARIABLE MACRO=set_fan_scaling VARIABLE=real_speed VALUE="{S}"
  M106.6245197 S{((((S + scale.boost) * scale.scale) | round | int,
                   scale.minimum) | max, scale.maximum) | min}
