Added girder translation axis drivers

This commit is contained in:
Mathis Stefan
2024-07-18 13:43:12 +02:00
parent 30228adf50
commit c972cce072
5 changed files with 335 additions and 2 deletions

View File

@ -15,7 +15,7 @@ REQUIRED+=asynMotor
# using a test version # using a test version
#scaler_VERSION=2024 #scaler_VERSION=2024
LIBVERSION=2024 LIBVERSION=2024-dev
TEMPLATES += sinqEPICSApp/Db/dimetix.db TEMPLATES += sinqEPICSApp/Db/dimetix.db
TEMPLATES += sinqEPICSApp/Db/slsvme.db TEMPLATES += sinqEPICSApp/Db/slsvme.db
@ -35,6 +35,5 @@ SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
SOURCES += sinqEPICSApp/src/pmacAxis.cpp SOURCES += sinqEPICSApp/src/pmacAxis.cpp
SOURCES += sinqEPICSApp/src/pmacController.cpp SOURCES += sinqEPICSApp/src/pmacController.cpp
SOURCES += sinqEPICSApp/src/drvAsynMasterMACSPort.c
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
# MISCS would be the place to keep the stream device template files # MISCS would be the place to keep the stream device template files

View File

@ -32,6 +32,10 @@
* *
* Mark Koennecke, June 2023 * Mark Koennecke, June 2023
* *
* Added driver for GirderAxis
*
* Stefan Mathis, July 2024
*
********************************************/ ********************************************/
#include <epicsExit.h> #include <epicsExit.h>
@ -1479,4 +1483,275 @@ asynStatus AmorDetectorAxis::poll(bool *moving)
return status; return status;
} }
/*-------------------------------------------------------------------------------*/
GirderAxis::GirderAxis(pmacController *pController, int axisNo)
: pmacV3Axis(pController, axisNo){
// GirderAxis expects a pmacV3Controller. Therefore it is checked whether the pointer pController can be cast
// to this object type. If this is not possible, the user made an error in the configuration files. This is documented
// in a corresponding error; after that, an exception is thrown to avoid returning an "illegal" instance of GirderAxis.
pmacV3Controller* pV3Controller = dynamic_cast<pmacV3Controller*>(pController);
if (pV3Controller == nullptr) {
errlogPrintf("A GirderAxis instance needs a pmacV3Controller. Please check the configuration files.");
throw std::invalid_argument("A GirderAxis instance needs a pmacV3Controller. Please check the configuration files.");
}
// Initial values for member variables
next_poll = -1;
previous_position_ = 0.0;
previous_direction_ = 0;
status6Time = 0;
statusPos = 0.0;
homing = 0;
axisErrorCount = 0;
};
/*-------------------------------------------------------------------------------*/
asynStatus GirderAxis::move(double position, int relative, double min_velocity, double max_velocity, double acceleration) {
// If the axis is not enabled, do nothing
if(!IsEnable) {
updateMsgTxtFromDriver("Error: axis disabled");
return asynError;
}
// =======================================
// Local variable declaration
asynStatus status = asynError;
char command[pC_->PMAC_MAXBUF_] = {0};
char response[pC_->PMAC_MAXBUF_] = {0};
double realPosition = 0;
// =======================================
updateMsgTxtFromDriver("");
static const char *functionName = "GirderAxis::move";
pC_->debugFlow(functionName);
if (relative) {
realPosition = previous_position_ + position / MULT;
} else {
realPosition = position / MULT;
}
startTime = time(NULL);
status6Time = 0;
starting = 1;
// Set target position
snprintf(command, sizeof(command), "Q251=%f", realPosition);
status = pC_->lowLevelWriteRead(axisNo_, command, response);
if (status == asynError) {
updateMsgTxtFromDriver("Error: Could not set target position");
return asynError;
}
// Start motion
snprintf(command, sizeof(command), "P150=1");
status = pC_->lowLevelWriteRead(axisNo_, command, response);
if (status == asynError) {
updateMsgTxtFromDriver("Error: Could not start motion");
return asynError;
}
next_poll = -1;
return status;
}
asynStatus GirderAxis::stop(double acceleration) {
// =======================================
// Local variable declaration
asynStatus status = asynSuccess;
static const char *functionName = "GirderAxis::stop";
bool moving = false;
char command[pC_->PMAC_MAXBUF_] = {0};
char response[pC_->PMAC_MAXBUF_] = {0};
// =======================================
pC_->debugFlow(functionName);
this->poll(&moving);
if(moving) {
// only send a stop when actually moving
snprintf(command, sizeof(command), "P150=8");
status = pC_->lowLevelWriteRead(axisNo_, command, response);
}
return status;
}
asynStatus GirderAxis::poll(bool *moving) {
// =======================================
// Local variable declaration
asynStatus status = asynSuccess;
static const char *functionName = "GirderAxis::poll";
char command[pC_->PMAC_MAXBUF_] = {0};
char response[pC_->PMAC_MAXBUF_] = {0};
char message[132], *axMessage;
double position = 0;
int moving_to_position = 0, nvals = 0, axisProblemFlag = 0, axStat = 0, axError = 0, isEnabled = 1;
asynStatus st;
// =======================================
// Check for girder axis specific errors
snprintf(command, sizeof(command), "P159");
status = pC_->lowLevelWriteRead(axisNo_, command, response);
sscanf(response, "P159=%d", &axError);
switch(axError) {
case 1:
snprintf(message, sizeof(message), "PMAC: %s on %d",
"Axis not switched on", axisNo_);
updateMsgTxtFromDriver(message);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s\n", message);
axisProblemFlag = 1;
isEnabled = 0;
break;
case 2:
snprintf(message, sizeof(message), "PMAC: %s on %d",
"Axis not ready for new command", axisNo_);
updateMsgTxtFromDriver(message);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s\n", message);
axisProblemFlag = 1;
break;
case 3:
snprintf(message, sizeof(message), "PMAC: %s on %d",
"Axis 1 ERROR during motion", axisNo_);
updateMsgTxtFromDriver(message);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s\n", message);
axisProblemFlag = 1;
break;
case 4:
snprintf(message, sizeof(message), "PMAC: %s on %d",
"Axis 2 ERROR during motion", axisNo_);
updateMsgTxtFromDriver(message);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s\n", message);
axisProblemFlag = 1;
break;
}
st = setIntegerParam(pC_->motorStatusProblem_, axisProblemFlag);
status = status > st ? status : st;
// Downcast the pointer pmacController to pmacV3Controller in a typesafe manner
pmacV3Controller* p3C_ = dynamic_cast<pmacV3Controller*>(pC_);
if (p3C_ == nullptr) {
errlogPrintf("A GirderAxis instance needs a pmacV3Controller. Please check the configuration files.");
throw std::invalid_argument("A GirderAxis instance needs a pmacV3Controller. Please check the configuration files.");
}
setIntegerParam(p3C_->axisEnabled_, isEnabled);
st = setIntegerParam(p3C_->enableAxis_, isEnabled);
status = status > st ? status : st;
int direction = 0;
/*
In GirderAxis::move, the user input is scaled by /MULT. Hence, the output of
Qxx10 needs to be scaled by *MULT
*/
st = setDoubleParam(pC_->motorPosition_, position * MULT);
status = status > st ? status : st;
st = setDoubleParam(pC_->motorEncoderPosition_, position * MULT);
status = status > st ? status : st;
// Calculate the current (or last) movement direction
if ((position - previous_position_) > 0) {
direction = 1;
} else if (position - previous_position_ == 0.0) {
direction = previous_direction_;
} else {
direction = 0;
}
st = setIntegerParam(pC_->motorStatusDirection_, direction);
status = status > st ? status : st;
// Store the position which was read out from the hardware together with the calculated direction for the next poll
previous_position_ = position;
previous_direction_ = direction;
// Is the axis currently moving?
snprintf(command, sizeof(command), "P154");
status = pC_->lowLevelWriteRead(axisNo_, command, response);
sscanf(response, "P154=%d", &moving_to_position);
/*
This code tests whether the axis is too long in status 5 or 6.
If the axis is in status 5 or 6, a time counter (status6Time) is started and updated during subsequent polls.
If status6Time exceeds the estimated arrival time of 120 seconds, a corresponding error is returned.
*/
int EstimatedTimeOfArrival = 120; // seconds
if (axStat == 5 || axStat == 6) {
if (status6Time == 0) {
status6Time = time(nullptr);
statusPos = position;
} else {
if (time(nullptr) > status6Time + EstimatedTimeOfArrival) {
/* trigger error only when not moving */
if (abs(position - statusPos) < .1) {
moving_to_position = 0;
errlogPrintf(
"Axis %d stayed in status 5 or 6 for more than %d seconds BROKEN\n",
axisNo_, EstimatedTimeOfArrival);
updateMsgTxtFromDriver("Axis stayed in status 5 or 6 for more than estimated time: BROKEN");
status6Time = 0;
return status;
} else {
status6Time = time(nullptr);
statusPos = position;
}
}
}
}
/*
If the axis is moving, set the corresponding flags in the pmacController (pC_) and end the poll.
*/
if (!moving_to_position) {
*moving = true;
st = setIntegerParam(pC_->motorStatusMoving_, true);
status = status > st ? status : st;
st = setIntegerParam(pC_->motorStatusDone_, false);
return status > st ? status : st;
} else {
*moving = false;
st = setIntegerParam(pC_->motorStatusMoving_, false);
status = status > st ? status : st;
st = setIntegerParam(pC_->motorStatusDone_, true);
status = status > st ? status : st;
}
/* Set any axis specific general problem bits. */
if (axError != 0) {
axisProblemFlag = 1;
if (axisErrorCount < 10) {
axMessage = translateAxisError(axError);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"drvGirderAxisGetStatus: Axis %d is in deep trouble: axis error "
"code %d, translated: %s:, status code = %d\n",
axisNo_, axError, axMessage, axStat);
snprintf(message, sizeof(message), "GirderAxis error: %s", axMessage);
updateMsgTxtFromDriver(message);
if (axMessage != NULL) {
free(axMessage);
}
axisErrorCount++;
} else if (axisErrorCount == 10) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Suppressing further axis error messages\n");
axisErrorCount++;
}
} else {
axisProblemFlag = 0;
axisErrorCount = 0;
}
st = setIntegerParam(pC_->motorStatusProblem_, axisProblemFlag);
status = status > st ? status : st;
return status;
}

View File

@ -189,4 +189,21 @@ protected:
time_t det_startTime; time_t det_startTime;
}; };
/*----------------------------------------------------------------------------------------------*/
class GirderAxis: public pmacV3Axis {
public:
GirderAxis(pmacController *pController, int axisNo);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
protected:
int IsEnable;
friend class pmacController;
friend class pmacV3Controller;
};
#endif /* pmacAxis_H */ #endif /* pmacAxis_H */

View File

@ -781,6 +781,34 @@ pC->unlock();
return asynSuccess; return asynSuccess;
} }
/**
* C wrapper for the GirderAxis constructor.
* See GirderAxis::GirderAxis.
*
*/
asynStatus pmacCreateGirderAxis(
const char *pmacName, /* specify which controller by port name */
int axis) /* axis number (start from 1). */
{
pmacController *pC;
pmacAxis *pAxis;
static const char *functionName = "pmacCreateGirderAxis";
pC = (pmacController *)findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n", driverName, functionName,
pmacName);
return asynError;
}
pC->lock();
pAxis = new GirderAxis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/*================================ SeleneController ===============================================*/ /*================================ SeleneController ===============================================*/
asynStatus SeleneController::writeFloat64(asynUser *pasynUser, epicsFloat64 value) asynStatus SeleneController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
@ -1057,6 +1085,18 @@ static void configpmacAmorDetectorAxisCallFunc(const iocshArgBuf *args)
pmacCreateAmorDetectorAxis(args[0].sval, args[1].ival, args[2].ival); pmacCreateAmorDetectorAxis(args[0].sval, args[1].ival, args[2].ival);
} }
/* GirderCreateAxis */
static const iocshArg pmacCreateGirderAxisArg0 = {"Controller port name",
iocshArgString};
static const iocshArg pmacCreateGirderAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const pmacCreateGirderAxisArgs[] = {&pmacCreateGirderAxisArg0,
&pmacCreateGirderAxisArg1};
static const iocshFuncDef configpmacGirderAxis = {"pmacGirderCreateAxis", 2,
pmacCreateGirderAxisArgs};
static void configpmacGirderAxisCallFunc(const iocshArgBuf *args) {
pmacCreateGirderAxis(args[0].sval, args[1].ival);
}
static void pmacControllerRegister(void) static void pmacControllerRegister(void)

View File

@ -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 GirderAxis;
friend class AmorDetectorAxis; friend class AmorDetectorAxis;
}; };
@ -182,6 +183,7 @@ public:
friend class pmacV3Axis; friend class pmacV3Axis;
friend class pmacAxis; friend class pmacAxis;
friend class GirderAxis;
protected: protected:
pmacV3Axis **pAxes_; /**< Array of pointers to axis objects */ pmacV3Axis **pAxes_; /**< Array of pointers to axis objects */