/*
 * Multi axis set zero script
 *
 * Description of the script: 
 *  This script changes "standoff" setting (found on "Home position" page in the mDrive Direct Control "Settings") so that the current position becomes the home position. 
 *  The script is very convenient for calibrating and configuring new stages, as well as for changing the zero position
 * 
 * How to use:
 *  - manually move your positioner to a desired position
 *  - launch this script and wait for completion
 *  As a result your positioner will return to the starting position and all subsequent calls to "homing" function will bring it there.
 * 
 * Note:
 *  This is a rather difficult script to learn, since it uses a large number of commands and structures.
 * 
 * Important: 
 *  Homing settings are saved into RAM and will be lost when controller is powered down. If you wish to save these settings to non-volatile memory you should either pick "Save to flash" on the mDrive Direct Control main Settings page or call "command_save_settings()" at the end of the script.
 *  To run the script, upload it to the mDrive Direct Control software. For multi-controller operation, open them in a single multi-axis mDrive Direct Control window
 */

var axes = [];
var number_of_axes = 0;
var last_serial = 0;
while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
    axes[number_of_axes] = new_axis(serial);
    log("Found axis " + number_of_axes + " with serial number " + serial);
    number_of_axes++;
    last_serial = serial;
}

for (var i = 0; i < number_of_axes; i++)
{
    set_zero(axes[i]);
}

function set_zero(axis)
{
    axis.command_stop(); // send STOP command (does immediate stop)
    
    var h = axis.get_home_settings(); // read homing settings from the controller
    h.HomeDelta = 0; // set "HomeDelta" parameter in "home_position" structure to 0
    h.uHomeDelta = 0; // set "uHomeDelta" parameter in "home_position" structure to 0
    var saved_fast = h.FastHome; // save "FastHome" parameter from "home_position" structure to a variable
    var saved_ufast = h.uFastHome; // save "uFastHome" parameter from "home_position" structure to a variable
    if (h.HomeFlags & HOME_MV_SEC_EN != 0) // if homing settings have two homing phases turned on
    {
        h.FastHome = 100; // set "FastHome" parameter in "home_position" structure (first movement speed) to 100 steps/s: this is required to avoid slip at the end of the first phase
        h.uFastHome = 0; // set "uFastHome" parameter in "home_position" structure to 0
    }
    axis.set_home_settings(h); // write homing settings into the controller

    var old_pos = axis.get_status().CurPosition; // save whole step part of the initial position into a variable
    var old_upos = axis.get_status().uCurPosition; // save microstep part of the initial position into a variable
    axis.command_home(); // send HOME command (find home position)
    do { msleep(100); } while (axis.get_status().MvCmdSts == (MVCMD_HOME | MVCMD_RUNNING)); // query controller state every 100 ms while movement state is "homing command is being executed"
    if (axis.get_status().MvCmdSts != MVCMD_HOME)  // if current state is not "homing completed successfully" (MVCMD_RUNNING unset, MVCMD_ERROR unset, last command MVCMD_HOME) then homing was interrupted
    {
        h.FastHome = saved_fast; // set "FastHome" parameter in "home_position" structure to a saved value
        h.uFastHome = saved_ufast; // set "uFastHome" parameter in "home_position" structure to a saved value
        axis.set_home_settings(h); // write movement settings into the controller (this restores the initial settings)
        throw "Script aborted: homing failed."; // throw an exception and terminate
    }

    var new_pos = axis.get_status().CurPosition; // read whole part of new position into "new_pos" variable
    var new_upos = axis.get_status().uCurPosition; // read microstep part of new position into "new_upos" variable
    h.HomeDelta = old_pos-new_pos; // set "HomeDelta" parameter in "home_position" structure to this value
    h.uHomeDelta = old_upos-new_upos; // set "uHomeDelta" parameter in "home_position" structure to this value
    h.FastHome = saved_fast; // set "FastHome" parameter in "home_position" structure to a saved value
    h.uFastHome = saved_ufast; // set "uFastHome" parameter in "home_position" structure to a saved value
    axis.set_home_settings(h); // write movement settings into the controller
    axis.command_move(old_pos, old_upos); // move to initial position
    do { msleep(100); } while (axis.get_status().MvCmdSts == (MVCMD_MOVE | MVCMD_RUNNING)); // query controller state every 100 ms while movement state is "movement command is being executed"
    if (axis.get_status().MvCmdSts != MVCMD_MOVE)  // if current state is not "movements completed successfully" (MVCMD_RUNNING unset, MVCMD_ERROR unset, last command MVCMD_MOVE) then movement was interrupted
    {
        throw "Script aborted: return to position failed."; // throw an exception and terminate
    }
    axis.command_zero(); // send ZERO command (sets current position and encoder value to zero)
}

log("Done."); // log success
