Interface changes:

Removed motorAxisPrimitive, motorAxisSetLogParam
    motorAxisSetLog now takes a logParam parameter
    drvMotorAsynConfigure takes an extra can_block parameter
    Simulator create function only takes int parameters to avoid problems
        passing double parameters from the vxWorks shell on PowerPC arch
Functional changes:
    Order of drvMotorAsyn interrupt callbacks has been changed to pass back
        Float64 interrupts (typically position, etc.) before Int32 interrupts
        (typically status), so that a move reaches its desired position before
        it is signalled as complete. This is not a complete solution.
    More parameter checking, particularly of axis number
This commit is contained in:
Peter Denison
2006-06-06 08:50:14 +00:00
parent fe139f287d
commit ad11d7ec6f
9 changed files with 397 additions and 256 deletions
+81 -55
View File
@@ -1,3 +1,20 @@
/*
FILENAME... drvMotorSim.c
USAGE... Simulated Motor Support.
Version: $Revision: 1.4 $
Modified By: $Author: peterd $
Last Modified: $Date: 2006-06-06 08:50:14 $
*/
/*
*
*
* Modification Log:
* -----------------
* 20060506 npr Added prolog
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -23,15 +40,13 @@
motorAxisDrvSET_t motorSim =
{
20,
14,
motorAxisReport, /**< Standard EPICS driver report function (optional) */
motorAxisInit, /**< Standard EPICS dirver initialisation function (optional) */
motorAxisSetLog, /**< Defines an external logging function (optional) */
motorAxisSetLogParam, /**< Defines an external logging function user parameter (optional) */
motorAxisOpen, /**< Driver open function */
motorAxisClose, /**< Driver close function */
motorAxisSetCallback, /**< Provides a callback function the driver can call when the status updates */
motorAxisPrimitive, /**< Passes a controller dependedent string */
motorAxisSetDouble, /**< Pointer to function to set a double value */
motorAxisSetInteger, /**< Pointer to function to set an integer value */
motorAxisGetDouble, /**< Pointer to function to get a double value */
@@ -64,6 +79,7 @@ typedef struct motorAxisHandle
double enc_offset;
double home;
int homing;
motorAxisLogFunc print;
void * logParam;
epicsTimeStamp tLast;
epicsMutexId axisMutex;
@@ -74,15 +90,15 @@ typedef struct
AXIS_HDL pFirst;
epicsThreadId motorThread;
motorAxisLogFunc print;
void * logParam;
epicsTimeStamp now;
} motorSim_t;
static int motorSimLogMsg( void * param, const motorAxisLogMask_t logMask, const char *pFormat, ...);
#define PRINT (drv.print)
#define FLOW motorAxisTraceFlow
#define ERROR motorAxisTraceError
#define TRACE_FLOW motorAxisTraceFlow
#define TRACE_ERROR motorAxisTraceError
static motorSim_t drv={ NULL, NULL, motorSimLogMsg, { 0, 0 } };
static motorSim_t drv={ NULL, NULL, motorSimLogMsg, NULL, { 0, 0 } };
#define MAX(a,b) ((a)>(b)? (a): (b))
#define MIN(a,b) ((a)<(b)? (a): (b))
@@ -129,22 +145,35 @@ static int motorAxisInit( void )
return MOTOR_AXIS_OK;
}
static int motorAxisSetLog( motorAxisLogFunc logFunc )
static int motorAxisSetLog( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param )
{
if (logFunc == NULL) drv.print=motorSimLogMsg;
else drv.print = logFunc;
return MOTOR_AXIS_OK;
}
static int motorAxisSetLogParam( AXIS_HDL pAxis, void * param )
{
if (pAxis == NULL) return MOTOR_AXIS_ERROR;
else
if (pAxis == NULL)
{
pAxis->logParam = param;
if (logFunc == NULL)
{
drv.print=motorSimLogMsg;
drv.logParam = NULL;
}
else
{
drv.print=logFunc;
drv.logParam = param;
}
}
return MOTOR_AXIS_OK;
else
{
if (logFunc == NULL)
{
pAxis->print=motorSimLogMsg;
pAxis->logParam = NULL;
}
else
{
pAxis->print=logFunc;
pAxis->logParam = param;
}
}
return MOTOR_AXIS_OK;
}
static AXIS_HDL motorAxisOpen( int card, int axis, char * param )
@@ -190,11 +219,6 @@ static int motorAxisSetCallback( AXIS_HDL pAxis, motorAxisCallbackFunc callback,
}
}
static int motorAxisPrimitive( AXIS_HDL pAxis, int length, char * string )
{
return MOTOR_AXIS_OK;
}
static int motorAxisSetDouble( AXIS_HDL pAxis, motorAxisParam_t function, double value )
{
int status = MOTOR_AXIS_OK;
@@ -207,47 +231,47 @@ static int motorAxisSetDouble( AXIS_HDL pAxis, motorAxisParam_t function, double
case motorAxisPosition:
{
pAxis->enc_offset = value - pAxis->nextpoint.axis[0].p;
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d to position %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d to position %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisResolution:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d resolution to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d resolution to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisEncoderRatio:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d to enc. ratio to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d to enc. ratio to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisLowLimit:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d low limit to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d low limit to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisHighLimit:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d high limit to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d high limit to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisPGain:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d pgain to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d pgain to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisIGain:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d igain to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d igain to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisDGain:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d dgain to %f", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d dgain to %f", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisClosedLoop:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d closed loop to %s", pAxis->card, pAxis->axis, (value!=0?"ON":"OFF") );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d closed loop to %s", pAxis->card, pAxis->axis, (value!=0?"ON":"OFF") );
break;
}
default:
@@ -272,22 +296,22 @@ static int motorAxisSetInteger( AXIS_HDL pAxis, motorAxisParam_t function, int v
case motorAxisPosition:
{
pAxis->enc_offset = (double) value - pAxis->nextpoint.axis[0].p;
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d to position %d", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d to position %d", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisLowLimit:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d low limit to %d", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d low limit to %d", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisHighLimit:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d high limit to %d", pAxis->card, pAxis->axis, value );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d high limit to %d", pAxis->card, pAxis->axis, value );
break;
}
case motorAxisClosedLoop:
{
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d closed loop to %s", pAxis->card, pAxis->axis, (value?"ON":"OFF") );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d closed loop to %s", pAxis->card, pAxis->axis, (value?"ON":"OFF") );
break;
}
default:
@@ -325,8 +349,8 @@ static int motorAxisMove( AXIS_HDL pAxis, double position, int relative, double
motorParam->setInteger( pAxis->params, motorAxisMoving, 1 );
epicsMutexUnlock( pAxis->axisMutex );
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d move to %f, min vel=%f, max_vel=%f, accel=%f",
pAxis->card, pAxis->axis, position, min_velocity, max_velocity, acceleration );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d move to %f, min vel=%f, max_vel=%f, accel=%f",
pAxis->card, pAxis->axis, position, min_velocity, max_velocity, acceleration );
}
}
return MOTOR_AXIS_OK;
@@ -370,8 +394,8 @@ static int motorAxisHome( AXIS_HDL pAxis, double min_velocity, double max_veloci
status = motorAxisVelocity( pAxis, (forwards? max_velocity: -max_velocity), acceleration );
pAxis->homing = 1;
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d to home %s, min vel=%f, max_vel=%f, accel=%f",
pAxis->card, pAxis->axis, (forwards?"FORWARDS":"REVERSE"), min_velocity, max_velocity, acceleration );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d to home %s, min vel=%f, max_vel=%f, accel=%f",
pAxis->card, pAxis->axis, (forwards?"FORWARDS":"REVERSE"), min_velocity, max_velocity, acceleration );
}
return status;
}
@@ -388,8 +412,8 @@ static int motorAxisVelocityMove( AXIS_HDL pAxis, double min_velocity, double v
{
status = motorAxisVelocity( pAxis, velocity, acceleration );
epicsMutexUnlock( pAxis->axisMutex );
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d move with velocity of %f, accel=%f",
pAxis->card, pAxis->axis, velocity, acceleration );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d move with velocity of %f, accel=%f",
pAxis->card, pAxis->axis, velocity, acceleration );
}
}
return status;
@@ -412,8 +436,8 @@ static int motorAxisStop( AXIS_HDL pAxis, double acceleration )
{
motorAxisVelocity( pAxis, 0.0, acceleration );
PRINT( pAxis->logParam, FLOW, "Set card %d, axis %d to stop with accel=%f",
pAxis->card, pAxis->axis, acceleration );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Set card %d, axis %d to stop with accel=%f",
pAxis->card, pAxis->axis, acceleration );
}
return MOTOR_AXIS_OK;
}
@@ -555,8 +579,10 @@ static int motorSimCreateAxis( motorSim_t * pDrv, int card, int axis, double low
pAxis->hiHardLimit = hiLimit;
pAxis->lowHardLimit = lowLimit;
pAxis->home = home;
pAxis->print = motorSimLogMsg;
pAxis->logParam = NULL;
*ppLast = pAxis;
PRINT( pAxis->logParam, FLOW, "Created motor for card %d, signal %d OK", card, axis );
pAxis->print( pAxis->logParam, TRACE_FLOW, "Created motor for card %d, signal %d OK", card, axis );
}
else
{
@@ -575,13 +601,13 @@ static int motorSimCreateAxis( motorSim_t * pDrv, int card, int axis, double low
}
else
{
PRINT( pAxis->logParam, ERROR, "Motor for card %d, signal %d already exists", card, axis );
pAxis->print( pAxis->logParam, TRACE_ERROR, "Motor for card %d, signal %d already exists", card, axis );
return MOTOR_AXIS_ERROR;
}
if (pAxis == NULL)
{
PRINT( pAxis->logParam, ERROR, "Cannot create motor for card %d, signal %d", card, axis );
pAxis->print( pAxis->logParam, TRACE_ERROR, "Cannot create motor for card %d, signal %d", card, axis );
return MOTOR_AXIS_ERROR;
}
@@ -589,7 +615,7 @@ static int motorSimCreateAxis( motorSim_t * pDrv, int card, int axis, double low
}
void motorSimCreate( int card, int axis, double lowLimit, double hiLimit, double home, int nCards, int nAxes )
void motorSimCreate( int card, int axis, int lowLimit, int hiLimit, int home, int nCards, int nAxes )
{
int i;
int j;
@@ -597,8 +623,8 @@ void motorSimCreate( int card, int axis, double lowLimit, double hiLimit, double
if (nCards < 1) nCards = 1;
if (nAxes < 1 ) nAxes = 1;
PRINT( NULL, FLOW,
"Creating motor simulator: card: %d, axis: %d, hi: %f, low %f, home: %f, ncards: %d, naxis: %d",
drv.print( drv.logParam, TRACE_FLOW,
"Creating motor simulator: card: %d, axis: %d, hi: %d, low %d, home: %d, ncards: %d, naxis: %d",
card, axis, hiLimit, lowLimit, home, nCards, nAxes );
if (drv.motorThread==NULL)
@@ -610,7 +636,7 @@ void motorSimCreate( int card, int axis, double lowLimit, double hiLimit, double
if (drv.motorThread == NULL)
{
PRINT( NULL, ERROR, "Cannot start motor simulation thread" );
drv.print( drv.logParam, TRACE_ERROR, "Cannot start motor simulation thread" );
return;
}
}
@@ -619,7 +645,7 @@ void motorSimCreate( int card, int axis, double lowLimit, double hiLimit, double
{
for (j = axis; j < axis+nAxes; j++ )
{
motorSimCreateAxis( &drv, i, j, lowLimit, hiLimit, home );
motorSimCreateAxis( &drv, i, j, (double) lowLimit, (double) hiLimit, (double) home );
}
}
}
@@ -633,6 +659,6 @@ static int motorSimLogMsg( void * param, const motorAxisLogMask_t mask, const ch
va_start(pvar, pFormat);
nchar = vfprintf(stdout,pFormat,pvar);
va_end (pvar);
printf("\n");
fprintf(stdout,"\n");
return(nchar);
}
+1 -1
View File
@@ -5,7 +5,7 @@
extern "C" {
#endif
void motorSimCreate( int card, int axis, double hiLimit, double lowLimit, double home, int nCards, int nAxes );
void motorSimCreate( int card, int axis, int hiLimit, int lowLimit, int home, int nCards, int nAxes );
#ifdef __cplusplus
}
+4 -4
View File
@@ -6,9 +6,9 @@ extern "C" {
static const iocshArg motorSimCreateArg0 = { "Card", iocshArgInt};
static const iocshArg motorSimCreateArg1 = { "Signal", iocshArgInt};
static const iocshArg motorSimCreateArg2 = { "High limit", iocshArgDouble};
static const iocshArg motorSimCreateArg3 = { "Low limit", iocshArgDouble};
static const iocshArg motorSimCreateArg4 = { "Home position", iocshArgDouble};
static const iocshArg motorSimCreateArg2 = { "High limit", iocshArgInt};
static const iocshArg motorSimCreateArg3 = { "Low limit", iocshArgInt};
static const iocshArg motorSimCreateArg4 = { "Home position", iocshArgInt};
static const iocshArg motorSimCreateArg5 = { "Num cards", iocshArgInt};
static const iocshArg motorSimCreateArg6 = { "Num signals", iocshArgInt};
@@ -25,7 +25,7 @@ static const iocshFuncDef motorSimCreateDef ={"motorSimCreate",7,motorSimCreateA
static void motorSimCreateCallFunc(const iocshArgBuf *args)
{
motorSimCreate(args[0].ival, args[1].ival, args[2].dval, args[3].dval, args[4].dval, args[5].ival, args[6].ival);
motorSimCreate(args[0].ival, args[1].ival, args[2].ival, args[3].ival, args[4].ival, args[5].ival, args[6].ival);
}
void motorSimRegister(void)
+38 -38
View File
@@ -1,38 +1,38 @@
#!$(INSTALL)/bin/$(ARCH)/motorSim
## You may have to change test to something else
## everywhere it appears in this file
cd "$(INSTALL)"
# Load binaries on architectures that need to do so.
# VXWORKS_ONLY, LINUX_ONLY and RTEMS_ONLY are macros that resolve
# to a comment symbol on architectures that are not the current
# build architecture, so they can be used liberally to do architecture
# specific things. Alternatively, you can include an architecture
# specific file.
$(VXWORKS_ONLY)ld < bin/$(ARCH)/test.munch
## This drvTS initializer is needed if the IOC has a hardware event system
#TSinit
## Register all support components
dbLoadDatabase("dbd/motorSim.dbd")
motorSim_registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadRecords("db/motorSimTest.db","DEVICE=npr78")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=1,scan=1 second")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=2,scan=2 second")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=3,scan=5 second")
#dbLoadRecords("db/dbSubExample.db","user=npr78")
## Set this to see messages from mySub
#mySubDebug 1
motorSimCreate( 0, 0, -32000, 32000, 0, 1, 1 )
iocInit()
## Start any sequence programs
#seq sncExample,"user=npr78Host"
#!$(INSTALL)/bin/$(ARCH)/motorSim
## You may have to change test to something else
## everywhere it appears in this file
cd "$(INSTALL)"
# Load binaries on architectures that need to do so.
# VXWORKS_ONLY, LINUX_ONLY and RTEMS_ONLY are macros that resolve
# to a comment symbol on architectures that are not the current
# build architecture, so they can be used liberally to do architecture
# specific things. Alternatively, you can include an architecture
# specific file.
$(VXWORKS_ONLY)ld < bin/$(ARCH)/motorSim.munch
## This drvTS initializer is needed if the IOC has a hardware event system
#TSinit
## Register all support components
dbLoadDatabase("dbd/motorSim.dbd")
motorSim_registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadRecords("db/motorSimTest.db","DEVICE=motorSim")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=1,scan=1 second")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=2,scan=2 second")
#dbLoadRecords("db/dbExample2.db","user=npr78,no=3,scan=5 second")
#dbLoadRecords("db/dbSubExample.db","user=npr78")
## Set this to see messages from mySub
#mySubDebug 1
motorSimCreate( 0, 0, -32000, 32000, 0, 1, 1 )
iocInit()
## Start any sequence programs
#seq sncExample,"user=npr78Host"
+45 -4
View File
@@ -1,5 +1,23 @@
/* devMotorAsyn.c */
/* Example device support module */
/*
* devMotorAsyn.c
*
* Motor record common Asyn device 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.
*
* Version: $Revision: 1.10 $
* Modified by: $Author: peterd $
* Last Modified: $Date: 2006-06-06 08:50:14 $
*
* Original Author: Peter Denison
* Current Author: Peter Denison
*/
#include <stddef.h>
#include <stdlib.h>
@@ -116,7 +134,7 @@ static long init_record(struct motorRecord * pmr )
status = pasynManager->connectDevice(pasynUser, port, signal);
if (status != asynSuccess) {
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMcaAsyn::init_record, %s connectDevice failed to %s\n",
"devMotorAsyn::init_record, %s connectDevice failed to %s\n",
pmr->name, port);
goto bad;
}
@@ -358,6 +376,12 @@ static RTN_STATUS build_trans( motor_cmnd command,
pmsg->ivalue = 0;
pmsg->interface = int32Type;
break;
case PRIMITIVE:
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMotorAsyn::send_msg: %s: PRIMITIVE no longer supported\n",
pmr->name);
return(ERROR);
break;
case SET_HIGH_LIMIT:
pmsg->command = motorHighLim;
pmsg->dvalue = *param;
@@ -378,7 +402,10 @@ static RTN_STATUS build_trans( motor_cmnd command,
pmsg->dvalue = *param;
break;
default:
status = ERROR;
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"devMotorAsyn::send_msg: %s: motor command %d not recognised\n",
pmr->name, command);
return(ERROR);
}
/* Queue asyn request, so we get a callback when driver is ready */
@@ -398,6 +425,11 @@ static RTN_STATUS end_trans(struct motorRecord * pmr )
return(OK);
}
/**
* Called once the request comes off the Asyn internal queue.
*
* The request is still "on its way down" at this point
*/
static void asynCallback(asynUser *pasynUser)
{
motorAsynPvt *pPvt = (motorAsynPvt *)pasynUser->userPvt;
@@ -443,6 +475,9 @@ static void asynCallback(asynUser *pasynUser)
}
}
/**
* True callback to notify that controller status has changed.
*/
static void statusCallback(void *drvPvt, asynUser *pasynUser,
epicsInt32 value)
{
@@ -467,6 +502,9 @@ static void statusCallback(void *drvPvt, asynUser *pasynUser,
}
}
/**
* True callback to notify that controller position has changed.
*/
static void positionCallback(void *drvPvt, asynUser *pasynUser,
epicsFloat64 value)
{
@@ -491,6 +529,9 @@ static void positionCallback(void *drvPvt, asynUser *pasynUser,
}
}
/**
* True callback to notify that controller encoder position has changed.
*/
static void encoderCallback(void *drvPvt, asynUser *pasynUser,
epicsFloat64 value)
{
+155 -66
View File
@@ -1,15 +1,31 @@
/* drvMotorAsyn.c
Derived from ip330 driver from GSE-CARS
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.
****************************************************************************
22-Sep-2005 Peter Denison
*/
/*
* 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.
* ************************************************************************
*
* Version: $Revision: 1.8 $
* Modified by: $Author: peterd $
* Last Modified: $Date: 2006-06-06 08:50:14 $
*
* Original Author: Peter Denison
* Current Author: Peter Denison
*/
#include <stdlib.h>
#include <string.h>
@@ -92,6 +108,7 @@ typedef struct drvmotorPvt {
char *portName;
motorAxisDrvSET_t *drvset;
int card;
int numAxes;
drvmotorAxisPvt *axisData;
/* Housekeeping */
epicsMutexId lock;
@@ -171,13 +188,17 @@ static asynDrvUser drvMotorDrvUser = {
drvUserDestroy
};
static asynUser *defaultAsynUser;
int drvAsynMotorConfigure(const char *portName, const char *driverName, int card, int num_axes)
int drvAsynMotorConfigure(const char *portName, const char *driverName,
int card, int num_axes, int can_block)
{
drvmotorPvt *pPvt;
drvmotorAxisPvt *pAxis;
asynStatus status;
int i;
int attributes;
pPvt = callocMustSucceed(1, sizeof(*pPvt), "drvAsynMotorConfigure");
pPvt->portName = epicsStrDup(portName);
@@ -203,8 +224,13 @@ int drvAsynMotorConfigure(const char *portName, const char *driverName, int card
pPvt->drvUser.interfaceType = asynDrvUserType;
pPvt->drvUser.pinterface = (void *)&drvMotorDrvUser;
pPvt->drvUser.drvPvt = pPvt;
attributes = ASYN_MULTIDEVICE;
if (can_block) {
attributes |= ASYN_CANBLOCK;
}
status = pasynManager->registerPort(portName,
ASYN_MULTIDEVICE, /*is multiDevice*/
attributes,
1, /* autoconnect */
0, /* medium priority */
0); /* default stack size */
@@ -257,10 +283,16 @@ int drvAsynMotorConfigure(const char *portName, const char *driverName, int card
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 */
@@ -271,11 +303,17 @@ int drvAsynMotorConfigure(const char *portName, const char *driverName, int card
errlogPrintf("drvAsynMotorConfigure, connectDevice failed\n");
return -1;
}
(*pPvt->drvset->setCallback)(pAxis->axis, intCallback, (void *)pAxis);
(*pPvt->drvset->setLogParam)(pAxis->axis, pAxis->pasynUser);
(*pPvt->drvset->setLog)(logFunc);
if (pAxis->axis) {
(*pPvt->drvset->setCallback)(pAxis->axis, intCallback, (void *)pAxis);
(*pPvt->drvset->setLog)(pAxis->axis, logFunc, pAxis->pasynUser);
}
setDefaults(pAxis);
}
/* 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;
}
@@ -296,9 +334,23 @@ static asynStatus readInt32(void *drvPvt, asynUser *pasynUser,
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 motorStatus:
*value = pAxis->status;
break;
case motorPosition:
case motorEncoderPosition:
(*pPvt->drvset->getInteger)(pAxis->axis, command, value);
@@ -325,7 +377,18 @@ static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
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 motorVelocity:
@@ -372,7 +435,18 @@ static asynStatus writeInt32(void *drvPvt, asynUser *pasynUser,
asynStatus status;
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 motorStop:
@@ -409,7 +483,18 @@ static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
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",
@@ -478,6 +563,10 @@ static int logFunc(void *userParam,
va_list pvar;
asynUser *pasynUser = (asynUser *)userParam;
if (!pasynUser) {
pasynUser = defaultAsynUser;
}
va_start(pvar, pFormat);
switch(logMask) {
case motorAxisTraceError:
@@ -530,6 +619,48 @@ static void intCallback(void *axisPvt, unsigned int nChanged,
}
}
/* Pass float64 interrupts - these should be dealt with first, so that
* the position etc. are notified before the status, which is an int32.
* This is not a very robust way of dealing with the problem, but may work
* for now.*/
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 float64Array interrupts */
pasynManager->interruptStart(pPvt->float64ArrayInterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynFloat64ArrayInterrupt *pfloat64ArrayInterrupt = pnode->drvPvt;
reason = pfloat64ArrayInterrupt->pasynUser->reason;
switch(reason) {
case motorPosition:
/* pfloat64ArrayInterrupt->callback(pfloat64ArrayInterrupt->userPvt,
pfloat64ArrayInterrupt->pasynUser,
pPvt->position,
MAX_AXES);*/
break;
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->float64ArrayInterruptPvt);
/* Pass int32 interrupts */
pasynManager->interruptStart(pPvt->int32InterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
@@ -558,50 +689,6 @@ static void intCallback(void *axisPvt, unsigned int nChanged,
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->int32InterruptPvt);
/* 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) {
switch(reason) {
case motorPosition:
case motorEncoderPosition:
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);
}
}
break;
}
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
/* Pass float64Array interrupts */
pasynManager->interruptStart(pPvt->float64ArrayInterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
asynFloat64ArrayInterrupt *pfloat64ArrayInterrupt = pnode->drvPvt;
reason = pfloat64ArrayInterrupt->pasynUser->reason;
switch(reason) {
case motorPosition:
/* pfloat64ArrayInterrupt->callback(pfloat64ArrayInterrupt->userPvt,
pfloat64ArrayInterrupt->pasynUser,
pPvt->position,
MAX_AXES);*/
break;
}
pnode = (interruptNode *)ellNext(&pnode->node);
}
pasynManager->interruptEnd(pPvt->float64ArrayInterruptPvt);
}
@@ -710,7 +797,7 @@ static void report(void *drvPvt, FILE *fp, int details)
}
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
/* Report int32Array interrupts */
/* Report float64Array interrupts */
pasynManager->interruptStart(pPvt->float64ArrayInterruptPvt, &pclientList);
pnode = (interruptNode *)ellFirst(pclientList);
while (pnode) {
@@ -745,15 +832,17 @@ 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,
static const iocshArg initArg4 = { "canBlock",iocshArgInt};
static const iocshArg * const initArgs[5] = {&initArg0,
&initArg1,
&initArg2,
&initArg3};
static const iocshFuncDef initFuncDef = {"drvAsynMotorConfigure",4,initArgs};
&initArg3,
&initArg4};
static const iocshFuncDef initFuncDef = {"drvAsynMotorConfigure",5,initArgs};
static void initCallFunc(const iocshArgBuf *args)
{
drvAsynMotorConfigure(args[0].sval, args[1].sval, args[2].ival,
args[3].ival);
args[3].ival, args[4].ival);
}
void motorRegister(void)
+12 -43
View File
@@ -165,8 +165,9 @@ The latter could be used for the primitive record approach, and the
former for the motor record.
Finally, in the PREM and the POST fields aren't seen in this
implementation - I assume they are handled via device support calling
motorAxisPrimitive.
implementation - This functionality is no longer supported through the
motor record and should be done by linking to controller specific
device support.
\section Status Analysis of commands that provide status information
@@ -301,8 +302,8 @@ typedef enum
typedef int (*motorAxisLogFunc)( void * userParam,
const motorAxisLogMask_t logMask,
const char *pFormat, ...);
typedef int (*motorAxisSetLogFunc)( motorAxisLogFunc logFunc );
typedef int (*motorAxisSetLogParamFunc)( AXIS_HDL pAxis, void * param );
typedef int (*motorAxisSetLogFunc)( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param );
/** Provide an external logging routine.
@@ -315,30 +316,19 @@ typedef int (*motorAxisSetLogParamFunc)( AXIS_HDL pAxis, void * param );
- enabling tracing of errors, flow, and device filter and driver layers.
infomational, minor, major or fatal.
If pAxis is NULL, then this logging function and parameter should be used as
a default - i.e. when logging is not taking place in the context of a single
axis (a background polling task, for example).
\param pAxis [in] Pointer to axis handle returned by motorAxisOpen.
\param logFunc [in] Pointer to function of motorAxisLogFunc type.
\param param [in] Pointer to the user parameter to be used for logging on this axis
\return Integer indicating 0 (MOTOR_AXIS_OK) for success or non-zero for failure.
*/
#ifdef DEFINE_MOTOR_PROTOTYPES
static int motorAxisSetLog( motorAxisLogFunc logFunc );
#endif
/** Provide an external logging routine axis specific user parameter.
This is an optional function which allows external software to provide
axis specific data to the logging function to be used when logging
information about this axis. If the logging information is not axis
specific a NULL pointer should be supplied to the logging routine.
\param param [in] Pointer to a user parameter to be used for logging on this axis
\return Integer indicating 0 (MOTOR_AXIS_OK) for success or non-zero for failure.
*/
#ifdef DEFINE_MOTOR_PROTOTYPES
static int motorAxisSetLogParam( AXIS_HDL pAxis, void * param );
static int motorAxisSetLog( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param );
#endif
/**@}*/
@@ -424,25 +414,6 @@ static int motorAxisSetCallback( AXIS_HDL pAxis, motorAxisCallbackFunc callback,
@{
*/
typedef int (*motorAxisStringFunc)( AXIS_HDL pAxis, int, char * );
/** Pass a controller specific string to the controller
This optional routine passes a controller specific string down to the controller.
The exact string format depends on the controller. The length parameter allows
the string to contain embedded nulls.
\param pAxis [in] Pointer to axis handle returned by motorAxisOpen.
\param length [in] Length of the string to be passed to the controller.
\param string [in] Character string to be passed to the controller.
\return Integer indicating 0 (MOTOR_AXIS_OK) for success or non-zero for failure.
*/
#ifdef DEFINE_MOTOR_PROTOTYPES
static int motorAxisPrimitive( AXIS_HDL pAxis, int length, char * string );
#endif
typedef int (*motorAxisSetDoubleFunc)( AXIS_HDL pAxis, motorAxisParam_t, double );
/** Sets a double parameter in the controller.
@@ -690,11 +661,9 @@ typedef struct
motorAxisReportFunc report; /**< Standard EPICS driver report function (optional) */
motorAxisInitFunc init; /**< Standard EPICS dirver initialisation function (optional) */
motorAxisSetLogFunc setLog; /**< Defines an external logging function (optional) */
motorAxisSetLogParamFunc setLogParam; /**< Defines a parameter to be used when calling the logging function for an axis */
motorAxisOpenFunc open; /**< Driver open function */
motorAxisCloseFunc close; /**< Driver close function */
motorAxisSetCallbackFunc setCallback; /**< Provides a callback function the driver can call when the status updates */
motorAxisStringFunc primitive; /**< Passes a controller dependedent string */
motorAxisSetDoubleFunc setDouble; /**< Pointer to function to set a double value */
motorAxisSetIntegerFunc setInteger; /**< Pointer to function to set an integer value */
motorAxisGetDoubleFunc getDouble; /**< Pointer to function to get a double value */
+30 -22
View File
@@ -26,15 +26,13 @@
motorAxisDrvSET_t motorMM4000 =
{
20,
14,
motorAxisReport, /**< Standard EPICS driver report function (optional) */
motorAxisInit, /**< Standard EPICS dirver initialisation function (optional) */
motorAxisSetLog, /**< Defines an external logging function (optional) */
motorAxisSetLogParam, /**< Defines an external logging function user parameter (optional) */
motorAxisOpen, /**< Driver open function */
motorAxisClose, /**< Driver close function */
motorAxisSetCallback, /**< Provides a callback function the driver can call when the status updates */
motorAxisPrimitive, /**< Passes a controller dependedent string */
motorAxisSetDouble, /**< Pointer to function to set a double value */
motorAxisSetInteger, /**< Pointer to function to set an integer value */
motorAxisGetDouble, /**< Pointer to function to get a double value */
@@ -78,6 +76,7 @@ typedef struct motorAxisHandle
int card;
int axis;
int maxDigits;
motorAxisLogFunc print;
void *logParam;
epicsMutexId mutexId;
} motorAxis;
@@ -87,6 +86,7 @@ typedef struct
AXIS_HDL pFirst;
epicsThreadId motorThread;
motorAxisLogFunc print;
void *logParam;
epicsTimeStamp now;
} motorMM4000_t;
@@ -113,7 +113,7 @@ static int sendAndReceive(MM4000Controller *pController, char *outputString, cha
#define TCP_TIMEOUT 2.0
static motorMM4000_t drv={ NULL, NULL, motorMM4000LogMsg, { 0, 0 } };
static motorMM4000_t drv={ NULL, NULL, motorMM4000LogMsg, 0, { 0, 0 } };
static int numMM4000Controllers;
/* Pointer to array of controller strutures */
static MM4000Controller *pMM4000Controller=NULL;
@@ -161,22 +161,35 @@ static int motorAxisInit(void)
return MOTOR_AXIS_OK;
}
static int motorAxisSetLog(motorAxisLogFunc logFunc)
static int motorAxisSetLog( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param )
{
if (logFunc == NULL) drv.print=motorMM4000LogMsg;
else drv.print = logFunc;
return MOTOR_AXIS_OK;
}
static int motorAxisSetLogParam(AXIS_HDL pAxis, void * param)
{
if (pAxis == NULL) return MOTOR_AXIS_ERROR;
else
if (pAxis == NULL)
{
pAxis->logParam = param;
if (logFunc == NULL)
{
drv.print=motorMM4000LogMsg;
drv.logParam = NULL;
}
else
{
drv.print=logFunc;
drv.logParam = param;
}
}
return MOTOR_AXIS_OK;
else
{
if (logFunc == NULL)
{
pAxis->print=motorMM4000LogMsg;
pAxis->logParam = NULL;
}
else
{
pAxis->print=logFunc;
pAxis->logParam = param;
}
}
return MOTOR_AXIS_OK;
}
static AXIS_HDL motorAxisOpen(int card, int axis, char * param)
@@ -221,11 +234,6 @@ static int motorAxisSetCallback(AXIS_HDL pAxis, motorAxisCallbackFunc callback,
}
}
static int motorAxisPrimitive(AXIS_HDL pAxis, int length, char * string)
{
return MOTOR_AXIS_OK;
}
static int motorAxisSetDouble(AXIS_HDL pAxis, motorAxisParam_t function, double value)
{
int ret_status = MOTOR_AXIS_ERROR;
+31 -23
View File
@@ -26,15 +26,13 @@
motorAxisDrvSET_t motorXPS =
{
20,
14,
motorAxisReport, /**< Standard EPICS driver report function (optional) */
motorAxisInit, /**< Standard EPICS dirver initialisation function (optional) */
motorAxisSetLog, /**< Defines an external logging function (optional) */
motorAxisSetLogParam, /**< Defines an external logging function user parameter (optional) */
motorAxisOpen, /**< Driver open function */
motorAxisClose, /**< Driver close function */
motorAxisSetCallback, /**< Provides a callback function the driver can call when the status updates */
motorAxisPrimitive, /**< Passes a controller dependedent string */
motorAxisSetDouble, /**< Pointer to function to set a double value */
motorAxisSetInteger, /**< Pointer to function to set an integer value */
motorAxisGetDouble, /**< Pointer to function to get a double value */
@@ -82,6 +80,7 @@ typedef struct motorAxisHandle
int positionerError;
int card;
int axis;
motorAxisLogFunc print;
void *logParam;
epicsMutexId mutexId;
} motorAxis;
@@ -91,11 +90,12 @@ typedef struct
AXIS_HDL pFirst;
epicsThreadId motorThread;
motorAxisLogFunc print;
void *logParam;
epicsTimeStamp now;
} motorXPS_t;
static int motorXPSLogMsg(void * param, const motorAxisLogMask_t logMask, const char *pFormat, ...);
#define PRINT (drv.print)
#define PRINT (pAxis->print)
#define FLOW motorAxisTraceFlow
#define ERROR motorAxisTraceError
#define IODRIVER motorAxisTraceIODriver
@@ -105,7 +105,7 @@ static int motorXPSLogMsg(void * param, const motorAxisLogMask_t logMask, const
#define XPSC8_END_OF_RUN_PLUS 0x00000200
#define TCP_TIMEOUT 2.0
static motorXPS_t drv={ NULL, NULL, motorXPSLogMsg, { 0, 0 } };
static motorXPS_t drv={ NULL, NULL, motorXPSLogMsg, 0, { 0, 0 } };
static int numXPSControllers;
/* Pointer to array of controller strutures */
static XPSController *pXPSController=NULL;
@@ -144,22 +144,35 @@ static int motorAxisInit(void)
return MOTOR_AXIS_OK;
}
static int motorAxisSetLog(motorAxisLogFunc logFunc)
static int motorAxisSetLog( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param )
{
if (logFunc == NULL) drv.print=motorXPSLogMsg;
else drv.print = logFunc;
return MOTOR_AXIS_OK;
}
static int motorAxisSetLogParam(AXIS_HDL pAxis, void * param)
{
if (pAxis == NULL) return MOTOR_AXIS_ERROR;
else
if (pAxis == NULL)
{
pAxis->logParam = param;
if (logFunc == NULL)
{
drv.print=motorXPSLogMsg;
drv.logParam = NULL;
}
else
{
drv.print=logFunc;
drv.logParam = param;
}
}
return MOTOR_AXIS_OK;
else
{
if (logFunc == NULL)
{
pAxis->print=motorXPSLogMsg;
pAxis->logParam = NULL;
}
else
{
pAxis->print=logFunc;
pAxis->logParam = param;
}
}
return MOTOR_AXIS_OK;
}
static AXIS_HDL motorAxisOpen(int card, int axis, char * param)
@@ -204,11 +217,6 @@ static int motorAxisSetCallback(AXIS_HDL pAxis, motorAxisCallbackFunc callback,
}
}
static int motorAxisPrimitive(AXIS_HDL pAxis, int length, char * string)
{
return MOTOR_AXIS_OK;
}
static int motorAxisSetDouble(AXIS_HDL pAxis, motorAxisParam_t function, double value)
{
int ret_status = MOTOR_AXIS_ERROR;