WIP version with offset RBV (integration from hardware currently
missing)
This commit is contained in:
6
Makefile
6
Makefile
@ -13,16 +13,18 @@ REQUIRED+=motorBase
|
|||||||
motorBase_VERSION=7.2.2
|
motorBase_VERSION=7.2.2
|
||||||
|
|
||||||
# Specify the version of sinqMotor we want to build against
|
# Specify the version of sinqMotor we want to build against
|
||||||
sinqMotor_VERSION=mathis_s
|
sinqMotor_VERSION=0.8.0
|
||||||
|
|
||||||
# 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=0.7.0
|
||||||
|
|
||||||
# These headers allow to depend on this library for derived drivers.
|
# These headers allow to depend on this library for derived drivers.
|
||||||
|
HEADERS += src/offsetAxis.h
|
||||||
HEADERS += src/detectorTowerAxis.h
|
HEADERS += src/detectorTowerAxis.h
|
||||||
HEADERS += src/detectorTowerController.h
|
HEADERS += src/detectorTowerController.h
|
||||||
|
|
||||||
# Source files to build
|
# Source files to build
|
||||||
|
SOURCES += src/offsetAxis.cpp
|
||||||
SOURCES += src/detectorTowerAxis.cpp
|
SOURCES += src/detectorTowerAxis.cpp
|
||||||
SOURCES += src/detectorTowerController.cpp
|
SOURCES += src/detectorTowerController.cpp
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ record(longout, "$(INSTR)$(M):ResetError") {
|
|||||||
field(PINI, "NO")
|
field(PINI, "NO")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Start the movement into the position defined by BeamAngle, LiftOffset and TiltOffset
|
# Start the movement into the position defined by DetectorTower, LiftOffset and TiltOffset
|
||||||
record(longout, "$(INSTR)$(M):MoveToWorkingPosition") {
|
record(longout, "$(INSTR)$(M):MoveToWorkingPosition") {
|
||||||
field(DTYP, "asynInt32")
|
field(DTYP, "asynInt32")
|
||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOVE_TO_WORKING_POSITION")
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOVE_TO_WORKING_POSITION")
|
||||||
@ -24,111 +24,3 @@ record(longout, "$(INSTR)$(M):PositionState")
|
|||||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS)) POSITION_STATE")
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS)) POSITION_STATE")
|
||||||
field(SCAN, "I/O Intr")
|
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")
|
|
||||||
}
|
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Contains all instances of turboPmacAxis which have been created and is used in
|
Contains all instances of detectorTowerAxis which have been created and is used
|
||||||
the initialization hook function.
|
in the initialization hook function.
|
||||||
*/
|
*/
|
||||||
static std::vector<detectorTowerAxis *> axes;
|
static std::vector<detectorTowerAxis *> axes;
|
||||||
|
|
||||||
@ -28,7 +29,24 @@ static void epicsInithookFunction(initHookState iState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
static void deferredMovementCollectorLoop(void *drvPvt) {
|
||||||
|
detectorTowerAxis *axis = (detectorTowerAxis *)drvPvt;
|
||||||
|
while (1) {
|
||||||
|
if (axis->receivedTarget_) {
|
||||||
|
// Wait for 50 ms and then start the movement with the information
|
||||||
|
// available
|
||||||
|
epicsThreadSleep(0.05);
|
||||||
|
axis->startCombinedMove();
|
||||||
|
|
||||||
|
// After the movement command has been send, reset the flag
|
||||||
|
axis->receivedTarget_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo,
|
||||||
|
offsetAxis *liftOffsetAxis,
|
||||||
|
offsetAxis *tiltOffsetAxis)
|
||||||
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
|
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -57,7 +75,12 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
|||||||
// Initialize all member variables
|
// Initialize all member variables
|
||||||
// Assumed to be not ready by default, this is overwritten in the next poll
|
// Assumed to be not ready by default, this is overwritten in the next poll
|
||||||
error_ = 0;
|
error_ = 0;
|
||||||
scheduleMoveFromParamLib_ = false;
|
targetPosition_ = 0.0;
|
||||||
|
receivedTarget_ = false;
|
||||||
|
liftOffsetAxis_ = liftOffsetAxis;
|
||||||
|
tiltOffsetAxis_ = tiltOffsetAxis;
|
||||||
|
liftOffsetAxis->dTA_ = this;
|
||||||
|
tiltOffsetAxis->dTA_ = this;
|
||||||
|
|
||||||
// Register the hook function during construction of the first axis object
|
// Register the hook function during construction of the first axis object
|
||||||
if (axes.empty()) {
|
if (axes.empty()) {
|
||||||
@ -67,6 +90,16 @@ detectorTowerAxis::detectorTowerAxis(detectorTowerController *pC, int axisNo)
|
|||||||
// Collect all axes into this list which will be used in the hook
|
// Collect all axes into this list which will be used in the hook
|
||||||
// function
|
// function
|
||||||
axes.push_back(this);
|
axes.push_back(this);
|
||||||
|
|
||||||
|
// Create a thread which collects all movement commands send to components
|
||||||
|
// of the virtual axis. After a component received a new target position,
|
||||||
|
// it forwards this information to the thread. The thread then waits a short
|
||||||
|
// time to see if other components also received new targets and starts the
|
||||||
|
// movement with all targets afterwards.
|
||||||
|
epicsThreadCreate("deferredMovement", epicsThreadPriorityLow,
|
||||||
|
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||||
|
(EPICSTHREADFUNC)deferredMovementCollectorLoop,
|
||||||
|
(void *)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
detectorTowerAxis::~detectorTowerAxis(void) {
|
detectorTowerAxis::~detectorTowerAxis(void) {
|
||||||
@ -90,7 +123,8 @@ asynStatus detectorTowerAxis::init() {
|
|||||||
if (status == asynParamUndefined) {
|
if (status == asynParamUndefined) {
|
||||||
if (now + maxInitTime < time(NULL)) {
|
if (now + maxInitTime < time(NULL)) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis "
|
||||||
|
"%ddeferredMovementCollectorLoop => %s, line "
|
||||||
"%d\nInitializing the parameter library failed.\n",
|
"%d\nInitializing the parameter library failed.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
@ -105,40 +139,6 @@ asynStatus detectorTowerAxis::init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +167,8 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
double limitsOffset = 0.0;
|
double limitsOffset = 0.0;
|
||||||
double highLimit = 0.0;
|
double highLimit = 0.0;
|
||||||
double lowLimit = 0.0;
|
double lowLimit = 0.0;
|
||||||
|
double detectorHeight = 0.0;
|
||||||
|
double detectorRadius = 0.0;
|
||||||
double liftOffsetHighLimit = 0.0;
|
double liftOffsetHighLimit = 0.0;
|
||||||
double liftOffsetLowLimit = 0.0;
|
double liftOffsetLowLimit = 0.0;
|
||||||
double tiltOffsetHighLimit = 0.0;
|
double tiltOffsetHighLimit = 0.0;
|
||||||
@ -205,7 +207,7 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
- Beam lift offset limits
|
- Beam lift offset limits
|
||||||
- Detector tilt offset limits
|
- Detector tilt offset limits
|
||||||
*/
|
*/
|
||||||
char command[] = "P354 P358 P359 Q510 Q513 Q514 Q353 Q354 Q553 Q554";
|
const char *command = "P354 P358 P359 Q510 Q513 Q514 Q353 Q354 Q553 Q554";
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 10);
|
rw_status = pC_->writeRead(axisNo_, command, response, 10);
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
return rw_status;
|
return rw_status;
|
||||||
@ -688,47 +690,66 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
pl_status =
|
pl_status =
|
||||||
pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver_, lowLimit);
|
pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver_, lowLimit);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_", axisNo_,
|
return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver_",
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->liftOffsetHighLimit_,
|
// Set the values for the offset axes
|
||||||
|
int liftAxisNo = liftOffsetAxis_->axisNo_;
|
||||||
|
double liftOffsetPosition =
|
||||||
|
detectorHeight + detectorRadius * sin(beamTiltAngle);
|
||||||
|
|
||||||
|
pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorPosition_,
|
||||||
|
liftOffsetPosition / motorRecResolution);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
|
||||||
|
liftAxisNo, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorHighLimitFromDriver_,
|
||||||
liftOffsetHighLimit);
|
liftOffsetHighLimit);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "liftOffsetHighLimit_",
|
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
liftAxisNo, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
pl_status = pC_->setDoubleParam(liftAxisNo, pC_->motorLowLimitFromDriver_,
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->liftOffsetLowLimit_,
|
|
||||||
liftOffsetLowLimit);
|
liftOffsetLowLimit);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "liftOffsetLowLimit_",
|
return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
liftAxisNo, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->tiltOffsetHighLimit_,
|
int tiltAxisNo = tiltOffsetAxis_->axisNo_;
|
||||||
|
pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorPosition_,
|
||||||
|
tiltOffsetAxis_->targetPosition_ /
|
||||||
|
motorRecResolution);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
|
||||||
|
liftAxisNo, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorHighLimitFromDriver_,
|
||||||
tiltOffsetHighLimit);
|
tiltOffsetHighLimit);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "tiltOffsetHighLimit_",
|
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
tiltAxisNo, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
pl_status = pC_->setDoubleParam(tiltAxisNo, pC_->motorLowLimitFromDriver_,
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->tiltOffsetLowLimit_,
|
|
||||||
tiltOffsetLowLimit);
|
tiltOffsetLowLimit);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "tiltOffsetLowLimit_",
|
return pC_->paramLibAccessFailed(pl_status, "motorLowLimitFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
tiltAxisNo, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform from motor to EPICS coordinates (see comment in
|
// Transform from motor to EPICS coordinates (see comment in
|
||||||
// turboPmacAxis::init())
|
// turboPmacAxis::init())
|
||||||
beamTiltAngle = beamTiltAngle / motorRecResolution;
|
pl_status =
|
||||||
|
setDoubleParam(pC_->motorPosition_, beamTiltAngle / motorRecResolution);
|
||||||
pl_status = setDoubleParam(pC_->motorPosition_, beamTiltAngle);
|
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
|
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -740,53 +761,30 @@ asynStatus detectorTowerAxis::doPoll(bool *moving) {
|
|||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a movement is scheduled and the axis is not moving anymore, start the
|
|
||||||
// scheduled movement. This replaces the original motor record movement
|
|
||||||
// control loop functionality.
|
|
||||||
if (scheduleMoveFromParamLib_ && !(*moving) && poll_status == asynSuccess) {
|
|
||||||
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 poll_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveFromParamLib();
|
asynStatus detectorTowerAxis::doMove(double position, int relative,
|
||||||
} else {
|
|
||||||
return poll_status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
asynStatus detectorTowerAxis::move(double position, int relative,
|
|
||||||
double min_velocity, double max_velocity,
|
double min_velocity, double max_velocity,
|
||||||
double acceleration) {
|
double acceleration) {
|
||||||
|
double motorRecResolution = 0.0;
|
||||||
// Status of parameter library operations
|
asynStatus pl_status = pC_->getDoubleParam(
|
||||||
asynStatus pl_status = asynSuccess;
|
axisNo_, pC_->motorRecResolution_, &motorRecResolution);
|
||||||
|
|
||||||
// Set the position as beam angle
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->beamAngle_, position);
|
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "beamAngle_", axisNo_,
|
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveFromParamLib();
|
// Signal to the deferredMovementCollectorLoop that a movement should be
|
||||||
|
// started to the defined target position.
|
||||||
|
targetPosition_ = position * motorRecResolution;
|
||||||
|
receivedTarget_ = true;
|
||||||
|
|
||||||
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus detectorTowerAxis::moveFromParamLib() {
|
asynStatus detectorTowerAxis::startCombinedMove() {
|
||||||
|
|
||||||
// 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;
|
||||||
@ -796,15 +794,23 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
|
|
||||||
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
||||||
double motorCoordinatesPosition = 0.0;
|
double motorCoordinatesPosition = 0.0;
|
||||||
double motorRecResolution = 0.0;
|
|
||||||
double beamAngle = 0.0;
|
|
||||||
double liftOffset = 0.0;
|
|
||||||
double tiltOffset = 0.0;
|
|
||||||
int writeOffset = 0;
|
|
||||||
int positionState = 0;
|
int positionState = 0;
|
||||||
|
int moving = 0;
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusMoving_, &moving);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the axis is already moving. In this case, do nothing
|
||||||
|
if (moving) {
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
pC_->getIntegerParam(axisNo_, pC_->positionState_, &positionState);
|
pC_->getIntegerParam(axisNo_, pC_->positionState_, &positionState);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
@ -830,38 +836,24 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the target values from the parameter library
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->beamAngle_, &beamAngle);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "beamAngle_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->liftOffset_, &liftOffset);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "liftOffset_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->tiltOffset_, &tiltOffset);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "tiltOffset_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
|
||||||
&motorRecResolution);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, sizeof(command), "Q451=%lf Q454=%lf Q456=%lf P350=1",
|
||||||
"Q451=%lf Q454=%lf Q456=%lf P350=1", beamAngle, liftOffset,
|
targetPosition_, liftOffsetAxis_->targetPosition_,
|
||||||
tiltOffset);
|
tiltOffsetAxis_->targetPosition_);
|
||||||
|
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s\n", command);
|
||||||
|
|
||||||
|
// 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
|
// We don't expect an answer
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
|
|
||||||
|
// Free the controller again
|
||||||
|
pC_->unlock();
|
||||||
|
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
@ -877,9 +869,6 @@ asynStatus detectorTowerAxis::moveFromParamLib() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start polling immediately
|
|
||||||
pC_->wakeupPoller();
|
|
||||||
|
|
||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,7 +908,6 @@ asynStatus detectorTowerAxis::stop(double acceleration) {
|
|||||||
// The detector tower 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);
|
||||||
|
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "encoderType_", axisNo_,
|
return pC_->paramLibAccessFailed(status, "encoderType_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -1056,7 +1044,8 @@ extern "C" {
|
|||||||
C wrapper for the axis constructor. Please refer to the detectorTower
|
C wrapper for the axis constructor. Please refer to the detectorTower
|
||||||
constructor documentation. The controller is read from the portName.
|
constructor documentation. The controller is read from the portName.
|
||||||
*/
|
*/
|
||||||
asynStatus detectorTowerCreateAxis(const char *portName, int axis) {
|
asynStatus detectorTowerCreateAxis(const char *portName, int axisDetectorTower,
|
||||||
|
int liftOffsetaxisNo, int tiltOffsetaxisNo) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
|
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
|
||||||
@ -1074,8 +1063,7 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axis) {
|
|||||||
/*
|
/*
|
||||||
We can't use asynPrint here since this macro would require us
|
We can't use asynPrint here since this macro would require us
|
||||||
to get a lowLevelPortUser_ from a pointer to an asynPortDriver.
|
to get a lowLevelPortUser_ from a pointer to an asynPortDriver.
|
||||||
However, the given pointer is a nullptr and therefore doesn't
|
However, the given pointer is a nullptr and therefore doesn'taxis
|
||||||
have a lowLevelPortUser_! printf is an EPICS alternative which
|
|
||||||
works w/o that, but doesn't offer the comfort provided
|
works w/o that, but doesn't offer the comfort provided
|
||||||
by the asynTrace-facility
|
by the asynTrace-facility
|
||||||
*/
|
*/
|
||||||
@ -1095,6 +1083,16 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axis) {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assert that the three indices are different from each other
|
||||||
|
if (axisDetectorTower == liftOffsetaxisNo ||
|
||||||
|
axisDetectorTower == tiltOffsetaxisNo ||
|
||||||
|
tiltOffsetaxisNo == liftOffsetaxisNo) {
|
||||||
|
errlogPrintf("Controller \"%s\" => %s, line %d\nAll three axis indices "
|
||||||
|
"must be unique.",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent manipulation of the controller from other threads while we
|
// Prevent manipulation of the controller from other threads while we
|
||||||
// create the new axis.
|
// create the new axis.
|
||||||
pC->lock();
|
pC->lock();
|
||||||
@ -1108,9 +1106,14 @@ asynStatus detectorTowerCreateAxis(const char *portName, int axis) {
|
|||||||
The created object is registered in EPICS in its constructor and can safely
|
The created object is registered in EPICS in its constructor and can safely
|
||||||
be "leaked" here.
|
be "leaked" here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
offsetAxis *liftOffsetAxis = new offsetAxis(pC, liftOffsetaxisNo);
|
||||||
|
offsetAxis *tiltOffsetAxis = new offsetAxis(pC, tiltOffsetaxisNo);
|
||||||
|
|
||||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
detectorTowerAxis *pAxis = new detectorTowerAxis(pC, axis);
|
detectorTowerAxis *pAxis = new detectorTowerAxis(
|
||||||
|
pC, axisDetectorTower, liftOffsetAxis, tiltOffsetAxis);
|
||||||
|
|
||||||
// Allow manipulation of the controller again
|
// Allow manipulation of the controller again
|
||||||
pC->unlock();
|
pC->unlock();
|
||||||
@ -1123,13 +1126,23 @@ itself.
|
|||||||
*/
|
*/
|
||||||
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
|
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
|
||||||
iocshArgString};
|
iocshArgString};
|
||||||
static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt};
|
static const iocshArg CreateAxisArg1 = {"Number of the detector angle axis",
|
||||||
static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
|
iocshArgInt};
|
||||||
&CreateAxisArg1};
|
static const iocshArg CreateAxisArg2 = {"Number of the lift offset axis",
|
||||||
|
iocshArgInt};
|
||||||
|
static const iocshArg CreateAxisArg3 = {"Number of the tilt offset axis",
|
||||||
|
iocshArgInt};
|
||||||
|
static const iocshArg *const CreateAxisArgs[] = {
|
||||||
|
&CreateAxisArg0,
|
||||||
|
&CreateAxisArg1,
|
||||||
|
&CreateAxisArg2,
|
||||||
|
&CreateAxisArg3,
|
||||||
|
};
|
||||||
static const iocshFuncDef configDetectorTowerCreateAxis = {"detectorTowerAxis",
|
static const iocshFuncDef configDetectorTowerCreateAxis = {"detectorTowerAxis",
|
||||||
2, CreateAxisArgs};
|
4, CreateAxisArgs};
|
||||||
static void configDetectorTowerCreateAxisCallFunc(const iocshArgBuf *args) {
|
static void configDetectorTowerCreateAxisCallFunc(const iocshArgBuf *args) {
|
||||||
detectorTowerCreateAxis(args[0].sval, args[1].ival);
|
detectorTowerCreateAxis(args[0].sval, args[1].ival, args[2].ival,
|
||||||
|
args[3].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is made known to EPICS in detectorTower.dbd and is called by
|
// This function is made known to EPICS in detectorTower.dbd and is called by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef detectorTowerAxis_H
|
#ifndef detectorTowerAxis_H
|
||||||
#define detectorTowerAxis_H
|
#define detectorTowerAxis_H
|
||||||
|
#include "offsetAxis.h"
|
||||||
#include "turboPmacAxis.h"
|
#include "turboPmacAxis.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
|
||||||
@ -16,7 +16,8 @@ class detectorTowerAxis : public turboPmacAxis {
|
|||||||
* @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
|
||||||
*/
|
*/
|
||||||
detectorTowerAxis(detectorTowerController *pController, int axisNo);
|
detectorTowerAxis(detectorTowerController *pController, int axisNo,
|
||||||
|
offsetAxis *liftOffsetAxis, offsetAxis *tiltOffsetAxis);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Destroy the turboPmacAxis
|
* @brief Destroy the turboPmacAxis
|
||||||
@ -50,16 +51,10 @@ class detectorTowerAxis : public turboPmacAxis {
|
|||||||
asynStatus doPoll(bool *moving);
|
asynStatus doPoll(bool *moving);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Empty dummy for the move method which is called by the EPICS
|
* @brief Set the target value for the detector angle without starting a
|
||||||
* movement control loop
|
* movement
|
||||||
*
|
*
|
||||||
* For the detector tower, we want to start movements manually without
|
* TODO
|
||||||
* using the EPICS control loop. Therefore, we call the `move` function of
|
|
||||||
* sinqMotor directly whenever a new value is written to the PV
|
|
||||||
* $(INSTR)$(M):TargetPosition". The reason is that we want to start a
|
|
||||||
* movement even if the VAL field of the motor record equals its RBV field
|
|
||||||
* because either the lift offset or the detector tilt offset might have
|
|
||||||
* changed.
|
|
||||||
*
|
*
|
||||||
* @param position
|
* @param position
|
||||||
* @param relative
|
* @param relative
|
||||||
@ -68,20 +63,19 @@ class detectorTowerAxis : public turboPmacAxis {
|
|||||||
* @param acceleration
|
* @param acceleration
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus doMove(double position, int relative, double min_velocity,
|
||||||
double max_velocity, double acceleration);
|
double max_velocity, double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start a movement based on the parameter library values for
|
* @brief Start a movement to the target positions of this axis and the
|
||||||
* motorTargetPosition_, liftOffset_ and tiltOffset_
|
* attached offset axes.
|
||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus moveFromParamLib();
|
asynStatus startCombinedMove();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the encoder type (incremental or absolute) for this axis from
|
* @brief This axis type has an absolute encoder by default
|
||||||
* the MCU and store the information in the PV ENCODER_TYPE.
|
|
||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
@ -103,14 +97,20 @@ class detectorTowerAxis : public turboPmacAxis {
|
|||||||
*/
|
*/
|
||||||
asynStatus reset();
|
asynStatus reset();
|
||||||
|
|
||||||
|
// If true, either this axis or one of the offsetAxis attached to it
|
||||||
|
// received a movement command.
|
||||||
|
bool receivedTarget_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
detectorTowerController *pC_;
|
detectorTowerController *pC_;
|
||||||
|
double targetPosition_;
|
||||||
bool scheduleMoveFromParamLib_;
|
|
||||||
int error_;
|
int error_;
|
||||||
|
offsetAxis *tiltOffsetAxis_;
|
||||||
|
offsetAxis *liftOffsetAxis_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class detectorTowerController;
|
friend class detectorTowerController;
|
||||||
|
friend class offsetAxis;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,105 +27,6 @@ detectorTowerController::detectorTowerController(
|
|||||||
|
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// =========================================================================
|
|
||||||
// Create additional parameter library entries
|
|
||||||
|
|
||||||
status = createParam("LIFT_OFFSET", asynParamFloat64, &liftOffset_);
|
|
||||||
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_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,
|
|
||||||
&liftOffsetLowLimit_);
|
|
||||||
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_HIGH_LIMIT", asynParamFloat64,
|
|
||||||
&liftOffsetHighLimit_);
|
|
||||||
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", asynParamFloat64, &tiltOffset_);
|
|
||||||
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_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,
|
|
||||||
&tiltOffsetLowLimit_);
|
|
||||||
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_HIGH_LIMIT", asynParamFloat64,
|
|
||||||
&tiltOffsetHighLimit_);
|
|
||||||
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("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,
|
||||||
@ -136,16 +37,6 @@ detectorTowerController::detectorTowerController(
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
status = createParam("MOVE_TO_WORKING_POSITION", asynParamInt32,
|
||||||
&moveToWorkingPosition_);
|
&moveToWorkingPosition_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -174,7 +65,7 @@ asynStatus detectorTowerController::readInt32(asynUser *pasynUser,
|
|||||||
// Check if the axis is a detectorTowerAxis
|
// Check if the axis is a detectorTowerAxis
|
||||||
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
// This is apparently a "normal" turboPmacAxis
|
// This is apparently a "normal" turboPmacAxis or an offsetAxis
|
||||||
return turboPmacController::readInt32(pasynUser, value);
|
return turboPmacController::readInt32(pasynUser, value);
|
||||||
} else {
|
} else {
|
||||||
// The detector tower cannot be disabled
|
// The detector tower cannot be disabled
|
||||||
@ -196,31 +87,10 @@ asynStatus detectorTowerController::writeInt32(asynUser *pasynUser,
|
|||||||
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
||||||
|
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
// This is apparently a "normal" turboPmacAxis
|
// This is apparently a "normal" turboPmacAxis or an offsetAxis
|
||||||
return turboPmacController::writeInt32(pasynUser, value);
|
return turboPmacController::writeInt32(pasynUser, value);
|
||||||
} else {
|
} else {
|
||||||
// Handle custom PVs
|
if (function == moveToWorkingPosition_) {
|
||||||
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);
|
return axis->moveToWorkingPosition(value != 0);
|
||||||
} else if (function == resetError_) {
|
} else if (function == resetError_) {
|
||||||
return axis->reset();
|
return axis->reset();
|
||||||
@ -230,40 +100,6 @@ asynStatus detectorTowerController::writeInt32(asynUser *pasynUser,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus detectorTowerController::writeFloat64(asynUser *pasynUser,
|
|
||||||
epicsFloat64 value) {
|
|
||||||
int function = pasynUser->reason;
|
|
||||||
|
|
||||||
detectorTowerAxis *axis = getDetectorTowerAxis(pasynUser);
|
|
||||||
|
|
||||||
if (axis == nullptr) {
|
|
||||||
// This is apparently a "normal" turboPmacAxis
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Access one of the axes of the controller via the axis adress stored in asynUser.
|
Access one of the axes of the controller via the axis adress stored in asynUser.
|
||||||
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#ifndef detectorTowerController_H
|
#ifndef detectorTowerController_H
|
||||||
#define detectorTowerController_H
|
#define detectorTowerController_H
|
||||||
#include "detectorTowerAxis.h"
|
#include "detectorTowerAxis.h"
|
||||||
|
#include "offsetAxis.h"
|
||||||
#include "turboPmacController.h"
|
#include "turboPmacController.h"
|
||||||
|
|
||||||
class detectorTowerController : public turboPmacController {
|
class detectorTowerController : public turboPmacController {
|
||||||
@ -55,17 +56,6 @@ class detectorTowerController : public turboPmacController {
|
|||||||
*/
|
*/
|
||||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 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
|
||||||
*
|
*
|
||||||
@ -86,23 +76,14 @@ class detectorTowerController : public turboPmacController {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Indices of additional PVs
|
// Indices of additional PVs
|
||||||
#define FIRST_detectorTower_PARAM liftOffset_
|
#define FIRST_detectorTower_PARAM positionState_
|
||||||
int liftOffset_;
|
|
||||||
int liftOffsetMove_;
|
|
||||||
int liftOffsetLowLimit_;
|
|
||||||
int liftOffsetHighLimit_;
|
|
||||||
int tiltOffset_;
|
|
||||||
int tiltOffsetMove_;
|
|
||||||
int tiltOffsetLowLimit_;
|
|
||||||
int tiltOffsetHighLimit_;
|
|
||||||
int beamAngle_;
|
|
||||||
int positionState_;
|
int positionState_;
|
||||||
int start_;
|
|
||||||
int moveToWorkingPosition_;
|
int moveToWorkingPosition_;
|
||||||
int resetError_;
|
int resetError_;
|
||||||
#define LAST_detectorTower_PARAM resetError_
|
#define LAST_detectorTower_PARAM resetError_
|
||||||
|
|
||||||
friend class detectorTowerAxis;
|
friend class detectorTowerAxis;
|
||||||
|
friend class offsetAxis;
|
||||||
};
|
};
|
||||||
#define NUM_detectorTower_DRIVER_PARAMS \
|
#define NUM_detectorTower_DRIVER_PARAMS \
|
||||||
(&LAST_detectorTower_PARAM - &FIRST_detectorTower_PARAM + 1)
|
(&LAST_detectorTower_PARAM - &FIRST_detectorTower_PARAM + 1)
|
||||||
|
224
src/offsetAxis.cpp
Normal file
224
src/offsetAxis.cpp
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#include "offsetAxis.h"
|
||||||
|
#include "detectorTowerAxis.h"
|
||||||
|
#include "detectorTowerController.h"
|
||||||
|
#include "turboPmacController.h"
|
||||||
|
#include <epicsExport.h>
|
||||||
|
#include <errlog.h>
|
||||||
|
#include <iocsh.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Contains all instances of offsetAxis which have been created and is used
|
||||||
|
in the initialization hook function.
|
||||||
|
*/
|
||||||
|
static std::vector<offsetAxis *> axes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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<offsetAxis *>::iterator itA = axes.begin();
|
||||||
|
itA != axes.end(); ++itA) {
|
||||||
|
offsetAxis *axis = *itA;
|
||||||
|
axis->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetAxis::offsetAxis(detectorTowerController *pC, int axisNo)
|
||||||
|
: turboPmacAxis(pC, axisNo, false), pC_(pC) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
The superclass constructor sinqAxis calls in turn its superclass constructor
|
||||||
|
asynMotorAxis. In the latter, a pointer to the constructed object this is
|
||||||
|
stored inside the array pAxes_:
|
||||||
|
|
||||||
|
pC->pAxes_[axisNo] = this;
|
||||||
|
|
||||||
|
Therefore, the axes are managed by the controller pC. If axisNo is out of
|
||||||
|
bounds, asynMotorAxis prints an error (see
|
||||||
|
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp,
|
||||||
|
line 40). However, we want the IOC creation to stop completely, since this
|
||||||
|
is a configuration error.
|
||||||
|
*/
|
||||||
|
if (axisNo >= pC->numAxes_) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d: FATAL ERROR: "
|
||||||
|
"Axis index %d must be smaller than the total number of axes "
|
||||||
|
"%d",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
axisNo_, pC->numAxes_);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize all member variables
|
||||||
|
// Assumed to be not ready by default, this is overwritten in the next poll
|
||||||
|
targetPosition_ = 0.0;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetAxis::~offsetAxis(void) {
|
||||||
|
// Since the controller memory is managed somewhere else, we don't need to
|
||||||
|
// clean up the pointer pC here.
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus offsetAxis::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__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the actual poll
|
||||||
|
asynStatus offsetAxis::doPoll(bool *moving) {
|
||||||
|
|
||||||
|
// Return value for the poll
|
||||||
|
asynStatus poll_status = asynSuccess;
|
||||||
|
|
||||||
|
// Status of parameter library operations
|
||||||
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
|
int isMoving = 0;
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
The axis is moving if the detectorTowerAxis is moving -> We read the moving
|
||||||
|
status from the detectorTowerAxis.
|
||||||
|
*/
|
||||||
|
pl_status =
|
||||||
|
pC_->getIntegerParam(dTA_->axisNo_, pC_->motorStatusMoving_, &isMoving);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
|
||||||
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
|
}
|
||||||
|
*moving = isMoving != 0;
|
||||||
|
|
||||||
|
// Update the parameter library
|
||||||
|
if (dTA_->error_ != 0) {
|
||||||
|
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*moving == false) {
|
||||||
|
pl_status = setIntegerParam(pC_->motorMoveToHome_, 0);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorMoveToHome_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pl_status = setIntegerParam(pC_->motorStatusMoving_, *moving);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
pl_status = setIntegerParam(pC_->motorStatusDone_, !(*moving));
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_,
|
||||||
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The limits are written into this class instance inside the doPoll
|
||||||
|
// function of detectorTowerAxis
|
||||||
|
return poll_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus offsetAxis::doMove(double position, int relative,
|
||||||
|
double min_velocity, double max_velocity,
|
||||||
|
double acceleration) {
|
||||||
|
|
||||||
|
double motorRecResolution = 0.0;
|
||||||
|
asynStatus pl_status = pC_->getDoubleParam(
|
||||||
|
axisNo_, pC_->motorRecResolution_, &motorRecResolution);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal to the deferredMovementCollectorLoop (of the detectorTowerAxis)
|
||||||
|
// that a movement should be started to the defined target position.
|
||||||
|
targetPosition_ = position * motorRecResolution;
|
||||||
|
dTA_->receivedTarget_ = true;
|
||||||
|
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus offsetAxis::stop(double acceleration) {
|
||||||
|
|
||||||
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
|
asynStatus rw_status = asynSuccess;
|
||||||
|
|
||||||
|
// Status of parameter library operations
|
||||||
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
|
char response[pC_->MAXBUF_];
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
rw_status = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||||
|
|
||||||
|
if (rw_status != asynSuccess) {
|
||||||
|
asynPrint(
|
||||||
|
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||||
|
"failed.\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
|
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
if (pl_status != asynSuccess) {
|
||||||
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||||
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
|
}
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rw_status;
|
||||||
|
}
|
78
src/offsetAxis.h
Normal file
78
src/offsetAxis.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef offsetAxis_H
|
||||||
|
#define offsetAxis_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 detectorTowerAxis;
|
||||||
|
|
||||||
|
class offsetAxis : public turboPmacAxis {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new detectorTowerAxis
|
||||||
|
*
|
||||||
|
* @param pController Pointer to the associated controller
|
||||||
|
* @param axisNo Index of the axis
|
||||||
|
*/
|
||||||
|
offsetAxis(detectorTowerController *pController, int axisNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the turboPmacAxis
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual ~offsetAxis();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Readout of some values from the controller at IOC startup
|
||||||
|
*
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implementation of the `stop` function from asynMotorAxis
|
||||||
|
*
|
||||||
|
* @param acceleration Acceleration ACCEL from the motor record. This
|
||||||
|
* value is currently not used.
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus stop(double acceleration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implementation of the `doPoll` function from sinqAxis. The
|
||||||
|
* parameters are described in the documentation of `sinqAxis::doPoll`.
|
||||||
|
*
|
||||||
|
* @param moving
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus doPoll(bool *moving);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the target value for the detector angle without starting a
|
||||||
|
* movement
|
||||||
|
*
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @param position
|
||||||
|
* @param relative
|
||||||
|
* @param min_velocity
|
||||||
|
* @param max_velocity
|
||||||
|
* @param acceleration
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus doMove(double position, int relative, double min_velocity,
|
||||||
|
double max_velocity, double acceleration);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
detectorTowerController *pC_;
|
||||||
|
detectorTowerAxis *dTA_;
|
||||||
|
double targetPosition_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class detectorTowerController;
|
||||||
|
friend class detectorTowerAxis;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user