2 Commits
0.3.0 ... 0.4.0

Author SHA1 Message Date
fe52245e38 Custom timeout for enable and position methods
Added a custom timeout for the enable command, as it takes quite a bit
of time for the motor controller to answer and we don't want to show a
premature communication timeout error. Also changed the code in order to
use the motorPosition() and setMotorPosition() methods instead of
directly accessing the paramLib.
2025-03-31 10:48:41 +02:00
a3e849f386 Changed to the "motorPosition" and "setMotorPosition" functions provided
by sinqMotor.
2025-03-28 14:53:04 +01:00
6 changed files with 77 additions and 67 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.9.0 sinqMotor_VERSION=0.10.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

@ -1,5 +1,7 @@
# masterMacs # masterMacs
## <span style="color:red">Please read the documentation of sinqMotor first: https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
## Overview ## Overview
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.

View File

@ -190,8 +190,8 @@ asynStatus masterMacsAxis::init() {
} }
nvals = sscanf(response, "%lf", &motorPosition); nvals = sscanf(response, "%lf", &motorPosition);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse("R12", response, axisNo_, return pC_->couldNotParseResponse("R12", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Read out the current velocity // Read out the current velocity
@ -201,8 +201,8 @@ asynStatus masterMacsAxis::init() {
} }
nvals = sscanf(response, "%lf", &motorVelocity); nvals = sscanf(response, "%lf", &motorVelocity);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse("R05", response, axisNo_, return pC_->couldNotParseResponse("R05", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Read out the maximum velocity // Read out the maximum velocity
@ -212,8 +212,8 @@ asynStatus masterMacsAxis::init() {
} }
nvals = sscanf(response, "%lf", &motorVmax); nvals = sscanf(response, "%lf", &motorVmax);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse("R26", response, axisNo_, return pC_->couldNotParseResponse("R26", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Read out the acceleration // Read out the acceleration
@ -223,8 +223,8 @@ asynStatus masterMacsAxis::init() {
} }
nvals = sscanf(response, "%lf", &motorAccel); nvals = sscanf(response, "%lf", &motorAccel);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse("R06", response, axisNo_, return pC_->couldNotParseResponse("R06", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
// Cache the motor speed. If this value differs from the one in the motor // Cache the motor speed. If this value differs from the one in the motor
@ -232,15 +232,10 @@ asynStatus masterMacsAxis::init() {
// MasterMACS. // MasterMACS.
lastSetSpeed_ = motorVelocity; lastSetSpeed_ = motorVelocity;
// Transform from motor to parameter library coordinates // Store the motor position in the parameter library
motorPosition = motorPosition / motorRecResolution; pl_status = setMotorPosition(motorPosition);
// Store these values in the parameter library
pl_status =
pC_->setDoubleParam(axisNo_, pC_->motorPosition(), motorPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pl_status;
__PRETTY_FUNCTION__, __LINE__);
} }
// Write to the motor record fields // Write to the motor record fields
@ -338,8 +333,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
nvals = sscanf(response, "%lf", &handshakePerformed); nvals = sscanf(response, "%lf", &handshakePerformed);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse( return pC_->couldNotParseResponse("R86", response, axisNo_,
"R86", response, axisNo_, __PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
if (handshakePerformed == 1.0) { if (handshakePerformed == 1.0) {
@ -379,17 +374,11 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
// Read the previous motor position // Read the previous motor position
pl_status = pl_status = motorPosition(&previousPosition);
pC_->getDoubleParam(axisNo_, pC_->motorPosition(), &previousPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pl_status;
__PRETTY_FUNCTION__, __LINE__);
} }
// Transform from EPICS to motor coordinates (see comment in
// masterMacsAxis::readConfig())
previousPosition = previousPosition * motorRecResolution;
// Update the axis status // Update the axis status
rw_status = readAxisStatus(); rw_status = readAxisStatus();
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
@ -411,8 +400,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
nvals = sscanf(response, "%lf", &currentPosition); nvals = sscanf(response, "%lf", &currentPosition);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse("R12", response, axisNo_, return pC_->couldNotParseResponse("R12", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
/* /*
@ -619,8 +608,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
nvals = sscanf(response, "%lf", &lowLimit); nvals = sscanf(response, "%lf", &lowLimit);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse( return pC_->couldNotParseResponse("R34", response, axisNo_,
"R34", response, axisNo_, __PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
rw_status = pC_->read(axisNo_, 33, response); rw_status = pC_->read(axisNo_, 33, response);
@ -629,8 +618,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
} }
nvals = sscanf(response, "%lf", &highLimit); nvals = sscanf(response, "%lf", &highLimit);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse( return pC_->couldNotParseResponse("R33", response, axisNo_,
"R33", response, axisNo_, __PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
/* /*
@ -719,14 +708,9 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
__LINE__); __LINE__);
} }
// Transform from motor to EPICS coordinates (see comment in pl_status = setMotorPosition(currentPosition);
// masterMacsAxis::init())
currentPosition = currentPosition / motorRecResolution;
pl_status = setDoubleParam(pC_->motorPosition(), currentPosition);
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorPosition_", axisNo_, return pl_status;
__PRETTY_FUNCTION__, __LINE__);
} }
return poll_status; return poll_status;
@ -894,7 +878,7 @@ asynStatus masterMacsAxis::stop(double acceleration) {
return rw_status; return rw_status;
} }
asynStatus masterMacsAxis::reset() { asynStatus masterMacsAxis::doReset() {
// Status of read-write-operations of ASCII commands to the controller // Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess; asynStatus rw_status = asynSuccess;
@ -994,8 +978,8 @@ asynStatus masterMacsAxis::readEncoderType() {
nvals = sscanf(response, "%d", &encoder_id); nvals = sscanf(response, "%d", &encoder_id);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse(command, response, axisNo_, return pC_->couldNotParseResponse(command, response, axisNo_,
__PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
/* /*
@ -1084,7 +1068,11 @@ asynStatus masterMacsAxis::enable(bool on) {
axisNo_, __PRETTY_FUNCTION__, axisNo_, __PRETTY_FUNCTION__,
__LINE__); __LINE__);
} }
rw_status = pC_->write(axisNo_, 04, value);
// The answer to the enable command on MasterMACS might take some time,
// hence we wait for a custom timespan in seconds instead of
// pC_->comTimeout_
rw_status = pC_->write(axisNo_, 04, value, 1.0);
if (rw_status != asynSuccess) { if (rw_status != asynSuccess) {
return rw_status; return rw_status;
} }
@ -1154,8 +1142,8 @@ asynStatus masterMacsAxis::readAxisStatus() {
float axisStatus = 0; float axisStatus = 0;
int nvals = sscanf(response, "%f", &axisStatus); int nvals = sscanf(response, "%f", &axisStatus);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse( return pC_->couldNotParseResponse("R10", response, axisNo_,
"R10", response, axisNo_, __PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
axisStatus_ = toBitset(axisStatus); axisStatus_ = toBitset(axisStatus);
@ -1175,8 +1163,8 @@ asynStatus masterMacsAxis::readAxisError() {
float axisError = 0; float axisError = 0;
int nvals = sscanf(response, "%f", &axisError); int nvals = sscanf(response, "%f", &axisError);
if (nvals != 1) { if (nvals != 1) {
return pC_->errMsgCouldNotParseResponse( return pC_->couldNotParseResponse("R11", response, axisNo_,
"R11", response, axisNo_, __PRETTY_FUNCTION__, __LINE__); __PRETTY_FUNCTION__, __LINE__);
} }
axisError_ = toBitset(axisError); axisError_ = toBitset(axisError);
} }

View File

@ -70,12 +70,12 @@ class masterMacsAxis : public sinqAxis {
asynStatus stop(double acceleration); asynStatus stop(double acceleration);
/** /**
* @brief Reset the axis error * @brief Implementation of the `doReset` function from sinqAxis.
* *
* @param on * @param on
* @return asynStatus * @return asynStatus
*/ */
asynStatus reset(); asynStatus doReset();
/** /**
* @brief Readout of some values from the controller at IOC startup * @brief Readout of some values from the controller at IOC startup

View File

@ -113,18 +113,19 @@ masterMacsAxis *masterMacsController::getMasterMacsAxis(int axisNo) {
return dynamic_cast<masterMacsAxis *>(asynAxis); return dynamic_cast<masterMacsAxis *>(asynAxis);
} }
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response) { asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response,
double comTimeout) {
return writeRead(axisNo, tcpCmd, NULL, response); return writeRead(axisNo, tcpCmd, NULL, response);
} }
asynStatus masterMacsController::write(int axisNo, int tcpCmd, asynStatus masterMacsController::write(int axisNo, int tcpCmd,
const char *payload) { const char *payload, double comTimeout) {
return writeRead(axisNo, tcpCmd, payload, NULL); return writeRead(axisNo, tcpCmd, payload, NULL, comTimeout);
} }
asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd, asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
const char *payload, const char *payload, char *response,
char *response) { double comTimeout) {
// Definition of local variables. // Definition of local variables.
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@ -156,6 +157,11 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
// ========================================================================= // =========================================================================
// Check if a timeout has been given
if (comTimeout < 0.0) {
comTimeout = comTimeout_;
}
masterMacsAxis *axis = getMasterMacsAxis(axisNo); masterMacsAxis *axis = getMasterMacsAxis(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
@ -179,8 +185,16 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
adjustForPrint(printableCommand, fullCommand, MAXBUF_); adjustForPrint(printableCommand, fullCommand, MAXBUF_);
// Send out the command // Send out the command
status = pasynOctetSyncIO->write( status = pasynOctetSyncIO->write(ipPortUser_, fullCommand,
ipPortUser_, fullCommand, fullCommandLength, comTimeout_, &nbytesOut); fullCommandLength, comTimeout, &nbytesOut);
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nError "
"%s while writing to the controller\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
}
msgPrintControlKey writeKey = msgPrintControlKey writeKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
@ -207,24 +221,28 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
https://www.slac.stanford.edu/grp/lcls/controls/global/doc/epics-modules/R3-14-12/asyn/asyn-R4-18-lcls2/asyn/interfaces/asynOctetBase.c) 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_, status = pasynOctetSyncIO->read(ipPortUser_, fullResponse, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason); comTimeout, &nbytesIn, &eomReason);
pasynOctetSyncIO->flush(ipPortUser_); pasynOctetSyncIO->flush(ipPortUser_);
if (status == asynSuccess) { if (status == asynSuccess) {
status = parseResponse(fullCommand, fullResponse, status = parseResponse(fullCommand, fullResponse,
drvMessageText, &valueStart, &valueStop, drvMessageText, &valueStart, &valueStop,
axisNo, tcpCmd, isRead); axisNo, tcpCmd, isRead);
if (status == asynSuccess) { if (status == asynSuccess) {
// Received the correct message // Received the correct message
break; break;
} }
} else { } else {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (status != asynTimeout) {
"Controller \"%s\", axis %d => %s, line %d:\nError " asynPrint(
"%s while reading from the controller\n", this->pasynUserSelf, ASYN_TRACE_ERROR,
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, "Controller \"%s\", axis %d => %s, line %d:\nError "
stringifyAsynStatus(status)); "%s while reading from the controller\n",
break; portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
break;
}
} }
if (i + 1 == maxTrials && status == asynError) { if (i + 1 == maxTrials && status == asynError) {

View File

@ -57,7 +57,8 @@ class masterMacsController : public sinqController {
* @param payload Value send to MasterMACS. * @param payload Value send to MasterMACS.
* @return asynStatus * @return asynStatus
*/ */
asynStatus write(int axisNo, int tcpCmd, const char *payload); asynStatus write(int axisNo, int tcpCmd, const char *payload,
double comTimeout = -1.0);
/** /**
* @brief Send a command to the hardware and receive a response (R mode) * @brief Send a command to the hardware and receive a response (R mode)
@ -68,7 +69,8 @@ class masterMacsController : public sinqController {
* expected to have the size MAXBUF_. * expected to have the size MAXBUF_.
* @return asynStatus * @return asynStatus
*/ */
asynStatus read(int axisNo, int tcpCmd, char *response); asynStatus read(int axisNo, int tcpCmd, char *response,
double comTimeout = -1.0);
/** /**
* @brief Send a command to the hardware (R or S mode) and receive a * @brief Send a command to the hardware (R or S mode) and receive a
@ -85,7 +87,7 @@ class masterMacsController : public sinqController {
* @return asynStatus * @return asynStatus
*/ */
asynStatus writeRead(int axisNo, int tcpCmd, const char *payload, asynStatus writeRead(int axisNo, int tcpCmd, const char *payload,
char *response); char *response, double comTimeout = -1.0);
/** /**
* @brief Parse "fullResponse" received upon sending "fullCommand". * @brief Parse "fullResponse" received upon sending "fullCommand".