forked from epics_driver_modules/motorBase
phase 3 asyn motor support for OMS MAXnet and MAXv from Jens Eden.
This commit is contained in:
@@ -21,6 +21,9 @@ SoftMotorSrc_DEPEND_DIRS = MotorSrc
|
||||
# All the following modules require ASYN.
|
||||
ifdef ASYN
|
||||
|
||||
DIRS += OmsAsynSrc
|
||||
OmsAsynSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += MotorSimSrc
|
||||
MotorSimSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ Last Modified: $Date: 2009-06-18 19:38:20 $
|
||||
* force a status update with a call to callCallback().
|
||||
* - Matthew Pearson added deferred move support.
|
||||
* 2010-10-05 rls - MP's fix for deferred moves broken in drvMotorSim.
|
||||
* 2012-10-09 rls - Added motorAxisforceCallback to support motor record
|
||||
* GET_INFO commands.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -63,7 +65,10 @@ motorAxisDrvSET_t motorSim =
|
||||
motorAxisHome, /**< Pointer to function to execute a more to reference or home */
|
||||
motorAxisMove, /**< Pointer to function to execute a position move */
|
||||
motorAxisVelocityMove, /**< Pointer to function to execute a velocity mode move */
|
||||
motorAxisStop /**< Pointer to function to stop motion */
|
||||
motorAxisStop, /**< Pointer to function to stop motion */
|
||||
motorAxisforceCallback, /**< Pointer to function to request a poller status update */
|
||||
motorAxisProfileMove, /**< Pointer to function to execute a profile move */
|
||||
motorAxisTriggerProfile /**< Pointer to function to trigger a profile move */
|
||||
};
|
||||
|
||||
epicsExportAddress(drvet, motorSim);
|
||||
@@ -120,10 +125,13 @@ 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))
|
||||
#define DELTA 0.1
|
||||
|
||||
/*Deferred moves functions.*/
|
||||
static int processDeferredMoves(const motorSim_t * pDrv);
|
||||
|
||||
static void motorProcTask(motorSim_t *);
|
||||
|
||||
static void motorAxisReportAxis( AXIS_HDL pAxis, int level )
|
||||
{
|
||||
printf( "Found driver for motorSim card %d, axis %d, mutex %p\n", pAxis->card, pAxis->axis, pAxis->axisMutex );
|
||||
@@ -562,6 +570,18 @@ static int motorAxisStop( AXIS_HDL pAxis, double acceleration )
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static int motorAxisforceCallback(AXIS_HDL pAxis)
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
return(MOTOR_AXIS_ERROR);
|
||||
|
||||
/* Force a status update. */
|
||||
motorParam->forceCallback(pAxis->params);
|
||||
motorProcTask(&drv);
|
||||
return(MOTOR_AXIS_OK);
|
||||
}
|
||||
|
||||
|
||||
/**\defgroup motorSimTask Routines to implement the motor axis simulation task
|
||||
@{
|
||||
*/
|
||||
@@ -636,34 +656,39 @@ static void motorSimProcess( AXIS_HDL pAxis, double delta )
|
||||
motorParam->setInteger( pAxis->params, motorAxisLowHardLimit, (pAxis->nextpoint.axis[0].p <= pAxis->lowHardLimit) );
|
||||
}
|
||||
|
||||
#define DELTA 0.1
|
||||
static void motorSimTask( motorSim_t * pDrv )
|
||||
|
||||
static void motorProcTask( motorSim_t *pDrv)
|
||||
{
|
||||
epicsTimeStamp now;
|
||||
double delta;
|
||||
AXIS_HDL pAxis;
|
||||
|
||||
/* Get a new timestamp */
|
||||
epicsTimeGetCurrent( &now );
|
||||
delta = epicsTimeDiffInSeconds( &now, &(pDrv->now) );
|
||||
pDrv->now = now;
|
||||
|
||||
if ( delta > (DELTA/4.0) && delta <= (4.0*DELTA) )
|
||||
{
|
||||
/* A reasonable time has elapsed, it's not a time step in the clock */
|
||||
|
||||
for (pAxis = pDrv->pFirst; pAxis != NULL; pAxis = pAxis->pNext )
|
||||
{
|
||||
if (epicsMutexLock( pAxis->axisMutex ) == epicsMutexLockOK)
|
||||
{
|
||||
motorSimProcess( pAxis, delta );
|
||||
motorParam->callCallback( pAxis->params );
|
||||
epicsMutexUnlock( pAxis->axisMutex );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void motorSimTask( motorSim_t * pDrv )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
/* Get a new timestamp */
|
||||
epicsTimeGetCurrent( &now );
|
||||
delta = epicsTimeDiffInSeconds( &now, &(pDrv->now) );
|
||||
pDrv->now = now;
|
||||
|
||||
if ( delta > (DELTA/4.0) && delta <= (4.0*DELTA) )
|
||||
{
|
||||
/* A reasonable time has elapsed, it's not a time step in the clock */
|
||||
|
||||
for (pAxis = pDrv->pFirst; pAxis != NULL; pAxis = pAxis->pNext )
|
||||
{
|
||||
if (epicsMutexLock( pAxis->axisMutex ) == epicsMutexLockOK)
|
||||
{
|
||||
motorSimProcess( pAxis, delta );
|
||||
motorParam->callCallback( pAxis->params );
|
||||
epicsMutexUnlock( pAxis->axisMutex );
|
||||
}
|
||||
}
|
||||
}
|
||||
motorProcTask(pDrv);
|
||||
epicsThreadSleep( DELTA );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Makefile
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
|
||||
#
|
||||
#USR_CXXFLAGS += -DDEBUG
|
||||
|
||||
DBD += omsAsynSupport.dbd
|
||||
|
||||
LIBRARY_IOC_DEFAULT += omsAsyn
|
||||
|
||||
SRCS += omsBaseAxis.cpp
|
||||
SRCS += omsBaseController.cpp
|
||||
SRCS += omsMAXnet.cpp
|
||||
SRCS += omsMAXv.cpp
|
||||
#SRCS += omsMAXvEncFunc.cpp
|
||||
|
||||
oms_LIBS += motor
|
||||
oms_LIBS += asyn
|
||||
oms_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
Please note:
|
||||
|
||||
- The MAXnet IP-stack is very basic. You cannot ping the card and it doesn't know
|
||||
anything about routing, which means you can only use it from hosts in the same
|
||||
subnet.
|
||||
- MAXnet cards with firmware versions older than 1.33.4 shouldn't be used
|
||||
with the ethernet port. They abort communication, if they detect a tcp packet
|
||||
with checksum 0xffff.
|
||||
- MAXnet cards with firmware versions below 1.33 use "\n\r" as input EOS
|
||||
on Ethernet ports. Version 1.33 and higher use "\n" on ethernet and serial ports.
|
||||
Comment the setInputEos call and set input EOS in st.cmd if using firmware
|
||||
versions below 1.33
|
||||
|
||||
add this to st.cmd if using the ethernet port:
|
||||
drvAsynIPPortConfigure("MAXNET","maxnet-ip-address:23",0,0,0)
|
||||
|
||||
add this to st.cmd if using the serial port:
|
||||
drvAsynSerialPortConfigure("MAXNET","/your/serial/device",0,0,0)
|
||||
asynSetOption("MAXNET",0,"baud","115200")
|
||||
asynSetOption("MAXNET",0,"bits","8")
|
||||
asynSetOption("MAXNET",0,"parity","none")
|
||||
asynSetOption("MAXNET",0,"crtscts","Y")
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
registrar(OmsMAXnetAsynRegister)
|
||||
registrar(OmsMAXvAsynRegister)
|
||||
#registrar(omsMAXvEncFuncAsynRegister)
|
||||
#variable(motorMAXvdebug)
|
||||
#variable(motorOMSBASEdebug)
|
||||
#variable(motorMAXvEncFuncdebug)
|
||||
#variable(motorMAXnetdebug)
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
FILENAME... omsBaseAxis.cpp
|
||||
USAGE... Pro-Dex OMS asyn motor base axes support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Created on: 6/2012
|
||||
* Author: eden
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "omsBaseAxis.h"
|
||||
#include "omsBaseController.h"
|
||||
|
||||
static const char *driverName = "omsBaseAxisDriver";
|
||||
|
||||
omsBaseAxis::omsBaseAxis(omsBaseController *pController, int axis, char axisChar)
|
||||
: asynMotorAxis(pController, axis), axisChar(axisChar)
|
||||
{
|
||||
pC_ = pController;
|
||||
stepper = 1;
|
||||
invertLimit = 0;
|
||||
}
|
||||
|
||||
asynStatus omsBaseAxis::move(double position, int relative, double min_velocity, double max_velocity, double acceleration)
|
||||
{
|
||||
// omsBaseAxis *pAxis = this->getAxis(pasynUser);
|
||||
static const char *functionName = "moveAxis";
|
||||
|
||||
asynStatus status = asynError;
|
||||
epicsInt32 minvelo, velo, acc, rela, pos;
|
||||
char *relabs[2] = {(char *) "MA", (char *) "MR"};
|
||||
char buff[100];
|
||||
|
||||
if (relative)
|
||||
rela = 1;
|
||||
else
|
||||
rela = 0;
|
||||
|
||||
pos = (epicsInt32) (position + 0.5);
|
||||
if (abs(pos) > 67000000){
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s:%s axis %d position out of range %f\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, position);
|
||||
return status;
|
||||
}
|
||||
|
||||
velo = (epicsInt32) (max_velocity + 0.5);
|
||||
if (velo < 1) velo = 1;
|
||||
else if (velo > 4000000) velo = 4000000;
|
||||
|
||||
minvelo = (epicsInt32) (min_velocity + 0.5);
|
||||
if (minvelo < 0) minvelo = 0;
|
||||
else if (minvelo >= velo) minvelo = velo - 1;
|
||||
|
||||
acc = abs((epicsInt32) acceleration);
|
||||
if (acc > 8000000)
|
||||
acc = 8000000;
|
||||
else if (acc < 1)
|
||||
acc = 1;
|
||||
|
||||
/* move to the specified position */
|
||||
sprintf(buff, "A%1c AC%d; VB%d; VL%d; %s%d; GO ID", axisChar, acc, minvelo, velo, relabs[rela], pos);
|
||||
status = pC_->sendOnlyLock(buff);
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: Set driver %s, axis %d move to %f, min vel=%f, max_vel=%f, accel=%f",
|
||||
driverName, functionName, pC_->portName, axisNo_, position, min_velocity, max_velocity, acceleration );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus omsBaseAxis::home(double min_velocity, double max_velocity, double acceleration, int forwards )
|
||||
{
|
||||
static const char *functionName = "homeAxis";
|
||||
|
||||
asynStatus status = asynError;
|
||||
char buff[60];
|
||||
char *direction[2] = {(char*) "HR", (char*) "HM"};
|
||||
epicsInt32 velo, acc, fw = 0;
|
||||
|
||||
if (forwards) fw = 1;
|
||||
|
||||
velo = (epicsInt32) max_velocity;
|
||||
if (velo < 1) velo = 1;
|
||||
else if (velo > 1000000) velo = 1000000;
|
||||
|
||||
acc = abs((epicsInt32) acceleration);
|
||||
if (acc > 8000000)
|
||||
acc = 8000000;
|
||||
else if (acc < 1)
|
||||
acc = 1;
|
||||
|
||||
/* do a home run and move to the home position */
|
||||
sprintf(buff, "A%1c AC%d; VL%d; %s; MA0 GO ID", axisChar, acc, velo, direction[forwards]);
|
||||
status = pC_->sendOnlyLock(buff);
|
||||
|
||||
homing = 1;
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: Set driver %s, axis %d to home %s, min vel=%f, max_vel=%f, accel=%f",
|
||||
driverName, functionName, pC_->portName, axisNo_, (forwards?"FORWARDS":"REVERSE"), min_velocity, max_velocity, acceleration );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus omsBaseAxis::doMoveToHome()
|
||||
{
|
||||
static const char *functionName = "doMoveToHome";
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s: This function is not yet implemented for axis %d\n",
|
||||
driverName, functionName, axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus omsBaseAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration )
|
||||
{
|
||||
asynStatus status = asynError;
|
||||
static const char *functionName = "moveVelocityAxis";
|
||||
|
||||
char buff[100];
|
||||
epicsInt32 velo, acc;
|
||||
|
||||
acc = (epicsInt32) acceleration;
|
||||
if (acc < 1) acc = 1;
|
||||
else if (acc > 8000000) acc = 8000000;
|
||||
|
||||
velo = (epicsInt32) maxVelocity;
|
||||
if (velo > 4000000) velo = 4000000;
|
||||
else if (velo < -4000000) velo = -4000000;
|
||||
|
||||
sprintf(buff, "A%1c AC%d; JG%d;", axisChar, acc, velo);
|
||||
status = pC_->sendOnlyLock(buff);
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: Set port %s, axis %d move with velocity of %f, acceleration=%f",
|
||||
driverName, functionName, pC_->portName, axisNo_, maxVelocity, acceleration );
|
||||
|
||||
/* Send a signal to the poller task which will make it do a poll, and switch to the moving poll rate */
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus omsBaseAxis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status = asynError;
|
||||
static const char *functionName = "stopAxis";
|
||||
int acc;
|
||||
char buff[50];
|
||||
|
||||
acc = (int)(fabs(acceleration)+0.5);
|
||||
if (acc > 8000000) acc=8000000;
|
||||
if (acc < 1) acc = 200000;
|
||||
|
||||
sprintf(buff, "A%1c AC%d; ST ID;", axisChar, acc);
|
||||
status = pC_->sendOnlyLock(buff);
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: port %s, set axis %d to stop with accel=%f\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, axisNo_, acceleration );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Set the current position of the motor.
|
||||
* \param[in] position The new absolute motor position that should be set in the hardware. Units=steps.
|
||||
*/
|
||||
asynStatus omsBaseAxis::setPosition(double position)
|
||||
{
|
||||
static const char *functionName = "setPosition";
|
||||
asynStatus status = asynError;
|
||||
char buff[20];
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s:%s axis %d set position to %f\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, position);
|
||||
sprintf(buff,"A%1c LP%d;", axisChar, (int)(position));
|
||||
status = pC_->sendOnlyLock(buff);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** we need to implement this, because we need to use the motorUpdateStatus_ function
|
||||
* in asynMotorController, because we cannot access statusChanged_ (shouldn't be private)
|
||||
* ignore moving flag, since we have our own poller.
|
||||
*/
|
||||
asynStatus omsBaseAxis::poll(bool *moving)
|
||||
{
|
||||
epicsEventSignal(pC_->pollEventId_);
|
||||
return asynSuccess;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
FILENAME... omsBaseAxis.h
|
||||
USAGE... Pro-Dex OMS asyn motor base axes support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 06/2012
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#ifndef OMSBASEAXIS_H_
|
||||
#define OMSBASEAXIS_H_
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
class omsBaseController;
|
||||
|
||||
class omsBaseAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
omsBaseAxis(class omsBaseController *, int, char );
|
||||
virtual asynStatus move(double position, int relative, double minVelocity, double maxVelocity, double acceleration);
|
||||
virtual asynStatus moveVelocity(double minVelocity, double maxVelocity, double acceleration);
|
||||
virtual asynStatus home(double minVelocity, double maxVelocity, double acceleration, int forwards);
|
||||
virtual asynStatus stop(double acceleration);
|
||||
virtual asynStatus doMoveToHome();
|
||||
virtual asynStatus setPosition(double position);
|
||||
virtual asynStatus poll(bool *moving);
|
||||
|
||||
int getAxis(){return axisNo_;};
|
||||
int isStepper(){return stepper;};
|
||||
void setStepper(int val){stepper=val;};
|
||||
int getLimitInvert(){return invertLimit;};
|
||||
void setLimitInvert(int val){invertLimit=val;};
|
||||
int card;
|
||||
int moveDelay;
|
||||
char axisChar;
|
||||
bool homing;
|
||||
|
||||
|
||||
private:
|
||||
omsBaseController *pC_;
|
||||
int stepper;
|
||||
int invertLimit;
|
||||
|
||||
friend class omsBaseController;
|
||||
};
|
||||
|
||||
#endif /* OMSBASEAXIS_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
FILENAME... omsBaseController.h
|
||||
USAGE... Pro-Dex OMS asyn motor base controller support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 06/2012
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#ifndef OMSBASECONTROLLER_H_
|
||||
#define OMSBASECONTROLLER_H_
|
||||
|
||||
#include <epicsTime.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <ellLib.h>
|
||||
#include <iocsh.h>
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "omsBaseAxis.h"
|
||||
|
||||
#define OMS_MAX_AXES 8
|
||||
#define OMSBASE_MAXNUMBERLEN 12
|
||||
#define OMSINPUTBUFFERLEN OMSBASE_MAXNUMBERLEN * OMS_MAX_AXES + 2
|
||||
|
||||
class omsBaseController : public asynMotorController {
|
||||
public:
|
||||
omsBaseController(const char *portName, int numAxes, int priority, int stackSize, int extMotorParams);
|
||||
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||
virtual void report(FILE *fp, int level);
|
||||
virtual asynStatus sendReceive(const char*, char*, unsigned int ) = 0;
|
||||
virtual asynStatus sendOnly(const char *outputBuff) = 0;
|
||||
void omsPoller();
|
||||
virtual asynStatus startPoller(double movingPollPeriod, double idlePollPeriod, int forcedFastPolls);
|
||||
static void callPoller(void*);
|
||||
static void callShutdown(void *ptr){((omsBaseController*)ptr)->shutdown();};
|
||||
void shutdown();
|
||||
|
||||
protected:
|
||||
virtual asynStatus writeOctet(asynUser *, const char *, size_t, size_t *);
|
||||
virtual asynStatus getFirmwareVersion();
|
||||
virtual asynStatus Init(const char*, int);
|
||||
virtual asynStatus sanityCheck();
|
||||
asynStatus sendReceiveLock(const char*, char*, unsigned int );
|
||||
asynStatus sendOnlyLock(const char *);
|
||||
virtual omsBaseAxis* getAxis(asynUser *pasynUser);
|
||||
virtual omsBaseAxis* getAxis(int);
|
||||
asynStatus getAxesArray(char*, int positions[OMS_MAX_AXES]);
|
||||
virtual asynStatus getAxesPositions(int positions[OMS_MAX_AXES]);
|
||||
virtual asynStatus getAxesStatus(char *, int, bool *);
|
||||
virtual asynStatus getEncoderPositions(epicsInt32 encPosArr[OMS_MAX_AXES]);
|
||||
virtual asynStatus getClosedLoopStatus(int clstatus[OMS_MAX_AXES]);
|
||||
virtual epicsEventWaitStatus waitInterruptible(double timeout);
|
||||
virtual bool watchdogOK();
|
||||
char* getPortName(){return portName;};
|
||||
bool firmwareMin(int, int, int);
|
||||
static omsBaseController* findController(const char*);
|
||||
static ELLLIST omsControllerList;
|
||||
static int omsTotalControllerNumber;
|
||||
char* controllerType;
|
||||
int fwMajor, fwMinor, fwRevision;
|
||||
epicsTimeStamp now;
|
||||
char* portName;
|
||||
bool useWatchdog;
|
||||
bool enabled;
|
||||
int numAxes;
|
||||
|
||||
private:
|
||||
asynStatus sendReplace(omsBaseAxis*, char*);
|
||||
asynStatus sendReceiveReplace(omsBaseAxis*, char *, char *, int);
|
||||
asynStatus getSubstring(unsigned int , char* , char *, unsigned int);
|
||||
int sanityCounter;
|
||||
epicsThreadId motorThread;
|
||||
char inputBuffer[OMSINPUTBUFFERLEN];
|
||||
char pollInputBuffer[OMSINPUTBUFFERLEN];
|
||||
omsBaseAxis** pAxes;
|
||||
int controllerNumber;
|
||||
epicsMutex *baseMutex;
|
||||
int sendReceiveIndex;
|
||||
int sendIndex;
|
||||
int receiveIndex;
|
||||
int pollIndex;
|
||||
int priority, stackSize;
|
||||
|
||||
friend class omsBaseAxis;
|
||||
};
|
||||
|
||||
typedef struct omsBaseNode {
|
||||
ELLNODE node;
|
||||
const char *portName;
|
||||
omsBaseController* pController;
|
||||
} omsBaseNode;
|
||||
|
||||
#endif /* OMSBASE_H_ */
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
FILENAME... omsMAXnet.cpp
|
||||
USAGE... Pro-Dex OMS MAXnet asyn motor controller support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 10/2010
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "omsMAXnet.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
#ifdef __GNUG__
|
||||
#ifdef DEBUG
|
||||
#define Debug(l, f, args...) {if (l <= motorMAXnetdebug) \
|
||||
errlogPrintf(f, ## args);}
|
||||
#else
|
||||
#define Debug(l, f, args...)
|
||||
#endif
|
||||
#else
|
||||
#define Debug
|
||||
#endif
|
||||
static const char *driverName = "omsMAXnetDriver";
|
||||
volatile int motorMAXnetdebug = 0;
|
||||
extern "C" {epicsExportAddress(int, motorMAXnetdebug);}
|
||||
|
||||
#define MAXnet_MAX_BUFFERLENGTH 80
|
||||
|
||||
static void connectCallback(asynUser *pasynUser, asynException exception)
|
||||
{
|
||||
asynStatus status;
|
||||
int connected = 0;
|
||||
omsMAXnet* pController = (omsMAXnet*)pasynUser->userPvt;
|
||||
|
||||
if (exception == asynExceptionConnect) {
|
||||
status = pasynManager->isConnected(pasynUser, &connected);
|
||||
if (connected){
|
||||
if (motorMAXnetdebug > 4) asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"MAXnet connectCallback: TCP-Port connected\n");
|
||||
pController->portConnected = 1;
|
||||
}
|
||||
else {
|
||||
if (motorMAXnetdebug > 3) asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"MAXnet connectCallback: TCP-Port disconnected\n");
|
||||
pController->portConnected = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void omsMAXnet::asynCallback(void *drvPvt, asynUser *pasynUser, char *data, size_t len, int eomReason)
|
||||
{
|
||||
omsMAXnet* pController = (omsMAXnet*)drvPvt;
|
||||
|
||||
/* If the string has a "%", it is a notification, increment counter and
|
||||
* send a signal to the poller task which will trigger a poll */
|
||||
|
||||
if ((len >= 1) && (strchr(data, '%') != NULL)){
|
||||
char* pos = strchr(data, '%');
|
||||
epicsEventSignal(pController->pollEventId_);
|
||||
while (pos != NULL){
|
||||
Debug(2, "omsMAXnet::asynCallback: %s (%d)\n", data, len);
|
||||
pController->notificationMutex->lock();
|
||||
++pController->notificationCounter;
|
||||
pController->notificationMutex->unlock();
|
||||
++pos;
|
||||
pos = strchr(pos, '%');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
omsMAXnet::omsMAXnet(const char* portName, int numAxes, const char* serialPortName, const char* initString, int priority, int stackSize)
|
||||
: omsBaseController(portName, numAxes, priority, stackSize, 0){
|
||||
|
||||
asynStatus status;
|
||||
asynInterface *pasynInterface;
|
||||
|
||||
controllerType = epicsStrDup("MAXnet");
|
||||
|
||||
notificationMutex = new epicsMutex();
|
||||
notificationCounter = 0;
|
||||
useWatchdog = true;
|
||||
|
||||
serialPortName = epicsStrDup(serialPortName);
|
||||
|
||||
pasynUserSerial = pasynManager->createAsynUser(0,0);
|
||||
pasynUserSerial->userPvt = this;
|
||||
|
||||
Debug(9, "omsMAXnet connect to %s \n", serialPortName);
|
||||
status = pasynManager->connectDevice(pasynUserSerial,serialPortName,0);
|
||||
if(status != asynSuccess){
|
||||
printf("MAXnetConfig: can't connect to port %s: %s\n",serialPortName,pasynUserSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(9, "omsMAXnet add Callback \n");
|
||||
status = pasynManager->exceptionCallbackAdd(pasynUserSerial, connectCallback);
|
||||
if(status != asynSuccess){
|
||||
printf("MAXnetConfig: can't set exceptionCallback for %s: %s\n",serialPortName,pasynUserSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
/* set the connect flag */
|
||||
pasynManager->isConnected(pasynUserSerial, &portConnected);
|
||||
|
||||
Debug(9, "omsMAXnet findInterface \n");
|
||||
pasynInterface = pasynManager->findInterface(pasynUserSerial,asynOctetType,1);
|
||||
if( pasynInterface == NULL) {
|
||||
printf("MAXnetConfig: %s driver not supported\n", asynOctetType);
|
||||
return;
|
||||
}
|
||||
pasynOctetSerial = (asynOctet*)pasynInterface->pinterface;
|
||||
octetPvtSerial = pasynInterface->drvPvt;
|
||||
|
||||
Debug(9, "omsMAXnet SyncIO->connect \n");
|
||||
status = pasynOctetSyncIO->connect(serialPortName, 0, &pasynUserSyncIOSerial, NULL);
|
||||
if(status != asynSuccess){
|
||||
printf("MAXnetConfig: can't connect pasynOctetSyncIO %s: %s\n",serialPortName,pasynUserSyncIOSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
/* flush any junk at input port - should be no data available */
|
||||
Debug(9, "omsMAXnet flush \n");
|
||||
pasynOctetSyncIO->flush(pasynUserSyncIOSerial);
|
||||
|
||||
timeout = 2.0;
|
||||
pasynUserSerial->timeout = 0.0;
|
||||
|
||||
Debug(9, "omsMAXnet setInputEos \n");
|
||||
// CAUTION firmware versions before 1.33.4 use '\n' for serial port and '\n\r' for IP port as InputEOS
|
||||
// Set inputEOS in st.cmd for old firmware versions
|
||||
status = pasynOctetSyncIO->setInputEos(pasynUserSyncIOSerial, "\n\r", 2);
|
||||
if(status != asynSuccess){
|
||||
printf("MAXnetConfig: unable to set InputEOS %s: %s\n", serialPortName, pasynUserSyncIOSerial->errorMessage);
|
||||
return ;
|
||||
}
|
||||
|
||||
Debug(9, "omsMAXnet setOutputEos \n");
|
||||
status = pasynOctetSyncIO->setOutputEos(pasynUserSyncIOSerial, "\n", 1);
|
||||
if(status != asynSuccess){
|
||||
printf("MAXnetConfig: unable to set OutputEOS %s: %s\n",serialPortName,pasynUserSyncIOSerial->errorMessage);
|
||||
return ;
|
||||
}
|
||||
|
||||
Debug(9, "omsMAXnet registerInterruptUser \n");
|
||||
void* registrarPvt= NULL;
|
||||
status = pasynOctetSerial->registerInterruptUser(octetPvtSerial, pasynUserSerial, omsMAXnet::asynCallback, this, ®istrarPvt);
|
||||
if(status != asynSuccess) {
|
||||
printf("MAXnetConfig: registerInterruptUser failed - %s: %s\n",serialPortName,pasynUserSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(9, "omsMAXnet get FirmwareVersion \n");
|
||||
/* get FirmwareVersion */
|
||||
if(getFirmwareVersion() != asynSuccess) {
|
||||
printf("MAXnetConfig: unable to talk to controller at %s: %s\n",serialPortName,pasynUserSyncIOSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
if (fwMinor < 30 ){
|
||||
printf("This Controllers Firmware Version %d.%d is not supported, version 1.30 or higher is mandatory\n", fwMajor, fwMinor);
|
||||
}
|
||||
|
||||
if( Init(initString, 0) != asynSuccess) {
|
||||
printf("MAXnetConfig: unable to talk to controller at %s: %s\n",serialPortName,pasynUserSyncIOSerial->errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// poll the serial port for notification messages while waiting
|
||||
epicsEventWaitStatus omsMAXnet::waitInterruptible(double timeout)
|
||||
{
|
||||
double pollWait, timeToWait = timeout;
|
||||
asynStatus status;
|
||||
size_t nRead;
|
||||
char inputBuff[1];
|
||||
int eomReason = 0;
|
||||
epicsTimeStamp starttime;
|
||||
epicsEventWaitStatus waitStatus = epicsEventWaitTimeout;
|
||||
epicsTimeGetCurrent(&starttime);
|
||||
|
||||
// TODO use local poll Periods or lock()
|
||||
if (timeout == idlePollPeriod_)
|
||||
pollWait = idlePollPeriod_ / 5.0;
|
||||
else
|
||||
pollWait = movingPollPeriod_ / 20.0;
|
||||
|
||||
pasynManager->lockPort(pasynUserSerial);
|
||||
pasynOctetSerial->flush(octetPvtSerial, pasynUserSerial);
|
||||
pasynManager->unlockPort(pasynUserSerial);
|
||||
while ( timeToWait > 0){
|
||||
/* reading with bufferlength 0 and timeout 0.0 triggers a callback and
|
||||
* poll event, if a notification is outstanding */
|
||||
if (enabled) {
|
||||
pasynManager->lockPort(pasynUserSerial);
|
||||
status = pasynOctetSerial->read(octetPvtSerial, pasynUserSerial, inputBuff,
|
||||
0, &nRead, &eomReason);
|
||||
pasynManager->unlockPort(pasynUserSerial);
|
||||
}
|
||||
if (epicsEventWaitWithTimeout(pollEventId_, pollWait) == epicsEventWaitOK) {
|
||||
waitStatus = epicsEventWaitOK;
|
||||
break;
|
||||
}
|
||||
epicsTimeGetCurrent(&now);
|
||||
timeToWait = timeout - epicsTimeDiffInSeconds(&now, &starttime);
|
||||
}
|
||||
return waitStatus;
|
||||
}
|
||||
|
||||
asynStatus omsMAXnet::sendOnly(const char *outputBuff)
|
||||
{
|
||||
size_t nActual = 0;
|
||||
asynStatus status;
|
||||
|
||||
if (!enabled) return asynError;
|
||||
Debug(9, "omsMAXnet::sendOnly: write: %s \n", outputBuff);
|
||||
|
||||
status = pasynOctetSyncIO->write(pasynUserSyncIOSerial, outputBuff,
|
||||
strlen(outputBuff), timeout, &nActual);
|
||||
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(pasynUserSyncIOSerial, ASYN_TRACE_ERROR,
|
||||
"drvMAXnetAsyn:sendOnly: error sending command %d, sent=%d, status=%d\n",
|
||||
outputBuff, nActual, status);
|
||||
}
|
||||
Debug(4, "omsMAXnet::sendOnly: wrote: %s \n", outputBuff);
|
||||
return(status);
|
||||
}
|
||||
|
||||
asynStatus omsMAXnet::sendReceive(const char *outputBuff, char *inputBuff, unsigned int inputSize)
|
||||
{
|
||||
char localBuffer[MAXnet_MAX_BUFFERLENGTH + 1] = "";
|
||||
size_t nRead, nWrite, bufferSize = inputSize;
|
||||
int eomReason = 0;
|
||||
asynStatus status = asynSuccess;
|
||||
char *outString;
|
||||
int errorCount = 10;
|
||||
|
||||
if (!enabled) return asynError;
|
||||
|
||||
Debug(4, "omsMAXnet::sendReceive: write: %s \n", outputBuff);
|
||||
|
||||
if (bufferSize > MAXnet_MAX_BUFFERLENGTH) bufferSize = MAXnet_MAX_BUFFERLENGTH;
|
||||
|
||||
Debug(9, "omsMAXnet::sendReceive: read the notification \n");
|
||||
/*
|
||||
* read the notification from input buffer
|
||||
*/
|
||||
while ((notificationCounter > 0) && errorCount){
|
||||
status = pasynOctetSyncIO->read(pasynUserSyncIOSerial, localBuffer, sizeof(localBuffer), 0.1, &nRead, &eomReason);
|
||||
if (status == asynSuccess) {
|
||||
localBuffer[nRead] = '\0';
|
||||
if (isNotification(localBuffer) && (notificationCounter > 0)) {
|
||||
Debug(2, "omsMAXnet::sendReceive: decrement notificationCounter: %s, len: %d, reason: %d\n", localBuffer, nRead, eomReason);
|
||||
--notificationCounter;
|
||||
}
|
||||
}
|
||||
else if (status == asynTimeout) {
|
||||
notificationCounter = 0;
|
||||
}
|
||||
else {
|
||||
--errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
Debug(9, "omsMAXnet::sendReceive: write \n");
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserSyncIOSerial, outputBuff, strlen(outputBuff), localBuffer,
|
||||
bufferSize, timeout, &nWrite, &nRead, &eomReason);
|
||||
if (status == asynSuccess) localBuffer[nRead] = '\0';
|
||||
|
||||
// if input data is a notification read until expected data arrived
|
||||
while ((status == asynSuccess) && isNotification(localBuffer)) {
|
||||
Debug(2, "omsMAXnet::sendReceive: notification while reading: %s\n", localBuffer);
|
||||
status = pasynOctetSyncIO->read(pasynUserSyncIOSerial, localBuffer,
|
||||
bufferSize, timeout, &nRead, &eomReason);
|
||||
if (status == asynSuccess) localBuffer[nRead] = '\0';
|
||||
}
|
||||
|
||||
if ((status == asynSuccess) && (eomReason == ASYN_EOM_EOS)) {
|
||||
// cut off a leading /006
|
||||
outString = strrchr(localBuffer, 6);
|
||||
if (outString == NULL) {
|
||||
outString = localBuffer;
|
||||
}
|
||||
else {
|
||||
++outString;
|
||||
}
|
||||
|
||||
// copy into inputBuffer
|
||||
strncpy(inputBuff, outString, inputSize);
|
||||
inputBuff[inputSize-1] = '\0';
|
||||
}
|
||||
|
||||
Debug(4, "omsMAXnet::sendReceive: read: %s \n", inputBuff);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if buffer is a notification messages with 13 chars ("%000 SSSSSSSS")
|
||||
*/
|
||||
int omsMAXnet::isNotification (char *buffer) {
|
||||
|
||||
const char* functionName="isNotification";
|
||||
char *inString;
|
||||
if ((inString = strstr(buffer, "000 0")) != NULL){
|
||||
if ((inString = strstr(buffer, "000 01")) != NULL){
|
||||
printf("%s:%s:%s: CMD_ERR_FLAG received\n", driverName, functionName, portName);
|
||||
}
|
||||
else {
|
||||
if (motorMAXnetdebug > 1) printf("%s:%s:%s: Interrupt notification: %s\n",
|
||||
driverName, functionName, portName, buffer);
|
||||
epicsEventSignal(pollEventId_);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int omsMAXnetConfig(
|
||||
const char *portName, /* MAXnet Motor Asyn Port name */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
const char *serialPortName,/* MAXnet Serial Asyn Port name */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod, /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
const char *initString) /* Init String sent to card */
|
||||
{
|
||||
// for now priority and stacksize are hardcoded here, should they be configurable in omsMAXnetConfig?
|
||||
int priority = epicsThreadPriorityMedium;
|
||||
int stackSize = epicsThreadGetStackSize(epicsThreadStackMedium);
|
||||
omsMAXnet *pController = new omsMAXnet(portName, numAxes, serialPortName, initString, priority, stackSize);
|
||||
pController->startPoller((double)movingPollPeriod, (double)idlePollPeriod, 10);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
/* Code for iocsh registration */
|
||||
|
||||
/* omsMAXnetConfig */
|
||||
static const iocshArg omsMAXnetConfigArg0 = {"asyn motor port name", iocshArgString};
|
||||
static const iocshArg omsMAXnetConfigArg1 = {"number of axes", iocshArgInt};
|
||||
static const iocshArg omsMAXnetConfigArg2 = {"asyn serial/tcp port name", iocshArgString};
|
||||
static const iocshArg omsMAXnetConfigArg3 = {"moving poll rate", iocshArgInt};
|
||||
static const iocshArg omsMAXnetConfigArg4 = {"idle poll rate", iocshArgInt};
|
||||
static const iocshArg omsMAXnetConfigArg5 = {"initstring", iocshArgString};
|
||||
static const iocshArg * const omsMAXnetConfigArgs[6] = {&omsMAXnetConfigArg0,
|
||||
&omsMAXnetConfigArg1,
|
||||
&omsMAXnetConfigArg2,
|
||||
&omsMAXnetConfigArg3,
|
||||
&omsMAXnetConfigArg4,
|
||||
&omsMAXnetConfigArg5 };
|
||||
static const iocshFuncDef configOmsMAXnet = {"omsMAXnetConfig", 6, omsMAXnetConfigArgs};
|
||||
static void configOmsMAXnetCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXnetConfig(args[0].sval, args[1].ival, args[2].sval, args[3].ival, args[4].ival, args[5].sval);
|
||||
}
|
||||
|
||||
static void OmsMAXnetAsynRegister(void)
|
||||
{
|
||||
iocshRegister(&configOmsMAXnet, configOmsMAXnetCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(OmsMAXnetAsynRegister);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
FILENAME... omsMAXnet.h
|
||||
USAGE... Pro-Dex OMS MAXnet asyn motor controller support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 10/2010
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#ifndef OMSMAXNET_H_
|
||||
#define OMSMAXNET_H_
|
||||
|
||||
#include "omsBaseController.h"
|
||||
|
||||
class omsMAXnet : public omsBaseController {
|
||||
public:
|
||||
omsMAXnet(const char* , int , const char*, const char*, int , int );
|
||||
static void asynCallback(void*, asynUser*, char *, size_t, int);
|
||||
int portConnected;
|
||||
int notificationCounter;
|
||||
epicsMutex* notificationMutex;
|
||||
epicsEventWaitStatus waitInterruptible(double);
|
||||
asynStatus sendReceive(const char *, char *, unsigned int );
|
||||
asynStatus sendOnly(const char *);
|
||||
|
||||
private:
|
||||
int isNotification (char *);
|
||||
asynUser* pasynUserSerial;
|
||||
asynUser* pasynUserSyncIOSerial;
|
||||
asynOctet *pasynOctetSerial;
|
||||
void* octetPvtSerial;
|
||||
char* serialPortName;
|
||||
double timeout;
|
||||
};
|
||||
|
||||
#endif /* OMSMAXNET_H_ */
|
||||
@@ -0,0 +1,649 @@
|
||||
/*
|
||||
FILENAME... omsMAXv.cpp
|
||||
USAGE... Pro-Dex OMS MAXv asyn motor controller support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* based on drvMAXv.cc written by Ron Sluiter
|
||||
*
|
||||
* Created on: 10/2010
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "omsMAXv.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include <epicsInterrupt.h>
|
||||
#include <epicsExit.h>
|
||||
|
||||
static const char *driverName = "omsMAXvDriver";
|
||||
|
||||
#define MIN(a,b) ((a)<(b)? (a): (b))
|
||||
|
||||
#ifdef __GNUG__
|
||||
#ifdef DEBUG
|
||||
#define Debug(l, f, args...) {if (l & motorMAXvdebug) \
|
||||
errlogPrintf(f, ## args);}
|
||||
#else
|
||||
#define Debug(l, f, args...)
|
||||
#endif
|
||||
#else
|
||||
#define Debug
|
||||
#endif
|
||||
volatile int motorMAXvdebug = 0;
|
||||
extern "C" {epicsExportAddress(int, motorMAXvdebug);}
|
||||
|
||||
char* omsMAXv::baseAddress = 0x0;
|
||||
int omsMAXv::numCards = 0;
|
||||
epicsUInt32 omsMAXv::baseInterruptVector = OMS_INT_VECTOR;
|
||||
epicsUInt8 omsMAXv::interruptLevel = OMS_INT_LEVEL;
|
||||
epicsAddressType omsMAXv::addrType = atVMEA16;
|
||||
|
||||
void omsMAXv::InterruptHandler( void * param )
|
||||
{
|
||||
omsMAXv* pController = (omsMAXv*) param;
|
||||
volatile struct MAXv_motor *pmotor = (MAXv_motor*) pController->getCardAddress();;
|
||||
STATUS1 status1_flag;
|
||||
static char errmsg[65];
|
||||
|
||||
status1_flag.All = pmotor->status1_flag.All;
|
||||
|
||||
/* Motion done handling */
|
||||
if (status1_flag.Bits.done != 0) epicsEventSignal(pController->pollEventId_);
|
||||
|
||||
if (status1_flag.Bits.cmndError)
|
||||
{
|
||||
strcpy(errmsg, "\nomsMAXv::InterruptHandler: command error - Port: ");
|
||||
strncat(errmsg, pController->getPortName(), sizeof(errmsg)-strlen(errmsg)-2);
|
||||
strcat(errmsg,"\n");
|
||||
epicsInterruptContextMessage(errmsg);
|
||||
}
|
||||
|
||||
// not clearing this may corrupt the next read/write operation
|
||||
if (status1_flag.Bits.text_response != 0) status1_flag.Bits.text_response = 0;
|
||||
|
||||
pmotor->status1_flag.All = status1_flag.All; /* Release IRQ's. */
|
||||
|
||||
/* do a dummy read to ensure that all previous writes, which may
|
||||
* have been queued in the VME bridge chip get processed
|
||||
*/
|
||||
status1_flag.All = pmotor->status1_flag.All;
|
||||
|
||||
}
|
||||
omsMAXv::omsMAXv(const char* portName, int numAxes, int cardNo, const char* initString,
|
||||
int priority, int stackSize, int addParams)
|
||||
: omsBaseController(portName, numAxes, priority, stackSize, addParams)
|
||||
{
|
||||
int vector = 0;
|
||||
|
||||
if (baseInterruptVector != 0)
|
||||
vector = baseInterruptVector + cardNo;
|
||||
|
||||
initialize(portName, numAxes, cardNo, initString, priority, stackSize, 1, vector, interruptLevel, addrType, addParams);
|
||||
}
|
||||
omsMAXv::omsMAXv(const char* portName, int numAxes, int slotNo, const char* initString, int priority,
|
||||
int stackSize, unsigned int vmeAddr, int vector, int intlevel, const char* addressType, int addParams)
|
||||
: omsBaseController(portName, numAxes, priority, stackSize, addParams)
|
||||
{
|
||||
const char* functionName = "omsMAXv";
|
||||
epicsAddressType vmeAddrType = atVMEA16;
|
||||
|
||||
if (vmeAddr < 0) {
|
||||
errlogPrintf("%s: invalid VME address: 0\n", functionName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp(addressType, "A16",3)){
|
||||
vmeAddrType = atVMEA16;
|
||||
if (vmeAddr & 0xFFFF0FFF) {
|
||||
errlogPrintf("%s: invalid %s address: 0x%X.\n", functionName, addressType, vmeAddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(addressType, "A24",3)){
|
||||
vmeAddrType = atVMEA24;
|
||||
if (vmeAddr & 0xFF00FFFF) {
|
||||
errlogPrintf("%s: invalid %s address: 0x%X.\n", functionName, addressType, vmeAddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(addressType, "A32",3)){
|
||||
vmeAddrType = atVMEA32;
|
||||
if (vmeAddr & 0x00FFFFFF) {
|
||||
errlogPrintf("%s: invalid %s address: 0x%X.\n", functionName, addressType, vmeAddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (strncmp(addressType, "CSR",3)){
|
||||
errlogPrintf("%s: VME CSR not supported\n", functionName);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
errlogPrintf("%s: invalid address type, Please specify one of A16,A24,A32\n", functionName);
|
||||
}
|
||||
if (intlevel < 1 || intlevel > 6) {
|
||||
errlogPrintf("%s: invalid interrupt level %d, Please specify a value between 1 and 6\n", functionName, intlevel);
|
||||
return;
|
||||
}
|
||||
initialize(portName, numAxes, 0, initString, priority, stackSize, vmeAddr, vector, intlevel, vmeAddrType, addParams);
|
||||
}
|
||||
|
||||
void omsMAXv::initialize(const char* portName, int numAxes, int cardNo, const char* initString, int prio,
|
||||
int stackSz, unsigned int vmeAddr, int intrVector, int level, epicsAddressType vmeAddrType, int paramCount)
|
||||
{
|
||||
|
||||
const char* functionName = "initialize";
|
||||
long status;
|
||||
void* probeAddr;
|
||||
|
||||
Debug(32, "omsMAXv::initialize: start initialize\n" );
|
||||
|
||||
controllerType = epicsStrDup("MAXv");
|
||||
|
||||
// TODO check if cardNo has already been used
|
||||
this->cardNo = cardNo;
|
||||
if(cardNo < 0 || cardNo >= MAXv_NUM_CARDS){
|
||||
printf("invalid cardNo: %d", cardNo);
|
||||
return;
|
||||
}
|
||||
|
||||
epicsUInt8 *startAddr;
|
||||
epicsUInt8 *endAddr;
|
||||
epicsUInt32 boardAddrSize = 0;
|
||||
|
||||
if (vmeAddrType == atVMEA16)
|
||||
boardAddrSize = 0x1000;
|
||||
else if (vmeAddrType == atVMEA24)
|
||||
boardAddrSize = 0x10000;
|
||||
else if (vmeAddrType == atVMEA32)
|
||||
boardAddrSize = 0x1000000;
|
||||
|
||||
// if vmeAddr == 1 Setup/Config is used and not Config2
|
||||
if (vmeAddr == 1)
|
||||
probeAddr = baseAddress + (cardNo * boardAddrSize);
|
||||
else
|
||||
probeAddr = (void*) vmeAddr;
|
||||
|
||||
startAddr = (epicsUInt8 *) probeAddr;
|
||||
endAddr = startAddr + boardAddrSize;
|
||||
|
||||
Debug(64, "motor_init: devNoResponseProbe() on addr %p\n", probeAddr);
|
||||
|
||||
/* Scan memory space to assure card id */
|
||||
while (startAddr < endAddr) {
|
||||
status = devNoResponseProbe(vmeAddrType, (size_t) startAddr, 2);
|
||||
if (status != S_dev_addressOverlap) {
|
||||
errlogPrintf("%s:%s:%s: Card NOT found in specified address range! \n",
|
||||
driverName, functionName, portName);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
startAddr += (boardAddrSize / 10);
|
||||
}
|
||||
|
||||
status = devRegisterAddress(controllerType, vmeAddrType,
|
||||
(size_t) probeAddr, boardAddrSize,
|
||||
(volatile void **) &pmotor);
|
||||
Debug(64, "motor_init: devRegisterAddress() status = %d\n", (int) status);
|
||||
|
||||
if (status) {
|
||||
errlogPrintf("%s:%s:%s: Can't register address 0x%lx \n",
|
||||
driverName, functionName, portName, (long unsigned int) probeAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(64, "motor_init: pmotor = %p\n", pmotor);
|
||||
|
||||
int loopCount=15;
|
||||
while (loopCount && (pmotor->firmware_status.Bits.initializing == 1)){
|
||||
Debug(1, "MAXv port %s still initializing; status = 0x%x\n",
|
||||
portName, (unsigned int) pmotor->firmware_status.All);
|
||||
epicsThreadSleep(0.2);
|
||||
--loopCount;
|
||||
}
|
||||
|
||||
Debug(64, "motor_init: check if card is ready\n");
|
||||
|
||||
if (pmotor->firmware_status.Bits.running == 0)
|
||||
errlogPrintf("MAXv port %s is NOT running; status = 0x%x\n",
|
||||
portName, (unsigned int) pmotor->firmware_status.All);
|
||||
|
||||
Debug(64, "motor_init: init card\n");
|
||||
|
||||
FIRMWARE_STATUS fwStatus;
|
||||
fwStatus.All = pmotor->firmware_status.All;
|
||||
Debug(64, "motor_init: firmware status register: 0x%x\n", fwStatus.All);
|
||||
|
||||
pmotor->IACK_vector = intrVector;
|
||||
|
||||
pmotor->status1_flag.All = 0xFFFFFFFF;
|
||||
pmotor->status2_flag = 0xFFFFFFFF;
|
||||
/* Disable all interrupts */
|
||||
pmotor->status1_irq_enable.All = 0;
|
||||
pmotor->status2_irq_enable = 0;
|
||||
|
||||
Debug(64, "motor_init: clear all interrupt\n");
|
||||
//sendOnly("IC");
|
||||
|
||||
Debug(64, "motor_init: firmware version\n");
|
||||
|
||||
/* get FirmwareVersion */
|
||||
if(getFirmwareVersion() != asynSuccess) {
|
||||
errlogPrintf("%s:%s:%s: unable to talk to controller card %d\n",
|
||||
driverName, functionName, portName, cardNo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fwMinor < 30 ){
|
||||
errlogPrintf("%s:%s:%s: This Controllers Firmware Version %d.%d is not supported, version 1.30 or higher is mandatory\n",
|
||||
driverName, functionName, portName, fwMajor, fwMinor);
|
||||
}
|
||||
|
||||
Debug(64, "motor_init: send init string\n");
|
||||
|
||||
if( Init(initString, 1) != asynSuccess) {
|
||||
errlogPrintf("%s:%s:%s: unable to send initstring to controller card %d\n",
|
||||
driverName, functionName, portName, cardNo);
|
||||
return;
|
||||
}
|
||||
|
||||
useWatchdog = true;
|
||||
|
||||
if (watchdogOK()) {
|
||||
Debug(64, "motor_init: enable interrupts ( vector=%d, level=%d) \n", intrVector, level);
|
||||
/* Enable interrupt-when-done if selected */
|
||||
if (intrVector) motorIsrSetup((unsigned int)intrVector, level);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
if (epicsAtExit(&omsMAXv::resetOnExit, this))
|
||||
errlogPrintf("%s:%s:%s: card %d, unable to register exit function\n",
|
||||
driverName, functionName, portName, cardNo);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void omsMAXv::resetIntr()
|
||||
{
|
||||
enabled=false;
|
||||
pmotor->status1_irq_enable.All = 0;
|
||||
}
|
||||
|
||||
asynStatus omsMAXv::sendOnly(const char *outputBuff)
|
||||
{
|
||||
STATUS1 flag1;
|
||||
const char* functionName = "sendOnly";
|
||||
int len = strlen(outputBuff);
|
||||
epicsUInt16 getIndex, putIndex;
|
||||
|
||||
if (!enabled) return asynError;
|
||||
Debug(16, "omsMAXv::send: sending: %s \n", outputBuff);
|
||||
|
||||
if (len > (BUFFER_SIZE-1))
|
||||
{
|
||||
errlogPrintf("%s:%s:%s: message too long: %d character\n",
|
||||
driverName, functionName, portName, len);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/* see if junk at input port - should not be any data available */
|
||||
if ((epicsUInt16) pmotor->inGetIndex != (epicsUInt16) pmotor->inPutIndex)
|
||||
{
|
||||
// flush cards response Buffer
|
||||
#ifdef DEBUG
|
||||
int deltaIndex = ((epicsUInt16)pmotor->inPutIndex) - ((epicsUInt16)pmotor->inGetIndex);
|
||||
#endif
|
||||
Debug(32, "%s:%s:%s: flushing %d characters\n",
|
||||
driverName, functionName, portName, (((deltaIndex < 0) ? BUFFER_SIZE +
|
||||
deltaIndex : deltaIndex)));
|
||||
putIndex = (epicsUInt16) pmotor->inPutIndex;
|
||||
pmotor->inGetIndex = putIndex;
|
||||
pmotor->status1_flag.Bits.text_response = 0;
|
||||
flag1.All = pmotor->status1_flag.All;
|
||||
pmotor->status1_flag.All = flag1.All;
|
||||
pmotor->msg_semaphore=0;
|
||||
|
||||
}
|
||||
|
||||
putIndex = (epicsUInt16) pmotor->outPutIndex;
|
||||
getIndex = (epicsUInt16) pmotor->outGetIndex;
|
||||
|
||||
for (int i = 0; (i < len); i++) {
|
||||
pmotor->outBuffer[putIndex++]= outputBuff[i];
|
||||
if (putIndex >= BUFFER_SIZE) putIndex = 0;
|
||||
}
|
||||
|
||||
pmotor->outPutIndex = putIndex; /* Message Sent */
|
||||
|
||||
int count=0, prevdeltaIndex =0;
|
||||
int deltaIndex = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
|
||||
int index = 0;
|
||||
while (deltaIndex != 0)
|
||||
{
|
||||
deltaIndex = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
|
||||
// do busy-waiting but not more than 100 times
|
||||
while ((index < 100) && (deltaIndex != 0)){
|
||||
deltaIndex = ((epicsUInt16)pmotor->outPutIndex) - ((epicsUInt16)pmotor->outGetIndex);
|
||||
++index;
|
||||
}
|
||||
// epicsThreadSleepQuantum => 0.02s for RTEMS
|
||||
if ((index >= 100) && (deltaIndex != 0)) epicsThreadSleep(epicsThreadSleepQuantum());
|
||||
if (deltaIndex == prevdeltaIndex)
|
||||
++count;
|
||||
else
|
||||
count =0;
|
||||
if (count > 10) break;
|
||||
prevdeltaIndex = deltaIndex;
|
||||
};
|
||||
Debug(32, "%s:%s:%s: Waited %d loops\n", driverName, functionName, portName, index);
|
||||
|
||||
if (deltaIndex != 0) {
|
||||
Debug(1, "%s:%s:%s: Timeout\n", driverName, functionName, portName);
|
||||
return asynTimeout;
|
||||
}
|
||||
|
||||
Debug(64, "omsMAXv::send: done\n");
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
/**
|
||||
* read just one line of input
|
||||
*/
|
||||
asynStatus omsMAXv::sendReceive(const char *outputBuff, char *inputBuff, unsigned int inputSize)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
const char* functionName = "sendReceive";
|
||||
#endif
|
||||
|
||||
STATUS1 flag1;
|
||||
epicsUInt16 getIndex, putIndex;
|
||||
size_t bufsize;
|
||||
size_t usedSpace = 0;
|
||||
char *start, *end;
|
||||
int itera;
|
||||
asynStatus status;
|
||||
|
||||
if (!enabled) return asynError;
|
||||
|
||||
status = sendOnly(outputBuff);
|
||||
if (status != asynSuccess) return status;
|
||||
|
||||
if (inputSize <= 0) return status;
|
||||
|
||||
*inputBuff = '\0';
|
||||
|
||||
Debug(64, "omsMAXv::sendReceive: receiving\n");
|
||||
itera = 0;
|
||||
double time = 0.0;
|
||||
double timeout = epicsThreadSleepQuantum() + 0.001;
|
||||
while ((pmotor->status1_flag.Bits.text_response == 0) && (time < timeout)){
|
||||
Debug(32, "%s:%s:%s: Waiting for reponse, itera:%d\n",
|
||||
driverName, functionName, portName, itera);
|
||||
// busy-waiting but not more than 2000 times
|
||||
if (itera > 2000){
|
||||
time += epicsThreadSleepQuantum();
|
||||
epicsThreadSleep(epicsThreadSleepQuantum());
|
||||
}
|
||||
itera++;
|
||||
}
|
||||
|
||||
if (pmotor->status1_flag.Bits.text_response == 0)
|
||||
{
|
||||
Debug(1, "Timeout occurred in recv_mess, %s\n", outputBuff);
|
||||
return asynTimeout;
|
||||
}
|
||||
|
||||
getIndex = (epicsUInt16) pmotor->inGetIndex;
|
||||
putIndex = (epicsUInt16) pmotor->inPutIndex;
|
||||
bufsize = putIndex - getIndex;
|
||||
start = (char *) &pmotor->inBuffer[getIndex];
|
||||
end = (char *) &pmotor->inBuffer[putIndex];
|
||||
|
||||
if (start < end) { /* Test for message wraparound in buffer. */
|
||||
usedSpace = MIN(bufsize, inputSize);
|
||||
memcpy(inputBuff, start, usedSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufsize += BUFFER_SIZE;
|
||||
size_t firstPart = ((char *) &pmotor->inBuffer[BUFFER_SIZE]) - start;
|
||||
|
||||
usedSpace = MIN(firstPart, inputSize);
|
||||
memcpy(inputBuff, start, usedSpace);
|
||||
size_t copySize = MIN(bufsize - firstPart, inputSize - usedSpace);
|
||||
memcpy((inputBuff + usedSpace), (const char *) &pmotor->inBuffer[0], copySize);
|
||||
usedSpace += copySize;
|
||||
}
|
||||
|
||||
inputBuff[usedSpace - 1]= '\0';
|
||||
|
||||
getIndex += bufsize;
|
||||
if (getIndex >= BUFFER_SIZE)
|
||||
getIndex -= BUFFER_SIZE;
|
||||
|
||||
while (getIndex != (epicsUInt16)pmotor->inPutIndex)
|
||||
{
|
||||
Debug(2, "readbuf(): flushed - %d\n", pmotor->inBuffer[getIndex]);
|
||||
if (++getIndex > BUFFER_SIZE)
|
||||
getIndex = 0;
|
||||
}
|
||||
pmotor->status1_flag.Bits.text_response = 0;
|
||||
|
||||
pmotor->inGetIndex = (epicsUInt32) getIndex;
|
||||
flag1.All = pmotor->status1_flag.All;
|
||||
pmotor->status1_flag.All = flag1.All;
|
||||
pmotor->msg_semaphore=0;
|
||||
|
||||
Debug(16, "omsMAXv::sendReceive: received %s\n", inputBuff);
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
|
||||
void omsMAXv::motorIsrSetup(volatile unsigned int vector, volatile epicsUInt8 level)
|
||||
{
|
||||
const char* functionName = "motorIsrSetup";
|
||||
STATUS1 status1_irq;
|
||||
long status;
|
||||
|
||||
Debug(64, "omsMAXv::isrSetup: start\n");
|
||||
|
||||
status = pdevLibVirtualOS->pDevConnectInterruptVME( vector, &omsMAXv::InterruptHandler, this);
|
||||
|
||||
if (status) {
|
||||
errlogPrintf("%s:%s:%s: Can't connect to interrupt vector %d\n",
|
||||
driverName, functionName, portName, vector);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(64, "omsMAXv::isrSetup: set level\n");
|
||||
status = devEnableInterruptLevel(intVME, level);
|
||||
if (status) {
|
||||
errlogPrintf("%s:%s:%s: Can't enable interrupt level %d\n",
|
||||
driverName, functionName, portName, level);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setup card for interrupt-on-done */
|
||||
status1_irq.All = 0;
|
||||
status1_irq.Bits.done = 0xFF;
|
||||
status1_irq.Bits.cmndError = 1;
|
||||
|
||||
pmotor->status1_irq_enable.All = status1_irq.All; /* Enable interrupts. */
|
||||
pmotor->status2_irq_enable = 0x0;
|
||||
|
||||
Debug(64, "omsMAXv::isrSetup: done\n");
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" int omsMAXvSetup(
|
||||
int num_cards, /* maximum number of cards in rack */
|
||||
int addr_type, /* VME address type; 16 -> A16, 24 -> A24 or 32 -> A32. */
|
||||
unsigned int addrs, /* Base Address. */
|
||||
unsigned int vector, /* noninterrupting(0), valid vectors(64-255) */
|
||||
int int_level) /* interrupt level (1-6) */
|
||||
|
||||
{
|
||||
const char* functionName = "omsMAXvSetup";
|
||||
if (num_cards < 1 || num_cards > MAXv_NUM_CARDS)
|
||||
{
|
||||
errlogPrintf("\n%s: number of cards specified = %d but must be 1 <= number <= %d\n",
|
||||
functionName, num_cards, MAXv_NUM_CARDS);
|
||||
epicsThreadSleep(5.0);
|
||||
return 1;
|
||||
}
|
||||
omsMAXv::numCards = num_cards;
|
||||
omsMAXv::baseAddress = (char *) addrs;
|
||||
|
||||
switch (addr_type)
|
||||
{
|
||||
case 16:
|
||||
omsMAXv::addrType = atVMEA16;
|
||||
if ((epicsUInt32) addrs & 0xFFFF0FFF) {
|
||||
errlogPrintf("%s: invalid A%d address: 0x%X.\n", functionName, addr_type, (epicsUInt32) addrs);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
omsMAXv::addrType = atVMEA24;
|
||||
if ((epicsUInt32) addrs & 0xFF00FFFF) {
|
||||
errlogPrintf("%s: invalid A%d address: 0x%X.\n", functionName, addr_type, (epicsUInt32) addrs);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
omsMAXv::addrType = atVMEA32;
|
||||
if ((epicsUInt32) addrs & 0x00FFFFFF) {
|
||||
errlogPrintf("%s: invalid A%d address: 0x%X.\n", functionName, addr_type, (epicsUInt32) addrs);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errlogPrintf("%s: invalid address type, Please specify one of 16/24/32 for VME A16/A24/A32\n", functionName);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((vector != 0) && (vector < 64 || vector > 255)) {
|
||||
errlogPrintf("%s: invalid address type, Please specify a value between 64 and 255\n", functionName);
|
||||
epicsThreadSleep(5.0);
|
||||
return 1;
|
||||
}
|
||||
omsMAXv::baseInterruptVector = vector;
|
||||
|
||||
if (int_level < 1 || int_level > 6) {
|
||||
errlogPrintf("%s: invalid interrupt level, Please specify a value between 1 and 6\n", functionName);
|
||||
epicsThreadSleep(5.0);
|
||||
return 1;
|
||||
}
|
||||
omsMAXv::interruptLevel = int_level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int omsMAXvConfig(
|
||||
int cardNo, /* card no, starts with 0*/
|
||||
const char *portName, /* MAXv Motor Asyn Port name */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod, /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
const char *initString) /* Init String sent to card */
|
||||
{
|
||||
omsMAXv *pController = new omsMAXv(portName, numAxes, cardNo, initString, 0, 0, 0);
|
||||
pController->startPoller((double)movingPollPeriod, (double)idlePollPeriod, 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* extended MAXv configuration, which may be used instead of omsMAXvConfig,
|
||||
* if more details need to be specified.
|
||||
* omsMAXvConfig2 does not need and ignores omsMAXvSetup
|
||||
*/
|
||||
extern "C" int omsMAXvConfig2(
|
||||
int slotNo, /* VME slot no of MAXv card*/
|
||||
const char* addr_type, /* VME address type; "A16", "A24" or "A32" */
|
||||
unsigned int addrs, /* Board Address */
|
||||
unsigned int vector, /* Interrupt Vector: noninterrupting(0), (64-255) */
|
||||
int int_level, /* interrupt level (1-6) */
|
||||
const char *portName, /* MAXv Motor Asyn Port name */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int priority, /* priority of PollerTask (0 => epicsThreadPriorityMedium)*/
|
||||
int stackSize, /* stackSize of PollerTask (0 => epicsThreadStackMedium) */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod, /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
const char *initString) /* Init String sent to card */
|
||||
{
|
||||
omsMAXv *pController = new omsMAXv(portName, numAxes, slotNo, initString, priority,
|
||||
stackSize, addrs, vector, int_level, addr_type, 0);
|
||||
pController->startPoller((double)movingPollPeriod, (double)idlePollPeriod, 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Code for iocsh registration */
|
||||
/* omsMAXvSetup */
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"VME address type", iocshArgInt};
|
||||
static const iocshArg setupArg2 = {"Base Address on 4K (0x1000) boundary", iocshArgInt};
|
||||
static const iocshArg setupArg3 = {"noninterrupting(0), valid vectors(64-255)", iocshArgInt};
|
||||
static const iocshArg setupArg4 = {"interrupt level (1-6)", iocshArgInt};
|
||||
static const iocshArg * const OmsSetupArgs[5] = { &setupArg0, &setupArg1, &setupArg2,
|
||||
&setupArg3, &setupArg4};
|
||||
static const iocshFuncDef setupMAXv = {"omsMAXvSetup", 5, OmsSetupArgs};
|
||||
static void setupMAXvCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXvSetup(args[0].ival, args[1].ival, args[2].ival, args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
/* omsMAXvConfig */
|
||||
static const iocshArg configArg0 = {"number of card", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn motor port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"number of axes", iocshArgInt};
|
||||
static const iocshArg configArg3 = {"moving poll rate", iocshArgInt};
|
||||
static const iocshArg configArg4 = {"idle poll rate", iocshArgInt};
|
||||
static const iocshArg configArg5 = {"initstring", iocshArgString};
|
||||
static const iocshArg * const configArgs[6] = {&configArg0, &configArg1, &configArg2,
|
||||
&configArg3, &configArg4, &configArg5 };
|
||||
static const iocshFuncDef configMAXv = {"omsMAXvConfig", 6, configArgs};
|
||||
static void configMAXvCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXvConfig(args[0].ival, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].sval);
|
||||
}
|
||||
|
||||
/* omsMAXvConfig2 */
|
||||
static const iocshArg config2Arg0 = {"Slot number", iocshArgInt};
|
||||
static const iocshArg config2Arg1 = {"Address type: A16,A24,A32", iocshArgString};
|
||||
static const iocshArg config2Arg2 = {"Board Address on 4K (0x1000) boundary", iocshArgInt};
|
||||
static const iocshArg config2Arg3 = {"Interrupt Vector: noninterrupting(0), (64-255)", iocshArgInt};
|
||||
static const iocshArg config2Arg4 = {"Interrupt level (1-6)", iocshArgInt};
|
||||
static const iocshArg config2Arg5 = {"Asyn motor port name", iocshArgString};
|
||||
static const iocshArg config2Arg6 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg config2Arg7 = {"Task priority: 0 => medium", iocshArgInt};
|
||||
static const iocshArg config2Arg8 = {"Stack size: 0 => medium", iocshArgInt};
|
||||
static const iocshArg config2Arg9 = {"Moving poll rate", iocshArgInt};
|
||||
static const iocshArg config2Arg10 = {"Idle poll rate", iocshArgInt};
|
||||
static const iocshArg config2Arg11 = {"Initstring", iocshArgString};
|
||||
static const iocshArg * const config2Args[12] = {&config2Arg0, &config2Arg1, &config2Arg2, &config2Arg3, &config2Arg4,
|
||||
&config2Arg5, &config2Arg6, &config2Arg7, &config2Arg8, &config2Arg9, &config2Arg10, &config2Arg11};
|
||||
static const iocshFuncDef config2MAXv = {"omsMAXvConfig2", 12, config2Args};
|
||||
static void config2MAXvCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXvConfig2(args[0].ival, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].sval,
|
||||
args[6].ival, args[7].ival, args[8].ival, args[9].ival, args[10].ival, args[11].sval);
|
||||
}
|
||||
|
||||
static void OmsMAXvAsynRegister(void)
|
||||
{
|
||||
iocshRegister(&setupMAXv, setupMAXvCallFunc);
|
||||
iocshRegister(&configMAXv, configMAXvCallFunc);
|
||||
iocshRegister(&config2MAXv, config2MAXvCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(OmsMAXvAsynRegister);
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
FILENAME... omsMAXv.h
|
||||
USAGE... Pro-Dex OMS MAXv asyn motor controller support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 10/2010
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#ifndef OMSMAXV_H_
|
||||
#define OMSMAXV_H_
|
||||
|
||||
#include "omsBaseController.h"
|
||||
#include <devLib.h>
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
#define MAXv_NUM_CARDS 15 /* maximum number of cards */
|
||||
#define OMS_INT_VECTOR 180 /* default interrupt vector (64-255) */
|
||||
#define OMS_INT_LEVEL 5 /* default interrupt level (1-6) */
|
||||
|
||||
/* Limit Switch Status - Offset = 0x40 */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt32 All;
|
||||
struct
|
||||
{
|
||||
unsigned int s_minus :1;
|
||||
unsigned int r_minus :1;
|
||||
unsigned int v_minus :1;
|
||||
unsigned int u_minus :1;
|
||||
unsigned int t_minus :1;
|
||||
unsigned int z_minus :1;
|
||||
unsigned int y_minus :1;
|
||||
unsigned int x_minus :1;
|
||||
unsigned int s_plus :1;
|
||||
unsigned int r_plus :1;
|
||||
unsigned int v_plus :1;
|
||||
unsigned int u_plus :1;
|
||||
unsigned int t_plus :1;
|
||||
unsigned int z_plus :1;
|
||||
unsigned int y_plus :1;
|
||||
unsigned int x_plus :1;
|
||||
} Bits;
|
||||
} LIMIT_SWITCH;
|
||||
|
||||
/* Home Switch Status - Offset = 0x44 */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt32 All;
|
||||
struct
|
||||
{
|
||||
unsigned int home_s :1; /* status of S axis */
|
||||
unsigned int home_r :1; /* status of R axis */
|
||||
unsigned int home_v :1; /* status of V axis */
|
||||
unsigned int home_u :1; /* status of U axis */
|
||||
unsigned int home_t :1; /* status of T axis */
|
||||
unsigned int home_z :1; /* status of Z axis */
|
||||
unsigned int home_y :1; /* status of Y axis */
|
||||
unsigned int home_x :1; /* status of X axis */
|
||||
} Bits;
|
||||
} HOME_SWITCH;
|
||||
|
||||
/* Firmware status - Offset = 0x48 */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt32 All;
|
||||
struct
|
||||
{
|
||||
unsigned int na19 :13; /* N/A bits 19-31 */
|
||||
unsigned int factoryparm_loaded :1;
|
||||
unsigned int altparm_loaded :1;
|
||||
unsigned int defaultparm_loaded :1;
|
||||
unsigned int altprgm_err :1;
|
||||
unsigned int altparm_chksum_err :1;
|
||||
unsigned int prgm_err :1;
|
||||
unsigned int parm_chksum_err :1;
|
||||
unsigned int na10 :2; /* N/A bits 10-11 */
|
||||
unsigned int program_error :1;
|
||||
unsigned int flash_chksum_err :1;
|
||||
unsigned int na3 :5; /* N/A bits 3-7 */
|
||||
unsigned int running :1;
|
||||
unsigned int initializing :1;
|
||||
unsigned int not_downloaded :1;
|
||||
} Bits;
|
||||
} FIRMWARE_STATUS;
|
||||
|
||||
|
||||
/* Status#1 - Offset = 0xFC0 */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt32 All;
|
||||
struct
|
||||
{
|
||||
unsigned int na3 :5; /* N/A bits 27-31. */
|
||||
unsigned int data_avail :1;
|
||||
unsigned int text_response :1;
|
||||
unsigned int cmndError :1; /* Command error dectect */
|
||||
unsigned int slip :8;
|
||||
unsigned int overtravel :8;
|
||||
unsigned int done :8;
|
||||
} Bits;
|
||||
} STATUS1;
|
||||
|
||||
/* OMS MAXv VME dual port memory map */
|
||||
struct MAXv_motor
|
||||
{
|
||||
epicsUInt32 cmndPos[8];
|
||||
epicsUInt32 encPos[8];
|
||||
LIMIT_SWITCH limit_switch;
|
||||
HOME_SWITCH home_switch;
|
||||
FIRMWARE_STATUS firmware_status;
|
||||
epicsUInt32 direct_cmnd_mbox;
|
||||
epicsUInt32 position_req_mbox;
|
||||
epicsUInt32 coherent_cmndPos[8];
|
||||
epicsUInt32 coherent_encPos[8];
|
||||
epicsUInt32 msg_semaphore;
|
||||
epicsUInt32 queue_flush_mbox;
|
||||
epicsUInt32 gpio;
|
||||
epicsUInt32 naA0[19]; /* N/A byte offset 0xA0 - 0xEB. */
|
||||
epicsUInt32 flash_pgm_ptr;
|
||||
epicsUInt32 outPutIndex;
|
||||
epicsUInt32 outGetIndex;
|
||||
epicsUInt32 inPutIndex;
|
||||
epicsUInt32 inGetIndex;
|
||||
epicsUInt8 outBuffer[BUFFER_SIZE];
|
||||
epicsUInt8 inBuffer[BUFFER_SIZE];
|
||||
epicsUInt8 utility[BUFFER_SIZE];
|
||||
epicsUInt32 naD00[176]; /* N/A byte offset 0xD00 - 0xFBF. */
|
||||
STATUS1 status1_flag;
|
||||
STATUS1 status1_irq_enable;
|
||||
epicsUInt32 status2_flag;
|
||||
epicsUInt32 status2_irq_enable;
|
||||
epicsUInt32 IACK_vector;
|
||||
epicsUInt32 config_switch;
|
||||
epicsUInt32 AM_register;
|
||||
epicsUInt32 naFDC[7];
|
||||
epicsUInt32 FIFO_status_cntrl;
|
||||
epicsUInt32 FIFO_date;
|
||||
|
||||
};
|
||||
|
||||
class omsMAXv : public omsBaseController {
|
||||
public:
|
||||
omsMAXv(const char*, int, int, const char*, int, int, unsigned int, int, int, const char*, int);
|
||||
omsMAXv(const char*, int, int, const char*, int, int, int );
|
||||
asynStatus sendReceive(const char *, char *, unsigned int );
|
||||
asynStatus sendOnly(const char *);
|
||||
static char* baseAddress;
|
||||
static epicsAddressType addrType;
|
||||
static int numCards;
|
||||
static epicsUInt32 baseInterruptVector;
|
||||
static epicsUInt8 interruptLevel;
|
||||
static void InterruptHandler( void * param );
|
||||
void* getCardAddress(){return (void*) pmotor;};
|
||||
static void resetOnExit(void* param){((omsMAXv*)param)->resetIntr();};
|
||||
void resetIntr();
|
||||
int getCardNo(){return cardNo;};
|
||||
|
||||
protected:
|
||||
virtual void initialize(const char*, int, int, const char*, int, int, unsigned int, int, int, epicsAddressType, int );
|
||||
|
||||
private:
|
||||
void motorIsrSetup(volatile unsigned int, volatile epicsUInt8);
|
||||
int cardNo;
|
||||
volatile struct MAXv_motor *pmotor;
|
||||
char readBuffer[BUFFER_SIZE];
|
||||
};
|
||||
|
||||
#endif /* OMSMAXV_H_ */
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
FILENAME... omsMAXvEncFunc.cpp
|
||||
USAGE... Pro-Dex OMS MAXv encoder asyn motor support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 10/2011
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "omsMAXvEncFunc.h"
|
||||
|
||||
static const char *driverName = "omsMAXvEncFuncDriver";
|
||||
|
||||
#ifdef __GNUG__
|
||||
#ifdef DEBUG
|
||||
#define Debug(l, f, args...) {if (l <= motorMAXvEncFuncdebug) \
|
||||
errlogPrintf(f, ## args);}
|
||||
#else
|
||||
#define Debug(l, f, args...)
|
||||
#endif
|
||||
#else
|
||||
#define Debug
|
||||
#endif
|
||||
volatile int motorMAXvEncFuncdebug = 0;
|
||||
extern "C" {epicsExportAddress(int, motorMAXvEncFuncdebug);}
|
||||
|
||||
/* define additional Parameters to use special encoder functions and auxiliary encoders of the MAXv */
|
||||
#define NUM_ADDITIONALPARAMS 18
|
||||
#define motorEncoderFunctionString "ENCODER_FUNCTION"
|
||||
#define motorAuxEncoderPositionString "AUX_ENC_POSITION"
|
||||
#define motorEncoderRawPosString "RAW_ENC_POSITION"
|
||||
|
||||
omsMAXvEncFunc::omsMAXvEncFunc(const char* portName, int numAxes, int cardNo,
|
||||
const char* initString, int priority, int stackSize)
|
||||
: omsMAXv(portName, numAxes, cardNo, initString, priority, stackSize, NUM_ADDITIONALPARAMS)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
omsMAXvEncFunc::omsMAXvEncFunc(const char* portName, int numAxes, int cardNo, const char* initString, int priority,
|
||||
int stackSize, unsigned int vmeAddr, int vector, int intlevel, const char* addressType)
|
||||
: omsMAXv(portName, numAxes, cardNo, initString, priority, stackSize, vmeAddr,
|
||||
vector, intlevel, addressType, NUM_ADDITIONALPARAMS)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
void omsMAXvEncFunc::initialize()
|
||||
{
|
||||
const char* functionName = "initialize";
|
||||
|
||||
Debug(5, "omsMAXvEncFunc::initialize: start initialize\n" );
|
||||
|
||||
int encIndex = numAxes;
|
||||
if (encIndex > MAXENCFUNC) encIndex = MAXENCFUNC;
|
||||
|
||||
/* auxiliary encoders */
|
||||
for (int i=0; i < encIndex; ++i){
|
||||
if (createParam(i, motorEncoderFunctionString, asynParamInt32, &encFuncIndex[i]) != asynSuccess)
|
||||
errlogPrintf("%s:%s:%s: unable to create param motorEncoderFunctionString, index %d\n",
|
||||
driverName, functionName, portName, i);
|
||||
if (createParam(i, motorEncoderRawPosString, asynParamFloat64, &encRawPosIndex[i]) != asynSuccess)
|
||||
errlogPrintf("%s:%s:%s: unable to create param motorEncoderRawPosString, index %d\n",
|
||||
driverName, functionName, portName, i);
|
||||
}
|
||||
createParam(0, motorAuxEncoderPositionString, asynParamFloat64, &encPosIndex[0]);
|
||||
createParam(1, motorAuxEncoderPositionString, asynParamFloat64, &encPosIndex[1]);
|
||||
Debug(3, "omsMAXvEncFunc::initialize: auxiliary encoder 0 position index %d\n", encPosIndex[0] );
|
||||
Debug(3, "omsMAXvEncFunc::initialize: auxiliary encoder 1 position index %d\n", encPosIndex[1] );
|
||||
for (int i=0; i < encIndex; ++i) Debug(3, "omsMAXvEncFunc::initialize: encFuncIndex %d => %d\n", i, encFuncIndex[i] );
|
||||
lock();
|
||||
for (int i=0; i < encIndex; ++i){
|
||||
setIntegerParam(i, encFuncIndex[i], 0);
|
||||
setDoubleParam(i, encRawPosIndex[i], 0.0);
|
||||
}
|
||||
setDoubleParam(0, encPosIndex[0], 0.0);
|
||||
setDoubleParam(1, encPosIndex[1], 0.0);
|
||||
for (int i=0; i < encIndex; ++i) {
|
||||
callParamCallbacks(i, i);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
asynStatus omsMAXvEncFunc::writeInt32(asynUser *pasynUser, epicsInt32 value)
|
||||
{
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynSuccess;
|
||||
omsBaseAxis *pAxis = (omsBaseAxis *)this->getAxis(pasynUser);
|
||||
static const char *functionName = "writeInt32";
|
||||
|
||||
if ((pAxis->getAxis() < MAXENCFUNC) && (function == encFuncIndex[pAxis->getAxis()])) {
|
||||
Debug(5, "omsMAXvEncFunc::writeInt32: set average axis %d with axis: %d\n", pAxis->getAxis(), value );
|
||||
if ((value >= 0) && (value < MAXENCFUNC)) averageChannel [pAxis->getAxis()] = value;
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"%s:%s: function=%d, value=%d\n",
|
||||
driverName, functionName, function, value);
|
||||
}
|
||||
else {
|
||||
status=omsMAXv::writeInt32(pasynUser, value);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* overrides the base class to add encoder functions and auxiliary encoders
|
||||
* for now we assume the function is average and averageChannel contains the
|
||||
* number of the other encoder to compute the average.
|
||||
*/
|
||||
asynStatus omsMAXvEncFunc::getEncoderPositions(epicsInt32 encPosArr[OMS_MAX_AXES])
|
||||
{
|
||||
// const char* functionName = "getEncoderPositions";
|
||||
asynStatus status = asynSuccess;
|
||||
double position;
|
||||
|
||||
omsBaseController::getEncoderPositions(encPosArr);
|
||||
|
||||
for (int i=0; i < OMS_MAX_AXES; ++i) {
|
||||
if ((i < MAXENCFUNC) && (averageChannel[i] != i) && (averageChannel[i] > 0) && (averageChannel[i] < OMS_MAX_AXES)){
|
||||
position = (double) encPosArr[i];
|
||||
encPosArr[i] = (int) (((double)(encPosArr[averageChannel[i]]) + position)/2.0);
|
||||
lock();
|
||||
setDoubleParam(i, encRawPosIndex[i], position);
|
||||
setDoubleParam(averageChannel[i], encRawPosIndex[averageChannel[i]], (double)encPosArr[averageChannel[i]]);
|
||||
unlock();
|
||||
Debug(9, "omsMAXvEncFunc::getEncPos: axis %d other: %d, old: %g, new: %d, other: %d \n", i, averageChannel[i], position, encPosArr[i], encPosArr[averageChannel[i]] );
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
extern "C" int omsMAXvEncFuncConfig(
|
||||
int cardNo, /* card no, starts with 0*/
|
||||
const char *portName, /* MAXv Motor Asyn Port name */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod, /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
const char *initString) /* Init String sent to card */
|
||||
{
|
||||
omsMAXvEncFunc *pController = new omsMAXvEncFunc(portName, numAxes, cardNo, initString, 0, 0);
|
||||
pController->startPoller((double)movingPollPeriod, (double)idlePollPeriod, 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* extended MAXv configuration, which may be used instead of omsMAXvEncFuncConfig,
|
||||
* if more details need to be specified.
|
||||
* omsMAXvEncFuncConfig2 does not need and ignores omsMAXvSetup
|
||||
*/
|
||||
extern "C" int omsMAXvEncFuncConfig2(
|
||||
int slotNo, /* VME slot no of MAXv card*/
|
||||
const char* addr_type, /* VME address type; "A16", "A24" or "A32" */
|
||||
unsigned int addrs, /* Board Address */
|
||||
unsigned int vector, /* Interrupt Vector: noninterrupting(0), (64-255) */
|
||||
int int_level, /* interrupt level (1-6) */
|
||||
const char *portName, /* MAXv Motor Asyn Port name */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int priority, /* priority of PollerTask (0 => epicsThreadPriorityMedium)*/
|
||||
int stackSize, /* stackSize of PollerTask (0 => epicsThreadStackMedium) */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod, /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
const char *initString) /* Init String sent to card */
|
||||
{
|
||||
omsMAXvEncFunc *pController = new omsMAXvEncFunc(portName, numAxes, slotNo, initString, priority,
|
||||
stackSize, addrs, vector, int_level, addr_type);
|
||||
pController->startPoller((double)movingPollPeriod, (double)idlePollPeriod, 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Code for iocsh registration */
|
||||
/* omsMAXvEncFuncConfig */
|
||||
static const iocshArg configArg0 = {"number of card", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn motor port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"number of axes", iocshArgInt};
|
||||
static const iocshArg configArg3 = {"moving poll rate", iocshArgInt};
|
||||
static const iocshArg configArg4 = {"idle poll rate", iocshArgInt};
|
||||
static const iocshArg configArg5 = {"initstring", iocshArgString};
|
||||
static const iocshArg * const configArgs[6] = {&configArg0, &configArg1, &configArg2,
|
||||
&configArg3, &configArg4, &configArg5 };
|
||||
static const iocshFuncDef configMAXv = {"omsMAXvEncFuncConfig", 6, configArgs};
|
||||
static void configMAXvCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXvEncFuncConfig(args[0].ival, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].sval);
|
||||
}
|
||||
|
||||
/* omsMAXvEncFuncConfig2 */
|
||||
static const iocshArg config2Arg0 = {"Slot number", iocshArgInt};
|
||||
static const iocshArg config2Arg1 = {"Address type: A16,A24,A32", iocshArgString};
|
||||
static const iocshArg config2Arg2 = {"Board Address on 4K (0x1000) boundary", iocshArgInt};
|
||||
static const iocshArg config2Arg3 = {"Interrupt Vector: noninterrupting(0), (64-255)", iocshArgInt};
|
||||
static const iocshArg config2Arg4 = {"Interrupt level (1-6)", iocshArgInt};
|
||||
static const iocshArg config2Arg5 = {"Asyn motor port name", iocshArgString};
|
||||
static const iocshArg config2Arg6 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg config2Arg7 = {"Task priority: 0 => medium", iocshArgInt};
|
||||
static const iocshArg config2Arg8 = {"Stack size: 0 => medium", iocshArgInt};
|
||||
static const iocshArg config2Arg9 = {"Moving poll rate", iocshArgInt};
|
||||
static const iocshArg config2Arg10 = {"Idle poll rate", iocshArgInt};
|
||||
static const iocshArg config2Arg11 = {"Initstring", iocshArgString};
|
||||
static const iocshArg * const config2Args[12] = {&config2Arg0, &config2Arg1, &config2Arg2, &config2Arg3, &config2Arg4,
|
||||
&config2Arg5, &config2Arg6, &config2Arg7, &config2Arg8, &config2Arg9, &config2Arg10, &config2Arg11};
|
||||
static const iocshFuncDef config2MAXv = {"omsMAXvEncFuncConfig2", 12, config2Args};
|
||||
static void config2MAXvCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
omsMAXvEncFuncConfig2(args[0].ival, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].sval,
|
||||
args[6].ival, args[7].ival, args[8].ival, args[9].ival, args[10].ival, args[11].sval);
|
||||
}
|
||||
|
||||
static void omsMAXvEncFuncAsynRegister(void)
|
||||
{
|
||||
iocshRegister(&configMAXv, configMAXvCallFunc);
|
||||
iocshRegister(&config2MAXv, config2MAXvCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(omsMAXvEncFuncAsynRegister);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
FILENAME... omsMAXvEncFunc.h
|
||||
USAGE... Pro-Dex OMS MAXv encoder asyn motor support
|
||||
|
||||
Version: $Revision$
|
||||
Modified By: $Author$
|
||||
Last Modified: $Date$
|
||||
HeadURL: $URL$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created on: 10/2010
|
||||
* Author: eden
|
||||
*/
|
||||
|
||||
#ifndef OMSMAXVENCFUNC_H_
|
||||
#define OMSMAXVENCFUNC_H_
|
||||
|
||||
#include "omsMAXv.h"
|
||||
|
||||
|
||||
#define ENCFUNCTION_FUNCTMASK 0xFF00 /* 8 function bits */
|
||||
#define ENCFUNCTION_ENC_MASK 0x00F0 /* 4 encoder bits (encoder 0 - 15) */
|
||||
#define ENCFUNCTION_AXISMASK 0x000F /* 4 axis bits (axis 0 - 15) */
|
||||
|
||||
#define ENCFUNCTION_NONE 0x00 /* no encoder functions */
|
||||
#define ENCFUNCTION_READ 0x01 /* read (auxiliary) encoder */
|
||||
#define ENCFUNCTION_REPLACE 0x02 /* replace encoder of axis axismask with encoder encodermask */
|
||||
#define ENCFUNCTION_AVERAGE 0x03 /* read (auxiliary) encoder */
|
||||
|
||||
#define ENCFUNCTION_AUXENC_0 0x0E /* aux encoder 0 is defined as encoder 14) */
|
||||
#define ENCFUNCTION_AUXENC_1 0x0F /* aux encoder 1 is defined as encoder 15) */
|
||||
|
||||
#define MAXENCFUNC 8
|
||||
|
||||
class omsMAXvEncFunc : public omsMAXv {
|
||||
public:
|
||||
omsMAXvEncFunc(const char*, int, int, const char*, int, int, unsigned int, int, int, const char* );
|
||||
omsMAXvEncFunc(const char*, int, int, const char*, int, int );
|
||||
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
virtual asynStatus getEncoderPositions(epicsInt32 encPosArr[OMS_MAX_AXES]);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
int averageChannel[MAXENCFUNC];
|
||||
int encFuncIndex[MAXENCFUNC];
|
||||
int encRawPosIndex[MAXENCFUNC];
|
||||
int encPosIndex[2];
|
||||
};
|
||||
|
||||
#endif /* OMSMAXVENCFUNC_H_ */
|
||||
Reference in New Issue
Block a user