event3.c -- Perform a repeated single-axis motion using command-line-specified axis (default 0).
/* event3.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/event3.c 13    7/23/01 2:36p Kevinh $";
#endif

/*

:Perform a repeated single-axis motion using command-line-specified axis (default 0).

Wait for events to be distributed by the event manager in a separate service thread.
 Check status after motion complete, warn of inPosition not set.

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    event3Main

argMainRENAME(main, event3)
#endif

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

/* Command line arguments and defaults */
long            axisNumber      = 0;
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

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

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.0,   },
    },
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.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],  },
};


long
    motionDone(MPIMotion    motion,
               MPIStatus    *status);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;        /* motion controller handle */
    MPIAxis     axisList[AXIS_COUNT];   /* axis handle(s) */
    MPIMotion   motion;         /* motion handle */
    MPINotify   notify;         /* event notification object */
    MPIEventMgr eventMgr;       /* event manager handle */

    MPIEventMask    eventMask;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    Service service;

    long    returnValue;    /* return value from library */

    long    index;

    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   >= MEIXmpMAX_Axes) ||
        (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 - 1,
                            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;
        }
    }

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

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

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

    /* Create motion supervisor object using MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create 1-axis motion coordinate system */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axisList);
    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));

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

    /* Create service thread */
    service =
        serviceCreate(eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    meiASSERT(service != NULL);

    /* 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);

        fprintf(stderr,
                "mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                motion,
                motionType,
                &motionParams,
                returnValue,
                mpiMessage(returnValue, NULL));

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion,
                        returnValue);
                msgCHECK(returnValue);

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

        /* Collect motion events */
        while (returnValue == MPIMessageOK) {
            MPIEventStatus  eventStatus;

            /* Wait for motion event */
            returnValue =
                mpiNotifyEventWait(notify,
                                   &eventStatus,
                                   MPIWaitFOREVER);

            fprintf(stderr,
                    "mpiNotifyEventWait(0x%x, 0x%x, %d) returns 0x%x\n"
                    "\teventStatus: type %d source 0x%x info 0x%x\n",
                    notify,
                    &eventStatus,
                    MPIWaitFOREVER,
                    returnValue,
                    eventStatus.type,
                    eventStatus.source,
                    eventStatus.info[0]);

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

        if (returnValue == MPIMessageOK) {
            MPIStatus   status;

            returnValue =
                motionDone(motion,
                           &status);

            if ((returnValue == MPIMessageOK) &&
                (status.state == MPIStateERROR)) {
                if ((status.action == MPIActionABORT) ||
                    (status.action == MPIActionE_STOP_ABORT)) {
                    double  position[AXIS_COUNT];

                    returnValue =
                        mpiMotionPositionGet(motion,
                                             position,  /* actual */
                                             NULL);     /* command */
                    msgCHECK(returnValue);

                    returnValue =
                        mpiMotionPositionSet(motion,
                                             NULL,      /* actual */
                                             position); /* command */
                    msgCHECK(returnValue);
                }

                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion,
                        returnValue);
                msgCHECK(returnValue);
            }
        }

        putchar('\n');

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

    fprintf(stderr,
            "%s exiting: returnValue 0x%x: %s\n",
            argv[0],
            returnValue,
            mpiMessage(returnValue, NULL));

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

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axisList[index]);
        msgCHECK(returnValue);
    }

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

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

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

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

    return ((int)returnValue);
}


long motionDone(MPIMotion motion,
                MPIStatus *status)
{
    long    returnValue;

    double  actual[AXIS_COUNT];
    double  command[AXIS_COUNT];

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

    printf("MotionDone: status: state %d action %d eventMask 0x%x\n"
           "\tatTarget %d settled %d %s\n",
            status->state,
            status->action,
            status->eventMask,
            status->atTarget,
            status->settled,
            (status->settled == FALSE)
                    ? "=== NOT SETTLED ==="
                    : "");

    returnValue =
        mpiMotionPositionGet(motion,
                             actual,
                             command);
    msgCHECK(returnValue);

    if (returnValue == MPIMessageOK) {
        long    index;

        /* Display axis positions */
        for (index = 0; index < AXIS_COUNT; index++) {
            printf("\taxis[%d]    position: command %11.3lf\tactual %11.3lf\n",
                    index,
                    command[index],
                    actual[index]);
        }
    }

    return (returnValue);
}