Compare commits
14 Commits
1.0.1
...
f423002d23
Author | SHA1 | Date | |
---|---|---|---|
f423002d23 | |||
79ec79fac1 | |||
1703542770 | |||
c7d1dc4930 | |||
6fd3848f13 | |||
56f08f3c76 | |||
168bfae983 | |||
0e29750d13 | |||
ba5b921aca | |||
1b810fb353 | |||
4bc3388bc6 | |||
c759156058 | |||
eca513f3a0 | |||
26175290bf |
@ -31,3 +31,14 @@ record(longout, "$(INSTR)FlushHardware") {
|
|||||||
field(PINI, "NO")
|
field(PINI, "NO")
|
||||||
field(VAL, "1")
|
field(VAL, "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# If this PV is set to 1 (default), the position limits are read out from the
|
||||||
|
# controller. Otherwise, the limits given in the substitution file (DHLM and
|
||||||
|
# DLLM) are used.
|
||||||
|
# This record is coupled to the parameter library via limFromHardware -> LIM_FROM_HARDWARE.
|
||||||
|
record(longout, "$(INSTR)$(M):LimFromHardware") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIM_FROM_HARDWARE")
|
||||||
|
field(PINI, "YES")
|
||||||
|
field(VAL, "$(LIMFROMHARDWARE=1)")
|
||||||
|
}
|
Submodule sinqMotor updated: c2eca33ce8...55a9fe6f3e
@ -194,11 +194,7 @@ asynStatus turboPmacAxis::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial motor status is idle
|
// Initial motor status is idle
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusDone(), 1);
|
setAxisParamChecked(this, motorStatusDone, 1);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorStatusDone_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to the motor record fields
|
// Write to the motor record fields
|
||||||
status = setVeloFields(motorVelocity, 0.0, motorVmax);
|
status = setVeloFields(motorVelocity, 0.0, motorVmax);
|
||||||
@ -239,10 +235,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
asynStatus errorStatus = asynSuccess;
|
asynStatus errorStatus = asynSuccess;
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
@ -266,9 +259,9 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
if (pTurboPmacA_->needInit) {
|
if (pTurboPmacA_->needInit) {
|
||||||
rw_status = init();
|
status = init();
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,22 +285,16 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timedOut) {
|
if (timedOut) {
|
||||||
pl_status =
|
setAxisParamChecked(this, motorMessageText,
|
||||||
setStringParam(pC_->motorMessageText(),
|
"Timed out while waiting for a handshake");
|
||||||
"Timed out while waiting for a handshake");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
pTurboPmacA_->waitForHandshake = false;
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(command, sizeof(command), "P%2.2d23 P%2.2d01", axisNo_,
|
snprintf(command, sizeof(command), "P%2.2d23 P%2.2d01", axisNo_,
|
||||||
axisNo_);
|
axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 2);
|
status = pC_->writeRead(axisNo_, command, response, 2);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvals = sscanf(response, "%d %d", &handshakePerformed, &error);
|
nvals = sscanf(response, "%d %d", &handshakePerformed, &error);
|
||||||
@ -330,52 +317,30 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
// poll. This is already part of the movement procedure.
|
// poll. This is already part of the movement procedure.
|
||||||
*moving = true;
|
*moving = true;
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
|
setAxisParamChecked(this, motorStatusMoving, *moving);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusDone, !(*moving));
|
||||||
return pC_->paramLibAccessFailed(pl_status,
|
|
||||||
"motorStatusMoving_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
|
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||||
&motorRecResolution);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the previous motor position
|
// Read the previous motor position
|
||||||
pl_status = motorPosition(&previousPosition);
|
status = motorPosition(&previousPosition);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pl_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusDone(),
|
getAxisParamChecked(this, motorStatusDone, &previousStatusDone);
|
||||||
&previousStatusDone);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query the axis status
|
// Query the axis status
|
||||||
snprintf(command, sizeof(command),
|
snprintf(command, sizeof(command),
|
||||||
"P%2.2d00 Q%2.2d10 P%2.2d01 Q%2.2d13 Q%2.2d14", axisNo_, axisNo_,
|
"P%2.2d00 Q%2.2d10 P%2.2d01 Q%2.2d13 Q%2.2d14", axisNo_, axisNo_,
|
||||||
axisNo_, axisNo_, axisNo_);
|
axisNo_, axisNo_, axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 5);
|
status = pC_->writeRead(axisNo_, command, response, 5);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvals = sscanf(response, "%d %lf %d %lf %lf", &axStatus, ¤tPosition,
|
nvals = sscanf(response, "%d %lf %d %lf %lf", &axStatus, ¤tPosition,
|
||||||
@ -397,13 +362,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
directly, but need to shrink them a bit. In this case, we're shrinking them
|
directly, but need to shrink them a bit. In this case, we're shrinking them
|
||||||
by limitsOffset on both sides.
|
by limitsOffset on both sides.
|
||||||
*/
|
*/
|
||||||
pl_status =
|
getAxisParamChecked(this, motorLimitsOffset, &limitsOffset);
|
||||||
pC_->getDoubleParam(axisNo_, pC_->motorLimitsOffset(), &limitsOffset);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorLimitsOffset_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
highLimit = highLimit - limitsOffset;
|
highLimit = highLimit - limitsOffset;
|
||||||
lowLimit = lowLimit + limitsOffset;
|
lowLimit = lowLimit + limitsOffset;
|
||||||
|
|
||||||
@ -411,12 +370,8 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
pTurboPmacA_->axisStatus = axStatus;
|
pTurboPmacA_->axisStatus = axStatus;
|
||||||
|
|
||||||
// Update the enablement PV
|
// Update the enablement PV
|
||||||
pl_status = setIntegerParam(pC_->motorEnableRBV(),
|
setAxisParamChecked(this, motorEnableRBV,
|
||||||
(axStatus != -3 && axStatus != -5));
|
(axStatus != -3 && axStatus != -5));
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the unique callsite identifier manually so it can be used later in
|
// Create the unique callsite identifier manually so it can be used later in
|
||||||
// the shouldBePrinted calls.
|
// the shouldBePrinted calls.
|
||||||
@ -448,13 +403,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetCountStatus = false;
|
resetCountStatus = false;
|
||||||
|
setAxisParamChecked(this, motorMessageText, "Emergency stop");
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), "Emergency stop");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
// Disabled
|
// Disabled
|
||||||
@ -547,12 +496,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
userMessage, sizeof(userMessage),
|
userMessage, sizeof(userMessage),
|
||||||
"Reached unknown state P%2.2d00 = %d. Please call the support.",
|
"Reached unknown state P%2.2d00 = %d. Please call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetCountStatus) {
|
if (resetCountStatus) {
|
||||||
@ -572,77 +516,44 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
// Update the parameter library
|
// Update the parameter library
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*moving == false) {
|
if (*moving == false) {
|
||||||
pl_status = setIntegerParam(pC_->motorMoveToHome(), 0);
|
setAxisParamChecked(this, motorMoveToHome, false);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMoveToHome_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
|
setAxisParamChecked(this, motorStatusMoving, *moving);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(this, motorStatusDone, !(*moving));
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_",
|
setAxisParamChecked(this, motorStatusDirection, direction);
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
int limFromHardware = 0;
|
||||||
|
getAxisParamChecked(this, limFromHardware, &limFromHardware);
|
||||||
|
|
||||||
|
if (limFromHardware != 0) {
|
||||||
|
setAxisParamChecked(this, motorHighLimitFromDriver, highLimit);
|
||||||
|
setAxisParamChecked(this, motorLowLimitFromDriver, lowLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
|
status = setMotorPosition(currentPosition);
|
||||||
if (pl_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_,
|
return status;
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusDirection(), direction);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusDirection_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
|
|
||||||
highLimit);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status =
|
|
||||||
pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(), lowLimit);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = setMotorPosition(currentPosition);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pl_status;
|
|
||||||
}
|
}
|
||||||
return errorStatus;
|
return errorStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||||
int sizeUserMessage) {
|
int sizeUserMessage) {
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynError;
|
||||||
|
|
||||||
// Create the unique callsite identifier manually so it can be used later in
|
// Create the unique callsite identifier manually so it can be used later in
|
||||||
// the shouldBePrinted calls.
|
// the shouldBePrinted calls.
|
||||||
msgPrintControlKey keyError = msgPrintControlKey(
|
msgPrintControlKey keyError = msgPrintControlKey(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
bool resetError = true;
|
|
||||||
|
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case 0:
|
case 0:
|
||||||
|
status = asynSuccess;
|
||||||
// No error -> Reset the message repetition watchdog
|
// No error -> Reset the message repetition watchdog
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -656,17 +567,8 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
setAxisParamChecked(this, motorMessageText,
|
||||||
|
"Target position would exceed software limits");
|
||||||
status = setStringParam(pC_->motorMessageText(),
|
|
||||||
"Target position would exceed software limits");
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
// Command not possible
|
// Command not possible
|
||||||
@ -680,18 +582,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
setAxisParamChecked(this, motorMessageText,
|
||||||
|
"Axis received move command while it is still "
|
||||||
status = setStringParam(pC_->motorMessageText(),
|
"moving. Please call the support.");
|
||||||
"Axis received move command while it is "
|
|
||||||
"still moving. Please call the support.");
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||||
@ -702,19 +595,11 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"Air cushion feedback stopped during movement (P%2.2d01 = "
|
"Air cushion feedback stopped during movement (P%2.2d01 = "
|
||||||
"%d). Please call the support.",
|
"%d). Please call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||||
@ -726,18 +611,12 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
|
||||||
error, pC_->getMsgPrintControl().getSuffix());
|
error, pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"No air cushion feedback before movement start (P%2.2d01 = "
|
"No air cushion feedback before movement start (P%2.2d01 = "
|
||||||
"%d). Please call the support.",
|
"%d). Please call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
/*
|
/*
|
||||||
@ -756,23 +635,13 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"Software limits or end switch hit (P%2.2d01 = %d). Try "
|
"Software limits or end switch hit (P%2.2d01 = %d). Try "
|
||||||
"homing the motor, moving in the opposite direction or check "
|
"homing the motor, moving in the opposite direction or check "
|
||||||
"the SPS for errors (if available). "
|
"the SPS for errors (if available). "
|
||||||
"Otherwise please call the support.",
|
"Otherwise please call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
// Following error
|
// Following error
|
||||||
@ -786,21 +655,12 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"Maximum allowed following error exceeded (P%2.2d01 = %d). "
|
"Maximum allowed following error exceeded (P%2.2d01 = %d). "
|
||||||
"Check if movement range is blocked. "
|
"Check if movement range is blocked. "
|
||||||
"Otherwise please call the support.",
|
"Otherwise please call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
@ -812,21 +672,12 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"Security input is triggered (P%2.2d01 = %d). Check the SPS "
|
"Security input is triggered (P%2.2d01 = %d). Check the SPS "
|
||||||
"for errors (if available). Otherwise please call "
|
"for errors (if available). Otherwise please call "
|
||||||
"the support.",
|
"the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 13:
|
case 13:
|
||||||
@ -840,25 +691,15 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->getMsgPrintControl().getSuffix());
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
userMessage, sizeUserMessage,
|
userMessage, sizeUserMessage,
|
||||||
"Driver hardware error (P%2.2d01 = 13). Please call the support.",
|
"Driver hardware error (P%2.2d01 = 13). Please call the support.",
|
||||||
axisNo_);
|
axisNo_);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
// EPICS should already prevent this issue in the first place,
|
// EPICS should already prevent this issue in the first place,
|
||||||
// since it contains the user limits
|
// since it contains the user limits
|
||||||
|
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||||
pC_->pasynUser())) {
|
pC_->pasynUser())) {
|
||||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
@ -867,20 +708,11 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
axisNo_, error, pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(userMessage, sizeUserMessage,
|
||||||
"Move command exceeds hardware limits (P%2.2d01 = %d). Please "
|
"Move command exceeds hardware limits (P%2.2d01 = %d). Please "
|
||||||
"call the support.",
|
"call the support.",
|
||||||
axisNo_, error);
|
axisNo_, error);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
@ -893,23 +725,11 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
|
||||||
error, pC_->getMsgPrintControl().getSuffix());
|
error, pC_->getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
resetError = false;
|
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
|
||||||
"Unknown error P%2.2d01 = %d. Please call the support.",
|
|
||||||
axisNo_, error);
|
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = asynError;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetError) {
|
if (status == asynSuccess) {
|
||||||
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
|
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -920,10 +740,7 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
double acceleration) {
|
double acceleration) {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
@ -936,19 +753,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableRBV(), &enabled);
|
getAxisParamChecked(this, motorEnableRBV, &enabled);
|
||||||
if (pl_status != asynSuccess) {
|
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
|
||||||
return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
|
|
||||||
&motorRecResolution);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled == 0) {
|
if (enabled == 0) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
@ -968,13 +774,7 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
|
||||||
|
|
||||||
// Check if the speed is allowed to be changed
|
// Check if the speed is allowed to be changed
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed(),
|
getAxisParamChecked(this, motorCanSetSpeed, &motorCanSetSpeed);
|
||||||
&motorCanSetSpeed);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorCanSetSpeed_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepend the new motor speed, if the user is allowed to set the speed.
|
// Prepend the new motor speed, if the user is allowed to set the speed.
|
||||||
// Mind the " " (space) before the closing "", as the command created here
|
// Mind the " " (space) before the closing "", as the command created here
|
||||||
@ -1004,8 +804,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We don't expect an answer
|
// We don't expect an answer
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
|
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
@ -1013,13 +813,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
"target position %lf failed.\n",
|
"target position %lf failed.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
motorCoordinatesPosition);
|
motorCoordinatesPosition);
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
if (pl_status != asynSuccess) {
|
return status;
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return rw_status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the next poll, we will check if the handshake has been performed in a
|
// In the next poll, we will check if the handshake has been performed in a
|
||||||
@ -1033,16 +828,13 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus turboPmacAxis::stop(double acceleration) {
|
asynStatus turboPmacAxis::stop(double acceleration) {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
@ -1050,37 +842,28 @@ asynStatus turboPmacAxis::stop(double acceleration) {
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
snprintf(command, sizeof(command), "M%2.2d=8", axisNo_);
|
snprintf(command, sizeof(command), "M%2.2d=8", axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
|
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement "
|
||||||
"failed.\n",
|
"failed.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the driver to idle state and move out of the handshake wait loop,
|
// Reset the driver to idle state and move out of the handshake wait loop,
|
||||||
// if we're currently inside it.
|
// if we're currently inside it.
|
||||||
pTurboPmacA_->waitForHandshake = false;
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
|
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus turboPmacAxis::doReset() {
|
asynStatus turboPmacAxis::doReset() {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
@ -1089,27 +872,21 @@ asynStatus turboPmacAxis::doReset() {
|
|||||||
|
|
||||||
// Reset the error for this axis manually
|
// Reset the error for this axis manually
|
||||||
snprintf(command, sizeof(command), "P%2.2d01=0", axisNo_);
|
snprintf(command, sizeof(command), "P%2.2d01=0", axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
|
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nResetting the "
|
"Controller \"%s\", axis %d => %s, line %d\nResetting the "
|
||||||
"error failed\n",
|
"error failed\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
setAxisParamChecked(this, motorStatusProblem, true);
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the driver to idle state and move out of the handshake wait loop,
|
// Reset the driver to idle state and move out of the handshake wait loop,
|
||||||
// if we're currently inside it.
|
// if we're currently inside it.
|
||||||
pTurboPmacA_->waitForHandshake = false;
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
|
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1119,38 +896,25 @@ asynStatus turboPmacAxis::doHome(double min_velocity, double max_velocity,
|
|||||||
double acceleration, int forwards) {
|
double acceleration, int forwards) {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
pl_status = pC_->getStringParam(axisNo_, pC_->encoderType(),
|
getAxisParamChecked(this, encoderType, &response);
|
||||||
sizeof(response), response);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only send the home command if the axis has an incremental encoder
|
// Only send the home command if the axis has an incremental encoder
|
||||||
if (strcmp(response, IncrementalEncoder) == 0) {
|
if (strcmp(response, IncrementalEncoder) == 0) {
|
||||||
|
|
||||||
snprintf(command, sizeof(command), "M%2.2d=9", axisNo_);
|
snprintf(command, sizeof(command), "M%2.2d=9", axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorMoveToHome(), 1);
|
setAxisParamChecked(this, motorMoveToHome, true);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMoveToHome_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return callParamCallbacks();
|
return callParamCallbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1163,10 +927,7 @@ Read the encoder type and update the parameter library accordingly
|
|||||||
asynStatus turboPmacAxis::readEncoderType() {
|
asynStatus turboPmacAxis::readEncoderType() {
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
char command[pC_->MAXBUF_] = {0};
|
char command[pC_->MAXBUF_] = {0};
|
||||||
char response[pC_->MAXBUF_] = {0};
|
char response[pC_->MAXBUF_] = {0};
|
||||||
@ -1177,9 +938,9 @@ asynStatus turboPmacAxis::readEncoderType() {
|
|||||||
|
|
||||||
// Check if this is an absolute encoder
|
// Check if this is an absolute encoder
|
||||||
snprintf(command, sizeof(command), "I%2.2d04", axisNo_);
|
snprintf(command, sizeof(command), "I%2.2d04", axisNo_);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 1);
|
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reponse_length = strlen(response);
|
int reponse_length = strlen(response);
|
||||||
@ -1197,22 +958,17 @@ asynStatus turboPmacAxis::readEncoderType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
snprintf(command, sizeof(command), "P46");
|
snprintf(command, sizeof(command), "P46");
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 1);
|
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
int number_of_axes = strtol(response, NULL, 10);
|
int number_of_axes = strtol(response, NULL, 10);
|
||||||
|
|
||||||
// If true, the encoder is incremental
|
// If true, the encoder is incremental
|
||||||
if (encoder_id <= number_of_axes) {
|
if (encoder_id <= number_of_axes) {
|
||||||
pl_status = setStringParam(pC_->encoderType(), IncrementalEncoder);
|
setAxisParamChecked(this, encoderType, IncrementalEncoder);
|
||||||
} else {
|
} else {
|
||||||
pl_status = setStringParam(pC_->encoderType(), AbsoluteEncoder);
|
setAxisParamChecked(this, encoderType, AbsoluteEncoder);
|
||||||
}
|
|
||||||
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
}
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
@ -1232,24 +988,16 @@ asynStatus turboPmacAxis::rereadEncoder() {
|
|||||||
char encoderType[pC_->MAXBUF_] = {0};
|
char encoderType[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
// Check if this is an absolute encoder
|
// Check if this is an absolute encoder
|
||||||
rw_status = readEncoderType();
|
status = readEncoderType();
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
|
||||||
pl_status = pC_->getStringParam(axisNo_, pC_->encoderType(),
|
|
||||||
sizeof(encoderType), encoderType);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
}
|
||||||
|
getAxisParamChecked(this, encoderType, &encoderType);
|
||||||
|
|
||||||
// Abort if the axis is incremental
|
// Abort if the axis is incremental
|
||||||
if (strcmp(encoderType, IncrementalEncoder) == 0) {
|
if (strcmp(encoderType, IncrementalEncoder) == 0) {
|
||||||
@ -1263,25 +1011,16 @@ asynStatus turboPmacAxis::rereadEncoder() {
|
|||||||
// Check if the axis is disabled. If not, inform the user that this
|
// Check if the axis is disabled. If not, inform the user that this
|
||||||
// is necessary
|
// is necessary
|
||||||
int enabled = 0;
|
int enabled = 0;
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableRBV(), &enabled);
|
getAxisParamChecked(this, motorEnableRBV, &enabled);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_", axisNo_,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled == 1) {
|
if (enabled == 1) {
|
||||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_WARNING,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_WARNING,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis must be "
|
"Controller \"%s\", axis %d => %s, line %d\nAxis must be "
|
||||||
"disabled before rereading the encoder.\n",
|
"disabled before rereading the encoder.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
pl_status = setStringParam(
|
setAxisParamChecked(
|
||||||
pC_->motorMessageText(),
|
this, motorMessageText,
|
||||||
"Axis must be disabled before rereading the encoder.");
|
"Axis must be disabled before rereading the encoder.");
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return asynError;
|
return asynError;
|
||||||
} else {
|
} else {
|
||||||
snprintf(command, sizeof(command), "M%2.2d=15", axisNo_);
|
snprintf(command, sizeof(command), "M%2.2d=15", axisNo_);
|
||||||
@ -1298,15 +1037,9 @@ asynStatus turboPmacAxis::rereadEncoder() {
|
|||||||
// it is actually finished, so we instead wait for 0.5 seconds.
|
// it is actually finished, so we instead wait for 0.5 seconds.
|
||||||
usleep(500000);
|
usleep(500000);
|
||||||
|
|
||||||
// turn off parameter as finished rereading
|
// Turn off parameter as finished rereading, this will only be immediately
|
||||||
// this will only be immediately noticed in the read back variable
|
// noticed in the read back variable though
|
||||||
// though
|
setAxisParamChecked(this, rereadEncoderPosition, false);
|
||||||
pl_status = pC_->setIntegerParam(pC_->rereadEncoderPosition(), 0);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "rereadEncoderPosition_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1318,10 +1051,7 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
int nvals = 0;
|
int nvals = 0;
|
||||||
|
|
||||||
// Status of read-write-operations of ASCII commands to the controller
|
// Status of read-write-operations of ASCII commands to the controller
|
||||||
asynStatus rw_status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Status of parameter library operations
|
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
@ -1348,15 +1078,8 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
"idle and can therefore not be enabled / disabled.\n",
|
"idle and can therefore not be enabled / disabled.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
pl_status =
|
setAxisParamChecked(this, motorMessageText,
|
||||||
setStringParam(pC_->motorMessageText(),
|
"Axis cannot be disabled while it is moving.");
|
||||||
"Axis cannot be disabled while it is moving.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1373,9 +1096,9 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
|
|
||||||
// Reread the encoder, if the axis is going to be enabled
|
// Reread the encoder, if the axis is going to be enabled
|
||||||
if (on != 0) {
|
if (on != 0) {
|
||||||
rw_status = rereadEncoder();
|
status = rereadEncoder();
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1386,9 +1109,9 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
on ? "Enable" : "Disable");
|
on ? "Enable" : "Disable");
|
||||||
|
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query the axis status every few milliseconds until the axis has been
|
// Query the axis status every few milliseconds until the axis has been
|
||||||
@ -1399,9 +1122,9 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
|
|
||||||
// Read the axis status
|
// Read the axis status
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 1);
|
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||||
if (rw_status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return rw_status;
|
return status;
|
||||||
}
|
}
|
||||||
nvals = sscanf(response, "%d", &pTurboPmacA_->axisStatus);
|
nvals = sscanf(response, "%d", &pTurboPmacA_->axisStatus);
|
||||||
if (nvals != 1) {
|
if (nvals != 1) {
|
||||||
@ -1428,12 +1151,7 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
// Output message to user
|
// Output message to user
|
||||||
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
||||||
on ? "enable" : "disable", timeout_enable_disable);
|
on ? "enable" : "disable", timeout_enable_disable);
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), command);
|
setAxisParamChecked(this, motorMessageText, command);
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
#ifndef turboPmacAXIS_H
|
#ifndef turboPmacAXIS_H
|
||||||
#define turboPmacAXIS_H
|
#define turboPmacAXIS_H
|
||||||
#include "sinqAxis.h"
|
#include "sinqController.h"
|
||||||
|
#include "turboPmacController.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
struct turboPmacAxisImpl;
|
struct turboPmacAxisImpl;
|
||||||
|
|
||||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
|
||||||
// between the controller and the axis .h-file. See
|
|
||||||
// https://en.cppreference.com/w/cpp/language/class.
|
|
||||||
class turboPmacController;
|
|
||||||
|
|
||||||
class turboPmacAxis : public sinqAxis {
|
class turboPmacAxis : public sinqAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -24,6 +20,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
/**
|
/**
|
||||||
* @brief Destroy the turboPmacAxis
|
* @brief Destroy the turboPmacAxis
|
||||||
*
|
*
|
||||||
|
* This destructor is necessary in order to use the PIMPL idiom.
|
||||||
*/
|
*/
|
||||||
virtual ~turboPmacAxis();
|
virtual ~turboPmacAxis();
|
||||||
|
|
||||||
@ -141,6 +138,11 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
*/
|
*/
|
||||||
void setNeedInit(bool needInit);
|
void setNeedInit(bool needInit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the axis controller
|
||||||
|
*/
|
||||||
|
virtual turboPmacController *pController() override { return pC_; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
turboPmacController *pC_;
|
turboPmacController *pC_;
|
||||||
std::unique_ptr<turboPmacAxisImpl> pTurboPmacA_;
|
std::unique_ptr<turboPmacAxisImpl> pTurboPmacA_;
|
||||||
|
@ -45,6 +45,7 @@ struct turboPmacControllerImpl {
|
|||||||
int rereadEncoderPosition;
|
int rereadEncoderPosition;
|
||||||
int readConfig;
|
int readConfig;
|
||||||
int flushHardware;
|
int flushHardware;
|
||||||
|
int limFromHardware;
|
||||||
};
|
};
|
||||||
#define NUM_turboPmac_DRIVER_PARAMS 3
|
#define NUM_turboPmac_DRIVER_PARAMS 3
|
||||||
|
|
||||||
@ -114,6 +115,17 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = createParam("LIM_FROM_HARDWARE", asynParamInt32,
|
||||||
|
&pTurboPmacC_->limFromHardware);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUser(), 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Define the end-of-string of a message coming from the device to EPICS.
|
Define the end-of-string of a message coming from the device to EPICS.
|
||||||
It is not necessary to append a terminator to outgoing messages, since
|
It is not necessary to append a terminator to outgoing messages, since
|
||||||
@ -167,6 +179,8 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
turboPmacController::~turboPmacController() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Access one of the axes of the controller via the axis adress stored in asynUser.
|
Access one of the axes of the controller via the axis adress stored in asynUser.
|
||||||
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
||||||
@ -192,7 +206,6 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
|
|
||||||
// Definition of local variables.
|
// Definition of local variables.
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
asynStatus paramLibStatus = asynSuccess;
|
|
||||||
asynStatus timeoutStatus = asynSuccess;
|
asynStatus timeoutStatus = asynSuccess;
|
||||||
// char fullCommand[MAXBUF_] = {0};
|
// char fullCommand[MAXBUF_] = {0};
|
||||||
char drvMessageText[MAXBUF_] = {0};
|
char drvMessageText[MAXBUF_] = {0};
|
||||||
@ -414,41 +427,18 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
|
|
||||||
// Log the overall status (communication successfull or not)
|
// Log the overall status (communication successfull or not)
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess) {
|
||||||
paramLibStatus = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||||
} else {
|
} else {
|
||||||
// Check if the axis already is in an error communication mode. If
|
// Check if the axis already is in an error communication mode. If
|
||||||
// it is not, upstream the error. This is done to avoid "flooding"
|
// it is not, upstream the error. This is done to avoid "flooding"
|
||||||
// the user with different error messages if more than one error
|
// the user with different error messages if more than one error
|
||||||
// ocurred before an error-free communication
|
// ocurred before an error-free communication
|
||||||
paramLibStatus =
|
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
|
||||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
|
||||||
if (paramLibStatus != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem",
|
|
||||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motorStatusProblem == 0) {
|
if (motorStatusProblem == 0) {
|
||||||
paramLibStatus =
|
setAxisParamChecked(axis, motorMessageText, drvMessageText);
|
||||||
axis->setStringParam(motorMessageText(), drvMessageText);
|
setAxisParamChecked(axis, motorStatusProblem, true);
|
||||||
if (paramLibStatus != asynSuccess) {
|
setAxisParamChecked(axis, motorStatusCommsError, true);
|
||||||
return paramLibAccessFailed(paramLibStatus, "motorMessageText",
|
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
||||||
if (paramLibStatus != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(paramLibStatus,
|
|
||||||
"motorStatusProblem", axisNo,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
||||||
if (paramLibStatus != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(paramLibStatus,
|
|
||||||
"motorStatusCommsError", axisNo,
|
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -506,6 +496,9 @@ int turboPmacController::rereadEncoderPosition() {
|
|||||||
}
|
}
|
||||||
int turboPmacController::readConfig() { return pTurboPmacC_->readConfig; }
|
int turboPmacController::readConfig() { return pTurboPmacC_->readConfig; }
|
||||||
int turboPmacController::flushHardware() { return pTurboPmacC_->flushHardware; }
|
int turboPmacController::flushHardware() { return pTurboPmacC_->flushHardware; }
|
||||||
|
int turboPmacController::limFromHardware() {
|
||||||
|
return pTurboPmacC_->limFromHardware;
|
||||||
|
}
|
||||||
|
|
||||||
asynUser *turboPmacController::pasynInt32SyncIOipPort() {
|
asynUser *turboPmacController::pasynInt32SyncIOipPort() {
|
||||||
return pTurboPmacC_->pasynInt32SyncIOipPort;
|
return pTurboPmacC_->pasynInt32SyncIOipPort;
|
||||||
|
@ -10,9 +10,13 @@
|
|||||||
#define turboPmacController_H
|
#define turboPmacController_H
|
||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
#include "sinqController.h"
|
#include "sinqController.h"
|
||||||
#include "turboPmacAxis.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||||
|
// between the controller and the axis .h-file. See
|
||||||
|
// https://en.cppreference.com/w/cpp/language/class.
|
||||||
|
class turboPmacAxis;
|
||||||
|
|
||||||
struct turboPmacControllerImpl;
|
struct turboPmacControllerImpl;
|
||||||
|
|
||||||
class turboPmacController : public sinqController {
|
class turboPmacController : public sinqController {
|
||||||
@ -36,6 +40,13 @@ class turboPmacController : public sinqController {
|
|||||||
double idlePollPeriod, double comTimeout,
|
double idlePollPeriod, double comTimeout,
|
||||||
int numExtraParams = 0);
|
int numExtraParams = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the controller. Its implementation is empty, however the
|
||||||
|
* destructor needs to be provided for handling turboPmacControllerImpl.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual ~turboPmacController();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
*
|
*
|
||||||
@ -122,6 +133,7 @@ class turboPmacController : public sinqController {
|
|||||||
int rereadEncoderPosition();
|
int rereadEncoderPosition();
|
||||||
int readConfig();
|
int readConfig();
|
||||||
int flushHardware();
|
int flushHardware();
|
||||||
|
int limFromHardware();
|
||||||
|
|
||||||
asynUser *pasynInt32SyncIOipPort();
|
asynUser *pasynInt32SyncIOipPort();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user