CutNPaste.c --
/**********************************************************************
A collection of various potentially useful functions. Nothing in here
approaches supported status.
Feel free to add, but not remove functions from this file. We only ask
that you add some comments above each function and add the name and
one line (or so) description to the following list to make it easy
for others to use this file.
After adding something to this file, PLEASE compile a program with it
to make sure it isn't broke! Make sure to add appropriate #includes.
**********************************************************************/
/***********************************************************************
Listing of functions in this file:
* trapMove() Commands a simple trap move. It checks for an
appropriate state first and returns error codes, if
appropriate.
* sCurveMove() Commands a simple S Curve move. It checks for an appropriate
state first and returns error codes, if appropriate.
* ptMove() Commands a pt move. Can be used to make appended lists.
* pvtMove() Commands a pvt move. Can be used to make appended lists.
* velMove() Commands a simple vel move. It checks for an appropriate
state first and returns error codes, if appropriate.
* isMotionDone() returns a 1 if the motion is idle, a 0 if it is not.
* waitForMotionDone() Stalls the program in a 10 msec polling loop until it
gets an MPIMotionIDLE
* clearError() clears all the errors on an MS and enables the amps on that MS.
* motionAxisLoop() For every axis attached to a motion supervisor (perform some action) [EXAMPLE]
* axisMotorLoop() For every motor attached to an axis (perform some action) [EXAMPLE]
* motionMotorLoop() For every motor attached to a motion supervisor (perform some action) [EXAMPLE]
* axisAmpEnable() Enable the amplifier for every motor attached to an axis
* axisAmpDisable() Disable the amplifier for every motor attached to an axis
* motionAmpEnable() Enable the amplifier for every motor attached to a motion supervisor
* motionAmpDisable() Disable the amplifier for every motor attached to a motion supervisor
* setIp() configures the program to use a controller at address "server"
* parseCommandLine() Parsing for apps that need command line arguments (example)
* basicParsing() Perform basic command line parsing. (-control -server -port -trace)
* programInit() / programCleanup():
A bare minimum object creation / deletion for programs of the scope of
motion1 or so.
* programInitSingle() Create and initialize MPI objects.
[One of each object -- Use as a model]
* programCleanupSingle() Perform certain cleanup actions and delete MPI objects
[One of each object -- Use as a model]
* programInitMultiple() Create and initialize MPI objects.
[Arrays of some objects -- Use as a model]
* programCleanupMultiple() Perform certain cleanup actions and delete MPI objects
[Arrays of some objects -- Use as a model]
* programInitSingleWithMapping() Create and initialize MPI objects, and place MS's axis map on XMP
[One of each object -- Use as a model]
* programInitMultipleWithMapping() Create and initialize MPI objects, and place MSs' axis maps on XMP
[Arrays of some objects -- Use as a model]
* homeLimitOnInput() Configure Home Limit to be triggered on the Home Input rather than the capture
* enableUserLimit() Configures and enables one user limit
* disableUserLimit() Disables and erases the configuration of one user limit
* userLimitEnable() Enables or disables one user limit
This function does not change (most of) the configuration of a user limit.
* sequenceCommandAdd() Creates a command (MPICommand object) and appends it to
sequence's list of commands.
* sequenceProgramCreate() Shows how one can create a MPISequence program.
* sequenceProgramDelete(MPISequence *sequence) Removes and deletes all command objects on sequence's
command list and then deletes sequence.
* sequenceRun() Starts a sequence, waits for the user to press a key and then
stops the sequence.
* recordData() Start the XMP's recorder, get data, and stop the recorder
* configureRecorder() Example of how to configure the data recorder object
* stopRecorder() Stops the data recorder ignoring the MPIRecorderMessageSTOPPED
message if the recorder is already stopped.
* setTorqueLimits() EventType is MPIEventTypeLIMIT_USERn -- Choose the user limit you want to use.
The axis will abort out after continually exceeding the high or low limit
for duration seconds. highLimit sets the positive torque limit. lowLimit
sets the negative torque limit.
* controlAddressGet() Works like mpiControlMemoryGet, but gets the address of location in the XMP memory space. This is the same number as you see as the address in VM3.
* controlAddrToAddr() Works like mpiControlMemorySet, but writes one firmware address to another. Host / controller memory spaces can be ignored. Useful
in pointer hocus pocus like can be done in VM3.
* SetDualLoop() Configures a filter to be dual loop. Requires using the PIV algorithm.
** add yours here **
***********************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"
long trapMove(MPIMotion *motion,
MPITrajectory *trajectory,
double *position);
long sCurveMove(MPIMotion *motion,
MPITrajectory *trajectory,
double *position);
long ptMove(MPIMotion motion,
double point[],
double time[],
long numPoints,
long final);
long pvtMove(MPIMotion motion,
double point[],
double velocity[],
double time[],
long numPoints,
long final);
long velMove(MPIMotion *motion,
MPITrajectory *trajectory);
long isMotionDone(MPIMotion motion);
void waitForMotionDone(MPIMotion motion);
long clearError(MPIMotion motion);
void motionAxisLoop(MPIMotion motion);
void axisMotorLoop(MPIAxis axis);
void motionMotorLoop(MPIMotion motion);
void axisAmpEnable(MPIAxis axis);
void axisAmpDisable(MPIAxis axis);
void motionAmpEnable(MPIMotion motion);
void motionAmpDisable(MPIMotion motion);
void setIp(MPIControlType *controlType,
MPIControlAddress *controlAddress,
char *server);
long parseCommandLine(long *motorNumber,
int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress);
void basicParsing(int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress);
long programInit(long motorNumber,
MPIControl *control,
MPIMotor *motor,
MPIAxis *axis,
MPIMotion *motion,
MPIControlType *controlType,
MPIControlAddress *controlAddress);
long programCleanup(MPIMotion *motion,
MPIAxis *axis,
MPIMotor *motor,
MPIControl *control);
void programInitSingle(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long motionNumber,
MPIAxis *axis,
long axisNumber,
MPIFilter *filter,
long filterNumber,
MPIMotor *motor,
long motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long sequenceNumber,
MPICapture *capture,
long captureNumber,
MPICompare *compare,
long compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service);
void programCleanupSingle(MPIControl *control,
MPIMotion *motion,
MPIAxis *axis,
MPIFilter *filter,
MPIMotor *motor,
MPIRecorder *recorder,
MPISequence *sequence,
MPICapture *capture,
MPICompare *compare,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service);
void programInitMultiple(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long numberOfMotions,
long *motionNumber,
MPIAxis *axis,
long numberOfAxes,
long *axisNumber,
MPIFilter *filter,
long numberOfFilters,
long *filterNumber,
MPIMotor *motor,
long numberOfMotors,
long *motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
long *sequenceNumber,
MPICapture *capture,
long numberOfCaptures,
long *captureNumber,
MPICompare *compare,
long numberOfCompares,
long *compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service);
void programCleanupMultiple(MPIControl *control,
MPIMotion *motion,
long numberOfMotions,
MPIAxis *axis,
long numberOfAxes,
MPIFilter *filter,
long numberOfFilters,
MPIMotor *motor,
long numberOfMotors,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
MPICapture *capture,
long numberOfCaptures,
MPICompare *compare,
long numberOfCompares,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service);
void programInitSingleWithMapping(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long motionNumber,
MPIAxis *axis,
long axisNumber,
MPIFilter *filter,
long filterNumber,
MPIMotor *motor,
long motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long sequenceNumber,
MPICapture *capture,
long captureNumber,
MPICompare *compare,
long compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service);
void programInitMultipleWithMapping(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long numberOfMotions,
long *motionNumber,
MPIAxis *axis,
long numberOfAxes,
long *axisNumber,
MPIFilter *filter,
long numberOfFilters,
long *filterNumber,
MPIMotor *motor,
long numberOfMotors,
long *motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
long *sequenceNumber,
MPICapture *capture,
long numberOfCaptures,
long *captureNumber,
MPICompare *compare,
long numberOfCompares,
long *compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service);
void homeLimitOnInput(MPIMotor motor,
long activeHigh);
void enableUserLimit(MPIMotor motor,
long enable);
void disableUserLimit(MPIMotor motor,
MPIEventType limit);
void userLimitEnable(MPIMotor motor,
MPIEventType limit,
long enable);
long sequenceCommandAdd(MPISequence sequence,
MPICommandType commandType,
MPICommandParams *commandParams,
const char *label);
MPISequence sequenceProgramCreate(MPIControl control);
long sequenceProgramDelete(MPISequence *sequence);
void sequenceRun(MPISequence sequence);
long recordData(MPIRecorder recorder,
long numRecords,
long period,
long eventCount,
MPIRecorderRecord *records);
void configureRecorder(MPIRecorder recorder);
void stopRecorder(MPIRecorder recorder);
long SetTorqueLimits(MPIMotor motor,
MPIEventType eventType,
float highLimit,
float lowLimit,
float duration); /* in seconds */
long controlAddressGet(MPIControl control, void *dst, void *src);
long controlAddrToAddr(MPIControl control, void *dst, void *src);
void SetDualLoop(MPIControl control, int outerMotor, int innerMotor);
/*******************************************************
trapMove commands a simple trap move to the specified motion supervisor with
the specified trajectory and position information. It checks for an idle
state before it commands the move. If it gets something an idle state, it
commands a motionStart, if it gets a moving state, it commands a
motionModify. If it gets something else, no move is commanded and an error
code is returned.
Error code description
0 No Error (MPIStateMoving, MPIStateIDLE,MPIStateSTOPPING)
1 MPIStateERROR
2 None of the above
*******************************************************/
long trapMove(MPIMotion *motion,
MPITrajectory *trajectory,
double *position)
{
MPIMotionParams params; /* Motion parameters */
MPIStatus status; /* Status handle */
long returnValue = MPIMessageOK;
params.trapezoidal.trajectory = trajectory;
params.trapezoidal.position = position;
returnValue =
mpiMotionStatus(*motion,
&status,
NULL);
msgCHECK(returnValue);
switch (status.state) /* Check state and take the appropriate action */
{
case MPIStateIDLE: /* IDLE is OK, start a move. */
{
/* Start motion */
returnValue =
mpiMotionStart(*motion,
MPIMotionTypeTRAPEZOIDAL,
¶ms);
msgCHECK(returnValue);
break;
}
case MPIStateSTOPPING: /* STOPPING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);
break;
}
case MPIStateMOVING: /* MOVING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);
break;
}
case MPIStateERROR: /* ERROR is not OK. */
{
returnValue = MPIMotionMessageERROR;
break;
}
default: /* Don't know what happened. */
{
returnValue = MPIMessageFATAL_ERROR;
break;
}
}
return returnValue;
}
/*******************************************************
sCurveMove commands a simple trap move to the specified motion supervisor
with the specified trajectory and position information. It checks for an
idle state before it commands the move. If it gets something an idle state,
it commands a motionStart, if it gets a moving state, it commands a
motionModify. If it gets something else, no move is commanded and an error
code is returned.
Error code description
0 No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
1 MPIStateERROR
2 None of the above
*******************************************************/
long sCurveMove(MPIMotion *motion,
MPITrajectory *trajectory,
double *position)
{
MPIMotionParams params; /* Motion parameters */
MPIStatus status; /* Status handle */
long returnValue = MPIMessageOK;
params.sCurve.trajectory = trajectory;
params.sCurve.position = position;
returnValue =
mpiMotionStatus(*motion,
&status,
NULL);
msgCHECK(returnValue);
switch (status.state) /* Check state and take the appropriate action */
{
case MPIStateIDLE: /* IDLE is OK, start a move. */
{
/* Start motion */
returnValue =
mpiMotionStart(*motion,
MPIMotionTypeS_CURVE,
¶ms);
msgCHECK(returnValue);
break;
}
case MPIStateSTOPPING: /* STOPPING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);
break;
}
case MPIStateMOVING: /* MOVING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);
break;
}
case MPIStateERROR: /* ERROR is not OK. */
{
returnValue = MPIMotionMessageERROR;
break;
}
default: /* Don't know what happened. */
{
returnValue = MPIMessageFATAL_ERROR;
break;
}
}
return returnValue;
}
/******************************************************************************
ptMove commands a PT move
******************************************************************************/
long ptMove(MPIMotion motion,
double point[],
double time[],
long numPoints,
long final)
{
MPIMotionParams params; /* Motion parameters */
long returnValue = MPIMessageOK;
/* Initialize motion params structure */
params.pt.pointCount = numPoints; /* Number of time points */
params.pt.position = point; /* Position array */
params.pt.time = time; /* Time array */
params.pt.point.retain = 0; /* Flush frame buffer after execution */
params.pt.point.final = final; /* Last point */
params.pt.point.emptyCount = 5; /* Start E-Stop if frames left to execute */
/* is less than this limit. -1 disables */
if(!isMotionDone(motion))
{
returnValue =
mpiMotionModify(motion,
(MPIMotionTypePT | MPIMotionAttrMaskAPPEND),
¶ms);
msgCHECK(returnValue);
printf("\nappend\n");
}
else{
/* Start motion */
returnValue =
mpiMotionStart(motion,
(MPIMotionTypePT),
¶ms);
msgCHECK(returnValue);
}
return returnValue;
}
/******************************************************************************
pvtMove commands a PVT move
******************************************************************************/
long pvtMove(MPIMotion motion,
double point[],
double velocity[],
double time[],
long numPoints,
long final)
{
MPIMotionParams params; /* Motion parameters */
long returnValue = MPIMessageOK;
/* Initialize motion params structure */
params.pvt.pointCount = numPoints; /* Number of time points */
params.pvt.position = point; /* Position array */
params.pvt.velocity = velocity;
params.pvt.time = time; /* Time array */
params.pvt.point.retain = 0; /* Flush frame buffer after execution */
params.pvt.point.final = final; /* Last point */
params.pvt.point.emptyCount = 5; /* E-Stop if frames left to execute */
/* is less than this limit. -1 disables */
if(!isMotionDone(motion))
{
returnValue =
mpiMotionModify(motion,
(MPIMotionTypePVT | MPIMotionAttrMaskAPPEND),
¶ms);
msgCHECK(returnValue);
printf("\nappend\n");
}
else{
/* Start motion */
returnValue =
mpiMotionStart(motion,
(MPIMotionTypePVT),
¶ms);
msgCHECK(returnValue);
}
return returnValue;
}
/*******************************************************
velMove commands a simple trap move to the specified motion supervisor with
the specified trajectory information. It checks for an idle state before
it commands the move. If it gets something an idle state, it commands a
motionStart, if it gets a moving state, it commands a motionModify. If it
gets something else, no move is commanded and an error code is returned.
Error code description
0 No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
1 MPIStateERROR
2 None of the above
*******************************************************/
long velMove(MPIMotion *motion,
MPITrajectory *trajectory)
{
MPIMotionParams params; /* Motion parameters */
MPIStatus status; /* Status handle */
long returnValue = MPIMessageOK;
params.velocity.trajectory = trajectory;
returnValue =
mpiMotionStatus(*motion,
&status,
NULL);
msgCHECK(returnValue);
switch (status.state) /* Check state and take the appropriate action */
{
case MPIStateIDLE: /* IDLE is OK, start a move. */
{
/* Start motion */
returnValue =
mpiMotionStart(*motion,
MPIMotionTypeVELOCITY,
¶ms);
msgCHECK(returnValue);
break;
}
case MPIStateSTOPPING: /* STOPPING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);
break;
}
case MPIStateMOVING: /* MOVING is OK, modify a move. */
{
/* Modify the executing motion profile */
returnValue =
mpiMotionModify(*motion,
MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
¶ms);
if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);
break;
}
case MPIStateERROR: /* ERROR is not OK. */
{
returnValue = MPIMotionMessageERROR;
break;
}
default: /* Don't know what happened. */
{
returnValue = MPIMessageFATAL_ERROR;
break;
}
}
return returnValue;
}
/*********************************************************************
isMotionDone() returns a 1 if the motion is idle, a 0 if it is not.
**********************************************************************/
long isMotionDone(MPIMotion motion)
{
MPIStatus status;
long returnValue = FALSE;
returnValue =
mpiMotionStatus(motion,
&status,
NULL);
msgCHECK(returnValue);
if(status.state == MPIStateIDLE)
{
returnValue = TRUE;
}
return returnValue;
}
/*********************************************************************
waitForMotionDone() polls motion to see if the axis is in an idle or error
state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.
**********************************************************************/
void waitForMotionDone(MPIMotion motion)
{
MPIStatus status;
long motionDone;
long returnValue = MPIMessageOK;
/* Poll status until motion done */
motionDone = FALSE;
while (motionDone == FALSE) {
/* Get the motion supervisor status */
returnValue =
mpiMotionStatus(motion,
&status,
NULL);
msgCHECK(returnValue);
switch (status.state) {
case MPIStateSTOPPING:
case MPIStateMOVING: {
/* Sleep for 10ms and give up control to other threads */
mpiPlatformSleep(10);
break;
}
case MPIStateIDLE:
case MPIStateERROR:
case MPIStateSTOPPING_ERROR: {
/* Motion is done */
motionDone = TRUE;
break;
}
default: {
/* Unknown State */
fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
msgCHECK(MPIMessageFATAL_ERROR);
break;
}
}
}
}
/******************************************************************************
clearError() clears all the errors on an MS and enables the amps on that MS.
It does this by commanding a mpiMotionAction(reset) and then waits a couple
samples, tries again if it needs to, then waits a couple samples and makes
sure it happened, returning an error if it didn't, and enables all the amps on
the MS using motionAmpEnable().
******************************************************************************/
long clearError(MPIMotion motion)
{
MPIStatus status; /* Status handle */
long returnValue;
returnValue = mpiMotionAction(motion, MPIActionRESET);
msgCHECK(returnValue);
mpiControlSampleWait(mpiMotionControl(motion), 2);
returnValue =
mpiMotionStatus(motion,
&status,
NULL);
msgCHECK(returnValue);
if(status.state == MPIStateERROR)
{
returnValue = mpiMotionAction(motion, MPIActionRESET);
msgCHECK(returnValue);
}
mpiControlSampleWait(mpiMotionControl(motion), 2);
returnValue =
mpiMotionStatus(motion,
&status,
NULL);
msgCHECK(returnValue);
if(status.state == MPIStateERROR)
{
returnValue = MPIMotionMessageERROR;
}
motionAmpEnable(motion);
return returnValue;
}
/*****************************************************************************
For every axis attached to a motion supervisor (perform some action)
This is a model for any MPI Object that has other MPI objects attached to
it via a linked list. (i.e. there exists mpiXxxYyyFirst(...) and
mpiXxxYyyNext(...) functions.)
******************************************************************************/
/* For every axis attached to a motion supervisor ... */
void motionAxisLoop(MPIMotion motion)
{
MPIAxis axis;
/* For every axis attached to a motion ... */
for (axis = mpiMotionAxisFirst(motion);
axis != MPIHandleVOID;
axis = mpiMotionAxisNext(motion, axis)) {
/* Place your code here */
}
}
/*****************************************************************************
For every motor attached to an axis (perform some action). This is useful
when motor objects haven't been created or when someone is using gantry code.
This is a model for any MPI Object that has other MPI objects attached to
it via object maps. (i.e. there exits an mpiXxxYyyMap(...) function.)
******************************************************************************/
/* For every motor attached to an axis ... */
void axisMotorLoop(MPIAxis axis)
{
MPIControl control;
MPIMotor motor;
MPIObjectMap map;
long motorIndex;
long returnValue;
/* Get the controller handle */
control = mpiAxisControl(axis);
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {
if (mpiObjectMapBitGET(map, motorIndex)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorIndex);
msgCHECK(mpiMotorValidate(motor));
/* Place your code here */
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
For every motor attached to a motion supervisor (perform some action)
This is a model for any MPI Object (Father) that has other MPI objects
(Children) attached to it indirectly in the following way:
MPIFather --(linked list)--> MPIIntermediate --(object map)-> MPIChild
******************************************************************************/
/* For every motor attached to a motion supervisor ... */
void motionMotorLoop(MPIMotion motion)
{
MPIControl control;
MPIAxis axis;
MPIMotor motor;
MPIObjectMap map;
MPIObjectMap motionMotorMap;
long motorIndex;
long returnValue;
/* Get the controller handle */
control = mpiMotionControl(motion);
for (axis = mpiMotionAxisFirst(motion);
axis != MPIHandleVOID;
axis = mpiMotionAxisNext(motion, axis)) {
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
/* Add map to motionMotorMap */
motionMotorMap |= map;
}
/* For every motor ... */
for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {
if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorIndex);
msgCHECK(mpiMotorValidate(motor));
/* Place your code here */
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
Enable the amplifier for every motor attached to an axis. This is useful
when motor objects haven't been created or when someone is using gantry code.
This code also sets the command position equal to the actual position and
resets the integrator before enabling the amplifiers so that the motors will
not "jump."
******************************************************************************/
/* Enable the amplifier for every motor attached to an axis */
void axisAmpEnable(MPIAxis axis)
{
MPIControl control;
MPIMotor motor;
MPIFilter filter;
MPIObjectMap axisMotorMap;
MPIObjectMap motorFilterMap;
long motorIndex;
long filterIndex;
long returnValue;
double position;
long enableState;
/* Get the controller handle */
control = mpiAxisControl(axis);
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &axisMotorMap);
msgCHECK(returnValue);
/* For every motor ... */
for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {
if (mpiObjectMapBitGET(axisMotorMap, motorIndex)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorIndex);
msgCHECK(mpiMotorValidate(motor));
/* Get the state of the amplifier */
returnValue = mpiMotorAmpEnableGet(motor, &enableState);
msgCHECK(returnValue);
/* If the amplifier is disabled ... */
if (enableState == FALSE) {
/* Get the actual position of the axis */
returnValue = mpiAxisActualPositionGet(axis, &position);
msgCHECK(returnValue);
/* Set the command position equal to the actual position */
returnValue = mpiAxisCommandPositionSet(axis, position);
msgCHECK(returnValue);
/* Get the object map for the filters */
returnValue = mpiMotorFilterMapGet(motor, &motorFilterMap);
msgCHECK(returnValue);
/* For every filter ... */
for (filterIndex = 0;
filterIndex < MPIXmpMAX_Filters;
filterIndex++) {
if (mpiObjectMapBitGET(motorFilterMap, filterIndex)) {
/* Create filter handle */
filter = mpiFilterCreate(control, filterIndex);
msgCHECK(mpiFilterValidate(filter));
/* Reset integrator */
returnValue = mpiFilterIntegratorReset(filter);
msgCHECK(returnValue);
/* Delete filter handle */
returnValue = mpiFilterDelete(filter);
msgCHECK(returnValue);
}
}
/* Enable the amplifier */
returnValue = mpiMotorAmpEnableSet(motor, TRUE);
msgCHECK(returnValue);
}
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
Disable the amplifier for every motor attached to an axis. This is useful
when motor objects haven't been created or when someone is using gantry code.
******************************************************************************/
/* Disable the amplifier for every motor attached to an axis */
void axisAmpDisable(MPIAxis axis)
{
MPIControl control;
MPIMotor motor;
MPIObjectMap map;
long motorNumber;
long returnValue;
/* Get the controller handle */
control = mpiAxisControl(axis);
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
/* For every motor ... */
for (motorNumber = 0; motorNumber < MPIXmpMAX_Motors; motorNumber++) {
if (map & (1<<motorNumber)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorNumber);
msgCHECK(mpiMotorValidate(motor));
/* Disable the amplifier */
returnValue = mpiMotorAmpEnableSet(motor, FALSE);
msgCHECK(returnValue);
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
Enable the amplifier for every motor attached to a motion supervisor. This
is useful when motor objects haven't been created or when someone is using
gantry code. This code also sets the command position equal to the actual
position and resets the integrator before enabling the amplifiers so that
the motors will not "jump."
******************************************************************************/
/* Enable the amplifier for every motor attached to a motion supervisor */
void motionAmpEnable(MPIMotion motion)
{
MPIControl control;
MPIAxis axis;
MPIMotor motor;
MPIFilter filter;
MPIObjectMap map;
MPIObjectMap motionMotorMap;
long motorIndex;
long filterIndex;
long returnValue;
double position;
long enableState;
/* Get the controller handle */
control = mpiMotionControl(motion);
for (axis = mpiMotionAxisFirst(motion);
axis != MPIHandleVOID;
axis = mpiMotionAxisNext(motion, axis)) {
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
/* Add map to motionMotorMap */
motionMotorMap |= map;
}
/* For every motor ... */
for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {
if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorIndex);
msgCHECK(mpiMotorValidate(motor));
/* Get the state of the amplifier */
returnValue = mpiMotorAmpEnableGet(motor, &enableState);
msgCHECK(returnValue);
/* If the amplifier is disabled ... */
if (enableState == FALSE) {
/* For every axis */
for (axis = mpiMotionAxisFirst(motion);
axis != MPIHandleVOID;
axis = mpiMotionAxisNext(motion, axis)) {
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
/* If axis is attached to motor ... */
if (mpiObjectMapBitGET(map, motorIndex)) {
/* Get the actual position of the axis */
returnValue = mpiAxisActualPositionGet(axis, &position);
msgCHECK(returnValue);
/* Set command position equal to actual position */
returnValue = mpiAxisCommandPositionSet(axis, position);
msgCHECK(returnValue);
}
}
/* Get the object map for the filters */
returnValue = mpiMotorFilterMapGet(motor, &map);
msgCHECK(returnValue);
/* For every filter ... */
for (filterIndex = 0;
filterIndex < MPIXmpMAX_Filters;
filterIndex++) {
if (mpiObjectMapBitGET(map, filterIndex)) {
/* Create filter handle */
filter = mpiFilterCreate(control, filterIndex);
msgCHECK(mpiFilterValidate(filter));
/* Reset integrator */
returnValue = mpiFilterIntegratorReset(filter);
msgCHECK(returnValue);
/* Delete filter handle */
returnValue = mpiFilterDelete(filter);
msgCHECK(returnValue);
}
}
/* Enable the amplifier */
returnValue = mpiMotorAmpEnableSet(motor, TRUE);
msgCHECK(returnValue);
}
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
Disable the amplifier for every motor attached to a motion supervisor. This
is useful when motor objects haven't been created or when someone is using
gantry code.
******************************************************************************/
/* Disable the amplifier for every motor attached to a motion supervisor */
void motionAmpDisable(MPIMotion motion)
{
MPIControl control;
MPIAxis axis;
MPIMotor motor;
MPIObjectMap map;
MPIObjectMap motionMotorMap;
long motorIndex;
long returnValue;
/* Get the controller handle */
control = mpiMotionControl(motion);
for (axis = mpiMotionAxisFirst(motion);
axis != MPIHandleVOID;
axis = mpiMotionAxisNext(motion, axis)) {
/* Get the object map for the motors */
returnValue = mpiAxisMotorMapGet(axis, &map);
msgCHECK(returnValue);
/* Add map to motionMotorMap */
motionMotorMap |= map;
}
/* For every motor ... */
for (motorIndex = 0; motorIndex < MPIXmpMAX_Motors; motorIndex++) {
if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {
/* Create motor handle */
motor = mpiMotorCreate(control, motorIndex);
msgCHECK(mpiMotorValidate(motor));
/* Disable the amplifier */
returnValue = mpiMotorAmpEnableSet(motor, FALSE);
msgCHECK(returnValue);
/* Delete motor handle */
returnValue = mpiMotorDelete(motor);
msgCHECK(returnValue);
}
}
}
/*****************************************************************************
Sets controller to Network mode. Server is the name of the computer in
quotes. Use IP or computer name.
******************************************************************************/
void setIp(MPIControlType *controlType,
MPIControlAddress *controlAddress,
char *server)
{
controlAddress->type.client.port = 3300;
controlAddress->type.client.server = server;
*controlType = MPIControlTypeCLIENT;
}
/**********************************************
Parsing for apps that need command line arguments (example)
In this example, you would pass in the default motor number you
want to use. parseCommandLine() would then change the motor number
if the user specified (s)he wanted to use a different motor.
**********************************************/
long parseCommandLine(long *motorNumber,
int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress)
{
long argIndex;
/* Command line arguments and defaults */
Arg argList[] =
{
{ "-motor", ArgTypeLONG, motorNumber, },
{ NULL, ArgTypeINVALID, NULL, }
};
/* 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) {
fprintf(stderr,"usage: %s %s\n"
"\t\t[-motor # (0 .. %d)]\n"
argv[0],
ArgUSAGE,
MPIXmpMAX_Motors);
exit(MPIMessageARG_INVALID);
}
return 0;
}
/*****************************************************************************
Perform basic command line parsing. (-control -server -port -trace)
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) */
basicParsing(argc,
argv,
&controlType,
&controlAddress);
******************************************************************************/
/* Perform basic command line parsing. (-control -server -port -trace) */
void basicParsing(int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress)
{
long argIndex;
/* Parse command line for Control type and address */
argIndex = argControl(argc, argv, controlType, controlAddress);
/* Check for unknown/invalid command line arguments */
if (argIndex < argc) {
fprintf(stderr,"usage: %s %s\n", argv[0], ArgUSAGE);
exit(MPIMessageARG_INVALID);
}
}
/************************************************************
Example of a typical program initialization function:
A bare minimum object creation for programs of the scope of
motion1 or so. Designed to work with programCleanup below.
#define at head of program file:
#define MOTOR_NUMBER (0)
Declare at head of main():
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIMotion motion;
MPIAxis axis;
MPIFilter filter;
MPIMotor motor;
MPISequence sequence;
MPICapture capture;
MPICompare compare;
MPINotify notify;
MPIEventMgr eventMgr;
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) *
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects *
programInit(&control,
controlType,
&controlAddress,
MOTOR_NUMBER,
&motion,
&axis,
&motor);
************************************************************/
long programInit(MPIControl *control,
MPIControlType *controlType,
MPIControlAddress *controlAddress,
long motorNumber,
MPIMotion *motion,
MPIAxis *axis,
MPIMotor *motor)
{
long returnValue;
/* Obtain a Control handle. */
*control =
mpiControlCreate(*controlType,
controlAddress);
msgCHECK(mpiControlValidate(*control));
/* Initialize the controller */
returnValue = mpiControlInit(*control);
if (returnValue != MPIMessageOK) {
fprintf(stderr, "mpiControlInit(0x%x) returns 0x%x: %s\n",
*control,
returnValue,
mpiMessage(returnValue, NULL));
exit(returnValue);
}
/* Create motor object */
*motor =
mpiMotorCreate(*control,
motorNumber);
msgCHECK(mpiMotorValidate(*motor));
/* Create axis object */
*axis =
mpiAxisCreate(*control,
motorNumber);
msgCHECK(mpiAxisValidate(*axis));
/* Create motion object */
*motion =
mpiMotionCreate(*control,
motorNumber,
*axis);
msgCHECK(mpiMotionValidate(*motion));
return returnValue;
}
/*********************************************************
Example of a typical program cleanup function:
A bare minimum object deletion for programs of the scope of
motion1 or so. Designed to work with programInit above.
Call function as:
/* Perform certain cleanup actions and delete MPI objects *
programCleanup(&control,
&motion,
&axis,
&motor);
*********************************************************/
long programCleanup(MPIControl *control,
MPIMotion *motion,
MPIAxis *axis,
MPIMotor *motor)
{
long returnValue;
/* Delete the remaining handles */
returnValue = mpiMotionDelete(*motion);
msgCHECK(returnValue);
returnValue = mpiAxisDelete(*axis);
msgCHECK(returnValue);
returnValue = mpiMotorDelete(*motor);
msgCHECK(returnValue);
returnValue = mpiControlDelete(*control);
msgCHECK(returnValue);
return returnValue;
}
/*****************************************************************************
Create and initialize MPI objects. [One of each object -- Use as a model]
Note: Rename function to programInit(...) and delete what you don't need.
#define at head of program file:
#define MOTION_NUMBER (0)
#define AXIS_NUMBER (0)
#define FILTER_NUMBER (0)
#define MOTOR_NUMBER (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER (0)
#define COMPARE_NUMBER (0)
Declare at head of main():
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIMotion motion;
MPIAxis axis;
MPIFilter filter;
MPIMotor motor;
MPISequence sequence;
MPICapture capture;
MPICompare compare;
MPINotify notify;
MPIEventMgr eventMgr;
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) *
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects *
programInit(&control,
controlType,
&controlAddress,
&motion,
MOTION_NUMBER,
&axis,
AXIS_NUMBER,
&filter,
FILTER_NUMBER,
&motor,
MOTOR_NUMBER,
&recorder,
&sequence,
SEQUENCE_NUMBER,
&capture,
CAPTURE_NUMBER,
&compare,
COMPARE_NUMBER,
&eventMgr,
¬ify,
&service);
******************************************************************************/
/* Create and initialize MPI objects */
void programInitSingle(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long motionNumber,
MPIAxis *axis,
long axisNumber,
MPIFilter *filter,
long filterNumber,
MPIMotor *motor,
long motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long sequenceNumber,
MPICapture *capture,
long captureNumber,
MPICompare *compare,
long compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service)
{
MPIEventMask eventMask;
long returnValue;
/* 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,
axisNumber);
msgCHECK(mpiAxisValidate(*axis));
/* Create motion supervisor object with axis */
*motion =
mpiMotionCreate(*control,
motionNumber,
*axis);
msgCHECK(mpiMotionValidate(*motion));
/* Create filter object */
*filter =
mpiFilterCreate(*control,
filterNumber);
msgCHECK(mpiFilterValidate(*filter));
/* Create motor object */
*motor =
mpiMotorCreate(*control,
motorNumber);
msgCHECK(mpiMotorValidate(*motor));
/* Create recorder object */
*recorder =
mpiRecorderCreate(*control);
msgCHECK(mpiRecorderValidate(*recorder));
/* Create sequencer object */
*sequence =
mpiSequenceCreate(*control,
sequenceNumber,
-1); /* Allocate all remaining sequencer space */
msgCHECK(mpiSequenceValidate(*sequence));
/* Create capture object */
*capture =
mpiCaptureCreate(*control,
captureNumber);
msgCHECK(mpiCaptureValidate(*capture));
/* Create compare object */
*compare =
mpiCompareCreate(*control,
compareNumber);
msgCHECK(mpiCompareValidate(*compare));
/* Create event manager object */
*eventMgr =
mpiEventMgrCreate(*control);
msgCHECK(mpiEventMgrValidate(*eventMgr));
/* Request notification of ALL events from motion */
mpiEventMaskCLEAR(eventMask);
mpiEventMaskALL(eventMask);
mpiEventMaskALL(eventMask);
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Create event notification object for NULL (all objects) */
*notify =
mpiNotifyCreate(eventMask,
NULL);
msgCHECK(mpiNotifyValidate(*notify));
/* Append notify to event manager */
returnValue =
mpiEventMgrNotifyAppend(*eventMgr,
*notify);
msgCHECK(returnValue);
/* Create service thread */
*service =
serviceCreate(*eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
if (*service != NULL) {
msgCHECK(MPIMessageHANDLE_INVALID);
}
}
/*****************************************************************************
Perform certain cleanup actions and delete MPI objects
[One of each object -- Use as a model]
Note: Rename function to programCleanup(...) and delete what you don't need.
Call function as:
/* Perform certain cleanup actions and delete MPI objects *
programCleanup(&control,
&motion,
&axis,
&filter,
&motor,
&recorder,
&sequence,
&capture,
&compare,
&eventMgr,
¬ify,
&service);
******************************************************************************/
/* Perform certain cleanup actions and delete MPI objects */
void programCleanupSingle(MPIControl *control,
MPIMotion *motion,
MPIAxis *axis,
MPIFilter *filter,
MPIMotor *motor,
MPIRecorder *recorder,
MPISequence *sequence,
MPICapture *capture,
MPICompare *compare,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service)
{
long returnValue;
/* Delete service thread */
returnValue =
serviceDelete(*service);
msgCHECK(returnValue);
/* Delete event manager object */
returnValue =
mpiEventMgrDelete(*eventMgr);
msgCHECK(returnValue);
/* Delete event notification object */
returnValue =
mpiNotifyDelete(*notify);
msgCHECK(returnValue);
/* Delete compare object */
returnValue =
mpiCompareDelete(*compare);
msgCHECK(returnValue);
/* Delete capture object */
returnValue =
mpiCaptureDelete(*capture);
msgCHECK(returnValue);
/* Delete sequencer object */
returnValue =
mpiSequenceDelete(*sequence);
msgCHECK(returnValue);
/* Delete recorder object */
returnValue =
mpiRecorderDelete(*recorder);
msgCHECK(returnValue);
/* Delete motor object */
returnValue =
mpiMotorDelete(*motor);
msgCHECK(returnValue);
/* Delete filter object */
returnValue =
mpiFilterDelete(*filter);
msgCHECK(returnValue);
/* Delete motion supervisor object */
returnValue =
mpiMotionDelete(*motion);
msgCHECK(returnValue);
/* Delete axis object */
returnValue =
mpiAxisDelete(*axis);
msgCHECK(returnValue);
/* Delete motion controller object */
returnValue =
mpiControlDelete(*control);
msgCHECK(returnValue);
}
/*****************************************************************************
Create and initialize MPI objects. [Arrays of some objects -- Use as a model]
Note: Rename function to programInit(...) and delete what you don't need.
Declare at head of main():
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIMotion motion[];
MPIAxis axis[];
MPIFilter filter[];
MPIMotor motor[];
MPISequence sequence[];
MPICapture capture[];
MPICompare compare[];
MPINotify notify[];
MPIEventMgr eventMgr;
long numberOfMotions;
long numberOfAxes;
long numberOfFilters;
long numberOfMotors;
long numberOfSequences;
long numberOfCaptures;
long numberOfCompares;
long numberOfNotifys;
long motionNumber[];
long axisNumber[];
long filterNumber[];
long motorNumber[];
long sequenceNumber[];
long captureNumber[];
long compareNumber[];
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) *
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects *
programInit(&control,
controlType,
&controlAddress,
motion,
numberOfMotions,
motionNumber,
axis,
numberOfAxes,
axisNumber,
filter,
numberOfFilters,
filterNumber,
motor,
numberOfMotors,
motorNumber,
&recorder,
sequence,
numberOfSequences,
sequenceNumber,
capture,
numberOfCaptures,
captureNumber,
compare,
numberOfCompares,
compareNumber,
&eventMgr,
notify,
numberOfNotifys,
&service);
******************************************************************************/
/* Create and initialize MPI objects */
void programInitMultiple(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long numberOfMotions,
long *motionNumber,
MPIAxis *axis,
long numberOfAxes,
long *axisNumber,
MPIFilter *filter,
long numberOfFilters,
long *filterNumber,
MPIMotor *motor,
long numberOfMotors,
long *motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
long *sequenceNumber,
MPICapture *capture,
long numberOfCaptures,
long *captureNumber,
MPICompare *compare,
long numberOfCompares,
long *compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service)
{
MPIEventMask eventMask;
long index;
long returnValue;
/* Create motion controller object */
*control =
mpiControlCreate(controlType,
controlAddress);
msgCHECK(mpiControlValidate(*control));
/* Initialize motion controller */
returnValue =
mpiControlInit(*control);
msgCHECK(returnValue);
/* Create axes objects */
for (index = 0; index < numberOfAxes; index++) {
axis[index] =
mpiAxisCreate(*control,
axisNumber[index]);
msgCHECK(mpiAxisValidate(axis[index]));
}
/* Create motion supervisor objects with axis[] */
for (index = 0; index < numberOfMotions; index++) {
motion[index] =
mpiMotionCreate(*control,
motionNumber[index],
axis[index]);
msgCHECK(mpiMotionValidate(motion[index]));
}
/* Create filter objects */
for (index = 0; index < numberOfFilters; index++) {
filter[index] =
mpiFilterCreate(*control,
filterNumber[index]);
msgCHECK(mpiFilterValidate(filter[index]));
}
/* Create motor objects */
for (index = 0; index < numberOfMotors; index++) {
motor[index] =
mpiMotorCreate(*control,
motorNumber[index]);
msgCHECK(mpiMotorValidate(motor[index]));
}
/* Create recorder object */
*recorder =
mpiRecorderCreate(*control);
msgCHECK(mpiRecorderValidate(*recorder));
/* Create sequencer objects */
for (index = 0; index < numberOfSequences; index++) {
sequence[index] =
mpiSequenceCreate(*control,
sequenceNumber[index],
sequencePageSize);
msgCHECK(mpiSequenceValidate(sequence[index]));
}
/* Create capture objects */
for (index = 0; index < numberOfCaptures; index++) {
capture[index] =
mpiCaptureCreate(*control,
captureNumber[index]);
msgCHECK(mpiCaptureValidate(capture[index]));
}
/* Create compare objects */
for (index = 0; index < numberOfCompares; index++) {
compare[index] =
mpiCompareCreate(*control,
compareNumber[index]);
msgCHECK(mpiCompareValidate(compare[index]));
}
/* Create event manager object */
*eventMgr =
mpiEventMgrCreate(*control);
msgCHECK(mpiEventMgrValidate(*eventMgr));
/* Request notification of ALL events from motion */
mpiEventMaskCLEAR(eventMask);
mpiEventMaskALL(eventMask);
mpiEventMaskALL(eventMask);
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Create event notification objects for NULL (all objects) */
for (index = 0; index < numberOfNotifys; index++) {
notify[index] =
mpiNotifyCreate(eventMask,
NULL);
msgCHECK(mpiNotifyValidate(notify[index]));
/* Append notify to event manager */
returnValue =
mpiEventMgrNotifyAppend(*eventMgr,
notify[index]);
msgCHECK(returnValue);
}
/* Create service thread */
*service =
serviceCreate(*eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
if (*service != NULL) {
msgCHECK(MPIMessageHANDLE_INVALID);
}
}
/*****************************************************************************
Perform certain cleanup actions and delete MPI objects
[Arrays of some objects -- Use as a model]
Note: Rename function to programCleanup(...) and delete what you don't need.
Call function as:
/* Perform certain cleanup actions and delete MPI objects *
programCleanup(&control,
motion,
numberOfMotions,
axis,
numberOfAxes,
filter,
numberOfFilters,
motor,
numberOfMotors,
&recorder,
sequence,
numberOfSequences,
capture,
numberOfCaptures,
compare,
numberOfCompares,
&eventMgr,
notify,
numberOfNotifys,
&service);
******************************************************************************/
/* Perform certain cleanup actions and delete MPI objects */
void programCleanupMultiple(MPIControl *control,
MPIMotion *motion,
long numberOfMotions,
MPIAxis *axis,
long numberOfAxes,
MPIFilter *filter,
long numberOfFilters,
MPIMotor *motor,
long numberOfMotors,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
MPICapture *capture,
long numberOfCaptures,
MPICompare *compare,
long numberOfCompares,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service)
{
long index;
long returnValue;
/* Delete service thread */
returnValue =
serviceDelete(*service);
msgCHECK(returnValue);
/* Delete event manager object */
returnValue =
mpiEventMgrDelete(*eventMgr);
msgCHECK(returnValue);
/* Delete event notification objects */
for (index = 0; index < numberOfNotifys; index++) {
returnValue =
mpiNotifyDelete(notify[index]);
msgCHECK(returnValue);
}
/* Delete compare objects */
for (index = 0; index < numberOfCompares; index++) {
returnValue =
mpiCompareDelete(compare[index]);
msgCHECK(returnValue);
}
/* Delete capture objects */
for (index = 0; index < numberOfCaptures; index++) {
returnValue =
mpiCaptureDelete(capture[index]);
msgCHECK(returnValue);
}
/* Delete sequencer objects */
for (index = 0; index < numberOfSequences; index++) {
returnValue =
mpiSequenceDelete(sequence[index]);
msgCHECK(returnValue);
}
/* Delete recorder object */
returnValue =
mpiRecorderDelete(*recorder);
msgCHECK(returnValue);
/* Delete motor objects */
for (index = 0; index < numberOfMotors; index++) {
returnValue =
mpiMotorDelete(motor[index]);
msgCHECK(returnValue);
}
/* Delete filter objects */
for (index = 0; index < numberOfFilters; index++) {
returnValue =
mpiFilterDelete(filter[index]);
msgCHECK(returnValue);
}
/* Delete motion supervisor objects */
for (index = 0; index < numberOfMotions; index++) {
returnValue =
mpiMotionDelete(motion[index]);
msgCHECK(returnValue);
}
/* Delete axes objects */
for (index = 0; index < numberOfAxes; index++) {
returnValue =
mpiAxisDelete(axis[index]);
msgCHECK(returnValue);
}
/* Delete motion controller object */
returnValue =
mpiControlDelete(*control);
msgCHECK(returnValue);
}
/*****************************************************************************
Create and initialize MPI objects, and place MS's axis map on XMP.
Use this function instead of programInitMultiple() if your program
calls some mpiMotion method that times out b/c the axis maps on the XMP
do not match those on the host.
[One of each object -- Use as a model]
Note: Rename function to programInit(...) and delete what you don't need.
#define at head of program file:
#define MOTION_NUMBER (0)
#define AXIS_NUMBER (0)
#define FILTER_NUMBER (0)
#define MOTOR_NUMBER (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER (0)
#define COMPARE_NUMBER (0)
Declare at head of main():
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIMotion motion;
MPIAxis axis;
MPIFilter filter;
MPIMotor motor;
MPISequence sequence;
MPICapture capture;
MPICompare compare;
MPINotify notify;
MPIEventMgr eventMgr;
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) *
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects *
programInit(&control,
controlType,
&controlAddress,
&motion,
MOTION_NUMBER,
&axis,
AXIS_NUMBER,
&filter,
FILTER_NUMBER,
&motor,
MOTOR_NUMBER,
&recorder,
&sequence,
SEQUENCE_NUMBER,
&capture,
CAPTURE_NUMBER,
&compare,
COMPARE_NUMBER,
&eventMgr,
¬ify,
&service);
******************************************************************************/
/* Create and initialize MPI objects */
void programInitSingleWithMapping(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long motionNumber,
MPIAxis *axis,
long axisNumber,
MPIFilter *filter,
long filterNumber,
MPIMotor *motor,
long motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long sequenceNumber,
MPICapture *capture,
long captureNumber,
MPICompare *compare,
long compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
Service *service)
{
MPIEventMask eventMask;
long returnValue;
/* 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,
axisNumber);
msgCHECK(mpiAxisValidate(*axis));
/* Create motion supervisor object with axis */
*motion =
mpiMotionCreate(*control,
motionNumber,
*axis);
msgCHECK(mpiMotionValidate(*motion));
/* Map axis to motion supervisor on XMP */
returnValue =
mpiMotionAction(*motion,
MPIActionMAP);
msgCHECK(returnValue);
/* Create filter object */
*filter =
mpiFilterCreate(*control,
filterNumber);
msgCHECK(mpiFilterValidate(*filter));
/* Create motor object */
*motor =
mpiMotorCreate(*control,
motorNumber);
msgCHECK(mpiMotorValidate(*motor));
/* Create recorder object */
*recorder =
mpiRecorderCreate(*control);
msgCHECK(mpiRecorderValidate(*recorder));
/* Create sequencer object */
*sequence =
mpiSequenceCreate(*control,
sequenceNumber,
-1); /* Allocate all remaining sequencer space */
msgCHECK(mpiSequenceValidate(*sequence));
/* Create capture object */
*capture =
mpiCaptureCreate(*control,
captureNumber);
msgCHECK(mpiCaptureValidate(*capture));
/* Create compare object */
*compare =
mpiCompareCreate(*control,
compareNumber);
msgCHECK(mpiCompareValidate(*compare));
/* Create event manager object */
*eventMgr =
mpiEventMgrCreate(*control);
msgCHECK(mpiEventMgrValidate(*eventMgr));
/* Request notification of ALL events from motion */
mpiEventMaskCLEAR(eventMask);
mpiEventMaskALL(eventMask);
mpiEventMaskALL(eventMask);
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Create event notification object for NULL (all objects) */
*notify =
mpiNotifyCreate(eventMask,
NULL);
msgCHECK(mpiNotifyValidate(*notify));
/* Append notify to event manager */
returnValue =
mpiEventMgrNotifyAppend(*eventMgr,
*notify);
msgCHECK(returnValue);
/* Create service thread */
*service =
serviceCreate(*eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
if (*service != NULL) {
msgCHECK(MPIMessageHANDLE_INVALID);
}
}
/*****************************************************************************
Create and initialize MPI objects, and place MSs' axis maps on XMP.
Use this function instead of programInitMultiple() if your program
calls some mpiMotion method that times out b/c the axis maps on the XMP
do not match those on the host.
[Arrays of some objects -- Use as a model]
Note: Rename function to programInit(...) and delete what you don't need.
Declare at head of main():
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIMotion motion[];
MPIAxis axis[];
MPIFilter filter[];
MPIMotor motor[];
MPISequence sequence[];
MPICapture capture[];
MPICompare compare[];
MPINotify notify[];
MPIEventMgr eventMgr;
long numberOfMotions;
long numberOfAxes;
long numberOfFilters;
long numberOfMotors;
long numberOfSequences;
long numberOfCaptures;
long numberOfCompares;
long numberOfNotifys;
long motionNumber[];
long axisNumber[];
long filterNumber[];
long motorNumber[];
long sequenceNumber[];
long captureNumber[];
long compareNumber[];
Call function as:
/* Perform basic command line parsing. (-control -server -port -trace) *
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects *
programInit(&control,
controlType,
&controlAddress,
motion,
numberOfMotions,
motionNumber,
axis,
numberOfAxes,
axisNumber,
filter,
numberOfFilters,
filterNumber,
motor,
numberOfMotors,
motorNumber,
&recorder,
sequence,
numberOfSequences,
sequenceNumber,
capture,
numberOfCaptures,
captureNumber,
compare,
numberOfCompares,
compareNumber,
&eventMgr,
notify,
numberOfNotifys,
&service);
******************************************************************************/
/* Create and initialize MPI objects */
void programInitMultipleWithMapping(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIMotion *motion,
long numberOfMotions,
long *motionNumber,
MPIAxis *axis,
long numberOfAxes,
long *axisNumber,
MPIFilter *filter,
long numberOfFilters,
long *filterNumber,
MPIMotor *motor,
long numberOfMotors,
long *motorNumber,
MPIRecorder *recorder,
MPISequence *sequence,
long numberOfSequences,
long sequencePageSize,
long *sequenceNumber,
MPICapture *capture,
long numberOfCaptures,
long *captureNumber,
MPICompare *compare,
long numberOfCompares,
long *compareNumber,
MPIEventMgr *eventMgr,
MPINotify *notify,
long numberOfNotifys,
Service *service)
{
MPIEventMask eventMask;
long index;
long returnValue;
/* Create motion controller object */
*control =
mpiControlCreate(controlType,
controlAddress);
msgCHECK(mpiControlValidate(*control));
/* Initialize motion controller */
returnValue =
mpiControlInit(*control);
msgCHECK(returnValue);
/* Create axes objects */
for (index = 0; index < numberOfAxes; index++) {
axis[index] =
mpiAxisCreate(*control,
axisNumber[index]);
msgCHECK(mpiAxisValidate(axis[index]));
}
/* Create motion supervisor objects with axis[] */
for (index = 0; index < numberOfMotions; index++) {
motion[index] =
mpiMotionCreate(*control,
motionNumber[index],
axis[index]);
msgCHECK(mpiMotionValidate(motion[index]));
/* Map axis to motion supervisor on XMP */
returnValue =
mpiMotionAction(motion[index],
MPIActionMAP);
msgCHECK(returnValue);
}
/* Create filter objects */
for (index = 0; index < numberOfFilters; index++) {
filter[index] =
mpiFilterCreate(*control,
filterNumber[index]);
msgCHECK(mpiFilterValidate(filter[index]));
}
/* Create motor objects */
for (index = 0; index < numberOfMotors; index++) {
motor[index] =
mpiMotorCreate(*control,
motorNumber[index]);
msgCHECK(mpiMotorValidate(motor[index]));
}
/* Create recorder object */
*recorder =
mpiRecorderCreate(*control);
msgCHECK(mpiRecorderValidate(*recorder));
/* Create sequencer objects */
for (index = 0; index < numberOfSequences; index++) {
sequence[index] =
mpiSequenceCreate(*control,
sequenceNumber[index],
sequencePageSize);
msgCHECK(mpiSequenceValidate(sequence[index]));
}
/* Create capture objects */
for (index = 0; index < numberOfCaptures; index++) {
capture[index] =
mpiCaptureCreate(*control,
captureNumber[index]);
msgCHECK(mpiCaptureValidate(capture[index]));
}
/* Create compare objects */
for (index = 0; index < numberOfCompares; index++) {
compare[index] =
mpiCompareCreate(*control,
compareNumber[index]);
msgCHECK(mpiCompareValidate(compare[index]));
}
/* Create event manager object */
*eventMgr =
mpiEventMgrCreate(*control);
msgCHECK(mpiEventMgrValidate(*eventMgr));
/* Request notification of ALL events from motion */
mpiEventMaskCLEAR(eventMask);
mpiEventMaskALL(eventMask);
mpiEventMaskALL(eventMask);
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Should call mpiXxxEventNotifySet(...) so that events will be reported */
/* Create event notification objects for NULL (all objects) */
for (index = 0; index < numberOfNotifys; index++) {
notify[index] =
mpiNotifyCreate(eventMask,
NULL);
msgCHECK(mpiNotifyValidate(notify[index]));
/* Append notify to event manager */
returnValue =
mpiEventMgrNotifyAppend(*eventMgr,
notify[index]);
msgCHECK(returnValue);
}
/* Create service thread */
*service =
serviceCreate(*eventMgr,
-1, /* default (max) priority */
-1); /* -1 => enable interrupts */
if (*service != NULL) {
msgCHECK(MPIMessageHANDLE_INVALID);
}
}
/*
Configure Home Limit to be triggered on the Home Input rather than the capture
*/
void homeLimitOnInput(MPIMotor motor,
long activeHigh)
{
MPIMotorConfig motorConfigXmp; /* XMP motor I/O configuration */
MPIXmpMotor *motorXmp; /* XMP motor memory */
long returnValue; /* return value from library */
/* Get pointer to Motor memory */
returnValue =
mpiMotorMemory(motor,
&motorXmp);
/* Get the XMP Motor configuration*/
returnValue =
mpiMotorConfigGet(motor,
NULL,
&motorConfigXmp);
msgCHECK(returnValue);
/* Set the new Home Limit parameters */
motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].SourceAddress =
&motorXmp->IO.DedicatedIN.IO;
motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].Mask =
MPIXmpMotorIOMaskHOME;
/* Set for Active High Home switch */
motorConfigXmp.Limit[MPIXmpLimitHOME].Condition[0].LimitValue.l =
(activeHigh) ? MPIXmpMotorIOMaskHOME : 0;
/* Set the new XMP Motor configuration*/
returnValue =
mpiMotorConfigSet(motor,
NULL,
&motorConfigXmp);
msgCHECK(returnValue);
}
/*
enableUserLimit() configures and enables one user limit.
A user configured motor limit (user limit) normally uses one of the following
limit types:
MPIEventTypeLIMIT_USER0
MPIEventTypeLIMIT_USER1
MPIEventTypeLIMIT_USER2
MPIEventTypeLIMIT_USER3
MPIEventTypeLIMIT_USER4
MPIEventTypeLIMIT_USER5
MPIEventTypeLIMIT_USER6
MPIEventTypeLIMIT_USER7
but can also be one of the following types:
MPIEventTypeAMP_FAULT
MPIEventTypeHOME
MPIEventTypeLIMIT_ERROR
MPIEventTypeLIMIT_HW_NEG
MPIEventTypeLIMIT_HW_POS
MPIEventTypeLIMIT_SW_NEG
MPIEventTypeLIMIT_SW_POS
MPIEventTypeENCODER_FAULT
Please read Application note 215 for a detailed discussion about user limits.
*/
void enableUserLimit(MPIMotor motor,
long enable)
{
/* Configure user limit zero */
MPIEventType limit = MPIEventTypeLIMIT_USER0;
MPIXmpLimitData customLimit;
MPIXmpData *firmware; /* Needed to access general XMP addresses */
MPIXmpMotor *motorXmp; /* Needed to access motor's addresses */
long returnValue;
/* Get the user limit configuration */
returnValue =
mpiMotorEventConfigGet(motor,
limit,
NULL,
&customLimit);
msgCHECK(returnValue);
if (enable) {
/* Get pointer to XMP firmware */
returnValue =
mpiControlMemory(mpiMotorControl(motor),
&(void *)firmware,
NULL);
msgCHECK(returnValue);
/* Get pointer to motor's memory */
returnValue =
mpiMotorMemory(motor, &(void *)motorXmp);
msgCHECK(returnValue);
/* Set up limit condition 0 */
customLimit.Condition[0].Type = MPIXmpLimitTypeGE;
customLimit.Condition[0].SourceAddress= &motorXmp->IO.DedicatedIN.IO;
customLimit.Condition[0].Mask = MPIMotorInputAMP_FAULT;
customLimit.Condition[0].LimitValue.l = MPIMotorInputUSER;
/* Set up limit condition 1 */
customLimit.Condition[1].Type = MPIXmpLimitTypeNE;
customLimit.Condition[1].SourceAddress= &firmware->MS[0].Action;
customLimit.Condition[1].Mask = MPIMotorInputAMP_FAULT;
customLimit.Condition[1].LimitValue.l = MPIMotorInputHOME;
/* Set up limit output */
customLimit.Output.OutputPtr = (void*)&firmware->Axis[0].ActualVelocity;
customLimit.Output.Enabled = TRUE;
customLimit.Output.AndMask = 0;
customLimit.Output.OrMask = 0;
/* Set up limit logic */
customLimit.Logic = MPIXmpLogicAND;
/* Set up the XMP to handle the user limit */
returnValue =
mpiMotorEventConfigSet(motor,
(MPIEventType)limit,
NULL,
&customLimit);
msgCHECK(returnValue);
} else {
/* Set default limit parameters */
customLimit.Condition[0].Type = MPIXmpLimitTypeFALSE;
customLimit.Condition[1].Type = MPIXmpLimitTypeFALSE;
customLimit.Status = MPIXmpStatusLIMIT;
customLimit.Logic = MPIXmpLogicNEVER;
customLimit.Output.AndMask = -1; /* ALL BITS */
customLimit.Output.OrMask = 0;
customLimit.Output.Enabled = FALSE;
/* Reset the user limit on the XMP */
returnValue =
mpiMotorEventConfigSet(motor,
(MPIEventType)limit,
NULL,
&customLimit);
msgCHECK(returnValue);
}
}
/*
disableUserLimit() disables and erases the configuration of one user limit.
*/
void disableUserLimit(MPIMotor motor,
MPIEventType limit)
{
MPIXmpLimitData userLimit;
long returnValue;
/* Get the user limit configuration */
returnValue =
mpiMotorEventConfigGet(motor,
limit,
NULL,
&userLimit);
msgCHECK(returnValue);
/* Set default limit parameters */
userLimit.Condition[0].Type = MPIXmpLimitTypeFALSE;
userLimit.Condition[1].Type = MPIXmpLimitTypeFALSE;
userLimit.Status = MPIXmpStatusLIMIT;
userLimit.Logic = MPIXmpLogicNEVER;
userLimit.Output.AndMask = -1; /* ALL BITS */
userLimit.Output.OrMask = 0;
userLimit.Output.Enabled = FALSE;
/* Reset the user limit on the XMP */
returnValue =
mpiMotorEventConfigSet(motor,
(MPIEventType)limit,
NULL,
&userLimit);
msgCHECK(returnValue);
}
/*
userLimitEnable() enables or disables one user limit.
This function does not change (most of) the configuration of a user limit.
Because the function does change the logic to temporarily disable
a user limit, this function must store the values of the limit's
logic.
*/
void userLimitEnable(MPIMotor motor,
MPIEventType limit,
long enable)
{
static MPIXmpLogic savedLogic[MPIXmpMAX_Motors][MPIEventTypeMOTOR_LAST];
MPIXmpLimitData limitData;
long motorNumber;
long returnValue;
/* Get the motor number */
mpiMotorNumber(motor,
&motorNumber);
/* Get the user limit configuration */
returnValue =
mpiMotorEventConfigGet(motor,
limit,
NULL,
&limitData);
msgCHECK(returnValue);
if (enable) {
/* Restore logic */
limitData.Logic = savedLogic[motorNumber][limit];
}
else {
/* Save logic */
savedLogic[motorNumber][limit] = limitData.Logic;
/* Set logic to MPIXmpLogicNEVER to disable limit */
limitData.Logic = MPIXmpLogicNEVER;
}
/* Set the new configuration */
returnValue =
mpiMotorEventConfigSet(motor,
limit,
NULL,
&limitData);
msgCHECK(returnValue);
}
/*
sequenceCommandAdd() creates a command (MPICommand object) and appends it to
sequence's list of commands. This function does return MPI error codes so
that sequence setup code may be more easily debugged.
Warning: sequenceCommandAdd() does not keep track of created command objects
so it is important that before a sequence object is deleted, that each
command object on sequence's list is itself deleted. Otherwise, there will
be memory leaks. One can use sequenceProgramDelete() to accomplish this.
*/
long sequenceCommandAdd(MPISequence sequence,
MPICommandType commandType,
MPICommandParams *commandParams,
const char *label)
{
MPICommand command;
long returnValue;
command =
mpiCommandCreate(commandType,
commandParams,
label);
returnValue =
mpiCommandValidate(command);
if (returnValue == MPIMessageOK) {
returnValue =
mpiSequenceCommandAppend(sequence,
command);
}
return returnValue;
}
/*
sequenceProgramCreate() is a prototype function showing how one can create a
MPISequence program. This prototype creates a program that simply loops
continually, much like the statement:
while(1) {}
would in C. This function uses sequenceCommandAdd() to add commands to
sequence. One should use sequenceProgramDelete() to delete the sequence
object and the MPICommand objects on sequence's command list. Please refer
to the description of sequenceCommandAdd() for more details.
*/
MPISequence sequenceProgramCreate(MPIControl control)
{
MPISequence sequence;
MPICommandParams commandParams;
long returnValue;
/* Create sequence object */
sequence =
mpiSequenceCreate(control,
-1, /* Use the next available sequence */
1); /* # of commands in sequence */
msgCHECK(mpiSequenceValidate(sequence));
/* Branch to the first command of the sequence */
commandParams.branch.label = "First"; /* First command */
commandParams.branch.expr.oper = MPICommandOperatorALWAYS;
/* Add command to sequence */
returnValue =
sequenceCommandAdd(sequence,
MPICommandTypeBRANCH,
&commandParams,
"First");
msgCHECK(returnValue);
/* Return the new sequence handle */
return sequence;
}
/*
sequenceProgramDelete() removes and deletes all command objects on sequence's
command list and then deletes sequence. This function does return MPI error
codes so that sequence setup code may be more easily debugged.
*/
long sequenceProgramDelete(MPISequence *sequence)
{
MPICommand command;
long returnValue = MPIMessageOK;
/* Remove and delete command objects on sequence list */
while(TRUE) {
command = mpiSequenceCommandLast(*sequence);
if ((returnValue != MPIMessageOK) ||
(command==MPIHandleVOID)) {
break;
}
returnValue =
mpiSequenceCommandRemove(*sequence,
command);
if (returnValue == MPIMessageOK) {
returnValue =
mpiCommandDelete(command);
}
}
/* Delete sequence object */
returnValue =
mpiSequenceDelete(*sequence);
if (returnValue == MPIMessageOK) {
/* Make it obvious that sequence is no longer a valid object */
*sequence = MPIHandleVOID;
}
return returnValue;
}
/*
Starts a sequence, waits for the user to press a key and then
stops the sequence.
*/
void sequenceRun(MPISequence sequence)
{
long returnValue;
/* Start sequence */
returnValue =
mpiSequenceStart(sequence,
MPIHandleVOID);
msgCHECK(returnValue);
fprintf(stderr,"Press any key to stop sequence.\n");
mpiPlatformKey(MPIWaitFOREVER);
fprintf(stderr,"Exiting ...\n");
/* Stop sequence */
returnValue = mpiSequenceStop(sequence);
if ((returnValue != MPIMessageOK) &&
(returnValue != MPISequenceMessageSTOPPED)) {
msgCHECK(returnValue);
}
returnValue = mpiSequenceDelete(sequence);
msgCHECK(returnValue);
}
/*****************************************************************************
Start the XMP's recorder, get data, and stop the recorder
******************************************************************************/
long recordData(MPIRecorder recorder,
long numRecords,
long period,
long eventCount,
MPIRecorderRecord *records)
{
long returnValue;
long recordIndex;
long recordCountRemaining;
long countGet;
/* Start recording the axis */
returnValue =
mpiRecorderStart(recorder,
numRecords,
period, /* period (milliseconds) */
eventCount);
msgCHECK(returnValue);
/* Fill the record buffer */
for (recordIndex = 0, recordCountRemaining = numRecords;
recordCountRemaining > 0; ) {
returnValue =
mpiRecorderRecordGet(recorder,
recordCountRemaining,
&records[recordIndex],
&countGet);
msgCHECK(returnValue);
recordCountRemaining -= countGet;
recordIndex += countGet;
}
/* Stop recording */
returnValue = mpiRecorderStop(recorder);
/* In case the recorder has already stopped */
if (returnValue == MPIRecorderMessageSTOPPED) {
returnValue = MPIMessageOK;
}
msgCHECK(returnValue);
return returnValue;
}
/*****************************************************************************
Example:
Configure recorder object
This example records 3 system data variables:
1) The sample counter -- increments by 1 every servo cycle
2) The background cycle -- increments by 1 after every background cycle
3) The "count delta" -- increments by 1 after every background cycle and
resets to zero after every servo cycle
******************************************************************************/
void configureRecorder(MPIRecorder recorder)
{
MPIControl control = mpiRecorderControl(recorder);
MPIXmpData* firmware;
MPIXmpBufferData* external;
void *point[MPIXmpMaxRecSize];
long pointCount = 0;
long returnValue;
returnValue =
mpiControlMemory(control,
&firmware,
&external);
msgCHECK(returnValue);
point[pointCount++] = &firmware->SystemData.SampleCounter;
point[pointCount++] = &firmware->SystemData.BackgroundCycle;
point[pointCount++] = &firmware->SystemData.CountDelta;
mpiAssert(pointCount <= MPIXmpMaxRecSize);
returnValue =
mpiRecorderRecordConfig(recorder,
MPIRecorderRecordTypePOINT,
pointCount,
point);
msgCHECK(returnValue);
}
/*****************************************************************************
Stops the data recorder ignoring the MPIRecorderMessageSTOPPED message if
the recorder is already stopped.
******************************************************************************/
void stopRecorder(MPIRecorder recorder)
{
long returnValue =
mpiRecorderStop(recorder);
/* In case the recorder has already stopped */
if (returnValue == MPIRecorderMessageSTOPPED) {
returnValue = MPIMessageOK;
}
msgCHECK(returnValue);
}
/*
EventType is MPIEventTypeLIMIT_USERn -- Choose the user limit you want to use.
The axis will abort out after continually exceeding the high or low limit for
duration seconds.
highLimit sets the positive torque limit.
lowLimit sets the negative torque limit.
*/
long SetTorqueLimits(MPIMotor motor,
MPIEventType eventType,
float highLimit,
float lowLimit,
float duration) /* in seconds */
{
MPIControl control;
MPIXmpData *firmware;
MPIMotorLimitConfig motorEventConfig;
MPIPlatform platform;
long returnValue;
long samples;
long ptr;
long motorNum;
/* Determine control handle */
control = mpiMotorControl(motor);
returnValue = mpiControlValidate(control);
if(returnValue == MPIMessageOK)
{
returnValue = mpiControlSecondsToSamples(control,
duration,
&samples);
}
if(returnValue == MPIMessageOK)
{
returnValue = mpiMotorNumber(motor, &motorNum);
}
/* If duration is out of range, make it zero */
if(duration > (MPIXmpLogicDURATION_MASK >> MPIXmpLogicBITS) || duration < 0)
{
samples = 0;
}
/* Get pointer to XMP firmware */
if(returnValue == MPIMessageOK)
{
returnValue =
mpiControlMemory(control,
(void **)&firmware,
NULL);
}
/* The source address requires a host pointer, not a controller pointer */
platform = mpiControlPlatform(control);
msgCHECK(mpiPlatformValidate(platform));
returnValue = mpiPlatformMemoryToHost(platform,
(void**)firmware->Motor[motorNum].Commutation.Input[0].Ptr,
(void**)&ptr);
msgCHECK(returnValue);
if (returnValue == MPIMessageOK)
{
/*
Set up the Condition blocks. They watch for the high and
low command levels
*/
motorEventConfig.Condition[0].Type = MPIXmpLimitTypeFGE;
motorEventConfig.Condition[0].SourceAddress = (void *)ptr;
motorEventConfig.Condition[0].LimitValue.f = highLimit;
motorEventConfig.Condition[1].Type = MPIXmpLimitTypeFLE;
motorEventConfig.Condition[1].SourceAddress = (void *)ptr;
motorEventConfig.Condition[1].LimitValue.f = lowLimit;
/* Abort on this condition */
motorEventConfig.Status = MPIXmpStatusABORT;
/*
Determine logic result from Condition[0] AND Condition[1].
The duration is logically combined with the logic.
*/
motorEventConfig.Logic = MPIXmpLogicOR | (samples << MPIXmpLogicBITS);
/* Disable the output feature */
motorEventConfig.Output.OutputPtr = NULL;
motorEventConfig.Output.AndMask = 0x0;
motorEventConfig.Output.OrMask = 0x0;
motorEventConfig.Output.Enabled = 0;
returnValue =
mpiMotorEventConfigSet(motor,
(MPIEventType)eventType,
NULL,
&motorEventConfig);
}
return returnValue;
}
/* Works like mpiControlMemoryGet, but gets the address of location in the XMP memory space. This is the same number as you see as the address in VM3. */ long controlAddressGet(MPIControl control,
void *dst,
void *src) { MPIPlatform platform; long returnValue;
platform = mpiControlPlatform(control);
returnValue = mpiPlatformValidate(platform);
if(returnValue) return returnValue;
returnValue = mpiPlatformMemoryToFirmware(platform,
(void**)src,
(void**)dst);
return returnValue;
}
/*
Works like mpiControlMemorySet, but writes one firmware address
to another. Host / controller memory spaces can be ignored. Useful
in pointer hocus pocus like can be done in VM3.
Example:
controlAddrToAddr(control,
&firmware->Axis[firstMotor].APos[0].Ptr,
&firmware->Motor[firstMotor].IO.Encoder[0].IO);
*/
long controlAddrToAddr(MPIControl control, void *dst, void *src)
{
long returnValue;
long addr;
returnValue = controlAddressGet(control,
&addr,
src);
if(returnValue)return returnValue;
returnValue = mpiControlMemorySet(control,
(void**)dst,
&addr,
sizeof(dst));
return returnValue;
}
/*
Set outerMotor as the motor with the outer "slow" control loop.
Set innerMotor as the motor with the inner "fast" control loop.
Uses Filter[outerLoop] as the Filter that has the control loop.
This only works with the PIV algorithm.
*/
void SetDualLoop(MPIControl control, int outerMotor, int innerMotor)
{
/* Simple code to increment userbuffer[0] */
MPIXmpData *firmware;
MPIXmpBufferData *buffer;
long returnValue;
/* Get memory pointers */
returnValue =
mpiControlMemory(control,
&firmware,
&buffer);
msgCHECK(returnValue);
returnValue = controlAddrToAddr(control,
&firmware->ControlLaw.Standard.Filter[outerMotor].VelPositionPtr,
&firmware->Motor[innerMotor].IO.Encoder[0].Encoder.IO);
msgCHECK(returnValue);
}
/* Get a default FPGA name, verify FPGA name then download FPGA to the node while printing download status. */ void fpgaDownload(MPISqNode sqNode) { MPISqNodeFileName fileName; MPISqNodeDownloadParams params; long returnValue;
/* Get default FPGA name */
returnValue = mpiSqNodeFpgaDefaultFileName(sqNode, &fileName); msgCHECK(returnValue);
params.filename = fileName.fileName; params.callback = printFpgaDownloadStatus; params.channel = MPISqNodeChannelNODE; printf("%s
", fileName.fileName);
/* Verify FPGA filename if it is the default FPGA for the node */ returnValue = mpiSqNodeFpgaFileNameVerify(sqNode, &fileName.fileName); msgCHECK(returnValue);
printf("Download Fpga begins \n"); returnValue = mpiSqNodeDownload(sqNode, ¶ms); msgCHECK(returnValue); printf("Download finishes \n"); }
/* This is the callback function for fpgaDownload. It prints out the fpgaDownload status */ long printFpgaDownloadStatus(long percentage) { printf("Percentage %ld percent complete\r", percentage); return 0; }
/* motorDemandGet(...) demonstrates how to read the primary and
auxiliary motor demand signals. mpiMotorMemory(...) obtains the
motor control memory pointer. The pointer's address is then
passed into mpiMotorMemoryGet(...) to obtain the demand values.
Note: MPIXmpMotor *memory must be casted as (void *) in
mpiMotorMemory.
*/
long motorDemandGet(MPIMotor motor,
float *primary,
float *aux)
{
MPIXmpMotor *memory;
long returnValue;
/* Get motor control memory pointer */
returnValue =
mpiMotorMemory(motor,
(void *)&memory);
/* Get primary motor demand value */
if(returnValue == MPIMessageOK)
{
returnValue =
mpiMotorMemoryGet(motor,
primary,
&memory->IO.Demand.Channel[0].Level,
sizeof(memory->IO.Demand.Channel[0].Level));
}
/* Get auxiliary motor demand value */
if(returnValue == MPIMessageOK)
{
returnValue =
mpiMotorMemoryGet(motor,
aux,
&memory->IO.Demand.Channel[1].Level,
sizeof(memory->IO.Demand.Channel[1].Level));
}
return returnValue;
}
|