3 Commits
0.2.0 ... 0.3.0

6 changed files with 172 additions and 168 deletions

View File

@ -13,7 +13,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=0.8.0 sinqMotor_VERSION=0.9.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/masterMacsAxis.h HEADERS += src/masterMacsAxis.h

View File

@ -4,6 +4,8 @@
This is a driver for the masterMacs motion controller with the SINQ communication protocol. It is based on the sinqMotor shared library (https://git.psi.ch/sinq-epics-modules/sinqmotor). The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one. This is a driver for the masterMacs motion controller with the SINQ communication protocol. It is based on the sinqMotor shared library (https://git.psi.ch/sinq-epics-modules/sinqmotor). The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one.
Compatible to MasterMACS software 2.0.0.
## User guide ## User guide
This driver is a standard sinqMotor-derived driver and does not need any specific configuration. For the general configuration, please see https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md. This driver is a standard sinqMotor-derived driver and does not need any specific configuration. For the general configuration, please see https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.

View File

@ -78,13 +78,13 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
bounds, asynMotorAxis prints an error. However, we want the IOC creation to bounds, asynMotorAxis prints an error. However, we want the IOC creation to
stop completely, since this is a configuration error. stop completely, since this is a configuration error.
*/ */
if (axisNo >= pC->numAxes_) { if (axisNo >= pC->numAxes()) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:: FATAL ERROR: " "Controller \"%s\", axis %d => %s, line %d:: FATAL ERROR: "
"Axis index %d must be smaller than the total number of axes " "Axis index %d must be smaller than the total number of axes "
"%d. Call the support.", "%d. Call the support.",
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__, axisNo_, pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__, axisNo_,
pC->numAxes_); pC->numAxes());
exit(-1); exit(-1);
} }
@ -108,10 +108,10 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
timeAtHandshake_ = 0; timeAtHandshake_ = 0;
// masterMacs motors can always be disabled // masterMacs motors can always be disabled
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable_, 1); status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
if (status != asynSuccess) { if (status != asynSuccess) {
asynPrint( asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR, pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR " "Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed with %s)\n. Terminating IOC", "(setting a parameter value failed with %s)\n. Terminating IOC",
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
@ -120,10 +120,10 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
} }
// Assume that the motor is initially not moving // Assume that the motor is initially not moving
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving_, false); status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving(), false);
if (status != asynSuccess) { if (status != asynSuccess) {
asynPrint( asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR, pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR " "Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed with %s)\n. Terminating IOC", "(setting a parameter value failed with %s)\n. Terminating IOC",
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
@ -163,11 +163,11 @@ asynStatus masterMacsAxis::init() {
time_t now = time(NULL); time_t now = time(NULL);
time_t maxInitTime = 60; time_t maxInitTime = 60;
while (1) { while (1) {
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution); &motorRecResolution);
if (pl_status == asynParamUndefined) { if (pl_status == asynParamUndefined) {
if (now + maxInitTime < time(NULL)) { if (now + maxInitTime < time(NULL)) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
"%d\nInitializing the parameter library failed.\n", "%d\nInitializing the parameter library failed.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, pC_->portName, axisNo_, __PRETTY_FUNCTION__,
@ -237,7 +237,7 @@ asynStatus masterMacsAxis::init() {
// Store these values in the parameter library // Store these values in the parameter library
pl_status = pl_status =
pC_->setDoubleParam(axisNo_, pC_->motorPosition_, motorPosition); pC_->setDoubleParam(axisNo_, pC_->motorPosition(), motorPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
@ -264,7 +264,7 @@ asynStatus masterMacsAxis::init() {
// If we can't communicate with the parameter library, it doesn't // 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 // make sense to try and upstream this to the user -> Just log the
// error // error
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
"%d:\ncallParamCallbacks failed with %s.\n", "%d:\ncallParamCallbacks failed with %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
@ -303,6 +303,34 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Are we currently waiting for a handshake? // Are we currently waiting for a handshake?
if (waitForHandshake_) { if (waitForHandshake_) {
// Check if the handshake takes too long and communicate an error in
// this case. A handshake should not take more than 5 seconds.
time_t currentTime = time(NULL);
bool timedOut = (currentTime > timeAtHandshake_ + 5);
if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
pC_->asynUserSelf())) {
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAsked for a "
"handshake at %ld s and didn't get a positive reply yet "
"(current time is %ld s).\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
timeAtHandshake_, currentTime);
}
if (timedOut) {
pl_status =
setStringParam(pC_->motorMessageText(),
"Timed out while waiting for a handshake");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
pC_->read(axisNo_, 86, response); pC_->read(axisNo_, 86, response);
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
return rw_status; return rw_status;
@ -323,14 +351,14 @@ asynStatus masterMacsAxis::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); pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, return pC_->paramLibAccessFailed(pl_status,
"motorStatusMoving_", axisNo_, "motorStatusMoving_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
pl_status = setIntegerParam(pC_->motorStatusDone_, !(*moving)); pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -342,7 +370,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
// Motor resolution from parameter library // Motor resolution from parameter library
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution); &motorRecResolution);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_", return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
@ -352,7 +380,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Read the previous motor position // Read the previous motor position
pl_status = pl_status =
pC_->getDoubleParam(axisNo_, pC_->motorPosition_, &previousPosition); pC_->getDoubleParam(axisNo_, pC_->motorPosition(), &previousPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
@ -403,17 +431,17 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
since this information is not reliable. since this information is not reliable.
*/ */
if (communicationError()) { if (communicationError()) {
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true, if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->pasynUserSelf)) { keyError, true, pC_->asynUserSelf())) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
"%d\nCommunication error.%s\n", "%d\nCommunication error.%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->msgPrintControl_.getSuffix()); pC_->getMsgPrintControl().getSuffix());
} }
pl_status = pl_status =
setStringParam(pC_->motorMessageText_, setStringParam(pC_->motorMessageText(),
"Communication error between PC and motor " "Communication error between PC and motor "
"controller. Please call the support."); "controller. Please call the support.");
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
@ -561,18 +589,18 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
if (strlen(shellMessage) > 0) { if (strlen(shellMessage) > 0) {
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true, if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->pasynUserSelf)) { keyError, true, pC_->asynUserSelf())) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line " "Controller \"%s\", axis %d => %s, line "
"%d\n%s.%s\n", "%d\n%s%s\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, pC_->portName, axisNo_, __PRETTY_FUNCTION__,
__LINE__, shellMessage, __LINE__, shellMessage,
pC_->msgPrintControl_.getSuffix()); pC_->getMsgPrintControl().getSuffix());
} }
} }
pl_status = setStringParam(pC_->motorMessageText_, userMessage); pl_status = setStringParam(pC_->motorMessageText(), userMessage);
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__,
@ -580,7 +608,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
} }
} else { } else {
pC_->msgPrintControl_.resetCount(keyError); pC_->getMsgPrintControl().resetCount(keyError, pC_->asynUserSelf());
} }
// Read out the limits, if the motor is not moving // Read out the limits, if the motor is not moving
@ -618,7 +646,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
directly, but need to shrink them a bit. In this case, we're shrinking directly, but need to shrink them a bit. In this case, we're shrinking
them by 0.1 mm or 0.1 degree (depending on the axis type) on both sides. them by 0.1 mm or 0.1 degree (depending on the axis type) on both sides.
*/ */
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorLimitsOffset_, pl_status = pC_->getDoubleParam(axisNo_, pC_->motorLimitsOffset(),
&limitsOffset); &limitsOffset);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLimitsOffset_", return pC_->paramLibAccessFailed(pl_status, "motorLimitsOffset_",
@ -628,15 +656,15 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
highLimit = highLimit - limitsOffset; highLimit = highLimit - limitsOffset;
lowLimit = lowLimit + limitsOffset; lowLimit = lowLimit + limitsOffset;
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver_, pl_status = pC_->setDoubleParam(
highLimit); axisNo_, pC_->motorHighLimitFromDriver(), highLimit);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed( return pC_->paramLibAccessFailed(
pl_status, "motorHighLimitFromDriver_", axisNo_, pl_status, "motorHighLimitFromDriver_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver_, pl_status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(),
lowLimit); lowLimit);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_", return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_",
@ -646,7 +674,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
// Update the enable PV // Update the enable PV
pl_status = setIntegerParam(pC_->motorEnableRBV_, pl_status = setIntegerParam(pC_->motorEnableRBV(),
readyToBeSwitchedOn() && switchedOn()); readyToBeSwitchedOn() && switchedOn());
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_,
@ -664,27 +692,27 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Update the parameter library // Update the parameter library
if (hasError) { if (hasError) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
__LINE__); __LINE__);
} }
} }
pl_status = setIntegerParam(pC_->motorStatusMoving_, *moving); pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_", return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
__LINE__); __LINE__);
} }
pl_status = setIntegerParam(pC_->motorStatusDone_, !(*moving)); pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
pl_status = setIntegerParam(pC_->motorStatusDirection_, direction); pl_status = setIntegerParam(pC_->motorStatusDirection(), direction);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDirection_", return pC_->paramLibAccessFailed(pl_status, "motorStatusDirection_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -695,7 +723,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// masterMacsAxis::init()) // masterMacsAxis::init())
currentPosition = currentPosition / motorRecResolution; currentPosition = currentPosition / motorRecResolution;
pl_status = setDoubleParam(pC_->motorPosition_, currentPosition); pl_status = setDoubleParam(pC_->motorPosition(), currentPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
@ -723,13 +751,13 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// ========================================================================= // =========================================================================
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableRBV_, &enabled); pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableRBV(), &enabled);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution); &motorRecResolution);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_", return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
@ -738,7 +766,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
} }
if (enabled == 0) { if (enabled == 0) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), 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__);
@ -750,12 +778,12 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
motorVelocity = maxVelocity * motorRecResolution; motorVelocity = maxVelocity * motorRecResolution;
asynPrint( asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_FLOW, pC_->asynUserSelf(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d:\nMove to position %lf.\n", "Controller \"%s\", axis %d => %s, line %d:\nMove to position %lf.\n",
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_, pl_status = pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed(),
&motorCanSetSpeed); &motorCanSetSpeed);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorCanSetSpeed_", return pC_->paramLibAccessFailed(pl_status, "motorCanSetSpeed_",
@ -766,7 +794,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// Initialize the movement handshake // Initialize the movement handshake
rw_status = pC_->write(axisNo_, 86, "0"); rw_status = pC_->write(axisNo_, 86, "0");
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -784,7 +812,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
snprintf(value, sizeof(value), "%lf", motorVelocity); snprintf(value, sizeof(value), "%lf", motorVelocity);
rw_status = pC_->write(axisNo_, 05, value); rw_status = pC_->write(axisNo_, 05, value);
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, return pC_->paramLibAccessFailed(pl_status,
"motorStatusProblem_", axisNo_, "motorStatusProblem_", axisNo_,
@ -793,7 +821,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
return rw_status; return rw_status;
} }
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d:\nSetting speed " "Controller \"%s\", axis %d => %s, line %d:\nSetting speed "
"to %lf.\n", "to %lf.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
@ -804,7 +832,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
snprintf(value, sizeof(value), "%lf", motorCoordinatesPosition); snprintf(value, sizeof(value), "%lf", motorCoordinatesPosition);
rw_status = pC_->write(axisNo_, 02, value); rw_status = pC_->write(axisNo_, 02, value);
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -820,7 +848,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
rw_status = pC_->write(axisNo_, 00, "1"); rw_status = pC_->write(axisNo_, 00, "1");
} }
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -855,7 +883,29 @@ asynStatus masterMacsAxis::stop(double acceleration) {
rw_status = pC_->write(axisNo_, 00, "8"); rw_status = pC_->write(axisNo_, 00, "8");
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
return rw_status;
}
asynStatus masterMacsAxis::reset() {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
// =========================================================================
rw_status = pC_->write(axisNo_, 17, "");
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
@ -882,7 +932,7 @@ asynStatus masterMacsAxis::doHome(double min_velocity, double max_velocity,
// ========================================================================= // =========================================================================
pl_status = pC_->getStringParam(axisNo_, pC_->encoderType_, pl_status = pC_->getStringParam(axisNo_, pC_->encoderType(),
sizeof(response), response); sizeof(response), response);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_, return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
@ -895,7 +945,7 @@ asynStatus masterMacsAxis::doHome(double min_velocity, double max_velocity,
// Initialize the movement handshake // Initialize the movement handshake
rw_status = pC_->write(axisNo_, 86, "0"); rw_status = pC_->write(axisNo_, 86, "0");
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem_, true); pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, return pC_->paramLibAccessFailed(pl_status,
"motorStatusProblem_", axisNo_, "motorStatusProblem_", axisNo_,
@ -955,9 +1005,9 @@ asynStatus masterMacsAxis::readEncoderType() {
2=SSI (Absolute encoder with BiSS interface) 2=SSI (Absolute encoder with BiSS interface)
*/ */
if (encoder_id == 0) { if (encoder_id == 0) {
pl_status = setStringParam(pC_->encoderType_, IncrementalEncoder); pl_status = setStringParam(pC_->encoderType(), IncrementalEncoder);
} else { } else {
pl_status = setStringParam(pC_->encoderType_, AbsoluteEncoder); pl_status = setStringParam(pC_->encoderType(), AbsoluteEncoder);
} }
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
@ -989,13 +1039,13 @@ asynStatus masterMacsAxis::enable(bool on) {
// axis instead of "moving", since status -6 is also moving, but the // axis instead of "moving", since status -6 is also moving, but the
// motor can actually be disabled in this state! // motor can actually be disabled in this state!
if (moving) { if (moving) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not " "Controller \"%s\", axis %d => %s, line %d:\nAxis is not "
"idle and can therefore not be disabled.\n", "idle and can therefore not be disabled.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__); pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
pl_status = pl_status =
setStringParam(pC_->motorMessageText_, setStringParam(pC_->motorMessageText(),
"Axis cannot be disabled while it is moving."); "Axis cannot be disabled while it is moving.");
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
@ -1011,7 +1061,7 @@ asynStatus masterMacsAxis::enable(bool on) {
if ((readyToBeSwitchedOn() && switchedOn()) == on) { if ((readyToBeSwitchedOn() && switchedOn()) == on) {
asynPrint( asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_WARNING, pC_->asynUserSelf(), ASYN_TRACE_WARNING,
"Controller \"%s\", axis %d => %s, line %d:\nAxis is already %s.\n", "Controller \"%s\", axis %d => %s, line %d:\nAxis is already %s.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
on ? "enabled" : "disabled"); on ? "enabled" : "disabled");
@ -1020,14 +1070,14 @@ asynStatus masterMacsAxis::enable(bool on) {
// Enable / disable the axis if it is not moving // Enable / disable the axis if it is not moving
snprintf(value, sizeof(value), "%d", on); snprintf(value, sizeof(value), "%d", on);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n", "Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
on ? "Enable" : "Disable"); on ? "Enable" : "Disable");
if (on == 0) { if (on == 0) {
pl_status = setStringParam(pC_->motorMessageText_, "Disabling ..."); pl_status = setStringParam(pC_->motorMessageText(), "Disabling ...");
} else { } else {
pl_status = setStringParam(pC_->motorMessageText_, "Enabling ..."); pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
} }
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
@ -1061,7 +1111,7 @@ asynStatus masterMacsAxis::enable(bool on) {
// Failed to change axis status within timeout_enable_disable => Send a // Failed to change axis status within timeout_enable_disable => Send a
// corresponding message // corresponding message
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFailed to %s axis " "Controller \"%s\", axis %d => %s, line %d:\nFailed to %s axis "
"within %d seconds\n", "within %d seconds\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
@ -1070,7 +1120,7 @@ asynStatus masterMacsAxis::enable(bool on) {
// Output message to user // Output message to user
snprintf(value, sizeof(value), "Failed to %s within %d seconds", snprintf(value, sizeof(value), "Failed to %s within %d seconds",
on ? "enable" : "disable", timeout_enable_disable); on ? "enable" : "disable", timeout_enable_disable);
pl_status = setStringParam(pC_->motorMessageText_, "Enabling ..."); pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
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__,

View File

@ -24,15 +24,6 @@ class masterMacsAxis : public sinqAxis {
*/ */
virtual ~masterMacsAxis(); virtual ~masterMacsAxis();
/**
* @brief Implementation of the `stop` function from asynMotorAxis
*
* @param acceleration Acceleration ACCEL from the motor record. This
* value is currently not used.
* @return asynStatus
*/
asynStatus stop(double acceleration);
/** /**
* @brief Implementation of the `doHome` function from sinqAxis. The * @brief Implementation of the `doHome` function from sinqAxis. The
* parameters are described in the documentation of `sinqAxis::doHome`. * parameters are described in the documentation of `sinqAxis::doHome`.
@ -69,6 +60,23 @@ class masterMacsAxis : public sinqAxis {
asynStatus doMove(double position, int relative, double min_velocity, asynStatus doMove(double position, int relative, double min_velocity,
double max_velocity, double acceleration); double max_velocity, double acceleration);
/**
* @brief Implementation of the `stop` function from asynMotorAxis
*
* @param acceleration Acceleration ACCEL from the motor record. This
* value is currently not used.
* @return asynStatus
*/
asynStatus stop(double acceleration);
/**
* @brief Reset the axis error
*
* @param on
* @return asynStatus
*/
asynStatus reset();
/** /**
* @brief Readout of some values from the controller at IOC startup * @brief Readout of some values from the controller at IOC startup
* *
@ -273,9 +281,6 @@ class masterMacsAxis : public sinqAxis {
* @brief Read the property from axisError_ * @brief Read the property from axisError_
*/ */
bool stoFault() { return axisError_[15]; } bool stoFault() { return axisError_[15]; }
private:
friend class masterMacsController;
}; };
#endif #endif

View File

@ -49,14 +49,10 @@ masterMacsController::masterMacsController(const char *portName,
int numAxes, double movingPollPeriod, int numAxes, double movingPollPeriod,
double idlePollPeriod, double idlePollPeriod,
double comTimeout) double comTimeout)
: sinqController( : sinqController(portName, ipPortConfigName, numAxes, movingPollPeriod,
portName, ipPortConfigName, numAxes, movingPollPeriod, idlePollPeriod, idlePollPeriod,
/* // No additional parameter library entries
The following parameter library entries are added in this driver: 0)
- REREAD_ENCODER_POSITION
- READ_CONFIG
*/
NUM_masterMacs_DRIVER_PARAMS)
{ {
@ -64,39 +60,25 @@ masterMacsController::masterMacsController(const char *portName,
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
// Initialization of all member variables // Initialization of all member variables
lowLevelPortUser_ = nullptr;
comTimeout_ = comTimeout; comTimeout_ = comTimeout;
// =========================================================================; // =========================================================================
/*
We try to connect to the port via the port name provided by the constructor.
If this fails, the function is terminated via exit
*/
pasynOctetSyncIO->connect(ipPortConfigName, 0, &lowLevelPortUser_, NULL);
if (status != asynSuccess || lowLevelPortUser_ == nullptr) {
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
"connect to MCU controller).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__);
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
the message length is encoded in the message header in the getSetResponse the message length is encoded in the message header.
method.
*/ */
const char *message_from_device = "\x03"; // Hex-code for ETX const char *message_from_device = "\x0D"; // Hex-code for CR
status = pasynOctetSyncIO->setInputEos( status = pasynOctetSyncIO->setInputEos(ipPortUser_, message_from_device,
lowLevelPortUser_, message_from_device, strlen(message_from_device)); strlen(message_from_device));
if (status != asynSuccess) { if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (setting " "Controller \"%s\" => %s, line %d:\nFATAL ERROR (setting "
"input EOS failed with %s).\nTerminating IOC", "input EOS failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__, portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status)); stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(lowLevelPortUser_); pasynOctetSyncIO->disconnect(ipPortUser_);
exit(-1); exit(-1);
} }
@ -107,7 +89,7 @@ masterMacsController::masterMacsController(const char *portName,
"ParamLib callbacks failed with %s).\nTerminating IOC", "ParamLib callbacks failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__, portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status)); stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(lowLevelPortUser_); pasynOctetSyncIO->disconnect(ipPortUser_);
exit(-1); exit(-1);
} }
} }
@ -180,71 +162,53 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
return asynError; return asynError;
} }
/*
PSI SINQ uses a custom protocol which is described in
PSI_TCP_Interface_V1-8.pdf (p. // 4-17).
A special case is the message length, which is specified by two bytes
LSB and MSB: MSB = message length / 256 LSB = message length % 256. For
example, a message length of 47 chars would result in MSB = 0, LSB = 47,
whereas a message length of 356 would result in MSB = 1, LSB = 100.
The full protocol looks as follows:
0x05 -> Start of protocol frame ENQ
[LSB]
[MSB]
0x19 -> Data type PDO1
value [Actual message] It is not necessary to append a terminator, since
this protocol encodes the message length in LSB and MSB.
0x0D -> Carriage return (ASCII alias \r)
0x03 -> End of text ETX
*/
fullCommand[0] = '\x05'; // ENQ
fullCommand[1] = 1; // Placeholder value, can be anything other than 0
fullCommand[2] = 1; // Placeholder value, can be anything other than 0
fullCommand[3] = '\x19'; // PD01
// Create the command and add CR and ETX at the end
if (isRead) { if (isRead) {
snprintf(&fullCommand[4], MAXBUF_ - 4, "%dR%02d\x0D\x03", axisNo, snprintf(fullCommand, MAXBUF_ - 1, "%dR%02d\x0D", axisNo, tcpCmd);
tcpCmd);
} else { } else {
snprintf(&fullCommand[4], MAXBUF_ - 4, "%dS%02d=%s\x0D\x03", axisNo, if (strlen(payload) == 0) {
tcpCmd, payload); snprintf(fullCommand, MAXBUF_ - 1, "%dS%02d\x0D", axisNo, tcpCmd);
} else {
snprintf(fullCommand, MAXBUF_ - 1, "%dS%02d=%s\x0D", axisNo, tcpCmd,
payload);
}
} }
// Calculate the command length // Calculate the command length
const size_t fullCommandLength = strlen(fullCommand); const size_t fullCommandLength = strlen(fullCommand);
// Length of the command without ENQ and ETX
const size_t lenWithMetadata = fullCommandLength - 2;
// Perform both division and modulo operation at once.
div_t lenWithMetadataSep = std::div(lenWithMetadata, 256);
// Now set the actual command length
fullCommand[1] = lenWithMetadataSep.rem; // LSB
fullCommand[2] = lenWithMetadataSep.quot; // MSB
adjustForPrint(printableCommand, fullCommand, MAXBUF_); adjustForPrint(printableCommand, fullCommand, MAXBUF_);
// Send out the command // Send out the command
status = status = pasynOctetSyncIO->write(
pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand, ipPortUser_, fullCommand, fullCommandLength, comTimeout_, &nbytesOut);
fullCommandLength, comTimeout_, &nbytesOut);
msgPrintControlKey writeKey = msgPrintControlKey writeKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (status == asynSuccess) { if (status == asynSuccess) {
msgPrintControl_.resetCount(writeKey); msgPrintControl_.resetCount(writeKey, pasynUserSelf);
// Try to read the answer repeatedly // Try to read the answer repeatedly
int maxTrials = 2; int maxTrials = 2;
for (int i = 0; i < maxTrials; i++) { for (int i = 0; i < maxTrials; i++) {
status =
pasynOctetSyncIO->read(lowLevelPortUser_, fullResponse, MAXBUF_, /*
comTimeout_, &nbytesIn, &eomReason); A typical response of the MasterMacs controller looks like this:
(.. TCP Header ...) 31 20 52 20 31 31 3d 35 31 32 2e 30 30 30 30 06
0d 00 00 00 00 00 00 00 00 00 00 00 00 00
The message terminator is the carriage return (0d), which is
specified in the controller constructor as the end-of-string (EOS)
character. However, we also need to remove the buffer zeros at the
end, because they will otherwise confuse the
pasynOctetSyncIO->read() during the next call. The
pasynOctetSyncIO->flush() method does exactly that: it takes all
bytes it can find in the socket and throws them away. We don't check
the return value of flush(), because it is always asynSuccess (see
https://www.slac.stanford.edu/grp/lcls/controls/global/doc/epics-modules/R3-14-12/asyn/asyn-R4-18-lcls2/asyn/interfaces/asynOctetBase.c)
*/
status = pasynOctetSyncIO->read(ipPortUser_, fullResponse, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason);
pasynOctetSyncIO->flush(ipPortUser_);
if (status == asynSuccess) { if (status == asynSuccess) {
status = parseResponse(fullCommand, fullResponse, status = parseResponse(fullCommand, fullResponse,
@ -283,10 +247,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
} }
} }
// MasterMACS needs a bit of time between messages, therefore thr
// program execution is paused after the communication happened.
// usleep(1500);
// Create custom error messages for different failure modes // Create custom error messages for different failure modes
switch (status) { switch (status) {
case asynSuccess: case asynSuccess:
@ -434,7 +394,7 @@ asynStatus masterMacsController::parseResponse(
} }
if (responseValid) { if (responseValid) {
msgPrintControl_.resetCount(parseKey); msgPrintControl_.resetCount(parseKey, pasynUserSelf);
// Check if the response matches the expectations. Each response // Check if the response matches the expectations. Each response
// contains the string "axisNo R tcpCmd" (including the spaces) // contains the string "axisNo R tcpCmd" (including the spaces)
@ -475,7 +435,7 @@ asynStatus masterMacsController::parseResponse(
printableResponse, printableCommand); printableResponse, printableCommand);
return asynError; return asynError;
} else { } else {
msgPrintControl_.resetCount(responseMatchKey); msgPrintControl_.resetCount(responseMatchKey, pasynUserSelf);
} }
} }
return asynSuccess; return asynSuccess;

View File

@ -49,9 +49,6 @@ class masterMacsController : public sinqController {
*/ */
masterMacsAxis *getMasterMacsAxis(int axisNo); masterMacsAxis *getMasterMacsAxis(int axisNo);
protected:
asynUser *lowLevelPortUser_;
/** /**
* @brief Send a command to the hardware (S mode) * @brief Send a command to the hardware (S mode)
* *
@ -114,26 +111,16 @@ class masterMacsController : public sinqController {
int *valueStop, int axisNo, int tcpCmd, int *valueStop, int axisNo, int tcpCmd,
bool isRead); bool isRead);
private:
// Set the maximum buffer size. This is an empirical value which must be // Set the maximum buffer size. This is an empirical value which must be
// large enough to avoid overflows for all commands to the device / // large enough to avoid overflows for all commands to the device /
// responses from it. // responses from it.
static const uint32_t MAXBUF_ = 200; static const uint32_t MAXBUF_ = 200;
private:
/* /*
Stores the constructor input comTimeout Stores the constructor input comTimeout
*/ */
double comTimeout_; double comTimeout_;
// Indices of additional PVs
#define FIRST_masterMacs_PARAM rereadEncoderPosition_
int rereadEncoderPosition_;
int readConfig_;
#define LAST_masterMacs_PARAM readConfig_
friend class masterMacsAxis;
}; };
#define NUM_masterMacs_DRIVER_PARAMS \
(&LAST_masterMacs_PARAM - &FIRST_masterMacs_PARAM + 1)
#endif /* masterMacsController_H */ #endif /* masterMacsController_H */