From 9bc90cff619d16bee710557b39fbf1d26f1f29f5 Mon Sep 17 00:00:00 2001 From: smathis Date: Wed, 14 May 2025 15:49:37 +0200 Subject: [PATCH] Simplified paramLib access and show error messages for one poll cycle Simplified getting and setting paramLib entries via a macro and created a mechanism within poll() which makes sure that error messages are shown for at least one poll cycle. Also moved MAXBUF_ to the SinqController level. --- README.md | 5 ++-- src/sinqAxis.cpp | 54 ++++++++++++++++++++++++++---------------- src/sinqAxis.h | 32 ------------------------- src/sinqController.cpp | 22 +++++------------ src/sinqController.h | 5 ++++ 5 files changed, 48 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 9db5ed6..607c787 100644 --- a/README.md +++ b/README.md @@ -233,13 +233,14 @@ It calls `doReset` and performs some fast polls after `doReset` returns. - `poll`: This is a wrapper around `doPoll` which performs some bookkeeping tasks before and after calling `doPoll`: Before calling `doPoll`: - - Reset the status problem flag, the communication error flag and the error message. + - Check if the paramLib already contains an old error message. If so, put it into a temporary bufffer After calling `doPoll`: - Call `checkMovTimeoutWatchdog`. If the movement timed out, create an error message for the user - Update the readback-value for the axis enablement. - - Reset `motorStatusProblem_`, `motorStatusCommsError_` and `motorMessageText_` if `doPoll` returned `asynSuccess` + - If `doPoll` returns anything other than `asynSuccess` or if an old error message is waiting in the temporary buffer, set `motorStatusProblem` to true, otherwise to false. If an old error message is waiting in the temporary buffer, but `doPoll` returned `asynSuccess`, overwrite the paramLib entry for `motorMessageText` with the old error message. - Run `callParamCallbacks` + - Reset `motorMessageText` AFTER updating the PVs. This makes sure that the error message is shown for at least one poll cycle. - Return the status of `doPoll` - `motorPosition`: Returns the parameter library value of the motor position, accounted for the motor record resolution (see section "Motor record resolution MRES") - `setMotorPosition`: Writes the given value into the parameter library, accounted for the motor record resolution (see section "Motor record resolution MRES") diff --git a/src/sinqAxis.cpp b/src/sinqAxis.cpp index 3b4310d..de89666 100644 --- a/src/sinqAxis.cpp +++ b/src/sinqAxis.cpp @@ -100,7 +100,7 @@ asynStatus getAxisParam(sinqAxis *axis, const char *indexName, int (sinqController::*func)(), char *readValue, const char *callerFunctionName, int lineNumber) { - int maxChars = 190; + int maxChars = 200; int indexValue = (axis->pController()->*func)(); asynStatus status = axis->pController()->getStringParam( @@ -259,6 +259,8 @@ asynStatus sinqAxis::poll(bool *moving) { asynStatus poll_status = asynSuccess; int homing = 0; int adaptivePolling = 0; + char waitingMessage[pC_->MAXBUF_] = {0}; + char newMessage[pC_->MAXBUF_] = {0}; /* If adaptive polling is enabled: @@ -300,35 +302,42 @@ asynStatus sinqAxis::poll(bool *moving) { lastPollTime_ = ts; /* - At the beginning of the poll, it is assumed that the axis has no status - problems and therefore all error indicators are reset. This does not affect - the PVs until callParamCallbacks has been called! - - The motorStatusProblem_ field changes the motor record fields SEVR and STAT. + If the "motorMessageText" record currently contains an error message, it + should be shown for at least one poll period. To assure this, it is read out + here from the paramLib into "waitingMessage". If no new error message was + added to the parameter library at the end of the poll cycle, the + "waitingMessage" is briefly put into the paramLib again, then the PVs are + updated and then the message text is cleared again. */ - setAxisParamChecked(this, motorStatusCommsError, false); - setAxisParamChecked(this, motorMessageText, ""); + getAxisParamChecked(this, motorMessageText, &waitingMessage); - // The poll function is just a wrapper around doPoll and - // handles mainly the callParamCallbacks() function. This wrapper is used - // to make sure callParamCallbacks() is called in case of a premature - // return. + // Clear the communication + setAxisParamChecked(this, motorStatusCommsError, false); + + /* + The poll function is just a wrapper around doPoll and handles mainly the + callParamCallbacks() function. This wrapper is used to make sure + callParamCallbacks() is called in case of a premature return. + */ poll_status = doPoll(moving); - // If the poll did not succeed, something went wrong and the motor has a - // status problem. - if (poll_status == asynSuccess) { - setAxisParamChecked(this, motorStatusProblem, false); - } else { + /* + If the poll did not succeed OR if an error message is waiting, something + went wrong and the motor has a status problem. Otherwise, delete the error + message entry which is currently in the paramLib. + */ + if (poll_status != asynSuccess || waitingMessage[0] != '\0') { setAxisParamChecked(this, motorStatusProblem, true); + } else { + setAxisParamChecked(this, motorMessageText, ""); + setAxisParamChecked(this, motorStatusProblem, false); } - getAxisParamChecked(this, motorStatusHome, &homing); - /* Motor is in homing mode, was moving, but is not moving anymore -> It can be assumed that the homing procedure is done. */ + getAxisParamChecked(this, motorStatusHome, &homing); if (homing == 1 && !(*moving) && wasMoving_) { setAxisParamChecked(this, motorStatusHome, false); setAxisParamChecked(this, motorStatusHomed, true); @@ -363,6 +372,12 @@ asynStatus sinqAxis::poll(bool *moving) { poll_status = pl_status; } + /* + Delete the error message AFTER updating the PVs so it is not there anymore + during the next poll. + */ + setAxisParamChecked(this, motorMessageText, ""); + return poll_status; } @@ -416,7 +431,6 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity, if (status == asynSuccess) { - setAxisParamChecked(this, motorMessageText, "Reference drive"); setAxisParamChecked(this, motorStatusHome, true); setAxisParamChecked(this, motorStatusHomed, false); setAxisParamChecked(this, motorStatusAtHome, false); diff --git a/src/sinqAxis.h b/src/sinqAxis.h index b13d72c..59e3596 100644 --- a/src/sinqAxis.h +++ b/src/sinqAxis.h @@ -500,40 +500,8 @@ asynStatus getAxisParam(sinqAxis *axis, const char *indexName, * return asynSuccess; * } * ``` - * - * If `readValue` is a `char *`, the size of the buffer needs to be provided as - * well: - * ``` - * char readValue[20] = {0}; - * getAxisParamChecked(this, motorStatusProblem_, &readValue, sizeof(readValue)) - * ``` - * expands to - * ``` - * { - * int indexValue = axis->pController()->motorStatusProblem_(); - * asynStatus status = axis->pController()->getStringParam(axis->axisNo(), - * indexValue, sizeof(readValue), readValue); if (status != asynSuccess) { - * return axis->pController()->paramLibAccessFailed( status, - * "motorStatusProblem_", axis->axisNo(), __PRETTY_FUNCTION__, - * __LINE__); - * } - * return asynSuccess; - * } - * ``` * ============================================================================= */ -// #define getAxisParamChecked(axis, indexGetterFunction, readValue, ...) \ -// { \ -// asynStatus getStatus = getAxisParam( \ -// axis, #indexGetterFunction, \ -// &std::remove_pointer< \ -// decltype(axis->pController())>::type::indexGetterFunction, \ -// readValue, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); \ -// if (getStatus != asynSuccess) { \ -// return getStatus; \ -// } \ -// } - #define getAxisParamChecked(axis, indexGetterFunction, readValue) \ { \ asynStatus getStatus = getAxisParam( \ diff --git a/src/sinqController.cpp b/src/sinqController.cpp index 7f67585..2da6b7b 100644 --- a/src/sinqController.cpp +++ b/src/sinqController.cpp @@ -490,17 +490,12 @@ asynStatus sinqController::checkComTimeoutWatchdog(int axisNo, asynStatus sinqController::checkComTimeoutWatchdog(sinqAxis *axis) { - char motorMessage[200] = {0}; + char errorMessage[MAXBUF_] = {0}; asynStatus status = - checkComTimeoutWatchdog(axis->axisNo(), motorMessage, 200); + checkComTimeoutWatchdog(axis->axisNo(), errorMessage, MAXBUF_); if (status == asynError) { - status = axis->setStringParam(motorMessageText_, motorMessage); - if (status != asynSuccess) { - return paramLibAccessFailed(status, "motorMessageText_", - axis->axisNo(), __PRETTY_FUNCTION__, - __LINE__); - } + setAxisParamChecked(axis, motorMessageText, motorMessage); } return status; } @@ -543,17 +538,12 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo, asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, sinqAxis *axis) { - char motorMessage[200] = {0}; + char motorMessage[MAXBUF_] = {0}; asynStatus status = checkMaxSubsequentTimeouts(timeoutNo, axis->axisNo(), - motorMessage, 200); + motorMessage, MAXBUF_); if (status == asynError) { - status = axis->setStringParam(motorMessageText_, motorMessage); - if (status != asynSuccess) { - return paramLibAccessFailed(status, "motorMessageText_", - axis->axisNo(), __PRETTY_FUNCTION__, - __LINE__); - } + setAxisParamChecked(axis, motorMessageText, motorMessage); } return status; } diff --git a/src/sinqController.h b/src/sinqController.h index e7e4abf..6c2aad9 100644 --- a/src/sinqController.h +++ b/src/sinqController.h @@ -376,6 +376,11 @@ class epicsShareClass sinqController : public asynMotorController { */ int outstandingForcedFastPolls() { return outstandingForcedFastPolls_; } + // Maximum error message buffer size. This is an empirical value which must + // be large enough to avoid overflows for all commands to the device / + // responses from it. + static const uint32_t MAXBUF_ = 200; + // ========================================================================= protected: