moved disconnect handling to sinqMotor

This commit is contained in:
2026-01-22 09:47:36 +01:00
parent 9c5fb9fecf
commit 6bc2d7de22
3 changed files with 189 additions and 158 deletions

View File

@@ -179,22 +179,52 @@ asynStatus turboPmacAxis::init() {
"Q%2.2d10 Q%2.2d03 Q%2.2d04 Q%2.2d06 P%2.2d22 Q%2.2d00 I%2.2d65", "Q%2.2d10 Q%2.2d03 Q%2.2d04 Q%2.2d06 P%2.2d22 Q%2.2d00 I%2.2d65",
axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_); axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_);
status = pC_->writeRead(axisNo_, command, response, 7); status = pC_->writeRead(axisNo_, command, response, 7);
msgPrintControlKey keyDisconnected = msgPrintControlKey(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, 1);
if (status != asynSuccess) { if (status != asynSuccess) {
asynPrint( if (pC_->getMsgPrintControl().shouldBePrinted(keyDisconnected, true,
pC_->pasynUser(), ASYN_TRACE_ERROR, pC_->pasynUser())) {
"Controller \"%s\", axis %d => %s, line %d\nCould not communicate " asynPrint(
"with controller during IOC initialization. Check if you used " pC_->pasynUser(), ASYN_TRACE_ERROR,
"\"pmacAsynIPPortConfigure\" instead of the standard " "Controller \"%s\", axis %d => %s, line %d\nCould not "
"\"drvAsynIPPortConfigure\" function in the .cmd file in order to " "communicate with controller during IOC initialization (error "
"create the port driver.\n", "%s). Did you use \"drvAsynIPPortConfigure\" instead of "
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__); "\"pmacAsynIPPortConfigure\" in the .cmd file to create the "
"port driver?\n",
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
}
pTurboPmacA_->needInit = true; pTurboPmacA_->needInit = true;
status = callParamCallbacks();
if (status != asynSuccess) {
// If we can't communicate with the parameter library, it
// doesn't make sense to try and upstream this to the user ->
// Just log the error
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d\ncallParamCallbacks failed with %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
return status;
}
return status;
} }
// No error has been detected -> Reset the error count
if (status == asynSuccess) {
pC_->getMsgPrintControl().resetCount(keyDisconnected, pC_->pasynUser());
}
nvals = sscanf(response, "%lf %lf %lf %lf %d %lf %lf", &motorPos, nvals = sscanf(response, "%lf %lf %lf %lf %d %lf %lf", &motorPos,
&motorVmax, &motorVelocity, &motorAccel, &acoDelay, &motorVmax, &motorVelocity, &motorAccel, &acoDelay,
&counts_to_eu, &deadband_counts); &counts_to_eu, &deadband_counts);
// The acoDelay is given in milliseconds -> Convert to seconds, rounded up // The acoDelay is given in milliseconds -> Convert to seconds, rounded
// up
setOffsetMovTimeout(std::ceil(acoDelay / 1000.0)); setOffsetMovTimeout(std::ceil(acoDelay / 1000.0));
// The PMAC electronic specifies the acceleration in m/s^2. Since we // The PMAC electronic specifies the acceleration in m/s^2. Since we
@@ -227,18 +257,18 @@ asynStatus turboPmacAxis::init() {
} }
/* /*
Check if the new target position is within the range current position +/- Check if the new target position is within the range current position
deadband. If that is the case, no movement command should be sent. This +/- deadband. If that is the case, no movement command should be sent.
functionality is implemented within the motor record itself, we just need to This functionality is implemented within the motor record itself, we
populate the field SPDP (see record PushSPDB2Field in db/turboPmac.db) just need to populate the field SPDP (see record PushSPDB2Field in
db/turboPmac.db)
First, the deadband is read out (Ixx65, see Turbo PMAC User Manual, p. First, the deadband is read out (Ixx65, see Turbo PMAC User Manual, p.
160). This value then needs to be converted into counts (by dividing it by 160). This value then needs to be converted into counts (by dividing it
16). After words, the deadband in counts then need to be converted into by 16). After words, the deadband in counts then need to be converted
engineering units. For this, the scaling factor Qxx10 needs to be applied into engineering units. For this, the scaling factor Qxx10 needs to be
(see SINQ_2G_MCU_SW_manual_rev7, p. 17): applied (see SINQ_2G_MCU_SW_manual_rev7, p. 17): [Qxx10] = engineering
[Qxx10] = engineering units (eu) / counts units (eu) / counts deadband_eu = Qxx10 * Ixx65 / 16
deadband_eu = Qxx10 * Ixx65 / 16
The values of Qxx10 and Ixx65 are read out during initialization and are The values of Qxx10 and Ixx65 are read out during initialization and are
assumed to not change during operation. assumed to not change during operation.
@@ -249,14 +279,15 @@ asynStatus turboPmacAxis::init() {
// Update the parameter library immediately // Update the parameter library immediately
status = callParamCallbacks(); status = callParamCallbacks();
if (status != asynSuccess) { if (status != asynSuccess) {
// If we can't communicate with the parameter library, it doesn't make // If we can't communicate with the parameter library, it doesn't
// sense to try and upstream this to the user -> Just log the error // make sense to try and upstream this to the user -> Just log the
asynPrint( // error
pC_->pasynUser(), ASYN_TRACE_ERROR, asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\ncallParamCallbacks " "Controller \"%s\", axis %d => %s, line "
"failed with %s.\n", "%d\ncallParamCallbacks "
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, "failed with %s.\n",
pC_->stringifyAsynStatus(status)); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
return status; return status;
} }
@@ -341,13 +372,13 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
} }
if (error != 0) { if (error != 0) {
// If an error occurred while waiting for the handshake, abort the // If an error occurred while waiting for the handshake, abort
// waiting procedure and continue with the poll in order to handle // the waiting procedure and continue with the poll in order to
// the error. // handle the error.
pTurboPmacA_->waitForHandshake = false; pTurboPmacA_->waitForHandshake = false;
} else if (handshakePerformed == 1) { } else if (handshakePerformed == 1) {
// Handshake has been performed successfully -> Continue with the // Handshake has been performed successfully -> Continue with
// poll // the poll
pTurboPmacA_->waitForHandshake = false; pTurboPmacA_->waitForHandshake = false;
} else { } else {
// Still waiting for the handshake - try again in the next busy // Still waiting for the handshake - try again in the next busy
@@ -387,15 +418,16 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
/* /*
The axis limits are set as: ({[]}) The axis limits are set as: ({[]})
where [] are the positive and negative limits set in EPICS/NICOS, {} are the where [] are the positive and negative limits set in EPICS/NICOS, {} are
software limits set on the MCU and () are the hardware limit switches. In the software limits set on the MCU and () are the hardware limit
other words, the EPICS/NICOS limits should be stricter than the software switches. In other words, the EPICS/NICOS limits should be stricter than
limits on the MCU which in turn should be stricter than the hardware limit the software limits on the MCU which in turn should be stricter than the
switches. For example, if the hardware limit switches are at [-10, 10], the hardware limit switches. For example, if the hardware limit switches are
software limits could be at [-9, 9] and the EPICS / NICOS limits could be at at [-10, 10], the software limits could be at [-9, 9] and the EPICS /
NICOS limits could be at
[-8, 8]. Therefore, we cannot use the software limits read from the MCU [-8, 8]. Therefore, we cannot use the software limits read from the MCU
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
by limitsOffset on both sides. them by limitsOffset on both sides.
*/ */
getAxisParamChecked(this, motorLimitsOffset, &limitsOffset); getAxisParamChecked(this, motorLimitsOffset, &limitsOffset);
highLimit = highLimit - limitsOffset; highLimit = highLimit - limitsOffset;
@@ -411,8 +443,8 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
(axStatus != -3 && axStatus != -5)); (axStatus != -3 && axStatus != -5));
} }
// Create the unique callsite identifier manually so it can be used later in // Create the unique callsite identifier manually so it can be used
// the shouldBePrinted calls. // later in the shouldBePrinted calls.
msgPrintControlKey keyStatus = msgPrintControlKey( msgPrintControlKey keyStatus = msgPrintControlKey(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
bool resetCountStatus = true; bool resetCountStatus = true;
@@ -433,12 +465,12 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
if (pC_->getMsgPrintControl().shouldBePrinted(keyStatus, true, if (pC_->getMsgPrintControl().shouldBePrinted(keyStatus, true,
pC_->pasynUser())) { pC_->pasynUser())) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line "
"Controller \"%s\", axis %d => %s, line %d\nEmergency stop " "%d\nEmergency stop "
"activated.%s\n", "activated.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->getMsgPrintControl().getSuffix()); pC_->getMsgPrintControl().getSuffix());
} }
resetCountStatus = false; resetCountStatus = false;
setAxisParamChecked(this, motorMessageText, "Emergency stop"); setAxisParamChecked(this, motorMessageText, "Emergency stop");
@@ -508,8 +540,8 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
*moving = false; *moving = false;
break; break;
case 15: case 15:
// Move is interrupted, but the motor is not ready to receive another // Move is interrupted, but the motor is not ready to receive
// move command. Therefore it is treated as still moving. // another move command. Therefore it is treated as still moving.
*moving = true; *moving = true;
break; break;
case 16: case 16:
@@ -604,13 +636,13 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
if (pC_->getMsgPrintControl().shouldBePrinted( if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
pC_->pasynUser())) { pC_->pasynUser())) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nAxis is "
"Controller \"%s\", axis %d => %s, line %d\nAxis is " "still moving, but received another move command. EPICS "
"still moving, but received another move command. EPICS " "should prevent this, check if *moving is set "
"should prevent this, check if *moving is set correctly.%s\n", "correctly.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->getMsgPrintControl().getSuffix()); pC_->getMsgPrintControl().getSuffix());
} }
setAxisParamChecked(this, motorMessageText, setAxisParamChecked(this, motorMessageText,
"Axis received move command while it is still " "Axis received move command while it is still "
@@ -623,27 +655,28 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
asynPrint( asynPrint(
pC_->pasynUser(), ASYN_TRACE_ERROR, pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nLost feedback " "Controller \"%s\", axis %d => %s, line %d\nLost feedback "
"from auxiliary device during movement (P%2.2d01 = %d).%s\n", "from auxiliary device during movement (P%2.2d01 = "
"%d).%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_,
error, pC_->getMsgPrintControl().getSuffix()); error, pC_->getMsgPrintControl().getSuffix());
} }
snprintf( snprintf(userMessage, sizeUserMessage,
userMessage, sizeUserMessage, "Lost feedback from auxiliary device during movement "
"Lost feedback from auxiliary device during movement (P%2.2d01 = " "(P%2.2d01 = "
"%d). Please call the support.", "%d). Please call the support.",
axisNo_, error); axisNo_, error);
setAxisParamChecked(this, motorMessageText, userMessage); setAxisParamChecked(this, motorMessageText, userMessage);
break; break;
case 9: case 9:
if (pC_->getMsgPrintControl().shouldBePrinted( if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
pC_->pasynUser())) { pC_->pasynUser())) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nNo feedback "
"Controller \"%s\", axis %d => %s, line %d\nNo feedback from " "from "
"auxiliary device before movement (P%2.2d01 = %d).%s\n", "auxiliary device before movement (P%2.2d01 = %d).%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo_, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
error, pC_->getMsgPrintControl().getSuffix()); axisNo_, error, pC_->getMsgPrintControl().getSuffix());
} }
snprintf( snprintf(
@@ -655,10 +688,10 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
break; break;
case 10: case 10:
/* /*
Software limits of the controller have been hit. Since the EPICS limits Software limits of the controller have been hit. Since the EPICS
are derived from the software limits and are a little bit smaller, this limits are derived from the software limits and are a little bit
error case can only happen if either the axis has an incremental encoder smaller, this error case can only happen if either the axis has an
which is not properly homed or if a bug occured. incremental encoder which is not properly homed or if a bug occured.
*/ */
if (pC_->getMsgPrintControl().shouldBePrinted( if (pC_->getMsgPrintControl().shouldBePrinted(
@@ -685,12 +718,12 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
if (pC_->getMsgPrintControl().shouldBePrinted( if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
pC_->pasynUser())) { pC_->pasynUser())) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nMaximum "
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed " "allowed "
"following error exceeded.%s\n", "following error exceeded.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->getMsgPrintControl().getSuffix()); pC_->getMsgPrintControl().getSuffix());
} }
snprintf(userMessage, sizeUserMessage, snprintf(userMessage, sizeUserMessage,
"Maximum allowed following error exceeded (P%2.2d01 = %d). " "Maximum allowed following error exceeded (P%2.2d01 = %d). "
@@ -730,10 +763,10 @@ 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());
} }
snprintf( snprintf(userMessage, sizeUserMessage,
userMessage, sizeUserMessage, "Driver hardware error (P%2.2d01 = 13). Please call the "
"Driver hardware error (P%2.2d01 = 13). Please call the support.", "support.",
axisNo_); axisNo_);
setAxisParamChecked(this, motorMessageText, userMessage); setAxisParamChecked(this, motorMessageText, userMessage);
break; break;
case 14: case 14:
@@ -798,10 +831,10 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
getAxisParamChecked(this, motorRecResolution, &motorRecResolution); getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
if (enabled == 0) { if (enabled == 0) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nAxis is "
"Controller \"%s\", axis %d => %s, line %d\nAxis is disabled.\n", "disabled.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
return asynSuccess; return asynSuccess;
} }
@@ -819,8 +852,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
getAxisParamChecked(this, motorCanSetSpeed, &motorCanSetSpeed); getAxisParamChecked(this, motorCanSetSpeed, &motorCanSetSpeed);
// 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
// is prepended to the one down below. // here is prepended to the one down below.
if (motorCanSetSpeed != 0) { if (motorCanSetSpeed != 0) {
snprintf(command, sizeof(command), "Q%2.2d04=%lf ", axisNo_, snprintf(command, sizeof(command), "Q%2.2d04=%lf ", axisNo_,
motorVelocity); motorVelocity);
@@ -833,8 +866,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
motorVelocity); motorVelocity);
} }
// Perform handshake, Set target position (and speed, if allowed) and start // Perform handshake, Set target position (and speed, if allowed) and
// the move command // start the move command
if (relative) { if (relative) {
snprintf(&command[writeOffset], sizeof(command) - writeOffset, snprintf(&command[writeOffset], sizeof(command) - writeOffset,
"P%2.2d23=0 Q%2.2d02=%lf M%2.2d=2", axisNo_, axisNo_, "P%2.2d23=0 Q%2.2d02=%lf M%2.2d=2", axisNo_, axisNo_,
@@ -849,18 +882,18 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
status = pC_->writeRead(axisNo_, command, response, 0); status = pC_->writeRead(axisNo_, command, response, 0);
if (status != asynSuccess) { if (status != asynSuccess) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nStarting "
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to " "movement to "
"target position %lf failed.\n", "target position %lf failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
motorTargetPosition); motorTargetPosition);
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
return status; return 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
// reasonable time // in a reasonable time
pTurboPmacA_->waitForHandshake = true; pTurboPmacA_->waitForHandshake = true;
pTurboPmacA_->timeAtHandshake = time(NULL); pTurboPmacA_->timeAtHandshake = time(NULL);
@@ -889,25 +922,25 @@ asynStatus turboPmacAxis::stop(double acceleration) {
status = pC_->writeRead(axisNo_, command, response, 0); status = pC_->writeRead(axisNo_, command, response, 0);
if (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 "
"Controller \"%s\", axis %d => %s, line %d\nStopping the movement " "the movement "
"failed.\n", "failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
} }
// 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
// if we're currently inside it. // loop, if we're currently inside it.
pTurboPmacA_->waitForHandshake = false; pTurboPmacA_->waitForHandshake = false;
/* /*
Stopping the motor results in a movement and further move commands have to Stopping the motor results in a movement and further move commands have
wait until the stopping movement is done. Therefore, we need to wait until to wait until the stopping movement is done. Therefore, we need to wait
the poller "sees" the changed state (otherwise, we risk issuing move until the poller "sees" the changed state (otherwise, we risk issuing
commands while the motor is stopping). To ensure that at least one poll is move commands while the motor is stopping). To ensure that at least one
done, this thread (which also runs move commands) is paused for twice the poll is done, this thread (which also runs move commands) is paused for
idle poll period. twice the idle poll period.
*/ */
unsigned int idlePollMicros = unsigned int idlePollMicros =
(unsigned int)ceil(pC_->idlePollPeriod() * 1e6); (unsigned int)ceil(pC_->idlePollPeriod() * 1e6);
@@ -938,8 +971,8 @@ asynStatus turboPmacAxis::doReset() {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
} }
// 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
// if we're currently inside it. // loop, if we're currently inside it.
pTurboPmacA_->waitForHandshake = false; pTurboPmacA_->waitForHandshake = false;
// Disable the axis // Disable the axis
@@ -1037,13 +1070,14 @@ asynStatus turboPmacAxis::readEncoderType() {
} }
/* /*
This is not a command that can always be run when enabling a motor as it also This is not a command that can always be run when enabling a motor as it
causes relative encoders to reread a position necessitating recalibration. We also causes relative encoders to reread a position necessitating
only want it to run on absolute encoders. We also want it to be clear to recalibration. We only want it to run on absolute encoders. We also want it
instrument scientists, that power has to be cut to the motor, in order to reread to be clear to instrument scientists, that power has to be cut to the motor,
the encoder as not all motors have breaks and they may start to move when in order to reread the encoder as not all motors have breaks and they may
disabled. For that reason, we don't automatically disable the motors to run the start to move when disabled. For that reason, we don't automatically disable
command and instead require that the scientists first disable the motor. the motors to run the command and instead require that the scientists first
disable the motor.
*/ */
asynStatus turboPmacAxis::rereadEncoder() { asynStatus turboPmacAxis::rereadEncoder() {
char command[pC_->MAXBUF_] = {0}; char command[pC_->MAXBUF_] = {0};
@@ -1087,11 +1121,12 @@ asynStatus turboPmacAxis::rereadEncoder() {
return asynError; return asynError;
} else { } else {
snprintf(command, sizeof(command), "M%2.2d=15", axisNo_); snprintf(command, sizeof(command), "M%2.2d=15", axisNo_);
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
pC_->pasynUser(), ASYN_TRACE_FLOW, "Controller \"%s\", axis %d => %s, line %d\nRereading "
"Controller \"%s\", axis %d => %s, line %d\nRereading absolute " "absolute "
"encoder via command %s.\n", "encoder via command %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, command); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
command);
pC_->writeRead(axisNo_, command, response, 0); pC_->writeRead(axisNo_, command, response, 0);
} }
@@ -1100,8 +1135,8 @@ 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, this will only be immediately // Turn off parameter as finished rereading, this will only be
// noticed in the read back variable though // immediately noticed in the read back variable though
setAxisParamChecked(this, rereadEncoderPosition, false); setAxisParamChecked(this, rereadEncoderPosition, false);
return asynSuccess; return asynSuccess;
} }
@@ -1121,27 +1156,28 @@ asynStatus turboPmacAxis::enable(bool on) {
/* /*
Continue regardless of the status returned by the poll; we just want to Continue regardless of the status returned by the poll; we just want to
find out whether the motor is currently moving or not. If the poll find out whether the motor is currently moving or not. If the poll
function fails before it can determine that, it is assumed that the motor function fails before it can determine that, it is assumed that the
is not moving. motor is not moving.
*/ */
bool moving = false; bool moving = false;
doPoll(&moving); doPoll(&moving);
// If the axis is currently moving, it cannot be disabled. Ignore the // If the axis is currently moving, it cannot be disabled. Ignore the
// command and inform the user. We check the last known status of the axis // command and inform the user. We check the last known status of the
// instead of "moving", since status -6 is also moving, but the motor can // axis instead of "moving", since status -6 is also moving, but the
// actually be disabled in this state! // motor can actually be disabled in this state!
int axStatus = pTurboPmacA_->axisStatus; int axStatus = pTurboPmacA_->axisStatus;
if (axStatus == 1 || axStatus == 2 || axStatus == 3 || axStatus == 4 || if (axStatus == 1 || axStatus == 2 || axStatus == 3 || axStatus == 4 ||
axStatus == 5 || axStatus == 6 || axStatus == 7 || axStatus == 8 || axStatus == 5 || axStatus == 6 || axStatus == 7 || axStatus == 8 ||
axStatus == 9 || axStatus == 10 || axStatus == 11 || axStatus == 12 || axStatus == 9 || axStatus == 10 || axStatus == 11 || axStatus == 12 ||
axStatus == 13 || axStatus == 15 || axStatus == 16) { axStatus == 13 || axStatus == 15 || axStatus == 16) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
pC_->pasynUser(), ASYN_TRACE_ERROR, "Controller \"%s\", axis %d => %s, line %d\nAxis is not "
"Controller \"%s\", axis %d => %s, line %d\nAxis is not " "idle (status %d) and can therefore not be enabled / "
"idle (status %d) and can therefore not be enabled / disabled.\n", "disabled.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axStatus); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
axStatus);
setAxisParamChecked(this, motorMessageText, setAxisParamChecked(this, motorMessageText,
"Axis cannot be disabled while it is moving."); "Axis cannot be disabled while it is moving.");
@@ -1152,11 +1188,11 @@ asynStatus turboPmacAxis::enable(bool on) {
// Axis is already enabled / disabled and a new enable / disable command // Axis is already enabled / disabled and a new enable / disable command
// was sent => Do nothing // was sent => Do nothing
if ((axStatus != -3) == on) { if ((axStatus != -3) == on) {
asynPrint( asynPrint(pC_->pasynUser(), ASYN_TRACE_WARNING,
pC_->pasynUser(), ASYN_TRACE_WARNING, "Controller \"%s\", axis %d => %s, line %d\nAxis is "
"Controller \"%s\", axis %d => %s, line %d\nAxis is already %s.\n", "already %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
on ? "enabled" : "disabled"); on ? "enabled" : "disabled");
return asynSuccess; return asynSuccess;
} }
@@ -1305,8 +1341,8 @@ asynStatus turboPmacCreateAxis(const char *portName, int axis) {
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"
@@ -1329,14 +1365,15 @@ static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
static const iocshFuncDef configTurboPmacCreateAxis = { static const iocshFuncDef configTurboPmacCreateAxis = {
"turboPmacAxis", 2, CreateAxisArgs, "turboPmacAxis", 2, CreateAxisArgs,
"Create an instance of a turboPmac axis. The first argument is the " "Create an instance of a turboPmac axis. The first argument is the "
"controller this axis should be attached to, the second argument is the " "controller this axis should be attached to, the second argument is "
"the "
"axis number."}; "axis number."};
static void configTurboPmacCreateAxisCallFunc(const iocshArgBuf *args) { static void configTurboPmacCreateAxisCallFunc(const iocshArgBuf *args) {
turboPmacCreateAxis(args[0].sval, args[1].ival); turboPmacCreateAxis(args[0].sval, args[1].ival);
} }
// 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 turboPmacAxisRegister(void) { static void turboPmacAxisRegister(void) {
iocshRegister(&configTurboPmacCreateAxis, iocshRegister(&configTurboPmacCreateAxis,
configTurboPmacCreateAxisCallFunc); configTurboPmacCreateAxisCallFunc);

View File

@@ -206,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 timeoutStatus = asynSuccess;
char drvMessageText[MAXBUF_] = {0}; char drvMessageText[MAXBUF_] = {0};
char modResponse[MAXBUF_] = {0}; char modResponse[MAXBUF_] = {0};
int motorStatusProblem = 0; int motorStatusProblem = 0;
@@ -284,8 +283,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
getMsgPrintControl().getSuffix()); getMsgPrintControl().getSuffix());
} }
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText, checkComTimeoutWatchdog(axisNo, drvMessageText, sizeof(drvMessageText));
sizeof(drvMessageText));
int timeoutCounter = 0; int timeoutCounter = 0;
while (1) { while (1) {
@@ -333,14 +331,10 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
axis->setNeedInit(true); axis->setNeedInit(true);
} }
if (timeoutStatus == asynError) {
status = asynError;
}
// The message should only ever terminate due to reason 2 // The message should only ever terminate due to reason 2
msgPrintControlKey terminateKey = msgPrintControlKey terminateKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (eomReason != 2) { if (status == asynSuccess && eomReason != 2) {
status = asynError; status = asynError;
char reasonStringified[30] = {0}; char reasonStringified[30] = {0};
@@ -391,7 +385,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
} }
msgPrintControlKey numResponsesKey = msgPrintControlKey numResponsesKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (numExpectedResponses != numReceivedResponses) { if (status == asynSuccess && numExpectedResponses != numReceivedResponses) {
adjustResponseForPrint(modResponse, response, MAXBUF_); adjustResponseForPrint(modResponse, response, MAXBUF_);
if (getMsgPrintControl().shouldBePrinted(numResponsesKey, true, if (getMsgPrintControl().shouldBePrinted(numResponsesKey, true,