stepcfg2.c -- Configure an 8 axis XMP to support 8 Servos and 8 Steppers
/* stepCfg2.c */

/* Copyright(c) 1991-2002 by Motion Engineering, Inc.  All rights reserved.
 *
 * This software  contains proprietary and  confidential information  of
 * Motion Engineering Inc., and its suppliers.  Except as may be set forth
 * in the license agreement under which  this software is supplied, use,
 * disclosure, or  reproduction is prohibited without the prior express
 * written consent of Motion Engineering, Inc.
 */

#if defined(MEI_RCS)
static const char MEIAppRCS[] =
    "$Header: /MainTree/XMPLib/XMP/app/stepcfg2.c 8     7/23/01 2:36p Kevinh $";
#endif

/*

:Configure an 8 axis XMP to support 8 Servos and 8 Steppers

The XMP controller has the capability to control 8 servo axes as well
 as 8 stepper axes on a single controller.  The XMP uses the Xcvr
 IO for axes 0 - 7 for stepper outputs on axes 8 - 15.  This is obtained
 by redirecting the stepper controller pointer from Xcvr hardware that
 would be present on a 16 axis controller to Xcvr's 0 - 7.

Certain limitations apply:
 -No Steppers can be configured on the first 8 axes.
 -The 2nd 8 axes will not have any IO (User, Home, PosLimits, AmpEnables, etc).
 -No encoder loopback is availiable on the Stepper axes.
 -The IN_FINE position criteria must be increased for motion done to return.

The following code performs the necessary configurations to run a Step/Dir
 stepper on Motor 8 using Xcvr0 A & B.  Define CONFIG_ONLY to configure the
 XMP, but not perform any motion.

Warning!  This is a sample program to assist in the integration of the
 XMP motion controller with your application.  It may not contain all
 of the logic and safety features that your application requires.

*/



#include <stdlib.h>
#include <stdio.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    stepCfg2Main

argMainRENAME(main, stepCfg2)
#endif

#define AXIS_COUNT      (16)
#define FILTER_COUNT    (16)
#define MS_COUNT        (16)
#define MOTOR_COUNT     (16)

/* Command line arguments and defaults */
long    axisNumber[AXIS_COUNT]      = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
long    filterNumber[FILTER_COUNT]  = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
long    motorNumber[MOTOR_COUNT]    = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
long    motionNumber                = -1;   /* Use next availiable MS */
long    width                       = 255;

Arg argList[] = {
    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* LOOPBACK_CONFIG : TRUE = count step pulses in encoder register, FALSE = no loopback */
#define LOOPBACK_CONFIG     TRUE
/* output pulse width  (seconds) */
#define PULSE_WIDTH_VALUE   (2.55e-5)

#undef CW_CCW_STEPPERS

#if defined CW_CCW_STEPPERS
#define IO_CONFIG_A         (MEIMotorTransceiverConfigCW)
#define IO_CONFIG_B         (MEIMotorTransceiverConfigCCW)
#else
#define IO_CONFIG_A         (MEIMotorTransceiverConfigSTEP)
#define IO_CONFIG_B         (MEIMotorTransceiverConfigDIR)
#endif

#define TRANSCEIVER_ID_A    (MEIXmpMotorIOBitXCVR_A)
#define TRANSCEIVER_ID_B    (MEIXmpMotorIOBitXCVR_B)
#define INVERT_BIT          (FALSE)

int
    main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlConfig    config;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIFilter           filter;

    MPIAxis             axis;
    MPIAxisConfig       axisConfig;     /* Axis configuration */

    MPIMotion           motion;

    MPIMotor            motorZero;
    MPIMotor            motorEight;
    MPIMotorConfig      motorZeroConfig;
    MPIMotorConfig      motorEightConfig;

    MEIMotorConfig      motorZeroConfigXmp;
    MEIMotorConfig      motorEightConfigXmp;

    MPIMotionParams params;     /* motion parameters */
    MPITrajectory   trajectory; /* motion trajectory */
    double          position;   /* final target position */

    long    argIndex;
    long    returnValue;
    long    motionDone = FALSE;
    long    stepperNumber;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &controlAddress);

    /* Parse command line for application-specific arguments */
    while (argIndex < argc) {
        long    argIndexNew;

        argIndexNew = argSet(argList, argIndex, argc, argv);

        if (argIndexNew <= argIndex) {
            argIndex = argIndexNew;
            break;
        }
        else {
            argIndex = argIndexNew;
        }
    }

    /* Check for unknown/invalid command line arguments */
    if ((argIndex < argc)) {
        meiPlatformConsole("usage: %s %s\n",
                            argv[0],
                            ArgUSAGE);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Get controller status */
    returnValue =
        mpiControlConfigGet(control,
                            &config,
                            NULL);
    msgCHECK(returnValue);

    /* Configure controller for 16 Axes, Filters, and Motors */
    config.axisCount            = AXIS_COUNT;
    config.filterCount          = FILTER_COUNT;
    config.motionCount          = MS_COUNT;
    config.motorCount           = MOTOR_COUNT;

    /* Set controller configuration */
    returnValue =
        mpiControlConfigSet(control,
                            &config,
                            NULL);
    msgCHECK(returnValue);

    /* Display controller configuration */
    printf("Controller:\n"
            "\taxisCount %d\n"
            "\tadcCount  %d\n"
            "\t cmdDacCount  %d\n"
            "\tfilterCount %d\n"
            "\tmotionCount %d\n"
            "\tmotorCount %d\n"
            "\tsequenceCount %d\n"
            "\tsampleRate    %d\n",
            config.axisCount,
            config.adcCount,
            config.cmdDacCount,
            config.filterCount,
            config.motionCount,
            config.motorCount,
            config.sequenceCount,
            config.sampleRate);

    /* Create filter object */
    filter =
        mpiFilterCreate(control,
                        filterNumber[8]);
    msgCHECK(mpiFilterValidate(filter));

    /* Configure Filter for Step algorithm */
    if (returnValue == MPIMessageOK) {
        MEIFilterConfig filterConfigXmp;

        returnValue =
            mpiFilterConfigGet(filter,
                               NULL,
                               &filterConfigXmp);
        msgCHECK(returnValue);

        filterConfigXmp.Algorithm = MEIXmpAlgorithmNONE;

        returnValue =
            mpiFilterConfigSet(filter,
                               NULL,
                               &filterConfigXmp);
        msgCHECK(returnValue);

    }

    /* Create axis object*/
    axis =
        mpiAxisCreate(control,
                      axisNumber[8]);       /* axis number */
    msgCHECK(mpiAxisValidate(axis));

    /* Configure axis */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    axisConfig.inPosition.tolerance.positionFine = (float)10E10;

    returnValue =
        mpiAxisConfigSet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /* Create motion object, append axis */
    motion =
        mpiMotionCreate(control,
                        motionNumber,   /* motion supervisor number */
                        axis);          /* axis object handle */
    msgCHECK(mpiMotionValidate(motion));

    /* Set up motion parameters */
    trajectory.velocity     =  1000.0;      /* counts per sec */
    trajectory.acceleration = 10000.0;      /* counts per sec * sec */
    trajectory.deceleration = 10000.0;

    position = 2000.0;          /* target position (counts) */

    params.trapezoidal.trajectory   = &trajectory;
    params.trapezoidal.position     = &position;

    /* Create Motor0 Object */
    motorZero =
        mpiMotorCreate(control,
                       0);
    msgCHECK(mpiMotorValidate(motorZero));

    /* Create Motor8 Object */
    motorEight =
        mpiMotorCreate(control,
                       8);
        msgCHECK(mpiMotorValidate(motorEight));

    /* Get Motor0's Configuration */
    returnValue =
        mpiMotorConfigGet(motorZero,
                         &motorZeroConfig,
                         &motorZeroConfigXmp);
    msgCHECK(returnValue);

    /* Configure Xcvr A/B for Step/Dir */
    motorZeroConfigXmp.Transceiver[TRANSCEIVER_ID_A].Config = IO_CONFIG_A;
    motorZeroConfigXmp.Transceiver[TRANSCEIVER_ID_B].Config = IO_CONFIG_B;
    motorZeroConfigXmp.Transceiver[TRANSCEIVER_ID_A].Invert = INVERT_BIT;
    motorZeroConfigXmp.Transceiver[TRANSCEIVER_ID_B].Invert = INVERT_BIT;

    returnValue =
        mpiMotorConfigSet(motorZero,
                          &motorZeroConfig,
                          &motorZeroConfigXmp);
    msgCHECK(returnValue);

    printf("StepControl Pointer for Motor 0: 0x%X\n", motorZeroConfigXmp.Commutation.StepControl);

    /* Get MotorEight's Configuration */
    returnValue =
        mpiMotorConfigGet(motorEight,
                         &motorEightConfig,
                         &motorEightConfigXmp);
    msgCHECK(returnValue);

    motorEightConfigXmp.Stepper.PulseWidth = (float)PULSE_WIDTH_VALUE;
    motorEightConfigXmp.Stepper.Loopback = LOOPBACK_CONFIG;

    /* Set motorEight's Commutation.StepControl register equal to MotorZero's */
    stepperNumber = motorNumber[0];

    returnValue =
        meiMotorConfigStepper(motorEight,
                              &motorEightConfigXmp,
                              stepperNumber);  /* StepControl source location */
    msgCHECK(returnValue);

    /*  Disable limit error */
    motorEightConfig.event[MPIEventTypeLIMIT_ERROR].action          = MPIActionNONE;
    motorEightConfig.event[MPIEventTypeLIMIT_ERROR].trigger.error   = (float)10E10;

    /*  Disable home event  */
    motorEightConfig.event[MPIEventTypeHOME].action         = MPIActionNONE;

    /*  Disable amp fault event */
    motorEightConfig.event[MPIEventTypeAMP_FAULT].action    = MPIActionNONE;

    /*  Disable neg. HW limit event */
    motorEightConfig.event[MPIEventTypeLIMIT_HW_NEG].action = MPIActionNONE;

    /*  Disable pos. HW limit event */
    motorEightConfig.event[MPIEventTypeLIMIT_HW_POS].action = MPIActionNONE;

    /*  Disable neg. SW limit event */
    motorEightConfig.event[MPIEventTypeLIMIT_SW_NEG].action = MPIActionNONE;

    /*  Disable pos. SW limit event */
    motorEightConfig.event[MPIEventTypeLIMIT_SW_POS].action = MPIActionNONE;

    /*  Disable Encoder Fault event */
    motorEightConfig.event[MPIEventTypeENCODER_FAULT].action= MPIActionNONE;

    /*  Configure Motor 8 as Stepper */
    motorEightConfig.type = MPIMotorTypeSTEPPER;

    returnValue =
        mpiMotorConfigSet(motorEight,
                          &motorEightConfig,
                          &motorEightConfigXmp);
    msgCHECK(returnValue);

    /* Write MS/Axis map to controller and clear any events */
    returnValue =
        mpiMotionAction(motion,
                        MPIActionRESET);
    msgCHECK(mpiMotionValidate(motion));

    /* Verify it worked */
    returnValue =
        mpiMotorConfigGet(motorEight,
                         &motorEightConfig,
                         &motorEightConfigXmp);
    msgCHECK(returnValue);

    printf("New StepControl Pointer for Motor 8: 0x%X\n", motorEightConfigXmp.Commutation.StepControl);

#ifndef CONFIG_ONLY

    printf("Motor 8 configured for Stepper using Xcvr 0 & 1.\n"
           "Starting move on Motor 8...\n");

    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {
        MPIStatus   status;

        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateIDLE: {
                motionDone = TRUE;

                /* Wait for the motor to settle */
                meiPlatformSleep(300);  /* msec */

                break;
            }

            case MPIStateERROR: {
                motionDone = TRUE;

                /* Clear any error condition(s) */
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                msgCHECK(returnValue);

                /* Wait for reset to take effect */
                meiPlatformSleep(100);      /* msec */

                break;
            }
            default: {
                break;
            }
        }
    }

    position = 0.0;         /* target position (counts) */
    params.trapezoidal.position     = &position;

    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);

#endif /* CONFIG_ONLY */

    /* Delete object handles */
    returnValue = mpiMotorDelete(motorZero);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motorEight);
    msgCHECK(returnValue);

    returnValue = mpiFilterDelete(filter);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}