phase 3 asyn motor support for OMS MAXnet and MAXv from Jens Eden.

This commit is contained in:
Ron Sluiter
2012-10-11 16:47:16 +00:00
parent 5b7b186f39
commit 83af8f1d92
15 changed files with 3078 additions and 22 deletions
+3
View File
@@ -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
+47 -22
View File
@@ -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 );
}
}
+26
View File
@@ -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
+24
View File
@@ -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")
+9
View File
@@ -0,0 +1,9 @@
registrar(OmsMAXnetAsynRegister)
registrar(OmsMAXvAsynRegister)
#registrar(omsMAXvEncFuncAsynRegister)
#variable(motorMAXvdebug)
#variable(motorOMSBASEdebug)
#variable(motorMAXvEncFuncdebug)
#variable(motorMAXnetdebug)
+200
View File
@@ -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;
}
+55
View File
@@ -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
+105
View File
@@ -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_ */
+369
View File
@@ -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, &registrarPvt);
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);
+42
View File
@@ -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_ */
+649
View File
@@ -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);
+176
View File
@@ -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_ */
+223
View File
@@ -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);
+51
View File
@@ -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_ */