Added new feature msgPrintControl from sinqMotor 0.8.0. Correspondingly,

the minimum version requirement for sinqMotor has been bumped to 0.8.0.
This commit is contained in:
2025-03-04 09:29:19 +01:00
parent 8f597550fa
commit dfb55a1b76
5 changed files with 261 additions and 203 deletions

View File

@ -14,7 +14,7 @@ REQUIRED+=sinqMotor
motorBase_VERSION=7.2.2 motorBase_VERSION=7.2.2
# Specify the version of sinqMotor we want to build against # Specify the version of sinqMotor we want to build against
sinqMotor_VERSION=mathis_s sinqMotor_VERSION=0.8.0
# These headers allow to depend on this library for derived drivers. # These headers allow to depend on this library for derived drivers.
HEADERS += src/turboPmacAxis.h HEADERS += src/turboPmacAxis.h

View File

@ -35,7 +35,8 @@ static void epicsInithookFunction(initHookState iState) {
} }
} }
turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo) turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
bool initialize)
: sinqAxis(pC, axisNo), pC_(pC) { : sinqAxis(pC, axisNo), pC_(pC) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@ -63,13 +64,17 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo)
exit(-1); exit(-1);
} }
// Register the hook function during construction of the first axis object if (initialize) {
if (axes.empty()) { // Register the hook function during construction of the first axis
initHookRegister(&epicsInithookFunction); // object
} if (axes.empty()) {
initHookRegister(&epicsInithookFunction);
}
// Collect all axes into this list which will be used in the hook function // Collect all axes into this list which will be used in the hook
axes.push_back(this); // function
axes.push_back(this);
}
// Initialize all member variables // Initialize all member variables
waitForHandshake_ = false; waitForHandshake_ = false;
@ -360,39 +365,43 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Intepret the status // Create the unique callsite identifier manually so it can be used later in
// the shouldBePrinted calls.
msgPrintControlKey keyStatus = msgPrintControlKey(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
bool resetCountStatus = true;
// Interpret the status
switch (axStatus) { switch (axStatus) {
case -6: case -6:
// Axis is stopping
*moving = true; *moving = true;
asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis is stopping\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case -5: case -5:
// Axis is deactivated
*moving = false; *moving = false;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis is "
"deactivated\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
pl_status = setStringParam(pC_->motorMessageText_, "Deactivated"); pl_status = setStringParam(pC_->motorMessageText_, "Deactivated");
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
__LINE__); __LINE__);
} }
break; break;
case -4: case -4:
// Emergency stop
*moving = false; *moving = false;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, if (pC_->msgPrintControl_.shouldBePrinted(keyStatus, true,
"Controller \"%s\", axis %d => %s, line %d\nEmergency stop " pC_->pasynUserSelf)) {
"activated\n", asynPrint(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nEmergency stop "
"activated.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetCountStatus = false;
pl_status = setStringParam(pC_->motorMessageText_, "Emergency stop"); pl_status = setStringParam(pC_->motorMessageText_, "Emergency stop");
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
@ -403,13 +412,9 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
case -3: case -3:
// Disabled
*moving = false; *moving = false;
asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis %d is disabled\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_);
pl_status = setStringParam(pC_->motorMessageText_, "Disabled"); pl_status = setStringParam(pC_->motorMessageText_, "Disabled");
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
@ -419,43 +424,24 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
case 0: case 0:
// Idle
*moving = false; *moving = false;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis is idle\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case 1: case 1:
// Move order acknowledged
*moving = true; *moving = true;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nMove order "
"acknowledged\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case 2: case 2:
// Move order confirmed possible
*moving = true; *moving = true;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nMove order is "
"possible\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case 3: case 3:
// Axis in Air Cushion Output status
*moving = true; *moving = true;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis in Air "
"Cushion Output status\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case 4: case 4:
// Axis in Air Cushion Input status
*moving = true; *moving = true;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis in Air "
"Cushion Input status\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break; break;
case 5: case 5:
*moving = true; *moving = true;
@ -469,12 +455,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
default: default:
*moving = false; *moving = false;
asynPrint( if (pC_->msgPrintControl_.shouldBePrinted(keyStatus, true,
pC_->pasynUserSelf, ASYN_TRACE_ERROR, pC_->pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nReached unreachable "
"state P%2.2d00 = %d\n", asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_, "Controller \"%s\", axis %d => %s, line %d\nReached "
axStatus); "unreachable state P%2.2d00 = %d.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axisNo_, axStatus, pC_->msgPrintControl_.getSuffix());
}
resetCountStatus = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"Unknown state P%2.2d00 = %d has been reached. Please call " "Unknown state P%2.2d00 = %d has been reached. Please call "
"the support.", "the support.",
@ -487,6 +478,10 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
} }
} }
if (resetCountStatus) {
pC_->msgPrintControl_.resetCount(keyStatus);
}
if (*moving) { if (*moving) {
// If the axis is moving, evaluate the movement direction // If the axis is moving, evaluate the movement direction
if ((currentPosition - previousPosition) > 0) { if ((currentPosition - previousPosition) > 0) {
@ -496,19 +491,30 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
} }
} }
// Error handling // Create the unique callsite identifier manually so it can be used later in
// the shouldBePrinted calls.
msgPrintControlKey keyError = msgPrintControlKey(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
bool resetError = true;
switch (error) { switch (error) {
case 0: case 0:
// No error // No error -> Reset the message repetition watchdog
pC_->msgPrintControl_.shouldBePrinted(keyError, false,
pC_->pasynUserSelf);
break; break;
case 1: case 1:
// 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
asynPrint( if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
pC_->pasynUserSelf, ASYN_TRACE_ERROR, pC_->pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nTarget position would " asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"exceed user limits.\n", "Controller \"%s\", axis %d => %s, line %d\nTarget "
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); "position would exceed user limits.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetError = false;
pl_status = setStringParam(pC_->motorMessageText_, pl_status = setStringParam(pC_->motorMessageText_,
"Target position would exceed software " "Target position would exceed software "
@ -523,11 +529,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
case 5: case 5:
// Command not possible // Command not possible
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, if (pC_->msgPrintControl_.shouldBePrinted(keyStatus, true,
"Controller \"%s\", axis %d => %s, line %d\nAxis is " pC_->pasynUserSelf)) {
"still moving, but received another move command. EPICS " asynPrint(
"should prevent this, check if *moving is set correctly.\n", pC_->pasynUserSelf, ASYN_TRACE_ERROR,
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); "Controller \"%s\", axis %d => %s, line %d\nAxis is "
"still moving, but received another move command. EPICS "
"should prevent this, check if *moving is set correctly.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetError = false;
pl_status = setStringParam(pC_->motorMessageText_, pl_status = setStringParam(pC_->motorMessageText_,
"Axis received move command while it is " "Axis received move command while it is "
@ -541,12 +553,15 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
poll_status = asynError; poll_status = asynError;
break; break;
case 8: case 8:
asynPrint( if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
pC_->pasynUserSelf, ASYN_TRACE_ERROR, pC_->pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nAir cushion feedback " asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"stopped during movement (P%2.2d01 = %d).\n", "Controller \"%s\", axis %d => %s, line %d\nAir cushion "
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_, "feedback stopped during movement (P%2.2d01 = %d).%s\n",
error); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axisNo_, error, pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"Air cushion feedback stopped during movement (P%2.2d01 = " "Air cushion feedback stopped during movement (P%2.2d01 = "
@ -561,11 +576,16 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
} }
break; break;
case 9: case 9:
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"Controller \"%s\", axis %d => %s, line %d\nNo air cushion " pC_->pasynUserSelf)) {
"feedback before movement start (P%2.2d01 = %d).\n", asynPrint(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->pasynUserSelf, ASYN_TRACE_ERROR,
axisNo_, error); "Controller \"%s\", axis %d => %s, line %d\nNo air cushion "
"feedback before movement start (P%2.2d01 = %d).%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
error, pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"No air cushion feedback before movement start (P%2.2d01 = " "No air cushion feedback before movement start (P%2.2d01 = "
@ -585,10 +605,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
error case can only happen if either the axis has an incremental encoder error case can only happen if either the axis has an incremental encoder
which is not properly homed or if a bug occured. which is not properly homed or if a bug occured.
*/ */
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis hit the " if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"controller limits.\n", pC_->pasynUserSelf)) {
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis hit the "
"controller limits.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"Software limits or end switch hit (P%2.2d01 = %d). Try " "Software limits or end switch hit (P%2.2d01 = %d). Try "
@ -608,10 +635,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
case 11: case 11:
// Following error // Following error
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed " if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"following error exceeded.\n", pC_->pasynUserSelf)) {
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed "
"following error exceeded.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"Maximum allowed following error exceeded (P%2.2d01 = %d). " "Maximum allowed following error exceeded (P%2.2d01 = %d). "
@ -629,6 +663,16 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
case 12: case 12:
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
pC_->pasynUserSelf)) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nSecurity "
"input is triggered (P%2.2d01 = %d).%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axisNo_, error, pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"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 "
@ -646,11 +690,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
case 13: case 13:
// Driver hardware error triggered // Driver hardware error triggered
asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR, if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"Controller \"%s\", axis %d => %s, line %d\nDriver hardware error " pC_->pasynUserSelf)) {
"triggered.\n", asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); "Controller \"%s\", axis %d => %s, line %d\nDriver "
"hardware error triggered.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"Driver hardware error (P%2.2d01 = 13). " "Driver hardware error (P%2.2d01 = 13). "
"Please call the support.", "Please call the support.",
@ -667,12 +717,16 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
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
asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR, if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"Controller \"%s\", axis %d => %s, line %d\nMove command exceeds " pC_->pasynUserSelf)) {
"hardware limits (P%2.2d01 = %d).\n", asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_, "Controller \"%s\", axis %d => %s, line %d\nMove "
error); "command exceeds hardware limits (P%2.2d01 = %d).%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axisNo_, error, pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"Move command exceeds hardware limits (P%2.2d01 = %d). Please " "Move command exceeds hardware limits (P%2.2d01 = %d). Please "
@ -688,11 +742,17 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
poll_status = asynError; poll_status = asynError;
break; break;
default: default:
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nUnknown error " if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
"P%2.2d01 = %d.\n", pC_->pasynUserSelf)) {
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, asynPrint(
axisNo_, error); pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nUnknown error "
"P%2.2d01 = %d.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
error, pC_->msgPrintControl_.getSuffix());
}
resetError = false;
snprintf(userMessage, sizeof(userMessage), snprintf(userMessage, sizeof(userMessage),
"Unknown error P%2.2d01 = %d. Please call the support.", "Unknown error P%2.2d01 = %d. Please call the support.",
@ -708,6 +768,10 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
break; break;
} }
if (resetError) {
pC_->msgPrintControl_.resetCount(keyError);
}
// Update the parameter library // Update the parameter library
if (error != 0) { if (error != 0) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem_, true);

View File

@ -15,7 +15,8 @@ class turboPmacAxis : public sinqAxis {
* @param pController Pointer to the associated controller * @param pController Pointer to the associated controller
* @param axisNo Index of the axis * @param axisNo Index of the axis
*/ */
turboPmacAxis(turboPmacController *pController, int axisNo); turboPmacAxis(turboPmacController *pController, int axisNo,
bool initialize = true);
/** /**
* @brief Destroy the turboPmacAxis * @brief Destroy the turboPmacAxis

View File

@ -133,39 +133,18 @@ 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
error is emitted. error is emitted.
*/ */
turboPmacAxis *turboPmacController::getAxis(asynUser *pasynUser) { turboPmacAxis *turboPmacController::getTurboPmacAxis(asynUser *pasynUser) {
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser); asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
return turboPmacController::castToAxis(asynAxis); return dynamic_cast<turboPmacAxis *>(asynAxis);
} }
/* /*
Access one of the axes of the controller via the axis index. Access one of the axes of the controller via the axis index.
If the axis does not exist or is not a Axis, the function must return Null If the axis does not exist or is not a Axis, the function must return Null
*/ */
turboPmacAxis *turboPmacController::getAxis(int axisNo) { turboPmacAxis *turboPmacController::getTurboPmacAxis(int axisNo) {
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo); asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
return turboPmacController::castToAxis(asynAxis); return dynamic_cast<turboPmacAxis *>(asynAxis);
}
turboPmacAxis *turboPmacController::castToAxis(asynMotorAxis *asynAxis) {
// =========================================================================
// If the axis slot of the pAxes_ array is empty, a nullptr must be returned
if (asynAxis == nullptr) {
return nullptr;
}
// Here, an error is emitted since asyn_axis is not a nullptr but also not
// an instance of Axis
turboPmacAxis *axis = dynamic_cast<turboPmacAxis *>(asynAxis);
if (axis == nullptr) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
"an instance of turboPmacAxis",
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
}
return axis;
} }
asynStatus turboPmacController::writeRead(int axisNo, const char *command, asynStatus turboPmacController::writeRead(int axisNo, const char *command,
@ -204,7 +183,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
// ========================================================================= // =========================================================================
turboPmacAxis *axis = getAxis(axisNo); turboPmacAxis *axis = getTurboPmacAxis(axisNo);
if (axis == nullptr) { if (axis == nullptr) {
// We already did the error logging directly in getAxis // We already did the error logging directly in getAxis
return asynError; return asynError;
@ -261,10 +240,6 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
// +1 for the carriage return. // +1 for the carriage return.
const size_t fullComandLength = offset + commandLength + 1; const size_t fullComandLength = offset + commandLength + 1;
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"Controller \"%s\", axis %d => %s, line %d\nSending command %s",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, fullCommand);
/* /*
We use separated write and read commands here, not the combined writeRead We use separated write and read commands here, not the combined writeRead
method, because the latter is actually a flushWriteRead (see method, because the latter is actually a flushWriteRead (see
@ -282,12 +257,19 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
status = pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand, status = pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand,
fullComandLength, comTimeout_, &nbytesOut); fullComandLength, comTimeout_, &nbytesOut);
msgPrintControlKey writeKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (status == asynTimeout) { if (status == asynTimeout) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (msgPrintControl_.shouldBePrinted(writeKey, true, pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nTimeout while " asynPrint(
"writing to the MCU\n", this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); "Controller \"%s\", axis %d => %s, line %d\nTimeout while "
"writing to the MCU.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
msgPrintControl_.getSuffix());
}
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText, timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText,
sizeof(drvMessageText)); sizeof(drvMessageText));
@ -309,23 +291,35 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
} }
} }
} else if (status != asynSuccess) { } else if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (msgPrintControl_.shouldBePrinted(writeKey, true, pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nError %s while " asynPrint(
"writing to the controller\n", this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, "Controller \"%s\", axis %d => %s, line %d\nError %s while "
stringifyAsynStatus(status)); "writing to the controller.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(writeKey);
} }
// Read the response from the MCU buffer // Read the response from the MCU buffer
status = pasynOctetSyncIO->read(lowLevelPortUser_, response, MAXBUF_, status = pasynOctetSyncIO->read(lowLevelPortUser_, response, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason); comTimeout_, &nbytesIn, &eomReason);
msgPrintControlKey readKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (status == asynTimeout) { if (status == asynTimeout) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (msgPrintControl_.shouldBePrinted(readKey, true, pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nTimeout while " asynPrint(
"reading from the MCU\n", this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); "Controller \"%s\", axis %d => %s, line %d\nTimeout while "
"reading from the MCU.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
msgPrintControl_.getSuffix());
}
// Add this event to the back of the timeout event counter // Add this event to the back of the timeout event counter
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText, timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText,
@ -348,11 +342,16 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
} }
} }
} else if (status != asynSuccess) { } else if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (msgPrintControl_.shouldBePrinted(readKey, true, pasynUserSelf)) {
"Controller \"%s\", axis %d => %s, line %d\nError %s while " asynPrint(
"reading from the controller\n", this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, "Controller \"%s\", axis %d => %s, line %d\nError %s while "
stringifyAsynStatus(status)); "reading from the controller.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(readKey);
} }
if (timeoutStatus == asynError) { if (timeoutStatus == asynError) {
@ -360,6 +359,8 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
} }
// The message should only ever terminate due to reason 2 // The message should only ever terminate due to reason 2
msgPrintControlKey terminateKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (eomReason != 2) { if (eomReason != 2) {
status = asynError; status = asynError;
@ -367,10 +368,16 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
"Terminated message due to reason %d (should be 2).", "Terminated message due to reason %d (should be 2).",
eomReason); eomReason);
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER, if (msgPrintControl_.shouldBePrinted(terminateKey, true,
"Controller \"%s\", axis %d => %s, line %d\nMessage " pasynUserSelf)) {
"terminated due to reason %i\n", asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, eomReason); "Controller \"%s\", axis %d => %s, line %d\nMessage "
"terminated due to reason %i.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
eomReason, msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(terminateKey);
} }
/* /*
@ -382,20 +389,30 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
numReceivedResponses++; numReceivedResponses++;
} }
} }
msgPrintControlKey numResponsesKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (numExpectedResponses != numReceivedResponses) { if (numExpectedResponses != numReceivedResponses) {
adjustResponseForPrint(modResponse, response, MAXBUF_); adjustResponseForPrint(modResponse, response, MAXBUF_);
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nUnexpected " if (msgPrintControl_.shouldBePrinted(numResponsesKey, true,
"response '%s' (carriage returns are replaced with spaces) " pasynUserSelf)) {
"for command %s\n", asynPrint(
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse, this->pasynUserSelf, ASYN_TRACE_ERROR,
command); "Controller \"%s\", axis %d => %s, line %d\nUnexpected "
"response '%s' (carriage returns are replaced with spaces) "
"for command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse,
command, msgPrintControl_.getSuffix());
}
snprintf(drvMessageText, sizeof(drvMessageText), snprintf(drvMessageText, sizeof(drvMessageText),
"Received unexpected response '%s' (carriage returns " "Received unexpected response '%s' (carriage returns "
"are replaced with spaces) for command %s. " "are replaced with spaces) for command %s. "
"Please call the support", "Please call the support",
modResponse, command); modResponse, command);
status = asynError; status = asynError;
} else {
msgPrintControl_.resetCount(numResponsesKey);
} }
// Create custom error messages for different failure modes, if no error // Create custom error messages for different failure modes, if no error
@ -425,23 +442,12 @@ 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) {
asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER,
"Controller \"%s\", axis %d => %s, line %d\nDevice "
"response: %s (carriage returns are replaced with spaces)\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse);
paramLibStatus = axis->setIntegerParam(this->motorStatusCommsError_, 0); paramLibStatus = axis->setIntegerParam(this->motorStatusCommsError_, 0);
} else { } else {
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, // Check if the axis already is in an error communication mode. If
"Controller \"%s\", axis %d => %s, line %d\nCommunication " // it is not, upstream the error. This is done to avoid "flooding"
"failed for command %s (%s)\n", // the user with different error messages if more than one error
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, fullCommand, // ocurred before an error-free communication
stringifyAsynStatus(status));
// Check if the axis already is in an error communication mode. If it is
// not, upstream the error. This is done to avoid "flooding" the user
// with different error messages if more than one error ocurred before
// an error-free communication
paramLibStatus = paramLibStatus =
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem); getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
if (paramLibStatus != asynSuccess) { if (paramLibStatus != asynSuccess) {
@ -482,11 +488,7 @@ asynStatus turboPmacController::writeInt32(asynUser *pasynUser,
// ===================================================================== // =====================================================================
turboPmacAxis *axis = getAxis(pasynUser); turboPmacAxis *axis = getTurboPmacAxis(pasynUser);
if (axis == nullptr) {
// We already did the error logging directly in getAxis
return asynError;
}
// Handle custom PVs // Handle custom PVs
if (function == rereadEncoderPosition_) { if (function == rereadEncoderPosition_) {
@ -538,8 +540,8 @@ asynStatus turboPmacCreateController(const char *portName,
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorController.cpp https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorController.cpp
https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/asynPortDriver.cpp https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/asynPortDriver.cpp
The created object is registered in EPICS in its constructor and can safely The created object is registered in EPICS in its constructor and can
be "leaked" here. safely be "leaked" here.
*/ */
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-variable"
@ -578,8 +580,8 @@ static void configTurboPmacCreateControllerCallFunc(const iocshArgBuf *args) {
args[3].dval, args[4].dval, args[5].dval); args[3].dval, args[4].dval, args[5].dval);
} }
// This function is made known to EPICS in turboPmac.dbd and is called by EPICS // This function is made known to EPICS in turboPmac.dbd and is called by
// in order to register both functions in the IOC shell // EPICS in order to register both functions in the IOC shell
static void turboPmacControllerRegister(void) { static void turboPmacControllerRegister(void) {
iocshRegister(&configTurboPmacCreateController, iocshRegister(&configTurboPmacCreateController,
configTurboPmacCreateControllerCallFunc); configTurboPmacCreateControllerCallFunc);

View File

@ -40,7 +40,7 @@ class turboPmacController : public sinqController {
* @return turboPmacAxis* If no axis could be found, this is a * @return turboPmacAxis* If no axis could be found, this is a
* nullptr * nullptr
*/ */
turboPmacAxis *getAxis(asynUser *pasynUser); turboPmacAxis *getTurboPmacAxis(asynUser *pasynUser);
/** /**
* @brief Get the axis object * @brief Get the axis object
@ -49,18 +49,18 @@ class turboPmacController : public sinqController {
* @return turboPmacAxis* If no axis could be found, this is a * @return turboPmacAxis* If no axis could be found, this is a
* nullptr * nullptr
*/ */
turboPmacAxis *getAxis(int axisNo); turboPmacAxis *getTurboPmacAxis(int axisNo);
/** /**
* @brief Overloaded function of sinqController * @brief Overloaded function of sinqController
* *
* The function is overloaded in order to read motorCanDisable_ * The function is overloaded in order to read motorCanDisable_.
* *
* @param pasynUser * @param pasynUser
* @param value * @param value
* @return asynStatus * @return asynStatus
*/ */
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value); virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
/** /**
* @brief Overloaded function of sinqController * @brief Overloaded function of sinqController
@ -71,7 +71,7 @@ class turboPmacController : public sinqController {
* @param value New value * @param value New value
* @return asynStatus * @return asynStatus
*/ */
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
protected: protected:
asynUser *lowLevelPortUser_; asynUser *lowLevelPortUser_;
@ -95,15 +95,6 @@ class turboPmacController : public sinqController {
asynStatus writeRead(int axisNo, const char *command, char *response, asynStatus writeRead(int axisNo, const char *command, char *response,
int numExpectedResponses); int numExpectedResponses);
/**
* @brief Save cast of the given asynAxis pointer to a turboPmacAxis
* pointer. If the cast fails, this function returns a nullptr.
*
* @param asynAxis
* @return turboPmacAxis*
*/
turboPmacAxis *castToAxis(asynMotorAxis *asynAxis);
/** /**
* @brief Specialized version of sinqController::errMsgCouldNotParseResponse * @brief Specialized version of sinqController::errMsgCouldNotParseResponse
* for turboPmac * for turboPmac