Bugfix for movTimeoutWatchdog
Update of README.md
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user