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.
This commit is contained in:
2025-05-14 15:49:37 +02:00
parent 9792697d03
commit 9bc90cff61
5 changed files with 48 additions and 70 deletions

View File

@ -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`: - `poll`: This is a wrapper around `doPoll` which performs some bookkeeping tasks before and after calling `doPoll`:
Before 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`: After calling `doPoll`:
- Call `checkMovTimeoutWatchdog`. If the movement timed out, create an error message for the user - Call `checkMovTimeoutWatchdog`. If the movement timed out, create an error message for the user
- Update the readback-value for the axis enablement. - 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` - 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` - 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") - `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") - `setMotorPosition`: Writes the given value into the parameter library, accounted for the motor record resolution (see section "Motor record resolution MRES")

View File

@ -100,7 +100,7 @@ asynStatus getAxisParam<char>(sinqAxis *axis, const char *indexName,
int (sinqController::*func)(), char *readValue, int (sinqController::*func)(), char *readValue,
const char *callerFunctionName, int lineNumber) { const char *callerFunctionName, int lineNumber) {
int maxChars = 190; int maxChars = 200;
int indexValue = (axis->pController()->*func)(); int indexValue = (axis->pController()->*func)();
asynStatus status = axis->pController()->getStringParam( asynStatus status = axis->pController()->getStringParam(
@ -259,6 +259,8 @@ asynStatus sinqAxis::poll(bool *moving) {
asynStatus poll_status = asynSuccess; asynStatus poll_status = asynSuccess;
int homing = 0; int homing = 0;
int adaptivePolling = 0; int adaptivePolling = 0;
char waitingMessage[pC_->MAXBUF_] = {0};
char newMessage[pC_->MAXBUF_] = {0};
/* /*
If adaptive polling is enabled: If adaptive polling is enabled:
@ -300,35 +302,42 @@ asynStatus sinqAxis::poll(bool *moving) {
lastPollTime_ = ts; lastPollTime_ = ts;
/* /*
At the beginning of the poll, it is assumed that the axis has no status If the "motorMessageText" record currently contains an error message, it
problems and therefore all error indicators are reset. This does not affect should be shown for at least one poll period. To assure this, it is read out
the PVs until callParamCallbacks has been called! 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
The motorStatusProblem_ field changes the motor record fields SEVR and STAT. "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); getAxisParamChecked(this, motorMessageText, &waitingMessage);
setAxisParamChecked(this, motorMessageText, "");
// The poll function is just a wrapper around doPoll and // Clear the communication
// handles mainly the callParamCallbacks() function. This wrapper is used setAxisParamChecked(this, motorStatusCommsError, false);
// to make sure callParamCallbacks() is called in case of a premature
// return. /*
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); poll_status = doPoll(moving);
// If the poll did not succeed, something went wrong and the motor has a /*
// status problem. If the poll did not succeed OR if an error message is waiting, something
if (poll_status == asynSuccess) { went wrong and the motor has a status problem. Otherwise, delete the error
setAxisParamChecked(this, motorStatusProblem, false); message entry which is currently in the paramLib.
} else { */
if (poll_status != asynSuccess || waitingMessage[0] != '\0') {
setAxisParamChecked(this, motorStatusProblem, true); 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 Motor is in homing mode, was moving, but is not moving anymore -> It can be
assumed that the homing procedure is done. assumed that the homing procedure is done.
*/ */
getAxisParamChecked(this, motorStatusHome, &homing);
if (homing == 1 && !(*moving) && wasMoving_) { if (homing == 1 && !(*moving) && wasMoving_) {
setAxisParamChecked(this, motorStatusHome, false); setAxisParamChecked(this, motorStatusHome, false);
setAxisParamChecked(this, motorStatusHomed, true); setAxisParamChecked(this, motorStatusHomed, true);
@ -363,6 +372,12 @@ asynStatus sinqAxis::poll(bool *moving) {
poll_status = pl_status; 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; return poll_status;
} }
@ -416,7 +431,6 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
if (status == asynSuccess) { if (status == asynSuccess) {
setAxisParamChecked(this, motorMessageText, "Reference drive");
setAxisParamChecked(this, motorStatusHome, true); setAxisParamChecked(this, motorStatusHome, true);
setAxisParamChecked(this, motorStatusHomed, false); setAxisParamChecked(this, motorStatusHomed, false);
setAxisParamChecked(this, motorStatusAtHome, false); setAxisParamChecked(this, motorStatusAtHome, false);

View File

@ -500,40 +500,8 @@ asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
* return asynSuccess; * 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) \ #define getAxisParamChecked(axis, indexGetterFunction, readValue) \
{ \ { \
asynStatus getStatus = getAxisParam( \ asynStatus getStatus = getAxisParam( \

View File

@ -490,17 +490,12 @@ asynStatus sinqController::checkComTimeoutWatchdog(int axisNo,
asynStatus sinqController::checkComTimeoutWatchdog(sinqAxis *axis) { asynStatus sinqController::checkComTimeoutWatchdog(sinqAxis *axis) {
char motorMessage[200] = {0}; char errorMessage[MAXBUF_] = {0};
asynStatus status = asynStatus status =
checkComTimeoutWatchdog(axis->axisNo(), motorMessage, 200); checkComTimeoutWatchdog(axis->axisNo(), errorMessage, MAXBUF_);
if (status == asynError) { if (status == asynError) {
status = axis->setStringParam(motorMessageText_, motorMessage); setAxisParamChecked(axis, motorMessageText, motorMessage);
if (status != asynSuccess) {
return paramLibAccessFailed(status, "motorMessageText_",
axis->axisNo(), __PRETTY_FUNCTION__,
__LINE__);
}
} }
return status; return status;
} }
@ -543,17 +538,12 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo,
sinqAxis *axis) { sinqAxis *axis) {
char motorMessage[200] = {0}; char motorMessage[MAXBUF_] = {0};
asynStatus status = checkMaxSubsequentTimeouts(timeoutNo, axis->axisNo(), asynStatus status = checkMaxSubsequentTimeouts(timeoutNo, axis->axisNo(),
motorMessage, 200); motorMessage, MAXBUF_);
if (status == asynError) { if (status == asynError) {
status = axis->setStringParam(motorMessageText_, motorMessage); setAxisParamChecked(axis, motorMessageText, motorMessage);
if (status != asynSuccess) {
return paramLibAccessFailed(status, "motorMessageText_",
axis->axisNo(), __PRETTY_FUNCTION__,
__LINE__);
}
} }
return status; return status;
} }

View File

@ -376,6 +376,11 @@ class epicsShareClass sinqController : public asynMotorController {
*/ */
int outstandingForcedFastPolls() { return outstandingForcedFastPolls_; } 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: protected: