compare1.c -- Compare an encoder counter and set an XCVR output when the condition is TRUE.
/* compare1.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/compare1.c 7     7/23/01 2:36p Kevinh $"
#endif

/*

:Compare an encoder counter and set an XCVR output when the condition is TRUE.

Each motion block supports 10 compare registers.   The default configuration
 is two compare registers per motor -- while the last two (8,9) on each motion
 block are reserved for the Auxiliary Encoder (not supported).   The compare
 registers are default mapped as follows.... 0 & 1 for Motor0, 2 & 3 for Motor1,
 10 & 11 for Motor4, etc.  The first Compare for each motor uses the default
 (primary) encoder input for position compare, the second uses the AUX encoder
 input. The equation used below calculates the Compare number for the primary
 motor feedback given the default compare mapping.

    compareNumber = ((motorNumber / MEIXmpMotorsPerBlock) * MEIXmpMaxComparePositions) +
                    ((motorNumber % MEIXmpMotorsPerBlock) * ComparesPerMotor);

A compare register is loaded with a position compare value, a compare operator
 (MPICommandOperatorGREATER or MPICommandOperatorLESS_OR_EQUAL), and an output
 state (sets the Motor's XCVR_C TRUE or FALSE when the compare state is true).

A compare's status can be polled, it does not generate an event.  If the
 compare register's state equals MPICompareStateCOMPARED, the compare
 position is stored and the compare register is ready for re-arming.

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    compare1Main

argMainRENAME(main, compare1)
#endif

#define MOTOR           (4)
#define COMPARE_POS     (15000)
#define ComparesPerMotor    (2) /* Default Compare configuration */

/* XCVR Settings */
#define TRANSCEIVER_CONFIG  (MEIMotorTransceiverConfigCOMPARE) /* XCVR will output Compare logic */
#define TRANSCEIVER_ID      (MEIMotorTransceiverIdC)  /* Must be XCVR_C for Compare */
#define TRANSCEIVER_MASK    (MEIMotorTransceiverMaskC) /* same as above */


int
    main(int    argc,
         char   *argv[])
{
    MPIControl          control;        /* motion controller object */
    MPIAxis             axis;           /* axis object */
    MPIMotor            motor;          /* motor object */
    MEIMotorConfig      motorConfigXmp;  /* contains transceiver configuration */
    MPIMotorIo          io;
    MPICompare          compare;        /* compare object */

    MPICompareParams    compareParams;  /* compare parameters */
    MPICompareStatus    compareStatus;  /* compare status */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    returnValue;        /* return value from library */
    long    argIndex;
    long    motorNumber;
    long    compareNumber;
    double  origin;
    double  actualPosition;

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

    motorNumber =
        (argIndex >= argc)
                ? MOTOR
                : meiPlatformAtol(argv[argIndex++]);

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[motor# (0)]\n",
                            argv[0],
                            ArgUSAGE);
        exit(0);
    }

    /* Calculate default compare number for axisNumber */
    compareNumber = ((motorNumber/MEIXmpMotorsPerBlock) * MEIXmpMaxComparePositions) +
                    ((motorNumber % MEIXmpMotorsPerBlock) * ComparesPerMotor);

    /* 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,
                      motorNumber);
    msgCHECK(mpiAxisValidate(axis));

    /* Read the Axis' Origin */
    returnValue =
        mpiAxisOriginGet(axis,
                         &origin);
    msgCHECK(returnValue);

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


    /* Configure selected transceiver */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Transceiver[TRANSCEIVER_ID].Config = TRANSCEIVER_CONFIG;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

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

    /* Disable compare */
    returnValue =
        mpiCompareArm(compare,
                      FALSE);
    msgCHECK(returnValue);

    /* Set compare parameters */

    /* remember to use the Axis' Origin when calculating the Compare position */
    compareParams.position = (long) (COMPARE_POS + origin);

    /* Configures state of the XCVR output, when Compare is valid */
    compareParams.outputState = TRUE;

    /*
        commandOperator must be MPICommandOperatorGREATER
        or MPICommandOperatorLESS_OR_EQUAL -- anything else is INVALID
     */
    compareParams.commandOperator = MPICommandOperatorGREATER;

    /* Load params */
    returnValue =
        mpiCompareLoad(compare,
                       &compareParams,
                       NULL);
    msgCHECK(returnValue);

    /* Arm the compare */
    returnValue =
        mpiCompareArm(compare,
                      TRUE);
    msgCHECK(returnValue);

    /* State Machine - Poll compare status, update display, etc */
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        returnValue =
            mpiCompareStatus(compare,
                             &compareStatus,
                             NULL);
        msgCHECK(returnValue);

        /* Display XCVR, Compare state and Axis' actual position */
        returnValue =
            mpiMotorIoGet(motor,
                          &io);
        msgCHECK(returnValue);

        returnValue =
            mpiAxisActualPositionGet(axis,
                                     &actualPosition);
        msgCHECK(returnValue);


        printf("\rXCVR_C:0x%x  State:0x%x  ActualPosition:%.0lf",
                io.input & TRANSCEIVER_MASK,    /* XCVR bit, read as input -- input from FPGA */
                compareStatus.state,            /* value of Compare bit (1=ARMED, 2=COMPARED) */
                actualPosition);

        if (compareStatus.state == MPICompareStateCOMPARED) {
            printf("  Compared Position:%.0lf\r",
                    (double) (compareStatus.position[compareNumber % MEIXmpMaxComparePositions] - origin));

            /* Re-arm position compare */
            returnValue =
                mpiCompareArm(compare,
                              TRUE);
            msgCHECK(returnValue);
        }
        else {
            /* clear any previous positions from the display... */
            printf("                             ");
        }
    }

    /* Disarm position compare */
    returnValue =
        mpiCompareArm(compare,
                      FALSE);
    msgCHECK(returnValue);

    /* Delete objects */

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

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

    returnValue = mpiCompareDelete(compare);
    msgCHECK(returnValue);

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

    return ((int)returnValue);
}