Current draft for the detector axis tower driver
This commit is contained in:
4
Makefile
4
Makefile
@ -8,11 +8,13 @@ ARCH_FILTER=RHEL%
|
|||||||
|
|
||||||
# Additional module dependencies
|
# Additional module dependencies
|
||||||
REQUIRED+=motorBase
|
REQUIRED+=motorBase
|
||||||
REQUIRED+=turboPmac
|
|
||||||
|
|
||||||
# Specify the version of motorBase we want to build against
|
# Specify the version of motorBase we want to build against
|
||||||
motorBase_VERSION=7.2.2
|
motorBase_VERSION=7.2.2
|
||||||
|
|
||||||
|
# Specify the version of sinqMotor we want to build against
|
||||||
|
sinqMotor_VERSION=mathis_s
|
||||||
|
|
||||||
# Specify the version of turboPmac we want to build against
|
# Specify the version of turboPmac we want to build against
|
||||||
turboPmac_VERSION=mathis_s
|
turboPmac_VERSION=mathis_s
|
||||||
|
|
||||||
|
65
README.md
65
README.md
@ -1,3 +1,66 @@
|
|||||||
# detectorTower
|
# detectorTower
|
||||||
|
|
||||||
TODO!
|
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 two objects:
|
||||||
|
- `detectorTowerAxis`: This is a virtual axis which controls multiple physical motors in order to provide a synchronized movement.
|
||||||
|
- `detectorTowerController`: This is an expanded variant of `turboPmacController` provided by the Turbo PMAC library linked above.It is needed to operate a `detectorTowerAxis`, but it can also be used to operate a "normal" `turboPmacAxis`.
|
||||||
|
The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one.
|
||||||
|
|
||||||
|
## User guide
|
||||||
|
|
||||||
|
This driver is a standard sinqMotor-derived driver and does not need any specific configuration. For the general configuration, please see https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md. The utilities provided in the `utils` folder of https://git.psi.ch/sinq-epics-modules/turboPmac work with this driver as well.
|
||||||
|
|
||||||
|
## Developer guide
|
||||||
|
|
||||||
|
### Usage in IOC shell
|
||||||
|
|
||||||
|
detectorTower exports the following IOC shell functions:
|
||||||
|
- `detectorTowerController`: Create a new controller object.
|
||||||
|
- `detectorTowerAxis`: Create a new axis object.
|
||||||
|
|
||||||
|
As mentioned above, also "normal" `turboPmacAxis` may be used together with this controller:
|
||||||
|
|
||||||
|
```
|
||||||
|
# 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
|
||||||
|
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.
|
||||||
|
# The other parameters are as follows:
|
||||||
|
# 8: Maximum number of axes
|
||||||
|
# 0.05: Busy poll period in seconds
|
||||||
|
# 1: Idle poll period in seconds
|
||||||
|
# 1: Socket communication timeout in seconds
|
||||||
|
detectorTowerController("$(NAME)", "$(ASYN_PORT)", 8, 0.05, 1, 1);
|
||||||
|
|
||||||
|
# Slot 1 is occupied by a detector tower axis, while the slots 2 and 3 are "normal" Turbo PMAC axes.
|
||||||
|
detectorTowerAxis("$(NAME)",1);
|
||||||
|
turboPmacAxis("$(NAME)",2);
|
||||||
|
turboPmacAxis("$(NAME)",3);
|
||||||
|
|
||||||
|
# Set the number of subsequent timeouts
|
||||||
|
setMaxSubsequentTimeouts("$(NAME)", 20);
|
||||||
|
|
||||||
|
# Configure the timeout frequency watchdog:
|
||||||
|
setThresholdComTimeout("$(NAME)", 100, 1);
|
||||||
|
|
||||||
|
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||||
|
# Since this driver is based on Turbo PMAC, we need to parametrize turboPmac.db in addition to sinqMotor.db and detectorTower.db.
|
||||||
|
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
epicsEnvSet("SINQDBPATH","$(detectorTower_DB)/detectorTower.db")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Versioning
|
||||||
|
|
||||||
|
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||||
|
|
||||||
|
### How to build it
|
||||||
|
|
||||||
|
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
@ -1,70 +0,0 @@
|
|||||||
# Reset any errors of the virtual axis.
|
|
||||||
# This record is coupled to the parameter library via reset_ -> RESET.
|
|
||||||
record(longout, "$(INSTR)$(M):Reset") {
|
|
||||||
field(DTYP, "asynInt32")
|
|
||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) RESET")
|
|
||||||
field(PINI, "NO")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read the position state of the axis:
|
|
||||||
# 0 = not ready
|
|
||||||
# 1 = ready (in working position)
|
|
||||||
# 2 = ready (in changer position)
|
|
||||||
record(longout, "$(INSTR)$(M):PositionState")
|
|
||||||
{
|
|
||||||
field(DTYP, "asynInt32")
|
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) POSITION_STATE")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set the target position for the offset of the lift (motor COZ)
|
|
||||||
# This record is coupled to the parameter library via liftOffset_ -> LIFT_OFFSET.
|
|
||||||
record(ao, "$(INSTR)$(M):LiftOffset") {
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIFT_OFFSET")
|
|
||||||
field(PINI, "NO")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set the target position for the offset of the lift (motor COZ)
|
|
||||||
# This record is coupled to the parameter library via liftOffset_ -> LIFT_OFFSET.
|
|
||||||
record(ao, "$(INSTR)$(M):LiftOffset") {
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIFT_OFFSET")
|
|
||||||
field(PINI, "NO")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read the lower and upper limits for the lift offset
|
|
||||||
record(ai, "$(INSTR)$(M):LiftOffsetLowLimitRBV")
|
|
||||||
{
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) LIFT_OFFSET_LOW_LIMIT")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
||||||
record(ai, "$(INSTR)$(M):LiftOffsetHighLimitRBV")
|
|
||||||
{
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) LIFT_OFFSET_HIGH_LIMIT")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set the target position for the offset of the detector tilt (motor COX)
|
|
||||||
# This record is coupled to the parameter library via tiltOffset_ -> TILT_OFFSET.
|
|
||||||
record(ao, "$(INSTR)$(M):TiltOffset") {
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) TILT_OFFSET")
|
|
||||||
field(PINI, "NO")
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read the lower and upper limits for the detector tilt offset
|
|
||||||
record(ai, "$(INSTR)$(M):TiltOffsetLowLimitRBV")
|
|
||||||
{
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) TILT_OFFSET_LOW_LIMIT")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
||||||
record(ai, "$(INSTR)$(M):TiltOffsetHighLimitRBV")
|
|
||||||
{
|
|
||||||
field(DTYP, "asynFloat64")
|
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) TILT_OFFSET_HIGH_LIMIT")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
134
db/detectorTower.db
Normal file
134
db/detectorTower.db
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# Reset any errors of the virtual axis.
|
||||||
|
# This record is coupled to the parameter library via resetError_ -> RESET_ERROR.
|
||||||
|
record(longout, "$(INSTR)$(M):ResetError") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) RESET_ERROR")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start the movement into the position defined by BeamAngle, LiftOffset and TiltOffset
|
||||||
|
record(longout, "$(INSTR)$(M):MoveToWorkingPosition") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOVE_TO_WORKING_POSITION")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the position state of the axis:
|
||||||
|
# 0 = not ready
|
||||||
|
# 1 = ready (in working position)
|
||||||
|
# 2 = Moving from working to changer position or in changer position
|
||||||
|
# 2 = Moving from changer to working position
|
||||||
|
record(longout, "$(INSTR)$(M):PositionState")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS)) POSITION_STATE")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start the movement into the position defined by BeamAngle, LiftOffset and TiltOffset
|
||||||
|
record(longout, "$(INSTR)$(M):Start") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) START")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the target angle for the beam
|
||||||
|
record(ao, "$(INSTR)$(M):BeamAngle") {
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) BEAM_ANGLE")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy the high and low limits from the motor record
|
||||||
|
record(ao, "$(INSTR)$(M):DHLM2BeamAngle_RBV") {
|
||||||
|
field(DOL, "$(INSTR)$(M).DHLM CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):BeamAngle.DRVH")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
||||||
|
record(ao, "$(INSTR)$(M):DLLM2BeamAngle_RBV") {
|
||||||
|
field(DOL, "$(INSTR)$(M).DLLM CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):BeamAngle.DRVL")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the target position for the offset of the lift (motor COZ)
|
||||||
|
# This record is coupled to the parameter library via liftOffset_ -> LIFT_OFFSET.
|
||||||
|
record(ao, "$(INSTR)$(M):LiftOffset") {
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIFT_OFFSET")
|
||||||
|
field(PINI, "NO")
|
||||||
|
field(FLNK, "$(INSTR)$(M):LiftOffsetFwd")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Like $(INSTR)$(M):LiftOffset, but starts a movement immediately, if able
|
||||||
|
record(ao, "$(INSTR)$(M):LiftOffsetMove") {
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIFT_OFFSET_MOVE")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the lower and upper limits for the lift offset
|
||||||
|
record(ai, "$(INSTR)$(M):LiftOffsetLowLimitRBV")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) LIFT_OFFSET_LOW_LIMIT")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
}
|
||||||
|
record(ao, "$(INSTR)$(M):LiftOffsetLowLimit2Field") {
|
||||||
|
field(DOL, "$(INSTR)$(M):LiftOffsetLowLimitRBV CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):LiftOffset.DRVL")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
record(ai, "$(INSTR)$(M):LiftOffsetHighLimitRBV")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) LIFT_OFFSET_HIGH_LIMIT")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
}
|
||||||
|
record(ao, "$(INSTR)$(M):LiftOffsetHighLimit2Field") {
|
||||||
|
field(DOL, "$(INSTR)$(M):LiftOffsetHighLimitRBV CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):LiftOffset.DRVH")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the target position for the offset of the detector tilt (motor COX)
|
||||||
|
# This record is coupled to the parameter library via tiltOffset_ -> TILT_OFFSET.
|
||||||
|
record(ao, "$(INSTR)$(M):TiltOffset") {
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) TILT_OFFSET")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Like $(INSTR)$(M):TiltOffset, but starts a movement immediately, if able
|
||||||
|
record(ao, "$(INSTR)$(M):TiltOffsetMove") {
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) TILT_OFFSET")
|
||||||
|
field(PINI, "NO")
|
||||||
|
field(FLNK, "$(INSTR)$(M):Start")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the lower and upper limits for the detector tilt offset
|
||||||
|
record(ai, "$(INSTR)$(M):TiltOffsetLowLimitRBV")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) TILT_OFFSET_LOW_LIMIT")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
}
|
||||||
|
record(ao, "$(INSTR)$(M):TiltOffsetLowLimit2Field") {
|
||||||
|
field(DOL, "$(INSTR)$(M):TiltOffsetLowLimitRBV CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):TiltOffset.DRVL")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
||||||
|
|
||||||
|
record(ai, "$(INSTR)$(M):TiltOffsetHighLimitRBV")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynFloat64")
|
||||||
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) TILT_OFFSET_HIGH_LIMIT")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
}
|
||||||
|
record(ao, "$(INSTR)$(M):TiltOffsetHighLimit2Field") {
|
||||||
|
field(DOL, "$(INSTR)$(M):TiltOffsetHighLimitRBV CP")
|
||||||
|
field(OUT, "$(INSTR)$(M):TiltOffset.DRVH")
|
||||||
|
field(OMSL, "closed_loop")
|
||||||
|
}
|
@ -1,13 +1,35 @@
|
|||||||
#include "detectorTowerAxis.h"
|
#include "detectorTowerAxis.h"
|
||||||
|
#include "detectorTowerController.h"
|
||||||
#include "turboPmacController.h"
|
#include "turboPmacController.h"
|
||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
|
|
||||||
detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
/*
|
||||||
: sinqAxis(pC, axisNo), pC_(pC) {
|
Contains all instances of turboPmacAxis which have been created and is used in
|
||||||
|
the initialization hook function.
|
||||||
|
*/
|
||||||
|
static std::vector<detectorTowerAxis *> axes;
|
||||||
|
|
||||||
asynStatus status = asynSuccess;
|
/**
|
||||||
|
* @brief Hook function to perform certain actions during the IOC initialization
|
||||||
|
*
|
||||||
|
* @param iState
|
||||||
|
*/
|
||||||
|
static void epicsInithookFunction(initHookState iState) {
|
||||||
|
if (iState == initHookAfterDatabaseRunning) {
|
||||||
|
// Iterate through all axes of each and call the initialization method
|
||||||
|
// on each one of them.
|
||||||
|
for (std::vector<detectorTowerAxis *>::iterator itA = axes.begin();
|
||||||
|
itA != axes.end(); ++itA) {
|
||||||
|
detectorTowerAxis *axis = *itA;
|
||||||
|
axis->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
||||||
|
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The superclass constructor sinqAxis calls in turn its superclass constructor
|
The superclass constructor sinqAxis calls in turn its superclass constructor
|
||||||
@ -37,7 +59,75 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
|||||||
error_ = 0;
|
error_ = 0;
|
||||||
scheduleMoveFromParamLib_ = false;
|
scheduleMoveFromParamLib_ = false;
|
||||||
|
|
||||||
// Speed cannot be changed
|
// Register the hook function during construction of the first axis object
|
||||||
|
if (axes.empty()) {
|
||||||
|
initHookRegister(&epicsInithookFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all axes into this list which will be used in the hook
|
||||||
|
// function
|
||||||
|
axes.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
detectorTowerAxis::~detectorTowerAxis(void) {
|
||||||
|
// Since the controller memory is managed somewhere else, we don't need to
|
||||||
|
// clean up the pointer pC here.
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus detectorTowerAxis::init() {
|
||||||
|
|
||||||
|
// Local variable declaration
|
||||||
|
asynStatus status = asynSuccess;
|
||||||
|
double motorRecResolution = 0.0;
|
||||||
|
|
||||||
|
// The parameter library takes some time to be initialized. Therefore we
|
||||||
|
// wait until the status is not asynParamUndefined anymore.
|
||||||
|
time_t now = time(NULL);
|
||||||
|
time_t maxInitTime = 60;
|
||||||
|
while (1) {
|
||||||
|
status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
||||||
|
&motorRecResolution);
|
||||||
|
if (status == asynParamUndefined) {
|
||||||
|
if (now + maxInitTime < time(NULL)) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d\nInitializing the parameter library failed.\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
} else if (status == asynSuccess) {
|
||||||
|
break;
|
||||||
|
} else if (status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(status, "motorRecResolution_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize some values in the parameter library
|
||||||
|
status = pC_->setDoubleParam(axisNo_, pC_->liftOffset_, 0.0);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(
|
||||||
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nFATAL ERROR "
|
||||||
|
"(setting a parameter value failed with %s)\n. Terminating IOC",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
status = pC_->setDoubleParam(axisNo_, pC_->tiltOffset_, 0.0);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(
|
||||||
|
pC_->pasynUserSelf, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize some values in the parameter library
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanSetSpeed_, 0);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanSetSpeed_, 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
@ -49,16 +139,7 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->positionState_, 1);
|
return status;
|
||||||
if (status != asynSuccess) {
|
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the actual poll
|
// Perform the actual poll
|
||||||
@ -131,8 +212,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nvals =
|
nvals =
|
||||||
sscanf(response, "%d %d %lf %d %lf %lf %lf %lf %lf %lf", &inPosition,
|
sscanf(response, "%d %d %d %lf %lf %lf %lf %lf %lf %lf", &inPosition,
|
||||||
&positionState, &beamTiltAngle, &error, &highLimit, &lowLimit,
|
&positionState, &error, &beamTiltAngle, &highLimit, &lowLimit,
|
||||||
&liftOffsetHighLimit, &liftOffsetLowLimit, &tiltOffsetHighLimit,
|
&liftOffsetHighLimit, &liftOffsetLowLimit, &tiltOffsetHighLimit,
|
||||||
&tiltOffsetLowLimit);
|
&tiltOffsetLowLimit);
|
||||||
if (nvals != 10) {
|
if (nvals != 10) {
|
||||||
@ -179,37 +260,49 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
*moving = true;
|
*moving = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intepret the position state
|
// Create the unique callsite identifier manually so it can be used later in
|
||||||
|
// the shouldBePrinted calls.
|
||||||
|
msgPrintControlKey keyPosState = msgPrintControlKey(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
|
// Reset the count, if the status is not an error state
|
||||||
|
bool resetCountPosState = true;
|
||||||
|
|
||||||
|
// Interpret the position state
|
||||||
switch (positionState) {
|
switch (positionState) {
|
||||||
case 0:
|
case 0:
|
||||||
asynPrint(
|
// Axis not ready
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis not ready\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
// Axis ready
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis ready\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyPosState, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis in change "
|
pC_->pasynUserSelf)) {
|
||||||
"position\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
asynPrint(
|
||||||
|
pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nAxis in change "
|
||||||
|
"position.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetCountPosState = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*moving = false;
|
*moving = false;
|
||||||
snprintf(userMessage, sizeof(userMessage),
|
|
||||||
"No air cushion feedback before movement start (P%2.2d01 = "
|
|
||||||
"%d). Please call the support.",
|
|
||||||
axisNo_, error);
|
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyPosState, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nReached unknown "
|
pC_->pasynUserSelf)) {
|
||||||
"state P354 = %d\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
positionState);
|
"Controller \"%s\", axis %d => %s, line %d\nReached unknown "
|
||||||
|
"state P354 = %d.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
positionState, pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetCountPosState = false;
|
||||||
|
|
||||||
snprintf(userMessage, sizeof(userMessage),
|
snprintf(userMessage, sizeof(userMessage),
|
||||||
"Unknown state P354 = %d has been reached. Please call "
|
"Unknown state P354 = %d has been reached. Please call "
|
||||||
"the support.",
|
"the support.",
|
||||||
@ -222,6 +315,10 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resetCountPosState) {
|
||||||
|
pC_->msgPrintControl_.resetCount(keyPosState);
|
||||||
|
}
|
||||||
|
|
||||||
if (*moving) {
|
if (*moving) {
|
||||||
// If the axis is moving, evaluate the movement direction
|
// If the axis is moving, evaluate the movement direction
|
||||||
if ((beamTiltAngle - previousBeamTiltAngle) > 0) {
|
if ((beamTiltAngle - previousBeamTiltAngle) > 0) {
|
||||||
@ -231,16 +328,28 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the unique callsite identifier manually so it can be used later in
|
||||||
|
// the shouldBePrinted calls.
|
||||||
|
msgPrintControlKey keyError = msgPrintControlKey(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
bool resetError = true;
|
||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case 0:
|
case 0:
|
||||||
// No error
|
// No error
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nBrake COZ not "
|
pC_->pasynUserSelf)) {
|
||||||
"released (P359=1).\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, error);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nBrake COZ not "
|
||||||
|
"released (P359=1).%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -256,10 +365,16 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nMove command "
|
pC_->pasynUserSelf)) {
|
||||||
"rejected because axis is already moving.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nMove command "
|
||||||
|
"rejected because axis is already moving.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText_,
|
pl_status = setStringParam(pC_->motorMessageText_,
|
||||||
"Move command rejected because axis is "
|
"Move command rejected because axis is "
|
||||||
@ -274,10 +389,15 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
asynPrint(
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nError motor FTZ.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line %d\nError motor "
|
||||||
|
"FTZ.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -293,10 +413,16 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis stopped "
|
pC_->pasynUserSelf)) {
|
||||||
"unexpectedly.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nAxis stopped "
|
||||||
|
"unexpectedly.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -313,10 +439,16 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nRelease removed "
|
pC_->pasynUserSelf)) {
|
||||||
"while moving.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nRelease removed "
|
||||||
|
"while moving.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status = setStringParam(
|
pl_status = setStringParam(
|
||||||
pC_->motorMessageText_,
|
pC_->motorMessageText_,
|
||||||
@ -333,10 +465,16 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nEmergency stop "
|
pC_->pasynUserSelf)) {
|
||||||
"activated.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nEmergency stop "
|
||||||
|
"activated.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_, "Emergency stop activate");
|
setStringParam(pC_->motorMessageText_, "Emergency stop activate");
|
||||||
@ -350,10 +488,15 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
asynPrint(
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nError motor COZ.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line %d\nError motor "
|
||||||
|
"COZ.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -369,10 +512,15 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 8:
|
case 8:
|
||||||
asynPrint(
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nError motor COM.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line %d\nError motor "
|
||||||
|
"COM.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -388,10 +536,15 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
asynPrint(
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nError motor COX.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line %d\nError motor "
|
||||||
|
"COX.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -407,10 +560,15 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
asynPrint(
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nHit end switch FTZ.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line %d\nHit end "
|
||||||
|
"switch FTZ.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_, "Hit end switch FTZ");
|
setStringParam(pC_->motorMessageText_, "Hit end switch FTZ");
|
||||||
@ -425,16 +583,22 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
case 11:
|
case 11:
|
||||||
// Following error
|
// Following error
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed "
|
pC_->pasynUserSelf)) {
|
||||||
"following error FTZ exceeded.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed "
|
||||||
|
"following error FTZ exceeded.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
snprintf(userMessage, sizeof(userMessage),
|
snprintf(userMessage, sizeof(userMessage),
|
||||||
"Maximum allowed following error exceeded (P359 = %d). "
|
"Maximum allowed following error exceeded (P359 = %d). "
|
||||||
"Check if movement range is blocked. "
|
"Check if movement range is blocked. "
|
||||||
"Otherwise please call the support.",
|
"Otherwise please call the support.",
|
||||||
axisNo_, error);
|
error);
|
||||||
pl_status = setStringParam(pC_->motorMessageText_, userMessage);
|
pl_status = setStringParam(pC_->motorMessageText_, userMessage);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||||
@ -446,10 +610,16 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nUnknown error "
|
pC_->pasynUserSelf)) {
|
||||||
"P359 = %d.\n",
|
asynPrint(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, error);
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nUnknown error "
|
||||||
|
"P359 = %d.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, error,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
resetError = false;
|
||||||
|
|
||||||
snprintf(userMessage, sizeof(userMessage),
|
snprintf(userMessage, sizeof(userMessage),
|
||||||
"Unknown error P359 = %d. Please call the support.", error);
|
"Unknown error P359 = %d. Please call the support.", error);
|
||||||
@ -464,6 +634,10 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resetError) {
|
||||||
|
pC_->msgPrintControl_.resetCount(keyError);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the parameter library
|
// Update the parameter library
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
@ -569,14 +743,49 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
// If a movement is scheduled and the axis is not moving anymore, start the
|
// If a movement is scheduled and the axis is not moving anymore, start the
|
||||||
// scheduled movement. This replaces the original motor record movement
|
// scheduled movement. This replaces the original motor record movement
|
||||||
// control loop functionality.
|
// control loop functionality.
|
||||||
if (scheduleMoveFromParamLib_ && !moving && poll_status == asynSuccess) {
|
if (scheduleMoveFromParamLib_ && !(*moving) && poll_status == asynSuccess) {
|
||||||
scheduleMoveFromParamLib_ = false;
|
scheduleMoveFromParamLib_ = false;
|
||||||
|
|
||||||
|
// Update the parameter library immediately
|
||||||
|
pl_status = callParamCallbacks();
|
||||||
|
|
||||||
|
if (pC_->msgPrintControl_.shouldBePrinted(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pl_status != asynSuccess, pC_->pasynUserSelf)) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d:\ncallParamCallbacks failed with %s.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->stringifyAsynStatus(poll_status),
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return poll_status;
|
||||||
|
}
|
||||||
|
|
||||||
return moveFromParamLib();
|
return moveFromParamLib();
|
||||||
} else {
|
} else {
|
||||||
return poll_status;
|
return poll_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus detectorTowerAxis::move(double position, int relative,
|
||||||
|
double min_velocity, double max_velocity,
|
||||||
|
double acceleration) {
|
||||||
|
|
||||||
|
// Status of parameter library operations
|
||||||
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
|
// Set the position as beam angle
|
||||||
|
pl_status = pC_->setDoubleParam(axisNo_, pC_->beamAngle_, position);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "beamAngle_", axisNo_,
|
||||||
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
return moveFromParamLib();
|
||||||
|
}
|
||||||
|
|
||||||
asynStatus detectorTowerAxis::moveFromParamLib() {
|
asynStatus detectorTowerAxis::moveFromParamLib() {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
@ -586,13 +795,11 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
||||||
double motorTargetPosition = 0.0;
|
|
||||||
double motorCoordinatesPosition = 0.0;
|
double motorCoordinatesPosition = 0.0;
|
||||||
double motorRecResolution = 0.0;
|
double motorRecResolution = 0.0;
|
||||||
|
double beamAngle = 0.0;
|
||||||
double liftOffset = 0.0;
|
double liftOffset = 0.0;
|
||||||
double tiltOffset = 0.0;
|
double tiltOffset = 0.0;
|
||||||
double motorVelocity = 0.0;
|
|
||||||
int motorCanSetSpeed = 0;
|
|
||||||
int writeOffset = 0;
|
int writeOffset = 0;
|
||||||
int positionState = 0;
|
int positionState = 0;
|
||||||
|
|
||||||
@ -607,21 +814,27 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
|
|
||||||
// If the axis is in changer position, it must be moved into working
|
// If the axis is in changer position, it must be moved into working
|
||||||
// position before any move can be started.
|
// position before any move can be started.
|
||||||
if (positionState == 2) {
|
bool isInChangerPos = positionState == 2 || positionState == 3;
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
if (pC_->msgPrintControl_.shouldBePrinted(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
isInChangerPos, pC_->pasynUserSelf)) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
||||||
"moved because it is in changer "
|
"moved because it is moving from working to changer "
|
||||||
"position. Move it to working position first.\n",
|
"position, is in changer position or is moving from changer "
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"to working position.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
if (isInChangerPos) {
|
||||||
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the target values from the parameter library
|
// Read the target values from the parameter library
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorTargetPosition_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->beamAngle_, &beamAngle);
|
||||||
&motorTargetPosition);
|
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorTargetPosition_",
|
return pC_->paramLibAccessFailed(pl_status, "beamAngle_", axisNo_,
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
__LINE__);
|
|
||||||
}
|
}
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->liftOffset_, &liftOffset);
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->liftOffset_, &liftOffset);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
@ -633,7 +846,6 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
return pC_->paramLibAccessFailed(pl_status, "tiltOffset_", axisNo_,
|
return pC_->paramLibAccessFailed(pl_status, "tiltOffset_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
||||||
&motorRecResolution);
|
&motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
@ -645,13 +857,12 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
// Set the target positions for beam tilt, detector tilt offset and lift
|
// Set the target positions for beam tilt, detector tilt offset and lift
|
||||||
// offset
|
// offset
|
||||||
snprintf(&command[writeOffset], sizeof(command) - writeOffset,
|
snprintf(&command[writeOffset], sizeof(command) - writeOffset,
|
||||||
"Q451=%lf Q454=%lf Qxxx=%lf P350=1", motorTargetPosition,
|
"Q451=%lf Q454=%lf Q456=%lf P350=1", beamAngle, liftOffset,
|
||||||
liftOffset, tiltOffset);
|
tiltOffset);
|
||||||
|
|
||||||
// We don't expect an answer
|
// We don't expect an answer
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
|
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to "
|
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to "
|
||||||
@ -665,6 +876,10 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start polling immediately
|
||||||
|
pC_->wakeupPoller();
|
||||||
|
|
||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,12 +910,13 @@ asynStatus detectorTowerAxis::stop(double acceleration) {
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The AMOR detector axis uses absolute encoders
|
// The detector tower axis uses absolute encoders
|
||||||
asynStatus detectorTowerAxis::readEncoderType() {
|
asynStatus detectorTowerAxis::readEncoderType() {
|
||||||
asynStatus status = setStringParam(pC_->encoderType_, AbsoluteEncoder);
|
asynStatus status = setStringParam(pC_->encoderType_, AbsoluteEncoder);
|
||||||
|
|
||||||
@ -713,9 +929,7 @@ asynStatus detectorTowerAxis::readEncoderType() {
|
|||||||
|
|
||||||
asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
||||||
|
|
||||||
int timeout_enable_disable = 2;
|
char response[pC_->MAXBUF_];
|
||||||
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
|
||||||
int nvals = 0;
|
|
||||||
|
|
||||||
// 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 rw_status = asynSuccess;
|
||||||
@ -741,12 +955,18 @@ asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
|||||||
// command and inform the user. We check the last known status of the axis
|
// command and inform the user. We check the last known status of the axis
|
||||||
// instead of "moving", since status -6 is also moving, but the motor can
|
// instead of "moving", since status -6 is also moving, but the motor can
|
||||||
// actually be disabled in this state!
|
// actually be disabled in this state!
|
||||||
if (moving) {
|
|
||||||
|
if (pC_->msgPrintControl_.shouldBePrinted(pC_->portName, axisNo_,
|
||||||
|
__PRETTY_FUNCTION__, __LINE__,
|
||||||
|
moving, pC_->pasynUserSelf)) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
||||||
"idle and can therefore not be moved to changer position.\n",
|
"idle and can therefore not be moved to %s position.%s\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
toWorkingPosition ? "working" : "changer",
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
if (moving) {
|
||||||
pl_status = setStringParam(
|
pl_status = setStringParam(
|
||||||
pC_->motorMessageText_,
|
pC_->motorMessageText_,
|
||||||
"Axis cannot be moved to changer position while it is moving.");
|
"Axis cannot be moved to changer position while it is moving.");
|
||||||
@ -755,19 +975,24 @@ asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Axis is already enabled / disabled and a new enable / disable command
|
// Axis is already in the correct position
|
||||||
// was sent => Do nothing
|
bool isAlreadyThere = (toWorkingPosition == true && positionState == 1) ||
|
||||||
if ((toWorkingPosition == true && positionState == 1) ||
|
(toWorkingPosition == false && positionState == 2);
|
||||||
(toWorkingPosition == false && positionState == 2)) {
|
|
||||||
|
if (pC_->msgPrintControl_.shouldBePrinted(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
isAlreadyThere, pC_->pasynUserSelf)) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is already "
|
"Controller \"%s\", axis %d => %s, line %d\nAxis is already "
|
||||||
"in %s position.\n",
|
"in %s position.%s\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
toWorkingPosition ? "working" : "changer");
|
toWorkingPosition ? "working" : "changer",
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
if (isAlreadyThere) {
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,6 +1001,7 @@ asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
|||||||
rw_status = pC_->writeRead(axisNo_, "P350=3", response, 0);
|
rw_status = pC_->writeRead(axisNo_, "P350=3", response, 0);
|
||||||
pl_status = setStringParam(pC_->motorMessageText_,
|
pl_status = setStringParam(pC_->motorMessageText_,
|
||||||
"Moving to working position ...");
|
"Moving to working position ...");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
rw_status = pC_->writeRead(axisNo_, "P350=2", response, 0);
|
rw_status = pC_->writeRead(axisNo_, "P350=2", response, 0);
|
||||||
pl_status = setStringParam(pC_->motorMessageText_,
|
pl_status = setStringParam(pC_->motorMessageText_,
|
||||||
@ -786,7 +1012,7 @@ asynStatus detectorTowerAxis::moveToWorkingPosition(bool toWorkingPosition) {
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
return pC_->writeRead(axisNo_, command, response, 0);
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus detectorTowerAxis::reset() {
|
asynStatus detectorTowerAxis::reset() {
|
||||||
@ -810,25 +1036,10 @@ asynStatus detectorTowerAxis::reset() {
|
|||||||
- If any other error: P352 = 2 (Reset error)
|
- If any other error: P352 = 2 (Reset error)
|
||||||
*/
|
*/
|
||||||
if (positionState == 0) {
|
if (positionState == 0) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nSetting axis in "
|
|
||||||
"closed-loop mode.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
return pC_->writeRead(axisNo_, "P352=1", response, 0);
|
return pC_->writeRead(axisNo_, "P352=1", response, 0);
|
||||||
} else if (error_ == 10 || error_ == 11) {
|
} else if (error_ == 10 || error_ == 11) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nResetting FTZ "
|
|
||||||
"motor error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
return pC_->writeRead(axisNo_, "P352=3", response, 0);
|
return pC_->writeRead(axisNo_, "P352=3", response, 0);
|
||||||
} else if (error_ != 0) {
|
} else if (error_ != 0) {
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nResetting error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
return pC_->writeRead(axisNo_, "P352=2", response, 0);
|
return pC_->writeRead(axisNo_, "P352=2", response, 0);
|
||||||
} else {
|
} else {
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
@ -879,7 +1090,7 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axis) {
|
|||||||
detectorTowerController *pC = dynamic_cast<detectorTowerController *>(apd);
|
detectorTowerController *pC = dynamic_cast<detectorTowerController *>(apd);
|
||||||
if (pC == nullptr) {
|
if (pC == nullptr) {
|
||||||
errlogPrintf("Controller \"%s\" => %s, line %d\nController "
|
errlogPrintf("Controller \"%s\" => %s, line %d\nController "
|
||||||
"is not a turboPmacController.",
|
"is not a detectorTowerController.",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
@ -929,4 +1140,4 @@ static void detectorTowerAxisRegister(void) {
|
|||||||
}
|
}
|
||||||
epicsExportRegistrar(detectorTowerAxisRegister);
|
epicsExportRegistrar(detectorTowerAxisRegister);
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
#ifndef detectorTowerAXIS_H
|
#ifndef detectorTowerAxis_H
|
||||||
#define detectorTowerAXIS_H
|
#define detectorTowerAxis_H
|
||||||
#include "detectorTowerController.h"
|
#include "turboPmacAxis.h"
|
||||||
#include "sinqAxis.h"
|
#include <errlog.h>
|
||||||
|
|
||||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||||
// between the controller and the axis .h-file. See
|
// between the controller and the axis .h-file. See
|
||||||
// https://en.cppreference.com/w/cpp/language/class.
|
// https://en.cppreference.com/w/cpp/language/class.
|
||||||
class detectorTowerController;
|
class detectorTowerController;
|
||||||
|
|
||||||
class detectorTowerAxis : public sinqAxis {
|
class detectorTowerAxis : public turboPmacAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new turboPmacAxis
|
* @brief Construct a new detectorTowerAxis
|
||||||
*
|
*
|
||||||
* @param pController Pointer to the associated controller
|
* @param pController Pointer to the associated controller
|
||||||
* @param axisNo Index of the axis
|
* @param axisNo Index of the axis
|
||||||
@ -69,9 +69,7 @@ class detectorTowerAxis : public sinqAxis {
|
|||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus move(double position, int relative, double min_velocity,
|
||||||
double max_velocity, double acceleration) {
|
double max_velocity, double acceleration);
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start a movement based on the parameter library values for
|
* @brief Start a movement based on the parameter library values for
|
||||||
@ -109,10 +107,6 @@ class detectorTowerAxis : public sinqAxis {
|
|||||||
detectorTowerController *pC_;
|
detectorTowerController *pC_;
|
||||||
|
|
||||||
bool scheduleMoveFromParamLib_;
|
bool scheduleMoveFromParamLib_;
|
||||||
bool waitForHandshake_;
|
|
||||||
time_t timeAtHandshake_;
|
|
||||||
bool inChangerPosition_;
|
|
||||||
|
|
||||||
int error_;
|
int error_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "detectorTowerController.h"
|
#include "detectorTowerController.h"
|
||||||
|
#include "detectorTowerAxis.h"
|
||||||
#include "turboPmacController.h"
|
#include "turboPmacController.h"
|
||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
|
#include <errlog.h>
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +40,17 @@ detectorTowerController::detectorTowerController(
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status =
|
||||||
|
createParam("LIFT_OFFSET_MOVE", asynParamFloat64, &liftOffsetMove_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
status = createParam("LIFT_OFFSET_LOW_LIMIT", asynParamFloat64,
|
status = createParam("LIFT_OFFSET_LOW_LIMIT", asynParamFloat64,
|
||||||
&liftOffsetLowLimit_);
|
&liftOffsetLowLimit_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -70,6 +83,17 @@ detectorTowerController::detectorTowerController(
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status =
|
||||||
|
createParam("TILT_OFFSET_MOVE", asynParamFloat64, &tiltOffsetMove_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
status = createParam("TILT_OFFSET_LOW_LIMIT", asynParamFloat64,
|
status = createParam("TILT_OFFSET_LOW_LIMIT", asynParamFloat64,
|
||||||
&tiltOffsetLowLimit_);
|
&tiltOffsetLowLimit_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -92,6 +116,16 @@ detectorTowerController::detectorTowerController(
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = createParam("BEAM_ANGLE", asynParamFloat64, &beamAngle_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
status = createParam("POSITION_STATE", asynParamInt32, &positionState_);
|
status = createParam("POSITION_STATE", asynParamInt32, &positionState_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
@ -102,7 +136,28 @@ detectorTowerController::detectorTowerController(
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("RESET", asynParamInt32, &reset_);
|
status = createParam("START", asynParamInt32, &start_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = createParam("MOVE_TO_WORKING_POSITION", asynParamInt32,
|
||||||
|
&moveToWorkingPosition_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = createParam("RESET_ERROR", asynParamInt32, &resetError_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
@ -115,12 +170,20 @@ detectorTowerController::detectorTowerController(
|
|||||||
|
|
||||||
asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
|
asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
|
||||||
epicsInt32 *value) {
|
epicsInt32 *value) {
|
||||||
// The detector tower cannot be disabled
|
|
||||||
if (pasynUser->reason == motorCanDisable_) {
|
// Check if the axis is a detectorTowerAxis
|
||||||
*value = 0;
|
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
||||||
return asynSuccess;
|
if (axis == nullptr) {
|
||||||
} else {
|
// This is apparently a "normal" turboPmacAxis
|
||||||
return turboPmacController::readInt32(pasynUser, value);
|
return turboPmacController::readInt32(pasynUser, value);
|
||||||
|
} else {
|
||||||
|
// The detector tower cannot be disabled
|
||||||
|
if (pasynUser->reason == motorCanDisable_) {
|
||||||
|
*value = 0;
|
||||||
|
return asynSuccess;
|
||||||
|
} else {
|
||||||
|
return turboPmacController::readInt32(pasynUser, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,22 +193,40 @@ asynStatus detectorTowerController::writeInt32(asynUser *pasynUser,
|
|||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
detectorTowerAxis *axis = getVirtualAxis(pasynUser);
|
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
||||||
if (axis == nullptr) {
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
|
||||||
"instance of sinqAxis",
|
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle custom PVs
|
if (axis == nullptr) {
|
||||||
if (function == motorEnable_) {
|
// This is apparently a "normal" turboPmacAxis
|
||||||
return axis->enable(value);
|
|
||||||
} else if (function == reset_) {
|
|
||||||
return axis->reset();
|
|
||||||
} else {
|
|
||||||
return turboPmacController::writeInt32(pasynUser, value);
|
return turboPmacController::writeInt32(pasynUser, value);
|
||||||
|
} else {
|
||||||
|
// Handle custom PVs
|
||||||
|
if (function == start_) {
|
||||||
|
|
||||||
|
// Start the movement, if the axis is not already moving.
|
||||||
|
// Otherwise stop it and schedule a movement.
|
||||||
|
int done = 0;
|
||||||
|
asynStatus status =
|
||||||
|
getIntegerParam(axis->axisNo_, motorStatusDone_, &done);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return paramLibAccessFailed(status, "motorStatusDone_",
|
||||||
|
axis->axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done == 1) {
|
||||||
|
return axis->moveFromParamLib();
|
||||||
|
} else {
|
||||||
|
axis->scheduleMoveFromParamLib_ = true;
|
||||||
|
return axis->stop(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (function == moveToWorkingPosition_) {
|
||||||
|
return axis->moveToWorkingPosition(value != 0);
|
||||||
|
} else if (function == resetError_) {
|
||||||
|
return axis->reset();
|
||||||
|
} else {
|
||||||
|
return turboPmacController::writeInt32(pasynUser, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,30 +234,33 @@ asynStatus detectorTowerController::writeFloat64(asynUser *pasynUser,
|
|||||||
epicsFloat64 value) {
|
epicsFloat64 value) {
|
||||||
int function = pasynUser->reason;
|
int function = pasynUser->reason;
|
||||||
|
|
||||||
// =====================================================================
|
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
||||||
|
|
||||||
detectorTowerAxis *axis = getVirtualAxis(pasynUser);
|
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
// This is apparently a "normal" turboPmacAxis
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
|
||||||
"instance of sinqAxis",
|
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function == motorTargetPosition_) {
|
|
||||||
// Start the movement, if the axis is not already moving. Otherwise stop
|
|
||||||
// it and schedule a movement.
|
|
||||||
bool moving = false;
|
|
||||||
axis->poll(&moving);
|
|
||||||
if (moving) {
|
|
||||||
axis->scheduleMoveFromParamLib_ = true;
|
|
||||||
return axis->stop(0.0);
|
|
||||||
} else {
|
|
||||||
return axis->moveFromParamLib();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return turboPmacController::writeFloat64(pasynUser, value);
|
return turboPmacController::writeFloat64(pasynUser, value);
|
||||||
|
} else {
|
||||||
|
if (function == liftOffsetMove_) {
|
||||||
|
asynStatus status =
|
||||||
|
setDoubleParam(axis->axisNo_, liftOffset_, value);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return paramLibAccessFailed(status, "liftOffset_",
|
||||||
|
axis->axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
return axis->moveFromParamLib();
|
||||||
|
} else if (function == tiltOffsetMove_) {
|
||||||
|
asynStatus status =
|
||||||
|
setDoubleParam(axis->axisNo_, tiltOffset_, value);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return paramLibAccessFailed(status, "tiltOffset_",
|
||||||
|
axis->axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
return axis->moveFromParamLib();
|
||||||
|
} else {
|
||||||
|
return turboPmacController::writeFloat64(pasynUser, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,40 +270,18 @@ If the axis does not exist or is not a Axis, a nullptr is returned and an
|
|||||||
error is emitted.
|
error is emitted.
|
||||||
*/
|
*/
|
||||||
detectorTowerAxis *
|
detectorTowerAxis *
|
||||||
detectorTowerController::getVirtualAxis(asynUser *pasynUser) {
|
detectorTowerController::getDetectorTowerAxis(asynUser *pasynUser) {
|
||||||
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
|
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
|
||||||
return detectorTowerController::castToVirtualAxis(asynAxis);
|
return dynamic_cast<detectorTowerAxis *>(asynAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Access one of the axes of the controller via the axis index.
|
Access one of the axes of the controller via the axis index.
|
||||||
If the axis does not exist or is not a Axis, the function must return Null
|
If the axis does not exist or is not a Axis, the function must return Null
|
||||||
*/
|
*/
|
||||||
detectorTowerAxis *detectorTowerController::getVirtualAxis(int axisNo) {
|
detectorTowerAxis *detectorTowerController::getDetectorTowerAxis(int axisNo) {
|
||||||
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
|
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
|
||||||
return detectorTowerController::castToVirtualAxis(asynAxis);
|
return dynamic_cast<detectorTowerAxis *>(asynAxis);
|
||||||
}
|
|
||||||
|
|
||||||
detectorTowerAxis *
|
|
||||||
detectorTowerController::castToVirtualAxis(asynMotorAxis *asynAxis) {
|
|
||||||
|
|
||||||
// =========================================================================
|
|
||||||
|
|
||||||
// If the axis slot of the pAxes_ array is empty, a nullptr must be returned
|
|
||||||
if (asynAxis == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here, an error is emitted since asyn_axis is not a nullptr but also not
|
|
||||||
// an instance of Axis
|
|
||||||
detectorTowerAxis *axis = dynamic_cast<detectorTowerAxis *>(asynAxis);
|
|
||||||
if (axis == nullptr) {
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
|
||||||
"an instance of turboPmacAxis",
|
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
return axis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************************/
|
/*************************************************************************************/
|
||||||
@ -292,4 +354,4 @@ static void detectorTowerControllerRegister(void) {
|
|||||||
}
|
}
|
||||||
epicsExportRegistrar(detectorTowerControllerRegister);
|
epicsExportRegistrar(detectorTowerControllerRegister);
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
@ -33,20 +33,38 @@ class detectorTowerController : public turboPmacController {
|
|||||||
int numAxes, double movingPollPeriod,
|
int numAxes, double movingPollPeriod,
|
||||||
double idlePollPeriod, double comTimeout);
|
double idlePollPeriod, double comTimeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Overloaded function of turboPmacController
|
||||||
|
*
|
||||||
|
* The function is overloaded in order to read motorCanDisable_
|
||||||
|
*
|
||||||
|
* @param pasynUser
|
||||||
|
* @param value
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||||
|
|
||||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Overloaded function of asynMotorController
|
* @brief Overloaded function of turboPmacController
|
||||||
*
|
*
|
||||||
* The function is overloaded to allow manual starting of an axis movement
|
* The function is overloaded to allow resetting an error.
|
||||||
*
|
*
|
||||||
* @param pasynUser Specify the axis via the asynUser
|
* @param pasynUser Specify the axis via the asynUser
|
||||||
* @param value New value
|
* @param value New value
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Overloaded function of turboPmacController
|
||||||
|
*
|
||||||
|
* The function is overloaded to immediate start of an offset movement
|
||||||
|
*
|
||||||
|
* @param pasynUser Specify the axis via the asynUser
|
||||||
|
* @param value New value
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
@ -55,7 +73,7 @@ class detectorTowerController : public turboPmacController {
|
|||||||
* @return detectorTowerAxis* If no axis could be found, this is a
|
* @return detectorTowerAxis* If no axis could be found, this is a
|
||||||
* nullptr
|
* nullptr
|
||||||
*/
|
*/
|
||||||
detectorTowerAxis *getVirtualAxis(asynUser *pasynUser);
|
detectorTowerAxis *getDetectorTowerAxis(asynUser *pasynUser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
@ -64,29 +82,25 @@ class detectorTowerController : public turboPmacController {
|
|||||||
* @return detectorTowerAxis* If no axis could be found, this is a
|
* @return detectorTowerAxis* If no axis could be found, this is a
|
||||||
* nullptr
|
* nullptr
|
||||||
*/
|
*/
|
||||||
detectorTowerAxis *getVirtualAxis(int axisNo);
|
detectorTowerAxis *getDetectorTowerAxis(int axisNo);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Save cast of the given asynAxis pointer to a detectorTowerAxis
|
|
||||||
* pointer. If the cast fails, this function returns a nullptr.
|
|
||||||
*
|
|
||||||
* @param asynAxis
|
|
||||||
* @return detectorTowerAxis*
|
|
||||||
*/
|
|
||||||
detectorTowerAxis *castToVirtualAxis(asynMotorAxis *asynAxis);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Indices of additional PVs
|
// Indices of additional PVs
|
||||||
#define FIRST_detectorTower_PARAM liftOffset_
|
#define FIRST_detectorTower_PARAM liftOffset_
|
||||||
int liftOffset_;
|
int liftOffset_;
|
||||||
|
int liftOffsetMove_;
|
||||||
int liftOffsetLowLimit_;
|
int liftOffsetLowLimit_;
|
||||||
int liftOffsetHighLimit_;
|
int liftOffsetHighLimit_;
|
||||||
int tiltOffset_;
|
int tiltOffset_;
|
||||||
|
int tiltOffsetMove_;
|
||||||
int tiltOffsetLowLimit_;
|
int tiltOffsetLowLimit_;
|
||||||
int tiltOffsetHighLimit_;
|
int tiltOffsetHighLimit_;
|
||||||
|
int beamAngle_;
|
||||||
int positionState_;
|
int positionState_;
|
||||||
int reset_;
|
int start_;
|
||||||
#define LAST_detectorTower_PARAM reset_
|
int moveToWorkingPosition_;
|
||||||
|
int resetError_;
|
||||||
|
#define LAST_detectorTower_PARAM resetError_
|
||||||
|
|
||||||
friend class detectorTowerAxis;
|
friend class detectorTowerAxis;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user