event1.c -- Perform a repeated two-axis motion while polling an event manager.
/* event1.c */

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

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

/*

:Perform a repeated two-axis motion while polling an event manager.

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

*/

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

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

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    event1Main

argMainRENAME(main, event1)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  20000.0,    },
    { 0.0,      0.0,        },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};


int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axisX;      /* X axis */
    MPIAxis     axisY;      /* Y axis */
    MPIMotion   motion;     /* coordinated motion object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    long    returnValue;    /* return value from library */

    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* 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) ||
        (axisNumber[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

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

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

    /* Create X axis object using axis number X_AXIS on controller */
    axisX =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axisX));

    /* Create Y axis object using axis number Y_AXIS on controller */
    axisY =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axisY));

    /* Create motion object using MS number */
    /* Append X axis to motion */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axisX);
    msgCHECK(mpiMotionValidate(motion));

    /* Append Y axis to motion */
    returnValue =
        mpiMotionAxisAppend(motion,
                            axisY);
    msgCHECK(returnValue);

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

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

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

    /* Flush any existing events */
    returnValue =
        mpiEventMgrFlush(eventMgr);
    msgCHECK(returnValue);

    /* Add notify to event manager's list */
    returnValue =
        mpiEventMgrNotifyAppend(eventMgr,
                                notify);
    msgCHECK(returnValue);

    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index = 0;
    while ((returnValue == MPIMessageOK) &&
           (meiPlatformKey(MPIWaitPOLL) <= 0)) {
        MPIMotionParams motionParams;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           motionType,
                           &motionParams);

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                msgCHECK(returnValue);

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

                /* FALL THROUGH */
            }
            case MPIMotionMessageNOT_READY: {
                returnValue = MPIMessageOK;
                continue;
            }
            case MPIMotionMessageMOVING: {
                returnValue = MPIMessageOK;
                break;
            }
            case MPIMessageOK:
            default: {
                break;
            }
        }

        /* Collect motion events */
        while (TRUE) {
            MPIEventStatus  eventStatus;

            /* Obtain firmware event(s) (if any) */
            returnValue =
                mpiEventMgrService(eventMgr,
                                   MPIHandleVOID);
            msgCHECK(returnValue);

            /* Poll for motion event */
            returnValue =
                mpiNotifyEventWait(notify,
                                   &eventStatus,
                                   MPIWaitPOLL);

            if (returnValue == MPIMessageOK) {
                if (eventStatus.type == MPIEventTypeMOTION_DONE) {
                    break;
                }
            }
            else {
                meiASSERT(returnValue == MPIMessageTIMEOUT);
            }
        }

        if (++index >= MOTION_COUNT) {
            index = 0;
        }
    }

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisX);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

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

    return ((int)returnValue);
}