From d837a8545b6d99f1529ad6e63f7eccae351d48dd Mon Sep 17 00:00:00 2001 From: smathis Date: Thu, 17 Apr 2025 16:30:33 +0200 Subject: [PATCH] Adjusted driver with auxiliary axes offsets --- .clang-format | 246 ++++++++++++++++++ Makefile | 9 +- README.md | 8 +- db/detectorTower.db | 9 + ...xis.cpp => detectorTowerAuxiliaryAxis.cpp} | 45 ++-- ...aryAxis.h => detectorTowerAuxiliaryAxis.h} | 11 +- src/detectorTowerAxis.cpp | 209 +++++++++------ src/detectorTowerAxis.h | 21 +- src/detectorTowerController.cpp | 87 +++++-- src/detectorTowerController.h | 34 ++- 10 files changed, 534 insertions(+), 145 deletions(-) create mode 100644 .clang-format rename src/{auxiliaryAxis.cpp => detectorTowerAuxiliaryAxis.cpp} (85%) rename src/{auxiliaryAxis.h => detectorTowerAuxiliaryAxis.h} (87%) diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..da3868c --- /dev/null +++ b/.clang-format @@ -0,0 +1,246 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/Makefile b/Makefile index 65c8c91..dd42e05 100644 --- a/Makefile +++ b/Makefile @@ -13,15 +13,18 @@ REQUIRED+=motorBase motorBase_VERSION=7.2.2 # Specify the version of turboPmac we want to build against -turboPmac_VERSION=0.10.0 +sinqMotor_VERSION=mathis_s + +# Specify the version of turboPmac we want to build against +turboPmac_VERSION=mathis_s # These headers allow to depend on this library for derived drivers. -HEADERS += src/auxiliaryAxis.h +HEADERS += src/detectorTowerAuxiliaryAxis.h HEADERS += src/detectorTowerAxis.h HEADERS += src/detectorTowerController.h # Source files to build -SOURCES += src/auxiliaryAxis.cpp +SOURCES += src/detectorTowerAuxiliaryAxis.cpp SOURCES += src/detectorTowerAxis.cpp SOURCES += src/detectorTowerController.cpp diff --git a/README.md b/README.md index bd6e83d..23f845b 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,17 @@ This is a driver for the detector tower which is based on the Turbo PMAC driver (https://git.psi.ch/sinq-epics-modules/turboPmac). It consists of the following three objects: - `detectorTowerAxis`: This is a virtual axis which controls multiple physical motors in order to provide a synchronized movement. - `detectorTowerController`: This is an expanded variant of `turboPmacController` provided by the Turbo PMAC library linked above.It is needed to operate a `detectorTowerAxis`, but it can also be used to operate a "normal" `turboPmacAxis`. -- `auxiliaryAxis`: This is an auxiliary axis type attached to the main detector axis. Multiple instances of these axes are constructed automatically when creating a `detectorTowerAxis`. +- `detectorTowerAuxiliaryAxis`: This is an auxiliary axis type attached to the main detector axis. Multiple instances of these axes are constructed automatically when creating a `detectorTowerAxis`. The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one. ## User guide -The centerpiece of this driver is the `detectorTowerAxis`, which controls the angle of the detector flight tube. Creating an instance of this axis type also creates multiple so-called `auxiliaryAxis`, which are used to perform secondary movements. +The centerpiece of this driver is the `detectorTowerAxis`, which controls the angle of the detector flight tube. Creating an instance of this axis type also creates multiple so-called `detectorTowerAuxiliaryAxis`, which are used to perform secondary movements. The utilities provided in the `utils` folder of https://git.psi.ch/sinq-epics-modules/turboPmac work with this driver as well. +TODO: How to start combined movement + ### Usage in IOC shell detectorTower exports the following IOC shell functions: @@ -99,7 +101,7 @@ Note that the speed of the detector tower axes 1, 2 and 3 cannot be set. Setting The code is designed around the `detectorTowerAxis`, which controls the angle of the beam guide and acts as a "master" axis. Other movements are realized as auxiliary axes (e.g. for the vertical lift offset and the tilt offset). The `detectorTowerAxis` has pointers to all associated auxiliary axes and (as described above) its IOC shell constructor also builds the associated auxiliary axes. -The `doPoll` implementation for `detectorTowerAxis` queries the status of both the `detectorTowerAxis` itself and all associated auxiliary axes. If any of the axes is moving, the `detectorTowerAxis` is set to "moving" as well. In turn, the `doPoll` implementation of a `auxiliaryAxis` checks if its associated `detectorTowerAxis` is moving and sets its own movement status accordingly. +The `doPoll` implementation for `detectorTowerAxis` queries the status of both the `detectorTowerAxis` itself and all associated auxiliary axes. If any of the axes is moving, the `detectorTowerAxis` is set to "moving" as well. In turn, the `doPoll` implementation of a `detectorTowerAuxiliaryAxis` checks if its associated `detectorTowerAxis` is moving and sets its own movement status accordingly. The `detectorTowerController` is a thin wrapper around a `turboPmacController` which overwrites the `readInt32` and `writeInt32` in order to support the PVs "$(INSTR)$(M):ChangeState", "$(INSTR)$(M):PositionStateRBV" and "$(INSTR)$(M):ChangingStateRBV". Any calls to these two methods not concerning the aforementioned PVs are directly forwarded to `turboPmacController::readInt32` / `turboPmacController::writeInt32`. diff --git a/db/detectorTower.db b/db/detectorTower.db index 7d878df..2383154 100644 --- a/db/detectorTower.db +++ b/db/detectorTower.db @@ -36,3 +36,12 @@ record(longout, "$(INSTR)$(M):ChangingStateRBV_int") { field(DOL, "$(INSTR)$(M):ChangingStateRBV CP") field(OMSL, "closed_loop") } + +# Set an additional offset to the target position of an auxiliary axis +# For all other axis types, writing to this parameter does nothing. +record(ao, "$(INSTR)$(M):TargetOffset") { + field(DTYP, "asynFloat64") + field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_TARGET_OFFSET") + field(PINI, "YES") + field(VAL, "0") +} \ No newline at end of file diff --git a/src/auxiliaryAxis.cpp b/src/detectorTowerAuxiliaryAxis.cpp similarity index 85% rename from src/auxiliaryAxis.cpp rename to src/detectorTowerAuxiliaryAxis.cpp index 58b6242..8e54f63 100644 --- a/src/auxiliaryAxis.cpp +++ b/src/detectorTowerAuxiliaryAxis.cpp @@ -1,4 +1,4 @@ -#include "auxiliaryAxis.h" +#include "detectorTowerAuxiliaryAxis.h" #include "detectorTowerAxis.h" #include "detectorTowerController.h" #include "turboPmacController.h" @@ -7,10 +7,10 @@ #include /* -Contains all instances of auxiliaryAxis which have been created and is used -in the initialization hook function. +Contains all instances of detectorTowerAuxiliaryAxis which have been created and +is used in the initialization hook function. */ -static std::vector axes; +static std::vector axes; /** * @brief Hook function to perform certain actions during the IOC initialization @@ -21,15 +21,17 @@ 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(); + for (std::vector::iterator itA = + axes.begin(); itA != axes.end(); ++itA) { - auxiliaryAxis *axis = *itA; + detectorTowerAuxiliaryAxis *axis = *itA; axis->init(); } } } -auxiliaryAxis::auxiliaryAxis(detectorTowerController *pC, int axisNo) +detectorTowerAuxiliaryAxis::detectorTowerAuxiliaryAxis( + detectorTowerController *pC, int axisNo) : turboPmacAxis(pC, axisNo, false), pC_(pC) { /* @@ -46,7 +48,7 @@ auxiliaryAxis::auxiliaryAxis(detectorTowerController *pC, int axisNo) is a configuration error. */ if (axisNo >= pC->numAxes()) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + 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", @@ -65,12 +67,12 @@ auxiliaryAxis::auxiliaryAxis(detectorTowerController *pC, int axisNo) axes.push_back(this); } -auxiliaryAxis::~auxiliaryAxis(void) { +detectorTowerAuxiliaryAxis::~detectorTowerAuxiliaryAxis(void) { // Since the controller memory is managed somewhere else, we don't need to // clean up the pointer pC here. } -asynStatus auxiliaryAxis::init() { +asynStatus detectorTowerAuxiliaryAxis::init() { // Local variable declaration asynStatus status = asynSuccess; @@ -85,7 +87,7 @@ asynStatus auxiliaryAxis::init() { &motorRecResolution); if (status == asynParamUndefined) { if (now + maxInitTime < time(NULL)) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line " "%d\nInitializing the parameter library failed.\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, @@ -104,7 +106,7 @@ asynStatus auxiliaryAxis::init() { } // Perform the actual poll -asynStatus auxiliaryAxis::doPoll(bool *moving) { +asynStatus detectorTowerAuxiliaryAxis::doPoll(bool *moving) { // Return value for the poll asynStatus poll_status = asynSuccess; @@ -167,8 +169,8 @@ asynStatus auxiliaryAxis::doPoll(bool *moving) { bool wantToPrint = pl_status != asynSuccess; if (pC_->getMsgPrintControl().shouldBePrinted( pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, wantToPrint, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line " "%d:\ncallParamCallbacks failed with %s.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -184,9 +186,10 @@ asynStatus auxiliaryAxis::doPoll(bool *moving) { return poll_status; } -asynStatus auxiliaryAxis::doMove(double position, int relative, - double min_velocity, double max_velocity, - double acceleration) { +asynStatus detectorTowerAuxiliaryAxis::doMove(double position, int relative, + double min_velocity, + double max_velocity, + double acceleration) { double motorRecResolution = 0.0; asynStatus pl_status = pC_->getDoubleParam( @@ -205,7 +208,7 @@ asynStatus auxiliaryAxis::doMove(double position, int relative, return asynSuccess; } -asynStatus auxiliaryAxis::stop(double acceleration) { +asynStatus detectorTowerAuxiliaryAxis::stop(double acceleration) { // Status of read-write-operations of ASCII commands to the controller asynStatus rw_status = asynSuccess; @@ -213,7 +216,7 @@ asynStatus auxiliaryAxis::stop(double acceleration) { // Status of parameter library operations asynStatus pl_status = asynSuccess; - char response[pC_->MAXBUF_]; + char response[pC_->MAXBUF_] = {0}; // ========================================================================= @@ -221,7 +224,7 @@ asynStatus auxiliaryAxis::stop(double acceleration) { if (rw_status != asynSuccess) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nStopping the movement " "failed.\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); @@ -238,4 +241,4 @@ asynStatus auxiliaryAxis::stop(double acceleration) { return rw_status; } -asynStatus auxiliaryAxis::reset() { return dTA_->reset(); }; +asynStatus detectorTowerAuxiliaryAxis::reset() { return dTA_->reset(); }; diff --git a/src/auxiliaryAxis.h b/src/detectorTowerAuxiliaryAxis.h similarity index 87% rename from src/auxiliaryAxis.h rename to src/detectorTowerAuxiliaryAxis.h index 5c8d54f..1d11cb0 100644 --- a/src/auxiliaryAxis.h +++ b/src/detectorTowerAuxiliaryAxis.h @@ -1,5 +1,5 @@ -#ifndef auxiliaryAxis_H -#define auxiliaryAxis_H +#ifndef detectorTowerAuxiliaryAxis_H +#define detectorTowerAuxiliaryAxis_H #include "turboPmacAxis.h" // Forward declaration of the controller class to resolve the cyclic dependency @@ -8,7 +8,7 @@ class detectorTowerController; class detectorTowerAxis; -class auxiliaryAxis : public turboPmacAxis { +class detectorTowerAuxiliaryAxis : public turboPmacAxis { public: /** * @brief Construct a new detectorTowerAxis @@ -16,13 +16,14 @@ class auxiliaryAxis : public turboPmacAxis { * @param pController Pointer to the associated controller * @param axisNo Index of the axis */ - auxiliaryAxis(detectorTowerController *pController, int axisNo); + detectorTowerAuxiliaryAxis(detectorTowerController *pController, + int axisNo); /** * @brief Destroy the turboPmacAxis * */ - virtual ~auxiliaryAxis(); + virtual ~detectorTowerAuxiliaryAxis(); /** * @brief Readout of some values from the controller at IOC startup diff --git a/src/detectorTowerAxis.cpp b/src/detectorTowerAxis.cpp index b2a8a19..829eadc 100644 --- a/src/detectorTowerAxis.cpp +++ b/src/detectorTowerAxis.cpp @@ -47,9 +47,10 @@ static void deferredMovementCollectorLoop(void *drvPvt) { } } -detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo, - auxiliaryAxis *liftOffsetAxis, - auxiliaryAxis *tiltOffsetAxis) +detectorTowerAxis::detectorTowerAxis( + detectorTowerController *pC, int axisNo, + detectorTowerAuxiliaryAxis *liftZeroCorrAxis, + detectorTowerAuxiliaryAxis *tiltZeroCorrAxis) : turboPmacAxis(pC, axisNo, false), pC_(pC) { /* @@ -66,7 +67,7 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo, is a configuration error. */ if (axisNo >= pC->numAxes()) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + 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", @@ -81,10 +82,13 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo, receivedTarget_ = false; startingDeferredMovement_ = false; deferredMovementWait_ = 0.1; // seconds - liftOffsetAxis_ = liftOffsetAxis; - tiltOffsetAxis_ = tiltOffsetAxis; - liftOffsetAxis->dTA_ = this; - tiltOffsetAxis->dTA_ = this; + liftZeroCorrAxis_ = liftZeroCorrAxis; + tiltZeroCorrAxis_ = tiltZeroCorrAxis; + liftZeroCorrAxis->dTA_ = this; + tiltZeroCorrAxis->dTA_ = this; + + // Will be populated in the init() method + beamRadius_ = 0.0; // Register the hook function during construction of the first axis object if (axes.empty()) { @@ -116,6 +120,8 @@ asynStatus detectorTowerAxis::init() { // Local variable declaration asynStatus status = asynSuccess; double motorRecResolution = 0.0; + char response[pC_->MAXBUF_] = {0}; + int nvals = 0; // The parameter library takes some time to be initialized. Therefore we // wait until the status is not asynParamUndefined anymore. @@ -126,7 +132,7 @@ asynStatus detectorTowerAxis::init() { &motorRecResolution); if (status == asynParamUndefined) { if (now + maxInitTime < time(NULL)) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis " "%ddeferredMovementCollectorLoop => %s, line " "%d\nInitializing the parameter library failed.\n", @@ -143,10 +149,22 @@ asynStatus detectorTowerAxis::init() { } } + // Read the detector radius + const char *command = "RADIUS"; + status = pC_->writeRead(axisNo_, command, response, 10); + if (status != asynSuccess) { + return status; + } + + nvals = sscanf(response, "%lf", &beamRadius_); + if (nvals != 1) { + return pC_->couldNotParseResponse(command, response, axisNo_, + __PRETTY_FUNCTION__, __LINE__); + } + return status; } -// Perform the actual poll asynStatus detectorTowerAxis::doPoll(bool *moving) { // Return value for the poll @@ -158,7 +176,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { // Status of parameter library operations asynStatus pl_status = asynSuccess; - char response[pC_->MAXBUF_], userMessage[pC_->MAXBUF_]; + char userMessage[pC_->MAXBUF_] = {0}; + char response[pC_->MAXBUF_] = {0}; int nvals = 0; int direction = 0; @@ -172,11 +191,10 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { double highLimit = 0.0; double lowLimit = 0.0; double detectorHeight = 0.0; - double detectorRadius = 0.0; - double liftOffsetHighLimit = 0.0; - double liftOffsetLowLimit = 0.0; - double tiltOffsetHighLimit = 0.0; - double tiltOffsetLowLimit = 0.0; + double liftZeroCorrHighLimit = 0.0; + double liftZeroCorrLowLimit = 0.0; + double tiltZeroCorrHighLimit = 0.0; + double tiltZeroCorrLowLimit = 0.0; // ========================================================================= @@ -202,23 +220,25 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { - Axis error - Beam tilt angle - Beam tilt angle limits + - Beam lift position - Beam lift offset limits - Detector tilt offset limits */ - const char *command = "P354 P358 P359 Q510 Q513 Q514 Q353 Q354 Q553 Q554"; + const char *command = + "P354 P358 P359 Q510 Q513 Q514 Q310 Q353 Q354 Q553 Q554"; rw_status = pC_->writeRead(axisNo_, command, response, 10); if (rw_status != asynSuccess) { return rw_status; } - nvals = - sscanf(response, "%d %d %d %lf %lf %lf %lf %lf %lf %lf", &inPosition, - &positionState, &error, &beamTiltAngle, &highLimit, &lowLimit, - &liftOffsetHighLimit, &liftOffsetLowLimit, &tiltOffsetHighLimit, - &tiltOffsetLowLimit); + nvals = sscanf(response, "%d %d %d %lf %lf %lf %lf %lf %lf %lf %lf", + &inPosition, &positionState, &error, &beamTiltAngle, + &highLimit, &lowLimit, &detectorHeight, + &liftZeroCorrHighLimit, &liftZeroCorrLowLimit, + &tiltZeroCorrHighLimit, &tiltZeroCorrLowLimit); if (nvals != 10) { return pC_->couldNotParseResponse(command, response, axisNo_, - __PRETTY_FUNCTION__, __LINE__); + __PRETTY_FUNCTION__, __LINE__); } /* @@ -300,9 +320,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { default: if (pC_->getMsgPrintControl().shouldBePrinted(keyPosState, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nReached unknown " "state P354 = %d.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -323,7 +343,7 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { } if (resetCountPosState) { - pC_->getMsgPrintControl().resetCount(keyPosState, pC_->asynUserSelf()); + pC_->getMsgPrintControl().resetCount(keyPosState, pC_->pasynUser()); } if (*moving) { @@ -348,9 +368,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { break; case 1: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nBrake COZ not " "released (P359=1).%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -373,9 +393,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 2: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nMove command " "rejected because axis is already moving.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -397,8 +417,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 3: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nError motor " "FTZ.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -421,9 +441,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 4: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nAxis stopped " "unexpectedly.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -447,9 +467,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 5: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nRelease removed " "while moving.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -473,9 +493,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 6: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nEmergency stop " "activated.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -496,8 +516,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 7: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nError motor " "COZ.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -520,8 +540,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 8: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nError motor " "COM.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -544,8 +564,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 9: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nError motor " "COX.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -568,8 +588,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 10: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser())) { + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nHit end " "switch FTZ.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -591,9 +611,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { case 11: // Following error if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nMaximum allowed " "following error FTZ exceeded.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -618,9 +638,9 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { default: if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true, - pC_->asynUserSelf())) { + pC_->pasynUser())) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nUnknown error " "P359 = %d.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, error, @@ -642,7 +662,7 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { } if (resetError) { - pC_->getMsgPrintControl().resetCount(keyError, pC_->asynUserSelf()); + pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser()); } // Update the parameter library @@ -701,46 +721,46 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) { } // Set the values for the offset axes - int liftAxisNo = liftOffsetAxis_->axisNo_; - double liftOffsetPosition = - detectorHeight + detectorRadius * sin(beamTiltAngle); + int liftAxisNo = liftZeroCorrAxis_->axisNo_; + double liftZeroCorrPosition = + detectorHeight + beamRadius_ * sin(beamTiltAngle); - pl_status = setMotorPosition(liftOffsetPosition); + pl_status = setMotorPosition(liftZeroCorrPosition); if (pl_status != asynSuccess) { return pl_status; } pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorHighLimitFromDriver(), - liftOffsetHighLimit); + liftZeroCorrHighLimit); if (pl_status != asynSuccess) { return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_", liftAxisNo, __PRETTY_FUNCTION__, __LINE__); } pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorLowLimitFromDriver(), - liftOffsetLowLimit); + liftZeroCorrLowLimit); if (pl_status != asynSuccess) { return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver_", liftAxisNo, __PRETTY_FUNCTION__, __LINE__); } - int tiltAxisNo = tiltOffsetAxis_->axisNo_; + int tiltAxisNo = tiltZeroCorrAxis_->axisNo_; - // There exists no readback value for tiltOffsetAxis_, hence we just set the - // current position to the target position. - tiltOffsetAxis_->setMotorPosition(tiltOffsetAxis_->targetPosition_); + // There exists no readback value for tiltZeroCorrAxis_, hence we just set + // the current position to the target position. + tiltZeroCorrAxis_->setMotorPosition(tiltZeroCorrAxis_->targetPosition_); if (pl_status != asynSuccess) { return pl_status; } pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorHighLimitFromDriver(), - tiltOffsetHighLimit); + tiltZeroCorrHighLimit); if (pl_status != asynSuccess) { return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_", tiltAxisNo, __PRETTY_FUNCTION__, __LINE__); } pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorLowLimitFromDriver(), - tiltOffsetLowLimit); + tiltZeroCorrLowLimit); if (pl_status != asynSuccess) { return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver_", tiltAxisNo, __PRETTY_FUNCTION__, @@ -792,8 +812,11 @@ asynStatus detectorTowerAxis::startCombinedMove() { // Status of parameter library operations asynStatus pl_status = asynSuccess; - char command[pC_->MAXBUF_], response[pC_->MAXBUF_]; + char command[pC_->MAXBUF_] = {0}; + char response[pC_->MAXBUF_] = {0}; double motorCoordinatesPosition = 0.0; + double offsetliftZeroCorr = 0.0; + double offsettiltZeroCorr = 0.0; int positionState = 0; // ========================================================================= @@ -803,8 +826,8 @@ asynStatus detectorTowerAxis::startCombinedMove() { bool isInChangerPos = positionState == 2 || positionState == 3; if (pC_->getMsgPrintControl().shouldBePrinted( pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, - isInChangerPos, pC_->asynUserSelf())) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + 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 " @@ -817,11 +840,30 @@ asynStatus detectorTowerAxis::startCombinedMove() { return asynError; } + // Read out any offsets for the zero correction axes + pl_status = + pC_->getDoubleParam(tiltZeroCorrAxis_->axisNo(), + pC_->motorTargetOffset(), &offsettiltZeroCorr); + if (pl_status != asynSuccess) { + return pC_->paramLibAccessFailed(pl_status, "motorTargetOffset", + axisNo_, __PRETTY_FUNCTION__, + __LINE__); + } + pl_status = + pC_->getDoubleParam(liftZeroCorrAxis_->axisNo(), + pC_->motorTargetOffset(), &offsetliftZeroCorr); + if (pl_status != asynSuccess) { + return pC_->paramLibAccessFailed(pl_status, "motorTargetOffset", + axisNo_, __PRETTY_FUNCTION__, + __LINE__); + } + // Set the target positions for beam tilt, detector tilt offset and lift // offset snprintf(command, sizeof(command), "Q451=%lf Q454=%lf Q456=%lf P350=1", - targetPosition_, liftOffsetAxis_->targetPosition_, - tiltOffsetAxis_->targetPosition_); + targetPosition_, + liftZeroCorrAxis_->targetPosition_ + offsetliftZeroCorr, + tiltZeroCorrAxis_->targetPosition_ + offsettiltZeroCorr); // Lock the access to the controller since this function runs in another // thread than the poll method. @@ -835,7 +877,7 @@ asynStatus detectorTowerAxis::startCombinedMove() { if (rw_status != asynSuccess) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nStarting movement to " "target position %lf failed.\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -859,7 +901,7 @@ asynStatus detectorTowerAxis::stop(double acceleration) { // Status of parameter library operations asynStatus pl_status = asynSuccess; - char response[pC_->MAXBUF_]; + char response[pC_->MAXBUF_] = {0}; // ========================================================================= @@ -867,7 +909,7 @@ asynStatus detectorTowerAxis::stop(double acceleration) { if (rw_status != asynSuccess) { asynPrint( - pC_->asynUserSelf(), ASYN_TRACE_ERROR, + pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nStopping the movement " "failed.\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); @@ -897,7 +939,7 @@ asynStatus detectorTowerAxis::readEncoderType() { asynStatus detectorTowerAxis::toggleWorkingChangerState(bool toChangingPosition) { - char response[pC_->MAXBUF_]; + char response[pC_->MAXBUF_] = {0}; // Status of read-write-operations of ASCII commands to the controller asynStatus rw_status = asynSuccess; @@ -921,7 +963,7 @@ detectorTowerAxis::toggleWorkingChangerState(bool toChangingPosition) { } if (moving) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR, + asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nAxis is not " "idle and can therefore not be moved to %s state.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -944,7 +986,7 @@ detectorTowerAxis::toggleWorkingChangerState(bool toChangingPosition) { (toChangingPosition == true && positionState == 2); if (isAlreadyThere) { - asynPrint(pC_->asynUserSelf(), ASYN_TRACE_WARNING, + asynPrint(pC_->pasynUser(), ASYN_TRACE_WARNING, "Controller \"%s\", axis %d => %s, line %d\nAxis is already " "in %s position.%s\n", pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, @@ -973,7 +1015,7 @@ detectorTowerAxis::toggleWorkingChangerState(bool toChangingPosition) { asynStatus detectorTowerAxis::doReset() { - char response[pC_->MAXBUF_]; + char response[pC_->MAXBUF_] = {0}; asynStatus pl_status = asynSuccess; int positionState = 0; @@ -1014,7 +1056,8 @@ 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 axisDetectorTower, - int liftOffsetaxisNo, int tiltOffsetaxisNo) { + int liftZeroCorraxisNo, + int tiltZeroCorraxisNo) { /* findAsynPortDriver is a asyn library FFI function which uses the C ABI. @@ -1053,9 +1096,9 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axisDetectorTower, } // Assert that the three indices are different from each other - if (axisDetectorTower == liftOffsetaxisNo || - axisDetectorTower == tiltOffsetaxisNo || - tiltOffsetaxisNo == liftOffsetaxisNo) { + if (axisDetectorTower == liftZeroCorraxisNo || + axisDetectorTower == tiltZeroCorraxisNo || + tiltZeroCorraxisNo == liftZeroCorraxisNo) { errlogPrintf("Controller \"%s\" => %s, line %d\nAll three axis indices " "must be unique.", portName, __PRETTY_FUNCTION__, __LINE__); @@ -1076,13 +1119,15 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axisDetectorTower, be "leaked" here. */ - auxiliaryAxis *liftOffsetAxis = new auxiliaryAxis(pC, liftOffsetaxisNo); - auxiliaryAxis *tiltOffsetAxis = new auxiliaryAxis(pC, tiltOffsetaxisNo); + detectorTowerAuxiliaryAxis *liftZeroCorrAxis = + new detectorTowerAuxiliaryAxis(pC, liftZeroCorraxisNo); + detectorTowerAuxiliaryAxis *tiltZeroCorrAxis = + new detectorTowerAuxiliaryAxis(pC, tiltZeroCorraxisNo); #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-variable" detectorTowerAxis *pAxis = new detectorTowerAxis( - pC, axisDetectorTower, liftOffsetAxis, tiltOffsetAxis); + pC, axisDetectorTower, liftZeroCorrAxis, tiltZeroCorrAxis); // Allow manipulation of the controller again pC->unlock(); diff --git a/src/detectorTowerAxis.h b/src/detectorTowerAxis.h index d0a4ea6..7e8fa29 100644 --- a/src/detectorTowerAxis.h +++ b/src/detectorTowerAxis.h @@ -1,6 +1,6 @@ #ifndef detectorTowerAxis_H #define detectorTowerAxis_H -#include "auxiliaryAxis.h" +#include "detectorTowerAuxiliaryAxis.h" #include "turboPmacAxis.h" // Forward declaration of the controller class to resolve the cyclic dependency @@ -15,14 +15,14 @@ class detectorTowerAxis : public turboPmacAxis { * * @param pController Pointer to the associated controller * @param axisNo Index of the axis - * @param liftOffsetAxis Pointer to the attached axis which controls + * @param liftZeroCorrAxis Pointer to the attached axis which controls * the lift offset - * @param tiltOffsetAxis Pointer to the attached axis which controls + * @param tiltZeroCorrAxis Pointer to the attached axis which controls * the tilt offset */ detectorTowerAxis(detectorTowerController *pController, int axisNo, - auxiliaryAxis *liftOffsetAxis, - auxiliaryAxis *tiltOffsetAxis); + detectorTowerAuxiliaryAxis *liftZeroCorrAxis, + detectorTowerAuxiliaryAxis *tiltZeroCorrAxis); /** * @brief Destroy the detectorTowerAxis @@ -100,8 +100,8 @@ class detectorTowerAxis : public turboPmacAxis { */ asynStatus doReset(); - // If true, either this axis or one of the auxiliaryAxis attached to it - // received a movement command. + // If true, either this axis or one of the detectorTowerAuxiliaryAxis + // attached to it received a movement command. bool receivedTarget_; // If set to true, the virtual axis is about to start a deferred movement @@ -118,11 +118,12 @@ class detectorTowerAxis : public turboPmacAxis { protected: detectorTowerController *pC_; int error_; - auxiliaryAxis *tiltOffsetAxis_; - auxiliaryAxis *liftOffsetAxis_; + detectorTowerAuxiliaryAxis *tiltZeroCorrAxis_; + detectorTowerAuxiliaryAxis *liftZeroCorrAxis_; + double beamRadius_; private: - friend class auxiliaryAxis; + friend class detectorTowerAuxiliaryAxis; }; #endif diff --git a/src/detectorTowerController.cpp b/src/detectorTowerController.cpp index ad770de..53d4a10 100644 --- a/src/detectorTowerController.cpp +++ b/src/detectorTowerController.cpp @@ -47,45 +47,73 @@ detectorTowerController::detectorTowerController( stringifyAsynStatus(status)); exit(-1); } + + status = createParam("MOTOR_OFFSET", asynParamFloat64, &motorTargetOffset_); + 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) { - // Check if the axis is a detectorTowerAxis - detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser); - if (axis == nullptr) { - // This is apparently a "normal" turboPmacAxis or an auxiliaryAxis - return turboPmacController::readInt32(pasynUser, value); - } else { - // The detector tower cannot be disabled - if (pasynUser->reason == motorCanDisable_) { + // The detector tower or its auxiliary axes cannot be disabled + if (pasynUser->reason == motorCanDisable_) { + detectorTowerAxis *dTAxis = getDetectorTowerAxis(pasynUser); + if (dTAxis != nullptr) { + *value = 0; + return asynSuccess; + } + detectorTowerAuxiliaryAxis *dTAAxis = + getDetectorTowerAuxiliaryAxis(pasynUser); + if (dTAAxis != nullptr) { *value = 0; return asynSuccess; - } else { - return turboPmacController::readInt32(pasynUser, value); } } + return turboPmacController::readInt32(pasynUser, value); } asynStatus detectorTowerController::writeInt32(asynUser *pasynUser, epicsInt32 value) { + + // ===================================================================== + + if (pasynUser->reason == motorCanDisable_) { + detectorTowerAxis *dTAxis = getDetectorTowerAxis(pasynUser); + if (dTAxis != nullptr) { + return dTAxis->toggleWorkingChangerState(value); + } + } + return turboPmacController::writeInt32(pasynUser, value); +} + +asynStatus detectorTowerController::writeFloat64(asynUser *pasynUser, + epicsFloat64 value) { int function = pasynUser->reason; // ===================================================================== - detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser); + if (function == motorTargetOffset_) { - if (axis == nullptr) { - // This is apparently a "normal" turboPmacAxis or an auxiliaryAxis - return turboPmacController::writeInt32(pasynUser, value); - } else { - if (function == changeState_) { - return axis->toggleWorkingChangerState(value); - } else { - return turboPmacController::writeInt32(pasynUser, value); + // Write into the parameter library and trigger a movement cycle, if the + // writing succeeded + asynStatus status = turboPmacController::writeFloat64(pasynUser, value); + if (status == asynSuccess) { + detectorTowerAxis *dTAxis = getDetectorTowerAxis(pasynUser); + if (dTAxis != nullptr) { + dTAxis->receivedTarget_ = true; + } } + return status; } + + return turboPmacController::writeFloat64(pasynUser, value); } /* @@ -108,6 +136,27 @@ detectorTowerAxis *detectorTowerController::getDetectorTowerAxis(int axisNo) { return dynamic_cast(asynAxis); } +/* +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. +*/ +detectorTowerAuxiliaryAxis * +detectorTowerController::getDetectorTowerAuxiliaryAxis(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 +*/ +detectorTowerAuxiliaryAxis * +detectorTowerController::getDetectorTowerAuxiliaryAxis(int axisNo) { + asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo); + return dynamic_cast(asynAxis); +} + /*************************************************************************************/ /** The following functions are C-wrappers, and can be called directly from * iocsh */ diff --git a/src/detectorTowerController.h b/src/detectorTowerController.h index 1a6be7b..6daf0b2 100644 --- a/src/detectorTowerController.h +++ b/src/detectorTowerController.h @@ -8,7 +8,7 @@ #ifndef detectorTowerController_H #define detectorTowerController_H -#include "auxiliaryAxis.h" +#include "detectorTowerAuxiliaryAxis.h" #include "detectorTowerAxis.h" #include "turboPmacController.h" @@ -52,6 +52,15 @@ class detectorTowerController : public turboPmacController { */ asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); + /** + * @brief Overloaded function of turboPmacController + * + * @param pasynUser Specify the axis via the asynUser + * @param value New value + * @return asynStatus + */ + asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + /** * @brief Get the axis object * @@ -70,16 +79,37 @@ class detectorTowerController : public turboPmacController { */ detectorTowerAxis *getDetectorTowerAxis(int axisNo); + /** + * @brief Get the axis object + * + * @param pasynUser Specify the axis via the asynUser + * @return detectorTowerAuxiliaryAxis* If no axis could be found, + * this is a nullptr + */ + detectorTowerAuxiliaryAxis * + getDetectorTowerAuxiliaryAxis(asynUser *pasynUser); + + /** + * @brief Get the axis object + * + * @param axisNo Specify the axis via its index + * @return detectorTowerAuxiliaryAxis* If no axis could be found, + * this is a nullptr + */ + detectorTowerAuxiliaryAxis *getDetectorTowerAuxiliaryAxis(int axisNo); + // Accessors for additional PVs int positionStateRBV() { return positionStateRBV_; } int changeState() { return changeState_; } + int motorTargetOffset() { return motorTargetOffset_; } private: // Indices of additional PVs #define FIRST_detectorTower_PARAM positionStateRBV_ int positionStateRBV_; int changeState_; -#define LAST_detectorTower_PARAM changeState_ + int motorTargetOffset_; +#define LAST_detectorTower_PARAM motorTargetOffset_ }; #define NUM_detectorTower_DRIVER_PARAMS \ (&LAST_detectorTower_PARAM - &FIRST_detectorTower_PARAM + 1)