Compare commits
28 Commits
static-dep
...
1.3.3
| Author | SHA1 | Date | |
|---|---|---|---|
| f5287609e5 | |||
| e322dd09c1 | |||
| 754fc16cd3 | |||
| a7cb1cd05f | |||
| f9d5d1aaee | |||
| ef81f38017 | |||
| 6ee554f9e5 | |||
| 7bd3adbfc3 | |||
| bff7ad79df | |||
| 70029b12b2 | |||
| ac5ab3855e | |||
| 2c9de618ec | |||
| b834dc3f8d | |||
| ee6235e74a | |||
| 48c068826c | |||
| c494fc88a5 | |||
| e0fa9ef3a9 | |||
| dc6d5c40b3 | |||
| 56288b1db8 | |||
| dde15eb30d | |||
| efccb26302 | |||
| 85d443a92b | |||
| 588ca158c1 | |||
| 3780dee24f | |||
| c736c191d0 | |||
| 42784c2bff | |||
| 2636296539 | |||
| b09f081db9 |
30
.gitea/workflows/action.yaml
Normal file
30
.gitea/workflows/action.yaml
Normal 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
|
||||||
@@ -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
|
|
||||||
3
Makefile
3
Makefile
@@ -42,4 +42,5 @@ DBDS += turboPmac/sinqMotor/src/sinqMotor.dbd
|
|||||||
DBDS += turboPmac/src/turboPmac.dbd
|
DBDS += turboPmac/src/turboPmac.dbd
|
||||||
DBDS += src/seleneGuide.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
|
||||||
@@ -44,7 +44,7 @@ Two additional PVs are provided in `db/seleneGuide.db`:
|
|||||||
### Usage in IOC shell
|
### Usage in IOC shell
|
||||||
|
|
||||||
seleneGuide exports the following IOC shell functions:
|
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.
|
- `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.
|
- `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);
|
seleneOffsetAxis("$(NAME)",6, 7463.87259, 0.0);
|
||||||
|
|
||||||
# These are two "normal" PMAC axes which work the same way they would with a turboPmacController.
|
# These are two "normal" PMAC axes which work the same way they would with a turboPmacController.
|
||||||
turboPmacAxis("$(NAME)",7);
|
# Using the wrapper seleneStandardAxis ensures compatibility to the seleneGuideController.
|
||||||
turboPmacAxis("$(NAME)",8);
|
seleneStandardAxis("$(NAME)",7);
|
||||||
|
seleneStandardAxis("$(NAME)",8);
|
||||||
|
|
||||||
# This function call creates the lift and the angle axes.
|
# 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
|
# The arguments on position 2 to 7 are the axis indices of the offset axes
|
||||||
|
|||||||
@@ -19,66 +19,79 @@ seleneAngleAxis::seleneAngleAxis(seleneGuideController *pController, int axisNo,
|
|||||||
// Selene guide motors cannot be disabled
|
// Selene guide motors cannot be disabled
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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
|
||||||
|
// motorMessageText is set here again, because apparently the sinqAxis
|
||||||
|
// constructor is not run before the string is accessed?
|
||||||
|
status = setStringParam(pC_->motorMessageText(), "");
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seleneAngleAxis::~seleneAngleAxis() {}
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::stop(double acceleration) {
|
asynStatus seleneAngleAxis::stop(double acceleration) {
|
||||||
return liftAxis_->stop(acceleration);
|
return liftAxis_->stop(acceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::doMove(double position, int relative,
|
asynStatus seleneAngleAxis::doMove(double position, int relative,
|
||||||
double min_velocity, double max_velocity,
|
double minVelocity, double maxVelocity,
|
||||||
double acceleration) {
|
double acceleration) {
|
||||||
|
|
||||||
|
// Suppress unused variable warnings
|
||||||
|
(void)relative;
|
||||||
|
(void)minVelocity;
|
||||||
|
(void)maxVelocity;
|
||||||
|
(void)acceleration;
|
||||||
|
|
||||||
double motorRecResolution = 0.0;
|
double motorRecResolution = 0.0;
|
||||||
|
|
||||||
asynStatus pl_status = pC_->getDoubleParam(
|
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
setTargetPosition(position * motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
targetPosition_ = position * motorRecResolution;
|
|
||||||
targetSet_ = true;
|
targetSet_ = true;
|
||||||
return liftAxis_->startCombinedMoveFromVirtualAxis();
|
return liftAxis_->startCombinedMoveFromVirtualAxis();
|
||||||
targetSet_ = false;
|
targetSet_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::targetPosition(double *targetPosition) {
|
double seleneAngleAxis::targetPosition() {
|
||||||
asynStatus status = asynSuccess;
|
|
||||||
|
|
||||||
if (targetSet_) {
|
if (targetSet_) {
|
||||||
*targetPosition = targetPosition_;
|
return turboPmacAxis::targetPosition();
|
||||||
} else {
|
} else {
|
||||||
status = motorPosition(targetPosition);
|
double targetPos = 0;
|
||||||
|
motorPosition(&targetPos);
|
||||||
|
return targetPos;
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::doPoll(bool *moving) {
|
asynStatus seleneAngleAxis::doPoll(bool *moving) {
|
||||||
|
|
||||||
char userMessage[pC_->MAXBUF_] = {0};
|
char errorMessage[pC_->MAXBUF_] = {0};
|
||||||
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// In the doPoll method of `seleneLiftAxis`, the parameters
|
// In the doPoll method of `seleneLiftAxis`, the parameters
|
||||||
// `motorStatusMoving` and `motorStatusDone` of this axis have already been
|
// `motorStatusMoving` and `motorStatusDone` of this axis have already been
|
||||||
// set accordingly.
|
// set accordingly.
|
||||||
int isMoving = 0;
|
getAxisParamChecked(this, motorStatusMoving, moving);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
double motPos = 0.0;
|
double motPos = 0.0;
|
||||||
pl_status = motorPosition(&motPos);
|
status = motorPosition(&motPos);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -111,9 +124,9 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
|
|||||||
double smallestHighLimit = std::numeric_limits<double>::infinity();
|
double smallestHighLimit = std::numeric_limits<double>::infinity();
|
||||||
double smallestLowLimit = std::numeric_limits<double>::infinity();
|
double smallestLowLimit = std::numeric_limits<double>::infinity();
|
||||||
double liftPosition = 0.0;
|
double liftPosition = 0.0;
|
||||||
pl_status = liftAxis_->motorPosition(&liftPosition);
|
status = liftAxis_->motorPosition(&liftPosition);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < liftAxis_->numAxes_; i++) {
|
for (int i = 0; i < liftAxis_->numAxes_; i++) {
|
||||||
@@ -122,9 +135,9 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
|
|||||||
double leverArm = oAxis->xOffset() - liftAxis_->xPos();
|
double leverArm = oAxis->xOffset() - liftAxis_->xPos();
|
||||||
|
|
||||||
double motPos = 0.0;
|
double motPos = 0.0;
|
||||||
pl_status = oAxis->motorPosition(&motPos);
|
status = oAxis->motorPosition(&motPos);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -161,52 +174,23 @@ asynStatus seleneAngleAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
|
setAxisParamChecked(this, motorHighLimitFromDriver, smallestHighLimit);
|
||||||
smallestHighLimit);
|
setAxisParamChecked(this, motorLowLimitFromDriver, smallestLowLimit);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This axis should always be seen as enabled, since it is automatically
|
// This axis should always be seen as enabled, since it is automatically
|
||||||
// enabled before each movement and disabled afterwards
|
// enabled before each movement and disabled afterwards
|
||||||
pl_status = setIntegerParam(pC_->motorEnableRBV(), 1);
|
setAxisParamChecked(this, motorEnableRBV, true);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If an error message is set in the liftAxis_, copy this message into this
|
// If an error message is set in the liftAxis_, copy this message into this
|
||||||
// axis.
|
// axis.
|
||||||
pl_status =
|
getAxisParamChecked(liftAxis_, motorMessageText, &errorMessage);
|
||||||
pC_->getStringParam(liftAxis_->axisNo(), pC_->motorMessageText(),
|
|
||||||
sizeof(userMessage), userMessage);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText",
|
|
||||||
liftAxis_->axisNo(),
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(userMessage) != 0) {
|
if (strlen(errorMessage) != 0) {
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, errorMessage);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::doReset() { return liftAxis_->reset(); }
|
asynStatus seleneAngleAxis::doReset() { return liftAxis_->reset(); }
|
||||||
@@ -214,13 +198,7 @@ asynStatus seleneAngleAxis::doReset() { return liftAxis_->reset(); }
|
|||||||
asynStatus seleneAngleAxis::enable(bool on) { return liftAxis_->enable(on); }
|
asynStatus seleneAngleAxis::enable(bool on) { return liftAxis_->enable(on); }
|
||||||
|
|
||||||
asynStatus seleneAngleAxis::readEncoderType() {
|
asynStatus seleneAngleAxis::readEncoderType() {
|
||||||
asynStatus pl_status =
|
setAxisParamChecked(this, encoderType, IncrementalEncoder);
|
||||||
setStringParam(pC_->encoderType(), IncrementalEncoder);
|
|
||||||
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,19 @@
|
|||||||
#ifndef seleneAngleAxis_H
|
#ifndef seleneAngleAxis_H
|
||||||
#define seleneAngleAxis_H
|
#define seleneAngleAxis_H
|
||||||
|
#include "seleneGuideController.h"
|
||||||
#include "turboPmacAxis.h"
|
#include "turboPmacAxis.h"
|
||||||
|
|
||||||
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
|
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
|
||||||
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
|
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
|
||||||
// See https://en.cppreference.com/w/cpp/language/class.
|
// See https://en.cppreference.com/w/cpp/language/class.
|
||||||
class seleneLiftAxis;
|
class HIDDEN seleneLiftAxis;
|
||||||
|
|
||||||
// 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 angle of the Selene guide
|
* @brief Virtual axis for setting the angle of the Selene guide
|
||||||
*
|
*
|
||||||
* Please see README.md for a detailed explanation.
|
* Please see README.md for a detailed explanation.
|
||||||
*/
|
*/
|
||||||
class seleneAngleAxis : public turboPmacAxis {
|
class HIDDEN seleneAngleAxis : public turboPmacAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new seleneAngleAxis.
|
* @brief Construct a new seleneAngleAxis.
|
||||||
@@ -32,6 +29,8 @@ class seleneAngleAxis : public turboPmacAxis {
|
|||||||
seleneAngleAxis(seleneGuideController *pController, int axisNo,
|
seleneAngleAxis(seleneGuideController *pController, int axisNo,
|
||||||
seleneLiftAxis *liftAxis);
|
seleneLiftAxis *liftAxis);
|
||||||
|
|
||||||
|
virtual ~seleneAngleAxis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `stop` function from asynMotorAxis
|
* @brief Implementation of the `stop` function from asynMotorAxis
|
||||||
*
|
*
|
||||||
@@ -49,12 +48,12 @@ class seleneAngleAxis : public turboPmacAxis {
|
|||||||
*
|
*
|
||||||
* @param position
|
* @param position
|
||||||
* @param relative
|
* @param relative
|
||||||
* @param min_velocity
|
* @param minVelocity
|
||||||
* @param maxOffset_velocity
|
* @param maxOffset_velocity
|
||||||
* @param acceleration
|
* @param acceleration
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doMove(double position, int relative, double min_velocity,
|
asynStatus doMove(double position, int relative, double minVelocity,
|
||||||
double maxOffset_velocity, double acceleration);
|
double maxOffset_velocity, double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,13 +99,11 @@ class seleneAngleAxis : public turboPmacAxis {
|
|||||||
double acceleration, int forwards);
|
double acceleration, int forwards);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the target position from the axis and write it into the
|
* @brief Override of the superclass method
|
||||||
* provided pointer.
|
|
||||||
*
|
*
|
||||||
* @param targetPosition
|
* @return double
|
||||||
* @return asynStatus
|
|
||||||
*/
|
*/
|
||||||
asynStatus targetPosition(double *targetPosition);
|
double targetPosition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the offsets of axis 3 and 4 to zero and recalculate all other
|
* @brief Set the offsets of axis 3 and 4 to zero and recalculate all other
|
||||||
@@ -140,6 +137,11 @@ class seleneAngleAxis : public turboPmacAxis {
|
|||||||
*/
|
*/
|
||||||
asynStatus rereadEncoder() { return asynSuccess; }
|
asynStatus rereadEncoder() { return asynSuccess; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the axis controller
|
||||||
|
*/
|
||||||
|
virtual seleneGuideController *pController() override { return pC_; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
seleneGuideController *pC_;
|
seleneGuideController *pC_;
|
||||||
seleneLiftAxis *liftAxis_;
|
seleneLiftAxis *liftAxis_;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
registrar(seleneVirtualAxesRegister)
|
registrar(seleneVirtualAxesRegister)
|
||||||
registrar(seleneOffsetAxisRegister)
|
registrar(seleneOffsetAxisRegister)
|
||||||
|
registrar(seleneStandardAxisRegister)
|
||||||
registrar(seleneGuideControllerRegister)
|
registrar(seleneGuideControllerRegister)
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
#include "seleneGuideController.h"
|
#include "seleneGuideController.h"
|
||||||
|
#include "seleneAngleAxis.h"
|
||||||
|
#include "seleneLiftAxis.h"
|
||||||
|
#include "seleneOffsetAxis.h"
|
||||||
#include "turboPmacController.h"
|
#include "turboPmacController.h"
|
||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
@@ -20,7 +23,8 @@ seleneGuideController::seleneGuideController(
|
|||||||
const char *portName, const char *ipPortConfigName, int numAxes,
|
const char *portName, const char *ipPortConfigName, int numAxes,
|
||||||
double movingPollPeriod, double idlePollPeriod, double comTimeout)
|
double movingPollPeriod, double idlePollPeriod, double comTimeout)
|
||||||
: turboPmacController(portName, ipPortConfigName, numAxes, movingPollPeriod,
|
: turboPmacController(portName, ipPortConfigName, numAxes, movingPollPeriod,
|
||||||
idlePollPeriod, NUM_seleneGuide_DRIVER_PARAMS)
|
idlePollPeriod, comTimeout,
|
||||||
|
NUM_seleneGuide_DRIVER_PARAMS)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -48,6 +52,8 @@ seleneGuideController::seleneGuideController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seleneGuideController::~seleneGuideController() {}
|
||||||
|
|
||||||
asynStatus seleneGuideController::writeInt32(asynUser *pasynUser,
|
asynStatus seleneGuideController::writeInt32(asynUser *pasynUser,
|
||||||
epicsInt32 value) {
|
epicsInt32 value) {
|
||||||
int function = pasynUser->reason;
|
int function = pasynUser->reason;
|
||||||
@@ -140,7 +146,8 @@ static const iocshArg *const CreateControllerArgs[] = {
|
|||||||
&CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2,
|
&CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2,
|
||||||
&CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5};
|
&CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5};
|
||||||
static const iocshFuncDef configSeleneGuideCreateController = {
|
static const iocshFuncDef configSeleneGuideCreateController = {
|
||||||
"seleneGuideController", 6, CreateControllerArgs};
|
"seleneGuideController", 6, CreateControllerArgs,
|
||||||
|
"Create a new instance of a Selene controller."};
|
||||||
static void configSeleneGuideCreateControllerCallFunc(const iocshArgBuf *args) {
|
static void configSeleneGuideCreateControllerCallFunc(const iocshArgBuf *args) {
|
||||||
seleneGuideCreateController(args[0].sval, args[1].sval, args[2].ival,
|
seleneGuideCreateController(args[0].sval, args[1].sval, args[2].ival,
|
||||||
args[3].dval, args[4].dval, args[5].dval);
|
args[3].dval, args[4].dval, args[5].dval);
|
||||||
@@ -154,4 +161,97 @@ static void seleneGuideControllerRegister(void) {
|
|||||||
}
|
}
|
||||||
epicsExportRegistrar(seleneGuideControllerRegister);
|
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"
|
} // extern "C"
|
||||||
|
|||||||
@@ -8,12 +8,16 @@
|
|||||||
|
|
||||||
#ifndef seleneGuideController_H
|
#ifndef seleneGuideController_H
|
||||||
#define seleneGuideController_H
|
#define seleneGuideController_H
|
||||||
#include "seleneAngleAxis.h"
|
|
||||||
#include "seleneLiftAxis.h"
|
|
||||||
#include "seleneOffsetAxis.h"
|
|
||||||
#include "turboPmacController.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:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -34,6 +38,8 @@ class seleneGuideController : public turboPmacController {
|
|||||||
int numAxes, double movingPollPeriod,
|
int numAxes, double movingPollPeriod,
|
||||||
double idlePollPeriod, double comTimeout);
|
double idlePollPeriod, double comTimeout);
|
||||||
|
|
||||||
|
virtual ~seleneGuideController();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Overloaded function of turboPmacController
|
* @brief Overloaded function of turboPmacController
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -96,11 +96,32 @@ seleneLiftAxis::seleneLiftAxis(seleneGuideController *pC, int axis1No,
|
|||||||
// Selene guide motors cannot be disabled
|
// Selene guide motors cannot be disabled
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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
|
||||||
|
// motorMessageText is set here again, because apparently the sinqAxis
|
||||||
|
// constructor is not run before the string is accessed?
|
||||||
|
status = setStringParam(pC_->motorMessageText(), "");
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seleneLiftAxis::~seleneLiftAxis() {}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::init() {
|
asynStatus seleneLiftAxis::init() {
|
||||||
|
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
@@ -135,44 +156,17 @@ asynStatus seleneLiftAxis::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assume the virtual axes are not moving at the start
|
// Assume the virtual axes are not moving at the start
|
||||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
setAxisParamChecked(this, motorStatusMoving, false);
|
||||||
if (status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusDone, true);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = angleAxis_->setIntegerParam(pC_->motorStatusMoving(), 0);
|
setAxisParamChecked(angleAxis_, motorStatusMoving, false);
|
||||||
if (status != asynSuccess) {
|
setAxisParamChecked(angleAxis_, motorStatusDone, true);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The virtual axes should always be seen as enabled, since the underlying
|
// The virtual axes should always be seen as enabled, since the underlying
|
||||||
// hardware is automatically enabled after sending a start command to the
|
// hardware is automatically enabled after sending a start command to the
|
||||||
// controller and automatically disabled after the movement finished.
|
// controller and automatically disabled after the movement finished.
|
||||||
status = setIntegerParam(pC_->motorEnableRBV(), 1);
|
setAxisParamChecked(this, motorEnableRBV, true);
|
||||||
if (status != asynSuccess) {
|
setAxisParamChecked(angleAxis_, motorEnableRBV, true);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = normalizePositions();
|
status = normalizePositions();
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@@ -261,12 +255,7 @@ asynStatus seleneLiftAxis::normalizePositions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
||||||
|
asynStatus status = asynSuccess;
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
|
||||||
asynStatus rw_status = asynSuccess;
|
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
char userMessage[pC_->MAXBUF_] = {0};
|
char userMessage[pC_->MAXBUF_] = {0};
|
||||||
@@ -277,18 +266,12 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
pl_status =
|
getAxisParamChecked(this, motorStatusDone, &wasDone);
|
||||||
pC_->getIntegerParam(axisNo(), pC_->motorStatusDone(), &wasDone);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving",
|
|
||||||
axisNo(), __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *command = "P158";
|
const char *command = "P158";
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 1);
|
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvals = sscanf(response, "%d", &axStatus);
|
nvals = sscanf(response, "%d", &axStatus);
|
||||||
@@ -299,31 +282,12 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
*moving = (axStatus != 0);
|
*moving = (axStatus != 0);
|
||||||
|
|
||||||
// Set the moving status of seleneLiftAxis
|
// Set the moving status of seleneLiftAxis
|
||||||
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
|
setAxisParamChecked(this, motorStatusMoving, *moving);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusDone, !(*moving));
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the moving status of seleneAngleAxis
|
// Set the moving status of seleneAngleAxis
|
||||||
pl_status = angleAxis_->setIntegerParam(pC_->motorStatusMoving(), *moving);
|
setAxisParamChecked(angleAxis_, motorStatusMoving, *moving);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(angleAxis_, motorStatusDone, !(*moving));
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If an seleneOffsetAxis is moving, the positions of the virtual axes
|
If an seleneOffsetAxis is moving, the positions of the virtual axes
|
||||||
@@ -342,22 +306,17 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
double motorRecResolution = 0.0;
|
double motorRecResolution = 0.0;
|
||||||
|
|
||||||
asynStatus pl_status = pC_->getDoubleParam(
|
getAxisParamChecked(angleAxis_, motorRecResolution,
|
||||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
&motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
status = offsetAxes_[2]->motorPosition(&offsetAx2Pos);
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
if (status != asynSuccess) {
|
||||||
__LINE__);
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = offsetAxes_[2]->motorPosition(&offsetAx2Pos);
|
status = offsetAxes_[3]->motorPosition(&offsetAx3Pos);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = offsetAxes_[3]->motorPosition(&offsetAx3Pos);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pl_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deriveLiftAndAngle(
|
deriveLiftAndAngle(
|
||||||
@@ -366,14 +325,14 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
&angle);
|
&angle);
|
||||||
|
|
||||||
// Set the position values in the parameter library
|
// Set the position values in the parameter library
|
||||||
pl_status = setMotorPosition(lift);
|
status = setMotorPosition(lift);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = angleAxis_->setMotorPosition(angle);
|
status = angleAxis_->setMotorPosition(angle);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the new liftPosition_ of all seleneOffsetAxis
|
// Calculate the new liftPosition_ of all seleneOffsetAxis
|
||||||
@@ -398,45 +357,22 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
// Set the limits for the lift axis
|
// Set the limits for the lift axis
|
||||||
double motPos = 0.0;
|
double motPos = 0.0;
|
||||||
pl_status = motorPosition(&motPos);
|
status = motorPosition(&motPos);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
|
setAxisParamChecked(this, motorHighLimitFromDriver,
|
||||||
motPos + smallestDistHighLimit);
|
motPos + smallestDistHighLimit);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(this, motorLowLimitFromDriver,
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
|
motPos - smallestDistLowLimit);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The virtual axes are in an error state, if at least one of the underlying
|
// The virtual axes are in an error state, if at least one of the underlying
|
||||||
// real axes is in an error state.
|
// real axes is in an error state.
|
||||||
for (int i = 0; i < numAxes_; i++) {
|
for (int i = 0; i < numAxes_; i++) {
|
||||||
pl_status = pC_->getStringParam(offsetAxes_[i]->axisNo(),
|
setAxisParamChecked(offsetAxes_[i], motorMessageText, userMessage);
|
||||||
pC_->motorMessageText(),
|
|
||||||
sizeof(userMessage), userMessage);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText",
|
|
||||||
offsetAxes_[i]->axisNo(),
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(userMessage) != 0) {
|
if (strlen(userMessage) != 0) {
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,33 +381,32 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::doMove(double position, int relative,
|
asynStatus seleneLiftAxis::doMove(double position, int relative,
|
||||||
double min_velocity, double max_velocity,
|
double minVelocity, double maxVelocity,
|
||||||
double acceleration) {
|
double acceleration) {
|
||||||
double motorRecResolution = 0.0;
|
|
||||||
asynStatus status = asynSuccess;
|
|
||||||
|
|
||||||
status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
|
// Suppress unused variable warnings
|
||||||
&motorRecResolution);
|
(void)relative;
|
||||||
if (status != asynSuccess) {
|
(void)minVelocity;
|
||||||
return pC_->paramLibAccessFailed(status, "motorRecResolution_", axisNo_,
|
(void)maxVelocity;
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
(void)acceleration;
|
||||||
}
|
|
||||||
targetPosition_ = position * motorRecResolution;
|
double motorRecResolution = 0.0;
|
||||||
|
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||||
|
setTargetPosition(position * motorRecResolution);
|
||||||
targetSet_ = true;
|
targetSet_ = true;
|
||||||
status = startCombinedMoveFromVirtualAxis();
|
asynStatus status = startCombinedMoveFromVirtualAxis();
|
||||||
targetSet_ = false;
|
targetSet_ = false;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::targetPosition(double *targetPosition) {
|
double seleneLiftAxis::targetPosition() {
|
||||||
asynStatus status = asynSuccess;
|
|
||||||
|
|
||||||
if (targetSet_) {
|
if (targetSet_) {
|
||||||
*targetPosition = targetPosition_;
|
return turboPmacAxis::targetPosition();
|
||||||
} else {
|
} else {
|
||||||
status = motorPosition(targetPosition);
|
double targetPos = 0;
|
||||||
|
motorPosition(&targetPos);
|
||||||
|
return targetPos;
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::startCombinedMove() {
|
asynStatus seleneLiftAxis::startCombinedMove() {
|
||||||
@@ -480,34 +415,18 @@ asynStatus seleneLiftAxis::startCombinedMove() {
|
|||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
double liftTargetPosition = 0.0;
|
double liftTargetPosition = 0.0;
|
||||||
double angleTargetPosition = 0.0;
|
double angleTargetPosition = 0.0;
|
||||||
asynStatus status = asynSuccess;
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
status = targetPosition(&liftTargetPosition);
|
liftTargetPosition = targetPosition();
|
||||||
if (status != asynSuccess) {
|
angleTargetPosition = angleAxis_->targetPosition();
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = angleAxis_->targetPosition(&angleTargetPosition);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
errlogPrintf("Target lift: %lf, Target angle: %lf\n", liftTargetPosition,
|
|
||||||
angleTargetPosition);
|
|
||||||
|
|
||||||
auto targetPositions =
|
auto targetPositions =
|
||||||
positionsFromLiftAndAngle(liftTargetPosition, angleTargetPosition);
|
positionsFromLiftAndAngle(liftTargetPosition, angleTargetPosition);
|
||||||
|
|
||||||
// Apply the offsets of the individual offset axes
|
// Apply the offsets of the individual offset axes
|
||||||
for (int i = 0; i < numAxes_; i++) {
|
for (int i = 0; i < numAxes_; i++) {
|
||||||
double offsetTargetPosition = 0.0;
|
targetPositions[i] =
|
||||||
status = offsetAxes_[i]->targetPosition(&offsetTargetPosition);
|
targetPositions[i] + offsetAxes_[i]->targetPosition();
|
||||||
if (status != asynSuccess) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
targetPositions[i] = targetPositions[i] + offsetTargetPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set all target positions and send the move command
|
// Set all target positions and send the move command
|
||||||
@@ -516,42 +435,35 @@ asynStatus seleneLiftAxis::startCombinedMove() {
|
|||||||
targetPositions[0], targetPositions[1], targetPositions[2],
|
targetPositions[0], targetPositions[1], targetPositions[2],
|
||||||
targetPositions[3], targetPositions[4], targetPositions[5]);
|
targetPositions[3], targetPositions[4], targetPositions[5]);
|
||||||
|
|
||||||
errlogPrintf("%s\n", command);
|
|
||||||
|
|
||||||
// No answer expected
|
// No answer expected
|
||||||
return pC_->writeRead(axisNo_, command, response, 0);
|
return pC_->writeRead(axisNo_, command, response, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::stop(double acceleration) {
|
asynStatus seleneLiftAxis::stop(double acceleration) {
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
// Stop all axes
|
// Suppress unused variable warnings
|
||||||
rw_status = pC_->writeRead(axisNo_, "P150=8", response, 0);
|
(void)acceleration;
|
||||||
|
|
||||||
if (rw_status != asynSuccess) {
|
// Stop all axes
|
||||||
|
status = pC_->writeRead(axisNo_, "P150=8", response, 0);
|
||||||
|
|
||||||
|
if (status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||||
"failed.\n",
|
"failed.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::doReset() {
|
asynStatus seleneLiftAxis::doReset() {
|
||||||
@@ -564,30 +476,29 @@ asynStatus seleneLiftAxis::doReset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::enable(bool on) {
|
asynStatus seleneLiftAxis::enable(bool on) {
|
||||||
asynStatus pl_status = setStringParam(pC_->motorMessageText(),
|
|
||||||
"Axis cannot be enabled / disabled");
|
// Suppress unused variable warnings
|
||||||
if (pl_status != asynSuccess) {
|
(void)on;
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
setAxisParamChecked(this, motorMessageText,
|
||||||
__LINE__);
|
"Axis cannot be enabled / disabled");
|
||||||
}
|
return asynSuccess;
|
||||||
return pl_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::readEncoderType() {
|
asynStatus seleneLiftAxis::readEncoderType() {
|
||||||
asynStatus pl_status =
|
setAxisParamChecked(this, encoderType, IncrementalEncoder);
|
||||||
setStringParam(pC_->encoderType(), IncrementalEncoder);
|
|
||||||
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneLiftAxis::doHome(double minVelocity, double maxVelocity,
|
asynStatus seleneLiftAxis::doHome(double minVelocity, double maxVelocity,
|
||||||
double acceleration, int forwards) {
|
double acceleration, int forwards) {
|
||||||
|
|
||||||
|
// Suppress unused variable warnings
|
||||||
|
(void)minVelocity;
|
||||||
|
(void)maxVelocity;
|
||||||
|
(void)acceleration;
|
||||||
|
(void)forwards;
|
||||||
|
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// No answer expected
|
// No answer expected
|
||||||
@@ -745,8 +656,9 @@ static const iocshArg *const CreateAxisArgs[] = {
|
|||||||
&CreateAxisArg3, &CreateAxisArg4, &CreateAxisArg5,
|
&CreateAxisArg3, &CreateAxisArg4, &CreateAxisArg5,
|
||||||
&CreateAxisArg6, &CreateAxisArg7, &CreateAxisArg8,
|
&CreateAxisArg6, &CreateAxisArg7, &CreateAxisArg8,
|
||||||
};
|
};
|
||||||
static const iocshFuncDef configSeleneVirtualCreateAxes = {"seleneVirtualAxes",
|
static const iocshFuncDef configSeleneVirtualCreateAxes = {
|
||||||
9, CreateAxisArgs};
|
"seleneVirtualAxes", 9, CreateAxisArgs,
|
||||||
|
"Creates instances of Selene axes."};
|
||||||
static void configSeleneVirtualCreateAxesCallFunc(const iocshArgBuf *args) {
|
static void configSeleneVirtualCreateAxesCallFunc(const iocshArgBuf *args) {
|
||||||
seleneVirtualCreateAxes(args[0].sval, args[1].ival, args[2].ival,
|
seleneVirtualCreateAxes(args[0].sval, args[1].ival, args[2].ival,
|
||||||
args[3].ival, args[4].ival, args[5].ival,
|
args[3].ival, args[4].ival, args[5].ival,
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
#ifndef seleneLiftAxis_H
|
#ifndef seleneLiftAxis_H
|
||||||
#define seleneLiftAxis_H
|
#define seleneLiftAxis_H
|
||||||
#include "seleneAngleAxis.h"
|
#include "seleneAngleAxis.h"
|
||||||
|
#include "seleneGuideController.h"
|
||||||
#include "seleneOffsetAxis.h"
|
#include "seleneOffsetAxis.h"
|
||||||
#include "turboPmacAxis.h"
|
#include "turboPmacAxis.h"
|
||||||
#include <array>
|
#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
|
* @brief Virtual axis for setting the height of the center of a Selene guide
|
||||||
*
|
*
|
||||||
* Please see README.md for a detailed explanation.
|
* Please see README.md for a detailed explanation.
|
||||||
*/
|
*/
|
||||||
class seleneLiftAxis : public turboPmacAxis {
|
class HIDDEN seleneLiftAxis : public turboPmacAxis {
|
||||||
public:
|
public:
|
||||||
static const int numAxes_ = 6;
|
static const int numAxes_ = 6;
|
||||||
|
|
||||||
@@ -39,6 +36,8 @@ class seleneLiftAxis : public turboPmacAxis {
|
|||||||
int axis3No, int axis4No, int axis5No, int axis6No,
|
int axis3No, int axis4No, int axis5No, int axis6No,
|
||||||
int liftAxisNo, int angleAxisNo);
|
int liftAxisNo, int angleAxisNo);
|
||||||
|
|
||||||
|
virtual ~seleneLiftAxis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `stop` function from asynMotorAxis
|
* @brief Implementation of the `stop` function from asynMotorAxis
|
||||||
*
|
*
|
||||||
@@ -66,12 +65,12 @@ class seleneLiftAxis : public turboPmacAxis {
|
|||||||
*
|
*
|
||||||
* @param position
|
* @param position
|
||||||
* @param relative
|
* @param relative
|
||||||
* @param min_velocity
|
* @param minVelocity
|
||||||
* @param maxOffset_velocity
|
* @param maxOffset_velocity
|
||||||
* @param acceleration
|
* @param acceleration
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doMove(double position, int relative, double min_velocity,
|
asynStatus doMove(double position, int relative, double minVelocity,
|
||||||
double maxOffset_velocity, double acceleration);
|
double maxOffset_velocity, double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,13 +253,11 @@ class seleneLiftAxis : public turboPmacAxis {
|
|||||||
bool virtualAxisMovement() { return virtualAxisMovement_; }
|
bool virtualAxisMovement() { return virtualAxisMovement_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the target position from the axis and write it into the
|
* @brief Override of the superclass method
|
||||||
* provided pointer.
|
|
||||||
*
|
*
|
||||||
* @param targetPosition
|
* @return double
|
||||||
* @return asynStatus
|
|
||||||
*/
|
*/
|
||||||
asynStatus targetPosition(double *targetPosition);
|
double targetPosition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Access the position of the lift axis
|
* @brief Access the position of the lift axis
|
||||||
@@ -278,6 +275,11 @@ class seleneLiftAxis : public turboPmacAxis {
|
|||||||
*/
|
*/
|
||||||
seleneOffsetAxis *offsetAxis(int idx);
|
seleneOffsetAxis *offsetAxis(int idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the axis controller
|
||||||
|
*/
|
||||||
|
virtual seleneGuideController *pController() override { return pC_; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::array<seleneOffsetAxis *, numAxes_> offsetAxes_;
|
std::array<seleneOffsetAxis *, numAxes_> offsetAxes_;
|
||||||
|
|
||||||
|
|||||||
@@ -50,18 +50,33 @@ seleneOffsetAxis::seleneOffsetAxis(seleneGuideController *pController,
|
|||||||
|
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusDone(), 1);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusDone(), 1);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorStatusDone", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorStatusMoving", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorEncoderPosition(), 0.0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorEncoderPosition", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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
|
// Register the hook function during construction of the first axis
|
||||||
@@ -77,11 +92,32 @@ seleneOffsetAxis::seleneOffsetAxis(seleneGuideController *pController,
|
|||||||
// Selene guide motors cannot be disabled
|
// Selene guide motors cannot be disabled
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(status, "motorCanDisable", axisNo_,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
"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
|
||||||
|
// motorMessageText is set here again, because apparently the sinqAxis
|
||||||
|
// constructor is not run before the string is accessed?
|
||||||
|
status = setStringParam(pC_->motorMessageText(), "");
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seleneOffsetAxis::~seleneOffsetAxis() {}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::init() {
|
asynStatus seleneOffsetAxis::init() {
|
||||||
|
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
@@ -116,16 +152,8 @@ asynStatus seleneOffsetAxis::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the initial limits from the paramlib
|
// Read the initial limits from the paramlib
|
||||||
status = pC_->getDoubleParam(axisNo_, pC_->motorHighLimit(), &highLimit_);
|
getAxisParamChecked(this, motorHighLimit, &highLimit_);
|
||||||
if (status != asynSuccess) {
|
getAxisParamChecked(this, motorLowLimit, &lowLimit_);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The high limits read from the paramLib are divided by motorRecResolution,
|
// The high limits read from the paramLib are divided by motorRecResolution,
|
||||||
// hence we need to multiply them to undo this change.
|
// hence we need to multiply them to undo this change.
|
||||||
@@ -135,15 +163,14 @@ asynStatus seleneOffsetAxis::init() {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::targetPosition(double *targetPosition) {
|
double seleneOffsetAxis::targetPosition() {
|
||||||
asynStatus status = asynSuccess;
|
|
||||||
|
|
||||||
if (targetSet_) {
|
if (targetSet_) {
|
||||||
*targetPosition = targetPosition_;
|
return turboPmacAxis::targetPosition();
|
||||||
} else {
|
} else {
|
||||||
status = motorPosition(targetPosition);
|
double targetPos = 0;
|
||||||
|
motorPosition(&targetPos);
|
||||||
|
return targetPos;
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::doPoll(bool *moving) {
|
asynStatus seleneOffsetAxis::doPoll(bool *moving) {
|
||||||
@@ -199,18 +226,10 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
// Update the parameter library
|
// Update the parameter library
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: To be removed, once the real limits are derived
|
|
||||||
// highLimit = 10.0;
|
|
||||||
// lowLimit = -10.0;
|
|
||||||
|
|
||||||
// Convert into lift coordinate system
|
// Convert into lift coordinate system
|
||||||
absoluteHighLimitLiftCS_ = highLimit - zOffset_;
|
absoluteHighLimitLiftCS_ = highLimit - zOffset_;
|
||||||
absoluteLowLimitLiftCS_ = lowLimit - zOffset_;
|
absoluteLowLimitLiftCS_ = lowLimit - zOffset_;
|
||||||
@@ -230,20 +249,8 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
|
|||||||
relLowLimit = lowLimit - encoderPosition;
|
relLowLimit = lowLimit - encoderPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
|
setAxisParamChecked(this, motorHighLimitFromDriver, relHighLimit);
|
||||||
relHighLimit);
|
setAxisParamChecked(this, motorLowLimitFromDriver, relLowLimit);
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If this axis is moving as a result of an individual move command to the axis
|
If this axis is moving as a result of an individual move command to the axis
|
||||||
@@ -257,60 +264,39 @@ asynStatus seleneOffsetAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = setIntegerParam(pC_->motorStatusMoving(), *moving);
|
setAxisParamChecked(this, motorStatusMoving, *moving);
|
||||||
if (status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusDone, !(*moving));
|
||||||
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__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Axis is always shown as enabled, since it is enabled automatically by the
|
// 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
|
// controller when a move command P150=1 is sent and disabled once the
|
||||||
// movement is completed.
|
// movement is completed.
|
||||||
status = setIntegerParam(pC_->motorEnableRBV(), 1);
|
setAxisParamChecked(this, motorEnableRBV, true);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorEnableRBV_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorStatus;
|
return errorStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus
|
asynStatus
|
||||||
seleneOffsetAxis::setPositionsFromEncoderPosition(double encoderPosition) {
|
seleneOffsetAxis::setPositionsFromEncoderPosition(double encoderPosition) {
|
||||||
asynStatus status = pC_->setDoubleParam(
|
setAxisParamChecked(this, motorAbsolutePositionRBV, encoderPosition);
|
||||||
axisNo_, pC_->motorAbsolutePositionRBV(), encoderPosition);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorEncoderPosition",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
absolutePositionLiftCS_ = encoderPosition - zOffset_;
|
absolutePositionLiftCS_ = encoderPosition - zOffset_;
|
||||||
return status;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::doMove(double position, int relative,
|
asynStatus seleneOffsetAxis::doMove(double position, int relative,
|
||||||
double min_velocity,
|
double minVelocity, double maxVelocity,
|
||||||
double maxOffset_velocity,
|
|
||||||
double acceleration) {
|
double acceleration) {
|
||||||
|
|
||||||
double motorRecResolution = 0.0;
|
// Suppress unused variable warnings
|
||||||
|
(void)relative;
|
||||||
|
(void)minVelocity;
|
||||||
|
(void)maxVelocity;
|
||||||
|
(void)acceleration;
|
||||||
|
|
||||||
asynStatus pl_status = pC_->getDoubleParam(
|
double motorRecResolution = 0.0;
|
||||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the target position
|
// Set the target position
|
||||||
targetPosition_ = position * motorRecResolution;
|
setTargetPosition(position * motorRecResolution);
|
||||||
targetSet_ = true;
|
targetSet_ = true;
|
||||||
asynStatus status = liftAxis_->startCombinedMoveFromOffsetAxis();
|
asynStatus status = liftAxis_->startCombinedMoveFromOffsetAxis();
|
||||||
targetSet_ = false;
|
targetSet_ = false;
|
||||||
@@ -318,14 +304,12 @@ asynStatus seleneOffsetAxis::doMove(double position, int relative,
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::enable(bool on) {
|
asynStatus seleneOffsetAxis::enable(bool on) {
|
||||||
asynStatus pl_status = setStringParam(pC_->motorMessageText(),
|
// Suppress unused variable warnings
|
||||||
"Axis cannot be enabled / disabled");
|
(void)on;
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
setAxisParamChecked(this, motorMessageText,
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
"Axis cannot be enabled / disabled");
|
||||||
__LINE__);
|
return asynSuccess;
|
||||||
}
|
|
||||||
return pl_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus seleneOffsetAxis::normalizePositions() {
|
asynStatus seleneOffsetAxis::normalizePositions() {
|
||||||
@@ -408,7 +392,8 @@ static const iocshArg *const CreateAxisArgs[] = {
|
|||||||
&CreateAxisArg3,
|
&CreateAxisArg3,
|
||||||
};
|
};
|
||||||
static const iocshFuncDef configSeleneOffsetAxisCreateAxis = {
|
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) {
|
static void configSeleneOffsetAxisCreateAxisCallFunc(const iocshArgBuf *args) {
|
||||||
seleneOffsetAxisCreateAxis(args[0].sval, args[1].ival, args[2].dval,
|
seleneOffsetAxisCreateAxis(args[0].sval, args[1].ival, args[2].dval,
|
||||||
args[3].dval);
|
args[3].dval);
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
#ifndef seleneOffsetAxis_H
|
#ifndef seleneOffsetAxis_H
|
||||||
#define seleneOffsetAxis_H
|
#define seleneOffsetAxis_H
|
||||||
|
|
||||||
|
#include "seleneGuideController.h"
|
||||||
#include "turboPmacAxis.h"
|
#include "turboPmacAxis.h"
|
||||||
|
|
||||||
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
|
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
|
||||||
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
|
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
|
||||||
// See https://en.cppreference.com/w/cpp/language/class.
|
// See https://en.cppreference.com/w/cpp/language/class.
|
||||||
class seleneLiftAxis;
|
class HIDDEN seleneLiftAxis;
|
||||||
|
|
||||||
// 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 offset of a motor of the Selene guide
|
* @brief Virtual axis for setting the offset of a motor of the Selene guide
|
||||||
*
|
*
|
||||||
* Please see README.md for a detailed explanation.
|
* Please see README.md for a detailed explanation.
|
||||||
*/
|
*/
|
||||||
class seleneOffsetAxis : public turboPmacAxis {
|
class HIDDEN seleneOffsetAxis : public turboPmacAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new selene Offset Axis object
|
* @brief Construct a new selene Offset Axis object
|
||||||
@@ -30,6 +27,8 @@ class seleneOffsetAxis : public turboPmacAxis {
|
|||||||
seleneOffsetAxis(seleneGuideController *pController, int axisNo,
|
seleneOffsetAxis(seleneGuideController *pController, int axisNo,
|
||||||
double xPos, double zPos);
|
double xPos, double zPos);
|
||||||
|
|
||||||
|
virtual ~seleneOffsetAxis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize this offset axis
|
* @brief Initialize this offset axis
|
||||||
*
|
*
|
||||||
@@ -52,12 +51,12 @@ class seleneOffsetAxis : public turboPmacAxis {
|
|||||||
*
|
*
|
||||||
* @param position
|
* @param position
|
||||||
* @param relative
|
* @param relative
|
||||||
* @param min_velocity
|
* @param minVelocity
|
||||||
* @param maxOffset_velocity
|
* @param maxOffset_velocity
|
||||||
* @param acceleration
|
* @param acceleration
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doMove(double position, int relative, double min_velocity,
|
asynStatus doMove(double position, int relative, double minVelocity,
|
||||||
double maxOffset_velocity, double acceleration);
|
double maxOffset_velocity, double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,13 +78,11 @@ class seleneOffsetAxis : public turboPmacAxis {
|
|||||||
asynStatus setPositionsFromEncoderPosition(double encoderPosition);
|
asynStatus setPositionsFromEncoderPosition(double encoderPosition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the target position from the axis and write it into the
|
* @brief Override of the superclass method
|
||||||
* provided pointer.
|
|
||||||
*
|
*
|
||||||
* @param targetPosition
|
* @return double
|
||||||
* @return asynStatus
|
|
||||||
*/
|
*/
|
||||||
asynStatus targetPosition(double *targetPosition);
|
double targetPosition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the offsets of axis 3 and 4 to zero and recalculate all other
|
* @brief Set the offsets of axis 3 and 4 to zero and recalculate all other
|
||||||
@@ -126,6 +123,11 @@ class seleneOffsetAxis : public turboPmacAxis {
|
|||||||
*/
|
*/
|
||||||
double absoluteLowLimitLiftCS() { return absoluteLowLimitLiftCS_; }
|
double absoluteLowLimitLiftCS() { return absoluteLowLimitLiftCS_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the axis controller
|
||||||
|
*/
|
||||||
|
virtual seleneGuideController *pController() override { return pC_; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// True, if the target has been set from this axis
|
// True, if the target has been set from this axis
|
||||||
bool targetSet_;
|
bool targetSet_;
|
||||||
|
|||||||
Submodule turboPmac updated: 2f83060ec1...1d662ecd43
Reference in New Issue
Block a user