Updated turboPmac dependency to 0.15.1

This commit is contained in:
2025-05-14 16:39:16 +02:00
parent 60960dde44
commit 203bb9475f
11 changed files with 757 additions and 286 deletions

View File

@ -16,14 +16,20 @@ motorBase_VERSION=7.2.2
HEADERS += src/detectorTowerAngleAxis.h
HEADERS += src/detectorTowerController.h
HEADERS += src/detectorTowerLiftAxis.h
HEADERS += src/detectorTowerSupportAxis.h
# Source files to build
SOURCES += turboPmac/sinqMotor/src/msgPrintControl.cpp
SOURCES += turboPmac/sinqMotor/src/sinqAxis.cpp
SOURCES += turboPmac/sinqMotor/src/sinqController.cpp
SOURCES += turboPmac/src/pmacAsynIPPort.c
SOURCES += turboPmac/src/turboPmacAxis.cpp
SOURCES += turboPmac/src/turboPmacController.cpp
SOURCES += turboPmac/src/pmacAsynIPPort.c
SOURCES += src/detectorTowerAngleAxis.cpp
SOURCES += src/detectorTowerController.cpp
SOURCES += src/detectorTowerLiftAxis.cpp
SOURCES += src/detectorTowerSupportAxis.cpp
# Store the record files
TEMPLATES += turboPmac/sinqMotor/db/asynRecord.db

View File

@ -89,47 +89,6 @@ record(ao, "$(INSTR)$(M):WriteAO") {
field(VAL, "0")
}
# Read out the origin of the lift axis support motor (FTZ at AMOR).
# This PV does nothing for "normal" Turbo PMAC axes or the angle axis.
record(ai, "$(INSTR)$(M):SupportOrigin") {
field(DTYP, "asynFloat64")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) SUPPORT_ORIGIN")
field(SCAN, "I/O Intr")
field(PINI, "NO")
field(VAL, "0")
}
# Shift the origin of the lift support axis by the given value. The axis will
# move to this position and the hardware controller will internally set this
# position as the new "0" value. This PV does nothing for "normal" Turbo PMAC
# axes or the angle axis.
record(ao, "$(INSTR)$(M):AdjustSupportOrigin") {
field(DTYP, "Raw Soft Channel")
field(PINI, "NO")
field(DRVH, "200") # Limit in encoder steps (not mm!)
field(DRVL, "-200") # Limit in encoder steps (not mm!)
field(FLNK, "$(INSTR)$(M):ResetASO")
field(VAL, "0")
}
# Reset the PV $(INSTR)$(M):AdjustOrigin to zero after it has been written to and
# forward the value to $(INSTR)$(M):WriteAO which does the actual writing.
record(seq, "$(INSTR)$(M):ResetASO") {
field(DESC, "Write value to hardware then reset to 0")
field(DOL1, "$(INSTR)$(M):AdjustSupportOrigin")
field(LNK1, "$(INSTR)$(M):WriteASO.VAL PP") # Perform write to hardware
field(DOL2, "0.0")
field(LNK2, "$(INSTR)$(M):AdjustSupportOrigin.VAL PP") # Reset to zero
}
# This record forwards the adjustment of the origin to the asyn driver.
record(ao, "$(INSTR)$(M):WriteASO") {
field(DTYP, "asynFloat64")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) SUPPORT_ADJUST_ORIGIN")
field(PINI, "NO")
field(VAL, "0")
}
# This record pair reads the parameter library value for "AdjustOriginHighLimitFromDriver_"
# and pushes it to the high limit field of the "$(INSTR)$(M):AdjustOrigin" PV.
# This can be used to read limits from the hardware and correspondingly update the motor record from the driver.

View File

@ -47,8 +47,7 @@ static void deferredMovementCollectorLoop(void *drvPvt) {
}
detectorTowerAngleAxis::detectorTowerAngleAxis(detectorTowerController *pC,
int axisNo,
detectorTowerLiftAxis *liftAxis)
int axisNo)
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
/*
@ -80,8 +79,6 @@ detectorTowerAngleAxis::detectorTowerAngleAxis(detectorTowerController *pC,
receivedTarget_ = false;
startingDeferredMovement_ = false;
deferredMovementWait_ = 0.1; // seconds
liftAxis_ = liftAxis;
liftAxis_->angleAxis_ = this;
// Will be populated in the init() method
beamRadius_ = 0.0;
@ -117,6 +114,7 @@ asynStatus detectorTowerAngleAxis::init() {
asynStatus status = asynSuccess;
double motorRecResolution = 0.0;
char response[pC_->MAXBUF_] = {0};
int positionState = 0;
int nvals = 0;
// The parameter library takes some time to be initialized. Therefore we
@ -146,14 +144,14 @@ asynStatus detectorTowerAngleAxis::init() {
}
// Read the detector radius
const char *command = "P459";
status = pC_->writeRead(axisNo_, command, response, 1);
const char *command = "P459 P358";
status = pC_->writeRead(axisNo_, command, response, 2);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%lf", &beamRadius_);
if (nvals != 1) {
nvals = sscanf(response, "%lf %d", &beamRadius_, &positionState);
if (nvals != 2) {
return pC_->couldNotParseResponse(command, response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
@ -165,7 +163,13 @@ asynStatus detectorTowerAngleAxis::init() {
__PRETTY_FUNCTION__, __LINE__);
}
return status;
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return callParamCallbacks();
}
// Perform the actual poll
@ -174,8 +178,8 @@ asynStatus detectorTowerAngleAxis::poll(bool *moving) {
// Is this axis the one with the smallest index?
// If not, just read out the movement status and update *moving
if (axisNo() < liftAxis_->axisNo()) {
status = pC_->pollDetectorAxes(moving, this, liftAxis_);
if (axisNo() < liftAxis()->axisNo() && axisNo() < supportAxis()->axisNo()) {
status = pC_->pollDetectorAxes(moving, this, liftAxis(), supportAxis());
} else {
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
(int *)moving);
@ -255,6 +259,23 @@ asynStatus detectorTowerAngleAxis::startCombinedMove() {
pC_->getMsgPrintControl().getSuffix());
}
if (isInChangerPos) {
plStatus = setStringParam(
pC_->motorMessageText(),
"Move the axis to working state first.");
if (plStatus != asynSuccess) {
return pC_->paramLibAccessFailed(plStatus, "motorMessageText",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
if (plStatus != asynSuccess) {
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
callParamCallbacks();
startingDeferredMovement_ = false;
return asynError;
}
@ -287,6 +308,7 @@ asynStatus detectorTowerAngleAxis::startCombinedMove() {
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
callParamCallbacks();
}
return rwStatus;
@ -416,13 +438,10 @@ detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
// Move the axis into changer or working position
if (toChangingPosition) {
rwStatus = pC_->writeRead(axisNo_, "P350=2", response, 0);
plStatus = setStringParam(pC_->motorMessageText(),
"Moving to changer position ...");
} else {
rwStatus = pC_->writeRead(axisNo_, "P350=3", response, 0);
plStatus = setStringParam(pC_->motorMessageText(),
"Moving to working state ...");
}
if (plStatus != asynSuccess) {
plStatus = setIntegerParam(pC_->changeStateRBV(), !toChangingPosition);
if (plStatus != asynSuccess) {
@ -444,34 +463,6 @@ detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
return rwStatus;
}
asynStatus detectorTowerAngleAxis::doReset() {
char response[pC_->MAXBUF_] = {0};
asynStatus plStatus = asynSuccess;
int positionState = 0;
plStatus =
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
if (plStatus != asynSuccess) {
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
/*
Check which action should be performed:
- If error_ == 10 or 11 (FTZ motor error): P352 = 3 (Recover FTZ)
- If any other error: P352 = 2 (Reset error)
- Otherwise: P352 = 1 (Set axis in closed-loop mode)
*/
if (error_ == 10 || error_ == 11) {
return pC_->writeRead(axisNo_, "P352=3", response, 0);
} else if (error_ != 0) {
return pC_->writeRead(axisNo_, "P352=2", response, 0);
} else {
return pC_->writeRead(axisNo_, "P352=1", response, 0);
}
}
asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
asynStatus status = asynSuccess;
@ -526,6 +517,34 @@ asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
return status;
}
asynStatus detectorTowerAngleAxis::doReset() {
char response[pC_->MAXBUF_] = {0};
asynStatus plStatus = asynSuccess;
int positionState = 0;
plStatus =
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
if (plStatus != asynSuccess) {
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
/*
Check which action should be performed:
- If error_ == 10 or 11 (FTZ motor error): P352 = 3 (Recover FTZ)
- If any other error: P352 = 2 (Reset error)
- Otherwise: P352 = 1 (Set axis in closed-loop mode)
*/
if (error_ == 10 || error_ == 11) {
return pC_->writeRead(axisNo_, "P352=3", response, 0);
} else if (error_ != 0) {
return pC_->writeRead(axisNo_, "P352=2", response, 0);
} else {
return pC_->writeRead(axisNo_, "P352=1", response, 0);
}
}
/*************************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */
@ -537,7 +556,7 @@ C wrapper for the axis constructor. Please refer to the detectorTower
constructor documentation. The controller is read from the portName.
*/
asynStatus detectorTowerCreateAxis(const char *portName, int angleAxisIdx,
int liftAxisIdx) {
int liftAxisIdx, int supportAxisIdx) {
/*
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
@ -597,13 +616,18 @@ asynStatus detectorTowerCreateAxis(const char *portName, int angleAxisIdx,
be "leaked" here.
*/
detectorTowerLiftAxis *liftAxis =
new detectorTowerLiftAxis(pC, liftAxisIdx);
detectorTowerAngleAxis *angleAxis =
new detectorTowerAngleAxis(pC, angleAxisIdx);
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-variable"
detectorTowerAngleAxis *pAxis =
new detectorTowerAngleAxis(pC, angleAxisIdx, liftAxis);
detectorTowerLiftAxis *liftAxis =
new detectorTowerLiftAxis(pC, liftAxisIdx, angleAxis);
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-variable"
detectorTowerSupportAxis *supportAxis =
new detectorTowerSupportAxis(pC, supportAxisIdx, angleAxis);
// Allow manipulation of the controller again
pC->unlock();
@ -615,15 +639,19 @@ static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
static const iocshArg CreateAxisArg1 = {"Number of the detector angle axis",
iocshArgInt};
static const iocshArg CreateAxisArg2 = {"Number of the lift axis", iocshArgInt};
static const iocshArg CreateAxisArg3 = {"Number of the support axis",
iocshArgInt};
static const iocshArg *const CreateAxisArgs[] = {
&CreateAxisArg0,
&CreateAxisArg1,
&CreateAxisArg2,
&CreateAxisArg3,
};
static const iocshFuncDef configDetectorTowerCreateAxis = {"detectorTowerAxis",
3, CreateAxisArgs};
4, CreateAxisArgs};
static void configDetectorTowerCreateAxisCallFunc(const iocshArgBuf *args) {
detectorTowerCreateAxis(args[0].sval, args[1].ival, args[2].ival);
detectorTowerCreateAxis(args[0].sval, args[1].ival, args[2].ival,
args[3].ival);
}
// =============================================================================

View File

@ -1,12 +1,13 @@
#ifndef detectorTowerAngleAxis_H
#define detectorTowerAngleAxis_H
#include "detectorTowerLiftAxis.h"
#include "turboPmacAxis.h"
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
// https://en.cppreference.com/w/cpp/language/class.
class detectorTowerController;
class detectorTowerLiftAxis;
class detectorTowerSupportAxis;
class detectorTowerAngleAxis : public turboPmacAxis {
public:
@ -15,13 +16,9 @@ class detectorTowerAngleAxis : public turboPmacAxis {
*
* @param pController Pointer to the associated controller
* @param axisNo Index of the axis
* @param liftZeroCorrAxis Pointer to the attached axis which controls
* the lift offset
* @param tiltZeroCorrAxis Pointer to the attached axis which controls
* the tilt offset
* @param liftAxis Pointer to the associated lift axis
*/
detectorTowerAngleAxis(detectorTowerController *pController, int axisNo,
detectorTowerLiftAxis *liftAxis);
detectorTowerAngleAxis(detectorTowerController *pController, int axisNo);
/**
* @brief Destroy the detectorTowerAngleAxis
@ -99,7 +96,6 @@ class detectorTowerAngleAxis : public turboPmacAxis {
/**
* @brief Implementation of the `doReset` method of sinqAxis
*
* @param on
* @return asynStatus
*/
asynStatus doReset();
@ -129,6 +125,13 @@ class detectorTowerAngleAxis : public turboPmacAxis {
*/
detectorTowerLiftAxis *liftAxis() { return liftAxis_; }
/**
* @brief Return a pointer to the associated support axis
*
* @return detectorTowerAngleAxis*
*/
detectorTowerSupportAxis *supportAxis() { return supportAxis_; }
// If true, either this axis or one of the detectorTowerLiftAxis
// attached to it received a movement command.
bool receivedTarget_;
@ -153,10 +156,12 @@ class detectorTowerAngleAxis : public turboPmacAxis {
protected:
detectorTowerController *pC_;
detectorTowerLiftAxis *liftAxis_;
detectorTowerSupportAxis *supportAxis_;
double beamRadius_;
private:
friend class detectorTowerLiftAxis;
friend class detectorTowerSupportAxis;
};
#endif

View File

@ -104,43 +104,26 @@ detectorTowerController::detectorTowerController(
stringifyAsynStatus(status));
exit(-1);
}
status =
createParam("SUPPORT_ORIGIN", asynParamFloat64, &liftSupportOrigin_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
"parameter failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
exit(-1);
}
status = createParam("SUPPORT_ADJUST_ORIGIN", asynParamFloat64,
&liftSupportAdjustOrigin_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
"parameter failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
exit(-1);
}
}
asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
epicsInt32 *value) {
// The detector tower or its auxiliary axes cannot be disabled
// The detector axes cannot be disabled
if (pasynUser->reason == motorCanDisable_) {
detectorTowerAngleAxis *angleAxis =
getDetectorTowerAngleAxis(pasynUser);
if (angleAxis != nullptr) {
detectorTowerAngleAxis *aAxis = getDetectorTowerAngleAxis(pasynUser);
if (aAxis != nullptr) {
*value = 0;
return asynSuccess;
}
detectorTowerLiftAxis *liftAxis = getDetectorTowerLiftAxis(pasynUser);
if (liftAxis != nullptr) {
detectorTowerLiftAxis *lAxis = getDetectorTowerLiftAxis(pasynUser);
if (lAxis != nullptr) {
*value = 0;
return asynSuccess;
}
detectorTowerSupportAxis *sAxis =
getDetectorTowerSupportAxis(pasynUser);
if (sAxis != nullptr) {
*value = 0;
return asynSuccess;
}
@ -151,17 +134,19 @@ asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
asynStatus detectorTowerController::writeInt32(asynUser *pasynUser,
epicsInt32 value) {
// =====================================================================
if (pasynUser->reason == changeState_) {
detectorTowerAngleAxis *angleAxis =
getDetectorTowerAngleAxis(pasynUser);
if (angleAxis != nullptr) {
return angleAxis->toggleWorkingChangerState(value);
detectorTowerAngleAxis *aAxis = getDetectorTowerAngleAxis(pasynUser);
if (aAxis != nullptr) {
return aAxis->toggleWorkingChangerState(value);
}
detectorTowerLiftAxis *liftAxis = getDetectorTowerLiftAxis(pasynUser);
if (liftAxis != nullptr) {
return liftAxis->angleAxis()->toggleWorkingChangerState(value);
detectorTowerLiftAxis *lAxis = getDetectorTowerLiftAxis(pasynUser);
if (lAxis != nullptr) {
return lAxis->angleAxis()->toggleWorkingChangerState(value);
}
detectorTowerSupportAxis *sAxis =
getDetectorTowerSupportAxis(pasynUser);
if (sAxis != nullptr) {
return sAxis->angleAxis()->toggleWorkingChangerState(value);
}
}
return turboPmacController::writeInt32(pasynUser, value);
@ -176,7 +161,7 @@ asynStatus detectorTowerController::writeFloat64(asynUser *pasynUser,
if (function == motorAdjustOrigin_) {
// Is this function called by an asynUser of the angle or lift axis?
// Is this function called by a detector axis?
detectorTowerAngleAxis *aAxis = getDetectorTowerAngleAxis(pasynUser);
if (aAxis != nullptr) {
status = aAxis->adjustOrigin(value);
@ -184,26 +169,27 @@ asynStatus detectorTowerController::writeFloat64(asynUser *pasynUser,
return status;
}
return turboPmacController::writeFloat64(pasynUser, value);
} else {
detectorTowerLiftAxis *lAxis = getDetectorTowerLiftAxis(pasynUser);
if (lAxis != nullptr) {
status = lAxis->adjustOrigin(value);
if (status != asynSuccess) {
return status;
}
return turboPmacController::writeFloat64(pasynUser, value);
}
}
return asynSuccess;
} else if (function == liftSupportAdjustOrigin_) {
detectorTowerLiftAxis *lAxis = getDetectorTowerLiftAxis(pasynUser);
if (lAxis != nullptr) {
status = lAxis->adjustSupportOrigin(value);
status = lAxis->adjustOrigin(value);
if (status != asynSuccess) {
return status;
}
return turboPmacController::writeFloat64(pasynUser, value);
}
detectorTowerSupportAxis *sAxis =
getDetectorTowerSupportAxis(pasynUser);
if (sAxis != nullptr) {
status = sAxis->adjustOrigin(value);
if (status != asynSuccess) {
return status;
}
return turboPmacController::writeFloat64(pasynUser, value);
}
return asynSuccess;
} else {
return turboPmacController::writeFloat64(pasynUser, value);
@ -252,10 +238,30 @@ detectorTowerController::getDetectorTowerLiftAxis(int axisNo) {
return dynamic_cast<detectorTowerLiftAxis *>(asynAxis);
}
asynStatus
detectorTowerController::pollDetectorAxes(bool *moving,
detectorTowerAngleAxis *angleAxis,
detectorTowerLiftAxis *liftAxis) {
/*
Access one of the axes of the controller via the axis adress stored in asynUser.
If the axis does not exist or is not a Axis, a nullptr is returned and an
error is emitted.
*/
detectorTowerSupportAxis *
detectorTowerController::getDetectorTowerSupportAxis(asynUser *pasynUser) {
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
return dynamic_cast<detectorTowerSupportAxis *>(asynAxis);
}
/*
Access one of the axes of the controller via the axis index.
If the axis does not exist or is not a Axis, the function must return Null
*/
detectorTowerSupportAxis *
detectorTowerController::getDetectorTowerSupportAxis(int axisNo) {
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
return dynamic_cast<detectorTowerSupportAxis *>(asynAxis);
}
asynStatus detectorTowerController::pollDetectorAxes(
bool *moving, detectorTowerAngleAxis *angleAxis,
detectorTowerLiftAxis *liftAxis, detectorTowerSupportAxis *supportAxis) {
// Return value for the poll
asynStatus pollStatus = asynSuccess;
@ -267,6 +273,8 @@ detectorTowerController::pollDetectorAxes(bool *moving,
asynStatus plStatus = asynSuccess;
char userMessage[MAXBUF_] = {0};
// User message which was created in one of the other axis methods
char oldUserMessage[MAXBUF_] = {0};
char response[MAXBUF_] = {0};
int nvals = 0;
@ -292,20 +300,26 @@ detectorTowerController::pollDetectorAxes(bool *moving,
double liftAdjustOriginHighLimit = 0.0;
double liftAdjustOriginLowLimit = 0.0;
double supportOrigin = 0.0;
double angleOrigin = 0.0;
double angleAdjustOriginHighLimit = 0.0;
double angleAdjustOriginLowLimit = 0.0;
double supportOrigin = 0.0;
int angleAxisNo = angleAxis->axisNo();
int liftAxisNo = liftAxis->axisNo();
int supportAxisNo = supportAxis->axisNo();
/*
For messages which in principle concern both axes, use the smaller of the
two indices.
For messages which in principle concern all axes, use the smallest index
*/
int comAxisNo = angleAxisNo > liftAxisNo ? liftAxisNo : angleAxisNo;
int comAxisNo = angleAxisNo;
if (comAxisNo > liftAxisNo) {
comAxisNo = liftAxisNo;
}
if (comAxisNo > supportAxisNo) {
comAxisNo = supportAxisNo;
}
// =========================================================================
@ -329,6 +343,11 @@ detectorTowerController::pollDetectorAxes(bool *moving,
paramLibAccessFailed(plStatus, "motorStatusProblem_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(motorStatusProblem(), false);
if (plStatus != asynSuccess) {
paramLibAccessFailed(plStatus, "motorStatusProblem_", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = angleAxis->setIntegerParam(motorStatusCommsError(), false);
if (plStatus != asynSuccess) {
@ -340,6 +359,11 @@ detectorTowerController::pollDetectorAxes(bool *moving,
paramLibAccessFailed(plStatus, "motorStatusCommsError_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(motorStatusCommsError(), false);
if (plStatus != asynSuccess) {
paramLibAccessFailed(plStatus, "motorStatusCommsError_", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// Read the previous motor positions
plStatus = angleAxis->motorPosition(&prevAngle);
@ -458,13 +482,9 @@ detectorTowerController::pollDetectorAxes(bool *moving,
}
resetCountPosState = false;
plStatus =
setStringParam(motorMessageText(), "Reset one of the tower axes.");
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_",
comAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
snprintf(userMessage, sizeof(userMessage),
"Reset one of the tower axes."
);
pollStatus = asynError;
break;
@ -504,12 +524,6 @@ detectorTowerController::pollDetectorAxes(bool *moving,
"Unknown state P358 = %d has been reached. Please call "
"the support.",
positionState);
plStatus = setStringParam(motorMessageText(), userMessage);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_",
comAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
pollStatus = asynError;
}
@ -627,12 +641,6 @@ detectorTowerController::pollDetectorAxes(bool *moving,
"Axis release was removed while moving. Try resetting the axis "
"and issue the move command again.");
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_",
comAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
pollStatus = asynError;
break;
@ -797,8 +805,13 @@ detectorTowerController::pollDetectorAxes(bool *moving,
getMsgPrintControl().resetCount(keyError, pasynUser());
}
// Update the parameter library for both axes
if (error != 0) {
// Update the parameter library for all axes
getStringParam(angleAxisNo, motorMessageText(), sizeof(oldUserMessage), oldUserMessage);
if (error != 0 || oldUserMessage[0] != '\0') {
plStatus = angleAxis->setIntegerParam(motorStatusProblem(), true);
if (plStatus != asynSuccess) {
@ -813,9 +826,17 @@ detectorTowerController::pollDetectorAxes(bool *moving,
liftAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
plStatus = supportAxis->setIntegerParam(motorStatusProblem(), true);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorStatusProblem_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
}
// Update the user message text
// Update the user message text, if one is available
if (userMessage[0] != '\0') {
plStatus = angleAxis->setStringParam(motorMessageText(), userMessage);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_", angleAxisNo,
@ -826,6 +847,13 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorMessageText_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setStringParam(motorMessageText(), userMessage);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
}
// Update the working position state PV
plStatus = angleAxis->setIntegerParam(positionStateRBV(), positionState);
@ -838,6 +866,12 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "positionStateRBV_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(positionStateRBV(), positionState);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "positionStateRBV_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// The axes are always enabled
plStatus = angleAxis->setIntegerParam(motorEnableRBV(), 1);
@ -850,6 +884,11 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorEnableRBV_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(motorEnableRBV(), 1);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorEnableRBV_", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// Are the axes currently moving?
plStatus = angleAxis->setIntegerParam(motorStatusMoving(), *moving);
@ -862,6 +901,12 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorStatusMoving_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(motorStatusMoving(), *moving);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorStatusMoving_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// Is the axis movement done?
plStatus = angleAxis->setIntegerParam(motorStatusDone(), !(*moving));
@ -874,8 +919,13 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorStatusDone_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setIntegerParam(motorStatusDone(), !(*moving));
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorStatusDone_", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// In which angleDir are the axes currently moving?
// In which direction are the axes currently moving?
plStatus = angleAxis->setIntegerParam(motorStatusDirection(), angleDir);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
@ -886,6 +936,13 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
}
// Using the lift direction for the support axis is done on purpose!
plStatus = supportAxis->setIntegerParam(motorStatusDirection(), liftDir);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// High limits from hardware
plStatus =
@ -900,6 +957,14 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorHighLimitFromDriver",
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
}
// Using the lift high limit for the support axis is done on purpose!
plStatus = setDoubleParam(supportAxisNo, motorHighLimitFromDriver(),
liftHighLimit);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorHighLimitFromDriver",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// Low limits from hardware
plStatus =
@ -914,6 +979,14 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorLowLimitFromDriver",
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
}
// Using the lift low limit for the support axis is done on purpose!
plStatus =
setDoubleParam(supportAxisNo, motorLowLimitFromDriver(), liftLowLimit);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorLowLimitFromDriver",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// Write the motor origin
plStatus = setDoubleParam(angleAxisNo, motorOrigin(), angleOrigin);
@ -926,11 +999,9 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorOrigin", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// Write the lift support origin motor
plStatus = setDoubleParam(liftAxisNo, liftSupportOrigin(), supportOrigin);
plStatus = setDoubleParam(supportAxisNo, motorOrigin(), supportOrigin);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "liftSupportOrigin", liftAxisNo,
return paramLibAccessFailed(plStatus, "supportOrigin", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
@ -949,6 +1020,15 @@ detectorTowerController::pollDetectorAxes(bool *moving,
return paramLibAccessFailed(plStatus, "motorOriginHighLimitFromDriver",
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
}
// Using the lift high limit for the support axis is done on purpose!
plStatus =
setDoubleParam(supportAxisNo, motorAdjustOriginHighLimitFromDriver(),
liftAdjustOriginHighLimit);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorOriginHighLimitFromDriver",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
// Origin adjustment low limit
plStatus =
@ -966,6 +1046,15 @@ detectorTowerController::pollDetectorAxes(bool *moving,
"motorAdjustOriginLowLimitFromDriver",
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
}
// Using the lift low limit for the support axis is done on purpose!
plStatus =
setDoubleParam(supportAxisNo, motorAdjustOriginLowLimitFromDriver(),
liftAdjustOriginLowLimit);
if (plStatus != asynSuccess) {
return paramLibAccessFailed(
plStatus, "motorAdjustOriginLowLimitFromDriver", supportAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// Axes positions
plStatus = angleAxis->setMotorPosition(angle);
@ -976,22 +1065,13 @@ detectorTowerController::pollDetectorAxes(bool *moving,
if (plStatus != asynSuccess) {
return plStatus;
}
// Something went wrong -> Report a status problem
if (pollStatus != asynSuccess) {
plStatus = angleAxis->setIntegerParam(motorStatusProblem(), true);
if (plStatus != asynSuccess) {
paramLibAccessFailed(plStatus, "motorStatusProblem_", angleAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = liftAxis->setIntegerParam(motorStatusProblem(), true);
if (plStatus != asynSuccess) {
paramLibAccessFailed(plStatus, "motorStatusProblem_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
// Using the lift position for the support axis is done on purpose!
plStatus = supportAxis->setMotorPosition(lift);
if (plStatus != asynSuccess) {
return plStatus;
}
// Update the parameter library
// Update the parameter library for all three axes
bool wantToPrint = false;
plStatus = angleAxis->callParamCallbacks();
@ -1009,6 +1089,7 @@ detectorTowerController::pollDetectorAxes(bool *moving,
if (wantToPrint) {
pollStatus = plStatus;
}
plStatus = liftAxis->callParamCallbacks();
wantToPrint = plStatus != asynSuccess;
if (getMsgPrintControl().shouldBePrinted(portName, liftAxisNo,
@ -1025,6 +1106,40 @@ detectorTowerController::pollDetectorAxes(bool *moving,
pollStatus = plStatus;
}
plStatus = supportAxis->callParamCallbacks();
wantToPrint = plStatus != asynSuccess;
if (getMsgPrintControl().shouldBePrinted(portName, supportAxisNo,
__PRETTY_FUNCTION__, __LINE__,
wantToPrint, pasynUser())) {
asynPrint(pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\ncallParamCallbacks failed with %s.%s\n",
portName, supportAxisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(pollStatus),
getMsgPrintControl().getSuffix());
}
if (wantToPrint) {
pollStatus = plStatus;
}
// Reset the message text for the next poll cycle AFTER updating the PVs
plStatus = angleAxis->setStringParam(motorMessageText(), "");
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_", angleAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = liftAxis->setStringParam(motorMessageText(), "");
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_", liftAxisNo,
__PRETTY_FUNCTION__, __LINE__);
}
plStatus = supportAxis->setStringParam(motorMessageText(), "");
if (plStatus != asynSuccess) {
return paramLibAccessFailed(plStatus, "motorMessageText_",
supportAxisNo, __PRETTY_FUNCTION__,
__LINE__);
}
return pollStatus;
}

View File

@ -10,6 +10,7 @@
#define detectorTowerController_H
#include "detectorTowerAngleAxis.h"
#include "detectorTowerLiftAxis.h"
#include "detectorTowerSupportAxis.h"
#include "turboPmacController.h"
class detectorTowerController : public turboPmacController {
@ -97,6 +98,24 @@ class detectorTowerController : public turboPmacController {
*/
detectorTowerLiftAxis *getDetectorTowerLiftAxis(int axisNo);
/**
* @brief Get the axis object
*
* @param pasynUser Specify the axis via the asynUser
* @return detectorTowerSupportAxis* If no axis could be found,
* this is a nullptr
*/
detectorTowerSupportAxis *getDetectorTowerSupportAxis(asynUser *pasynUser);
/**
* @brief Get the axis object
*
* @param axisNo Specify the axis via its index
* @return detectorTowerSupportAxis* If no axis could be found,
* this is a nullptr
*/
detectorTowerSupportAxis *getDetectorTowerSupportAxis(int axisNo);
/**
* @brief Common poll function for both lift and angle axes
*
@ -106,7 +125,8 @@ class detectorTowerController : public turboPmacController {
* @return asynStatus
*/
asynStatus pollDetectorAxes(bool *moving, detectorTowerAngleAxis *angleAxis,
detectorTowerLiftAxis *liftAxis);
detectorTowerLiftAxis *liftAxis,
detectorTowerSupportAxis *supportAxis);
// Accessors for additional PVs
int positionStateRBV() { return positionStateRBV_; }
@ -120,8 +140,6 @@ class detectorTowerController : public turboPmacController {
int motorAdjustOriginLowLimitFromDriver() {
return motorAdjustOriginLowLimitFromDriver_;
}
int liftSupportOrigin() { return liftSupportOrigin_; }
int liftSupportAdjustOrigin() { return liftSupportAdjustOrigin_; }
private:
// Indices of additional PVs
@ -133,9 +151,7 @@ class detectorTowerController : public turboPmacController {
int motorAdjustOrigin_;
int motorAdjustOriginHighLimitFromDriver_;
int motorAdjustOriginLowLimitFromDriver_;
int liftSupportOrigin_;
int liftSupportAdjustOrigin_;
#define LAST_detectorTower_PARAM liftSupportAdjustOrigin_
#define LAST_detectorTower_PARAM motorAdjustOriginLowLimitFromDriver_
};
#define NUM_detectorTower_DRIVER_PARAMS \
(&LAST_detectorTower_PARAM - &FIRST_detectorTower_PARAM + 1)

View File

@ -30,21 +30,22 @@ static void epicsInithookFunction(initHookState iState) {
}
detectorTowerLiftAxis::detectorTowerLiftAxis(detectorTowerController *pC,
int axisNo)
int axisNo,
detectorTowerAngleAxis *angleAxis)
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
/*
The superclass constructor sinqAxis calls in turn its superclass constructor
asynMotorAxis. In the latter, a pointer to the constructed object this is
stored inside the array pAxes_:
The superclass constructor sinqAxis calls in turn its superclass
constructor asynMotorAxis. In the latter, a pointer to the constructed
object this is stored inside the array pAxes_:
pC->pAxes_[axisNo] = this;
Therefore, the axes are managed by the controller pC. If axisNo is out of
bounds, asynMotorAxis prints an error (see
Therefore, the axes are managed by the controller pC. If axisNo is out
of bounds, asynMotorAxis prints an error (see
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp,
line 40). However, we want the IOC creation to stop completely, since this
is a configuration error.
line 40). However, we want the IOC creation to stop completely, since
this is a configuration error.
*/
if (axisNo >= pC->numAxes()) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
@ -56,7 +57,8 @@ detectorTowerLiftAxis::detectorTowerLiftAxis(detectorTowerController *pC,
exit(-1);
}
// Register the hook function during construction of the first axis object
// Register the hook function during construction of the first axis
// object
if (axes.empty()) {
initHookRegister(&epicsInithookFunction);
}
@ -64,11 +66,14 @@ detectorTowerLiftAxis::detectorTowerLiftAxis(detectorTowerController *pC,
// Collect all axes into this list which will be used in the hook
// function
axes.push_back(this);
angleAxis_ = angleAxis;
angleAxis->liftAxis_ = this;
}
detectorTowerLiftAxis::~detectorTowerLiftAxis(void) {
// Since the controller memory is managed somewhere else, we don't need to
// clean up the pointer pC here.
// Since the controller memory is managed somewhere else, we don't need
// to clean up the pointer pC here.
}
asynStatus detectorTowerLiftAxis::init() {
@ -76,6 +81,9 @@ asynStatus detectorTowerLiftAxis::init() {
// Local variable declaration
asynStatus status = asynSuccess;
double motorRecResolution = 0.0;
char response[pC_->MAXBUF_] = {0};
int positionState = 0;
int nvals = 0;
// The parameter library takes some time to be initialized. Therefore we
// wait until the status is not asynParamUndefined anymore.
@ -109,7 +117,22 @@ asynStatus detectorTowerLiftAxis::init() {
__PRETTY_FUNCTION__, __LINE__);
}
return asynSuccess;
// Check if we are currently in the changer position and update the PV
// accordingly
status = pC_->writeRead(axisNo_, "P358", response, 1);
nvals = sscanf(response, "%d", &positionState);
if (nvals != 1) {
return pC_->couldNotParseResponse("P358", response, axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return callParamCallbacks();
}
// Perform the actual poll
@ -118,8 +141,10 @@ asynStatus detectorTowerLiftAxis::poll(bool *moving) {
// Is this axis the one with the smallest index?
// If not, just read out the movement status and update *moving
if (axisNo() < angleAxis_->axisNo()) {
status = pC_->pollDetectorAxes(moving, angleAxis_, this);
if (axisNo() < angleAxis()->axisNo() &&
axisNo() < angleAxis()->supportAxis()->axisNo()) {
status = pC_->pollDetectorAxes(moving, angleAxis(), this,
angleAxis()->supportAxis());
} else {
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
(int *)moving);
@ -156,14 +181,16 @@ asynStatus detectorTowerLiftAxis::doMove(double position, int relative,
}
// Signal to the deferredMovementCollectorLoop (of the
// detectorTowerAngleAxis) that a movement should be started to the defined
// target position.
// detectorTowerAngleAxis) that a movement should be started to the
// defined target position.
targetPosition_ = position * motorRecResolution;
angleAxis_->receivedTarget_ = true;
return asynSuccess;
}
asynStatus detectorTowerLiftAxis::reset() { return angleAxis()->reset(); };
asynStatus detectorTowerLiftAxis::stop(double acceleration) {
// Status of read-write-operations of ASCII commands to the controller
@ -179,11 +206,11 @@ asynStatus detectorTowerLiftAxis::stop(double acceleration) {
rwStatus = pC_->writeRead(axisNo_, "P350=8", response, 0);
if (rwStatus != asynSuccess) {
asynPrint(
pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
"failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nStopping "
"the movement "
"failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
if (plStatus != asynSuccess) {
@ -197,7 +224,9 @@ asynStatus detectorTowerLiftAxis::stop(double acceleration) {
return rwStatus;
}
asynStatus detectorTowerLiftAxis::reset() { return angleAxis_->reset(); };
asynStatus detectorTowerLiftAxis::readEncoderType() {
return angleAxis()->readEncoderType();
}
asynStatus detectorTowerLiftAxis::adjustOrigin(double newOrigin) {
@ -251,58 +280,4 @@ asynStatus detectorTowerLiftAxis::adjustOrigin(double newOrigin) {
}
return status;
}
asynStatus detectorTowerLiftAxis::adjustSupportOrigin(double newOrigin) {
asynStatus status = asynSuccess;
char command[pC_->MAXBUF_] = {0};
char response[pC_->MAXBUF_] = {0};
int positionState = 0;
// =========================================================================
status =
pC_->getIntegerParam(axisNo(), pC_->positionStateRBV(), &positionState);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
// If the axis is in changer position, it must be moved into working
// position before any move can be started.
bool isInChangerPos = positionState == 2 || positionState == 3;
if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__,
isInChangerPos, pC_->pasynUser())) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
"moved because it is moving from working to changer "
"position, is in changer position or is moving from changer "
"to working position.%s\n",
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__,
pC_->getMsgPrintControl().getSuffix());
}
// Set the new adjust for the lift axis
snprintf(command, sizeof(command), "Q656=%lf P350=6", newOrigin);
// We don't expect an answer
status = pC_->writeRead(axisNo_, command, response, 0);
if (status != asynSuccess) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nSetting new "
"lift origin %lf failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
newOrigin);
status = setIntegerParam(pC_->motorStatusProblem(), true);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
return status;
}
}

View File

@ -16,7 +16,8 @@ class detectorTowerLiftAxis : public turboPmacAxis {
* @param pController Pointer to the associated controller
* @param axisNo Index of the axis
*/
detectorTowerLiftAxis(detectorTowerController *pController, int axisNo);
detectorTowerLiftAxis(detectorTowerController *pController, int axisNo,
detectorTowerAngleAxis *angleAxis);
/**
* @brief Destroy the turboPmacAxis
@ -69,9 +70,9 @@ class detectorTowerLiftAxis : public turboPmacAxis {
double max_velocity, double acceleration);
/**
* @brief Call the reset function of the associated
* `detectorTowerAngleAxis`.
* @brief Calls the `reset` function of the associated lift axis.
*
* @param on
* @return asynStatus
*/
asynStatus reset();
@ -106,6 +107,13 @@ class detectorTowerLiftAxis : public turboPmacAxis {
*/
detectorTowerAngleAxis *angleAxis() { return angleAxis_; }
/**
* @brief This axis type has an absolute encoder by default
*
* @return asynStatus
*/
asynStatus readEncoderType();
protected:
detectorTowerController *pC_;
detectorTowerAngleAxis *angleAxis_;

View File

@ -0,0 +1,232 @@
#include "detectorTowerSupportAxis.h"
#include "detectorTowerAngleAxis.h"
#include "detectorTowerController.h"
#include "turboPmacController.h"
#include <epicsExport.h>
#include <errlog.h>
#include <iocsh.h>
/*
Contains all instances of detectorTowerSupportAxis which have been created and
is used in the initialization hook function.
*/
static std::vector<detectorTowerSupportAxis *> axes;
/**
* @brief Hook function to perform certain actions during the IOC initialization
*
* @param iState
*/
static void epicsInithookFunction(initHookState iState) {
if (iState == initHookAfterDatabaseRunning) {
// Iterate through all axes of each and call the initialization method
// on each one of them.
for (std::vector<detectorTowerSupportAxis *>::iterator itA =
axes.begin();
itA != axes.end(); ++itA) {
detectorTowerSupportAxis *axis = *itA;
axis->init();
}
}
}
detectorTowerSupportAxis::detectorTowerSupportAxis(
detectorTowerController *pC, int axisNo, detectorTowerAngleAxis *angleAxis)
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
/*
The superclass constructor sinqAxis calls in turn its superclass constructor
asynMotorAxis. In the latter, a pointer to the constructed object this is
stored inside the array pAxes_:
pC->pAxes_[axisNo] = this;
Therefore, the axes are managed by the controller pC. If axisNo is out of
bounds, asynMotorAxis prints an error (see
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp,
line 40). However, we want the IOC creation to stop completely, since this
is a configuration error.
*/
if (axisNo >= pC->numAxes()) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d: FATAL ERROR: "
"Axis index %d must be smaller than the total number of axes "
"%d",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axisNo_, pC->numAxes());
exit(-1);
}
// Register the hook function during construction of the first axis object
if (axes.empty()) {
initHookRegister(&epicsInithookFunction);
}
// Collect all axes into this list which will be used in the hook
// function
axes.push_back(this);
// Link the axes to each other
angleAxis_ = angleAxis;
angleAxis_->supportAxis_ = this;
}
detectorTowerSupportAxis::~detectorTowerSupportAxis(void) {
// Since the controller memory is managed somewhere else, we don't need to
// clean up the pointer pC here.
}
asynStatus detectorTowerSupportAxis::init() {
// Local variable declaration
asynStatus status = asynSuccess;
double motorRecResolution = 0.0;
char response[pC_->MAXBUF_] = {0};
int positionState = 0;
int nvals = 0;
// The parameter library takes some time to be initialized. Therefore we
// wait until the status is not asynParamUndefined anymore.
time_t now = time(NULL);
time_t maxInitTime = 60;
while (1) {
status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution);
if (status == asynParamUndefined) {
if (now + maxInitTime < time(NULL)) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d\nInitializing the parameter library failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
__LINE__);
return asynError;
}
} else if (status == asynSuccess) {
break;
} else if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
// Initialize the motorStatusMoving flag
status = setIntegerParam(pC_->motorStatusMoving(), 0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
// Check if we are currently in the changer position and update the PV
// accordingly
status = pC_->writeRead(axisNo_, "P358", response, 1);
nvals = sscanf(response, "%d", &positionState);
if (nvals != 1) {
return pC_->couldNotParseResponse("P358", response, axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return callParamCallbacks();
}
// Perform the actual poll
asynStatus detectorTowerSupportAxis::poll(bool *moving) {
asynStatus status = asynSuccess;
// Is this axis the one with the smallest index?
// If not, just read out the movement status and update *moving
if (axisNo() < angleAxis()->liftAxis()->axisNo() &&
axisNo() < angleAxis()->axisNo()) {
status = pC_->pollDetectorAxes(moving, angleAxis(),
angleAxis()->liftAxis(), this);
} else {
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
(int *)moving);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
wasMoving_ = *moving;
return status;
}
asynStatus detectorTowerSupportAxis::doPoll(bool *moving) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nThe doPoll method "
"of this axis type should not be reachable. This is a bug.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
asynStatus detectorTowerSupportAxis::stop(double acceleration) {
return angleAxis()->stop(acceleration);
}
asynStatus detectorTowerSupportAxis::reset() { return angleAxis()->reset(); };
asynStatus detectorTowerSupportAxis::readEncoderType() {
return angleAxis()->readEncoderType();
}
asynStatus detectorTowerSupportAxis::adjustOrigin(double newOrigin) {
asynStatus status = asynSuccess;
char command[pC_->MAXBUF_] = {0};
char response[pC_->MAXBUF_] = {0};
int positionState = 0;
// =========================================================================
status =
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
// If the axis is in changer position, it must be moved into working
// position before any move can be started.
bool isInChangerPos = positionState == 2 || positionState == 3;
if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
isInChangerPos, pC_->pasynUser())) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
"moved because it is moving from working to changer "
"position, is in changer position or is moving from changer "
"to working position.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->getMsgPrintControl().getSuffix());
}
// Set the new adjust for the lift axis
snprintf(command, sizeof(command), "Q656=%lf P350=6", newOrigin);
// We don't expect an answer
status = pC_->writeRead(axisNo_, command, response, 0);
if (status != asynSuccess) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nSetting new "
"lift origin %lf failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
newOrigin);
status = setIntegerParam(pC_->motorStatusProblem(), true);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
return status;
}

View File

@ -0,0 +1,127 @@
#ifndef detectorTowerSupportAxis_H
#define detectorTowerSupportAxis_H
#include "turboPmacAxis.h"
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
// https://en.cppreference.com/w/cpp/language/class.
class detectorTowerController;
class detectorTowerAngleAxis;
/**
* @brief Passive axis which is mostly controlled indirectly by the hardware
*
*/
class detectorTowerSupportAxis : public turboPmacAxis {
public:
/**
* @brief Construct a new detectorTowerSupportAxis
*
* @param pController Pointer to the associated controller
* @param axisNo Index of the axis
* @param liftAxis Pointer to the associated lift axis
*/
detectorTowerSupportAxis(detectorTowerController *pController, int axisNo,
detectorTowerAngleAxis *angleAxis);
/**
* @brief Destroy the detectorTowerSupportAxis
*
*/
virtual ~detectorTowerSupportAxis();
/**
* @brief Readout of some values from the controller at IOC startup
*
* @return asynStatus
*/
asynStatus init();
/**
* @brief Implementation of the `stop` function from asynMotorAxis
*
* @param acceleration Acceleration ACCEL from the motor record. This
* value is currently not used.
* @return asynStatus
*/
asynStatus stop(double acceleration);
/**
* @brief Poll all detector tower axes, if this axis is the one with the
* smallest index.
*
* We do not use the doPoll framework from sinqMotor here on purpose, since
* we want to e.g. reset the motorStatusProblem for all axes at once at the
* beginning of the poll.
*
* @param moving
* @return asynStatus
*/
asynStatus poll(bool *moving);
asynStatus doPoll(bool *moving);
/**
* @brief This axis cannot be moved directly
*
* @param position
* @param relative
* @param min_velocity
* @param max_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
double max_velocity, double acceleration) {
return asynSuccess;
}
/**
* @brief If the input value is true, move the axis into working position,
* otherwise into changer position.
*
* @return asynStatus
*/
asynStatus toggleWorkingChangerState(bool toChangingPosition);
/**
* @brief Calls the `reset` function of the associated lift axis.
*
* @param on
* @return asynStatus
*/
asynStatus reset();
/**
* @brief Move the axis to the position `newOrigin` and recalibrate
*
* When calling this function, the angle axis moves to `newOrigin` and the
* hardware sets this position as the new origin.
*
* @param origin
* @return asynStatus
*/
asynStatus adjustOrigin(double newOrigin);
/**
* @brief Return a pointer to the associated angle axis
*
* @return detectorTowerAngleAxis*
*/
detectorTowerAngleAxis *angleAxis() { return angleAxis_; }
/**
* @brief This axis type has an absolute encoder by default
*
* @return asynStatus
*/
asynStatus readEncoderType();
protected:
detectorTowerController *pC_;
detectorTowerAngleAxis *angleAxis_;
private:
friend class detectorTowerLiftAxis;
};
#endif