Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 49c8ff5497 | |||
| 761c691a86 | |||
| aa5f2f0315 | |||
| 82c6710d2b | |||
| ab596ded48 | |||
| bfd565aabd | |||
| 0005775c9d | |||
| e5f9e33c66 | |||
| 46b839cc66 | |||
| 38b4ba9843 | |||
| 8eba612524 | |||
| 9565198424 | |||
| bc8561c299 | |||
| cf6f836416 | |||
| 6e99b37ed2 | |||
| f745af48fe | |||
| 0fd312b672 | |||
| c15e513b2e | |||
| 6f9b890374 | |||
| fbbe8c4553 | |||
| 675819741b | |||
| eb3826ec35 | |||
| 5dd5a26243 | |||
| 832884179c | |||
| 94edef6cd8 | |||
| afdd66a648 |
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 TURBOPMAC_VERSION="$(grep 'turboPmac_VERSION=' Makefile | cut -d= -f2)"
|
||||
- git clone --depth 1 --branch "${TURBOPMAC_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=${TURBOPMAC_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/detectorTower/$(ls -U /ioc/modules/detectorTower/ | head -1)" "./detectorTower-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
artifacts:
|
||||
name: "detectorTower-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
paths:
|
||||
- "detectorTower-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
|
||||
expire_in: 1 week
|
||||
when: always
|
||||
tags:
|
||||
- sinq
|
||||
2
Makefile
2
Makefile
@@ -42,4 +42,4 @@ DBDS += turboPmac/sinqMotor/src/sinqMotor.dbd
|
||||
DBDS += turboPmac/src/turboPmac.dbd
|
||||
DBDS += src/detectorTower.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 -fvisibility=hidden # -Wpedantic // Does not work because EPICS macros trigger warnings
|
||||
|
||||
138
README.md
138
README.md
@@ -1,62 +1,107 @@
|
||||
# detectorTower
|
||||
|
||||
## <span style="color:red">Please read the documentation of sinqMotor first: https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
|
||||
## <span style="color:red">Please read the documentation of sinqMotor first:https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
|
||||
|
||||
## Overview
|
||||
|
||||

|
||||
|
||||
This is a driver for the detector tower which is based on the Turbo PMAC driver (https://git.psi.ch/sinq-epics-modules/turboPmac). It consists of the following four objects:
|
||||
- `detectorTowerController`: This is an expanded variant of `turboPmacController` provided by the Turbo PMAC library linked above.It is needed to operate a `detectorTowerAngleAxis`, but it can also be used to operate a "normal" `turboPmacAxis`.
|
||||
- `detectorTowerAngleAxis`: This is a virtual axis which controls multiple physical motors ($x$ and $z$) in order to provide a combined movement. Moving it results in a rotation of the entire beam around the support axis position ($\alpha$).
|
||||
- `detectorTowerLiftAxis`: This is a virtual axis which controls multiple physical motors in order to provide a combined movement. Moving it results in a vertical lift ($z_{lift}$).
|
||||
- `detectorTowerSupportAxis`: This is an axis at the rotation center of the beam which is part of the combined movements. Its origin can be shifted manually for small adjustments, resulting in a corresponding movement. Other than that, it is not meant to move on its own, hence setting a new value to the `VAL` field of the motor record won't cause it to move.
|
||||
This is a driver for the detector tower which is based on the Turbo PMAC driver
|
||||
(https://gitea.psi.ch/lin-epics-modules/turboPmac). It consists of the following
|
||||
four objects:
|
||||
- `detectorTowerController`: This is an extended variant of `turboPmacController`
|
||||
provided by the Turbo PMAC library linked above.It is needed to operate a
|
||||
`detectorTowerAngleAxis`, but it can also be used to operate a "normal" `turboPmacAxis`.
|
||||
- `detectorTowerAngleAxis`: This is a virtual axis which controls multiple
|
||||
physical motors ($x$ and $z$) in order to provide a combined movement. Moving it
|
||||
results in a rotation of the entire beam around the support axis position ($\alpha$).
|
||||
- `detectorTowerLiftAxis`: This is a virtual axis which controls multiple
|
||||
physical motors in order to provide a combined movement. Moving it results in a
|
||||
vertical lift ($z_{lift}$).
|
||||
- `detectorTowerSupportAxis`: This is an axis at the rotation center of the beam
|
||||
which is part of the combined movements. Its origin can be shifted manually for
|
||||
small adjustments, resulting in a corresponding movement. Other than that, it is
|
||||
not meant to move on its own, hence setting a new value to the `VAL` field of
|
||||
the motor record won't cause it to move.
|
||||
|
||||
## User guide
|
||||
|
||||
The centerpiece of this driver is the `detectorTowerAngleAxis`, which controls the angle of the detector flight tube. It is supported by two secondary axes, `detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three axes are created by a single IOC shell command `detectorTowerAxis` (see [Usage in IOC shell](#usage-in-ioc-shell)). All three axes use absolute encoders and therefore cannot perform a reference / home drive.
|
||||
The centerpiece of this driver is the `detectorTowerAngleAxis`, which controls
|
||||
the angle of the detector flight tube. It is supported by two secondary axes,
|
||||
`detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three axes are
|
||||
created by a single IOC shell command `detectorTowerAxis` (see
|
||||
[Usage in IOC shell](#usage-in-ioc-shell)). All three axes use absolute encoders
|
||||
and therefore cannot perform a reference / home drive.
|
||||
|
||||
The first two axes can be moved independently from each other or together as a combined movement by issuing both move orders within a certain time span. This time span can be configured via the IOC shell function `setDeferredMovementWait` and defaults to 100 ms. This allows the user to start a combined movement e.g. via caput:
|
||||
The first two axes can be moved independently from each other or together as a
|
||||
combined movement by issuing both move orders within a certain time span. This
|
||||
time span can be configured via the IOC shell function `setDeferredMovementWait`
|
||||
and defaults to 100 ms. This allows the user to start a combined movement e.g.
|
||||
via caput:
|
||||
|
||||
```
|
||||
```bash
|
||||
caput $(ControllerPV):angle 2 & $(ControllerPV):caput lift 10
|
||||
```
|
||||
which moves the angle to 2 degree and shifts the entire beam vertically by 10 mm. When using the axis from NICOS, using the `maw` or `move` command with multiple devices has the same effect:
|
||||
which moves the angle to 2 degree and shifts the entire beam vertically by 10 mm.
|
||||
When using the axis from NICOS, using the `maw` or `move` command with multiple
|
||||
devices has the same effect:
|
||||
|
||||
```
|
||||
```bash
|
||||
move("angle", 2, "lift", 10)
|
||||
```
|
||||
|
||||
If one axis is already moving, no new move command can be issued until the movement is finished. The `detectorTowerSupportAxis` cannot be moved directly.
|
||||
If one axis is already moving, no new move command can be issued until the
|
||||
movement is finished. The `detectorTowerSupportAxis` cannot be moved directly.
|
||||
|
||||
It is possible to shift the origin of all three axes (and therefore also moving the `detectorTowerSupportAxis`) for small adjustments. The current origin position in the axis unit (degree for `detectorTowerAngleAxis`, mm for `detectorTowerLiftAxis` and encoder steps for `detectorTowerSupportAxis`) can be read from the PV `$(INSTR)$(M):Origin`. The origin can be shifted by the amount of axis units written to `$(INSTR)$(M):AdjustOrigin`. Since this is a relative movement, writing "10" two times to `$(INSTR)$(M):AdjustOrigin` shifts the origin by 20 axis units. Therefore, the limits are only there to prevent too large shifts during a single write (since the origin can be shifted to any position by writing to `$(INSTR)$(M):AdjustOrigin` repeatedly).
|
||||
It is possible to shift the origin of all three axes (and therefore also moving
|
||||
the `detectorTowerSupportAxis`) for small adjustments. The current origin
|
||||
position in the axis unit (degree for `detectorTowerAngleAxis`, mm for
|
||||
`detectorTowerLiftAxis` and encoder steps for `detectorTowerSupportAxis`) can be
|
||||
read from the PV `$(INSTR)$(M):Origin`. The origin can be shifted by the amount
|
||||
of axis units written to `$(INSTR)$(M):AdjustOrigin`. Since this is a relative
|
||||
movement, writing "10" two times to `$(INSTR)$(M):AdjustOrigin` shifts the
|
||||
origin by 20 axis units. Therefore, the limits are only there to prevent too
|
||||
large shifts during a single write (since the origin can be shifted to any
|
||||
position by writing to `$(INSTR)$(M):AdjustOrigin` repeatedly).
|
||||
|
||||
The detector tower can be moved into a so-called "changer position" by writing "1" to the PV `$(INSTR)$(M):ChangeState`. This causes the entire tower to move vertically down. When it is in the changer position, the axes cannot be moved at all. In order to go back to the "working state" where the axes can be moved again, write "0" to `$(INSTR)$(M):ChangeState`. The current state of the axis can be read out from `$(INSTR)$(M):ChangingStateRBV`. In case starting a change movement succeeds, `$(INSTR)$(M):ChangeStateRBV` changes its value accordingly, otherwise it stays at its current value.
|
||||
The detector tower can be moved into a so-called "changer position" by writing
|
||||
"1" to the PV `$(INSTR)$(M):ChangeState`. This causes the entire tower to move
|
||||
vertically down. When it is in the changer position, the axes cannot be moved at
|
||||
all. In order to go back to the "working state" where the axes can be moved
|
||||
again, write "0" to `$(INSTR)$(M):ChangeState`. The current state of the axis
|
||||
can be read out from `$(INSTR)$(M):ChangingStateRBV`. In case starting a change
|
||||
movement succeeds, `$(INSTR)$(M):ChangeStateRBV` changes its value accordingly,
|
||||
otherwise it stays at its current value.
|
||||
|
||||
The utilities provided in the `utils` folder in `turboPmac/utils` work with this driver as well.
|
||||
The utilities provided in the `utils` folder in `turboPmac/utils` work with this
|
||||
driver as well.
|
||||
|
||||
### Usage in IOC shell
|
||||
|
||||
detectorTower exports the following IOC shell functions:
|
||||
- `detectorTowerController`: Create a new controller object.
|
||||
- `detectorTowerAxis`: Create a `detectorTowerAngleAxis`, a `detectorTowerLiftAxis` and a `detectorTowerSupportAxis` object and link them to each other
|
||||
- `detectorTowerAxis`: Create a `detectorTowerAngleAxis`, a `detectorTowerLiftAxis`
|
||||
and a `detectorTowerSupportAxis` object and link them to each other
|
||||
|
||||
The constructor function for `detectorTowerAxis` has the following syntax:
|
||||
|
||||
```
|
||||
```bash
|
||||
detectorTowerAngleAxis("$(NAME)",1, 2, 3)
|
||||
```
|
||||
|
||||
with 1 being the axis number / index of the `detectorTowerAngleAxis`, 2 being the `detectorTowerLiftAxis` and 3 being the `detectorTowerSupportAxis`. These axes are parametrized in the same way as any "normal" axes via a substitution file (see corresponding section below).
|
||||
with 1 being the axis number / index of the `detectorTowerAngleAxis`, 2 being
|
||||
the `detectorTowerLiftAxis` and 3 being the `detectorTowerSupportAxis`. These
|
||||
axes are parametrized in the same way as any "normal" axes via a substitution
|
||||
file (see corresponding section below).
|
||||
|
||||
"Normal" `turboPmacAxis` may be used together with this controller:
|
||||
|
||||
```
|
||||
```bash
|
||||
# Define the name of the controller and the corresponding port
|
||||
epicsEnvSet("NAME","mcu")
|
||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||
|
||||
# Create the TCP/IP socket used to talk with the controller. The socket can be adressed from within the IOC shell via the port name
|
||||
# Create the TCP/IP socket used to talk with the controller. The socket can beadressed from within the IOC shell via the port name
|
||||
drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
||||
|
||||
# Create the controller object with the defined name and connect it to the socket via the port name.
|
||||
@@ -91,13 +136,17 @@ dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_POR
|
||||
|
||||
### Substitution file
|
||||
|
||||
From the perspective of EPICS, the main detector flight tube axis and the auxiliary axes are independent axes and therefore each axis needs its own parametrization in the substitution file. If additional axes are used in the axis, they are parametrized as usual:
|
||||
```
|
||||
From the perspective of EPICS, the main detector flight tube axis and the
|
||||
auxiliary axes are independent axes and therefore each axis needs its own
|
||||
parametrization in the substitution file. If additional axes are used in the
|
||||
axis, they are parametrized as usual:
|
||||
|
||||
```bash
|
||||
detectorTowerAngleAxis("$(NAME)",1, 2, 3);
|
||||
turboPmacAxis("$(NAME)",4);
|
||||
turboPmacAxis("$(NAME)",5);
|
||||
```
|
||||
```
|
||||
```bash
|
||||
file "$(SINQDBPATH)"
|
||||
{
|
||||
pattern
|
||||
@@ -110,22 +159,53 @@ pattern
|
||||
}
|
||||
```
|
||||
|
||||
Note that the speed of the detector tower axes 1, 2 and 3 cannot be set. Setting `CANSETSPEED` to 1 does not change this behaviour.
|
||||
Note that the speed of the detector tower axes 1, 2 and 3 cannot be set. Setting
|
||||
`CANSETSPEED` to 1 does not change this behaviour.
|
||||
|
||||
## Developer guide
|
||||
|
||||
### Code architecture
|
||||
|
||||
The code is designed around the `detectorTowerAngleAxis`, which controls the angle of the beam guide and acts as a "master" axis which contains pointers to its attached `detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three axes are polled at once via the function `detectorTowerController::pollDetectorAxes`, which is called from the individual `poll` functions of the axes (the `doPoll` mechanism from `sinqMotor` is not used). To avoid polling the axes multiple times during one controller cycle, the function `detectorTowerController::pollDetectorAxes` is only executed for the axis with the smallest index. Since this axis is polled first, the other two axes are therefore already up-to-date when they execute their own poll function. If one of the axes is moving, all three axes are marked as moving. The same is true for errors.
|
||||
The code is designed around the `detectorTowerAngleAxis`, which controls the
|
||||
angle of the beam guide and acts as a "master" axis which contains pointers to
|
||||
its attached `detectorTowerLiftAxis` and `detectorTowerSupportAxis`. All three
|
||||
axes are polled at once via the function `detectorTowerController::pollDetectorAxes`,
|
||||
which is called from the individual `poll` functions of the axes (the `doPoll`
|
||||
mechanism from `sinqMotor` is not used). To avoid polling the axes multiple
|
||||
times during one controller cycle, the function `detectorTowerController::pollDetectorAxes`
|
||||
is only executed for the axis with the smallest index. Since this axis is polled
|
||||
first, the other two axes are therefore already up-to-date when they execute
|
||||
their own poll function. If one of the axes is moving, all three axes are marked
|
||||
as moving. The same is true for errors.
|
||||
|
||||
In order to save on movement time, movement commands to auxiliary axes and the `detectorTowerAngleAxis` are collected and then send as a single resulting movement command to the MCU. In order to do so, a "collector" thread is running which checks if a movement request has been send to one of the axes. If that is the case, it waits for `detectorTowerAngleAxis->deferredMovementWait_` seconds and checks if commands for other axes are given as well. Then, it calls `detectorTowerAngleAxis::startCombinedMove` which combines all commands to a single request which is sent to the MCU. `detectorTowerAngleAxis->deferredMovementWait_` can be set with the IOC shell function `setDeferredMovementWait` and defaults to 100 ms.
|
||||
In order to save on movement time, movement commands to auxiliary axes and the
|
||||
`detectorTowerAngleAxis` are collected and then send as a single resulting
|
||||
movement command to the MCU. In order to do so, a "collector" thread is running
|
||||
which checks if a movement request has been send to one of the axes. If that is
|
||||
the case, it waits for `detectorTowerAngleAxis->deferredMovementWait_` seconds
|
||||
and checks if commands for other axes are given as well. Then, it calls
|
||||
`detectorTowerAngleAxis::startCombinedMove` which combines all commands to a
|
||||
single request which is sent to the MCU.
|
||||
`detectorTowerAngleAxis->deferredMovementWait_` can be set with the IOC shell
|
||||
function `setDeferredMovementWait` and defaults to 100 ms.
|
||||
|
||||
The `detectorTowerController` is a thin wrapper around a `turboPmacController` which overwrites the `readInt32`, `writeInt32` and `writeFloat64` methods in order to support the additional PVs defined in `db/detectorTower.db`. Any calls to these two methods not concerning the aforementioned PVs are directly forwarded to `turboPmacController::readInt32` / `turboPmacController::writeInt32`.
|
||||
The `detectorTowerController` is a thin wrapper around a `turboPmacController`
|
||||
which overwrites the `readInt32`, `writeInt32` and `writeFloat64` methods in
|
||||
order to support the additional PVs defined in `db/detectorTower.db`. Any calls
|
||||
to these two methods not concerning the aforementioned PVs are directly
|
||||
forwarded to `turboPmacController::readInt32` / `turboPmacController::writeInt32`.
|
||||
|
||||
### Versioning
|
||||
|
||||
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||
Please see the documentation for the module sinqMotor:
|
||||
https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||
|
||||
### How to build it
|
||||
|
||||
This driver can be compiled and installed by running `make install` from the same directory where the Makefile is located. However, since it uses the git submodule turboPmac, make sure that the correct version of the submodule repository is checked out AND the change is commited (`git status` shows no non-committed changes). Please see the section "Usage as static dependency" in https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md for more details.
|
||||
This driver can be compiled and installed by running `make install` from the
|
||||
same directory where the Makefile is located. However, since it uses the git
|
||||
submodule turboPmac, make sure that the correct version of the submodule
|
||||
repository is checked out AND the change is commited (`git status` shows no
|
||||
non-committed changes). Please see the section "Usage as static dependency" in
|
||||
https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md for more
|
||||
details.
|
||||
@@ -58,7 +58,6 @@ record(ai, "$(INSTR)$(M):Origin") {
|
||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_ORIGIN")
|
||||
field(SCAN, "I/O Intr")
|
||||
field(PINI, "NO")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
# Shift the origin of the corresponding axis by the given value. The axis will move to this
|
||||
@@ -69,16 +68,28 @@ record(ao, "$(INSTR)$(M):AdjustOrigin") {
|
||||
field(PINI, "NO")
|
||||
field(FLNK, "$(INSTR)$(M):ResetAO")
|
||||
field(VAL, "0")
|
||||
field(UDF, "0")
|
||||
field(SCAN, "Passive")
|
||||
}
|
||||
|
||||
# Only forward nonzero inputs for the origin adjustment
|
||||
record(calcout, "$(INSTR)$(M):GateOrigin") {
|
||||
field(CALC, "A!=0?A:0")
|
||||
field(INPA, "$(INSTR)$(M):AdjustOrigin")
|
||||
field(OUT, "$(INSTR)$(M):WriteAO.VAL PP") # Forward the value to the driver
|
||||
field(PINI, "NO")
|
||||
field(SCAN, "Passive")
|
||||
}
|
||||
|
||||
# Reset the PV $(INSTR)$(M):AdjustOrigin to zero after it has been written to and
|
||||
# forward the value to $(INSTR)$(M):WriteAO which does the actual writing.
|
||||
record(seq, "$(INSTR)$(M):ResetAO") {
|
||||
field(DESC, "Write value to hardware then reset to 0")
|
||||
field(DOL1, "$(INSTR)$(M):AdjustOrigin")
|
||||
field(LNK1, "$(INSTR)$(M):WriteAO.VAL PP") # Perform write to hardware
|
||||
field(DOL1, "1") # Dummy value which is only here to trigger processing of LNK1
|
||||
field(LNK1, "$(INSTR)$(M):GateOrigin.PROC PP")
|
||||
field(DOL2, "0.0")
|
||||
field(LNK2, "$(INSTR)$(M):AdjustOrigin.VAL PP") # Reset to zero
|
||||
field(UDF, "0")
|
||||
}
|
||||
|
||||
# This record forwards the adjustment of the origin to the asyn driver.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "detectorTowerSupportAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
@@ -32,17 +34,16 @@ static void deferredMovementCollectorLoop(void *drvPvt) {
|
||||
detectorTowerAngleAxis *axis = (detectorTowerAngleAxis *)drvPvt;
|
||||
while (1) {
|
||||
if (axis->receivedTarget_) {
|
||||
// Wait for 100 ms and then start the movement with the information
|
||||
// available
|
||||
axis->startingDeferredMovement_ = true;
|
||||
// Wait for the time span defined in deferredMovementWait_ and then
|
||||
// start the movement with the information available
|
||||
epicsThreadSleep(axis->deferredMovementWait_);
|
||||
axis->startCombinedMove();
|
||||
|
||||
// After the movement command has been send, reset the flag
|
||||
axis->receivedTarget_ = false;
|
||||
}
|
||||
// Limit this loop to an idle frequency of 1 kHz
|
||||
epicsThreadSleep(0.001);
|
||||
// Limit this loop to an idle frequency of 10 kHz
|
||||
epicsThreadSleep(0.01);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,11 +75,10 @@ detectorTowerAngleAxis::detectorTowerAngleAxis(detectorTowerController *pC,
|
||||
}
|
||||
|
||||
// Initialize all member variables
|
||||
// Assumed to be not ready by default, this is overwritten in the next poll
|
||||
error_ = 0;
|
||||
waitingForStart_ = false;
|
||||
receivedTarget_ = false;
|
||||
startingDeferredMovement_ = false;
|
||||
deferredMovementWait_ = 0.1; // seconds
|
||||
deferredMovementWait_ = 0.5; // seconds
|
||||
|
||||
// Will be populated in the init() method
|
||||
beamRadius_ = 0.0;
|
||||
@@ -157,17 +157,8 @@ asynStatus detectorTowerAngleAxis::init() {
|
||||
}
|
||||
|
||||
// Initialize the motorStatusMoving flag
|
||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusMoving, false);
|
||||
setAxisParamChecked(this, changeStateRBV, positionState == 2);
|
||||
|
||||
return callParamCallbacks();
|
||||
}
|
||||
@@ -181,15 +172,9 @@ asynStatus detectorTowerAngleAxis::poll(bool *moving) {
|
||||
if (axisNo() < liftAxis()->axisNo() && axisNo() < supportAxis()->axisNo()) {
|
||||
status = pC_->pollDetectorAxes(moving, this, liftAxis(), supportAxis());
|
||||
} else {
|
||||
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
|
||||
(int *)moving);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, motorStatusMoving, moving);
|
||||
}
|
||||
wasMoving_ = *moving;
|
||||
setWasMoving(*moving);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -206,29 +191,20 @@ asynStatus detectorTowerAngleAxis::doMove(double position, int relative,
|
||||
double max_velocity,
|
||||
double acceleration) {
|
||||
double motorRecResolution = 0.0;
|
||||
asynStatus plStatus = pC_->getDoubleParam(
|
||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorRecResolution_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||
|
||||
// Signal to the deferredMovementCollectorLoop that a movement should be
|
||||
// started to the defined target position.
|
||||
targetPosition_ = position * motorRecResolution;
|
||||
setTargetPosition(position * motorRecResolution);
|
||||
receivedTarget_ = true;
|
||||
|
||||
waitingForStart_ = true;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::startCombinedMove() {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
@@ -237,12 +213,7 @@ asynStatus detectorTowerAngleAxis::startCombinedMove() {
|
||||
|
||||
// =========================================================================
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
@@ -259,100 +230,75 @@ asynStatus detectorTowerAngleAxis::startCombinedMove() {
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
if (isInChangerPos) {
|
||||
|
||||
plStatus = setStringParam(pC_->motorMessageText(),
|
||||
"Move the axis to working state first.");
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorMessageText",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorMessageText,
|
||||
"Move the axis to working state first.");
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
|
||||
callParamCallbacks();
|
||||
startingDeferredMovement_ = false;
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Set the target positions for beam tilt, detector tilt offset and lift
|
||||
// offset
|
||||
snprintf(command, sizeof(command), "Q451=%lf Q454=%lf P350=1",
|
||||
targetPosition_, liftAxis_->targetPosition_);
|
||||
targetPosition(), liftAxis_->targetPosition());
|
||||
|
||||
// Lock the access to the controller since this function runs in another
|
||||
// thread than the poll method.
|
||||
pC_->lock();
|
||||
|
||||
// We don't expect an answer
|
||||
rwStatus = pC_->writeRead(axisNo_, command, response, 0);
|
||||
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||
|
||||
// Free the controller again
|
||||
pC_->unlock();
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to "
|
||||
"target position %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
motorCoordinatesPosition);
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
callParamCallbacks();
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::stop(double acceleration) {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
status = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
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__);
|
||||
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
// Reset the deferred movement flags
|
||||
receivedTarget_ = false;
|
||||
waitingForStart_ = false;
|
||||
liftAxis()->waitingForStart_ = false;
|
||||
return status;
|
||||
}
|
||||
|
||||
// The detector tower axis uses absolute encoders
|
||||
asynStatus detectorTowerAngleAxis::readEncoderType() {
|
||||
asynStatus status = setStringParam(pC_->encoderType(), AbsoluteEncoder);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "encoderType_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, encoderType, AbsoluteEncoder);
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
@@ -362,27 +308,19 @@ detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
bool moving = false;
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = poll(&moving);
|
||||
if (rwStatus != asynSuccess) {
|
||||
return rwStatus;
|
||||
status = poll(&moving);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
if (moving) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
@@ -392,21 +330,10 @@ detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
|
||||
toChangingPosition ? "changer" : "working",
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
|
||||
plStatus = setStringParam(
|
||||
pC_->motorMessageText(),
|
||||
setAxisParamChecked(
|
||||
this, motorMessageText,
|
||||
"Axis cannot be moved to changer position while it is moving.");
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), !toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, changeStateRBV, !toChangingPosition);
|
||||
|
||||
return asynError;
|
||||
}
|
||||
@@ -424,39 +351,20 @@ detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
|
||||
// Update the PV anyway, even though nothing changed.
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, changeStateRBV, toChangingPosition);
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
// Move the axis into changer or working position
|
||||
if (toChangingPosition) {
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=2", response, 0);
|
||||
status = pC_->writeRead(axisNo_, "P350=2", response, 0);
|
||||
} else {
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=3", response, 0);
|
||||
status = pC_->writeRead(axisNo_, "P350=3", response, 0);
|
||||
}
|
||||
|
||||
if (plStatus != asynSuccess) {
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), !toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
setAxisParamChecked(this, changeStateRBV, toChangingPosition);
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
|
||||
@@ -468,12 +376,7 @@ asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
@@ -502,12 +405,7 @@ asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
|
||||
"angle origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -516,15 +414,14 @@ asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
|
||||
asynStatus detectorTowerAngleAxis::doReset() {
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
asynStatus plStatus = asynSuccess;
|
||||
int positionState = 0;
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
// Reset the deferred movement flags
|
||||
receivedTarget_ = false;
|
||||
waitingForStart_ = false;
|
||||
liftAxis()->waitingForStart_ = false;
|
||||
|
||||
/*
|
||||
Check which action should be performed:
|
||||
@@ -653,11 +550,12 @@ static void configDetectorTowerCreateAxisCallFunc(const iocshArgBuf *args) {
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the setDeferredMovementWait (FFI implementation)
|
||||
* @brief Set the setDeferredMovementWait time (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param scaleMovTimeout Scaling factor (in seconds)
|
||||
* @param deferredMovementWait Time (in seconds) the driver waits to collect
|
||||
* all movement commands from the different axes
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setDeferredMovementWait(const char *portName, int axisNo,
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
#ifndef detectorTowerAngleAxis_H
|
||||
#define detectorTowerAngleAxis_H
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacAxis.h"
|
||||
#include <errlog.h>
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class detectorTowerController;
|
||||
class detectorTowerLiftAxis;
|
||||
class detectorTowerSupportAxis;
|
||||
|
||||
class detectorTowerAngleAxis : public turboPmacAxis {
|
||||
class HIDDEN detectorTowerAngleAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerAngleAxis
|
||||
@@ -143,15 +136,15 @@ class detectorTowerAngleAxis : public turboPmacAxis {
|
||||
*/
|
||||
detectorTowerSupportAxis *supportAxis() { return supportAxis_; }
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the axis controller
|
||||
*/
|
||||
virtual detectorTowerController *pController() override { return pC_; };
|
||||
|
||||
// If true, either this axis or one of the detectorTowerLiftAxis
|
||||
// attached to it received a movement command.
|
||||
bool receivedTarget_;
|
||||
|
||||
// If set to true, the virtual axis is about to start a deferred movement
|
||||
// (but is currently still collecting movement commands from its component
|
||||
// axes)
|
||||
bool startingDeferredMovement_;
|
||||
|
||||
/*
|
||||
The collector cycle waits until this time in seconds has passed before
|
||||
starting a deferred movement
|
||||
@@ -164,6 +157,10 @@ class detectorTowerAngleAxis : public turboPmacAxis {
|
||||
*/
|
||||
int error_;
|
||||
|
||||
// True, if this axis has received a move command and the driver is
|
||||
// currently starting a deferred movement.
|
||||
bool waitingForStart_;
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
detectorTowerLiftAxis *liftAxis_;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "detectorTowerController.h"
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "detectorTowerSupportAxis.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
@@ -106,11 +107,13 @@ detectorTowerController::detectorTowerController(
|
||||
}
|
||||
}
|
||||
|
||||
detectorTowerController::~detectorTowerController() {}
|
||||
|
||||
asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
|
||||
epicsInt32 *value) {
|
||||
|
||||
// The detector axes cannot be disabled
|
||||
if (pasynUser->reason == motorCanDisable_) {
|
||||
if (pasynUser->reason == motorCanDisable()) {
|
||||
detectorTowerAngleAxis *aAxis = getDetectorTowerAngleAxis(pasynUser);
|
||||
if (aAxis != nullptr) {
|
||||
*value = 0;
|
||||
@@ -150,31 +153,6 @@ asynStatus detectorTowerController::writeInt32(asynUser *pasynUser,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Due to a bug which is currently not understood, the reset has to be handled
|
||||
here rather than using the default implementation in sinqController. Piping
|
||||
the motor reset request to sinqController causes segfaults. It might be due
|
||||
to the fact that the default `reset` implementation of sinqAxis locks the
|
||||
controller in order to perform some fast polls and that for some reason this
|
||||
behaviour cannot be overwritten even by providing custom `reset` methods for
|
||||
all three axes.
|
||||
*/
|
||||
if (pasynUser->reason == motorReset_) {
|
||||
detectorTowerAngleAxis *aAxis = getDetectorTowerAngleAxis(pasynUser);
|
||||
if (aAxis != nullptr) {
|
||||
return aAxis->reset();
|
||||
}
|
||||
detectorTowerLiftAxis *lAxis = getDetectorTowerLiftAxis(pasynUser);
|
||||
if (lAxis != nullptr) {
|
||||
return lAxis->reset();
|
||||
}
|
||||
detectorTowerSupportAxis *sAxis =
|
||||
getDetectorTowerSupportAxis(pasynUser);
|
||||
if (sAxis != nullptr) {
|
||||
return sAxis->reset();
|
||||
}
|
||||
}
|
||||
|
||||
return turboPmacController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
@@ -309,7 +287,7 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
|
||||
int error = 0;
|
||||
int positionState = 0;
|
||||
int inPosition = 0;
|
||||
int notInPosition = 0;
|
||||
|
||||
double angle = 0.0;
|
||||
double prevAngle = 0.0;
|
||||
@@ -359,37 +337,13 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
|
||||
The motorStatusProblem_ field changes the motor record fields SEVR and STAT.
|
||||
*/
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusProblem(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusProblem_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusProblem(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusProblem_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusProblem(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusProblem_", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorStatusProblem, false);
|
||||
setAxisParamChecked(liftAxis, motorStatusProblem, false);
|
||||
setAxisParamChecked(supportAxis, motorStatusProblem, false);
|
||||
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusCommsError(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusCommsError_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusCommsError(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusCommsError_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusCommsError(), false);
|
||||
if (plStatus != asynSuccess) {
|
||||
paramLibAccessFailed(plStatus, "motorStatusCommsError_", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorStatusCommsError, false);
|
||||
setAxisParamChecked(liftAxis, motorStatusCommsError, false);
|
||||
setAxisParamChecked(supportAxis, motorStatusCommsError, false);
|
||||
|
||||
// Read the previous motor positions
|
||||
plStatus = angleAxis->motorPosition(&prevAngle);
|
||||
@@ -426,7 +380,7 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
nvals =
|
||||
sscanf(response,
|
||||
"%d %d %d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
|
||||
&inPosition, &positionState, &error, &angle, &angleHighLimit,
|
||||
¬InPosition, &positionState, &error, &angle, &angleHighLimit,
|
||||
&angleLowLimit, &angleOrigin, &angleAdjustOriginHighLimit,
|
||||
&angleAdjustOriginLowLimit, &lift, &liftHighLimit, &liftLowLimit,
|
||||
&liftOrigin, &liftAdjustOriginHighLimit,
|
||||
@@ -450,20 +404,12 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
*/
|
||||
|
||||
// Angle
|
||||
plStatus = getDoubleParam(angleAxisNo, motorLimitsOffset(), &limitsOffset);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorLimitsOffset_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(angleAxis, motorLimitsOffset, &limitsOffset);
|
||||
angleHighLimit = angleHighLimit - limitsOffset;
|
||||
angleLowLimit = angleLowLimit + limitsOffset;
|
||||
|
||||
// Lift
|
||||
plStatus = getDoubleParam(liftAxisNo, motorLimitsOffset(), &limitsOffset);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorLimitsOffset_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(liftAxis, motorLimitsOffset, &limitsOffset);
|
||||
liftHighLimit = liftHighLimit - limitsOffset;
|
||||
liftLowLimit = liftLowLimit + limitsOffset;
|
||||
|
||||
@@ -471,16 +417,15 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
angleAxis->error_ = error;
|
||||
|
||||
// Check if the tower is moving
|
||||
if (inPosition == 1 || positionState > 2) {
|
||||
// By now, the controller has actually started the movement
|
||||
angleAxis->startingDeferredMovement_ = false;
|
||||
if (notInPosition == 1 || positionState > 2) {
|
||||
*moving = true;
|
||||
|
||||
// Since the tower is now moving, the axis by definition do not wait for
|
||||
// movement start anymore.
|
||||
liftAxis->waitingForStart_ = false;
|
||||
angleAxis->waitingForStart_ = false;
|
||||
} else {
|
||||
if (angleAxis->startingDeferredMovement_) {
|
||||
*moving = true;
|
||||
} else {
|
||||
*moving = false;
|
||||
}
|
||||
*moving = false;
|
||||
}
|
||||
|
||||
// Calculate the lift position /w consideration of the angle
|
||||
@@ -835,257 +780,96 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
Does the paramLib already contain an error message? If either this is the
|
||||
case or if error != 0, report a status problem for all axes.
|
||||
*/
|
||||
getStringParam(angleAxisNo, motorMessageText(), sizeof(waitingErrorMessage),
|
||||
waitingErrorMessage);
|
||||
getAxisParamChecked(angleAxis, motorMessageText, &waitingErrorMessage);
|
||||
|
||||
if (error != 0 || waitingErrorMessage[0] != '\0') {
|
||||
if (error != 0 || errorMessage[0] != '\0' ||
|
||||
waitingErrorMessage[0] != '\0') {
|
||||
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
angleAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
liftAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorStatusProblem, true);
|
||||
setAxisParamChecked(liftAxis, motorStatusProblem, true);
|
||||
setAxisParamChecked(supportAxis, motorStatusProblem, true);
|
||||
}
|
||||
|
||||
// Update the error message text with the one created in this poll (in case
|
||||
// it is not empty).
|
||||
if (errorMessage[0] != '\0') {
|
||||
plStatus = angleAxis->setStringParam(motorMessageText(), errorMessage);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
angleAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setStringParam(motorMessageText(), errorMessage);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
liftAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
plStatus =
|
||||
supportAxis->setStringParam(motorMessageText(), errorMessage);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorMessageText, errorMessage);
|
||||
setAxisParamChecked(liftAxis, motorMessageText, errorMessage);
|
||||
setAxisParamChecked(supportAxis, motorMessageText, errorMessage);
|
||||
}
|
||||
|
||||
// Update the working position state PV
|
||||
plStatus = angleAxis->setIntegerParam(positionStateRBV(), positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "positionStateRBV_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(positionStateRBV(), positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "positionStateRBV_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(positionStateRBV(), positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "positionStateRBV_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, positionStateRBV, positionState);
|
||||
setAxisParamChecked(liftAxis, positionStateRBV, positionState);
|
||||
setAxisParamChecked(supportAxis, positionStateRBV, positionState);
|
||||
|
||||
// The axes are always enabled
|
||||
plStatus = angleAxis->setIntegerParam(motorEnableRBV(), 1);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorEnableRBV_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorEnableRBV(), 1);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorEnableRBV_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(motorEnableRBV(), 1);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorEnableRBV_", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
setAxisParamChecked(angleAxis, motorEnableRBV, true);
|
||||
setAxisParamChecked(liftAxis, motorEnableRBV, true);
|
||||
setAxisParamChecked(supportAxis, motorEnableRBV, true);
|
||||
|
||||
// If the axis is starting a movement, mark it as moving. Otherwise use the
|
||||
// moving parameter.
|
||||
if (angleAxis->waitingForStart_) {
|
||||
setAxisParamChecked(angleAxis, motorStatusMoving, true);
|
||||
setAxisParamChecked(angleAxis, motorStatusDone, false);
|
||||
} else {
|
||||
setAxisParamChecked(angleAxis, motorStatusMoving, *moving);
|
||||
setAxisParamChecked(angleAxis, motorStatusDone, !(*moving));
|
||||
}
|
||||
|
||||
// Are the axes currently moving?
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusMoving(), *moving);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusMoving_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusMoving(), *moving);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusMoving_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusMoving(), *moving);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusMoving_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
if (liftAxis->waitingForStart_) {
|
||||
setAxisParamChecked(liftAxis, motorStatusMoving, true);
|
||||
setAxisParamChecked(liftAxis, motorStatusDone, false);
|
||||
} else {
|
||||
setAxisParamChecked(liftAxis, motorStatusMoving, *moving);
|
||||
setAxisParamChecked(liftAxis, motorStatusDone, !(*moving));
|
||||
}
|
||||
|
||||
// Is the axis movement done?
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusDone(), !(*moving));
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDone_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusDone(), !(*moving));
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDone_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusDone(), !(*moving));
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDone_", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
// Support axis status is solely deduced from system movement state
|
||||
setAxisParamChecked(supportAxis, motorStatusMoving, *moving);
|
||||
setAxisParamChecked(supportAxis, motorStatusDone, !(*moving));
|
||||
|
||||
// In which direction are the axes currently moving?
|
||||
plStatus = angleAxis->setIntegerParam(motorStatusDirection(), angleDir);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
|
||||
angleAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setIntegerParam(motorStatusDirection(), liftDir);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
|
||||
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorStatusDirection, angleDir);
|
||||
setAxisParamChecked(liftAxis, motorStatusDirection, liftDir);
|
||||
// Using the lift direction for the support axis is done on purpose!
|
||||
plStatus = supportAxis->setIntegerParam(motorStatusDirection(), liftDir);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorStatusDirection_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(supportAxis, motorStatusDirection, liftDir);
|
||||
|
||||
// High limits from hardware
|
||||
plStatus =
|
||||
setDoubleParam(angleAxisNo, motorHighLimitFromDriver(), angleHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorHighLimitFromDriver",
|
||||
angleAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus =
|
||||
setDoubleParam(liftAxisNo, motorHighLimitFromDriver(), liftHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorHighLimitFromDriver",
|
||||
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorHighLimitFromDriver, angleHighLimit);
|
||||
setAxisParamChecked(liftAxis, motorHighLimitFromDriver, liftHighLimit);
|
||||
// Using the lift high limit for the support axis is done on purpose!
|
||||
plStatus = setDoubleParam(supportAxisNo, motorHighLimitFromDriver(),
|
||||
liftHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorHighLimitFromDriver",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(supportAxis, motorHighLimitFromDriver, liftHighLimit);
|
||||
|
||||
// Low limits from hardware
|
||||
plStatus =
|
||||
setDoubleParam(angleAxisNo, motorLowLimitFromDriver(), angleLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorLowLimitFromDriver",
|
||||
angleAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus =
|
||||
setDoubleParam(liftAxisNo, motorLowLimitFromDriver(), liftLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorLowLimitFromDriver",
|
||||
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorLowLimitFromDriver, angleLowLimit);
|
||||
setAxisParamChecked(liftAxis, motorLowLimitFromDriver, liftLowLimit);
|
||||
// Using the lift low limit for the support axis is done on purpose!
|
||||
plStatus =
|
||||
setDoubleParam(supportAxisNo, motorLowLimitFromDriver(), liftLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorLowLimitFromDriver",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(supportAxis, motorLowLimitFromDriver, liftLowLimit);
|
||||
|
||||
// Write the motor origin
|
||||
plStatus = setDoubleParam(angleAxisNo, motorOrigin(), angleOrigin);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorOrigin", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = setDoubleParam(liftAxisNo, motorOrigin(), liftOrigin);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorOrigin", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = setDoubleParam(supportAxisNo, motorOrigin(), supportOrigin);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "supportOrigin", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorOrigin, angleOrigin);
|
||||
setAxisParamChecked(liftAxis, motorOrigin, liftOrigin);
|
||||
setAxisParamChecked(supportAxis, motorOrigin, supportOrigin);
|
||||
|
||||
// Origin adjustment high limit
|
||||
plStatus =
|
||||
setDoubleParam(angleAxisNo, motorAdjustOriginHighLimitFromDriver(),
|
||||
angleAdjustOriginHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorOriginHighLimitFromDriver",
|
||||
angleAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus =
|
||||
setDoubleParam(liftAxisNo, motorAdjustOriginHighLimitFromDriver(),
|
||||
liftAdjustOriginHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorOriginHighLimitFromDriver",
|
||||
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorAdjustOriginHighLimitFromDriver,
|
||||
angleAdjustOriginHighLimit);
|
||||
setAxisParamChecked(liftAxis, motorAdjustOriginHighLimitFromDriver,
|
||||
liftAdjustOriginHighLimit);
|
||||
// Using the lift high limit for the support axis is done on purpose!
|
||||
plStatus =
|
||||
setDoubleParam(supportAxisNo, motorAdjustOriginHighLimitFromDriver(),
|
||||
liftAdjustOriginHighLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorOriginHighLimitFromDriver",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(supportAxis, motorAdjustOriginHighLimitFromDriver,
|
||||
liftAdjustOriginHighLimit);
|
||||
|
||||
// Origin adjustment low limit
|
||||
plStatus =
|
||||
setDoubleParam(angleAxisNo, motorAdjustOriginLowLimitFromDriver(),
|
||||
angleAdjustOriginLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus,
|
||||
"motorAdjustOriginLowLimitFromDriver",
|
||||
angleAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = setDoubleParam(liftAxisNo, motorAdjustOriginLowLimitFromDriver(),
|
||||
liftAdjustOriginLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus,
|
||||
"motorAdjustOriginLowLimitFromDriver",
|
||||
liftAxisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorAdjustOriginLowLimitFromDriver,
|
||||
angleAdjustOriginLowLimit);
|
||||
setAxisParamChecked(liftAxis, motorAdjustOriginLowLimitFromDriver,
|
||||
liftAdjustOriginLowLimit);
|
||||
// Using the lift low limit for the support axis is done on purpose!
|
||||
plStatus =
|
||||
setDoubleParam(supportAxisNo, motorAdjustOriginLowLimitFromDriver(),
|
||||
liftAdjustOriginLowLimit);
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(
|
||||
plStatus, "motorAdjustOriginLowLimitFromDriver", supportAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(supportAxis, motorAdjustOriginLowLimitFromDriver,
|
||||
liftAdjustOriginLowLimit);
|
||||
|
||||
// Axes positions
|
||||
plStatus = angleAxis->setMotorPosition(angle);
|
||||
@@ -1159,22 +943,9 @@ asynStatus detectorTowerController::pollDetectorAxes(
|
||||
one poll cycle, but are cleared afterwards. Persisting error messages will
|
||||
be recreated during each poll.
|
||||
*/
|
||||
plStatus = angleAxis->setStringParam(motorMessageText(), "");
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_", angleAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = liftAxis->setStringParam(motorMessageText(), "");
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_", liftAxisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
plStatus = supportAxis->setStringParam(motorMessageText(), "");
|
||||
if (plStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
supportAxisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(angleAxis, motorMessageText, "");
|
||||
setAxisParamChecked(liftAxis, motorMessageText, "");
|
||||
setAxisParamChecked(supportAxis, motorMessageText, "");
|
||||
|
||||
return pollStatus;
|
||||
}
|
||||
|
||||
@@ -8,12 +8,16 @@
|
||||
|
||||
#ifndef detectorTowerController_H
|
||||
#define detectorTowerController_H
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "detectorTowerSupportAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
|
||||
class detectorTowerController : public turboPmacController {
|
||||
// Forward declaration of the axis classes to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class HIDDEN detectorTowerAngleAxis;
|
||||
class HIDDEN detectorTowerLiftAxis;
|
||||
class HIDDEN detectorTowerSupportAxis;
|
||||
|
||||
class HIDDEN detectorTowerController : public turboPmacController {
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -35,6 +39,8 @@ class detectorTowerController : public turboPmacController {
|
||||
int numAxes, double movingPollPeriod,
|
||||
double idlePollPeriod, double comTimeout);
|
||||
|
||||
virtual ~detectorTowerController();
|
||||
|
||||
/**
|
||||
* @brief Overloaded function of turboPmacController
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "detectorTowerSupportAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
@@ -69,6 +70,9 @@ detectorTowerLiftAxis::detectorTowerLiftAxis(detectorTowerController *pC,
|
||||
|
||||
angleAxis_ = angleAxis;
|
||||
angleAxis->liftAxis_ = this;
|
||||
|
||||
// Initialize the flag to false
|
||||
waitingForStart_ = false;
|
||||
}
|
||||
|
||||
detectorTowerLiftAxis::~detectorTowerLiftAxis(void) {
|
||||
@@ -111,11 +115,7 @@ asynStatus detectorTowerLiftAxis::init() {
|
||||
}
|
||||
|
||||
// Initialize the motorStatusMoving flag
|
||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusMoving, false);
|
||||
|
||||
// Check if we are currently in the changer position and update the PV
|
||||
// accordingly
|
||||
@@ -126,11 +126,7 @@ asynStatus detectorTowerLiftAxis::init() {
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, changeStateRBV, positionState == 2);
|
||||
|
||||
return callParamCallbacks();
|
||||
}
|
||||
@@ -146,15 +142,9 @@ asynStatus detectorTowerLiftAxis::poll(bool *moving) {
|
||||
status = pC_->pollDetectorAxes(moving, angleAxis(), this,
|
||||
angleAxis()->supportAxis());
|
||||
} else {
|
||||
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
|
||||
(int *)moving);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, motorStatusMoving, moving);
|
||||
}
|
||||
wasMoving_ = *moving;
|
||||
setWasMoving(*moving);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -170,59 +160,23 @@ asynStatus detectorTowerLiftAxis::doMove(double position, int relative,
|
||||
double min_velocity,
|
||||
double max_velocity,
|
||||
double acceleration) {
|
||||
|
||||
double motorRecResolution = 0.0;
|
||||
asynStatus plStatus = pC_->getDoubleParam(
|
||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorRecResolution_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||
|
||||
// Signal to the deferredMovementCollectorLoop (of the
|
||||
// detectorTowerAngleAxis) that a movement should be started to the
|
||||
// defined target position.
|
||||
targetPosition_ = position * motorRecResolution;
|
||||
setTargetPosition(position * motorRecResolution);
|
||||
angleAxis_->receivedTarget_ = true;
|
||||
|
||||
waitingForStart_ = true;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::reset() { return angleAxis()->reset(); };
|
||||
|
||||
asynStatus detectorTowerLiftAxis::stop(double acceleration) {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStopping "
|
||||
"the movement "
|
||||
"failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
}
|
||||
return angleAxis()->stop(acceleration);
|
||||
};
|
||||
|
||||
asynStatus detectorTowerLiftAxis::readEncoderType() {
|
||||
return angleAxis()->readEncoderType();
|
||||
@@ -237,12 +191,7 @@ asynStatus detectorTowerLiftAxis::adjustOrigin(double newOrigin) {
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
@@ -271,13 +220,8 @@ asynStatus detectorTowerLiftAxis::adjustOrigin(double newOrigin) {
|
||||
"lift origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
#ifndef detectorTowerLiftAxis_H
|
||||
#define detectorTowerLiftAxis_H
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacAxis.h"
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class detectorTowerController;
|
||||
class detectorTowerAngleAxis;
|
||||
|
||||
class detectorTowerLiftAxis : public turboPmacAxis {
|
||||
class HIDDEN detectorTowerLiftAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerAngleAxis
|
||||
@@ -19,10 +14,6 @@ class detectorTowerLiftAxis : public turboPmacAxis {
|
||||
detectorTowerLiftAxis(detectorTowerController *pController, int axisNo,
|
||||
detectorTowerAngleAxis *angleAxis);
|
||||
|
||||
/**
|
||||
* @brief Destroy the turboPmacAxis
|
||||
*
|
||||
*/
|
||||
virtual ~detectorTowerLiftAxis();
|
||||
|
||||
/**
|
||||
@@ -114,6 +105,15 @@ class detectorTowerLiftAxis : public turboPmacAxis {
|
||||
*/
|
||||
asynStatus readEncoderType();
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the axis controller
|
||||
*/
|
||||
virtual detectorTowerController *pController() override { return pC_; };
|
||||
|
||||
// True, if this axis has received a move command and the driver is
|
||||
// currently starting a deferred movement.
|
||||
bool waitingForStart_;
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
detectorTowerAngleAxis *angleAxis_;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "detectorTowerSupportAxis.h"
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
@@ -111,11 +112,7 @@ asynStatus detectorTowerSupportAxis::init() {
|
||||
}
|
||||
|
||||
// Initialize the motorStatusMoving flag
|
||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(this, motorStatusMoving, false);
|
||||
|
||||
// Check if we are currently in the changer position and update the PV
|
||||
// accordingly
|
||||
@@ -126,12 +123,7 @@ asynStatus detectorTowerSupportAxis::init() {
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
status = setIntegerParam(pC_->changeStateRBV(), positionState == 2);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "changeStateRBV", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
setAxisParamChecked(this, changeStateRBV, positionState == 2);
|
||||
return callParamCallbacks();
|
||||
}
|
||||
|
||||
@@ -147,15 +139,9 @@ asynStatus detectorTowerSupportAxis::poll(bool *moving) {
|
||||
status = pC_->pollDetectorAxes(moving, angleAxis(),
|
||||
angleAxis()->liftAxis(), this);
|
||||
} else {
|
||||
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
|
||||
(int *)moving);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, motorStatusMoving, moving);
|
||||
}
|
||||
wasMoving_ = *moving;
|
||||
setWasMoving(*moving);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -186,12 +172,7 @@ asynStatus detectorTowerSupportAxis::adjustOrigin(double newOrigin) {
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(this, positionStateRBV, &positionState);
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
@@ -220,12 +201,8 @@ asynStatus detectorTowerSupportAxis::adjustOrigin(double newOrigin) {
|
||||
"lift origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
#ifndef detectorTowerSupportAxis_H
|
||||
#define detectorTowerSupportAxis_H
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacAxis.h"
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class detectorTowerController;
|
||||
class detectorTowerAngleAxis;
|
||||
|
||||
/**
|
||||
* @brief Passive axis which is mostly controlled indirectly by the hardware
|
||||
*
|
||||
*/
|
||||
class detectorTowerSupportAxis : public turboPmacAxis {
|
||||
class HIDDEN detectorTowerSupportAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerSupportAxis
|
||||
@@ -24,10 +19,6 @@ class detectorTowerSupportAxis : public turboPmacAxis {
|
||||
detectorTowerSupportAxis(detectorTowerController *pController, int axisNo,
|
||||
detectorTowerAngleAxis *angleAxis);
|
||||
|
||||
/**
|
||||
* @brief Destroy the detectorTowerSupportAxis
|
||||
*
|
||||
*/
|
||||
virtual ~detectorTowerSupportAxis();
|
||||
|
||||
/**
|
||||
@@ -116,6 +107,11 @@ class detectorTowerSupportAxis : public turboPmacAxis {
|
||||
*/
|
||||
asynStatus readEncoderType();
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the axis controller
|
||||
*/
|
||||
virtual detectorTowerController *pController() override { return pC_; };
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
detectorTowerAngleAxis *angleAxis_;
|
||||
|
||||
Submodule turboPmac updated: 55b523ddaa...9d61852713
Reference in New Issue
Block a user