Files
motorBase/motorApp/MotorSrc/drvMotorAsyn.c
T
Torsten Bögershausen 532afdc5a0 Remove all lines with svn keywords
They have no meaning in Git, are not updated and may cause unwanted diffs when
otherwise nothing is changed in a file
2015-11-23 08:23:12 +01:00

1099 lines
39 KiB
C

/*
* drvMotorAsyn.c
*
* Motor record common Asyn driver support layer
*
* Copyright (C) 2005-6 Peter Denison, Diamond Light Source
*
* This software is distributed subject to the EPICS Open Licence, which can
* be found at http://www.aps.anl.gov/epics/licence/open.php
*
* Notwithstanding the above, explicit permission is granted for APS to
* redistribute this software.
*
* Derived from ip330 driver from GSE-CARS which was:
* Original Authors: Jim Kowalkowski, Mark Rivers, Joe Sullivan, and Marty Kraimer
* ********************COPYRIGHT NOTIFICATION******************************
* This software was developed under a United States Government license
* described on the COPYRIGHT_UniversityOfChicago file included as part
* of this distribution.
* ************************************************************************
*
*
* Original Author: Peter Denison
* Current Author: Peter Denison
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef vxWorks
#include <taskLib.h>
#include <intLib.h>
#endif
#include <iocsh.h>
#include <epicsThread.h>
#include <epicsString.h>
#include <epicsTimer.h>
#include <epicsMutex.h>
#include <errlog.h>
#include <epicsMessageQueue.h>
#include <errlog.h>
#include <cantProceed.h> /* !! for callocMustSucceed() */
#include <asynDriver.h>
#include <asynInt32.h>
#include <asynUInt32Digital.h>
#include <asynFloat64.h>
#include <asynFloat64Array.h>
#include <asynGenericPointer.h>
#include <asynDrvUser.h>
#include <drvSup.h>
#include <registryDriverSupport.h>
#include "asynMotorController.h"
#include "motor_interface.h"
#include <limits.h>
#include <epicsExport.h>
/* Message queue size */
#define MAX_MESSAGES 100
#define NMASKBITS (sizeof(int) * CHAR_BIT)
#define BIT_ISSET(bit, n, mask) ( ((bit)/NMASKBITS < (n)) && \
((mask)[(bit)/NMASKBITS] & (1 << ((bit) % NMASKBITS))) )
#define BIT_SET(bit, mask, value) do { \
(mask)[(bit)/NMASKBITS] &= ~(1 << ((bit) % NMASKBITS)); \
if (value) { \
(mask)[(bit)/NMASKBITS] |= (1 << ((bit) % NMASKBITS)); \
} \
} while (0);
/* Note, these values must not be used for pasynUser->reason in device support */
typedef enum {
/* Parameters - these must match the definitions in motor_interface.h */
motorPosition = motorAxisPosition,
motorEncRatio = motorAxisEncoderRatio,
motorResolution = motorAxisResolution,
motorPGain = motorAxisPGain,
motorIGain = motorAxisIGain,
motorDGain = motorAxisDGain,
motorHighLimit = motorAxisHighLimit,
motorLowLimit = motorAxisLowLimit,
motorSetClosedLoop = motorAxisClosedLoop,
motorEncoderPosition = motorAxisEncoderPosn,
motorActualVel = motorAxisActualVel,
motorDeferMoves = motorAxisDeferMoves,
motorMoveToHome = motorAxisMoveToHome,
/* Status bits split out */
motorStatusDirection=motorAxisDirection,
motorStatusDone, motorStatusHighLimit, motorStatusAtHome,
motorStatusSlip, motorStatusPowerOn, motorStatusFollowingError,
motorStatusHome, motorStatusHasEncoder, motorStatusProblem,
motorStatusMoving, motorStatusGainSupport, motorStatusCommsError,
motorStatusLowLimit, motorStatusHomed, motorStatusLast,
/* Not exposed by the driver */
motorVelocity=100, motorVelBase, motorAccel,
/* Commands */
motorMoveRel, motorMoveAbs, motorMoveVel, motorHome, motorStop,
/* Status readback */
motorStatus, motorUpdateStatus
} motorCommand;
typedef struct {
motorCommand command;
char *commandString;
} motorCommandStruct;
static motorCommandStruct motorCommands[] = {
{motorMoveRel, motorMoveRelString},
{motorMoveAbs, motorMoveAbsString},
{motorMoveVel, motorMoveVelString},
{motorHome, motorHomeString},
{motorStop, motorStopString},
{motorVelocity, motorVelocityString},
{motorVelBase, motorVelBaseString},
{motorAccel, motorAccelString},
{motorPosition, motorPositionString},
{motorEncoderPosition, motorEncoderPositionString},
{motorDeferMoves, motorDeferMovesString},
{motorResolution, motorResolutionString},
{motorEncRatio, motorEncoderRatioString},
{motorPGain, motorPGainString},
{motorIGain, motorIGainString},
{motorDGain, motorDGainString},
{motorHighLimit, motorHighLimitString},
{motorLowLimit, motorLowLimitString},
{motorSetClosedLoop, motorClosedLoopString},
{motorDeferMoves, motorDeferMovesString},
{motorMoveToHome, motorMoveToHomeString},
{motorStatus, motorStatusString},
{motorUpdateStatus, motorUpdateStatusString},
{motorStatusDirection, motorStatusDirectionString},
{motorStatusDone, motorStatusDoneString},
{motorStatusHighLimit, motorStatusHighLimitString},
{motorStatusAtHome, motorStatusAtHomeString},
{motorStatusSlip, motorStatusSlipString},
{motorStatusPowerOn, motorStatusPowerOnString},
{motorStatusFollowingError, motorStatusFollowingErrorString},
{motorStatusHome, motorStatusHomeString},
{motorStatusHasEncoder, motorStatusHasEncoderString},
{motorStatusProblem, motorStatusProblemString},
{motorStatusMoving, motorStatusMovingString},
{motorStatusGainSupport, motorStatusGainSupportString},
{motorStatusCommsError, motorStatusCommsErrorString},
{motorStatusLowLimit, motorStatusLowLimitString},
{motorStatusHomed, motorStatusHomedString},
};
typedef enum{typeInt32, typeFloat64, typeFloat64Array} dataType;
struct drvmotorPvt;
typedef struct drvmotorAxisPvt {
AXIS_HDL axis;
int num;
/* Current parameters for move commands */
double max_velocity;
double min_velocity;
double accel;
/* Received status */
MotorStatus status;
struct drvmotorPvt *pPvt;
asynUser *pasynUser;
} drvmotorAxisPvt;
typedef struct drvmotorPvt {
char *portName;
motorAxisDrvSET_t *drvset;
int card;
int numAxes;
drvmotorAxisPvt *axisData;
/* Housekeeping */
epicsMutexId lock;
int rebooting;
epicsMessageQueueId intMsgQId;
int messagesSent;
int messagesFailed;
/* Asyn interfaces */
asynInterface common;
asynInterface int32;
void *int32InterruptPvt;
asynInterface uint32digital;
void *uint32digitalInterruptPvt;
asynInterface float64;
void *float64InterruptPvt;
asynInterface float64Array;
asynInterface genericPointer;
void *genericPointerInterruptPvt;
asynInterface drvUser;
asynUser *pasynUser;
} drvmotorPvt;
/* These functions are used by the interfaces */
static asynStatus readInt32 (void *drvPvt, asynUser *pasynUser,
epicsInt32 *value);
static asynStatus writeInt32 (void *drvPvt, asynUser *pasynUser,
epicsInt32 value);
static asynStatus readUInt32Digital (void *drvPvt, asynUser *pasynUser,
epicsUInt32 *value, epicsUInt32 mask);
static asynStatus writeUInt32Digital (void *drvPvt, asynUser *pasynUser,
epicsUInt32 value, epicsUInt32 mask);
static asynStatus getBounds (void *drvPvt, asynUser *pasynUser,
epicsInt32 *low, epicsInt32 *high);
static asynStatus readFloat64 (void *drvPvt, asynUser *pasynUser,
epicsFloat64 *value);
static asynStatus writeFloat64 (void *drvPvt, asynUser *pasynUser,
epicsFloat64 value);
static asynStatus readGenericPointer (void *drvPvt, asynUser *pasynUser,
void *value);
static asynStatus drvUserCreate (void *drvPvt, asynUser *pasynUser,
const char *drvInfo,
const char **pptypeName, size_t *psize);
static asynStatus drvUserGetType (void *drvPvt, asynUser *pasynUser,
const char **pptypeName, size_t *psize);
static asynStatus drvUserDestroy (void *drvPvt, asynUser *pasynUser);
static void report (void *drvPvt, FILE *fp, int details);
static asynStatus connect (void *drvPvt, asynUser *pasynUser);
static asynStatus disconnect (void *drvPvt, asynUser *pasynUser);
/* These are private functions, not used in any interfaces */
static void intCallback(void *drvPvt, unsigned int num, unsigned int *changed);
static int config (drvmotorPvt *pPvt);
static int logFunc (void *userParam,
const motorAxisLogMask_t logMask,
const char *pFormat, ...);
static asynCommon drvMotorCommon = {
report,
connect,
disconnect
};
static asynInt32 drvMotorInt32 = {
writeInt32,
readInt32,
getBounds
};
static asynUInt32Digital drvMotorUInt32Digital = {
writeUInt32Digital,
readUInt32Digital,
NULL,
NULL,
NULL,
NULL,
NULL
};
static asynFloat64 drvMotorFloat64 = {
writeFloat64,
readFloat64
};
static asynFloat64Array drvMotorFloat64Array = {
NULL,
NULL,
NULL,
NULL
};
static asynGenericPointer drvMotorGenericPointer = {
NULL,
readGenericPointer,
};
static asynDrvUser drvMotorDrvUser = {
drvUserCreate,
drvUserGetType,
drvUserDestroy
};
static asynUser *defaultAsynUser;
int drvAsynMotorConfigure(const char *portName, const char *driverName,
int card, int num_axes)
{
drvmotorPvt *pPvt;
drvmotorAxisPvt *pAxis;
asynStatus status;
int i;
pPvt = callocMustSucceed(1, sizeof(*pPvt), "drvAsynMotorConfigure");
pPvt->portName = epicsStrDup(portName);
pPvt->drvset = (motorAxisDrvSET_t *) registryDriverSupportFind( driverName );
if (pPvt->drvset == NULL) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't find driver: %s\n", driverName);
return -1;
}
/* Link with higher level routines */
pPvt->common.interfaceType = asynCommonType;
pPvt->common.pinterface = (void *)&drvMotorCommon;
pPvt->common.drvPvt = pPvt;
pPvt->int32.interfaceType = asynInt32Type;
pPvt->int32.pinterface = (void *)&drvMotorInt32;
pPvt->int32.drvPvt = pPvt;
pPvt->uint32digital.interfaceType = asynUInt32DigitalType;
pPvt->uint32digital.pinterface = (void *)&drvMotorUInt32Digital;
pPvt->uint32digital.drvPvt = pPvt;
pPvt->float64.interfaceType = asynFloat64Type;
pPvt->float64.pinterface = (void *)&drvMotorFloat64;
pPvt->float64.drvPvt = pPvt;
pPvt->float64Array.interfaceType = asynFloat64ArrayType;
pPvt->float64Array.pinterface = (void *)&drvMotorFloat64Array;
pPvt->float64Array.drvPvt = pPvt;
pPvt->genericPointer.interfaceType = asynGenericPointerType;
pPvt->genericPointer.pinterface = (void *)&drvMotorGenericPointer;
pPvt->genericPointer.drvPvt = pPvt;
pPvt->drvUser.interfaceType = asynDrvUserType;
pPvt->drvUser.pinterface = (void *)&drvMotorDrvUser;
pPvt->drvUser.drvPvt = pPvt;
status = pasynManager->registerPort(portName,
ASYN_MULTIDEVICE | ASYN_CANBLOCK,
1, /* autoconnect */
0, /* medium priority */
0); /* default stack size */
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register port\n");
return -1;
}
status = pasynManager->registerInterface(portName,&pPvt->common);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register common.\n");
return -1;
}
status = pasynInt32Base->initialize(pPvt->portName,&pPvt->int32);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register int32\n");
return -1;
}
pasynManager->registerInterruptSource(portName, &pPvt->int32,
&pPvt->int32InterruptPvt);
status = pasynUInt32DigitalBase->initialize(pPvt->portName,&pPvt->uint32digital);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register uint32digital\n");
return -1;
}
pasynManager->registerInterruptSource(portName, &pPvt->uint32digital,
&pPvt->uint32digitalInterruptPvt);
status = pasynFloat64Base->initialize(pPvt->portName,&pPvt->float64);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register float64\n");
return -1;
}
pasynManager->registerInterruptSource(portName, &pPvt->float64,
&pPvt->float64InterruptPvt);
status = pasynFloat64ArrayBase->initialize(pPvt->portName,&pPvt->float64Array);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register float64Array\n");
return -1;
}
status = pasynGenericPointerBase->initialize(pPvt->portName,&pPvt->genericPointer);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register genericPointer\n");
return -1;
}
pasynManager->registerInterruptSource(portName, &pPvt->genericPointer,
&pPvt->genericPointerInterruptPvt);
status = pasynManager->registerInterface(pPvt->portName,&pPvt->drvUser);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure ERROR: Can't register drvUser\n");
return -1;
}
/* Create asynUser for debugging */
pPvt->pasynUser = pasynManager->createAsynUser(0, 0);
/* Connect to device */
status = pasynManager->connectDevice(pPvt->pasynUser, portName, -1);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure, connectDevice failed\n");
return -1;
}
pPvt->lock = epicsMutexCreate();
pPvt->card = card;
config(pPvt);
pPvt->numAxes = num_axes;
pPvt->axisData = callocMustSucceed(num_axes, sizeof(drvmotorAxisPvt), "drvAsynMotorConfigure");
for ( i = 0; i < num_axes; i++) {
pAxis = &pPvt->axisData[i];
pAxis->axis = (*pPvt->drvset->open)(card, i, "");
if (!pAxis->axis) {
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
"drvAsynMotorConfigure: Failed to open axis %d\n", i);
}
pAxis->num = i;
pAxis->pPvt = pPvt;
/* Create asynUser for debugging */
pAxis->pasynUser = pasynManager->createAsynUser(0, 0);
/* Connect to device */
status = pasynManager->connectDevice(pAxis->pasynUser, portName, i);
if (status != asynSuccess) {
errlogPrintf("drvAsynMotorConfigure, connectDevice failed\n");
return -1;
}
if (pAxis->axis) {
(*pPvt->drvset->setCallback)(pAxis->axis, intCallback, (void *)pAxis);
(*pPvt->drvset->setLog)(pAxis->axis, logFunc, pAxis->pasynUser);
}
/* All other axis parameters are initialised to zero at allocation */
}
/* Create a fallback asynUser for logging, but only the first time */
if (!defaultAsynUser) {
defaultAsynUser = pasynManager->createAsynUser(0,0);
}
(*pPvt->drvset->setLog)(NULL, logFunc, defaultAsynUser );
return 0;
}
static int config(drvmotorPvt *pPvt)
{
/* XXX call the driver config? with pPvt->card */
return(0);
}
static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
epicsInt32 *value)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readInt32 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readInt32 Uninitialised axis %d", pAxis->num);
return(asynError);
}
switch(command) {
case -1: /* This is commands we know about but don't want int32 interface for */
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readInt32 invalid command=%d",
command);
return(asynError);
case motorStatus:
*value = pAxis->status.status;
break;
case motorPosition:
case motorEncoderPosition:
default:
(*pPvt->drvset->getInteger)(pAxis->axis, command, value);
break;
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::readInt32, reason=%d, value=%d\n",
command, *value);
return(asynSuccess);
}
static asynStatus readUInt32Digital(void *drvPvt, asynUser *pasynUser,
epicsUInt32 *value, epicsUInt32 mask)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readInt32 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readInt32 Uninitialised axis %d", pAxis->num);
return(asynError);
}
switch(command) {
case -1: /* This is commands we know about but don't want uint32digital interface for */
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readUInt32Digital invalid command=%d",
command);
return(asynError);
default:
(*pPvt->drvset->getInteger)(pAxis->axis, command, (epicsInt32*)value);
break;
}
*value = *value & mask;
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::readUInt32Digital, reason=%d, value=%d\n",
command, *value);
return(asynSuccess);
}
static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
epicsFloat64 *value)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
asynStatus status = asynSuccess;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readFloat64 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readFloat64 Uninitialised axis %d", pAxis->num);
return(asynError);
}
switch(command) {
case -1:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readFloat64 invalid command=%d",
command);
return(asynError);
case motorVelocity:
*value = pAxis->max_velocity;
break;
case motorVelBase:
*value = pAxis->min_velocity;
break;
case motorAccel:
*value = pAxis->accel;
break;
case motorPosition:
case motorEncoderPosition:
default:
(*pPvt->drvset->getDouble)(pAxis->axis, command, value);
break;
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::readFloat64, reason=%d, value=%f\n",
command, *value);
return(status);
}
static asynStatus getBounds(void *drvPvt, asynUser *pasynUser,
epicsInt32 *low, epicsInt32 *high)
{
*low = 0;
*high = 65535;
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::getBounds,low=%d, high=%d\n", *low, *high);
return(asynSuccess);
}
static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
epicsInt32 value)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
asynStatus status=asynSuccess;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeInt32 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeInt32 Uninitialised axis %d", pAxis->num);
return(asynError);
}
switch(command) {
case -1:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeInt32 invalid command=%d",
command);
return(asynError);
case motorStop:
status = (*pPvt->drvset->stop)(pAxis->axis, pAxis->accel);
break;
case motorHome:
status = (*pPvt->drvset->home)(pAxis->axis, pAxis->min_velocity,
pAxis->max_velocity, pAxis->accel,
(value == 0) ? 0 : 1);
break;
case motorSetClosedLoop:
status = (*pPvt->drvset->setInteger)(pAxis->axis, motorAxisClosedLoop,
value);
break;
case motorUpdateStatus:
if (pPvt->drvset->forceCallback != NULL)
status = (*pPvt->drvset->forceCallback)(pAxis->axis);
break;
default:
status = (*pPvt->drvset->setInteger)(pAxis->axis, command, value);
break;
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::writeInt32, reason=%d, value=%d\n",
command, value);
return(status);
}
static asynStatus writeUInt32Digital(void *drvPvt, asynUser *pasynUser,
epicsUInt32 value, epicsUInt32 mask)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
asynStatus status;
epicsUInt32 temp = 0;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeInt32 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeInt32 Uninitialised axis %d", pAxis->num);
return(asynError);
}
switch(command) {
case -1:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeUInt32Digital invalid command=%d",
command);
return(asynError);
default:
(*pPvt->drvset->getInteger)(pAxis->axis, command, (epicsInt32*)&temp);
temp &= ~mask;
temp |= (value & mask);
status = (*pPvt->drvset->setInteger)(pAxis->axis, command, temp);
break;
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::writeUInt32Digital, reason=%d, value=%d\n",
command, temp);
return(status);
}
static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
epicsFloat64 value)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
motorCommand command = pasynUser->reason;
asynStatus status = asynError;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeFloat64 Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeFloat64 Uninitialised axis %d", pAxis->num);
return(asynError);
}
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::writeFloat64, reason=%d, pasynUser=%p pAxis=%p\n",
command, pasynUser, pAxis);
switch(command) {
case -1:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::writeFloat64 invalid command=%d",
command);
return(asynError);
case motorMoveRel:
status = (*pPvt->drvset->move)(pAxis->axis, value, 1, pAxis->min_velocity,
pAxis->max_velocity, pAxis->accel);
break;
case motorMoveAbs:
status = (*pPvt->drvset->move)(pAxis->axis, value, 0, pAxis->min_velocity,
pAxis->max_velocity, pAxis->accel);
break;
case motorMoveVel:
status = (*pPvt->drvset->velocityMove)(pAxis->axis, pAxis->min_velocity,
value, pAxis->accel);
break;
case motorHome:
status = (*pPvt->drvset->home)(pAxis->axis, pAxis->min_velocity,
pAxis->max_velocity, pAxis->accel,
(value == 0) ? 0 : 1);
break;
case motorVelocity:
pAxis->max_velocity = value;
status = asynSuccess;
break;
case motorVelBase:
pAxis->min_velocity = value;
status = asynSuccess;
break;
case motorAccel:
pAxis->accel = value;
status = asynSuccess;
break;
case motorPosition:
case motorResolution:
case motorEncRatio:
case motorPGain:
case motorIGain:
case motorDGain:
case motorHighLimit:
case motorLowLimit:
default:
status = (*pPvt->drvset->setDouble)(pAxis->axis, command, value);
break;
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::writeFloat64, reason=%d, value=%f\n",
command, value);
return(status);
}
static asynStatus readGenericPointer(void *drvPvt, asynUser *pasynUser,
void *pValue)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
drvmotorAxisPvt *pAxis;
int channel;
MotorStatus *value = (MotorStatus *)pValue;
pasynManager->getAddr(pasynUser, &channel);
if (channel >= pPvt->numAxes) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readGenericPointer Invalid axis %d", channel);
return(asynError);
}
pAxis = &pPvt->axisData[channel];
if (!pAxis->axis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvMotorAsyn::readGenericPointer Uninitialised axis %d", pAxis->num);
return(asynError);
}
if (value) {
value->status = pAxis->status.status;
(*pPvt->drvset->getDouble)(pAxis->axis, motorPosition,
&(value->position));
(*pPvt->drvset->getDouble)(pAxis->axis, motorEncoderPosition,
&(value->encoderPosition));
(*pPvt->drvset->getDouble)(pAxis->axis, motorVelocity,
&(value->velocity));
}
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"drvMotorAsyn::readMotorStatus, [%08x,%f,%f,%f]\n",
value->status, value->position, value->encoderPosition,
value->velocity);
return(asynSuccess);
}
static int logFunc(void *userParam,
const motorAxisLogMask_t logMask,
const char *pFormat, ...)
{
va_list pvar;
asynUser *pasynUser = (asynUser *)userParam;
if (!pasynUser) {
pasynUser = defaultAsynUser;
}
va_start(pvar, pFormat);
switch(logMask) {
case motorAxisTraceError:
pasynTrace->vprint(pasynUser, ASYN_TRACE_ERROR, pFormat, pvar);
break;
case motorAxisTraceIODevice:
pasynTrace->vprint(pasynUser, ASYN_TRACEIO_DEVICE, pFormat, pvar);
break;
case motorAxisTraceIOFilter:
pasynTrace->vprint(pasynUser, ASYN_TRACEIO_FILTER, pFormat, pvar);
break;
case motorAxisTraceIODriver:
pasynTrace->vprint(pasynUser, ASYN_TRACEIO_DRIVER, pFormat, pvar);
break;
case motorAxisTraceFlow:
pasynTrace->vprint(pasynUser, ASYN_TRACE_FLOW, pFormat, pvar);
break;
default:
asynPrint(pasynUser, ASYN_TRACE_ERROR, "drvMotorAsyn:logFunc unknown logMask %d\n", logMask);
}
va_end (pvar);
return(MOTOR_AXIS_OK);
}
static void intCallback(void *axisPvt, unsigned int nChanged,
unsigned int *changed)
{
drvmotorAxisPvt *pAxis = (drvmotorAxisPvt *)axisPvt;
drvmotorPvt *pPvt = pAxis->pPvt;
int addr;
unsigned int reason;
ELLLIST *pclientList;
interruptNode *pnode;
int ivalue;
double dvalue;
unsigned int i, bit_num;
epicsInt32 changedmask = 0;
/* We are called back with an array of things that have changed.
First put these into a single int32 word for passing up to higher layers
Note that for now this relies on the order of the changed flags being
correct */
for (i = 0; i < nChanged; i++) {
if (changed[i] >= motorAxisDirection &&
changed[i] <= motorAxisHomed) {
bit_num = changed[i] - motorAxisDirection;
changedmask |= (1 << bit_num);
(*pPvt->drvset->getInteger)(pAxis->axis, changed[i], &ivalue);
BIT_SET(bit_num, &(pAxis->status.status), ivalue);
}
if (changed[i] == motorPosition) {
(*pPvt->drvset->getDouble)(pAxis->axis, changed[i],
&(pAxis->status.position));
}
if (changed[i] == motorEncoderPosition) {
(*pPvt->drvset->getDouble)(pAxis->axis, changed[i],
&(pAxis->status.encoderPosition));
}
if (changed[i] == motorAxisActualVel) {
(*pPvt->drvset->getDouble)(pAxis->axis, changed[i],
&(pAxis->status.velocity));
}
}
/* Pass float64 interrupts */
pasynManager->interruptStart(pPvt->float64InterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynFloat64Interrupt *pfloat64Interrupt = pnode->drvPvt;
addr = pfloat64Interrupt->addr;
reason = pfloat64Interrupt->pasynUser->reason;
if (addr == pAxis->num) {
for (i = 0; i < nChanged; i++) {
if (changed[i] == reason) {
(*pPvt->drvset->getDouble)(pAxis->axis, changed[i], &dvalue);
pfloat64Interrupt->callback(pfloat64Interrupt->userPvt,
pfloat64Interrupt->pasynUser,
dvalue);
}
}
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
/* Pass motorStatus interrupts */
pasynManager->interruptStart(pPvt->genericPointerInterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynGenericPointerInterrupt *pInterrupt = pnode->drvPvt;
addr = pInterrupt->addr;
reason = pInterrupt->pasynUser->reason;
if (addr == pAxis->num) {
pInterrupt->callback(pInterrupt->userPvt,
pInterrupt->pasynUser,
(void *)&pAxis->status);
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->genericPointerInterruptPvt);
/* Pass int32 interrupts */
pasynManager->interruptStart(pPvt->int32InterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynInt32Interrupt *pint32Interrupt = pnode->drvPvt;
addr = pint32Interrupt->addr;
reason = pint32Interrupt->pasynUser->reason;
if (addr == pAxis->num) {
if ( reason >= motorStatusDirection &&
reason < motorStatusLast ) {
if (BIT_ISSET(reason - motorStatusDirection, 1, &changedmask))
{
(*pPvt->drvset->getInteger)(pAxis->axis, reason, &ivalue);
pint32Interrupt->callback(pint32Interrupt->userPvt,
pint32Interrupt->pasynUser,
ivalue);
}
}
/* If we've subscribed to the aggregate status */
else if (reason == motorStatus) {
pint32Interrupt->callback(pint32Interrupt->userPvt,
pint32Interrupt->pasynUser,
pAxis->status.status);
}
else {
(*pPvt->drvset->getInteger)(pAxis->axis, reason, &ivalue);
pint32Interrupt->callback(pint32Interrupt->userPvt,
pint32Interrupt->pasynUser,
ivalue);
}
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->int32InterruptPvt);
}
/*static void rebootCallback(void *drvPvt)*/
/*{*/
/* drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;*/
/* Anything special we have to do on reboot */
/* pPvt->rebooting = 1;*/
/*}*/
/* asynDrvUser routines */
static asynStatus drvUserCreate(void *drvPvt, asynUser *pasynUser,
const char *drvInfo,
const char **pptypeName, size_t *psize)
{
int i;
char *pstring;
int ncommands = sizeof(motorCommands)/sizeof(motorCommands[0]);
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::drvUserCreate, drvInfo=%s, pptypeName=%p, psize=%p, pasynUser=%p\n", drvInfo, pptypeName, psize, pasynUser);
for (i=0; i < ncommands; i++) {
pstring = motorCommands[i].commandString;
if (epicsStrCaseCmp(drvInfo, pstring) == 0) {
break;
}
}
if (i < ncommands) {
pasynUser->reason = motorCommands[i].command;
if (pptypeName) {
*pptypeName = epicsStrDup(pstring);
}
if (psize) {
*psize = sizeof(motorCommands[i].command);
}
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::drvUserCreate, command=%s\n", pstring);
return(asynSuccess);
} else {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"drvmotorAsyn::drvUserCreate, unknown command=%s", drvInfo);
return(asynError);
}
}
static asynStatus drvUserGetType(void *drvPvt, asynUser *pasynUser,
const char **pptypeName, size_t *psize)
{
motorCommand command = pasynUser->reason;
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::drvUserGetType entered");
*pptypeName = NULL;
*psize = 0;
if (pptypeName)
*pptypeName = epicsStrDup(motorCommands[command].commandString);
if (psize) *psize = sizeof(command);
return(asynSuccess);
}
static asynStatus drvUserDestroy(void *drvPvt, asynUser *pasynUser)
{
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::drvUserDestroy, drvPvt=%p, pasynUser=%p\n",
drvPvt, pasynUser);
return(asynSuccess);
}
/* asynCommon routines */
/* Report parameters */
static void report(void *drvPvt, FILE *fp, int details)
{
drvmotorPvt *pPvt = (drvmotorPvt *)drvPvt;
interruptNode *pnode;
ELLLIST *pclientList;
fprintf(fp, "Port: %s\n", pPvt->portName);
if (details >= 1) {
fprintf(fp, " messages sent OK=%d; send failed (queue full)=%d\n",
pPvt->messagesSent, pPvt->messagesFailed);
/* Report int32 interrupts */
pasynManager->interruptStart(pPvt->int32InterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynInt32Interrupt *pint32Interrupt = pnode->drvPvt;
fprintf(fp, " int32 callback client address=%p, addr=%d, reason=%d\n",
pint32Interrupt->callback, pint32Interrupt->addr,
pint32Interrupt->pasynUser->reason);
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->int32InterruptPvt);
/* Report float64 interrupts */
pasynManager->interruptStart(pPvt->float64InterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynFloat64Interrupt *pfloat64Interrupt = pnode->drvPvt;
fprintf(fp, " float64 callback client address=%p, addr=%d, reason=%d\n",
pfloat64Interrupt->callback, pfloat64Interrupt->addr,
pfloat64Interrupt->pasynUser->reason);
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
/* Report motorStatus interrupts */
pasynManager->interruptStart(pPvt->genericPointerInterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynGenericPointerInterrupt *pInterrupt = pnode->drvPvt;
fprintf(fp, " motorStatus callback client address=%p, reason=%d\n",
pInterrupt->callback,
pInterrupt->pasynUser->reason);
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->genericPointerInterruptPvt);
}
}
/* Connect */
static asynStatus connect(void *drvPvt, asynUser *pasynUser)
{
pasynManager->exceptionConnect(pasynUser);
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"drvMotorAsyn::connect, pasynUser=%p\n", pasynUser);
return(asynSuccess);
}
/* Disconnect */
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser)
{
pasynManager->exceptionDisconnect(pasynUser);
return(asynSuccess);
}
static const iocshArg initArg0 = { "portName",iocshArgString};
static const iocshArg initArg1 = { "driverName",iocshArgString};
static const iocshArg initArg2 = { "cardNum",iocshArgInt};
static const iocshArg initArg3 = { "numAxes",iocshArgInt};
static const iocshArg * const initArgs[4] = {&initArg0,
&initArg1,
&initArg2,
&initArg3};
static const iocshFuncDef initFuncDef = {"drvAsynMotorConfigure",4,initArgs};
static void initCallFunc(const iocshArgBuf *args)
{
drvAsynMotorConfigure(args[0].sval, args[1].sval, args[2].ival,
args[3].ival);
}
void motorRegister(void)
{
iocshRegister(&initFuncDef,initCallFunc);
}
epicsExportRegistrar(motorRegister);