Changed dependencies to static linking.
This commit is contained in:
693
src/detectorTowerAngleAxis.cpp
Normal file
693
src/detectorTowerAngleAxis.cpp
Normal file
@@ -0,0 +1,693 @@
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
/*
|
||||
Contains all instances of detectorTowerAngleAxis which have been created and is
|
||||
used in the initialization hook function.
|
||||
*/
|
||||
static std::vector<detectorTowerAngleAxis *> 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<detectorTowerAngleAxis *>::iterator itA = axes.begin();
|
||||
itA != axes.end(); ++itA) {
|
||||
detectorTowerAngleAxis *axis = *itA;
|
||||
axis->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deferredMovementCollectorLoop(void *drvPvt) {
|
||||
detectorTowerAngleAxis *axis = (detectorTowerAngleAxis *)drvPvt;
|
||||
while (1) {
|
||||
if (axis->receivedTarget_) {
|
||||
// Wait for 100 ms and then start the movement with the information
|
||||
// available
|
||||
axis->startingDeferredMovement_ = true;
|
||||
epicsThreadSleep(axis->deferredMovementWait_);
|
||||
axis->startCombinedMove();
|
||||
|
||||
// After the movement command has been send, reset the flag
|
||||
axis->receivedTarget_ = false;
|
||||
}
|
||||
// Limit this loop to an idle frequency of 1 kHz
|
||||
epicsThreadSleep(0.001);
|
||||
}
|
||||
}
|
||||
|
||||
detectorTowerAngleAxis::detectorTowerAngleAxis(detectorTowerController *pC,
|
||||
int axisNo,
|
||||
detectorTowerLiftAxis *liftAxis)
|
||||
: 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_->pasynUser(), 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
|
||||
error_ = 0;
|
||||
receivedTarget_ = false;
|
||||
startingDeferredMovement_ = false;
|
||||
deferredMovementWait_ = 0.1; // seconds
|
||||
liftAxis_ = liftAxis;
|
||||
liftAxis_->angleAxis_ = this;
|
||||
|
||||
// Will be populated in the init() method
|
||||
beamRadius_ = 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
detectorTowerAngleAxis::~detectorTowerAngleAxis(void) {
|
||||
// Since the controller memory is managed somewhere else, we don't need to
|
||||
// clean up the pointer pC here.
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::init() {
|
||||
|
||||
// Local variable declaration
|
||||
asynStatus status = asynSuccess;
|
||||
double motorRecResolution = 0.0;
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
int nvals = 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_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis "
|
||||
"%ddeferredMovementCollectorLoop => %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__);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the detector radius
|
||||
const char *command = "P459";
|
||||
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
nvals = sscanf(response, "%lf", &beamRadius_);
|
||||
if (nvals != 1) {
|
||||
return pC_->couldNotParseResponse(command, response, axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// Initialize the motorStatusMoving flag
|
||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Perform the actual poll
|
||||
asynStatus detectorTowerAngleAxis::poll(bool *moving) {
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
// Is this axis the one with the smallest index?
|
||||
// If not, just read out the movement status and update *moving
|
||||
if (axisNo() < liftAxis_->axisNo()) {
|
||||
status = pC_->pollDetectorAxes(moving, this, liftAxis_);
|
||||
} else {
|
||||
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
|
||||
(int *)moving);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
wasMoving_ = *moving;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::doPoll(bool *moving) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nThe doPoll method "
|
||||
"of this axis type should not be reachable. This is a bug.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::doMove(double position, int relative,
|
||||
double min_velocity,
|
||||
double max_velocity,
|
||||
double acceleration) {
|
||||
double motorRecResolution = 0.0;
|
||||
asynStatus plStatus = pC_->getDoubleParam(
|
||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorRecResolution_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
// Signal to the deferredMovementCollectorLoop that a movement should be
|
||||
// started to the defined target position.
|
||||
targetPosition_ = position * motorRecResolution;
|
||||
receivedTarget_ = true;
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::startCombinedMove() {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
double motorCoordinatesPosition = 0.0;
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
bool isInChangerPos = positionState == 2 || positionState == 3;
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
isInChangerPos, pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
||||
"moved because it is moving from working to changer "
|
||||
"position, is in changer position or is moving from changer "
|
||||
"to working position.%s\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
if (isInChangerPos) {
|
||||
startingDeferredMovement_ = false;
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Set the target positions for beam tilt, detector tilt offset and lift
|
||||
// offset
|
||||
snprintf(command, sizeof(command), "Q451=%lf Q454=%lf P350=1",
|
||||
targetPosition_, liftAxis_->targetPosition_);
|
||||
|
||||
// Lock the access to the controller since this function runs in another
|
||||
// thread than the poll method.
|
||||
pC_->lock();
|
||||
|
||||
// We don't expect an answer
|
||||
rwStatus = pC_->writeRead(axisNo_, command, response, 0);
|
||||
|
||||
// Free the controller again
|
||||
pC_->unlock();
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to "
|
||||
"target position %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
motorCoordinatesPosition);
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::stop(double acceleration) {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||
"failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
}
|
||||
|
||||
// The detector tower axis uses absolute encoders
|
||||
asynStatus detectorTowerAngleAxis::readEncoderType() {
|
||||
asynStatus status = setStringParam(pC_->encoderType(), AbsoluteEncoder);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "encoderType_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus
|
||||
detectorTowerAngleAxis::toggleWorkingChangerState(bool toChangingPosition) {
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
|
||||
bool moving = false;
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = poll(&moving);
|
||||
if (rwStatus != asynSuccess) {
|
||||
return rwStatus;
|
||||
}
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
if (moving) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
||||
"idle and can therefore not be moved to %s state.%s\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
toChangingPosition ? "changer" : "working",
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
|
||||
plStatus = setStringParam(
|
||||
pC_->motorMessageText(),
|
||||
"Axis cannot be moved to changer position while it is moving.");
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorMessageText_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), !toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Axis is already in the correct position
|
||||
bool isAlreadyThere = (toChangingPosition == false && positionState == 1) ||
|
||||
(toChangingPosition == true && positionState == 2);
|
||||
|
||||
if (isAlreadyThere) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is already "
|
||||
"in %s position.%s\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
toChangingPosition ? "changer" : "working",
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
|
||||
// Update the PV anyway, even though nothing changed.
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
// Move the axis into changer or working position
|
||||
if (toChangingPosition) {
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=2", response, 0);
|
||||
plStatus = setStringParam(pC_->motorMessageText(),
|
||||
"Moving to changer position ...");
|
||||
} else {
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=3", response, 0);
|
||||
plStatus = setStringParam(pC_->motorMessageText(),
|
||||
"Moving to working state ...");
|
||||
}
|
||||
if (plStatus != asynSuccess) {
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), !toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorMessageText_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
plStatus = setIntegerParam(pC_->changeStateRBV(), toChangingPosition);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "changeStateRBV", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::doReset() {
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
asynStatus plStatus = asynSuccess;
|
||||
int positionState = 0;
|
||||
|
||||
plStatus =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
/*
|
||||
Check which action should be performed:
|
||||
- If error_ == 10 or 11 (FTZ motor error): P352 = 3 (Recover FTZ)
|
||||
- If any other error: P352 = 2 (Reset error)
|
||||
- Otherwise: P352 = 1 (Set axis in closed-loop mode)
|
||||
*/
|
||||
if (error_ == 10 || error_ == 11) {
|
||||
return pC_->writeRead(axisNo_, "P352=3", response, 0);
|
||||
} else if (error_ != 0) {
|
||||
return pC_->writeRead(axisNo_, "P352=2", response, 0);
|
||||
} else {
|
||||
return pC_->writeRead(axisNo_, "P352=1", response, 0);
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAngleAxis::adjustOrigin(double newOrigin) {
|
||||
|
||||
asynStatus status = asynSuccess;
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
bool isInChangerPos = positionState == 2 || positionState == 3;
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
isInChangerPos, pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
||||
"moved because it is moving from working to changer "
|
||||
"position, is in changer position or is moving from changer "
|
||||
"to working position.%s\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
|
||||
// Set the new origin for the angle axis
|
||||
snprintf(command, sizeof(command), "Q556=%lf P350=4", newOrigin);
|
||||
|
||||
// We don't expect an answer
|
||||
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nSetting new "
|
||||
"angle origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************/
|
||||
/** The following functions are C-wrappers, and can be called directly from
|
||||
* iocsh */
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
C wrapper for the axis constructor. Please refer to the detectorTower
|
||||
constructor documentation. The controller is read from the portName.
|
||||
*/
|
||||
asynStatus detectorTowerCreateAxis(const char *portName, int angleAxisIdx,
|
||||
int liftAxisIdx) {
|
||||
|
||||
/*
|
||||
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
|
||||
Therefore it returns a void pointer instead of e.g. a pointer to a
|
||||
superclass of the controller such as asynPortDriver. Type-safe upcasting
|
||||
via dynamic_cast is therefore not possible directly. However, we do know
|
||||
that the void pointer is either a pointer to asynPortDriver (if a driver
|
||||
with the specified name exists) or a nullptr. Therefore, we first do a
|
||||
nullptr check, then a cast to asynPortDriver and lastly a (typesafe)
|
||||
dynamic_upcast to Controller
|
||||
https://stackoverflow.com/questions/70906749/is-there-a-safe-way-to-cast-void-to-class-pointer-in-c
|
||||
*/
|
||||
void *ptr = findAsynPortDriver(portName);
|
||||
if (ptr == nullptr) {
|
||||
/*
|
||||
We can't use asynPrint here since this macro would require us
|
||||
to get a lowLevelPortUser_ from a pointer to an asynPortDriver.
|
||||
However, the given pointer is a nullptr and therefore doesn'taxis
|
||||
works w/o that, but doesn't offer the comfort provided
|
||||
by the asynTrace-facility
|
||||
*/
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d\nPort not found.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
// Unsafe cast of the pointer to an asynPortDriver
|
||||
asynPortDriver *apd = (asynPortDriver *)(ptr);
|
||||
|
||||
// Safe downcast
|
||||
detectorTowerController *pC = dynamic_cast<detectorTowerController *>(apd);
|
||||
if (pC == nullptr) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d\nController "
|
||||
"is not a detectorTowerController.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Assert that the three indices are different from each other
|
||||
if (angleAxisIdx == liftAxisIdx) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d\nAll axis indices "
|
||||
"must be unique.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Prevent manipulation of the controller from other threads while we
|
||||
// create the new axis.
|
||||
pC->lock();
|
||||
|
||||
/*
|
||||
We create a new instance of the axis, using the "new" keyword to
|
||||
allocate it on the heap while avoiding RAII.
|
||||
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorController.cpp
|
||||
https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/asynPortDriver.cpp
|
||||
|
||||
The created object is registered in EPICS in its constructor and can safely
|
||||
be "leaked" here.
|
||||
*/
|
||||
|
||||
detectorTowerLiftAxis *liftAxis =
|
||||
new detectorTowerLiftAxis(pC, liftAxisIdx);
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
detectorTowerAngleAxis *pAxis =
|
||||
new detectorTowerAngleAxis(pC, angleAxisIdx, liftAxis);
|
||||
|
||||
// Allow manipulation of the controller again
|
||||
pC->unlock();
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
|
||||
iocshArgString};
|
||||
static const iocshArg CreateAxisArg1 = {"Number of the detector angle axis",
|
||||
iocshArgInt};
|
||||
static const iocshArg CreateAxisArg2 = {"Number of the lift axis", iocshArgInt};
|
||||
static const iocshArg *const CreateAxisArgs[] = {
|
||||
&CreateAxisArg0,
|
||||
&CreateAxisArg1,
|
||||
&CreateAxisArg2,
|
||||
};
|
||||
static const iocshFuncDef configDetectorTowerCreateAxis = {"detectorTowerAxis",
|
||||
3, CreateAxisArgs};
|
||||
static void configDetectorTowerCreateAxisCallFunc(const iocshArgBuf *args) {
|
||||
detectorTowerCreateAxis(args[0].sval, args[1].ival, args[2].ival);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the setDeferredMovementWait (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param scaleMovTimeout Scaling factor (in seconds)
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setDeferredMovementWait(const char *portName, int axisNo,
|
||||
double deferredMovementWait) {
|
||||
|
||||
sinqController *pC;
|
||||
pC = (sinqController *)findAsynPortDriver(portName);
|
||||
if (pC == nullptr) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nPort %s not found.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynMotorAxis *asynAxis = pC->getAxis(axisNo);
|
||||
detectorTowerAngleAxis *axis =
|
||||
dynamic_cast<detectorTowerAngleAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nAxis %d does not "
|
||||
"exist or is not an instance of detectorTowerAngleAxis.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
axis->deferredMovementWait_ = deferredMovementWait;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
static const iocshArg setDeferredMovementWaitArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setDeferredMovementWaitArg1 = {"Axis number",
|
||||
iocshArgInt};
|
||||
static const iocshArg setDeferredMovementWaitArg2 = {
|
||||
"Minimum time a deferred movement will be delayed in order to collect "
|
||||
"commands in seconds",
|
||||
iocshArgDouble};
|
||||
static const iocshArg *const setDeferredMovementWaitArgs[] = {
|
||||
&setDeferredMovementWaitArg0, &setDeferredMovementWaitArg1,
|
||||
&setDeferredMovementWaitArg2};
|
||||
static const iocshFuncDef setDeferredMovementWaitDef = {
|
||||
"setDeferredMovementWait", 3, setDeferredMovementWaitArgs};
|
||||
|
||||
static void setDeferredMovementWaitCallFunc(const iocshArgBuf *args) {
|
||||
setDeferredMovementWait(args[0].sval, args[1].ival, args[2].dval);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// This function is made known to EPICS in detectorTower.dbd and is
|
||||
// called by EPICS in order to register both functions in the IOC shell
|
||||
static void detectorTowerAxisRegister(void) {
|
||||
iocshRegister(&configDetectorTowerCreateAxis,
|
||||
configDetectorTowerCreateAxisCallFunc);
|
||||
iocshRegister(&setDeferredMovementWaitDef, setDeferredMovementWaitCallFunc);
|
||||
}
|
||||
epicsExportRegistrar(detectorTowerAxisRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifndef detectorTowerAxis_H
|
||||
#define detectorTowerAxis_H
|
||||
#include "detectorTowerAuxiliaryAxis.h"
|
||||
#ifndef detectorTowerAngleAxis_H
|
||||
#define detectorTowerAngleAxis_H
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "turboPmacAxis.h"
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
@@ -8,10 +8,10 @@
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class detectorTowerController;
|
||||
|
||||
class detectorTowerAxis : public turboPmacAxis {
|
||||
class detectorTowerAngleAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerAxis
|
||||
* @brief Construct a new detectorTowerAngleAxis
|
||||
*
|
||||
* @param pController Pointer to the associated controller
|
||||
* @param axisNo Index of the axis
|
||||
@@ -20,15 +20,14 @@ class detectorTowerAxis : public turboPmacAxis {
|
||||
* @param tiltZeroCorrAxis Pointer to the attached axis which controls
|
||||
* the tilt offset
|
||||
*/
|
||||
detectorTowerAxis(detectorTowerController *pController, int axisNo,
|
||||
detectorTowerAuxiliaryAxis *liftZeroCorrAxis,
|
||||
detectorTowerAuxiliaryAxis *tiltZeroCorrAxis);
|
||||
detectorTowerAngleAxis(detectorTowerController *pController, int axisNo,
|
||||
detectorTowerLiftAxis *liftAxis);
|
||||
|
||||
/**
|
||||
* @brief Destroy the detectorTowerAxis
|
||||
* @brief Destroy the detectorTowerAngleAxis
|
||||
*
|
||||
*/
|
||||
virtual ~detectorTowerAxis();
|
||||
virtual ~detectorTowerAngleAxis();
|
||||
|
||||
/**
|
||||
* @brief Readout of some values from the controller at IOC startup
|
||||
@@ -47,12 +46,17 @@ class detectorTowerAxis : public turboPmacAxis {
|
||||
asynStatus stop(double acceleration);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the `doPoll` function from sinqAxis. The
|
||||
* parameters are described in the documentation of `sinqAxis::doPoll`.
|
||||
* @brief Poll all detector tower axes, if this axis is the one with the
|
||||
* smallest index.
|
||||
*
|
||||
* We do not use the doPoll framework from sinqMotor here on purpose, since
|
||||
* we want to e.g. reset the motorStatusProblem for all axes at once at the
|
||||
* beginning of the poll.
|
||||
*
|
||||
* @param moving
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus doPoll(bool *moving);
|
||||
|
||||
/**
|
||||
@@ -100,7 +104,32 @@ class detectorTowerAxis : public turboPmacAxis {
|
||||
*/
|
||||
asynStatus doReset();
|
||||
|
||||
// If true, either this axis or one of the detectorTowerAuxiliaryAxis
|
||||
/**
|
||||
* @brief Move the axis to the position `newOrigin` and recalibrate
|
||||
*
|
||||
* When calling this function, the angle axis moves to `newOrigin` and the
|
||||
* hardware sets this position as the new origin.
|
||||
*
|
||||
* @param origin
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus adjustOrigin(double newOrigin);
|
||||
|
||||
/**
|
||||
* @brief Read out the beam radius
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
double beamRadius() { return beamRadius_; }
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the associated angle axis
|
||||
*
|
||||
* @return detectorTowerAngleAxis*
|
||||
*/
|
||||
detectorTowerLiftAxis *liftAxis() { return liftAxis_; }
|
||||
|
||||
// If true, either this axis or one of the detectorTowerLiftAxis
|
||||
// attached to it received a movement command.
|
||||
bool receivedTarget_;
|
||||
|
||||
@@ -115,15 +144,19 @@ class detectorTowerAxis : public turboPmacAxis {
|
||||
*/
|
||||
double deferredMovementWait_;
|
||||
|
||||
/**
|
||||
* @brief Variable holding the axis error for later use
|
||||
*
|
||||
*/
|
||||
int error_;
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
int error_;
|
||||
detectorTowerAuxiliaryAxis *tiltZeroCorrAxis_;
|
||||
detectorTowerAuxiliaryAxis *liftZeroCorrAxis_;
|
||||
detectorTowerLiftAxis *liftAxis_;
|
||||
double beamRadius_;
|
||||
|
||||
private:
|
||||
friend class detectorTowerAuxiliaryAxis;
|
||||
friend class detectorTowerLiftAxis;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,244 +0,0 @@
|
||||
#include "detectorTowerAuxiliaryAxis.h"
|
||||
#include "detectorTowerAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
/*
|
||||
Contains all instances of detectorTowerAuxiliaryAxis which have been created and
|
||||
is used in the initialization hook function.
|
||||
*/
|
||||
static std::vector<detectorTowerAuxiliaryAxis *> 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<detectorTowerAuxiliaryAxis *>::iterator itA =
|
||||
axes.begin();
|
||||
itA != axes.end(); ++itA) {
|
||||
detectorTowerAuxiliaryAxis *axis = *itA;
|
||||
axis->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detectorTowerAuxiliaryAxis::detectorTowerAuxiliaryAxis(
|
||||
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_->pasynUser(), 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
detectorTowerAuxiliaryAxis::~detectorTowerAuxiliaryAxis(void) {
|
||||
// Since the controller memory is managed somewhere else, we don't need to
|
||||
// clean up the pointer pC here.
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAuxiliaryAxis::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_->pasynUser(), 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 detectorTowerAuxiliaryAxis::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, "motorStatusMoving_",
|
||||
dTA_->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__);
|
||||
}
|
||||
|
||||
// According to the function documentation of asynMotorAxis::poll, this
|
||||
// function should be called at the end of a poll implementation.
|
||||
pl_status = callParamCallbacks();
|
||||
bool wantToPrint = pl_status != asynSuccess;
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, wantToPrint,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), 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_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
if (wantToPrint) {
|
||||
poll_status = pl_status;
|
||||
}
|
||||
|
||||
// The limits are written into this class instance inside the doPoll
|
||||
// function of detectorTowerAxis
|
||||
return poll_status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAuxiliaryAxis::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 detectorTowerAuxiliaryAxis::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_] = {0};
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rw_status = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
|
||||
if (rw_status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||
"failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return rw_status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerAuxiliaryAxis::reset() { return dTA_->reset(); };
|
||||
@@ -1,82 +0,0 @@
|
||||
#ifndef detectorTowerAuxiliaryAxis_H
|
||||
#define detectorTowerAuxiliaryAxis_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 detectorTowerAuxiliaryAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerAxis
|
||||
*
|
||||
* @param pController Pointer to the associated controller
|
||||
* @param axisNo Index of the axis
|
||||
*/
|
||||
detectorTowerAuxiliaryAxis(detectorTowerController *pController,
|
||||
int axisNo);
|
||||
|
||||
/**
|
||||
* @brief Destroy the turboPmacAxis
|
||||
*
|
||||
*/
|
||||
virtual ~detectorTowerAuxiliaryAxis();
|
||||
|
||||
/**
|
||||
* @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 and trigger a position
|
||||
* collection cycle
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Call the reset function of the associated `detectorTowerAxis`.
|
||||
*
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus reset();
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
detectorTowerAxis *dTA_;
|
||||
|
||||
private:
|
||||
friend class detectorTowerAxis;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@
|
||||
|
||||
#ifndef detectorTowerController_H
|
||||
#define detectorTowerController_H
|
||||
#include "detectorTowerAuxiliaryAxis.h"
|
||||
#include "detectorTowerAxis.h"
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "turboPmacController.h"
|
||||
|
||||
class detectorTowerController : public turboPmacController {
|
||||
@@ -19,7 +19,7 @@ class detectorTowerController : public turboPmacController {
|
||||
* @brief Construct a new detectorTowerController object
|
||||
*
|
||||
* This controller object can handle both "normal" TurboPMAC axes created
|
||||
with the turboPmacAxis constructor and the special detectorTowerAxis.
|
||||
with the turboPmacAxis constructor and the special detectorTowerAngleAxis.
|
||||
*
|
||||
* @param portName See sinqController constructor
|
||||
* @param ipPortConfigName See sinqController constructor
|
||||
@@ -65,51 +65,77 @@ class detectorTowerController : public turboPmacController {
|
||||
* @brief Get the axis object
|
||||
*
|
||||
* @param pasynUser Specify the axis via the asynUser
|
||||
* @return detectorTowerAxis* If no axis could be found, this is a
|
||||
* nullptr
|
||||
* @return detectorTowerAngleAxis* If no axis could be found, this is
|
||||
* a nullptr
|
||||
*/
|
||||
detectorTowerAxis *getDetectorTowerAxis(asynUser *pasynUser);
|
||||
detectorTowerAngleAxis *getDetectorTowerAngleAxis(asynUser *pasynUser);
|
||||
|
||||
/**
|
||||
* @brief Get the axis object
|
||||
*
|
||||
* @param axisNo Specify the axis via its index
|
||||
* @return detectorTowerAxis* If no axis could be found, this is a
|
||||
* nullptr
|
||||
* @return detectorTowerAngleAxis* If no axis could be found, this is
|
||||
* a nullptr
|
||||
*/
|
||||
detectorTowerAxis *getDetectorTowerAxis(int axisNo);
|
||||
detectorTowerAngleAxis *getDetectorTowerAngleAxis(int axisNo);
|
||||
|
||||
/**
|
||||
* @brief Get the axis object
|
||||
*
|
||||
* @param pasynUser Specify the axis via the asynUser
|
||||
* @return detectorTowerAuxiliaryAxis* If no axis could be found,
|
||||
* @return detectorTowerLiftAxis* If no axis could be found,
|
||||
* this is a nullptr
|
||||
*/
|
||||
detectorTowerAuxiliaryAxis *
|
||||
getDetectorTowerAuxiliaryAxis(asynUser *pasynUser);
|
||||
detectorTowerLiftAxis *getDetectorTowerLiftAxis(asynUser *pasynUser);
|
||||
|
||||
/**
|
||||
* @brief Get the axis object
|
||||
*
|
||||
* @param axisNo Specify the axis via its index
|
||||
* @return detectorTowerAuxiliaryAxis* If no axis could be found,
|
||||
* @return detectorTowerLiftAxis* If no axis could be found,
|
||||
* this is a nullptr
|
||||
*/
|
||||
detectorTowerAuxiliaryAxis *getDetectorTowerAuxiliaryAxis(int axisNo);
|
||||
detectorTowerLiftAxis *getDetectorTowerLiftAxis(int axisNo);
|
||||
|
||||
/**
|
||||
* @brief Common poll function for both lift and angle axes
|
||||
*
|
||||
* @param moving
|
||||
* @param angleAxis
|
||||
* @param liftAxis
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus pollDetectorAxes(bool *moving, detectorTowerAngleAxis *angleAxis,
|
||||
detectorTowerLiftAxis *liftAxis);
|
||||
|
||||
// Accessors for additional PVs
|
||||
int positionStateRBV() { return positionStateRBV_; }
|
||||
int changeState() { return changeState_; }
|
||||
int motorTargetOffset() { return motorTargetOffset_; }
|
||||
int changeStateRBV() { return changeStateRBV_; }
|
||||
int motorOrigin() { return motorOrigin_; }
|
||||
int motorAdjustOrigin() { return motorAdjustOrigin_; }
|
||||
int motorAdjustOriginHighLimitFromDriver() {
|
||||
return motorAdjustOriginHighLimitFromDriver_;
|
||||
}
|
||||
int motorAdjustOriginLowLimitFromDriver() {
|
||||
return motorAdjustOriginLowLimitFromDriver_;
|
||||
}
|
||||
int liftSupportOrigin() { return liftSupportOrigin_; }
|
||||
int liftSupportAdjustOrigin() { return liftSupportAdjustOrigin_; }
|
||||
|
||||
private:
|
||||
// Indices of additional PVs
|
||||
#define FIRST_detectorTower_PARAM positionStateRBV_
|
||||
int positionStateRBV_;
|
||||
int changeState_;
|
||||
int motorTargetOffset_;
|
||||
#define LAST_detectorTower_PARAM motorTargetOffset_
|
||||
int changeStateRBV_;
|
||||
int motorOrigin_;
|
||||
int motorAdjustOrigin_;
|
||||
int motorAdjustOriginHighLimitFromDriver_;
|
||||
int motorAdjustOriginLowLimitFromDriver_;
|
||||
int liftSupportOrigin_;
|
||||
int liftSupportAdjustOrigin_;
|
||||
#define LAST_detectorTower_PARAM liftSupportAdjustOrigin_
|
||||
};
|
||||
#define NUM_detectorTower_DRIVER_PARAMS \
|
||||
(&LAST_detectorTower_PARAM - &FIRST_detectorTower_PARAM + 1)
|
||||
|
||||
308
src/detectorTowerLiftAxis.cpp
Normal file
308
src/detectorTowerLiftAxis.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include "detectorTowerLiftAxis.h"
|
||||
#include "detectorTowerAngleAxis.h"
|
||||
#include "detectorTowerController.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <epicsExport.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
/*
|
||||
Contains all instances of detectorTowerLiftAxis which have been created and
|
||||
is used in the initialization hook function.
|
||||
*/
|
||||
static std::vector<detectorTowerLiftAxis *> 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<detectorTowerLiftAxis *>::iterator itA = axes.begin();
|
||||
itA != axes.end(); ++itA) {
|
||||
detectorTowerLiftAxis *axis = *itA;
|
||||
axis->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detectorTowerLiftAxis::detectorTowerLiftAxis(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_->pasynUser(), 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
detectorTowerLiftAxis::~detectorTowerLiftAxis(void) {
|
||||
// Since the controller memory is managed somewhere else, we don't need to
|
||||
// clean up the pointer pC here.
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::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_->pasynUser(), 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 the motorStatusMoving flag
|
||||
status = setIntegerParam(pC_->motorStatusMoving(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
// Perform the actual poll
|
||||
asynStatus detectorTowerLiftAxis::poll(bool *moving) {
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
// Is this axis the one with the smallest index?
|
||||
// If not, just read out the movement status and update *moving
|
||||
if (axisNo() < angleAxis_->axisNo()) {
|
||||
status = pC_->pollDetectorAxes(moving, angleAxis_, this);
|
||||
} else {
|
||||
status = pC_->getIntegerParam(axisNo(), pC_->motorStatusMoving(),
|
||||
(int *)moving);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusMoving",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
wasMoving_ = *moving;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::doPoll(bool *moving) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nThe doPoll method "
|
||||
"of this axis type should not be reachable. This is a bug.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::doMove(double position, int relative,
|
||||
double min_velocity,
|
||||
double max_velocity,
|
||||
double acceleration) {
|
||||
|
||||
double motorRecResolution = 0.0;
|
||||
asynStatus plStatus = pC_->getDoubleParam(
|
||||
axisNo_, pC_->motorRecResolution(), &motorRecResolution);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorRecResolution_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
// Signal to the deferredMovementCollectorLoop (of the
|
||||
// detectorTowerAngleAxis) that a movement should be started to the defined
|
||||
// target position.
|
||||
targetPosition_ = position * motorRecResolution;
|
||||
angleAxis_->receivedTarget_ = true;
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::stop(double acceleration) {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus rwStatus = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus plStatus = asynSuccess;
|
||||
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
|
||||
// =========================================================================
|
||||
|
||||
rwStatus = pC_->writeRead(axisNo_, "P350=8", response, 0);
|
||||
|
||||
if (rwStatus != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||
"failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
plStatus = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (plStatus != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(plStatus, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return rwStatus;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::reset() { return angleAxis_->reset(); };
|
||||
|
||||
asynStatus detectorTowerLiftAxis::adjustOrigin(double newOrigin) {
|
||||
|
||||
asynStatus status = asynSuccess;
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
bool isInChangerPos = positionState == 2 || positionState == 3;
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
isInChangerPos, pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
||||
"moved because it is moving from working to changer "
|
||||
"position, is in changer position or is moving from changer "
|
||||
"to working position.%s\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
|
||||
// Set the new adjust for the lift axis
|
||||
snprintf(command, sizeof(command), "Q356=%lf P350=5", newOrigin);
|
||||
|
||||
// We don't expect an answer
|
||||
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nSetting new "
|
||||
"lift origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus detectorTowerLiftAxis::adjustSupportOrigin(double newOrigin) {
|
||||
|
||||
asynStatus status = asynSuccess;
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
int positionState = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo(), pC_->positionStateRBV(), &positionState);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "positionStateRBV_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// If the axis is in changer position, it must be moved into working
|
||||
// position before any move can be started.
|
||||
bool isInChangerPos = positionState == 2 || positionState == 3;
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__,
|
||||
isInChangerPos, pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis cannot be "
|
||||
"moved because it is moving from working to changer "
|
||||
"position, is in changer position or is moving from changer "
|
||||
"to working position.%s\n",
|
||||
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->getMsgPrintControl().getSuffix());
|
||||
}
|
||||
|
||||
// Set the new adjust for the lift axis
|
||||
snprintf(command, sizeof(command), "Q656=%lf P350=6", newOrigin);
|
||||
|
||||
// We don't expect an answer
|
||||
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nSetting new "
|
||||
"lift origin %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
newOrigin);
|
||||
status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusProblem_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
117
src/detectorTowerLiftAxis.h
Normal file
117
src/detectorTowerLiftAxis.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifndef detectorTowerLiftAxis_H
|
||||
#define detectorTowerLiftAxis_H
|
||||
#include "turboPmacAxis.h"
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class detectorTowerController;
|
||||
class detectorTowerAngleAxis;
|
||||
|
||||
class detectorTowerLiftAxis : public turboPmacAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new detectorTowerAngleAxis
|
||||
*
|
||||
* @param pController Pointer to the associated controller
|
||||
* @param axisNo Index of the axis
|
||||
*/
|
||||
detectorTowerLiftAxis(detectorTowerController *pController, int axisNo);
|
||||
|
||||
/**
|
||||
* @brief Destroy the turboPmacAxis
|
||||
*
|
||||
*/
|
||||
virtual ~detectorTowerLiftAxis();
|
||||
|
||||
/**
|
||||
* @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 Poll all detector tower axes, if this axis is the one with the
|
||||
* smallest index.
|
||||
*
|
||||
* We do not use the doPoll framework from sinqMotor here on purpose, since
|
||||
* we want to e.g. reset the motorStatusProblem for all axes at once at the
|
||||
* beginning of the poll.
|
||||
*
|
||||
* @param moving
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus doPoll(bool *moving);
|
||||
|
||||
/**
|
||||
* @brief Set the target value for the detector angle and trigger a position
|
||||
* collection cycle
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Call the reset function of the associated
|
||||
* `detectorTowerAngleAxis`.
|
||||
*
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus reset();
|
||||
|
||||
/**
|
||||
* @brief Move the axis to the position `newOrigin` and recalibrate
|
||||
*
|
||||
* When calling this function, the lift axis moves to `newOrigin` and the
|
||||
* hardware sets this position as the new origin.
|
||||
*
|
||||
* @param origin
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus adjustOrigin(double newOrigin);
|
||||
|
||||
/**
|
||||
* @brief Move the support motor of the beam lift to the position
|
||||
* `newOrigin` and recalibrate
|
||||
*
|
||||
* When calling this function, the lift axis support motor moves to
|
||||
* `newOrigin` and the hardware sets this position as the new origin.
|
||||
*
|
||||
* @param origin
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus adjustSupportOrigin(double newOrigin);
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the associated angle axis
|
||||
*
|
||||
* @return detectorTowerAngleAxis*
|
||||
*/
|
||||
detectorTowerAngleAxis *angleAxis() { return angleAxis_; }
|
||||
|
||||
protected:
|
||||
detectorTowerController *pC_;
|
||||
detectorTowerAngleAxis *angleAxis_;
|
||||
|
||||
private:
|
||||
friend class detectorTowerAngleAxis;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user