.

     

MPI Application Template
template.c
 

UsrLim3.c -- Position comparison using User Limits to generate events and outputs.
/* UsrLim3.c */

/* Copyright(c) 1991-2006 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.
 */

/*

:Position comparison using User Limits to generate events and outputs.

This sample code shows how to configure the XMP controller's User Limits
 to compare an axis' actual position to a specific position value.  If the
 actual position is greater than or equal to the value specified, then
 the controller will generate a User Event to the Host.  Additionally,
 a Motor I/O bit is configured for an output.  When the User Limit triggers
 an event, an output bit will be set or cleared.

The function CompareLimitSet(...) demonstrates how to configure a
 User Limit for position compare.  There are two positions compared,
 "positionEnable" and "positionDisable" which specify the range in which
 the output is written.  The output bit is specified in the "outputMask"
 and the state is specified by "enableOutput".

Note, each User Limit configuration can only apply a single output AND and
 OR mask.  Thus, to set an output requires a User Limit, and to clear
 an output requires another User Limit.  Be careful not to configure the
 position compare values that would cause more than one User Limit to write
 to the output simultaneously.


The XMP-Series controller "User Limit" feature allows the user to program a
 the result of two logical condition to generate an event to the host.  Also,
 a "User Limit" can be configured to write an "output" to any XMP memory
 location, using an AND mask and OR mask.

Here is the "User Limit" block structure:

typedef struct {
    MEIXmpLimitType         Type;
    void                    *SourceAddress;
    long                    Mask;
    MEIXmpGenericValue      LimitValue;
} MEIXmpLimitCondition;

typedef struct {
    long                    AndMask;
    long                    OrMask;
    long                    *OutputPtr;
    long                    Enabled;
} MEIXmpLimitOutput;

typedef struct {
    MEIXmpLimitCondition    Condition[MEIXmpLimitConditions];
    MEIXmpStatus            Status;
    MEIXmpLogic             Logic;
    MEIXmpLimitOutput       Output;
    long                    Count;
    long                    State;
} MEIXmpLimitData;


MEIXmpLimitTypes are the operators that are used for the User Limit's
 Condition[0] and Condition[1].  They are found in xmp.h.

*SourceAddress is a pointer to an XMP memory location.

Mask is ANDed with the value located at the *SourceAddress.

LimitValue is compared with the masked value located at *SourceAddress,
 using the Type operator.

Status defines the status bit used to generate an event to the host.

MEIXmpLogic is the logic applied between the two condition block outputs,
 Condition[0] and Condition[1]:

 MEIXmpLogicNEVER
    Does NOT evaluate Condition[0], Condition[1].  No event is generated.

 MEIXmpLogicSINGLE
    Only evaluates Condition[0].  Event is generated if Condition[0] is TRUE.

 MEIXmpLogicOR
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    OR Condition[1]) = TRUE.

 MEIXmpLogicAND
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    AND Condition[1]) = TRUE.

The other MEIXmpLogic enums in xmp.h are for internal use only.

*OutputPtr is a pointer to an XMP memory location.

AndMask is ANDed, and OrMask is ORed with the value located at
 *OutputPtr when the resultant MEIXmpLogic applied Condition[0] and
 Condition[1] are TRUE.

Count and State are for internal use only.  Do not write these values.
  The MPI method, mpiMotorEventConfigSet(...) will not write these values.


The XMP supports up to 16 User Limits per motor.  The User Limit processing
 occurs in the firmware background task.  For maximum efficiency, the XMP only
 processes the User Limits (in order 0, 1, 2, etc.), up to the largest User
 Limit number that has (motorEventConfig.Logic ! = MEIXmpLogicNEVER).

For example:
 If UserLimit 0 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    only process the first UserLimit for each motor.
 If UserLimit 3 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    process UserLimits number 0, 1, 2, and 3 for each motor.

It's best to use the lower numbered UserLimits for maximum efficiency.  When
 finished using UserLimits, it's a good idea to set the Logic to
 MEIXmpLogicNEVER.

Warning!  This is a sample program to assist in the integration of an
 MEI 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"

#define MOTION_COUNT (2)

/* Motor I/O Configurations */
#define OUTPUT_BIT      (MPIMotorGeneralIo0) /* index to bit #0 */
#define OUTPUT_MASK     (0x1)             /* mask for bit #0 */


/* Compare positions to enable/disable output */
long comparePosition[] = {
    1000,   /* enable */
    2000,   /* disable */
    5000,
    6000,
    10000,
    11000,
    15000,
    16000   /* disable */
};

/* User Limits for compare positions */
MEIEventType eventType[] = {
    MEIEventTypeLIMIT_USER0,
    MEIEventTypeLIMIT_USER1,
    MEIEventTypeLIMIT_USER2,
    MEIEventTypeLIMIT_USER3,
    MEIEventTypeLIMIT_USER4,
    MEIEventTypeLIMIT_USER5,
    MEIEventTypeLIMIT_USER6
};

#define LIMIT_COUNT (sizeof(eventType) / sizeof(long))


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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT] = {
    25000.0,
    0.0,
};

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

/* Motion Parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0], &position[0],   },
    {   &trajectory[1], &position[1],   },
};

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

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


/* Function Prototypes */
long CompareLimitSet(MPIAxis axis,
                     MPIMotor motor,
                     long positionEnable,
                     long positionDisable,
                     long outputMask,
                     long enableOutput,
                     MEIEventType eventType);

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

    MPIEventMask    eventMask;
    MEIMotorConfig  motorConfigXmp;  /* XMP motor I/O configuration */

    long    returnValue;    /* return value from library */

    long    index;
    long    motionDone;     /* flag when Done occurs */

    Service service;

    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 >= MEIXmpMAX_Axes) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motorNumber >= MEIXmpMAX_Motors) ||
        (motionType < MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 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 for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

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

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

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(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);

    /* Configure the specified OUTPUT_BIT */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Io[OUTPUT_BIT].Type = MEIMotorIoTypeOUTPUT;

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

    /* Configure the Position Compares, using User Limits */
    for (index = 0; index < (long)LIMIT_COUNT; index++) {
        long enableOutput = ((index % 2) ? FALSE:TRUE);

        printf("\nEn:%d", enableOutput);

        returnValue =
            CompareLimitSet(axis,
                            motor,
                            comparePosition[index],
                            comparePosition[index + 1],
                            OUTPUT_MASK,
                            enableOutput,
                            eventType[index]);
        msgCHECK(returnValue);
    }

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

    /* Loop repeatedly */
    index       = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        if (motionDone) {
            MPIMotionParams     motionParams;       /* motion parameters */

            /* fill in the MPIMotionParams structure */
            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;
                }
            }

            printf("\n\nMotion Start...");

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

            motionDone = FALSE;
        }

        /* Wait for events */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        info = (MEIEventStatusInfo *)eventStatus.info;

        switch (eventStatus.type) {
            /* In Coarse Event from axis source */
            case MEIEventTypeIN_POSITION_COARSE: {
                printf("\nInCoarse (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeIN_POSITION_FINE: {
                printf("\nInFine (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeAT_TARGET: {
                printf("\nAtTarget (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* Motion Done Event from motion source */
            case MPIEventTypeMOTION_DONE: {
                printf("\nDone (%ld)",
                       info->data.motion.sampleCounter);

                motionDone = TRUE;

                if (++index >= MOTION_COUNT) {
                    index = 0;
                }
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER0: {
                printf("\nUser Limit #0, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER1: {
                printf("\nUser Limit #1, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER2: {
                printf("\nUser Limit #2, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER3: {
                printf("\nUser Limit #3, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER4: {
                printf("\nUser Limit #4, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER5: {
                printf("\nUser Limit #5, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER6: {
                printf("\nUser Limit #6, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER7: {
                printf("\nUser Limit #7, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }

            default: {
                printf("mpiNotifyEventWait() returns 0x%x\n"
                    "\teventStatus: type %d source 0x%x info 0x%x\n",
                    returnValue,
                    eventStatus.type,
                    eventStatus.source,
                    eventStatus.info[0]);
                break;
            }
        }
    }

    printf("\n");

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

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

    returnValue = mpiAxisDelete(axis);
    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 CompareLimitSet(MPIAxis axis,
                     MPIMotor motor,
                     long positionEnable,
                     long positionDisable,
                     long outputMask,
                     long enableOutput,
                     MEIEventType eventType)
{
    MPIControl          control;
    MEIXmpAxis          *xmpAxis;
    MEIXmpData          *firmware;

    MEIMotorEventConfig motorEventConfig;
    MEIXmpStatus        status;

    long                motorIndex;
    long                returnValue;
    MPIEventMask        resetMask;

    /* Determine motor number */
    returnValue =
        mpiMotorNumber(motor,
                       &motorIndex);

    /* Determine control handle */
    if(returnValue == MPIMessageOK) {
        control = mpiMotorControl(motor);
        returnValue = mpiControlValidate(control);
    }

    /* Get pointer to XMP firmware */
    if(returnValue == MPIMessageOK) {
        returnValue =
            mpiControlMemory(control,
                             (void **)&firmware,
                             NULL);
    }

    if (returnValue == MPIMessageOK) {
        returnValue  =
            mpiAxisMemory(axis,
                          (void *)&xmpAxis);
    }

    mpiEventMaskCLEAR(resetMask);

    if (returnValue == MPIMessageOK) {
        switch (eventType) {
            case MEIEventTypeLIMIT_USER0: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER0);
                break;
            }
            case MEIEventTypeLIMIT_USER1: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER1);
                break;
            }
            case MEIEventTypeLIMIT_USER2: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER2);
                break;
            }
            case MEIEventTypeLIMIT_USER3: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER3);
                break;
            }
            case MEIEventTypeLIMIT_USER4: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER4);
                break;
            }
            case MEIEventTypeLIMIT_USER5: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER5);
                break;
            }
            case MEIEventTypeLIMIT_USER6: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER6);
                break;
            }
            case MEIEventTypeLIMIT_USER7: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER7);
                break;
            }
            default:
                printf("\nError, invalid event type\n");
                break;
        }

        returnValue =
            mpiMotorEventConfigGet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    if (returnValue == MPIMessageOK) {
        /* Write to Output between positionEnable and positionDisable */
        if (positionDisable > positionEnable ) {
            motorEventConfig.Condition[0].Type = MEIXmpLimitTypeGE;
            motorEventConfig.Condition[1].Type = MEIXmpLimitTypeLT;
        }

        /* Write to Output between positionDisable and positionEnable */
        if (positionDisable <= positionEnable ) {
            motorEventConfig.Condition[0].Type = MEIXmpLimitTypeLT;
            motorEventConfig.Condition[1].Type = MEIXmpLimitTypeGE;
        }

        if (enableOutput) {
            /* Enable output */
            motorEventConfig.Output.AndMask = 0xFFFFFFFF;
            motorEventConfig.Output.OrMask = outputMask;
        }
        else {
            /* Disable Output */
            motorEventConfig.Output.AndMask = (~outputMask);
            motorEventConfig.Output.OrMask = 0x0;
        }

        /* Set up the Condition[0] block. */
        motorEventConfig.Condition[0].SourceAddress = &(xmpAxis->ActPosition);
        motorEventConfig.Condition[0].Mask = 0xffffffff;
        motorEventConfig.Condition[0].LimitValue.g32.l = positionEnable;

        /* Set up the Condition[1] block. */
        motorEventConfig.Condition[1].SourceAddress = &(xmpAxis->ActPosition);
        motorEventConfig.Condition[1].Mask = 0xffffffff;
        motorEventConfig.Condition[1].LimitValue.g32.l = positionDisable;

        motorEventConfig.Status = status;
        /* Determine logic result from Condition[0] AND Condition[1] */
        motorEventConfig.Logic  = MEIXmpLogicAND;

        motorEventConfig.Output.OutputPtr =
            &firmware->Motor[motorIndex].IO.MotorOutput; /* General purpose motor output address */
        motorEventConfig.Output.Enabled = TRUE;

        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    /* Reset event in case conditions have already been satisfied */
    if (returnValue == MPIMessageOK) {
        returnValue =
                mpiMotorEventReset(motor,
                                   resetMask);
    }

    return returnValue;
}


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