From 203bb9475fb38de226a3c22ce37a72d1c2d5c42a Mon Sep 17 00:00:00 2001 From: smathis Date: Wed, 14 May 2025 16:39:16 +0200 Subject: [PATCH] Updated turboPmac dependency to 0.15.1 --- Makefile | 6 + db/detectorTower.db | 41 ---- src/detectorTowerAngleAxis.cpp | 128 ++++++++----- src/detectorTowerAngleAxis.h | 21 ++- src/detectorTowerController.cpp | 315 +++++++++++++++++++++---------- src/detectorTowerController.h | 28 ++- src/detectorTowerLiftAxis.cpp | 129 +++++-------- src/detectorTowerLiftAxis.h | 14 +- src/detectorTowerSupportAxis.cpp | 232 +++++++++++++++++++++++ src/detectorTowerSupportAxis.h | 127 +++++++++++++ turboPmac | 2 +- 11 files changed, 757 insertions(+), 286 deletions(-) create mode 100644 src/detectorTowerSupportAxis.cpp create mode 100644 src/detectorTowerSupportAxis.h diff --git a/Makefile b/Makefile index 4ad5a22..b8b305a 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/db/detectorTower.db b/db/detectorTower.db index 95b5b91..b102fc8 100644 --- a/db/detectorTower.db +++ b/db/detectorTower.db @@ -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. diff --git a/src/detectorTowerAngleAxis.cpp b/src/detectorTowerAngleAxis.cpp index 8447e8a..594e0cb 100644 --- a/src/detectorTowerAngleAxis.cpp +++ b/src/detectorTowerAngleAxis.cpp @@ -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); } // ============================================================================= diff --git a/src/detectorTowerAngleAxis.h b/src/detectorTowerAngleAxis.h index 6e017e7..b71772e 100644 --- a/src/detectorTowerAngleAxis.h +++ b/src/detectorTowerAngleAxis.h @@ -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 diff --git a/src/detectorTowerController.cpp b/src/detectorTowerController.cpp index a760fd0..3fc0929 100644 --- a/src/detectorTowerController.cpp +++ b/src/detectorTowerController.cpp @@ -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(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(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(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; } diff --git a/src/detectorTowerController.h b/src/detectorTowerController.h index f31d9d7..7dfc931 100644 --- a/src/detectorTowerController.h +++ b/src/detectorTowerController.h @@ -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) diff --git a/src/detectorTowerLiftAxis.cpp b/src/detectorTowerLiftAxis.cpp index ae51463..f94e851 100644 --- a/src/detectorTowerLiftAxis.cpp +++ b/src/detectorTowerLiftAxis.cpp @@ -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; -} +} \ No newline at end of file diff --git a/src/detectorTowerLiftAxis.h b/src/detectorTowerLiftAxis.h index a85ce76..1d6337f 100644 --- a/src/detectorTowerLiftAxis.h +++ b/src/detectorTowerLiftAxis.h @@ -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_; diff --git a/src/detectorTowerSupportAxis.cpp b/src/detectorTowerSupportAxis.cpp new file mode 100644 index 0000000..ef9e17b --- /dev/null +++ b/src/detectorTowerSupportAxis.cpp @@ -0,0 +1,232 @@ +#include "detectorTowerSupportAxis.h" +#include "detectorTowerAngleAxis.h" +#include "detectorTowerController.h" +#include "turboPmacController.h" +#include +#include +#include + +/* +Contains all instances of detectorTowerSupportAxis which have been created and +is used in the initialization hook function. + */ +static std::vector 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::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; +} \ No newline at end of file diff --git a/src/detectorTowerSupportAxis.h b/src/detectorTowerSupportAxis.h new file mode 100644 index 0000000..8be316d --- /dev/null +++ b/src/detectorTowerSupportAxis.h @@ -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 diff --git a/turboPmac b/turboPmac index 5298b5e..2f83060 160000 --- a/turboPmac +++ b/turboPmac @@ -1 +1 @@ -Subproject commit 5298b5ef6986dcfee22d8272fb8c059ef78e61f6 +Subproject commit 2f83060ec145636ad949d89534c129453b1b06e6