Bugfix for movTimeoutWatchdog
Update of README.md
This commit is contained in:
585
src/sinqAxis.cpp
585
src/sinqAxis.cpp
@ -1,5 +1,8 @@
|
||||
#include "sinqAxis.h"
|
||||
#include "epicsExport.h"
|
||||
#include "iocsh.h"
|
||||
#include "sinqController.h"
|
||||
#include <errlog.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -12,124 +15,95 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
||||
init_poll_counter_ = 0;
|
||||
scaleMovTimeout_ = 2.0;
|
||||
offsetMovTimeout_ = 30;
|
||||
targetPosition_ = 0.0;
|
||||
|
||||
// Motor is assumed to be enabled
|
||||
status = pC_->setIntegerParam(axisNo_, pC_->motorEnableRBV_, 1);
|
||||
status = setIntegerParam(pC_->motorEnableRBV_, 1);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (setting a parameter value failed "
|
||||
"with %s)\n. Terminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, pC_->stringifyAsynStatus(status));
|
||||
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);
|
||||
}
|
||||
|
||||
// By default, motors cannot be disabled
|
||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable_, 0);
|
||||
status = setIntegerParam(pC_->motorCanDisable_, 0);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (setting a parameter value failed "
|
||||
"with %s)\n. Terminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, pC_->stringifyAsynStatus(status));
|
||||
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);
|
||||
}
|
||||
|
||||
// Provide a default value for the motor position.
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorPosition_, 0.0);
|
||||
status = setDoubleParam(pC_->motorPosition_, 0.0);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (setting a parameter value failed "
|
||||
"with %s)\n. Terminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, pC_->stringifyAsynStatus(status));
|
||||
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);
|
||||
}
|
||||
|
||||
// We assume that the motor has no status problems initially
|
||||
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusProblem_, 0);
|
||||
status = setIntegerParam(pC_->motorStatusProblem_, 0);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (setting a parameter value failed "
|
||||
"with %s)\n. Terminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, pC_->stringifyAsynStatus(status));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::atFirstPoll() {
|
||||
asynStatus status = asynSuccess;
|
||||
int variableSpeed = 0;
|
||||
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed_, &variableSpeed);
|
||||
// Set the homing-related flags
|
||||
status = setIntegerParam(pC_->motorStatusHome_, 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
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);
|
||||
}
|
||||
|
||||
if (variableSpeed == 1) {
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, 0.0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_,
|
||||
1000000000.0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
} else {
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, 0.0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, 0.0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
status = setIntegerParam(pC_->motorStatusHomed_, 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 = setIntegerParam(pC_->motorStatusAtHome_, 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;
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::poll(bool *moving) {
|
||||
// Local variable declaration
|
||||
asynStatus pl_status = asynSuccess;
|
||||
asynStatus poll_status = asynSuccess;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
// If this poll is the initial poll, check if the parameter library has
|
||||
// already been initialized. If not, force EPICS to repeat the poll until
|
||||
// the initialization is complete (or until a timeout is reached). Once the
|
||||
// parameter library has been initialized, read configuration data from the
|
||||
// motor controller into it.
|
||||
if (initial_poll_) {
|
||||
poll_status = atFirstPoll();
|
||||
|
||||
if (poll_status == asynSuccess) {
|
||||
initial_poll_ = false;
|
||||
} else {
|
||||
// Send a message to the IOC shell every 10 trials.
|
||||
init_poll_counter_ += 1;
|
||||
if (init_poll_counter_ % 10 == 0) {
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nRunning function 'atFirstPoll' "
|
||||
"failed %d times with error %s.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__, init_poll_counter_,
|
||||
pC_->stringifyAsynStatus(poll_status));
|
||||
}
|
||||
|
||||
// Wait for 100 ms until trying the entire poll again
|
||||
usleep(100000);
|
||||
return poll_status;
|
||||
}
|
||||
}
|
||||
int homing = 0;
|
||||
int homed = 0;
|
||||
|
||||
/*
|
||||
At the beginning of the poll, it is assumed that the axis has no status
|
||||
@ -140,18 +114,19 @@ asynStatus sinqAxis::poll(bool *moving) {
|
||||
*/
|
||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
pl_status = setIntegerParam(pC_->motorStatusCommsError_, false);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusCommsError_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
pl_status = setStringParam(pC_->motorMessageText_, "");
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
// The poll function is just a wrapper around doPoll and
|
||||
@ -165,41 +140,62 @@ asynStatus sinqAxis::poll(bool *moving) {
|
||||
if (poll_status != asynSuccess) {
|
||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHomed_, &homed);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHome_, &homing);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
if (homing == 1 && !(*moving)) {
|
||||
|
||||
// Set the homing-related flags
|
||||
pl_status = setIntegerParam(pC_->motorStatusHome_, 0);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
pl_status = setIntegerParam(pC_->motorStatusHomed_, 1);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
pl_status = setIntegerParam(pC_->motorStatusAtHome_, 1);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// Check and update the watchdog
|
||||
if (checkMovTimeoutWatchdog(*moving) != asynSuccess) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
if (pl_status != asynSuccess) {
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFunction isEnabled failed with %s.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->stringifyAsynStatus(poll_status));
|
||||
pl_status = setStringParam(pC_->motorMessageText_,
|
||||
"Could not check whether the motor is "
|
||||
"enabled or not. Please call the support");
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
__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();
|
||||
if (pl_status != asynSuccess) {
|
||||
// If we can't communicate with the parameter library, it doesn't make
|
||||
// sense to try and upstream this to the user -> Just log the error
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\ncallParamCallbacks failed with %s for axis %d",
|
||||
__PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->stringifyAsynStatus(poll_status), axisNo_);
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line "
|
||||
"%d:\ncallParamCallbacks failed with %s.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->stringifyAsynStatus(poll_status));
|
||||
poll_status = pl_status;
|
||||
}
|
||||
|
||||
@ -211,35 +207,35 @@ asynStatus sinqAxis::doPoll(bool *moving) { return asynSuccess; }
|
||||
asynStatus sinqAxis::move(double position, int relative, double minVelocity,
|
||||
double maxVelocity, double acceleration) {
|
||||
|
||||
double targetPosition = 0.0;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus pl_status = asynSuccess;
|
||||
double motorRecResolution = 0.0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
// Calculate the (absolute) target position
|
||||
if (relative) {
|
||||
|
||||
double motorPosition = 0.0;
|
||||
pl_status =
|
||||
pC_->getDoubleParam(axisNo_, pC_->motorPosition_, &motorPosition);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
targetPosition = position + motorPosition;
|
||||
} else {
|
||||
targetPosition = position;
|
||||
}
|
||||
|
||||
// Set the target position
|
||||
pl_status = setDoubleParam(pC_->motorTargetPosition_, targetPosition);
|
||||
// When a new move is done, the motor is not homed anymore
|
||||
pl_status = setIntegerParam(pC_->motorStatusHomed_, 0);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorTargetPosition_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
pl_status = setIntegerParam(pC_->motorStatusAtHome_, 0);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
||||
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__);
|
||||
}
|
||||
|
||||
// Store the target position internally
|
||||
targetPosition_ = position * motorRecResolution;
|
||||
|
||||
return doMove(position, relative, minVelocity, maxVelocity, acceleration);
|
||||
}
|
||||
@ -252,48 +248,58 @@ asynStatus sinqAxis::doMove(double position, int relative, double minVelocity,
|
||||
asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
|
||||
double acceleration, int forwards) {
|
||||
|
||||
double targetPosition = 0.0;
|
||||
double position = 0.0;
|
||||
double highLimit = 0.0;
|
||||
double lowLimit = 0.0;
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
// Status of parameter library operations
|
||||
asynStatus pl_status = asynSuccess;
|
||||
status = doHome(minVelocity, maxVelocity, acceleration, forwards);
|
||||
|
||||
// =========================================================================
|
||||
if (status == asynSuccess) {
|
||||
|
||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorPosition_, &position);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorPosition_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
status = setStringParam(pC_->motorMessageText_, "Homing");
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorHighLimit_, &highLimit);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorHighLimit_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
// Set the homing-related flags
|
||||
status = setIntegerParam(pC_->motorStatusHome_, 1);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusHome_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
status = setIntegerParam(pC_->motorStatusHomed_, 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusHomed_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
status = setIntegerParam(pC_->motorStatusAtHome_, 0);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorStatusAtHome_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorLowLimit_, &lowLimit);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
// Update the motor record
|
||||
return callParamCallbacks();
|
||||
|
||||
if (std::fabs(position - highLimit) > std::fabs(position - lowLimit)) {
|
||||
targetPosition = highLimit;
|
||||
} else if (status == asynError) {
|
||||
// asynError means that we tried to home an absolute encoder
|
||||
status = setStringParam(pC_->motorMessageText_,
|
||||
"Can't home a motor with absolute encoder");
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
// Update the motor record
|
||||
return callParamCallbacks();
|
||||
} else {
|
||||
targetPosition = lowLimit;
|
||||
// Bubble up all other problems
|
||||
return status;
|
||||
}
|
||||
|
||||
// Set the target position
|
||||
pl_status = setDoubleParam(pC_->motorTargetPosition_, targetPosition);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorTargetPosition_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return doHome(minVelocity, maxVelocity, acceleration, forwards);
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::doHome(double minVelocity, double maxVelocity,
|
||||
@ -311,7 +317,7 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
||||
status =
|
||||
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed_, &variableSpeed);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_",
|
||||
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
if (variableSpeed == 1) {
|
||||
@ -319,30 +325,36 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
||||
// Check the inputs and create corresponding error messages
|
||||
if (vbas > vmax) {
|
||||
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nLower speed limit vbas=%lf must not be "
|
||||
"smaller than upper limit vmax=%lf.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__, vbas, vmax);
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nLower speed "
|
||||
"limit vbas=%lf must not be smaller than upper limit "
|
||||
"vmax=%lf.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
vbas, vmax);
|
||||
|
||||
status = setStringParam(
|
||||
pC_->motorMessageText_,
|
||||
"Lower speed limit must not be smaller than upper speed limit");
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
if (velo < vbas || velo > vmax) {
|
||||
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nActual speed velo=%lf must be between "
|
||||
"lower limit vbas=%lf and upper limit vmax=%lf.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__, velo, vbas, vmax);
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nActual "
|
||||
"speed velo=%lf must be between lower limit vbas=%lf and "
|
||||
"upper limit vmax=%lf.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
velo, vbas, vmax);
|
||||
|
||||
status = setStringParam(pC_->motorMessageText_,
|
||||
"Speed is not inside limits");
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
@ -350,38 +362,44 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, vbas);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, vmax);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
} else {
|
||||
// Set minimum and maximum speed equal to the set speed
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, velo);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, velo);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
@ -393,17 +411,17 @@ asynStatus sinqAxis::setAcclField(double accl) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus status =
|
||||
pC_->setDoubleParam(axisNo_, pC_->motorAcclFromDriver_, accl);
|
||||
asynStatus status = setDoubleParam(pC_->motorAcclFromDriver_, accl);
|
||||
if (status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(status, "motorAcclFromDriver_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::setWatchdogEnabled(bool enable) {
|
||||
return pC_->setIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_, enable);
|
||||
return setIntegerParam(pC_->motorEnableMovWatchdog_, enable);
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
||||
@ -414,15 +432,14 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
||||
&enableMovWatchdog);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
if (enableMovWatchdog == 1) {
|
||||
// These parameters are only needed in this branch
|
||||
double motorPosition = 0.0;
|
||||
double motorPositionRec = 0.0;
|
||||
double motorTargetPositionRec = 0.0;
|
||||
double motorTargetPosition = 0.0;
|
||||
double motorVelocity = 0.0;
|
||||
double motorVelocityRec = 0.0;
|
||||
double motorAccel = 0.0;
|
||||
@ -443,14 +460,16 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
||||
&motorRecResolution);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorPosition_,
|
||||
&motorPositionRec);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorPosition",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
motorPosition = motorPositionRec * motorRecResolution;
|
||||
@ -477,15 +496,10 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
||||
if (pl_status == asynSuccess && motorVelocityRec > 0.0) {
|
||||
// Convert back to the value in the VELO field
|
||||
motorVelocity = motorVelocityRec * motorRecResolution;
|
||||
|
||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorTargetPosition_,
|
||||
&motorTargetPositionRec);
|
||||
motorTargetPosition = motorTargetPositionRec * motorRecResolution;
|
||||
if (pl_status == asynSuccess) {
|
||||
|
||||
timeContSpeed =
|
||||
std::ceil(std::fabs(motorTargetPosition - motorPosition) /
|
||||
motorVelocity);
|
||||
timeContSpeed = std::ceil(
|
||||
std::fabs(targetPosition_ - motorPosition) / motorVelocity);
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,7 +533,8 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
||||
&enableMovWatchdog);
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
// Not moving or watchdog not active / enabled
|
||||
@ -532,22 +547,23 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
||||
if (expectedArrivalTime_ < time(NULL)) {
|
||||
// Check the watchdog
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nAxis %d exceeded the expected arrival time "
|
||||
"%ld (current time is %ld).\n",
|
||||
__PRETTY_FUNCTION__, __LINE__, axisNo_, expectedArrivalTime_,
|
||||
time(NULL));
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nExceeded "
|
||||
"expected arrival time %ld (current time is %ld).\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
expectedArrivalTime_, time(NULL));
|
||||
|
||||
pl_status = setStringParam(
|
||||
pC_->motorMessageText_,
|
||||
"Exceeded expected arrival time. Check if the axis is blocked.");
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
@ -555,4 +571,161 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
||||
return asynSuccess;
|
||||
}
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// IOC shell functions
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* @brief Enable / disable the watchdog (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param enable If 0, disable the watchdog, otherwise enable
|
||||
* it
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setWatchdogEnabled(const char *portName, int axisNo, int enable) {
|
||||
|
||||
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);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf(
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis does not "
|
||||
"exist or is not an instance of sinqAxis.",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return axis->setWatchdogEnabled(enable != 0);
|
||||
}
|
||||
|
||||
static const iocshArg setWatchdogEnabledArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setWatchdogEnabledArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setWatchdogEnabledArg2 = {
|
||||
"Enabling / disabling the watchdog", iocshArgInt};
|
||||
static const iocshArg *const setWatchdogEnabledArgs[] = {
|
||||
&setWatchdogEnabledArg0, &setWatchdogEnabledArg1, &setWatchdogEnabledArg2};
|
||||
static const iocshFuncDef setWatchdogEnabledDef = {"setWatchdogEnabled", 3,
|
||||
setWatchdogEnabledArgs};
|
||||
|
||||
static void setWatchdogEnabledCallFunc(const iocshArgBuf *args) {
|
||||
setWatchdogEnabled(args[0].sval, args[1].ival, args[2].ival);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the offsetMovTimeout (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param offsetMovTimeout Offset (in seconds)
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setOffsetMovTimeout(const char *portName, int axisNo,
|
||||
double offsetMovTimeout) {
|
||||
|
||||
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);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nAxis %d does not "
|
||||
"exist or is not an "
|
||||
"instance of sinqAxis.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
}
|
||||
|
||||
return axis->setOffsetMovTimeout(offsetMovTimeout);
|
||||
}
|
||||
|
||||
static const iocshArg setOffsetMovTimeoutArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setOffsetMovTimeoutArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setOffsetMovTimeoutArg2 = {"Offset timeout for movement",
|
||||
iocshArgDouble};
|
||||
static const iocshArg *const setOffsetMovTimeoutArgs[] = {
|
||||
&setOffsetMovTimeoutArg0, &setOffsetMovTimeoutArg1,
|
||||
&setOffsetMovTimeoutArg2};
|
||||
static const iocshFuncDef setOffsetMovTimeoutDef = {"setOffsetMovTimeout", 3,
|
||||
setOffsetMovTimeoutArgs};
|
||||
|
||||
static void setOffsetMovTimeoutCallFunc(const iocshArgBuf *args) {
|
||||
setOffsetMovTimeout(args[0].sval, args[1].ival, args[2].dval);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the setScaleMovTimeout (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param scaleMovTimeout Scaling factor (in seconds)
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setScaleMovTimeout(const char *portName, int axisNo,
|
||||
double scaleMovTimeout) {
|
||||
|
||||
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);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nAxis %d does not "
|
||||
"exist or is not an "
|
||||
"instance of sinqAxis.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
}
|
||||
|
||||
return axis->setScaleMovTimeout(scaleMovTimeout);
|
||||
}
|
||||
|
||||
static const iocshArg setScaleMovTimeoutArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setScaleMovTimeoutArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setScaleMovTimeoutArg2 = {
|
||||
"Multiplier for calculated move time", iocshArgDouble};
|
||||
static const iocshArg *const setScaleMovTimeoutArgs[] = {
|
||||
&setScaleMovTimeoutArg0, &setScaleMovTimeoutArg1, &setScaleMovTimeoutArg2};
|
||||
static const iocshFuncDef setScaleMovTimeoutDef = {"setScaleMovTimeout", 3,
|
||||
setScaleMovTimeoutArgs};
|
||||
|
||||
static void setScaleMovTimeoutCallFunc(const iocshArgBuf *args) {
|
||||
setScaleMovTimeout(args[0].sval, args[1].ival, args[2].dval);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// This function is made known to EPICS in sinqMotor.dbd and is called by EPICS
|
||||
// in order to register all functions in the IOC shell
|
||||
static void sinqAxisRegister(void) {
|
||||
iocshRegister(&setOffsetMovTimeoutDef, setOffsetMovTimeoutCallFunc);
|
||||
iocshRegister(&setScaleMovTimeoutDef, setScaleMovTimeoutCallFunc);
|
||||
iocshRegister(&setWatchdogEnabledDef, setWatchdogEnabledCallFunc);
|
||||
}
|
||||
epicsExportRegistrar(sinqAxisRegister);
|
||||
|
||||
} // extern C
|
||||
|
@ -18,33 +18,29 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||
*/
|
||||
sinqAxis(class sinqController *pC_, int axisNo);
|
||||
|
||||
/**
|
||||
* @brief This function is executed once during the very first poll.
|
||||
*
|
||||
* This function is executed at the very first poll after the IOC startup.
|
||||
If it returns anything else than 'asynSuccess', the function is evaluated
|
||||
again after 100 ms until it succeeds. Every 10 trials a warning is emitted.
|
||||
The default implementation just returns asynSuccess and is meant to be
|
||||
overwritten by concrete driver implementations.
|
||||
*
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus atFirstPoll();
|
||||
|
||||
/**
|
||||
* @brief Perform some standardized operation before and after the concrete
|
||||
`doPoll` implementation.
|
||||
*
|
||||
* Wrapper around doPoll which performs the following operations:
|
||||
Before calling doPoll:
|
||||
|
||||
- Try to execute atFirstPoll once (and retry, if that failed)
|
||||
|
||||
After calling doPoll:
|
||||
|
||||
- Reset motorStatusProblem_, motorStatusCommsError_ and motorMessageText_ if
|
||||
doPoll returned asynSuccess
|
||||
|
||||
- If the movement timeout watchdog has been started, check it.
|
||||
- Update the parameter library entry motorEnableRBV_ by calling isEnabled.
|
||||
- Run `callParamCallbacks`
|
||||
|
||||
- The flags `motorStatusHome_`, `motorStatusHomed_` and
|
||||
`motorStatusAtHome_` are set to their idle values (0, 1 and 1 respectively)
|
||||
in the `poll()` method once the homing procedure is finished. See the
|
||||
documentation of the `home()` method for more details.
|
||||
|
||||
- Run `callParamCallbacks()`
|
||||
|
||||
- Return the status of `doPoll`
|
||||
*
|
||||
* @param moving Forwarded to `doPoll`.
|
||||
@ -100,23 +96,42 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||
double maxVelocity, double acceleration);
|
||||
|
||||
/**
|
||||
* @brief Perform some standardized operation before and after the concrete
|
||||
`doHome` implementation.
|
||||
*
|
||||
* Wrapper around move which calculates the (absolute) target position and
|
||||
stores it in the parameter library. The target position in a homing maneuver
|
||||
is calculated as follows:
|
||||
* @brief Wrapper around doHome which handles the homing-related flags
|
||||
*
|
||||
* The homing procedure of the motor record is controlled by the following
|
||||
* parameter library flags:
|
||||
*
|
||||
* - `motorMoveToHome_`: Setting this flag to `1` indicates to EPICS that a
|
||||
homing procedure should start and can therefore be used to start homing from
|
||||
within the driver.
|
||||
|
||||
if abs(current position - high limit) > abs(current position - low limit)
|
||||
{
|
||||
high limit
|
||||
}
|
||||
else
|
||||
{
|
||||
low limit
|
||||
}
|
||||
* - `motorStatusHome_`: This flag should be set to `1` while the motor is
|
||||
actively moving toward its home position and to `0` when the home position
|
||||
is reached.
|
||||
*
|
||||
* - `motorStatusHomed_`: This flag should be set to `0` at the start of a
|
||||
homing command and to 1 once the home position is reached.
|
||||
*
|
||||
* - `motorStatusAtHome_`: This flag is similar to `motorStatusHomed_`, but
|
||||
in addition it should also be `1` when the motor is at its home position,
|
||||
but wasn't actively homed in order to get there.
|
||||
*
|
||||
* This function performs the following operations in the given order:
|
||||
*
|
||||
* - Call `doHome()` and forward the parameters
|
||||
*
|
||||
* - If `doHome()` returned asynSuccess: Set `motorStatusHome_` to `1`,
|
||||
`motorStatusHomed_` to `0` and `motorStatusAtHome_` to `0`.
|
||||
*
|
||||
* - If `doHome()` returned asynError: This means that the motor cannot be
|
||||
homed because the encoder is absolute. Set a corresponding error message,
|
||||
but return asynSuccess in order to avoid any automatic retries by asyn.
|
||||
|
||||
After that, it calls and returns doHome.
|
||||
* - If `doHome()` returned anything else: Forward the status.
|
||||
*
|
||||
* The flags `motorStatusHome_`, `motorStatusHomed_` and
|
||||
`motorStatusAtHome_` are set to their idle values (0, 1 and 1 respectively)
|
||||
in the `poll()` method once the homing procedure is finished.
|
||||
*
|
||||
* @param minVelocity Forwarded to `doHome`.
|
||||
* @param maxVelocity Forwarded to `doHome`.
|
||||
@ -131,7 +146,9 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||
|
||||
/**
|
||||
* @brief Implementation of the "proper", device-specific home method. This
|
||||
method should be implemented by a child class of sinqAxis.
|
||||
method should be implemented by a child class of sinqAxis. If the motor
|
||||
cannot be homed because it has an absolute encoder, this function should
|
||||
return asynError.
|
||||
*
|
||||
* @param minVelocity Minimum velocity VMIN from the motor record
|
||||
* @param maxVelocity Maximum velocity VMAX from the motor record
|
||||
@ -280,11 +297,13 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||
bool initial_poll_;
|
||||
int init_poll_counter_;
|
||||
|
||||
// Helper variables for movementTimeoutWatchdog
|
||||
// Internal variables used in the movement timeout watchdog
|
||||
time_t expectedArrivalTime_;
|
||||
time_t offsetMovTimeout_;
|
||||
double scaleMovTimeout_;
|
||||
bool watchdogMovActive_;
|
||||
// Store the motor target position for the movement time calculation
|
||||
double targetPosition_;
|
||||
|
||||
private:
|
||||
sinqController *pC_;
|
||||
|
@ -5,6 +5,32 @@
|
||||
#include "iocsh.h"
|
||||
#include "sinqAxis.h"
|
||||
#include <errlog.h>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
Contains all instances of turboPmacAxis which have been created and is used in
|
||||
the initialization hook function.
|
||||
*/
|
||||
static std::vector<sinqController *> controller;
|
||||
|
||||
/**
|
||||
* @brief Hook function to perform certain actions during the IOC initialization
|
||||
*
|
||||
* @param iState
|
||||
*/
|
||||
void sinqController::epicsInithookFunction(initHookState iState) {
|
||||
if (iState == initHookAfterIocRunning) {
|
||||
// Iterate through all axes of each and call the initialization method
|
||||
// on each one of them.
|
||||
for (std::vector<sinqController *>::iterator itC = controller.begin();
|
||||
itC != controller.end(); ++itC) {
|
||||
|
||||
sinqController *controller = *itC;
|
||||
controller->startPoller(controller->movingPollPeriod_,
|
||||
controller->idlePollPeriod_, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sinqController::sinqController(const char *portName,
|
||||
const char *ipPortConfigName, int numAxes,
|
||||
@ -15,15 +41,6 @@ sinqController::sinqController(const char *portName,
|
||||
// As described in the function documentation, an offset of 1 is
|
||||
// added for better readability of the configuration.
|
||||
numAxes + 1,
|
||||
/*
|
||||
4 Parameters are added in sinqController:
|
||||
- MOTOR_MESSAGE_TEXT
|
||||
- MOTOR_TARGET_POSITION
|
||||
- ENABLE_AXIS
|
||||
- ENABLE_AXIS_RBV
|
||||
- ENABLE_MOV_WATCHDOG
|
||||
- LIMITS_OFFSET
|
||||
*/
|
||||
NUM_MOTOR_DRIVER_PARAMS + NUM_SINQMOTOR_DRIVER_PARAMS +
|
||||
numExtraParams,
|
||||
0, // No additional interfaces beyond those in base class
|
||||
@ -40,6 +57,21 @@ sinqController::sinqController(const char *portName,
|
||||
// Initialization of all member variables
|
||||
lowLevelPortUser_ = nullptr;
|
||||
|
||||
// Initial values for the average timeout mechanism, can be overwritten
|
||||
// later by a FFI function
|
||||
comTimeoutWindow_ = 3600;
|
||||
maxNumberTimeouts_ = 60;
|
||||
timeoutEvents_ = {};
|
||||
|
||||
// Inform the user after 10 timeouts in a row (default value)
|
||||
maxSubsequentTimeouts_ = 10;
|
||||
maxSubsequentTimeoutsExceeded_ = false;
|
||||
|
||||
// Store the poll period information. The poller itself will be started
|
||||
// later (after the IOC is running in epicsInithookFunction)
|
||||
movingPollPeriod_ = movingPollPeriod;
|
||||
idlePollPeriod_ = idlePollPeriod;
|
||||
|
||||
// =========================================================================;
|
||||
|
||||
/*
|
||||
@ -48,10 +80,10 @@ sinqController::sinqController(const char *portName,
|
||||
*/
|
||||
pasynOctetSyncIO->connect(ipPortConfigName, 0, &lowLevelPortUser_, NULL);
|
||||
if (status != asynSuccess || lowLevelPortUser_ == nullptr) {
|
||||
errlogPrintf(
|
||||
"%s => line %d:\nFATAL ERROR (cannot connect to MCU controller).\n"
|
||||
"Terminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
||||
"connect to MCU controller).\n"
|
||||
"Terminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -64,38 +96,30 @@ sinqController::sinqController(const char *portName,
|
||||
createParam("MOTOR_MESSAGE_TEXT", asynParamOctet, &motorMessageText_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Internal parameter library entry which stores the movement target
|
||||
status = createParam("MOTOR_TARGET_POSITION", asynParamFloat64,
|
||||
&motorTargetPosition_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"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("MOTOR_ENABLE", asynParamInt32, &motorEnable_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"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("MOTOR_ENABLE_RBV", asynParamInt32, &motorEnableRBV_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -103,9 +127,10 @@ sinqController::sinqController(const char *portName,
|
||||
createParam("MOTOR_CAN_DISABLE", asynParamInt32, &motorCanDisable_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -113,9 +138,10 @@ sinqController::sinqController(const char *portName,
|
||||
createParam("MOTOR_CAN_SET_SPEED", asynParamInt32, &motorCanSetSpeed_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -123,9 +149,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorLimitsOffset_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -138,9 +165,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorHighLimitFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -148,9 +176,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorLowLimitFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -158,9 +187,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorEnableMovWatchdog_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -168,9 +198,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorVeloFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -178,9 +209,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorVbasFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -188,9 +220,10 @@ sinqController::sinqController(const char *portName,
|
||||
&motorVmaxFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@ -198,31 +231,40 @@ sinqController::sinqController(const char *portName,
|
||||
&motorAcclFromDriver_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"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("ENCODER_TYPE", asynParamOctet, &encoderType_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Poller configuration
|
||||
status = startPoller(movingPollPeriod, idlePollPeriod, 1);
|
||||
status = createParam("MOTOR_FORCE_STOP", asynParamInt32, &motorForceStop_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nFATAL ERROR (starting the poller failed "
|
||||
"with %s).\nTerminating IOC",
|
||||
__PRETTY_FUNCTION__, __LINE__, stringifyAsynStatus(status));
|
||||
pasynOctetSyncIO->disconnect(lowLevelPortUser_);
|
||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||
"parameter failed with %s).\nTerminating IOC",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||
stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Register the hook function during construction of the first axis object
|
||||
if (controller.empty()) {
|
||||
initHookRegister(&epicsInithookFunction);
|
||||
}
|
||||
|
||||
// Collect all axes into this list which will be used in the hook function
|
||||
controller.push_back(this);
|
||||
}
|
||||
|
||||
sinqController::~sinqController(void) {
|
||||
@ -241,8 +283,9 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nAxis %d is not an instance of sinqAxis",
|
||||
__PRETTY_FUNCTION__, __LINE__, axis->axisNo_);
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
||||
"instance of sinqAxis",
|
||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
@ -255,27 +298,21 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||
}
|
||||
|
||||
asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||
|
||||
// Casting into a sinqAxis is necessary to get access to the field axisNo_
|
||||
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
||||
"instance of sinqAxis",
|
||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
if (pasynUser->reason == motorEnableRBV_) {
|
||||
// Read out the parameter library
|
||||
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nAxis %d is not an instance of sinqAxis",
|
||||
__PRETTY_FUNCTION__, __LINE__, axis->axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
return getIntegerParam(axis->axisNo_, motorEnableRBV_, value);
|
||||
} else if (pasynUser->reason == motorCanDisable_) {
|
||||
// Check if the motor can be disabled
|
||||
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nAxis %d is not an instance of sinqAxis",
|
||||
__PRETTY_FUNCTION__, __LINE__, axis->axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
return getIntegerParam(axis->axisNo_, motorCanDisable_, value);
|
||||
} else {
|
||||
return asynMotorController::readInt32(pasynUser, value);
|
||||
@ -290,21 +327,21 @@ asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
|
||||
asynStatus pl_status = asynSuccess;
|
||||
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nCould not interpret response '%s' for "
|
||||
"command %s.\n",
|
||||
functionName, lineNumber, response, command);
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
|
||||
"response \"%s\" for command \"%s\".\n",
|
||||
portName, axisNo, functionName, lineNumber, response, command);
|
||||
|
||||
pl_status = setStringParam(
|
||||
motorMessageText_,
|
||||
"Could not interpret MCU response. Please call the support");
|
||||
"Could not interpret controller response. Please call the support");
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
return paramLibAccessFailed(pl_status, "motorMessageText_", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
pl_status = setIntegerParam(motorStatusCommsError_, 1);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
@ -313,6 +350,7 @@ asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
|
||||
|
||||
asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
||||
const char *parameter,
|
||||
int axisNo,
|
||||
const char *functionName,
|
||||
int lineNumber) {
|
||||
|
||||
@ -320,9 +358,9 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
||||
// Log the error message and try to propagate it. If propagating fails,
|
||||
// there is nothing we can do here anyway.
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\n Accessing the parameter library failed for "
|
||||
"parameter %s with error %s.\n",
|
||||
functionName, lineNumber, parameter,
|
||||
"Controller \"%s\", axis %d => %s, line %d:\n Accessing the "
|
||||
"parameter library failed for parameter %s with error %s.\n",
|
||||
portName, axisNo, functionName, lineNumber, parameter,
|
||||
stringifyAsynStatus(status));
|
||||
setStringParam(motorMessageText_,
|
||||
"Accessing paramLib failed. Please call the support.");
|
||||
@ -331,6 +369,125 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus sinqController::checkComTimeoutWatchdog(int axisNo,
|
||||
char *motorMessage,
|
||||
size_t motorMessageSize) {
|
||||
|
||||
asynStatus paramLibStatus = asynSuccess;
|
||||
|
||||
// Add a new timeout event to the queue
|
||||
timeoutEvents_.push_back(time(NULL));
|
||||
|
||||
// Remove every event which is older than the time window from the deque
|
||||
while (1) {
|
||||
if (timeoutEvents_.empty()) {
|
||||
break;
|
||||
}
|
||||
if (timeoutEvents_[0] + comTimeoutWindow_ <= time(NULL)) {
|
||||
timeoutEvents_.pop_front();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the maximum allowed number of events has been exceeded
|
||||
if (timeoutEvents_.size() > maxNumberTimeouts_) {
|
||||
|
||||
snprintf(motorMessage, motorMessageSize,
|
||||
"More than %ld communication timeouts in %ld seconds. Please "
|
||||
"call the support.",
|
||||
maxNumberTimeouts_, comTimeoutWindow_);
|
||||
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
|
||||
"communication timeouts in %ld "
|
||||
"seconds\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||
maxNumberTimeouts_, comTimeoutWindow_);
|
||||
|
||||
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus,
|
||||
"motorStatusCommsError_", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
return asynError;
|
||||
} else {
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus sinqController::checkComTimeoutWatchdog(sinqAxis *axis) {
|
||||
|
||||
char motorMessage[200] = {0};
|
||||
|
||||
asynStatus status =
|
||||
checkComTimeoutWatchdog(axis->axisNo_, motorMessage, 200);
|
||||
if (status == asynError) {
|
||||
status = axis->setStringParam(motorMessageText_, motorMessage);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorMessageText_",
|
||||
axis->axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
|
||||
char *motorMessage,
|
||||
size_t motorMessageSize) {
|
||||
asynStatus paramLibStatus = asynSuccess;
|
||||
|
||||
if (timeoutNo >= maxSubsequentTimeouts_) {
|
||||
if (!maxSubsequentTimeoutsExceeded_) {
|
||||
snprintf(motorMessage, motorMessageSize,
|
||||
"Communication timeout between IOC and motor controller. "
|
||||
"Trying to reconnect ...");
|
||||
asynPrint(
|
||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nMore than %d "
|
||||
"subsequent communication "
|
||||
"timeouts\n",
|
||||
this->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||
maxSubsequentTimeouts_);
|
||||
|
||||
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus,
|
||||
"motorStatusCommsError_", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
maxSubsequentTimeoutsExceeded_ = true;
|
||||
}
|
||||
|
||||
return asynError;
|
||||
} else {
|
||||
maxSubsequentTimeoutsExceeded_ = false;
|
||||
motorMessage[0] = '\0';
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo,
|
||||
sinqAxis *axis) {
|
||||
|
||||
char motorMessage[200] = {0};
|
||||
|
||||
asynStatus status =
|
||||
checkMaxSubsequentTimeouts(axis->axisNo_, timeoutNo, motorMessage, 200);
|
||||
if (status == asynError) {
|
||||
status = axis->setStringParam(motorMessageText_, motorMessage);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorMessageText_",
|
||||
axis->axisNo_, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Static pointers (valid for the entire lifetime of the IOC). The number behind
|
||||
// the strings gives the integer number of each variant (see also method
|
||||
// stringifyAsynStatus)
|
||||
@ -386,161 +543,131 @@ const char *sinqController::stringifyAsynStatus(asynStatus status) {
|
||||
return asynParamInvalidListStringified;
|
||||
}
|
||||
|
||||
asynPrint(
|
||||
pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nInput did not match any variant of asynStatus.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s, line %d:\nInput did not match any "
|
||||
"variant of asynStatus.\n",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
return inputDidNotMatchAsynStatus;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Provide the setters to IOC shell
|
||||
// IOC shell functions
|
||||
extern "C" {
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Enable / disable the watchdog (FFI implementation)
|
||||
* @brief Set the threshold for the communication timeout frequency (FFI
|
||||
* implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param enable If 0, disable the watchdog, otherwise enable
|
||||
* it
|
||||
* @param comTimeoutWindow Size of the time window used to calculate
|
||||
* the moving average of timeout events. Set this value to 0 to deactivate
|
||||
* the watchdog.
|
||||
* @param maxNumberTimeouts Maximum number of timeouts which may occur
|
||||
* within the time window before the watchdog is triggered.
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setWatchdogEnabled(const char *portName, int axisNo, int enable) {
|
||||
asynStatus setThresholdComTimeout(const char *portName, int comTimeoutWindow,
|
||||
int maxNumberTimeouts) {
|
||||
|
||||
sinqController *pC;
|
||||
pC = (sinqController *)findAsynPortDriver(portName);
|
||||
if (pC == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nPort %s not found.", __PRETTY_FUNCTION__,
|
||||
__LINE__, portName);
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nPort %s not found.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynMotorAxis *asynAxis = pC->getAxis(axisNo);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nAxis %d does not exist or is not an "
|
||||
"instance of sinqAxis.",
|
||||
__PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
}
|
||||
|
||||
return axis->setWatchdogEnabled(enable != 0);
|
||||
return pC->setThresholdComTimeout(comTimeoutWindow, maxNumberTimeouts);
|
||||
}
|
||||
|
||||
static const iocshArg setWatchdogEnabledArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setWatchdogEnabledArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setWatchdogEnabledArg2 = {
|
||||
"Enabling / disabling the watchdog", iocshArgInt};
|
||||
static const iocshArg *const setWatchdogEnabledArgs[] = {
|
||||
&setWatchdogEnabledArg0, &setWatchdogEnabledArg1, &setWatchdogEnabledArg2};
|
||||
static const iocshFuncDef setWatchdogEnabledDef = {"setWatchdogEnabled", 3,
|
||||
setWatchdogEnabledArgs};
|
||||
static const iocshArg setThresholdComTimeoutArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setThresholdComTimeoutArg1 = {
|
||||
"Time window communication timeout frequency", iocshArgInt};
|
||||
static const iocshArg setThresholdComTimeoutArg2 = {
|
||||
"Maximum allowed number of communication timeouts within the window",
|
||||
iocshArgInt};
|
||||
static const iocshArg *const setThresholdComTimeoutArgs[] = {
|
||||
&setThresholdComTimeoutArg0, &setThresholdComTimeoutArg1,
|
||||
&setThresholdComTimeoutArg2};
|
||||
static const iocshFuncDef setThresholdComTimeoutDef = {
|
||||
"setThresholdComTimeout", 3, setThresholdComTimeoutArgs};
|
||||
|
||||
static void setWatchdogEnabledCallFunc(const iocshArgBuf *args) {
|
||||
setWatchdogEnabled(args[0].sval, args[1].ival, args[2].ival);
|
||||
static void setThresholdComTimeoutCallFunc(const iocshArgBuf *args) {
|
||||
setThresholdComTimeout(args[0].sval, args[1].ival, args[2].ival);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the offsetMovTimeout (FFI implementation)
|
||||
* @brief Set the maximum number of subsequent timeouts (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param offsetMovTimeout Offset (in seconds)
|
||||
* @param comTimeoutWindow Size of the time window used to calculate
|
||||
* the moving average of timeout events. Set this value to 0 to deactivate
|
||||
* the watchdog.
|
||||
* @param maxNumberTimeouts Maximum number of timeouts which may occur
|
||||
* within the time window before the watchdog is triggered.
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setOffsetMovTimeout(const char *portName, int axisNo,
|
||||
double offsetMovTimeout) {
|
||||
asynStatus setMaxSubsequentTimeouts(const char *portName,
|
||||
int maxSubsequentTimeouts) {
|
||||
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't
|
||||
have a lowLevelPortUser_! printf is an EPICS alternative which
|
||||
works w/o that, but doesn't offer the comfort provided
|
||||
by the asynTrace-facility
|
||||
*/
|
||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nPort %s not found.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, portName);
|
||||
return asynError;
|
||||
}
|
||||
// Unsafe cast of the pointer to an asynPortDriver
|
||||
asynPortDriver *apd = (asynPortDriver *)(ptr);
|
||||
|
||||
sinqController *pC;
|
||||
pC = (sinqController *)findAsynPortDriver(portName);
|
||||
// Safe downcast
|
||||
sinqController *pC = dynamic_cast<sinqController *>(apd);
|
||||
if (pC == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nPort %s not found.", __PRETTY_FUNCTION__,
|
||||
__LINE__, portName);
|
||||
errlogPrintf(
|
||||
"Controller \"%s\" => %s, line %d:\ncontroller on port %s is not a "
|
||||
"turboPmacController.",
|
||||
portName, __PRETTY_FUNCTION__, __LINE__, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynMotorAxis *asynAxis = pC->getAxis(axisNo);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nAxis %d does not exist or is not an "
|
||||
"instance of sinqAxis.",
|
||||
__PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
}
|
||||
// Set the new value
|
||||
pC->setMaxSubsequentTimeouts(maxSubsequentTimeouts);
|
||||
|
||||
return axis->setOffsetMovTimeout(offsetMovTimeout);
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
static const iocshArg setOffsetMovTimeoutArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setOffsetMovTimeoutArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setOffsetMovTimeoutArg2 = {"Offset timeout for movement",
|
||||
iocshArgDouble};
|
||||
static const iocshArg *const setOffsetMovTimeoutArgs[] = {
|
||||
&setOffsetMovTimeoutArg0, &setOffsetMovTimeoutArg1,
|
||||
&setOffsetMovTimeoutArg2};
|
||||
static const iocshFuncDef setOffsetMovTimeoutDef = {"setOffsetMovTimeout", 3,
|
||||
setOffsetMovTimeoutArgs};
|
||||
|
||||
static void setOffsetMovTimeoutCallFunc(const iocshArgBuf *args) {
|
||||
setOffsetMovTimeout(args[0].sval, args[1].ival, args[2].dval);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* @brief Set the setScaleMovTimeout (FFI implementation)
|
||||
*
|
||||
* @param portName Name of the controller
|
||||
* @param axisNo Axis number
|
||||
* @param scaleMovTimeout Scaling factor (in seconds)
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setScaleMovTimeout(const char *portName, int axisNo,
|
||||
double scaleMovTimeout) {
|
||||
|
||||
sinqController *pC;
|
||||
pC = (sinqController *)findAsynPortDriver(portName);
|
||||
if (pC == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nPort %s not found.", __PRETTY_FUNCTION__,
|
||||
__LINE__, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynMotorAxis *asynAxis = pC->getAxis(axisNo);
|
||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||
if (axis == nullptr) {
|
||||
errlogPrintf("%s => line %d:\nAxis %d does not exist or is not an "
|
||||
"instance of sinqAxis.",
|
||||
__PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||
}
|
||||
|
||||
return axis->setScaleMovTimeout(scaleMovTimeout);
|
||||
}
|
||||
|
||||
static const iocshArg setScaleMovTimeoutArg0 = {"Controller port name",
|
||||
iocshArgString};
|
||||
static const iocshArg setScaleMovTimeoutArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg setScaleMovTimeoutArg2 = {
|
||||
"Multiplier for calculated move time", iocshArgDouble};
|
||||
static const iocshArg *const setScaleMovTimeoutArgs[] = {
|
||||
&setScaleMovTimeoutArg0, &setScaleMovTimeoutArg1, &setScaleMovTimeoutArg2};
|
||||
static const iocshFuncDef setScaleMovTimeoutDef = {"setScaleMovTimeout", 3,
|
||||
setScaleMovTimeoutArgs};
|
||||
|
||||
static void setScaleMovTimeoutCallFunc(const iocshArgBuf *args) {
|
||||
setScaleMovTimeout(args[0].sval, args[1].ival, args[2].dval);
|
||||
static const iocshArg SetMaxSubsequentTimeoutsArg0 = {
|
||||
"Controller name (e.g. mcu1)", iocshArgString};
|
||||
static const iocshArg SetMaxSubsequentTimeoutsArg1 = {
|
||||
"Maximum number of subsequent timeouts before the user receives an error "
|
||||
"message",
|
||||
iocshArgInt};
|
||||
static const iocshArg *const SetMaxSubsequentTimeoutsArgs[] = {
|
||||
&SetMaxSubsequentTimeoutsArg0, &SetMaxSubsequentTimeoutsArg1};
|
||||
static const iocshFuncDef setMaxSubsequentTimeoutsDef = {
|
||||
"setMaxSubsequentTimeouts", 2, SetMaxSubsequentTimeoutsArgs};
|
||||
static void setMaxSubsequentTimeoutsCallFunc(const iocshArgBuf *args) {
|
||||
setMaxSubsequentTimeouts(args[0].sval, args[1].ival);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// This function is made known to EPICS in sinqMotor.dbd and is called by EPICS
|
||||
// in order to register all functions in the IOC shell
|
||||
static void sinqControllerRegister(void) {
|
||||
iocshRegister(&setOffsetMovTimeoutDef, setOffsetMovTimeoutCallFunc);
|
||||
iocshRegister(&setScaleMovTimeoutDef, setScaleMovTimeoutCallFunc);
|
||||
iocshRegister(&setWatchdogEnabledDef, setWatchdogEnabledCallFunc);
|
||||
iocshRegister(&setThresholdComTimeoutDef, setThresholdComTimeoutCallFunc);
|
||||
iocshRegister(&setMaxSubsequentTimeoutsDef,
|
||||
setMaxSubsequentTimeoutsCallFunc);
|
||||
}
|
||||
epicsExportRegistrar(sinqControllerRegister);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
This class extends asynMotorController by some features used in SINQ.
|
||||
This class extends asynMotorController by some features used in SINQ. See the
|
||||
README.md for details.
|
||||
|
||||
Stefan Mathis, November 2024
|
||||
*/
|
||||
@ -7,6 +8,8 @@ Stefan Mathis, November 2024
|
||||
#ifndef __sinqController
|
||||
#define __sinqController
|
||||
#include "asynMotorController.h"
|
||||
#include <deque>
|
||||
#include <initHooks.h>
|
||||
|
||||
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
||||
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
||||
@ -90,7 +93,8 @@ class epicsShareClass sinqController : public asynMotorController {
|
||||
* @return asynStatus Returns input status.
|
||||
*/
|
||||
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter,
|
||||
const char *functionName, int lineNumber);
|
||||
int axisNo, const char *functionName,
|
||||
int lineNumber);
|
||||
|
||||
/**
|
||||
* @brief Error handling in case parsing a command response failed.
|
||||
@ -122,20 +126,122 @@ class epicsShareClass sinqController : public asynMotorController {
|
||||
*/
|
||||
const char *stringifyAsynStatus(asynStatus status);
|
||||
|
||||
/**
|
||||
* @brief This function should be called when a communication timeout
|
||||
occured. It calculates the frequency of communication timeout events and
|
||||
creates an error message, if an threshold has been exceeded.
|
||||
*
|
||||
Occasionally, communication timeouts between the IOC and the motor
|
||||
controller may happen, usually because the controller takes too long to
|
||||
respond. If this happens infrequently, this is not a problem. However, if it
|
||||
happens very often, this may indicate a network problem and must therefore
|
||||
be forwarded to the user. This is checked by calculating the moving average
|
||||
of events and comparing it to a threshhold. Both the threshold and the time
|
||||
window for the moving average can be configured in the IOC via the function
|
||||
setThresholdCom.
|
||||
|
||||
This function exists in two variants: Either the error message can be
|
||||
written into a buffer provided by the caller or it written directly into the
|
||||
parameter library of the provided axis.
|
||||
|
||||
* @param axis Axis to which the error message is sent
|
||||
*
|
||||
* @return asynStatus asynError, if the threshold has been
|
||||
exceeded, asynSuccess otherwise
|
||||
*/
|
||||
virtual asynStatus checkComTimeoutWatchdog(class sinqAxis *axis);
|
||||
|
||||
/**
|
||||
* @brief See documentation of checkComTimeoutWatchdog(sinqAxis * axis)
|
||||
*
|
||||
* @param userMessage Buffer for the user message
|
||||
* @param userMessageSize Buffer size in chars
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus checkComTimeoutWatchdog(int axisNo, char *motorMessage,
|
||||
size_t motorMessageSize);
|
||||
|
||||
/**
|
||||
* @brief Set the threshold for the communication timeout mechanism
|
||||
*
|
||||
* @param comTimeoutWindow Size of the time window used to calculate
|
||||
* the moving average of timeout events. Set this value to 0 to deactivate
|
||||
* the watchdog.
|
||||
* @param maxNumberTimeouts Maximum number of timeouts which may occur
|
||||
* within the time window before the watchdog is triggered.
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus setThresholdComTimeout(time_t comTimeoutWindow,
|
||||
size_t maxNumberTimeouts) {
|
||||
comTimeoutWindow_ = comTimeoutWindow;
|
||||
maxNumberTimeouts_ = maxNumberTimeouts;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inform the user, if the number of timeouts exceeds the threshold
|
||||
* specified with setMaxSubsequentTimeouts
|
||||
*
|
||||
* @param timeoutNo Number of subsequent timeouts which already
|
||||
* happened.
|
||||
* @param axis
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus checkMaxSubsequentTimeouts(int timeoutNo,
|
||||
class sinqAxis *axis);
|
||||
|
||||
/**
|
||||
* @brief See documentation of checkMaxSubsequentTimeouts(sinqAxis * axis)
|
||||
*
|
||||
* @param userMessage Buffer for the user message
|
||||
* @param userMessageSize Buffer size in chars
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
|
||||
char *motorMessage,
|
||||
size_t motorMessageSize);
|
||||
|
||||
/**
|
||||
* @brief Set the maximum number of subsequent timeouts before the user is
|
||||
* informed.
|
||||
*
|
||||
* @param maxSubsequentTimeouts
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus setMaxSubsequentTimeouts(int maxSubsequentTimeouts) {
|
||||
maxSubsequentTimeouts_ = maxSubsequentTimeouts;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
friend class sinqAxis;
|
||||
|
||||
protected:
|
||||
asynUser *lowLevelPortUser_;
|
||||
|
||||
double movingPollPeriod_;
|
||||
double idlePollPeriod_;
|
||||
|
||||
// Internal variables used in the communication timeout frequency watchdog
|
||||
time_t comTimeoutWindow_; // Size of the time window
|
||||
size_t maxNumberTimeouts_; // Maximum acceptable number of events within the
|
||||
// time window
|
||||
std::deque<time_t>
|
||||
timeoutEvents_; // Deque holding the timestamps of the individual events
|
||||
|
||||
// Communicate a timeout to the user after it has happened this many times
|
||||
// in a row
|
||||
int maxSubsequentTimeouts_;
|
||||
bool maxSubsequentTimeoutsExceeded_;
|
||||
|
||||
#define FIRST_SINQMOTOR_PARAM motorMessageText_
|
||||
int motorMessageText_;
|
||||
int motorTargetPosition_;
|
||||
int motorEnable_;
|
||||
int motorEnableRBV_;
|
||||
int motorCanDisable_;
|
||||
int motorEnableMovWatchdog_;
|
||||
int motorCanSetSpeed_;
|
||||
int motorLimitsOffset_;
|
||||
int motorForceStop_;
|
||||
/*
|
||||
These parameters are here to write values from the hardware to the EPICS
|
||||
motor record. Using motorHighLimit_ / motorLowLimit_ does not work:
|
||||
@ -151,6 +257,9 @@ class epicsShareClass sinqController : public asynMotorController {
|
||||
int motorLowLimitFromDriver_;
|
||||
int encoderType_;
|
||||
#define LAST_SINQMOTOR_PARAM encoderType_
|
||||
|
||||
private:
|
||||
static void epicsInithookFunction(initHookState iState);
|
||||
};
|
||||
#define NUM_SINQMOTOR_DRIVER_PARAMS \
|
||||
(&LAST_SINQMOTOR_PARAM - &FIRST_SINQMOTOR_PARAM + 1)
|
||||
|
@ -2,3 +2,4 @@
|
||||
# SINQ specific DB definitions
|
||||
#---------------------------------------------
|
||||
registrar(sinqControllerRegister)
|
||||
registrar(sinqAxisRegister)
|
||||
|
Reference in New Issue
Block a user