Added some flags for NICOS and refactored some records from pmacv3 to

sinqMotor
This commit is contained in:
2024-11-29 14:54:54 +01:00
parent 682325de7d
commit 6656841a01
6 changed files with 394 additions and 63 deletions

View File

@ -13,7 +13,44 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
offsetMovTimeout_ = 30;
}
asynStatus sinqAxis::atFirstPoll() { return asynSuccess; }
asynStatus sinqAxis::atFirstPoll() {
asynStatus status = asynSuccess;
int variableSpeed = 0;
status =
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed_, &variableSpeed);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_",
__PRETTY_FUNCTION__, __LINE__);
}
if (variableSpeed == 1) {
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, 0.0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_,
1000000000.0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
} else {
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, 0.0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, 0.0);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
}
return status;
}
asynStatus sinqAxis::poll(bool *moving) {
// Local variable declaration
@ -98,9 +135,9 @@ asynStatus sinqAxis::poll(bool *moving) {
__PRETTY_FUNCTION__, __LINE__);
}
} else {
pl_status = setIntegerParam(pC_->enableMotorRBV_, axisIsEnabled);
pl_status = setIntegerParam(pC_->motorEnableRBV_, axisIsEnabled);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_",
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_",
__PRETTY_FUNCTION__, __LINE__);
}
}
@ -224,18 +261,117 @@ asynStatus sinqAxis::isEnabled(bool *on) {
return asynSuccess;
}
asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
asynStatus status = asynSuccess;
int variableSpeed = 0;
// Can the speed of the motor be varied?
status =
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed_, &variableSpeed);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_",
__PRETTY_FUNCTION__, __LINE__);
}
if (variableSpeed == 1) {
// Check the inputs and create corresponding error messages
if (vbas > vmax) {
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
"%s => line %d:\nLower speed limit vbas=%lf must not be "
"smaller than upper limit vmax=%lf.\n",
__PRETTY_FUNCTION__, __LINE__, vbas, vmax);
status = setStringParam(
pC_->motorMessageText_,
"Lower speed limit must not be smaller than upper speed limit");
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorMessageText_",
__PRETTY_FUNCTION__, __LINE__);
}
return asynError;
}
if (velo < vbas || velo > vmax) {
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
"%s => line %d:\nActual speed velo=%lf must be between "
"lower limit vbas=%lf and upper limit vmx=%lf.\n",
__PRETTY_FUNCTION__, __LINE__, velo, vbas, vmax);
status = setStringParam(pC_->motorMessageText_,
"Speed is not inside limits");
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorMessageText_",
__PRETTY_FUNCTION__, __LINE__);
}
return asynError;
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, vbas);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, vmax);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
} else {
// Set minimum and maximum speed equal to the set speed
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, velo);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, velo);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
}
return status;
}
asynStatus sinqAxis::setAcclField(double accl) {
if (accl <= 0.0) {
return asynError;
}
asynStatus status =
pC_->setDoubleParam(axisNo_, pC_->motorAcclFromDriver_, accl);
if (status != asynSuccess) {
return pC_->paramLibAccessFailed(status, "motorAcclFromDriver_",
__PRETTY_FUNCTION__, __LINE__);
}
return status;
}
asynStatus sinqAxis::setWatchdogEnabled(bool enable) {
return pC_->setIntegerParam(axisNo_, pC_->enableMovWatchdog_, enable);
return pC_->setIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_, enable);
}
asynStatus sinqAxis::startMovTimeoutWatchdog() {
asynStatus pl_status;
int enableMovWatchdog = 0;
pl_status = pC_->getIntegerParam(axisNo_, pC_->enableMovWatchdog_,
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_,
&enableMovWatchdog);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "enableMovWatchdog_",
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
__PRETTY_FUNCTION__, __LINE__);
}
@ -385,10 +521,10 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
asynStatus pl_status;
int enableMovWatchdog = 0;
pl_status = pC_->getIntegerParam(axisNo_, pC_->enableMovWatchdog_,
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_,
&enableMovWatchdog);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "enableMovWatchdog_",
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
__PRETTY_FUNCTION__, __LINE__);
}

View File

@ -43,7 +43,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
- Reset motorStatusProblem_, motorStatusCommsError_ and motorMessageText_ if
doPoll returned asynSuccess
- If the movement timeout watchdog has been started, check it.
- Update the parameter library entry enableMotorRBV_ by calling isEnabled.
- Update the parameter library entry motorEnableRBV_ by calling isEnabled.
- Run `callParamCallbacks`
- Return the status of `doPoll`
*
@ -162,6 +162,44 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
*/
virtual asynStatus isEnabled(bool *on);
/**
* @brief Populate the motor record fields VELO, VBAS and VMAX
*
* Populates the speed fields of the motor record. If the param lib
* entry motorCanSetSpeed_ (connected to the PV x:VariableSpeed) is set to
* 1, VBAS and VMAX are set to min and max respectively. Otherwise, they are
* set to val. Additionally, the speed itself is set to velo.
*
* The units of the inputs are engineering units (EGU) per second (e.g. mm/s
* if the EGU is mm).
*
* If the given configuration is invalid (min > max, velo < min, velo > max)
* and the motor is configured as a variable speed motor (param lib entry
* motorCanSetSpeed_ is 1), this function returns an asynError.
*
* @param velo Actual velocity (EGU / s)
* @param vbas Minimum allowed velocity (EGU / s)
* @param velo Maximum allowed velocity (EGU / s)
*
* @return asynStatus
*/
virtual asynStatus setVeloFields(double velo, double vbas, double vmax);
/**
* @brief Populate the ACCL field of the motor record
*
* Populates the acceleration field of the motor record with the given
* value. If accl is not positive, this function does not set the value and
* returns an asynError.
*
* The unit of the input is engineering units (EGU) per second squared (e.g.
* mm/s^2 if the EGU is mm).
*
* @param accl Actual acceleration (EGU / s^2)
* @return asynStatus
*/
virtual asynStatus setAcclField(double accl);
/**
* @brief Start the watchdog for the movement, if the watchdog is not
disabled. See the documentation of checkMovTimeoutWatchdog for more details.

View File

@ -81,7 +81,7 @@ sinqController::sinqController(const char *portName,
exit(-1);
}
status = createParam("ENABLE_AXIS", asynParamInt32, &enableMotor_);
status = createParam("MOTOR_ENABLE", asynParamInt32, &motorEnable_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
@ -90,7 +90,37 @@ sinqController::sinqController(const char *portName,
exit(-1);
}
status = createParam("ENABLE_AXIS_RBV", asynParamInt32, &enableMotorRBV_);
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));
exit(-1);
}
status =
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));
exit(-1);
}
status =
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));
exit(-1);
}
status = createParam("MOTOR_LIMITS_OFFSET", asynParamFloat64,
&motorLimitsOffset_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
@ -124,8 +154,8 @@ sinqController::sinqController(const char *portName,
exit(-1);
}
status =
createParam("ENABLE_MOV_WATCHDOG", asynParamInt32, &enableMovWatchdog_);
status = createParam("MOTOR_ENABLE_MOV_WATCHDOG", asynParamInt32,
&motorEnableMovWatchdog_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
@ -134,8 +164,38 @@ sinqController::sinqController(const char *portName,
exit(-1);
}
status =
createParam("LIMITS_OFFSET", asynParamFloat64, &motorLimitsOffset_);
status = createParam("MOTOR_VELO_FROM_DRIVER", asynParamFloat64,
&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));
exit(-1);
}
status = createParam("MOTOR_VBAS_FROM_DRIVER", asynParamFloat64,
&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));
exit(-1);
}
status = createParam("MOTOR_VMAX_FROM_DRIVER", asynParamFloat64,
&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));
exit(-1);
}
status = createParam("MOTOR_ACCL_FROM_DRIVER", asynParamFloat64,
&motorAcclFromDriver_);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s => line %d:\nFATAL ERROR (creating a parameter failed "
@ -178,20 +238,21 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
}
// Handle custom PVs
if (function == enableMotor_) {
if (function == motorEnable_) {
return axis->enable(value != 0);
} else {
return asynMotorController::writeInt32(pasynUser, value);
}
}
/*
Overloaded from asynMotorController to cover the readback value of enableMotor.
*/
asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
if (pasynUser->reason == enableMotorRBV_) {
if (pasynUser->reason == motorEnableRBV_) {
// Value is updated in the poll function of an axis
return asynSuccess;
} else if (pasynUser->reason == motorCanDisable_) {
// By default, motors cannot be disabled
*value = 0;
return asynSuccess;
} else {
return asynMotorController::readInt32(pasynUser, value);
}
@ -199,18 +260,30 @@ asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
const char *response,
int axisNo_,
int axisNo,
const char *functionName,
int lineNumber) {
asynStatus pl_status = asynSuccess;
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
"%s => line %d:\n Could not interpret response %s for "
"%s => line %d:\nCould not interpret response %s for "
"command %s.\n",
functionName, lineNumber, response, command);
setStringParam(motorMessageText_,
"Could not interpret MCU response. Please call the support");
setIntegerParam(motorStatusCommsError_, 1);
pl_status = setStringParam(
motorMessageText_,
"Could not interpret MCU response. Please call the support");
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorMessageText_",
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = setIntegerParam(motorStatusCommsError_, 1);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
__PRETTY_FUNCTION__, __LINE__);
}
return asynError;
}
@ -220,7 +293,8 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
int lineNumber) {
if (status != asynSuccess) {
// Log the error message and try to propagate it
// 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",

View File

@ -55,7 +55,7 @@ class epicsShareClass sinqController : public asynMotorController {
* @param value New value
* @return asynStatus
*/
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
/**
* @brief Overloaded function of asynMotorController
@ -67,7 +67,7 @@ class epicsShareClass sinqController : public asynMotorController {
* @param value Read-out value
* @return asynStatus
*/
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
/**
* @brief Error handling in case accessing the parameter library failed.
@ -107,7 +107,7 @@ class epicsShareClass sinqController : public asynMotorController {
* @return asynStatus Returns asynError.
*/
asynStatus errMsgCouldNotParseResponse(const char *command,
const char *response, int axisNo_,
const char *response, int axisNo,
const char *functionName,
int lineNumber);
@ -127,18 +127,23 @@ class epicsShareClass sinqController : public asynMotorController {
#define FIRST_SINQMOTOR_PARAM motorMessageText_
int motorMessageText_;
int motorTargetPosition_;
int enableMotor_;
int enableMotorRBV_;
int enableMovWatchdog_;
int motorEnable_;
int motorEnableRBV_;
int motorCanDisable_;
int motorEnableMovWatchdog_;
int motorCanSetSpeed_;
int motorLimitsOffset_;
/*
These parameters are here to write the high and low limits from the MCU to
the EPICS motor record. Using motorHighLimit_ / motorLowLimit_ does not
work: https://epics.anl.gov/tech-talk/2023/msg00576.php.
Therefore, some additional records are introduced which read from these
parameters and write into the motor record. See the sinq_asyn_motor.db file.
These parameters are here to write values from the hardware to the EPICS
motor record. Using motorHighLimit_ / motorLowLimit_ does not work:
https://epics.anl.gov/tech-talk/2023/msg00576.php. Therefore, some
additional records are introduced which read from these parameters and write
into the motor record.
*/
int motorVeloFromDriver_;
int motorVbasFromDriver_;
int motorVmaxFromDriver_;
int motorAcclFromDriver_;
int motorHighLimitFromDriver_;
int motorLowLimitFromDriver_;
#define LAST_SINQMOTOR_PARAM motorLowLimitFromDriver_