Added AMOR detector tower special pmac motors: working now
This commit is contained in:
@ -394,7 +394,12 @@ asynStatus NanotecAxis::poll(bool *moving)
|
|||||||
|
|
||||||
pPtr = strchr(reply,'C');
|
pPtr = strchr(reply,'C');
|
||||||
pPtr++;
|
pPtr++;
|
||||||
posVal = atoi(pPtr);
|
if(pPtr){
|
||||||
|
posVal = atoi(pPtr);
|
||||||
|
} else {
|
||||||
|
errlogPrintf("Invalid response %s for #C received for axis %d\n", reply, axisNo_);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
//errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
|
//errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
|
||||||
setDoubleParam(pC_->motorPosition_, (double)posVal);
|
setDoubleParam(pC_->motorPosition_, (double)posVal);
|
||||||
@ -408,7 +413,12 @@ asynStatus NanotecAxis::poll(bool *moving)
|
|||||||
|
|
||||||
pPtr = strchr(reply,'$');
|
pPtr = strchr(reply,'$');
|
||||||
pPtr++;
|
pPtr++;
|
||||||
statVal = atoi(pPtr);
|
if(pPtr) {
|
||||||
|
statVal = atoi(pPtr);
|
||||||
|
} else {
|
||||||
|
errlogPrintf("Invalid response %s for #$ received for axis %d\n", reply, axisNo_);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
||||||
// axisNo_, reply, statVal);
|
// axisNo_, reply, statVal);
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/********************************************
|
/*******************************************
|
||||||
* pmacAxis.cpp
|
* pmacAxis.cpp
|
||||||
*
|
*
|
||||||
* PMAC Asyn motor based on the
|
* PMAC Asyn motor based on the
|
||||||
@ -28,6 +28,10 @@
|
|||||||
*
|
*
|
||||||
* Michele Brambilla, February 2022
|
* Michele Brambilla, February 2022
|
||||||
*
|
*
|
||||||
|
* Added driver for special AMOR detector axes
|
||||||
|
*
|
||||||
|
* Mark Koennecke, June 2023
|
||||||
|
*
|
||||||
********************************************/
|
********************************************/
|
||||||
|
|
||||||
#include <epicsExit.h>
|
#include <epicsExit.h>
|
||||||
@ -42,6 +46,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include<algorithm>
|
#include<algorithm>
|
||||||
#include<cmath>
|
#include<cmath>
|
||||||
@ -1181,3 +1186,309 @@ asynStatus pmacV3Axis::move(double position, int relative, double min_velocity,
|
|||||||
updateMsgTxtFromDriver("");
|
updateMsgTxtFromDriver("");
|
||||||
return pmacAxis::move(position, relative, min_velocity, max_velocity, acceleration);
|
return pmacAxis::move(position, relative, min_velocity, max_velocity, acceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*========================= Amor Detector Motor code ==============*/
|
||||||
|
AmorDetectorAxis::AmorDetectorAxis(pmacController *pC, int axisNo, int function)
|
||||||
|
: pmacAxis(pC, axisNo, false) {
|
||||||
|
static const char *functionName = "pmacAxis::pmacAxis";
|
||||||
|
|
||||||
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
|
_function = function;
|
||||||
|
|
||||||
|
callParamCallbacks();
|
||||||
|
|
||||||
|
/* Wake up the poller task which will make it do a poll,
|
||||||
|
* updating values for this axis to use the new resolution (stepSize_) */
|
||||||
|
pC_->wakeupPoller();
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::moveVelocity(double min_velocity,
|
||||||
|
double max_velocity,
|
||||||
|
double acceleration)
|
||||||
|
{
|
||||||
|
updateMsgTxtFromDriver("Function moveVelocity not allowed");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::home(double min_velocity,
|
||||||
|
double max_velocity,
|
||||||
|
double acceleration,
|
||||||
|
int forwards)
|
||||||
|
{
|
||||||
|
updateMsgTxtFromDriver("Cannot home AMOR detector motors");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::setPosition(double position)
|
||||||
|
{
|
||||||
|
updateMsgTxtFromDriver("Cannot setPosition() AMOR detector motors");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::move(double position, int relative,
|
||||||
|
double min_velocity, double max_velocity,
|
||||||
|
double acceleration)
|
||||||
|
{
|
||||||
|
asynStatus status = asynError;
|
||||||
|
static const char *functionName = "AmorDetectorAxis::move";
|
||||||
|
double realPosition;
|
||||||
|
int parkStatus;
|
||||||
|
time_t errorWait;
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
|
char command[128] = {0};
|
||||||
|
char response[32] = {0};
|
||||||
|
|
||||||
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
|
/* test if we are not in the change position */
|
||||||
|
sprintf(command,"P358");
|
||||||
|
pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
sscanf(response, "%d", &parkStatus);
|
||||||
|
if(_function != ADPARK && parkStatus == 2) {
|
||||||
|
updateMsgTxtFromDriver("Cannot run motor when in park position");
|
||||||
|
errlogPrintf("Cannot run motor when in park position");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relative) {
|
||||||
|
realPosition = previous_position_ + position / MULT;
|
||||||
|
} else {
|
||||||
|
realPosition = position / MULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set target */
|
||||||
|
errlogPrintf("function %d, sending position %f\n", _function, realPosition);
|
||||||
|
|
||||||
|
switch(_function){
|
||||||
|
case ADCOM:
|
||||||
|
sprintf(command, "Q451=%f", realPosition);
|
||||||
|
break;
|
||||||
|
case ADCOZ:
|
||||||
|
sprintf(command, "Q454=%f", realPosition);
|
||||||
|
break;
|
||||||
|
case ADPARK:
|
||||||
|
// test if a reset is required first
|
||||||
|
sprintf(command, "P359");
|
||||||
|
pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
sscanf(response, "%d", &parkStatus);
|
||||||
|
errlogPrintf("park status %d\n", parkStatus);
|
||||||
|
if(parkStatus != 0){
|
||||||
|
sprintf(command,"P352=2");
|
||||||
|
pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
errlogPrintf("Park status %d, error reset: %s\n", parkStatus, command);
|
||||||
|
}
|
||||||
|
errorWait = time(NULL);
|
||||||
|
while(true){
|
||||||
|
usleep(5000);
|
||||||
|
sprintf(command, "P359");
|
||||||
|
pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
sscanf(response, "%d", &parkStatus);
|
||||||
|
errlogPrintf("P359 = %d\n", parkStatus);
|
||||||
|
if(parkStatus == 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(time(NULL) > errorWait + 3){
|
||||||
|
errlogPrintf("Failed to clear error status after 3 seconds\n");
|
||||||
|
updateMsgTxtFromDriver("Failed to clear errorState in 3 seconds");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// now drive to the real place
|
||||||
|
if(realPosition == 0) {
|
||||||
|
sprintf(command, "P350=3");
|
||||||
|
} else if(realPosition < -90){
|
||||||
|
sprintf(command, "P350=2");
|
||||||
|
} else {
|
||||||
|
updateMsgTxtFromDriver("Can only reach -100, 0, nothing else");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
errlogPrintf("Park position %f, park command: %s\n", realPosition, command);
|
||||||
|
|
||||||
|
}
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
if(status != asynSuccess) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"AmorDetectorAxis::move failed to send command %s", command);
|
||||||
|
updateMsgTxtFromDriver("Cannot send Amor Detector Command");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send move command */
|
||||||
|
if(_function != ADPARK) {
|
||||||
|
sprintf(command, "P350=1");
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
if(status != asynSuccess) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"AmorDetectorAxis::move failed to send command %s", command);
|
||||||
|
updateMsgTxtFromDriver("Cannot send Amor Detector Command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
det_starting = true;
|
||||||
|
det_startTime = time(NULL);
|
||||||
|
|
||||||
|
next_poll = BUSYPOLL;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::stop(double acceleration) {
|
||||||
|
asynStatus status = asynError;
|
||||||
|
static const char *functionName = "AmorDetectorAxis::stopAxis";
|
||||||
|
bool moving = false;
|
||||||
|
|
||||||
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
|
char command[128] = {0};
|
||||||
|
char response[32] = {0};
|
||||||
|
|
||||||
|
this->poll(&moving);
|
||||||
|
det_starting = false;
|
||||||
|
|
||||||
|
if(moving) {
|
||||||
|
// only send a stop when actually moving
|
||||||
|
sprintf(command, "P350=8");
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------------*/
|
||||||
|
asynStatus AmorDetectorAxis::poll(bool *moving)
|
||||||
|
{
|
||||||
|
asynStatus status = asynError;
|
||||||
|
static const char *functionName = "AmorDetectorAxis::poll";
|
||||||
|
int targetReached, errorCode, parkCode;
|
||||||
|
double position;
|
||||||
|
|
||||||
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
|
char command[128] = {0};
|
||||||
|
char response[32] = {0};
|
||||||
|
char errorMessage[128] = {0};
|
||||||
|
|
||||||
|
/* read in position flag*/
|
||||||
|
sprintf(command, "P354");
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
if(status != asynSuccess){
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"AmorDetectorAxis::poll failed to read in position");
|
||||||
|
updateMsgTxtFromDriver("Failed to read Amor Detector in position");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
sscanf(response, "%d", &targetReached);
|
||||||
|
|
||||||
|
//if(_function == ADCOM){
|
||||||
|
// errlogPrintf("startTime: %ld, current time: %ld, starting flag %d, targetReached %d\n", det_startTime, time(NULL),
|
||||||
|
// det_starting, targetReached);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// The thing is sometimes slow to start, allow 7 seconds
|
||||||
|
// Especially coz is really slow to indicate
|
||||||
|
if(det_starting && time(NULL) > (det_startTime + 7)) {
|
||||||
|
det_starting = false;
|
||||||
|
//if(_function == ADCOM){
|
||||||
|
// errlogPrintf("Resetting starting flag after timeout\n");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
if(targetReached == 0 && det_starting == false){
|
||||||
|
*moving = false;
|
||||||
|
setIntegerParam(pC_->motorStatusDone_, true);
|
||||||
|
next_poll = IDLEPOLL;
|
||||||
|
} else {
|
||||||
|
*moving = true;
|
||||||
|
if(targetReached == 1){
|
||||||
|
det_starting = false;
|
||||||
|
//if(_function == ADCOM){
|
||||||
|
// errlogPrintf("Resetting starting flag following targetReached flag\n");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
setIntegerParam(pC_->motorStatusDone_, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read position
|
||||||
|
if(_function == ADCOM) {
|
||||||
|
strcpy(command,"Q0510");
|
||||||
|
} else if(_function == ADCOZ) {
|
||||||
|
strcpy(command, "Q454");
|
||||||
|
} else if(_function == ADPARK){
|
||||||
|
strcpy(command,"P358");
|
||||||
|
}
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
if(status != asynSuccess){
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"AmorDetectorAxis::poll failed to read value");
|
||||||
|
updateMsgTxtFromDriver("Failed to read Amor Detector value");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
if(_function != ADPARK){
|
||||||
|
sscanf(response, "%lf", &position);
|
||||||
|
} else {
|
||||||
|
// analyse the park code to check where the thing is. This does
|
||||||
|
// not show good values while driving. But that is a limitation
|
||||||
|
// of the hardware.
|
||||||
|
sscanf(response, "%d", &parkCode);
|
||||||
|
if(parkCode == 1) {
|
||||||
|
position = 0;
|
||||||
|
} else {
|
||||||
|
position = -100;
|
||||||
|
}
|
||||||
|
// errlogPrintf("parkCode %d , position %f,targetREached = %d\n", parkCode, position, targetReached);
|
||||||
|
}
|
||||||
|
setDoubleParam(pC_->motorPosition_, position * 1000.);
|
||||||
|
setDoubleParam(pC_->motorEncoderPosition_, position * 1000.);
|
||||||
|
|
||||||
|
//if(_function == ADCOM){
|
||||||
|
// errlogPrintf("polling for function %d, position %f, pos*10^3 %f, targetREached = %d\n", _function, position,
|
||||||
|
// position*MULT, targetReached);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// read error status
|
||||||
|
sprintf(command, "P359");
|
||||||
|
status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
|
if(status == asynSuccess) {
|
||||||
|
sscanf(response, "%d", &errorCode);
|
||||||
|
switch(errorCode) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strcpy(errorMessage,"COZ not released");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strcpy(errorMessage,"Motor is in wrong state");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
strcpy(errorMessage,"FTZ error while moving");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
strcpy(errorMessage, "Break while moving");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
strcpy(errorMessage, "No freigabe during move");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strcpy(errorMessage, "Unknown error code from: ");
|
||||||
|
strcat(errorMessage, response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strlen(errorMessage) > 1) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"AmorDetectorAxis::poll: %s", errorMessage);
|
||||||
|
updateMsgTxtFromDriver(errorMessage);
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
status = asynError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callParamCallbacks();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,4 +157,35 @@ public:
|
|||||||
friend class pmacV3Controller;
|
friend class pmacV3Controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special motors for the AMOR detector movement. The whole
|
||||||
|
* command set is different but on a pmac controller. This implements
|
||||||
|
* a coordinated movement of cox, coz and ftz in order not to break
|
||||||
|
* the flight tube which may have been mounted. This is mapped to three
|
||||||
|
* motors selected via the function code: com, the detector omega, coz,
|
||||||
|
* the detector z offset and park, for parking the flightpath.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ADCOM 1
|
||||||
|
#define ADCOZ 2
|
||||||
|
#define ADPARK 3
|
||||||
|
|
||||||
|
class AmorDetectorAxis: public pmacAxis {
|
||||||
|
public:
|
||||||
|
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
|
||||||
|
|
||||||
|
asynStatus move(double position, int relative, double min_velocity,
|
||||||
|
double max_velocity, double acceleration);
|
||||||
|
asynStatus poll(bool *moving);
|
||||||
|
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||||
|
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||||
|
asynStatus stop(double acceleration);
|
||||||
|
asynStatus setPosition(double position);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _function;
|
||||||
|
int det_starting;
|
||||||
|
time_t det_startTime;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* pmacAxis_H */
|
#endif /* pmacAxis_H */
|
||||||
|
@ -751,7 +751,33 @@ asynStatus pmacCreateAxes(const char *pmacName,
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C wrapper for the pmacAmorDetectorAxis constructor.
|
||||||
|
* See pmacAmorDetectorAxis::pmacAmorDetectorAxis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
asynStatus pmacCreateAmorDetectorAxis(const char *pmacName, /* specify which controller by port name */
|
||||||
|
int axis, /* axis number (start from 1). */
|
||||||
|
int function_code) /* AMOR detector axis function */
|
||||||
|
{
|
||||||
|
pmacController *pC;
|
||||||
|
pmacAxis *pAxis;
|
||||||
|
|
||||||
|
static const char *functionName = "pmacCreateHRPTAxis";
|
||||||
|
|
||||||
|
pC = (pmacController*) findAsynPortDriver(pmacName);
|
||||||
|
if (!pC) {
|
||||||
|
printf("%s:%s: Error port %s not found\n",
|
||||||
|
driverName, functionName, pmacName);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pC->lock();
|
||||||
|
pAxis = new AmorDetectorAxis(pC, axis, function_code);
|
||||||
|
pAxis = NULL;
|
||||||
|
pC->unlock();
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/*================================ SeleneController ===============================================*/
|
/*================================ SeleneController ===============================================*/
|
||||||
|
|
||||||
@ -996,6 +1022,19 @@ static void configpmacAxesCallFunc(const iocshArgBuf *args)
|
|||||||
pmacCreateAxes(args[0].sval, args[1].ival);
|
pmacCreateAxes(args[0].sval, args[1].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pmacCraeteAmorDetectorAxis */
|
||||||
|
static const iocshArg pmacCreateAmorDetectorAxisArg0 = {"Controller port name", iocshArgString};
|
||||||
|
static const iocshArg pmacCreateAmorDetectorAxisArg1 = {"Axis number", iocshArgInt};
|
||||||
|
static const iocshArg pmacCreateAmorDetectorAxisArg2 = {"Function code", iocshArgInt};
|
||||||
|
static const iocshArg * const pmacCreateAmorDetectorAxisArgs[] = {&pmacCreateAmorDetectorAxisArg0,
|
||||||
|
&pmacCreateAmorDetectorAxisArg1, &pmacCreateAmorDetectorAxisArg2};
|
||||||
|
static const iocshFuncDef configpmacAmorDetectorAxis = {"pmacCreateAmorDetectorAxis", 3, pmacCreateAmorDetectorAxisArgs};
|
||||||
|
|
||||||
|
static void configpmacAmorDetectorAxisCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
pmacCreateAmorDetectorAxis(args[0].sval, args[1].ival, args[2].ival);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void pmacControllerRegister(void)
|
static void pmacControllerRegister(void)
|
||||||
@ -1005,6 +1044,7 @@ static void pmacControllerRegister(void)
|
|||||||
iocshRegister(&configpmacV3CreateController, configpmacV3CreateControllerCallFunc);
|
iocshRegister(&configpmacV3CreateController, configpmacV3CreateControllerCallFunc);
|
||||||
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
|
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
|
||||||
iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc);
|
iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc);
|
||||||
|
iocshRegister(&configpmacAmorDetectorAxis, configpmacAmorDetectorAxisCallFunc);
|
||||||
iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc);
|
iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc);
|
||||||
iocshRegister(&configLiftAxis, configLiftAxisCallFunc);
|
iocshRegister(&configLiftAxis, configLiftAxisCallFunc);
|
||||||
iocshRegister(&configpmacV3Axis, configpmacV3AxisCallFunc);
|
iocshRegister(&configpmacV3Axis, configpmacV3AxisCallFunc);
|
||||||
|
@ -140,6 +140,7 @@ class pmacController : public SINQController {
|
|||||||
friend class SeleneAxis;
|
friend class SeleneAxis;
|
||||||
friend class LiftAxis;
|
friend class LiftAxis;
|
||||||
friend class pmacV3Axis;
|
friend class pmacV3Axis;
|
||||||
|
friend class AmorDetectorAxis;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_PMAC_PARAMS (&LAST_PMAC_PARAM - &FIRST_PMAC_PARAM + 1)
|
#define NUM_PMAC_PARAMS (&LAST_PMAC_PARAM - &FIRST_PMAC_PARAM + 1)
|
||||||
|
Reference in New Issue
Block a user