Added msgPrintControl feature to control the maximum number of IOC shell

message repetitions.
This commit is contained in:
2025-03-04 09:12:11 +01:00
parent 591509bd43
commit d3307db987
7 changed files with 92 additions and 82 deletions

View File

@@ -10,9 +10,7 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
: asynMotorAxis((asynMotorController *)pC, axisNo), pC_(pC) {
asynStatus status = asynSuccess;
initial_poll_ = true;
watchdogMovActive_ = false;
init_poll_counter_ = 0;
scaleMovTimeout_ = 2.0;
offsetMovTimeout_ = 30;
targetPosition_ = 0.0;
@@ -188,14 +186,18 @@ asynStatus sinqAxis::poll(bool *moving) {
// 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
bool wantToPrint = pl_status != asynSuccess;
if (pC_->msgPrintControl_.shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, wantToPrint,
pC_->pasynUserSelf)) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\ncallParamCallbacks failed with %s.\n",
"%d:\ncallParamCallbacks failed with %s.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(poll_status));
pC_->stringifyAsynStatus(poll_status),
pC_->msgPrintControl_.getSuffix());
}
if (wantToPrint) {
poll_status = pl_status;
}

View File

@@ -4,8 +4,8 @@ This class extends asynMotorAxis by some features used in SINQ.
Stefan Mathis, November 2024
*/
#ifndef __SINQDRIVER
#define __SINQDRIVER
#ifndef sinqAxis_H
#define sinqAxis_H
#include "asynMotorAxis.h"
class epicsShareClass sinqAxis : public asynMotorAxis {
@@ -294,9 +294,6 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
friend class sinqController;
protected:
bool initial_poll_;
int init_poll_counter_;
// Internal variables used in the movement timeout watchdog
time_t expectedArrivalTime_;
time_t offsetMovTimeout_;

View File

@@ -46,15 +46,11 @@ sinqController::sinqController(const char *portName,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0,
0) // Default priority and stack size
{
1, // autoconnect
0, 0), // Default priority and stack size
msgPrintControl_(4) {
// Initialization of local variables
asynStatus status = asynSuccess;
// Initialization of all member variables
lowLevelPortUser_ = nullptr;
// Initial values for the average timeout mechanism, can be overwritten
@@ -103,17 +99,6 @@ sinqController::sinqController(const char *portName,
exit(-1);
}
status = createParam("MOTOR_TARGET_POSITION", asynParamFloat64,
&motorTargetPosition_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
"parameter failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
exit(-1);
}
status = createParam("MOTOR_ENABLE", asynParamInt32, &motorEnable_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
@@ -285,6 +270,10 @@ sinqController::~sinqController(void) {
free(this->pAxes_);
}
msgPrintControl &sinqController::getMsgPrintControl() {
return msgPrintControl_;
}
asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
int function = pasynUser->reason;
@@ -292,6 +281,7 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
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 "
@@ -303,6 +293,8 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
// Handle custom PVs
if (function == motorEnable_) {
return axis->enable(value != 0);
} else if (function == motorForceStop_) {
return axis->stop(0.0);
} else {
return asynMotorController::writeInt32(pasynUser, value);
}
@@ -313,10 +305,11 @@ 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",
"instance of sinqAxis.\n",
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
@@ -334,13 +327,13 @@ asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
const char *response,
int axisNo,
const char *functionName,
int lineNumber) {
int line) {
asynStatus pl_status = asynSuccess;
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
"response \"%s\" for command \"%s\".\n",
portName, axisNo, functionName, lineNumber, response, command);
portName, axisNo, functionName, line, response, command);
pl_status = setStringParam(
motorMessageText_,
@@ -363,16 +356,17 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
const char *parameter,
int axisNo,
const char *functionName,
int lineNumber) {
int line) {
if (status != asynSuccess) {
// 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,
"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,
portName, axisNo, functionName, line, parameter,
stringifyAsynStatus(status));
// Log the error message and try to propagate it. If propagating fails,
// there is nothing we can do here anyway.
setStringParam(motorMessageText_,
"Accessing paramLib failed. Please call the support.");
}
@@ -402,20 +396,26 @@ asynStatus sinqController::checkComTimeoutWatchdog(int axisNo,
}
// Check if the maximum allowed number of events has been exceeded
if (timeoutEvents_.size() > maxNumberTimeouts_) {
bool wantToPrint = timeoutEvents_.size() > maxNumberTimeouts_;
if (msgPrintControl_.shouldBePrinted(portName, axisNo, __PRETTY_FUNCTION__,
__LINE__, wantToPrint,
pasynUserSelf)) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
"communication timeouts in %ld "
"seconds.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
maxNumberTimeouts_, comTimeoutWindow_,
msgPrintControl_.getSuffix());
}
if (wantToPrint) {
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,

View File

@@ -5,11 +5,13 @@ README.md for details.
Stefan Mathis, November 2024
*/
#ifndef __sinqController
#define __sinqController
#ifndef sinqController_H
#define sinqController_H
#include "asynMotorController.h"
#include "msgPrintControl.h"
#include <deque>
#include <initHooks.h>
#include <unordered_map>
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
@@ -88,13 +90,13 @@ class epicsShareClass sinqController : public asynMotorController {
error messages.
* @param functionName Name of the caller function. It is recommended
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
* @param lineNumber Source code line where this function is
* @param line Source code line where this function is
called. It is recommended to use a macro, e.g. __LINE__.
* @return asynStatus Returns input status.
*/
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter,
int axisNo, const char *functionName,
int lineNumber);
int line);
/**
* @brief Error handling in case parsing a command response failed.
@@ -109,14 +111,13 @@ class epicsShareClass sinqController : public asynMotorController {
* @param axisNo_ Axis where the problem occurred
* @param functionName Name of the caller function. It is recommended
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
* @param lineNumber Source code line where this function is
* @param line Source code line where this function is
called. It is recommended to use a macro, e.g. __LINE__.
* @return asynStatus Returns asynError.
*/
asynStatus errMsgCouldNotParseResponse(const char *command,
const char *response, int axisNo,
const char *functionName,
int lineNumber);
const char *functionName, int line);
/**
* @brief Convert an asynStatus into a descriptive string.
@@ -213,13 +214,22 @@ class epicsShareClass sinqController : public asynMotorController {
return asynSuccess;
}
/**
* @brief Get a reference to the map used to control the maximum number of
* message repetitions. See the documentation of printRepetitionWatchdog in
* msgPrintControl.h for details.
*
* @return std::unordered_map<msgPrintControlKey, size_t>&
*/
msgPrintControl &getMsgPrintControl();
friend class sinqAxis;
protected:
asynUser *lowLevelPortUser_;
double movingPollPeriod_;
double idlePollPeriod_;
msgPrintControl msgPrintControl_;
// Internal variables used in the communication timeout frequency watchdog
time_t comTimeoutWindow_; // Size of the time window
@@ -235,7 +245,6 @@ class epicsShareClass sinqController : public asynMotorController {
#define FIRST_SINQMOTOR_PARAM motorMessageText_
int motorMessageText_;
int motorTargetPosition_;
int motorEnable_;
int motorEnableRBV_;
int motorCanDisable_;