UsrLim5.c -- User Limit to watch an analog input and set an output.
/* usrlim5.c */
/* Copyright(c) 1991-2007 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.
*/
/*
:User Limit to watch an analog input and set an output.
This sample code shows how to use the XMP-Series controller "User Limit" feature
which allows the user to program 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.
if (Enabled) {
*OutputPtr = OrMask | ( AndMask & (*OutputPtr) );
}
Please note it is up to the user application to clear output at position "x"
since output remains set after an event even after the condition is no longer
true. "User Limit" is not responsible for monitoring the input behavior and
clearing the output when input goes back to normal level.
__________
/ \ /
---E------------x---------------E-------------------------HIGH
/ \ /
------------------E-----------x---------------------------- LOW
\_________/
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 "sqNode.h"
#include "apputil.h"
/* Analog I/O Configurations */
#define INPUT_MASK (0x0000FFFF) /* mask for analog input 0 */
#define LOW (2000) /* analog trigger LOW ~ 5.0 V */
#define HIGH (4000) /* analog trigger HIGH ~ 2.5 V */
#define OUTPUT_MASK (0x1) /* mask for general motor output */
/* User Limit Event configuration */
#define EVENT_TYPE (MEIEventTypeLIMIT_USER0) /* 0, 1, 2...7 */
/* Notify Wait Timeout */
#define CYCLE_TIME (100) /* msec */
/* SqNode input channel */
#define INPUT_CHANNEL (0) /* 0, 1, 2... */
/* Command line arguments and defaults */
long motorNumber = 0;
Arg argList[] = {
{ "-motor", ArgTypeLONG, &motorNumber, },
{ NULL, ArgTypeINVALID, NULL, }
};
/* Function Prototypes */
long XcvrUserLimitSet(MPIControl control,
MPIMotor motor,
MEISqNode sqNode,
long inputMask,
long outputMask,
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, resetMask;
long motionNumber; /* motion supervisor number */
long axisNumber; /* axis number */
long returnValue; /* return value from library */
Service service;
MPIControlType controlType;
MPIControlAddress controlAddress;
long argIndex;
MEISqNode sqNode;
/* 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) ||
(motorNumber >= MEIXmpMAX_Motors)) {
meiPlatformConsole("usage: %s %s\n"
"\t\t[-motor # (0 .. %d)]\n",
argv[0],
ArgUSAGE,
MEIXmpMAX_Axes - 1,
MEIXmpMAX_MSs - 1,
MEIXmpMAX_Motors - 1);
exit(MPIMessageARG_INVALID);
}
/* Use a one to one relationship between motor, axis, and motion */
motionNumber = motorNumber;
axisNumber = motorNumber;
/* Create motion controller object */
control =
mpiControlCreate(controlType,
&controlAddress);
msgCHECK(mpiControlValidate(control));
/* Initialize motion controller */
returnValue = mpiControlInit(control);
msgCHECK(returnValue);
sqNode = meiSqNodeCreate(control, 0);
msgCHECK(meiSqNodeValidate(sqNode));
/* Create motor object for motorNumber */
motor =
mpiMotorCreate(control,
motorNumber);
msgCHECK(mpiMotorValidate(motor));
/* Create axis object for axisNumber */
axis =
mpiAxisCreate(control,
axisNumber);
msgCHECK(mpiAxisValidate(axis));
/* 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);
mpiEventMaskCLEAR(resetMask);
/* Requests host notification of the event(s) */
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 User Limit */
returnValue =
XcvrUserLimitSet(control,
motor,
sqNode,
INPUT_MASK,
OUTPUT_MASK,
EVENT_TYPE);
msgCHECK(returnValue);
printf("Press any key to exit ...\n");
/* Loop repeatedly */
while (meiPlatformKey(MPIWaitPOLL) <= 0) {
MPIEventStatus eventStatus;
MEIEventStatusInfo *info;
/* Wait for events */
returnValue =
mpiNotifyEventWait(notify,
&eventStatus,
(MPIWait)CYCLE_TIME);
/* Ignore timeouts */
if (returnValue == MPIMessageTIMEOUT) {
returnValue = MPIMessageOK;
}
else {
msgCHECK(returnValue);
info = (MEIEventStatusInfo *)eventStatus.info;
if (eventStatus.type == MEIEventTypeLIMIT_USER0){
/* User Limit Event from motor source */
printf("\nUser Limit #0, type %d source 0x%x info 0x%x",
eventStatus.type,
eventStatus.source,
eventStatus.info[0]);
}
}
}
printf("\n");
/* Delete objects */
returnValue = serviceDelete(service);
msgCHECK(returnValue);
returnValue = mpiEventMgrDelete(eventMgr);
msgCHECK(returnValue);
returnValue = mpiNotifyDelete(notify);
msgCHECK(returnValue);
returnValue = meiSqNodeDelete(sqNode);
msgCHECK(returnValue);
returnValue = mpiMotionDelete(motion);
msgCHECK(returnValue);
returnValue = mpiAxisDelete(axis);
msgCHECK(returnValue);
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
returnValue = mpiControlDelete(control);
msgCHECK(returnValue);
return ((int)returnValue);
}
long XcvrUserLimitSet(MPIControl control,
MPIMotor motor,
MEISqNode sqNode,
long inputMask,
long outputMask,
MEIEventType eventType)
{
/* Pointers to firmware and buffer data */
MEIXmpData *firmware;
MEIXmpBufferData *buffer;
/* Motor event configuration handle */
MEIMotorEventConfig motorEventConfig;
MPIEventMask resetMask;
long returnValue;
long motorIndex;
/* Pointer to analog input */
long* analogPtr;
/* Determine motor number */
returnValue =
mpiMotorNumber(motor,
&motorIndex);
/* Get pointer to XMP firmware */
if(returnValue == MPIMessageOK) {
returnValue =
mpiControlMemory(control,
&firmware,
&buffer);
msgCHECK(returnValue);
}
mpiEventMaskCLEAR(resetMask);
if (returnValue == MPIMessageOK) {
/* Reset EventMask when an event is generated */
if (eventType == MEIEventTypeLIMIT_USER0) {
status = MEIXmpStatusLIMIT;
mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER0);
}
/* Get motor event configuration handle */
returnValue =
mpiMotorEventConfigGet(motor,
(MPIEventType)eventType,
NULL,
&motorEventConfig);
}
if (returnValue == MPIMessageOK) {
/* Get Slice I/O input address */
returnValue = meiSqNodeAnalogInPtr(sqNode,
INPUT_CHANNEL,
&inputMask,
&analogPtr);
/* Set up the Condition[0] block. The operator between the value in
the SourceAddress (masked by the Mask), and LimitValue.l, is
MEIXmpLimitTypeGT (greater than). Thus, when the value in
SourceAddress is greater than condition[0].LimitValue.g32.l then an
event will be generated.
*/
motorEventConfig.Condition[0].Type = MEIXmpLimitTypeGT;
motorEventConfig.Condition[0].SourceAddress = analogPtr;
motorEventConfig.Condition[0].Mask = inputMask;
motorEventConfig.Condition[0].LimitValue.g32.l = HIGH;
/* Set up the Condition[1] block. The operator between the value in
the SourceAddress (masked by the Mask), and LimitValue.l, is
MEIXmpLimitTypeLT (less than). Thus, when the value in
SourceAddress is less than condition[1].LimitValue.g32.l then an
event will be generated.
*/
motorEventConfig.Condition[1].Type = MEIXmpLimitTypeLT;
motorEventConfig.Condition[1].SourceAddress = analogPtr;
motorEventConfig.Condition[1].Mask = inputMask;
motorEventConfig.Condition[1].LimitValue.g32.l = LOW;
motorEventConfig.Status = MEIXmpStatusLIMIT;
/* Determine logic result when Condition[0] or Condition[1] is true */
motorEventConfig.Logic = MEIXmpLogicOR;
/* Set general purpose motor output address */
motorEventConfig.Output.OutputPtr =
&firmware->Motor[motorIndex].IO.MotorOutput;
motorEventConfig.Output.Enabled = TRUE;
motorEventConfig.Output.AndMask = 0xffffffff;
motorEventConfig.Output.OrMask = 0x10;
/* Set motor event configuration */
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;
}
|