.



MPI 03.04.xx Sample Functions (Last Updated: 21Dec06)

Below is a list of MPI-related functions that you can cut and paste into your own application code. These cut and paste functions are useful for accomplishing many common tasks, such as enabling every amplifier associated with a motion supervisor.

Note: The MPI related sample functions provided below are for MPI 03.04 and prior releases only.

Short descriptions of the functions are located at the top of the file, while full descriptions of the functions are located further down in the document. New functions will be added to this library, and the latest version will always be available here.

If you find a bug in one of these functions, please submit the bug to tech@motioneng.com.

Note: The functions located on this page are not officially supported by MEI. Feel free to use them at your own discretion.



CutNPaste.c --
/**********************************************************************

    A collection of various potentially useful functions. Nothing in here
    approaches supported status.

    Feel free to add, but not remove functions from this file. We only ask
    that you add some comments above each function and add the name and 
    one line (or so) description to the following list to make it easy
    for others to use this file.

    After adding something to this file, PLEASE compile a program with it
    to make sure it isn't broke! Make sure to add appropriate #includes.

**********************************************************************/


/***********************************************************************

Listing of functions in this file:

* trapMove()            Commands a simple trap move. It checks for an
                        appropriate state first and returns error codes, if
                        appropriate.

* sCurveMove()      Commands a simple S Curve move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* ptMove()          Commands a pt move. Can be used to make appended lists.

* pvtMove()         Commands a pvt move. Can be used to make appended lists.

* velMove()         Commands a simple vel move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* isMotionDone()     returns a 1 if the motion is idle, a 0 if it is not.

* waitForMotionDone()   Stalls the program in a 10 msec polling loop until it
                        gets an MPIMotionIDLE

* clearError()          clears all the errors on an MS and enables the amps on that MS.

* motionAxisLoop()      For every axis attached to a motion supervisor (perform some action) [EXAMPLE]

* axisMotorLoop()       For every motor attached to an axis (perform some action) [EXAMPLE]

* motionMotorLoop()     For every motor attached to a motion supervisor (perform some action) [EXAMPLE]

* axisAmpEnable()       Enable the amplifier for every motor attached to an axis

* axisAmpDisable()      Disable the amplifier for every motor attached to an axis

* motionAmpEnable()     Enable the amplifier for every motor attached to a motion supervisor

* motionAmpDisable()    Disable the amplifier for every motor attached to a motion supervisor

* setIp()           configures the program to use a controller at address "server"

* parseCommandLine()    Parsing for apps that need command line arguments (example)
  
* basicParsing()    Perform basic command line parsing. (-control -server -port -trace)

* programInit() / programCleanup():     
    A bare minimum object creation / deletion for programs of the scope of
    motion1 or so.
  
* programInitSingle()       Create and initialize MPI objects.  
                                [One of each object -- Use as a model]

* programCleanupSingle()    Perform certain cleanup actions and delete MPI objects
                                [One of each object -- Use as a model]

* programInitMultiple()     Create and initialize MPI objects.  
                                [Arrays of some objects -- Use as a model]

* programCleanupMultiple()  Perform certain cleanup actions and delete MPI objects
                                [Arrays of some objects -- Use as a model]

* programInitSingleWithMapping()    Create and initialize MPI objects, and place MS's axis map on XMP
                                        [One of each object -- Use as a model]

* programInitMultipleWithMapping()  Create and initialize MPI objects, and place MSs' axis maps on XMP
                                        [Arrays of some objects -- Use as a model]

* homeLimitOnInput()    Configure Home Limit to be triggered on the Home Input rather than the capture

* enableUserLimit()     Configures and enables one user limit

* disableUserLimit()    Disables and erases the configuration of one user limit

* userLimitEnable()     Enables or disables one user limit
                            This function does not change (most of) the configuration of a user limit.

* sequenceCommandAdd() Creates a command (MPICommand object) and appends it to
                        sequence's list of commands.

* sequenceProgramCreate()    Shows how one can create a MPISequence program.


* sequenceProgramDelete(MPISequence *sequence)  Removes and deletes all command objects on sequence's
                                                   command list and then deletes sequence.

* sequenceRun()     Starts a sequence, waits for the user to press a key and then
                       stops the sequence.

* recordData()      Start the XMP's recorder, get data, and stop the recorder 

* configureRecorder()   Example of how to configure the data recorder object


* stopRecorder()    Stops the data recorder ignoring the MPIRecorderMessageSTOPPED 
                        message if the recorder is already stopped.

* setTorqueLimits()    EventType is MPIEventTypeLIMIT_USERn -- Choose the user limit you want to use. 
                         The axis will abort out after continually exceeding the high or low limit 
                         for duration seconds. highLimit sets the positive torque limit. lowLimit 
                         sets the negative torque limit.

* controlAddressGet()    Works like mpiControlMemoryGet, but gets the address of location
in the XMP memory space. This is the same number as you see as
the address in VM3.
* controlAddrToAddr() Works like mpiControlMemorySet, but writes one firmware address
to another. Host / controller memory spaces can be ignored. Useful in pointer hocus pocus like can be done in VM3. * SetDualLoop() Configures a filter to be dual loop. Requires using the PIV algorithm.
** add yours here ** ***********************************************************************/ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <math.h> #include "stdmpi.h" #include "stdmei.h" #include "apputil.h" long trapMove(MPIMotion *motion, MPITrajectory *trajectory, double *position); long sCurveMove(MPIMotion *motion, MPITrajectory *trajectory, double *position); long ptMove(MPIMotion motion, double point[], double time[], long numPoints, long final); long pvtMove(MPIMotion motion, double point[], double velocity[], double time[], long numPoints, long final); long velMove(MPIMotion *motion, MPITrajectory *trajectory); long isMotionDone(MPIMotion motion); void waitForMotionDone(MPIMotion motion); long clearError(MPIMotion motion); void motionAxisLoop(MPIMotion motion); void axisMotorLoop(MPIAxis axis); void motionMotorLoop(MPIMotion motion); void axisAmpEnable(MPIAxis axis); void axisAmpDisable(MPIAxis axis); void motionAmpEnable(MPIMotion motion); void motionAmpDisable(MPIMotion motion); void setIp(MPIControlType *controlType, MPIControlAddress *controlAddress, char *server); long parseCommandLine(long *motorNumber, int argc, char *argv[], MPIControlType *controlType, MPIControlAddress *controlAddress); void basicParsing(int argc, char *argv[], MPIControlType *controlType, MPIControlAddress *controlAddress); long programInit(long motorNumber, MPIControl *control, MPIMotor *motor, MPIAxis *axis, MPIMotion *motion, MPIControlType *controlType, MPIControlAddress *controlAddress); long programCleanup(MPIMotion *motion, MPIAxis *axis, MPIMotor *motor, MPIControl *control); void programInitSingle(MPIControl *control, MPIControlType controlType, MPIControlAddress *controlAddress, MPIMotion *motion, long motionNumber, MPIAxis *axis, long axisNumber, MPIFilter *filter, long filterNumber, MPIMotor *motor, long motorNumber, MPIRecorder *recorder, MPISequence *sequence, long sequenceNumber, MPICapture *capture, long captureNumber, MPICompare *compare, long compareNumber, MPIEventMgr *eventMgr, MPINotify *notify, Service *service); void programCleanupSingle(MPIControl *control, MPIMotion *motion, MPIAxis *axis, MPIFilter *filter, MPIMotor *motor, MPIRecorder *recorder, MPISequence *sequence, MPICapture *capture, MPICompare *compare, MPIEventMgr *eventMgr, MPINotify *notify, Service *service); void programInitMultiple(MPIControl *control, MPIControlType controlType, MPIControlAddress *controlAddress, MPIMotion *motion, long numberOfMotions, long *motionNumber, MPIAxis *axis, long numberOfAxes, long *axisNumber, MPIFilter *filter, long numberOfFilters, long *filterNumber, MPIMotor *motor, long numberOfMotors, long *motorNumber, MPIRecorder *recorder, MPISequence *sequence, long numberOfSequences, long sequencePageSize, long *sequenceNumber, MPICapture *capture, long numberOfCaptures, long *captureNumber, MPICompare *compare, long numberOfCompares, long *compareNumber, MPIEventMgr *eventMgr, MPINotify *notify, long numberOfNotifys, Service *service); void programCleanupMultiple(MPIControl *control, MPIMotion *motion, long numberOfMotions, MPIAxis *axis, long numberOfAxes, MPIFilter *filter, long numberOfFilters, MPIMotor *motor, long numberOfMotors, MPIRecorder *recorder, MPISequence *sequence, long numberOfSequences, long sequencePageSize, MPICapture *capture, long numberOfCaptures, MPICompare *compare, long numberOfCompares, MPIEventMgr *eventMgr, MPINotify *notify, long numberOfNotifys, Service *service); void programInitSingleWithMapping(MPIControl *control, MPIControlType controlType, MPIControlAddress *controlAddress, MPIMotion *motion, long motionNumber, MPIAxis *axis, long axisNumber, MPIFilter *filter, long filterNumber, MPIMotor *motor, long motorNumber, MPIRecorder *recorder, MPISequence *sequence, long sequenceNumber, MPICapture *capture, long captureNumber, MPICompare *compare, long compareNumber, MPIEventMgr *eventMgr, MPINotify *notify, Service *service); void programInitMultipleWithMapping(MPIControl *control, MPIControlType controlType, MPIControlAddress *controlAddress, MPIMotion *motion, long numberOfMotions, long *motionNumber, MPIAxis *axis, long numberOfAxes, long *axisNumber, MPIFilter *filter, long numberOfFilters, long *filterNumber, MPIMotor *motor, long numberOfMotors, long *motorNumber, MPIRecorder *recorder, MPISequence *sequence, long numberOfSequences, long sequencePageSize, long *sequenceNumber, MPICapture *capture, long numberOfCaptures, long *captureNumber, MPICompare *compare, long numberOfCompares, long *compareNumber, MPIEventMgr *eventMgr, MPINotify *notify, long numberOfNotifys, Service *service); void homeLimitOnInput(MPIMotor motor, long activeHigh); void enableUserLimit(MPIMotor motor, long enable); void disableUserLimit(MPIMotor motor, MPIEventType limit); void userLimitEnable(MPIMotor motor, MPIEventType limit, long enable); long sequenceCommandAdd(MPISequence sequence, MPICommandType commandType, MPICommandParams *commandParams, const char *label); MPISequence sequenceProgramCreate(MPIControl control); long sequenceProgramDelete(MPISequence *sequence); void sequenceRun(MPISequence sequence); long recordData(MPIRecorder recorder, long numRecords, long period, long eventCount, MPIRecorderRecord *records); void configureRecorder(MPIRecorder recorder); void stopRecorder(MPIRecorder recorder); long SetTorqueLimits(MPIMotor motor, MPIEventType eventType, float highLimit, float lowLimit, float duration); /* in seconds */ long controlAddressGet(MPIControl control, void *dst, void *src); long controlAddrToAddr(MPIControl control, void *dst, void *src); void SetDualLoop(MPIControl control, int outerMotor, int innerMotor);

/*******************************************************

    trapMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory and    position information. It checks for an idle 
    state before it commands the move. If it gets something an idle state, it 
    commands a motionStart, if it gets a moving state, it commands a 
    motionModify. If it gets something else, no move is commanded and an error 
    code is returned.
    
    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE,MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/


long    trapMove(MPIMotion      *motion,
                MPITrajectory   *trajectory,
                double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;
    
    params.trapezoidal.trajectory   = trajectory;
    params.trapezoidal.position     = position;

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

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeTRAPEZOIDAL,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}


/*******************************************************

    sCurveMove commands a simple trap move to the specified motion supervisor
    with the specified trajectory and position information. It checks for an
    idle state before it commands the move. If it gets something an idle state,
    it commands a motionStart, if it gets a moving state, it commands a 
    motionModify.  If it gets something else, no move is commanded and an error
    code is returned.
    
    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/


long     sCurveMove(MPIMotion       *motion,
                    MPITrajectory   *trajectory,
                    double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;
    
    params.sCurve.trajectory    = trajectory;
    params.sCurve.position      = position;

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

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeS_CURVE,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}


/******************************************************************************

    ptMove commands a PT move 

******************************************************************************/

long    ptMove(MPIMotion    motion,
               double       point[],
               double       time[],
               long         numPoints,
               long         final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pt.pointCount = numPoints;   /* Number of time points */
    params.pt.position = point;     /* Position array */
    params.pt.time = time;          /* Time array */
    params.pt.point.retain = 0;     /* Flush frame buffer after execution */
    params.pt.point.final = final;      /* Last point */
    params.pt.point.emptyCount = 5; /* Start E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}


/******************************************************************************

    pvtMove commands a PVT move 

******************************************************************************/

long    pvtMove(MPIMotion   motion,
                double      point[],
                double      velocity[],
                double      time[],
                long        numPoints,
                long        final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pvt.pointCount = numPoints;  /* Number of time points */
    params.pvt.position = point;        /* Position array */
    params.pvt.velocity = velocity;
    params.pvt.time = time;         /* Time array */
    params.pvt.point.retain = 0;        /* Flush frame buffer after execution */
    params.pvt.point.final = final;     /* Last point */
    params.pvt.point.emptyCount = 5;    /* E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePVT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePVT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}


/*******************************************************

    velMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory    information. It checks for an idle state before
    it commands the move. If it gets something an idle state, it commands a 
    motionStart, if it gets a moving state, it commands a motionModify.  If it
    gets something else, no move is commanded and an error code is returned.
    
    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/


long    velMove(MPIMotion       *motion,
                MPITrajectory   *trajectory)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;
    
    params.velocity.trajectory  = trajectory;

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

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeVELOCITY,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
            /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}


/*********************************************************************

    isMotionDone() returns a 1 if the motion is idle, a 0 if it is not.

**********************************************************************/

long    isMotionDone(MPIMotion      motion)
{
    MPIStatus   status;
    
    long    returnValue = FALSE;

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

    if(status.state == MPIStateIDLE)
    {
        returnValue = TRUE;
    }

    return returnValue;
}



/*********************************************************************

 waitForMotionDone() polls motion to see if the axis is in an idle or error
 state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
 MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.

**********************************************************************/
void waitForMotionDone(MPIMotion motion)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue = MPIMessageOK;


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

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 10ms and give up control to other threads */
                mpiPlatformSleep(10);
                break;
            }
            case MPIStateIDLE: 
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}



/******************************************************************************

 clearError() clears all the errors on an MS and enables the amps on that MS.
 It does this by commanding a mpiMotionAction(reset) and then waits a couple
 samples, tries again if it needs to, then waits a couple samples and makes
 sure it happened, returning an error if it didn't, and enables all the amps on
 the MS using motionAmpEnable().

******************************************************************************/



long    clearError(MPIMotion motion)
{
    MPIStatus           status;         /* Status handle */
    
    long returnValue;
    
    returnValue = mpiMotionAction(motion, MPIActionRESET);
    msgCHECK(returnValue);

    mpiControlSampleWait(mpiMotionControl(motion), 2);
    
    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);
    
    if(status.state == MPIStateERROR)
    {
        returnValue = mpiMotionAction(motion, MPIActionRESET);
        msgCHECK(returnValue);
    }

    mpiControlSampleWait(mpiMotionControl(motion), 2);

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

    if(status.state == MPIStateERROR)
    {
        returnValue = MPIMotionMessageERROR;
    }

    motionAmpEnable(motion);

    return returnValue;
}


/*****************************************************************************

  For every axis attached to a motion supervisor (perform some action)

  This is a model for any MPI Object that has other MPI objects attached to
   it via a linked list. (i.e. there exists mpiXxxYyyFirst(...) and 
   mpiXxxYyyNext(...) functions.)

******************************************************************************/

/* For every axis attached to a motion supervisor ... */
void motionAxisLoop(MPIMotion   motion) 
{
    MPIAxis axis;

    /* For every axis attached to a motion ... */
    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Place your code here */
    }
}


/*****************************************************************************

  For every motor attached to an axis (perform some action).  This is useful
   when motor objects haven't been created or when someone is using gantry code.

  This is a model for any MPI Object that has other MPI objects attached to
   it via object maps.  (i.e. there exits an mpiXxxYyyMap(...) function.)

******************************************************************************/

/* For every motor attached to an axis ... */
void axisMotorLoop(MPIAxis  axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorIndex;
    long            returnValue;

    
    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(map, motorIndex)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

  For every motor attached to a motion supervisor (perform some action)

  This is a model for any MPI Object (Father) that has other MPI objects 
   (Children) attached to it indirectly in the following way:

    MPIFather --(linked list)--> MPIIntermediate --(object map)-> MPIChild

******************************************************************************/

/* For every motor attached to a motion supervisor ... */
void motionMotorLoop(MPIMotion  motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;


    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

  Enable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.
   This code also sets the command position equal to the actual position and 
   resets the integrator before enabling the amplifiers so that the motors will
   not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to an axis */
void axisAmpEnable(MPIAxis  axis) 
{
    MPIControl      control;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    axisMotorMap;
    MPIObjectMap    motorFilterMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;


    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &axisMotorMap);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(axisMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* Get the actual position of the axis */
                returnValue = mpiAxisActualPositionGet(axis, &position);
                msgCHECK(returnValue);

                /* Set the command position equal to the actual position */
                returnValue = mpiAxisCommandPositionSet(axis, position);
                msgCHECK(returnValue);

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &motorFilterMap);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MPIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(motorFilterMap, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

  Disable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to an axis */
void axisAmpDisable(MPIAxis axis) 
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorNumber;
    long            returnValue;

    
    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorNumber = 0; motorNumber < MPIXmpMAX_Motors; motorNumber++) {

        if (map & (1<<motorNumber)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorNumber);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

  Enable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using 
   gantry code.  This code also sets the command position equal to the actual 
   position and resets the integrator before enabling the amplifiers so that
   the motors will not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to a motion supervisor */
void motionAmpEnable(MPIMotion  motion) 
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;


    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* For every axis */
                for (axis =  mpiMotionAxisFirst(motion);
                     axis != MPIHandleVOID;
                     axis =  mpiMotionAxisNext(motion, axis)) {

                    /* Get the object map for the motors */
                    returnValue = mpiAxisMotorMapGet(axis, &map);
                    msgCHECK(returnValue);

                    /* If axis is attached to motor ... */
                    if (mpiObjectMapBitGET(map, motorIndex)) {

                        /* Get the actual position of the axis */
                        returnValue = mpiAxisActualPositionGet(axis, &position);
                        msgCHECK(returnValue);

                        /* Set command position equal to actual position */
                        returnValue = mpiAxisCommandPositionSet(axis, position);
                        msgCHECK(returnValue);
                    }
                }

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &map);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MPIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(map, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

  Disable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using 
   gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to a motion supervisor */
void motionAmpDisable(MPIMotion motion) 
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;


    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}


/*****************************************************************************

    Sets controller to Network mode.  Server is the name of the computer in 
    quotes.     Use IP or computer name.

******************************************************************************/

void setIp(MPIControlType       *controlType,
           MPIControlAddress    *controlAddress,
           char                 *server)
{
    controlAddress->type.client.port = 3300;
    controlAddress->type.client.server = server;
    *controlType = MPIControlTypeCLIENT;
}


/**********************************************

    Parsing for apps that need command line arguments (example)

    In this example, you would pass in the default motor number you
    want to use.  parseCommandLine() would then change the motor number
    if the user specified (s)he wanted to use a different motor.

**********************************************/

long    parseCommandLine(long               *motorNumber,
                         int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress)
{       
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-motor",   ArgTypeLONG,    motorNumber,    },
        {   NULL,       ArgTypeINVALID, NULL,   }
    };


    /* 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) {
        fprintf(stderr,"usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                            argv[0],
                            ArgUSAGE,
                            MPIXmpMAX_Motors);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}


/*****************************************************************************

  Perform basic command line parsing. (-control -server -port -trace)

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

******************************************************************************/

/* Perform basic command line parsing. (-control -server -port -trace) */
void basicParsing(int                    argc,
                  char                  *argv[],
                  MPIControlType        *controlType,
                  MPIControlAddress     *controlAddress)
{
    long argIndex;

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

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


/************************************************************

  Example of a typical program initialization function:
    A bare minimum object creation for programs of the scope of
    motion1 or so. Designed to work with programCleanup below.

  #define at head of program file:

#define MOTOR_NUMBER    (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control, 
                controlType,
                &controlAddress,
                MOTOR_NUMBER,
                &motion,
                &axis,
                &motor);

************************************************************/


long    programInit(MPIControl          *control,
                    MPIControlType      *controlType,
                    MPIControlAddress   *controlAddress,
                    long                motorNumber,
                    MPIMotion           *motion,
                    MPIAxis             *axis,
                    MPIMotor            *motor)
{
    long returnValue;


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

    /* Initialize the controller */
    returnValue = mpiControlInit(*control);
    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "mpiControlInit(0x%x) returns 0x%x: %s\n",
                        *control,
                        returnValue,
                        mpiMessage(returnValue, NULL));

        exit(returnValue);
    }

    /* Create motor object */
    *motor =
        mpiMotorCreate(*control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(*motor));


    /* Create axis object */
    *axis = 
        mpiAxisCreate(*control, 
                      motorNumber);
    msgCHECK(mpiAxisValidate(*axis));


    /* Create motion object */
    *motion =
        mpiMotionCreate(*control,
                        motorNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    return  returnValue;

}

/*********************************************************

  Example of a typical program cleanup function:
    A bare minimum object deletion for programs of the scope of
    motion1 or so. Designed to work with programInit above.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control, 
                   &motion,
                   &axis,
                   &motor);

*********************************************************/

long    programCleanup(MPIControl       *control,
                       MPIMotion        *motion,
                       MPIAxis          *axis,
                       MPIMotor         *motor)
{
    long returnValue;
    
    /* Delete the remaining handles */
    returnValue = mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(*motor);
    msgCHECK(returnValue);

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

    return returnValue;
}



/*****************************************************************************

  Create and initialize MPI objects.  [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control, 
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitSingle(MPIControl           *control, 
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service) 
{
    MPIEventMask    eventMask;
    long            returnValue;

    
    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axis object */
    *axis =
        mpiAxisCreate(*control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(*axis));

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

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

    /* Create motor object */
    *motor =
        mpiMotorCreate(*control,
                        motorNumber);
    msgCHECK(mpiMotorValidate(*motor));

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr = 
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    mpiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}


/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [One of each object -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control, 
                   &motion,
                   &axis,
                   &filter,
                   &motor,
                   &recorder,
                   &sequence,
                   &capture,
                   &compare,
                   &eventMgr,
                   &notify,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupSingle(MPIControl        *control, 
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    MPIFilter       *filter,
                    MPIMotor        *motor,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    MPICapture      *capture,
                    MPICompare      *compare,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    Service         *service) 
{
    long    returnValue;

    
    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification object */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    /* Delete compare object */
    returnValue =
        mpiCompareDelete(*compare);
    msgCHECK(returnValue);

    /* Delete capture object */
    returnValue =
        mpiCaptureDelete(*capture);
    msgCHECK(returnValue);

    /* Delete sequencer object */
    returnValue =
        mpiSequenceDelete(*sequence);
    msgCHECK(returnValue);

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete filter object */
    returnValue =
        mpiFilterDelete(*filter);
    msgCHECK(returnValue);

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}


/*****************************************************************************

  Create and initialize MPI objects.  [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control, 
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitMultiple(MPIControl         *control, 
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service) 
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    
    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr = 
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    mpiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}


/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [Arrays of some objects -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control, 
                   motion,
                   numberOfMotions,
                   axis,
                   numberOfAxes,
                   filter,
                   numberOfFilters,
                   motor,
                   numberOfMotors,
                   &recorder,
                   sequence,
                   numberOfSequences,
                   capture,
                   numberOfCaptures,
                   compare,
                   numberOfCompares,
                   &eventMgr,
                   notify,
                   numberOfNotifys,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupMultiple(MPIControl      *control, 
                    MPIMotion       *motion,
                    long             numberOfMotions,
                    MPIAxis         *axis,
                    long             numberOfAxes,
                    MPIFilter       *filter,
                    long             numberOfFilters,
                    MPIMotor        *motor,
                    long             numberOfMotors,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    long             numberOfSequences,
                    long             sequencePageSize,
                    MPICapture      *capture,
                    long             numberOfCaptures,
                    MPICompare      *compare,
                    long             numberOfCompares,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    long             numberOfNotifys,
                    Service         *service) 
{
    long    index;
    long    returnValue;

    
    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification objects */
    for (index = 0; index < numberOfNotifys; index++) {
        returnValue =
            mpiNotifyDelete(notify[index]);
        msgCHECK(returnValue);
    }

    /* Delete compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        returnValue =
            mpiCompareDelete(compare[index]);
        msgCHECK(returnValue);
    }

    /* Delete capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        returnValue =
            mpiCaptureDelete(capture[index]);
        msgCHECK(returnValue);
    }

    /* Delete sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        returnValue =
            mpiSequenceDelete(sequence[index]);
        msgCHECK(returnValue);
    }

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        returnValue =
            mpiMotorDelete(motor[index]);
        msgCHECK(returnValue);
    }

    /* Delete filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        returnValue =
            mpiFilterDelete(filter[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion supervisor objects */
    for (index = 0; index < numberOfMotions; index++) {
        returnValue =
            mpiMotionDelete(motion[index]);
        msgCHECK(returnValue);
    }

    /* Delete axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        returnValue =
            mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}


/*****************************************************************************

  Create and initialize MPI objects, and place MS's axis map on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control, 
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/


/* Create and initialize MPI objects */
void programInitSingleWithMapping(MPIControl            *control, 
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service) 
{
    MPIEventMask    eventMask;
    long            returnValue;

    
    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axis object */
    *axis =
        mpiAxisCreate(*control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(*axis));

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

    /* Map axis to motion supervisor on XMP */
    returnValue =
        mpiMotionAction(*motion,
                        MPIActionMAP);
    msgCHECK(returnValue);

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

    /* Create motor object */
    *motor =
        mpiMotorCreate(*control,
                        motorNumber);
    msgCHECK(mpiMotorValidate(*motor));

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr = 
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    mpiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}


/*****************************************************************************

  Create and initialize MPI objects, and place MSs' axis maps on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control, 
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/


/* Create and initialize MPI objects */
void programInitMultipleWithMapping(MPIControl          *control, 
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service) 
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    
    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));

        /* Map axis to motion supervisor on XMP */
        returnValue =
            mpiMotionAction(motion[index],
                            MPIActionMAP);
        msgCHECK(returnValue);
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr = 
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    mpiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}


/*
  Configure Home Limit to be triggered on the Home Input rather than the capture
*/
void homeLimitOnInput(MPIMotor  motor,
                      long      activeHigh)
{
    MPIMotorConfig   motorConfigXmp;    /* XMP motor I/O configuration */
    MPIXmpMotor     *motorXmp;          /* XMP motor memory */
    long             returnValue;       /* return value from library */


    /* Get pointer to Motor memory */
    returnValue =
        mpiMotorMemory(motor,
                       &motorXmp);
    
    /* Get the XMP Motor configuration*/
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Set the new Home Limit parameters */
    motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].SourceAddress = 
        &motorXmp->IO.DedicatedIN.IO;
    
    motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].Mask = 
        MPIXmpMotorIOMaskHOME;
    /* Set for Active High Home switch */
    motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].LimitValue.l = 
        (activeHigh) ? MPIXmpMotorIOMaskHOME : 0;

    /* Set the new XMP Motor configuration*/
    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);
}


/* 
  enableUserLimit()  configures and enables one user limit.

  A user configured motor limit (user limit) normally uses one of the following
  limit types:

    MPIEventTypeLIMIT_USER0
    MPIEventTypeLIMIT_USER1
    MPIEventTypeLIMIT_USER2
    MPIEventTypeLIMIT_USER3
    MPIEventTypeLIMIT_USER4
    MPIEventTypeLIMIT_USER5
    MPIEventTypeLIMIT_USER6
    MPIEventTypeLIMIT_USER7

  but can also be one of the following types:

    MPIEventTypeAMP_FAULT
    MPIEventTypeHOME
    MPIEventTypeLIMIT_ERROR
    MPIEventTypeLIMIT_HW_NEG
    MPIEventTypeLIMIT_HW_POS
    MPIEventTypeLIMIT_SW_NEG
    MPIEventTypeLIMIT_SW_POS
    MPIEventTypeENCODER_FAULT

  Please read Application note 215 for a detailed discussion about user limits.

*/
void enableUserLimit(MPIMotor       motor,
                     long           enable)
{
    /* Configure user limit zero */
    MPIEventType     limit       = MPIEventTypeLIMIT_USER0;

    MPIXmpLimitData  customLimit;
    MPIXmpData      *firmware;      /* Needed to access general XMP addresses */
    MPIXmpMotor     *motorXmp;      /* Needed to access motor's addresses     */

    long             returnValue;


    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &customLimit);
    msgCHECK(returnValue);

    if (enable) {

        /* Get pointer to XMP firmware */
        returnValue =
            mpiControlMemory(mpiMotorControl(motor),
                             &(void *)firmware,
                             NULL);
        msgCHECK(returnValue);

        /* Get pointer to motor's memory */
        returnValue =
            mpiMotorMemory(motor, &(void *)motorXmp);
        msgCHECK(returnValue);


        /* Set up limit condition 0 */
        customLimit.Condition[0].Type         = MPIXmpLimitTypeGE;
        customLimit.Condition[0].SourceAddress= &motorXmp->IO.DedicatedIN.IO;
        customLimit.Condition[0].Mask         = MPIMotorInputAMP_FAULT;
        customLimit.Condition[0].LimitValue.l = MPIMotorInputUSER;

        /* Set up limit condition 1 */
        customLimit.Condition[1].Type         = MPIXmpLimitTypeNE;
        customLimit.Condition[1].SourceAddress= &firmware->MS[0].Action;
        customLimit.Condition[1].Mask         = MPIMotorInputAMP_FAULT;
        customLimit.Condition[1].LimitValue.l = MPIMotorInputHOME;

        /* Set up limit output */
        customLimit.Output.OutputPtr = (void*)&firmware->Axis[0].ActualVelocity;
        customLimit.Output.Enabled   = TRUE;
        customLimit.Output.AndMask   = 0;
        customLimit.Output.OrMask    = 0;

        /* Set up limit logic */
        customLimit.Logic = MPIXmpLogicAND;


        /* Set up the XMP to handle the user limit */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);

    } else {
        /* Set default limit parameters */
        customLimit.Condition[0].Type = MPIXmpLimitTypeFALSE;
        customLimit.Condition[1].Type = MPIXmpLimitTypeFALSE;

        customLimit.Status = MPIXmpStatusLIMIT;
        customLimit.Logic  = MPIXmpLogicNEVER;

        customLimit.Output.AndMask = -1;    /* ALL BITS */
        customLimit.Output.OrMask  = 0;
        customLimit.Output.Enabled = FALSE;

        /* Reset the user limit on the XMP */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);
    }
}


/* 
  disableUserLimit()  disables and erases the configuration of one user limit.
*/
void disableUserLimit(MPIMotor      motor,
                      MPIEventType  limit)
{
    MPIXmpLimitData userLimit;
    long            returnValue;


    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);

    /* Set default limit parameters */
    userLimit.Condition[0].Type = MPIXmpLimitTypeFALSE;
    userLimit.Condition[1].Type = MPIXmpLimitTypeFALSE;

    userLimit.Status = MPIXmpStatusLIMIT;
    userLimit.Logic  = MPIXmpLogicNEVER;

    userLimit.Output.AndMask = -1;  /* ALL BITS */
    userLimit.Output.OrMask  = 0;
    userLimit.Output.Enabled = FALSE;

    /* Reset the user limit on the XMP */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               (MPIEventType)limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);
}


/* 
  userLimitEnable()  enables or disables one user limit.

    This function does not change (most of) the configuration of a user limit.

    Because the function does change the logic to temporarily disable
    a user limit, this function must store the values of the limit's
    logic.
*/
void userLimitEnable(MPIMotor       motor,
                     MPIEventType   limit,
                     long           enable)
{
    static MPIXmpLogic  savedLogic[MPIXmpMAX_Motors][MPIEventTypeMOTOR_LAST];

    MPIXmpLimitData limitData;
    long            motorNumber;
    long            returnValue;


    /* Get the motor number */
    mpiMotorNumber(motor,
                   &motorNumber);

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);

    if (enable) {
        /* Restore logic */
        limitData.Logic = savedLogic[motorNumber][limit];
    }
    else {
        /* Save logic */
        savedLogic[motorNumber][limit] = limitData.Logic;

        /* Set logic to MPIXmpLogicNEVER to disable limit */
        limitData.Logic = MPIXmpLogicNEVER;
    }

    /* Set the new configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);
}


/* 
   sequenceCommandAdd() creates a command (MPICommand object) and appends it to
   sequence's list of commands.  This function does return MPI error codes so
   that sequence setup code may be more easily debugged.

   Warning:  sequenceCommandAdd() does not keep track of created command objects
   so it is important that before a sequence object is deleted, that each
   command object on sequence's list is itself deleted.  Otherwise, there will
   be memory leaks.  One can use sequenceProgramDelete() to accomplish this.
*/
long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label)
{
    MPICommand  command;
    long        returnValue;
    

    command =
        mpiCommandCreate(commandType,
                         commandParams,
                         label);
    returnValue = 
        mpiCommandValidate(command);

    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiSequenceCommandAppend(sequence,
                                     command);
    }

    return returnValue;
}


/* 
   sequenceProgramCreate() is a prototype function showing how one can create a
   MPISequence program.  This prototype creates a program that simply loops
   continually, much like the statement:

    while(1) {}

   would in C.  This function uses sequenceCommandAdd() to add commands to
   sequence.  One should use sequenceProgramDelete() to delete the sequence
   object and the MPICommand objects on sequence's command list.  Please refer
   to the description of sequenceCommandAdd() for more details.
*/
MPISequence sequenceProgramCreate(MPIControl control)
{
    MPISequence         sequence;
    MPICommandParams    commandParams;
    long                returnValue;


    /* Create sequence object */
    sequence =
        mpiSequenceCreate(control,
                          -1,   /* Use the next available sequence */
                          1);   /* # of commands in sequence */
    msgCHECK(mpiSequenceValidate(sequence));

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Add command to sequence */
    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeBRANCH,
                           &commandParams,
                           "First");
    msgCHECK(returnValue);

    /* Return the new sequence handle */
    return sequence;
}


/* 
   sequenceProgramDelete() removes and deletes all command objects on sequence's
   command list and then deletes sequence.  This function does return MPI error 
   codes so that sequence setup code may be more easily debugged.
*/
long sequenceProgramDelete(MPISequence *sequence)
{
    MPICommand  command;
    long        returnValue = MPIMessageOK;


    /* Remove and delete command objects on sequence list */
    while(TRUE) {
        command = mpiSequenceCommandLast(*sequence);
        if ((returnValue != MPIMessageOK) ||
            (command==MPIHandleVOID)) {
            break;
        }
        returnValue =
            mpiSequenceCommandRemove(*sequence,
                                     command);

        if (returnValue == MPIMessageOK) {
            returnValue =
                mpiCommandDelete(command);
        }
    }

    /* Delete sequence object */
    returnValue =
        mpiSequenceDelete(*sequence);

    if (returnValue == MPIMessageOK) {
        /* Make it obvious that sequence is no longer a valid object */
        *sequence = MPIHandleVOID;
    }

    return returnValue;
}


/* 
   Starts a sequence, waits for the user to press a key and then
   stops the sequence.
*/
void sequenceRun(MPISequence sequence)
{
    long returnValue;


    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    fprintf(stderr,"Press any key to stop sequence.\n");
    mpiPlatformKey(MPIWaitFOREVER);
    fprintf(stderr,"Exiting ...\n");

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    if ((returnValue != MPIMessageOK) &&
        (returnValue != MPISequenceMessageSTOPPED)) {
        msgCHECK(returnValue);
    }

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Start the XMP's recorder, get data, and stop the recorder 

******************************************************************************/

long recordData(MPIRecorder         recorder, 
                long                numRecords,
                long                period,
                long                eventCount,
                MPIRecorderRecord  *records)
 {
    long returnValue;
    long recordIndex;
    long recordCountRemaining;
    long countGet;

    /* Start recording the axis */
    returnValue =
        mpiRecorderStart(recorder,
                         numRecords,
                         period,    /* period (milliseconds) */
                         eventCount);
    msgCHECK(returnValue);

    /* Fill the record buffer */
    for (recordIndex = 0, recordCountRemaining = numRecords;
         recordCountRemaining > 0; ) {

        returnValue =
            mpiRecorderRecordGet(recorder,
                                 recordCountRemaining,
                                 &records[recordIndex],
                                 &countGet);
        msgCHECK(returnValue);

        recordCountRemaining -= countGet;
        recordIndex += countGet;
    }

    /* Stop recording */
    returnValue = mpiRecorderStop(recorder);

    /* In case the recorder has already stopped */
    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);

    return returnValue;
}


/*****************************************************************************

   Example:
    Configure recorder object

   This example records 3 system data variables:
    1) The sample counter -- increments by 1 every servo cycle
    2) The background cycle -- increments by 1 after every background cycle
    3) The "count delta" -- increments by 1 after every background cycle and 
            resets to zero after every servo cycle

******************************************************************************/

void configureRecorder(MPIRecorder recorder)
{
    MPIControl          control = mpiRecorderControl(recorder);
    MPIXmpData*         firmware;
    MPIXmpBufferData*   external;

    void    *point[MPIXmpMaxRecSize];

    long    pointCount = 0;
    long    returnValue;


    returnValue =
        mpiControlMemory(control,
                         &firmware,
                         &external);
    msgCHECK(returnValue);

    point[pointCount++] = &firmware->SystemData.SampleCounter;
    point[pointCount++] = &firmware->SystemData.BackgroundCycle;
    point[pointCount++] = &firmware->SystemData.CountDelta;

    mpiAssert(pointCount <= MPIXmpMaxRecSize);

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                MPIRecorderRecordTypePOINT,
                                pointCount,
                                point);
    msgCHECK(returnValue);
}

/*****************************************************************************

   Stops the data recorder ignoring the MPIRecorderMessageSTOPPED message if 
    the recorder is already stopped.

******************************************************************************/

void stopRecorder(MPIRecorder recorder)
{
    long returnValue =
        mpiRecorderStop(recorder);

    /* In case the recorder has already stopped */
    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);
}

/*
	EventType is MPIEventTypeLIMIT_USERn -- Choose the user limit you want to use.
	The axis will abort out after continually exceeding the high or low limit for
	duration seconds.

	highLimit sets the positive torque limit.
	lowLimit sets the negative torque limit.
*/
long SetTorqueLimits(MPIMotor motor,
                     MPIEventType eventType,
					 float highLimit,
					 float lowLimit,
					 float duration) /* in seconds */
{
    MPIControl          control;
    MPIXmpData          *firmware;
    MPIMotorLimitConfig motorEventConfig;
	MPIPlatform platform;

    long returnValue;
	long samples;
	long ptr;
	long motorNum;

   /* Determine control handle */
    control = mpiMotorControl(motor);
    returnValue = mpiControlValidate(control);
 
    if(returnValue == MPIMessageOK)
    {
        returnValue = mpiControlSecondsToSamples(control,
        duration,
        &samples);
    }	
    if(returnValue == MPIMessageOK)
    {
        returnValue = mpiMotorNumber(motor, &motorNum);
    }
	
    /* If duration is out of range, make it zero */
    if(duration > (MPIXmpLogicDURATION_MASK >> MPIXmpLogicBITS) || duration < 0)
    {
        samples = 0;
    }
	 
    /* Get pointer to XMP firmware */
    if(returnValue == MPIMessageOK)
    {
        returnValue =
            mpiControlMemory(control,
                             (void **)&firmware,
                             NULL);
    }

    /* The source address requires a host pointer, not a controller pointer */
    platform = mpiControlPlatform(control);
    msgCHECK(mpiPlatformValidate(platform));
    returnValue = mpiPlatformMemoryToHost(platform,
        (void**)firmware->Motor[motorNum].Commutation.Input[0].Ptr,
        (void**)&ptr);
    msgCHECK(returnValue);

    if (returnValue == MPIMessageOK)
	{
		/*
            Set up the Condition blocks. They watch for the high and
            low command levels
		*/
        motorEventConfig.Condition[0].Type = MPIXmpLimitTypeFGE;
        motorEventConfig.Condition[0].SourceAddress = (void *)ptr;
        motorEventConfig.Condition[0].LimitValue.f = highLimit;

        motorEventConfig.Condition[1].Type = MPIXmpLimitTypeFLE;
        motorEventConfig.Condition[1].SourceAddress = (void *)ptr;
        motorEventConfig.Condition[1].LimitValue.f = lowLimit;

        /* Abort on this condition */
        motorEventConfig.Status = MPIXmpStatusABORT;
        /*
            Determine logic result from Condition[0] AND Condition[1].
            The duration is logically combined with the logic.
		*/
        motorEventConfig.Logic  = MPIXmpLogicOR | (samples << MPIXmpLogicBITS);

        /* Disable the output feature */
        motorEventConfig.Output.OutputPtr = NULL;
        motorEventConfig.Output.AndMask = 0x0;
        motorEventConfig.Output.OrMask = 0x0;
        motorEventConfig.Output.Enabled = 0;
		
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    } 
    return returnValue;
}

/*
Works like mpiControlMemoryGet, but gets the address of location
in the XMP memory space. This is the same number as you see as
the address in VM3.
*/
long controlAddressGet(MPIControl control, void *dst, void *src)
{
MPIPlatform platform;
long returnValue;
   platform = mpiControlPlatform(control);
   returnValue = mpiPlatformValidate(platform);
   if(returnValue) return returnValue;
   returnValue = mpiPlatformMemoryToFirmware(platform,
      (void**)src,
      (void**)dst);
   return returnValue;
}
/*
   Works like mpiControlMemorySet, but writes one firmware address
   to another. Host / controller memory spaces can be ignored. Useful
   in pointer hocus pocus like can be done in VM3.
   Example:
   controlAddrToAddr(control, 
                     &firmware->Axis[firstMotor].APos[0].Ptr,
                     &firmware->Motor[firstMotor].IO.Encoder[0].IO);
*/
long controlAddrToAddr(MPIControl control, void *dst, void *src)
{
   long returnValue;
   long addr;
   returnValue = controlAddressGet(control,
                                   &addr,
                                   src);
   if(returnValue)return returnValue;
   returnValue = mpiControlMemorySet(control,
       (void**)dst,
       &addr,
       sizeof(dst));
   return returnValue;
}
             
/*
   Set outerMotor as the motor with the outer "slow" control loop.
   Set innerMotor as the motor with the inner "fast" control loop.
   Uses Filter[outerLoop] as the Filter that has the control loop.
   This only works with the PIV algorithm.
*/
   void SetDualLoop(MPIControl control, int outerMotor, int innerMotor)
{
   /* Simple code to increment userbuffer[0] */
   MPIXmpData        *firmware;
   MPIXmpBufferData  *buffer;
   long returnValue;
                 
   /* Get memory pointers */
   returnValue =
   mpiControlMemory(control,
                    &firmware,
                    &buffer);
   msgCHECK(returnValue);
   returnValue = controlAddrToAddr(control,
       &firmware->ControlLaw.Standard.Filter[outerMotor].VelPositionPtr,
       &firmware->Motor[innerMotor].IO.Encoder[0].Encoder.IO);
   msgCHECK(returnValue);
}

/*
Get a default FPGA name, verify FPGA name then download FPGA
to the node while printing download status.
*/
void fpgaDownload(MPISqNode sqNode)
{
MPISqNodeFileName fileName;
MPISqNodeDownloadParams params;
long returnValue; /* Get default FPGA name */ returnValue = mpiSqNodeFpgaDefaultFileName(sqNode, &fileName);
msgCHECK(returnValue); params.filename = fileName.fileName;
params.callback = printFpgaDownloadStatus;
params.channel = MPISqNodeChannelNODE;
printf("%s ", fileName.fileName); /* Verify FPGA filename if it is the default FPGA for the node */
returnValue = mpiSqNodeFpgaFileNameVerify(sqNode, &fileName.fileName);
msgCHECK(returnValue); printf("Download Fpga begins \n");
returnValue = mpiSqNodeDownload(sqNode, &params);
msgCHECK(returnValue);
printf("Download finishes \n");
} /*
This is the callback function for fpgaDownload.
It prints out the fpgaDownload status
*/
long printFpgaDownloadStatus(long percentage)
{
printf("Percentage %ld percent complete\r", percentage);
return 0;
} /* motorDemandGet(...) demonstrates how to read the primary and auxiliary motor demand signals. mpiMotorMemory(...) obtains the motor control memory pointer. The pointer's address is then passed into mpiMotorMemoryGet(...) to obtain the demand values. Note: MPIXmpMotor *memory must be casted as (void *) in mpiMotorMemory. */ long motorDemandGet(MPIMotor motor, float *primary, float *aux) { MPIXmpMotor *memory; long returnValue; /* Get motor control memory pointer */ returnValue = mpiMotorMemory(motor, (void *)&memory); /* Get primary motor demand value */ if(returnValue == MPIMessageOK) { returnValue = mpiMotorMemoryGet(motor, primary, &memory->IO.Demand.Channel[0].Level, sizeof(memory->IO.Demand.Channel[0].Level)); } /* Get auxiliary motor demand value */ if(returnValue == MPIMessageOK) { returnValue = mpiMotorMemoryGet(motor, aux, &memory->IO.Demand.Channel[1].Level, sizeof(memory->IO.Demand.Channel[1].Level)); } return returnValue; }

             

       Legal Notice  |  Tech Email  |  Feedback
      
Copyright ©
2001-2009 Motion Engineering