Improved homing doc, fixed wrong setting of motorStatusHomed and added check to move
All checks were successful
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 6s

This commit is contained in:
2026-03-06 11:20:33 +01:00
parent 492f459678
commit 86e6ab1fdd
5 changed files with 103 additions and 15 deletions

View File

@@ -109,11 +109,11 @@ record(ao,"$(INSTR)$(M):RecResolution") {
# This record contains messages from the driver (usually error messages).
# The macro ERRORMSGSIZE can be used to set the maximum length of the message.
# if not provided, a default value of 200 is used.
# This record is coupled to the parameter library via motorErrorMessage -> MOTOR_MESSAGE_TEXT.
# This record is coupled to the parameter library via motorErrorMessage -> MOTOR_ERROR_MESSAGE.
record(waveform, "$(INSTR)$(M):ErrorMessage") {
alias("$(INSTR)$(M)-MsgTxt") # Old PV name, aliased for backwards compatibility
field(DTYP, "asynOctetRead")
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_MESSAGE_TEXT")
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_ERROR_MESSAGE")
field(FTVL, "CHAR")
field(NELM, "$(ERRORMSGSIZE=200)") # Should be the same as MAXBUF in the driver code
field(SCAN, "I/O Intr")

View File

@@ -35,6 +35,11 @@ struct sinqAxisImpl {
Store the time since the last poll
*/
epicsTimeStamp lastPollTime;
// For this time in seconds, any error message will be kept alive in the
// parameter library.
time_t errorDisplayDuration;
epicsTimeStamp errorInitialAppearance;
};
sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
@@ -49,6 +54,8 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
.targetPosition = 0.0,
.wasMoving = false,
.lastPollTime = lastPollTime,
.errorDisplayDuration = 2,
.errorInitialAppearance = lastPollTime,
});
}()) {
@@ -281,6 +288,14 @@ asynStatus sinqAxis::forcedPoll(bool *moving) {
setAxisParamChecked(this, motorErrorMessage,
static_cast<char *>(waitingMessage));
}
bool statProblem = false;
getAxisParamChecked(this, motorStatusProblem, &statProblem);
if (!statProblem) {
// The error initially appeared at this point in time
pSinqA_->errorInitialAppearance = ts;
}
setAxisParamChecked(this, motorStatusProblem, true);
} else {
// No errors are waiting -> Clear everything.
@@ -330,11 +345,12 @@ asynStatus sinqAxis::forcedPoll(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, motorErrorMessage, "");
// Delete the error message after the display duration has been exceeded.
epicsTimeStamp errorRemovalTime = pSinqA_->errorInitialAppearance;
epicsTimeAddSeconds(&errorRemovalTime, pSinqA_->errorDisplayDuration);
if (epicsTimeLessThanEqual(&ts, &errorRemovalTime) == 0) {
setAxisParamChecked(this, motorErrorMessage, "");
}
return poll_status;
}
@@ -370,6 +386,10 @@ asynStatus sinqAxis::move(double position, int relative, double minVelocity,
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(this, motorErrorMessage,
"Motor needs to be homed / referenced first.");
setAxisParamChecked(this, motorStatusProblem, true);
epicsTimeStamp ts;
epicsTimeGetCurrent(&ts);
pSinqA_->errorInitialAppearance = ts;
return pC_->callParamCallbacks();
}
@@ -746,6 +766,11 @@ asynStatus sinqAxis::setScaleMovTimeout(time_t scaleMovTimeout) {
return asynSuccess;
}
asynStatus sinqAxis::setErrorDisplayDuration(time_t errorDisplayDuration) {
pSinqA_->errorDisplayDuration = errorDisplayDuration;
return asynSuccess;
}
bool sinqAxis::wasMoving() { return pSinqA_->wasMoving; }
void sinqAxis::setWasMoving(bool wasMoving) { pSinqA_->wasMoving = wasMoving; }
@@ -903,12 +928,63 @@ static void setScaleMovTimeoutCallFunc(const iocshArgBuf *args) {
// =============================================================================
// 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
/**
* @brief Set the (minimum) error display duration (FFI implementation)
*
* @param portName Name of the controller
* @param axisNo Axis number
* @param errorDisplayDuration Minimum display duration
* @return asynStatus
*/
asynStatus setErrorDisplayDuration(const char *portName, int axisNo,
double errorDisplayDuration) {
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->setErrorDisplayDuration(errorDisplayDuration);
}
static const iocshArg setErrorDisplayDurationArg0 = {"Controller port name",
iocshArgString};
static const iocshArg setErrorDisplayDurationArg1 = {"Axis number",
iocshArgInt};
static const iocshArg setErrorDisplayDurationArg2 = {
"(Minimum) error display duration", iocshArgDouble};
static const iocshArg *const setErrorDisplayDurationArgs[] = {
&setErrorDisplayDurationArg0, &setErrorDisplayDurationArg1,
&setErrorDisplayDurationArg2};
static const iocshFuncDef setErrorDisplayDurationDef = {
"setErrorDisplayDuration", 3, setErrorDisplayDurationArgs,
"Specify an offset (in seconds) for the movement timeout watchdog"};
static void settErrorDisplayDurationCallFunc(const iocshArgBuf *args) {
setErrorDisplayDuration(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);
iocshRegister(&setErrorDisplayDurationDef,
settErrorDisplayDurationCallFunc);
}
epicsExportRegistrar(sinqAxisRegister);

View File

@@ -337,7 +337,7 @@ class HIDDEN sinqAxis : public asynMotorAxis {
/**
* @brief Enable / disable the watchdog. Also available in the IOC shell
* (see "extern C" section in sinqController.cpp).
* (see "extern C" section in sinqAxis.cpp).
*
* If enable is set to false and the watchdog is currently running, this
* function stops it immediately.
@@ -349,7 +349,7 @@ class HIDDEN sinqAxis : public asynMotorAxis {
/**
* @brief Set the offsetMovTimeout. Also available in the IOC shell
* (see "extern C" section in sinqController.cpp).
* (see "extern C" section in sinqAxis.cpp).
*
* See documentation of `checkMovTimeoutWatchdog` for details.
*
@@ -360,7 +360,7 @@ class HIDDEN sinqAxis : public asynMotorAxis {
/**
* @brief Set the scaleMovTimeout. Also available in the IOC shell
* (see "extern C" section in sinqController.cpp).
* (see "extern C" section in sinqAxis.cpp).
*
See documentation of `checkMovTimeoutWatchdog` for details.
*
@@ -369,6 +369,18 @@ class HIDDEN sinqAxis : public asynMotorAxis {
*/
virtual asynStatus setScaleMovTimeout(time_t scaleMovTimeout);
/**
* @brief Set the errorDisplayDuration. Also available in the IOC shell
* (see "extern C" section in sinqAxis.cpp).
*
This time in seconds define for which time an error will be displayed after
its root cause has been resolved.
*
* @param errorDisplayDuration Error display time (in seconds)
* @return asynStatus
*/
virtual asynStatus setErrorDisplayDuration(time_t errorDisplayDuration);
/**
* @brief Return the axis number of this axis
*

View File

@@ -176,10 +176,10 @@ sinqController::sinqController(const char *portName,
// =========================================================================;
// MOTOR_MESSAGE_TEXT corresponds to the PV definition inside sinqMotor.db.
// MOTOR_ERROR_MESSAGE corresponds to the PV definition inside sinqMotor.db.
// This text is used to forward status messages to NICOS and in turn to the
// user.
status = createParam("MOTOR_MESSAGE_TEXT", asynParamOctet,
status = createParam("MOTOR_ERROR_MESSAGE", asynParamOctet,
&pSinqC_->motorErrorMessage);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,

View File

@@ -24,7 +24,7 @@ Stefan Mathis, November 2024
#include <memory>
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
#define motorMessageTextString "MOTOR_ERROR_MESSAGE"
#define IncrementalEncoder "incremental"
#define AbsoluteEncoder "absolute"
#define NoEncoder "none"