22 Commits
1.0.0 ... 1.3.3

Author SHA1 Message Date
f5287609e5 Updated to turboPmac 1.6.3
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 7s
2026-02-11 11:16:10 +01:00
e322dd09c1 Updated turboPmac version to 1.6.2 2026-02-03 14:08:28 +01:00
754fc16cd3 Updated to turboPmac 1.6.1
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 7s
2026-02-03 13:47:10 +01:00
a7cb1cd05f Readded correct version of turboPmac
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 7s
2026-01-23 13:28:38 +01:00
f9d5d1aaee Completely removed turboPmac temporarily 2026-01-23 13:27:47 +01:00
ef81f38017 Added correct repo for turboPMAC 2026-01-23 11:47:48 +01:00
6ee554f9e5 Remove turboPmac submodule 2026-01-23 11:46:45 +01:00
7bd3adbfc3 Remove turboPmac submodule 2026-01-23 11:46:12 +01:00
bff7ad79df Fully remove turboPmac submodule 2026-01-23 11:44:46 +01:00
70029b12b2 Temporarily removed turboPmac module 2026-01-23 11:42:59 +01:00
ac5ab3855e Updated turboPmac version and added constructor for standard axis 2026-01-23 11:38:18 +01:00
2c9de618ec Made code compile with compiler flags
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 7s
2025-12-23 14:00:08 +01:00
b834dc3f8d Updated turboPmac version 2025-12-23 13:51:18 +01:00
ee6235e74a Removed C++ only flag from USR_CFLAGS and updated turboPmac version
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 9s
2025-08-22 15:30:33 +02:00
48c068826c Updated sinqMotor to fix bug in forcedPoll regarding watchdog
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 10s
2025-08-14 17:25:35 +02:00
c494fc88a5 Updated to turboPmac 1.4 and hid symbols
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 9s
2025-08-12 09:28:06 +02:00
e0fa9ef3a9 also check header files
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 10s
2025-07-04 14:37:43 +02:00
dc6d5c40b3 need to build sinqmotor first
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 10s
2025-07-04 14:23:21 +02:00
56288b1db8 adds gitea action
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 3s
2025-07-04 14:21:39 +02:00
dde15eb30d Updated param lib accessors to use macro to reduce boilerplate 2025-06-18 10:22:49 +02:00
efccb26302 Updated param lib accessors to use macro to reduce boilerplate 2025-06-18 10:19:43 +02:00
85d443a92b Updated turboPmac version 2025-06-18 08:56:32 +02:00
14 changed files with 346 additions and 421 deletions

View File

@@ -0,0 +1,30 @@
name: Test And Build
on: [push]
jobs:
Lint:
runs-on: linepics
steps:
- name: checkout repo
uses: actions/checkout@v4
- name: cppcheck
run: cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
- name: formatting
run: clang-format --style=file --Werror --dry-run src/*.cpp src/*.h
Build:
runs-on: linepics
steps:
- name: checkout repo
uses: actions/checkout@v4
with:
submodules: 'true'
- run: |
pushd turboPmac
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
echo -e "\nIGNORE_SUBMODULES += sinqmotor" >> Makefile
make install
popd
- run: |
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
echo -e "\nIGNORE_SUBMODULES += turboPmac" >> Makefile
make install

View File

@@ -1,58 +0,0 @@
default:
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
stages:
- lint
- build
- test
cppcheck:
stage: lint
script:
- cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
artifacts:
expire_in: 1 week
tags:
- sinq
formatting:
stage: lint
script:
- clang-format --style=file --Werror --dry-run src/*.cpp
artifacts:
expire_in: 1 week
tags:
- sinq
# clangtidy:
# stage: lint
# script:
# - curl https://docker.psi.ch:5000/v2/_catalog
# # - dnf update -y
# # - dnf install -y clang-tools-extra
# # - clang-tidy sinqEPICSApp/src/*.cpp sinqEPICSApp/src/*.c sinqEPICSApp/src/*.h -checks=cppcoreguidelines-*,cert-*
# # tags:
# # - sinq
build_module:
stage: build
script:
- export SINQMOTOR_VERSION="$(grep 'sinqMotor_VERSION=' Makefile | cut -d= -f2)"
- git clone --depth 1 --branch "${SINQMOTOR_VERSION}" https://gitlab-ci-token:${CI_JOB_TOKEN}@git.psi.ch/sinq-epics-modules/sinqmotor.git
- pushd sinqmotor
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
- echo "LIBVERSION=${SINQMOTOR_VERSION}" >> Makefile
- make install
- popd
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
- echo "LIBVERSION=${CI_COMMIT_TAG:-0.0.1}" >> Makefile
- make install
- cp -rT "/ioc/modules/seleneLift/$(ls -U /ioc/modules/seleneLift/ | head -1)" "./seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
artifacts:
name: "seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
paths:
- "seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
expire_in: 1 week
when: always
tags:
- sinq

View File

@@ -42,4 +42,5 @@ DBDS += turboPmac/sinqMotor/src/sinqMotor.dbd
DBDS += turboPmac/src/turboPmac.dbd
DBDS += src/seleneGuide.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wextra -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings
USR_CFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings
USR_CXXFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror

View File

@@ -44,7 +44,7 @@ Two additional PVs are provided in `db/seleneGuide.db`:
### Usage in IOC shell
seleneGuide exports the following IOC shell functions:
- `seleneGuideController`: Create a new controller object. This object is essentially a `turboPmacController` object from the standard [Turbo PMAC driver](https://git.psi.ch/sinq-epics-modules/turboPmac), but it supports the additional motor PVs for absolute position and normalization. This means that it can be used with "normal" `turboPmacAxis` as well.
- `seleneGuideController`: Create a new controller object. This object is essentially a `turboPmacController` object from the standard [Turbo PMAC driver](https://git.psi.ch/sinq-epics-modules/turboPmac), but it supports the additional motor PVs for absolute position and normalization. This means that it can be used to control a "standard" TurboPMAC axis as well. To ensure compatibility between controller and axis, it is recommended to use the wrapper `seleneStandardAxis` instead of the `turboPmacAxis` provided by the basic TurboPMAC driver (because otherwise the versions of the `seleneGuide` and the `turboPmac` drivers are not independent from each other).
- `seleneOffsetAxis`: Create a new offset axis object with the specified x- and z-offset from an arbitrary origin in mm.
- `seleneVirtualAxes`: Create the virtual lift and the angle axes.
@@ -78,8 +78,9 @@ seleneOffsetAxis("$(NAME)",5, 5933.99477, 0.0);
seleneOffsetAxis("$(NAME)",6, 7463.87259, 0.0);
# These are two "normal" PMAC axes which work the same way they would with a turboPmacController.
turboPmacAxis("$(NAME)",7);
turboPmacAxis("$(NAME)",8);
# Using the wrapper seleneStandardAxis ensures compatibility to the seleneGuideController.
seleneStandardAxis("$(NAME)",7);
seleneStandardAxis("$(NAME)",8);
# This function call creates the lift and the angle axes.
# The arguments on position 2 to 7 are the axis indices of the offset axes

View File

@@ -19,8 +19,13 @@ seleneAngleAxis::seleneAngleAxis(seleneGuideController *pController, int axisNo,
// Selene guide motors cannot be disabled
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
// Even though this happens already in sinqAxis, a default value for
@@ -45,17 +50,18 @@ asynStatus seleneAngleAxis::stop(double acceleration) {
}
asynStatus seleneAngleAxis::doMove(double position, int relative,
double min_velocity, double max_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
double motorRecResolution = 0.0;
asynStatus pl_status = pC_->getDoubleParam(
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
setTargetPosition(position * motorRecResolution);
targetSet_ = true;
return liftAxis_->startCombinedMoveFromVirtualAxis();
@@ -75,25 +81,17 @@ double seleneAngleAxis::targetPosition() {
asynStatus seleneAngleAxis::doPoll(bool *moving) {
char errorMessage[pC_->MAXBUF_] = {0};
asynStatus status = asynSuccess;
// In the doPoll method of `seleneLiftAxis`, the parameters
// `motorStatusMoving` and `motorStatusDone` of this axis have already been
// set accordingly.
int isMoving = 0;
asynStatus pl_status =
pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(), &isMoving);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving",
axisNo(), __PRETTY_FUNCTION__,
__LINE__);
}
*moving = (isMoving != 0);
getAxisParamChecked(this, motorStatusMoving, moving);
double motPos = 0.0;
pl_status = motorPosition(&motPos);
if (pl_status != asynSuccess) {
return pl_status;
status = motorPosition(&motPos);
if (status != asynSuccess) {
return status;
}
/*
@@ -126,9 +124,9 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
double smallestHighLimit = std::numeric_limits<double>::infinity();
double smallestLowLimit = std::numeric_limits<double>::infinity();
double liftPosition = 0.0;
pl_status = liftAxis_->motorPosition(&liftPosition);
if (pl_status != asynSuccess) {
return pl_status;
status = liftAxis_->motorPosition(&liftPosition);
if (status != asynSuccess) {
return status;
}
for (int i = 0; i < liftAxis_->numAxes_; i++) {
@@ -137,9 +135,9 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
double leverArm = oAxis->xOffset() - liftAxis_->xPos();
double motPos = 0.0;
pl_status = oAxis->motorPosition(&motPos);
if (pl_status != asynSuccess) {
return pl_status;
status = oAxis->motorPosition(&motPos);
if (status != asynSuccess) {
return status;
}
/*
@@ -176,52 +174,23 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
}
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
smallestHighLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(),
smallestLowLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorHighLimitFromDriver, smallestHighLimit);
setAxisParamChecked(this, motorLowLimitFromDriver, smallestLowLimit);
// This axis should always be seen as enabled, since it is automatically
// enabled before each movement and disabled afterwards
pl_status = setIntegerParam(pC_->motorEnableRBV(), 1);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorEnableRBV, true);
// If an error message is set in the liftAxis_, copy this message into this
// axis.
pl_status =
pC_->getStringParam(liftAxis_->axisNo(), pC_->motorMessageText(),
sizeof(errorMessage), errorMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText",
liftAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
getAxisParamChecked(liftAxis_, motorMessageText, &errorMessage);
if (strlen(errorMessage) != 0) {
pl_status = setStringParam(pC_->motorMessageText(), errorMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText, errorMessage);
return asynError;
}
return pl_status;
return status;
}
asynStatus seleneAngleAxis::doReset() { return liftAxis_->reset(); }
@@ -229,13 +198,7 @@ asynStatus seleneAngleAxis::doReset() { return liftAxis_->reset(); }
asynStatus seleneAngleAxis::enable(bool on) { return liftAxis_->enable(on); }
asynStatus seleneAngleAxis::readEncoderType() {
asynStatus pl_status =
setStringParam(pC_->encoderType(), IncrementalEncoder);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, encoderType, IncrementalEncoder);
return asynSuccess;
}

View File

@@ -1,22 +1,19 @@
#ifndef seleneAngleAxis_H
#define seleneAngleAxis_H
#include "seleneGuideController.h"
#include "turboPmacAxis.h"
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class seleneLiftAxis;
// Forward declaration of the seleneGuideController class to resolve the cyclic
// dependency. See https://en.cppreference.com/w/cpp/language/class.
class seleneGuideController;
class HIDDEN seleneLiftAxis;
/**
* @brief Virtual axis for setting the angle of the Selene guide
*
* Please see README.md for a detailed explanation.
*/
class seleneAngleAxis : public turboPmacAxis {
class HIDDEN seleneAngleAxis : public turboPmacAxis {
public:
/**
* @brief Construct a new seleneAngleAxis.
@@ -51,12 +48,12 @@ class seleneAngleAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**
@@ -140,6 +137,11 @@ class seleneAngleAxis : public turboPmacAxis {
*/
asynStatus rereadEncoder() { return asynSuccess; }
/**
* @brief Return a pointer to the axis controller
*/
virtual seleneGuideController *pController() override { return pC_; };
protected:
seleneGuideController *pC_;
seleneLiftAxis *liftAxis_;

View File

@@ -1,3 +1,4 @@
registrar(seleneVirtualAxesRegister)
registrar(seleneOffsetAxisRegister)
registrar(seleneStandardAxisRegister)
registrar(seleneGuideControllerRegister)

View File

@@ -1,4 +1,7 @@
#include "seleneGuideController.h"
#include "seleneAngleAxis.h"
#include "seleneLiftAxis.h"
#include "seleneOffsetAxis.h"
#include "turboPmacController.h"
#include <epicsExport.h>
#include <errlog.h>
@@ -20,7 +23,8 @@ seleneGuideController::seleneGuideController(
const char *portName, const char *ipPortConfigName, int numAxes,
double movingPollPeriod, double idlePollPeriod, double comTimeout)
: turboPmacController(portName, ipPortConfigName, numAxes, movingPollPeriod,
idlePollPeriod, NUM_seleneGuide_DRIVER_PARAMS)
idlePollPeriod, comTimeout,
NUM_seleneGuide_DRIVER_PARAMS)
{
@@ -142,7 +146,8 @@ static const iocshArg *const CreateControllerArgs[] = {
&CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2,
&CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5};
static const iocshFuncDef configSeleneGuideCreateController = {
"seleneGuideController", 6, CreateControllerArgs};
"seleneGuideController", 6, CreateControllerArgs,
"Create a new instance of a Selene controller."};
static void configSeleneGuideCreateControllerCallFunc(const iocshArgBuf *args) {
seleneGuideCreateController(args[0].sval, args[1].sval, args[2].ival,
args[3].dval, args[4].dval, args[5].dval);
@@ -156,4 +161,97 @@ static void seleneGuideControllerRegister(void) {
}
epicsExportRegistrar(seleneGuideControllerRegister);
/*
C wrapper for a "standard" TurboPMAC axis constructor. This function is
identical to "turboPmacCreateAxis" in the standard TurboPMAC driver. However, it
is recommended to use this constructor to make sure the version of the axis
matches that of the controller. The controller is read from the portName.
*/
asynStatus seleneStandardCreateAxis(const char *portName, int axis) {
/*
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
Therefore it returns a void pointer instead of e.g. a pointer to a
superclass of the controller such as asynPortDriver. Type-safe upcasting
via dynamic_cast is therefore not possible directly. However, we do know
that the void pointer is either a pointer to asynPortDriver (if a driver
with the specified name exists) or a nullptr. Therefore, we first do a
nullptr check, then a cast to asynPortDriver and lastly a (typesafe)
dynamic_upcast to Controller
https://stackoverflow.com/questions/70906749/is-there-a-safe-way-to-cast-void-to-class-pointer-in-c
*/
void *ptr = findAsynPortDriver(portName);
if (ptr == nullptr) {
/*
We can't use asynPrint here since this macro would require us
to get an asynUser from a pointer to an asynPortDriver.
However, the given pointer is a nullptr and therefore doesn't
have an asynUser! printf is an EPICS alternative which
works w/o that, but doesn't offer the comfort provided
by the asynTrace-facility
*/
errlogPrintf("Controller \"%s\" => %s, line %d\nPort not found.",
portName, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
// Unsafe cast of the pointer to an asynPortDriver
asynPortDriver *apd = (asynPortDriver *)(ptr);
// Safe downcast
seleneGuideController *pC = dynamic_cast<seleneGuideController *>(apd);
if (pC == nullptr) {
errlogPrintf("Controller \"%s\" => %s, line %d\nController "
"is not a seleneGuideController.",
portName, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
// Prevent manipulation of the controller from other threads while we
// create the new axis.
pC->lock();
/*
We create a new instance of the axis, using the "new" keyword to
allocate it on the heap while avoiding RAII.
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorController.cpp
https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/asynPortDriver.cpp
The created object is registered in EPICS in its constructor and can
safely be "leaked" here.
*/
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-variable"
turboPmacAxis *pAxis = new turboPmacAxis(pC, axis);
// Allow manipulation of the controller again
pC->unlock();
return asynSuccess;
}
/*
Same procedure as for the CreateController function, but for the axis
itself.
*/
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
iocshArgString};
static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
&CreateAxisArg1};
static const iocshFuncDef configSeleneStandardCreateAxis = {
"seleneStandardAxis", 2, CreateAxisArgs,
"Create an instance of a standard turboPmac axis for the selene "
"controller. The first argument is the controller this axis should be "
"attached to, the second argument is the axis number."};
static void configSeleneStandardCreateAxisCallFunc(const iocshArgBuf *args) {
seleneStandardCreateAxis(args[0].sval, args[1].ival);
}
// This function is made known to EPICS in turboPmac.dbd and is called by
// EPICS in order to register both functions in the IOC shell
static void seleneStandardAxisRegister(void) {
iocshRegister(&configSeleneStandardCreateAxis,
configSeleneStandardCreateAxisCallFunc);
}
epicsExportRegistrar(seleneStandardAxisRegister);
} // extern "C"

View File

@@ -8,12 +8,16 @@
#ifndef seleneGuideController_H
#define seleneGuideController_H
#include "seleneAngleAxis.h"
#include "seleneLiftAxis.h"
#include "seleneOffsetAxis.h"
#include "turboPmacController.h"
class seleneGuideController : public turboPmacController {
// Forward declaration of the axis classes to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class HIDDEN seleneAngleAxis;
class HIDDEN seleneLiftAxis;
class HIDDEN seleneOffsetAxis;
class HIDDEN seleneGuideController : public turboPmacController {
public:
/**

View File

@@ -96,8 +96,13 @@ seleneLiftAxis::seleneLiftAxis(seleneGuideController *pC, int axis1No,
// Selene guide motors cannot be disabled
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
// Even though this happens already in sinqAxis, a default value for
@@ -151,44 +156,17 @@ asynStatus seleneLiftAxis::init() {
}
// Assume the virtual axes are not moving at the start
status = setIntegerParam(pC_->motorStatusMoving(), 0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusMoving", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
status = setIntegerParam(pC_->motorStatusDone(), 1);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusDone", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorStatusMoving, false);
setAxisParamChecked(this, motorStatusDone, true);
status = angleAxis_->setIntegerParam(pC_->motorStatusMoving(), 0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
angleAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
status = angleAxis_->setIntegerParam(pC_->motorStatusDone(), 1);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusDone",
angleAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(angleAxis_, motorStatusMoving, false);
setAxisParamChecked(angleAxis_, motorStatusDone, true);
// The virtual axes should always be seen as enabled, since the underlying
// hardware is automatically enabled after sending a start command to the
// controller and automatically disabled after the movement finished.
status = setIntegerParam(pC_->motorEnableRBV(), 1);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorEnableRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
status = angleAxis_->setIntegerParam(pC_->motorEnableRBV(), 1);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorEnableRBV_",
angleAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorEnableRBV, true);
setAxisParamChecked(angleAxis_, motorEnableRBV, true);
status = normalizePositions();
if (status != asynSuccess) {
@@ -277,12 +255,7 @@ asynStatus seleneLiftAxis::normalizePositions() {
}
asynStatus seleneLiftAxis::doPoll(bool *moving) {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
asynStatus status = asynSuccess;
char response[pC_->MAXBUF_] = {0};
char userMessage[pC_->MAXBUF_] = {0};
@@ -293,18 +266,12 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
// =========================================================================
pl_status =
pC_->getIntegerParam(axisNo(), pC_->motorStatusDone(), &wasDone);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving",
axisNo(), __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorStatusDone, &wasDone);
const char *command = "P158";
rw_status = pC_->writeRead(axisNo_, command, response, 1);
if (rw_status != asynSuccess) {
return rw_status;
status = pC_->writeRead(axisNo_, command, response, 1);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%d", &axStatus);
@@ -315,31 +282,12 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
*moving = (axStatus != 0);
// Set the moving status of seleneLiftAxis
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving));
// Set the moving status of seleneAngleAxis
pl_status = angleAxis_->setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving",
angleAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = angleAxis_->setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone",
angleAxis_->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(angleAxis_, motorStatusMoving, *moving);
setAxisParamChecked(angleAxis_, motorStatusDone, !(*moving));
/*
If an seleneOffsetAxis is moving, the positions of the virtual axes
@@ -358,22 +306,17 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
double motorRecResolution = 0.0;
asynStatus pl_status = pC_->getDoubleParam(
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
getAxisParamChecked(angleAxis_, motorRecResolution,
&motorRecResolution);
status = offsetAxes_[2]->motorPosition(&offsetAx2Pos);
if (status != asynSuccess) {
return status;
}
pl_status = offsetAxes_[2]->motorPosition(&offsetAx2Pos);
if (pl_status != asynSuccess) {
return pl_status;
}
pl_status = offsetAxes_[3]->motorPosition(&offsetAx3Pos);
if (pl_status != asynSuccess) {
return pl_status;
status = offsetAxes_[3]->motorPosition(&offsetAx3Pos);
if (status != asynSuccess) {
return status;
}
deriveLiftAndAngle(
@@ -382,14 +325,14 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
&angle);
// Set the position values in the parameter library
pl_status = setMotorPosition(lift);
if (pl_status != asynSuccess) {
return pl_status;
status = setMotorPosition(lift);
if (status != asynSuccess) {
return status;
}
pl_status = angleAxis_->setMotorPosition(angle);
if (pl_status != asynSuccess) {
return pl_status;
status = angleAxis_->setMotorPosition(angle);
if (status != asynSuccess) {
return status;
}
// Calculate the new liftPosition_ of all seleneOffsetAxis
@@ -414,45 +357,22 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
// Set the limits for the lift axis
double motPos = 0.0;
pl_status = motorPosition(&motPos);
if (pl_status != asynSuccess) {
return pl_status;
status = motorPosition(&motPos);
if (status != asynSuccess) {
return status;
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
motPos + smallestDistHighLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(),
motPos - smallestDistLowLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorHighLimitFromDriver,
motPos + smallestDistHighLimit);
setAxisParamChecked(this, motorLowLimitFromDriver,
motPos - smallestDistLowLimit);
// The virtual axes are in an error state, if at least one of the underlying
// real axes is in an error state.
for (int i = 0; i < numAxes_; i++) {
pl_status = pC_->getStringParam(offsetAxes_[i]->axisNo(),
pC_->motorMessageText(),
sizeof(userMessage), userMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText",
offsetAxes_[i]->axisNo(),
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(offsetAxes_[i], motorMessageText, userMessage);
if (strlen(userMessage) != 0) {
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText, userMessage);
return asynError;
}
}
@@ -461,20 +381,20 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
}
asynStatus seleneLiftAxis::doMove(double position, int relative,
double min_velocity, double max_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
double motorRecResolution = 0.0;
asynStatus status = asynSuccess;
status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorRecResolution_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
double motorRecResolution = 0.0;
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
setTargetPosition(position * motorRecResolution);
targetSet_ = true;
status = startCombinedMoveFromVirtualAxis();
asynStatus status = startCombinedMoveFromVirtualAxis();
targetSet_ = false;
return status;
}
@@ -521,34 +441,29 @@ asynStatus seleneLiftAxis::startCombinedMove() {
asynStatus seleneLiftAxis::stop(double acceleration) {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
asynStatus status = asynSuccess;
char response[pC_->MAXBUF_] = {0};
// =========================================================================
// Stop all axes
rw_status = pC_->writeRead(axisNo_, "P150=8", response, 0);
// Suppress unused variable warnings
(void)acceleration;
if (rw_status != asynSuccess) {
// Stop all axes
status = pC_->writeRead(axisNo_, "P150=8", response, 0);
if (status != 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__);
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorStatusProblem, true);
}
return rw_status;
return status;
}
asynStatus seleneLiftAxis::doReset() {
@@ -561,30 +476,29 @@ asynStatus seleneLiftAxis::doReset() {
}
asynStatus seleneLiftAxis::enable(bool on) {
asynStatus pl_status = setStringParam(pC_->motorMessageText(),
"Axis cannot be enabled / disabled");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
return pl_status;
// Suppress unused variable warnings
(void)on;
setAxisParamChecked(this, motorMessageText,
"Axis cannot be enabled / disabled");
return asynSuccess;
}
asynStatus seleneLiftAxis::readEncoderType() {
asynStatus pl_status =
setStringParam(pC_->encoderType(), IncrementalEncoder);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, encoderType, IncrementalEncoder);
return asynSuccess;
}
asynStatus seleneLiftAxis::doHome(double minVelocity, double maxVelocity,
double acceleration, int forwards) {
// Suppress unused variable warnings
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
(void)forwards;
char response[pC_->MAXBUF_] = {0};
// No answer expected
@@ -742,8 +656,9 @@ static const iocshArg *const CreateAxisArgs[] = {
&CreateAxisArg3, &CreateAxisArg4, &CreateAxisArg5,
&CreateAxisArg6, &CreateAxisArg7, &CreateAxisArg8,
};
static const iocshFuncDef configSeleneVirtualCreateAxes = {"seleneVirtualAxes",
9, CreateAxisArgs};
static const iocshFuncDef configSeleneVirtualCreateAxes = {
"seleneVirtualAxes", 9, CreateAxisArgs,
"Creates instances of Selene axes."};
static void configSeleneVirtualCreateAxesCallFunc(const iocshArgBuf *args) {
seleneVirtualCreateAxes(args[0].sval, args[1].ival, args[2].ival,
args[3].ival, args[4].ival, args[5].ival,

View File

@@ -1,20 +1,17 @@
#ifndef seleneLiftAxis_H
#define seleneLiftAxis_H
#include "seleneAngleAxis.h"
#include "seleneGuideController.h"
#include "seleneOffsetAxis.h"
#include "turboPmacAxis.h"
#include <array>
// Forward declaration of the seleneGuideController class to resolve the cyclic
// dependency. See https://en.cppreference.com/w/cpp/language/class.
class seleneGuideController;
/**
* @brief Virtual axis for setting the height of the center of a Selene guide
*
* Please see README.md for a detailed explanation.
*/
class seleneLiftAxis : public turboPmacAxis {
class HIDDEN seleneLiftAxis : public turboPmacAxis {
public:
static const int numAxes_ = 6;
@@ -68,12 +65,12 @@ class seleneLiftAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**
@@ -278,6 +275,11 @@ class seleneLiftAxis : public turboPmacAxis {
*/
seleneOffsetAxis *offsetAxis(int idx);
/**
* @brief Return a pointer to the axis controller
*/
virtual seleneGuideController *pController() override { return pC_; };
protected:
std::array<seleneOffsetAxis *, numAxes_> offsetAxes_;

View File

@@ -50,18 +50,33 @@ seleneOffsetAxis::seleneOffsetAxis(seleneGuideController *pController,
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusDone(), 1);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorStatusDone", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving(), 0);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorStatusMoving", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorEncoderPosition(), 0.0);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorEncoderPosition", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
// Register the hook function during construction of the first axis
@@ -77,8 +92,13 @@ seleneOffsetAxis::seleneOffsetAxis(seleneGuideController *pController,
// Selene guide motors cannot be disabled
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
if (status != asynSuccess) {
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
// Even though this happens already in sinqAxis, a default value for
@@ -132,16 +152,8 @@ asynStatus seleneOffsetAxis::init() {
}
// Read the initial limits from the paramlib
status = pC_->getDoubleParam(axisNo_, pC_->motorHighLimit(), &highLimit_);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorHighLimit", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->getDoubleParam(axisNo_, pC_->motorLowLimit(), &lowLimit_);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorLowLimit", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
getAxisParamChecked(this, motorHighLimit, &highLimit_);
getAxisParamChecked(this, motorLowLimit, &lowLimit_);
// The high limits read from the paramLib are divided by motorRecResolution,
// hence we need to multiply them to undo this change.
@@ -214,24 +226,10 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
// Update the parameter library
if (error != 0) {
status = setStringParam(pC_->motorMessageText(), userMessage);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorMessageText",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
status = setIntegerParam(pC_->motorStatusProblem(), true);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText, userMessage);
setAxisParamChecked(this, motorStatusProblem, true);
}
// TODO: To be removed, once the real limits are derived
// highLimit = 10.0;
// lowLimit = -10.0;
// Convert into lift coordinate system
absoluteHighLimitLiftCS_ = highLimit - zOffset_;
absoluteLowLimitLiftCS_ = lowLimit - zOffset_;
@@ -251,20 +249,8 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
relLowLimit = lowLimit - encoderPosition;
}
status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
relHighLimit);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorHighLimitFromDriver_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(),
relLowLimit);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorLowLimit_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorHighLimitFromDriver, relHighLimit);
setAxisParamChecked(this, motorLowLimitFromDriver, relLowLimit);
/*
If this axis is moving as a result of an individual move command to the axis
@@ -278,57 +264,36 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
}
}
status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorStatusDone_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving));
// Axis is always shown as enabled, since it is enabled automatically by the
// controller when a move command P150=1 is sent and disabled once the
// movement is completed.
status = setIntegerParam(pC_->motorEnableRBV(), 1);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorEnableRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorEnableRBV, true);
return errorStatus;
}
asynStatus
seleneOffsetAxis::setPositionsFromEncoderPosition(double encoderPosition) {
asynStatus status = pC_->setDoubleParam(
axisNo_, pC_->motorAbsolutePositionRBV(), encoderPosition);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorEncoderPosition",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorAbsolutePositionRBV, encoderPosition);
absolutePositionLiftCS_ = encoderPosition - zOffset_;
return status;
return asynSuccess;
}
asynStatus seleneOffsetAxis::doMove(double position, int relative,
double min_velocity,
double maxOffset_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
double motorRecResolution = 0.0;
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
asynStatus pl_status = pC_->getDoubleParam(
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
double motorRecResolution = 0.0;
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
// Set the target position
setTargetPosition(position * motorRecResolution);
@@ -339,14 +304,12 @@ asynStatus seleneOffsetAxis::doMove(double position, int relative,
}
asynStatus seleneOffsetAxis::enable(bool on) {
asynStatus pl_status = setStringParam(pC_->motorMessageText(),
"Axis cannot be enabled / disabled");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
return pl_status;
// Suppress unused variable warnings
(void)on;
setAxisParamChecked(this, motorMessageText,
"Axis cannot be enabled / disabled");
return asynSuccess;
}
asynStatus seleneOffsetAxis::normalizePositions() {
@@ -429,7 +392,8 @@ static const iocshArg *const CreateAxisArgs[] = {
&CreateAxisArg3,
};
static const iocshFuncDef configSeleneOffsetAxisCreateAxis = {
"seleneOffsetAxis", 4, CreateAxisArgs};
"seleneOffsetAxis", 4, CreateAxisArgs,
"Creates a new instance of a Selene offset axis."};
static void configSeleneOffsetAxisCreateAxisCallFunc(const iocshArgBuf *args) {
seleneOffsetAxisCreateAxis(args[0].sval, args[1].ival, args[2].dval,
args[3].dval);

View File

@@ -1,23 +1,20 @@
#ifndef seleneOffsetAxis_H
#define seleneOffsetAxis_H
#include "seleneGuideController.h"
#include "turboPmacAxis.h"
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class seleneLiftAxis;
// Forward declaration of the seleneGuideController class to resolve the cyclic
// dependency. See https://en.cppreference.com/w/cpp/language/class.
class seleneGuideController;
class HIDDEN seleneLiftAxis;
/**
* @brief Virtual axis for setting the offset of a motor of the Selene guide
*
* Please see README.md for a detailed explanation.
*/
class seleneOffsetAxis : public turboPmacAxis {
class HIDDEN seleneOffsetAxis : public turboPmacAxis {
public:
/**
* @brief Construct a new selene Offset Axis object
@@ -54,12 +51,12 @@ class seleneOffsetAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**
@@ -126,6 +123,11 @@ class seleneOffsetAxis : public turboPmacAxis {
*/
double absoluteLowLimitLiftCS() { return absoluteLowLimitLiftCS_; }
/**
* @brief Return a pointer to the axis controller
*/
virtual seleneGuideController *pController() override { return pC_; };
protected:
// True, if the target has been set from this axis
bool targetSet_;