21 Commits
0.7.0 ... 1.1.2

Author SHA1 Message Date
52fa4e1e78 Updated sinqMotor version 2025-06-18 08:35:00 +02:00
a9e08460d9 Updated sinqMotor 2025-06-18 08:17:21 +02:00
37dacbd3ee Updated sinqMotor version and removed unnecessary require 2025-06-17 13:21:59 +02:00
d198dc8c9f Use axisParam accessor macros 2025-06-17 13:21:55 +02:00
13f2ec4fbf Switched to macro-based getters and setters for paramLib 2025-06-17 13:21:08 +02:00
6ccb60f263 Merge pull request 'Remove sinqmotor dep, it's statically linked. specify rhel8 arch' (#1) from makefile-fixes into main
Reviewed-on: #1
2025-06-11 16:52:42 +02:00
b8730e80e0 Remove sinqmotor dep, it's statically linked. specify rhel8 arch 2025-05-28 10:54:59 +02:00
deb6e6996e Ready for release 1.0 2025-05-23 12:29:30 +02:00
d1d694ad6b Applied PIMPL principle 2025-05-23 12:16:25 +02:00
e0a74c5598 Changed sinqMotor version to 0.15.2 2025-05-16 16:15:01 +02:00
c334ed9f04 Add default value for motorMessageText 2025-05-15 12:22:33 +02:00
4b0031c3af Fixed bug with readInt32 function 2025-05-15 12:03:06 +02:00
61335970ce Use latest version of sinqMotor 2025-05-15 11:43:40 +02:00
081a21073b Adjusted Makefile for static linking 2025-05-15 11:34:43 +02:00
f2e8eb2762 Fixed serious bug in sinqMotor 2025-05-15 11:32:35 +02:00
e93f11e779 Adjusted usage of motorMessageText to be an error text only 2025-05-14 16:28:51 +02:00
989410474e Added sinqMotor 0.15.0 as static dependency 2025-05-14 16:20:08 +02:00
8d8561d833 Removed sinqMotor from required
sinqMotor is statically compiled into this driver.
2025-05-14 12:20:15 +02:00
a56a8cf646 Added explanation why the return status of doPoll is not used in the enable function. 2025-05-13 14:46:13 +02:00
cd57409f3c Added motorConnected logic 2025-04-25 15:58:03 +02:00
21ffcba8be Back to dev version 2025-04-22 15:07:45 +02:00
7 changed files with 438 additions and 427 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "sinqMotor"]
path = sinqMotor
url = https://gitea.psi.ch/lin-epics-modules/sinqMotor

View File

@ -6,24 +6,26 @@ BUILDCLASSES=Linux
EPICS_VERSIONS=7.0.7
ARCH_FILTER=RHEL%
# Additional module dependencies
REQUIRED+=sinqMotor
# Specify the version of asynMotor we want to build against
motorBase_VERSION=7.2.2
# Specify the version of sinqMotor we want to build against
sinqMotor_VERSION=0.13.0
# These headers allow to depend on this library for derived drivers.
HEADERS += src/masterMacsAxis.h
HEADERS += src/masterMacsController.h
# Source files to build
SOURCES += sinqMotor/src/msgPrintControl.cpp
SOURCES += sinqMotor/src/sinqAxis.cpp
SOURCES += sinqMotor/src/sinqController.cpp
SOURCES += src/masterMacsAxis.cpp
SOURCES += src/masterMacsController.cpp
# Store the record files
TEMPLATES += sinqMotor/db/asynRecord.db
TEMPLATES += sinqMotor/db/sinqMotor.db
# This file registers the motor-specific functions in the IOC shell.
DBDS += sinqMotor/src/sinqMotor.dbd
DBDS += src/masterMacs.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wpedantic -Wextra -Werror
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wextra -Werror

1
sinqMotor Submodule

Submodule sinqMotor added at 55a9fe6f3e

View File

@ -11,6 +11,21 @@
#include <string.h>
#include <unistd.h>
struct masterMacsAxisImpl {
/*
The axis status and axis error of MasterMACS are given as an integer from
the controller. The 16 individual bits contain the actual information.
*/
std::bitset<16> axisStatus;
std::bitset<16> axisError;
double lastSetSpeed;
bool waitForHandshake;
time_t timeAtHandshake;
bool needInit = true;
bool targetReachedUninitialized;
};
/*
A special communication timeout is used in the following two cases:
1) Enable command
@ -104,17 +119,14 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
// Collect all axes into this list which will be used in the hook function
axes.push_back(this);
// Initialize all member variables
axisStatus_ = std::bitset<16>(0);
axisError_ = std::bitset<16>(0);
// Initial value for the motor speed, is overwritten in atFirstPoll.
lastSetSpeed_ = 0.0;
// Flag for handshake waiting
waitForHandshake_ = false;
timeAtHandshake_ = 0;
targetReachedUninitialized_ = true;
pMasterMacsA_ = std::make_unique<masterMacsAxisImpl>((masterMacsAxisImpl){
.axisStatus = std::bitset<16>(0),
.axisError = std::bitset<16>(0),
.lastSetSpeed = 0.0,
.waitForHandshake = false,
.timeAtHandshake = 0,
.targetReachedUninitialized = true,
});
// masterMacs motors can always be disabled
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
@ -138,6 +150,20 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
}
// Even though this happens already in sinqAxis, a default value for
// motorMessageText is set here again, because apparently the sinqAxis
// constructor is not run before the string is accessed?
status = setStringParam(pC_->motorMessageText(), "");
if (status != asynSuccess) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
}
masterMacsAxis::~masterMacsAxis(void) {
@ -239,7 +265,7 @@ asynStatus masterMacsAxis::init() {
// Cache the motor speed. If this value differs from the one in the motor
// record at the start of a movement, the motor record value is sent to
// MasterMACS.
lastSetSpeed_ = motorVelocity;
pMasterMacsA_->lastSetSpeed = motorVelocity;
// Store the motor position in the parameter library
pl_status = setMotorPosition(motorPosition);
@ -275,6 +301,10 @@ asynStatus masterMacsAxis::init() {
pC_->stringifyAsynStatus(pl_status));
return pl_status;
}
// Axis is fully initialized
setNeedInit(false);
return pl_status;
}
@ -305,13 +335,21 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// =========================================================================
// Does the axis need to be intialized?
if (needInit()) {
rw_status = init();
if (rw_status != asynSuccess) {
return rw_status;
}
}
// Are we currently waiting for a handshake?
if (waitForHandshake_) {
if (pMasterMacsA_->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);
bool timedOut = (currentTime > pMasterMacsA_->timeAtHandshake + 5);
if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
@ -321,18 +359,12 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
"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);
pMasterMacsA_->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__);
}
setAxisParamChecked(this, motorMessageText,
"Timed out while waiting for a handshake");
}
pC_->read(axisNo_, 86, response);
@ -349,39 +381,22 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (handshakePerformed == 1.0) {
// Handshake has been performed successfully -> Continue with the
// poll
waitForHandshake_ = false;
targetReachedUninitialized_ = false;
pMasterMacsA_->waitForHandshake = false;
pMasterMacsA_->targetReachedUninitialized = false;
} else {
// Still waiting for the handshake - try again in the next busy
// poll. This is already part of the movement procedure.
*moving = true;
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status,
"motorStatusMoving_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving));
return asynSuccess;
}
}
// Motor resolution from parameter library
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
// Read the previous motor position
pl_status = motorPosition(&previousPosition);
@ -395,7 +410,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
return rw_status;
}
if (targetReachedUninitialized_) {
if (pMasterMacsA_->targetReachedUninitialized) {
*moving = false;
} else {
if (targetReached() || !switchedOn()) {
@ -406,7 +421,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
}
if (targetReached()) {
targetReachedUninitialized_ = false;
pMasterMacsA_->targetReachedUninitialized = false;
}
// Read the current position
@ -445,22 +460,16 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
pC_->getMsgPrintControl().getSuffix());
}
pl_status =
setStringParam(pC_->motorMessageText(),
"Communication error between PC and motor "
"controller. Please call the support.");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText,
"Communication error between PC and motor "
"controller. Please call the support.");
poll_status = asynError;
} else {
// This buffer must be initialized to zero because we build the
// error message by appending strings.
char userMessage[pC_->MAXBUF_] = {0};
char errorMessage[pC_->MAXBUF_] = {0};
char shellMessage[pC_->MAXBUF_] = {0};
// Concatenate all other errors
@ -468,7 +477,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Short circuit fault.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Short circuit error. Please call the support.");
poll_status = asynError;
@ -477,7 +486,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (encoderError()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Encoder error.");
appendErrorMessage(userMessage, sizeof(userMessage),
appendErrorMessage(errorMessage, sizeof(errorMessage),
"Encoder error. Please call the support.");
poll_status = asynError;
@ -488,7 +497,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
shellMessage, sizeof(shellMessage),
"Maximum callowed following error exceeded.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Maximum allowed following error exceeded.Check if "
"movement range is blocked. Otherwise please call the "
"support.");
@ -499,7 +508,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (feedbackError()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Feedback error.");
appendErrorMessage(userMessage, sizeof(userMessage),
appendErrorMessage(errorMessage, sizeof(errorMessage),
"Feedback error. Please call the support.");
poll_status = asynError;
@ -535,7 +544,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Generic error message for user
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Software limits or end switch hit. Try homing the motor, "
"moving in the opposite direction or check the SPS for "
"errors (if available). Otherwise please call the "
@ -548,7 +557,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overcurrent error.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Overcurrent error. Please call the support.");
poll_status = asynError;
@ -558,7 +567,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overtemperature error.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Overtemperature error. Please call the support.");
poll_status = asynError;
@ -568,7 +577,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overvoltage error.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Overvoltage error. Please call the support.");
poll_status = asynError;
@ -578,7 +587,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Undervoltage error.");
appendErrorMessage(
userMessage, sizeof(userMessage),
errorMessage, sizeof(errorMessage),
"Undervoltage error. Please call the support.");
poll_status = asynError;
@ -587,7 +596,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (stoFault()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"STO input is on disable state.");
appendErrorMessage(userMessage, sizeof(userMessage),
appendErrorMessage(errorMessage, sizeof(errorMessage),
"STO fault. Please call the support.");
poll_status = asynError;
@ -605,12 +614,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
}
}
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText, errorMessage);
}
} else {
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
@ -651,40 +655,18 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
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.
*/
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorLimitsOffset(),
&limitsOffset);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLimitsOffset_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorLimitsOffset, &limitsOffset);
highLimit = highLimit - limitsOffset;
lowLimit = lowLimit + limitsOffset;
pl_status = pC_->setDoubleParam(
axisNo_, pC_->motorHighLimitFromDriver(), highLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(
pl_status, "motorHighLimitFromDriver_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorLowLimitFromDriver(),
lowLimit);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorLowLimit_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorHighLimitFromDriver, highLimit);
setAxisParamChecked(this, motorLowLimitFromDriver, lowLimit);
}
// Update the enable PV
pl_status = setIntegerParam(pC_->motorEnableRBV(),
readyToBeSwitchedOn() && switchedOn());
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorEnableRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
setAxisParamChecked(this, motorEnableRBV,
readyToBeSwitchedOn() && switchedOn());
if (*moving) {
// If the axis is moving, evaluate the movement direction
@ -697,32 +679,11 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Update the parameter library
if (hasError) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
pl_status = setIntegerParam(pC_->motorStatusMoving(), *moving);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusMoving_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = setIntegerParam(pC_->motorStatusDone(), !(*moving));
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDone_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = setIntegerParam(pC_->motorStatusDirection(), direction);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusDirection_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
setAxisParamChecked(this, motorStatusProblem, true);
}
setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving));
setAxisParamChecked(this, motorStatusDirection, direction);
pl_status = setMotorPosition(currentPosition);
if (pl_status != asynSuccess) {
@ -737,10 +698,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
double acceleration) {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
asynStatus status = asynSuccess;
char value[pC_->MAXBUF_];
double motorCoordinatesPosition = 0.0;
@ -751,19 +709,8 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// =========================================================================
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableRBV(), &enabled);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "enableMotorRBV_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
&motorRecResolution);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorEnableRBV, &enabled);
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
if (enabled == 0) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
@ -783,42 +730,26 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
// Check if the speed is allowed to be changed
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed(),
&motorCanSetSpeed);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorCanSetSpeed_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
getAxisParamChecked(this, motorCanSetSpeed, &motorCanSetSpeed);
// Initialize the movement handshake
rw_status = pC_->write(axisNo_, 86, "0");
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
return rw_status;
status = pC_->write(axisNo_, 86, "0");
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
// Set the new motor speed, if the user is allowed to do so and if the
// motor speed changed since the last move command.
if (motorCanSetSpeed != 0 && lastSetSpeed_ != motorVelocity) {
if (motorCanSetSpeed != 0 && pMasterMacsA_->lastSetSpeed != motorVelocity) {
lastSetSpeed_ = motorVelocity;
pMasterMacsA_->lastSetSpeed = motorVelocity;
snprintf(value, sizeof(value), "%lf", motorVelocity);
rw_status = pC_->write(axisNo_, 05, value);
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status,
"motorStatusProblem_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return rw_status;
status = pC_->write(axisNo_, 05, value);
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
@ -830,43 +761,34 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
// Set the target position
snprintf(value, sizeof(value), "%lf", motorCoordinatesPosition);
rw_status = pC_->write(axisNo_, 02, value);
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
return rw_status;
status = pC_->write(axisNo_, 02, value);
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
// If the motor has just been enabled, use Enable
double timeout = pC_->comTimeout();
if (targetReachedUninitialized_ && timeout < PowerCycleTimeout) {
if (pMasterMacsA_->targetReachedUninitialized &&
timeout < PowerCycleTimeout) {
timeout = PowerCycleTimeout;
}
// Start the move
if (relative) {
rw_status = pC_->write(axisNo_, 00, "2", timeout);
status = pC_->write(axisNo_, 00, "2", timeout);
} else {
rw_status = pC_->write(axisNo_, 00, "1", timeout);
status = pC_->write(axisNo_, 00, "1", timeout);
}
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
return rw_status;
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
// In the next poll, we will check if the handshake has been performed in a
// reasonable time
waitForHandshake_ = true;
timeAtHandshake_ = time(NULL);
pMasterMacsA_->waitForHandshake = true;
pMasterMacsA_->timeAtHandshake = time(NULL);
// Waiting for a handshake is already part of the movement procedure =>
// Start the watchdog
@ -874,52 +796,35 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
return asynError;
}
return rw_status;
return status;
}
asynStatus masterMacsAxis::stop(double acceleration) {
// 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_, 00, "8");
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
asynStatus status = pC_->write(axisNo_, 00, "8");
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
}
return rw_status;
// Reset the driver to idle state and move out of the handshake wait loop,
// if we're currently inside it.
pMasterMacsA_->waitForHandshake = false;
return status;
}
asynStatus masterMacsAxis::doReset() {
// 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) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
asynStatus status = pC_->write(axisNo_, 17, "");
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
}
return rw_status;
// Reset the driver to idle state and move out of the handshake wait loop,
// if we're currently inside it.
pMasterMacsA_->waitForHandshake = false;
return status;
}
/*
@ -928,47 +833,31 @@ Home the axis. On absolute encoder systems, this is a no-op
asynStatus masterMacsAxis::doHome(double min_velocity, double max_velocity,
double acceleration, int forwards) {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
char response[pC_->MAXBUF_] = {0};
// =========================================================================
pl_status = pC_->getStringParam(axisNo_, pC_->encoderType(),
sizeof(response), response);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
getAxisParamChecked(this, encoderType, &response);
// Only send the home command if the axis has an incremental encoder
if (strcmp(response, IncrementalEncoder) == 0) {
// Initialize the movement handshake
rw_status = pC_->write(axisNo_, 86, "0");
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status,
"motorStatusProblem_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return rw_status;
asynStatus status = pC_->write(axisNo_, 86, "0");
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
return status;
}
rw_status = pC_->write(axisNo_, 00, "9");
if (rw_status != asynSuccess) {
return rw_status;
status = pC_->write(axisNo_, 00, "9");
if (status != asynSuccess) {
return status;
}
// In the next poll, we will check if the handshake has been performed
// in a reasonable time
waitForHandshake_ = true;
timeAtHandshake_ = time(NULL);
pMasterMacsA_->waitForHandshake = true;
pMasterMacsA_->timeAtHandshake = time(NULL);
return asynSuccess;
} else {
return asynError;
@ -980,12 +869,6 @@ Read the encoder type and update the parameter library accordingly
*/
asynStatus masterMacsAxis::readEncoderType() {
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
char command[pC_->MAXBUF_] = {0};
char response[pC_->MAXBUF_] = {0};
int nvals = 0;
@ -994,9 +877,9 @@ asynStatus masterMacsAxis::readEncoderType() {
// =========================================================================
// Check if this is an absolute encoder
rw_status = pC_->read(axisNo_, 60, response);
if (rw_status != asynSuccess) {
return rw_status;
asynStatus status = pC_->read(axisNo_, 60, response);
if (status != asynSuccess) {
return status;
}
nvals = sscanf(response, "%d", &encoder_id);
@ -1012,30 +895,18 @@ asynStatus masterMacsAxis::readEncoderType() {
2=SSI (Absolute encoder with BiSS interface)
*/
if (encoder_id == 0) {
pl_status = setStringParam(pC_->encoderType(), IncrementalEncoder);
setAxisParamChecked(this, encoderType, IncrementalEncoder);
} else {
pl_status = setStringParam(pC_->encoderType(), AbsoluteEncoder);
setAxisParamChecked(this, encoderType, AbsoluteEncoder);
}
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "encoderType_", axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
return asynSuccess;
}
asynStatus masterMacsAxis::enable(bool on) {
int timeout_enable_disable = 2;
char value[pC_->MAXBUF_];
// Status of read-write-operations of ASCII commands to the controller
asynStatus rw_status = asynSuccess;
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
bool moving = false;
char msg[pC_->MAXBUF_];
// =========================================================================
@ -1044,8 +915,15 @@ asynStatus masterMacsAxis::enable(bool on) {
0. In order to prevent the poll method in interpreting the motor state as
"moving", this flag is used. It is reset in the handshake.
*/
targetReachedUninitialized_ = true;
pMasterMacsA_->targetReachedUninitialized = true;
/*
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
function fails before it can determine that, it is assumed that the motor
is not moving.
*/
bool moving = false;
doPoll(&moving);
// If the axis is currently moving, it cannot be disabled. Ignore the
@ -1058,14 +936,8 @@ asynStatus masterMacsAxis::enable(bool on) {
"idle and can therefore not be disabled.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
pl_status =
setStringParam(pC_->motorMessageText(),
"Axis cannot be disabled while it is moving.");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText,
"Axis cannot be disabled while it is moving.");
return asynError;
}
@ -1083,33 +955,24 @@ asynStatus masterMacsAxis::enable(bool on) {
}
// Enable / disable the axis if it is not moving
snprintf(value, sizeof(value), "%d", on);
snprintf(msg, sizeof(msg), "%d", on);
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
on ? "Enable" : "Disable");
if (on == 0) {
pl_status = setStringParam(pC_->motorMessageText(), "Disabling ...");
} else {
pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
}
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
// 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_
double timeout = pC_->comTimeout();
if (targetReachedUninitialized_ && timeout < PowerCycleTimeout) {
if (pMasterMacsA_->targetReachedUninitialized &&
timeout < PowerCycleTimeout) {
timeout = PowerCycleTimeout;
}
rw_status = pC_->write(axisNo_, 04, value, timeout);
if (rw_status != asynSuccess) {
return rw_status;
asynStatus status = pC_->write(axisNo_, 04, msg, timeout);
if (status != asynSuccess) {
return status;
}
// Query the axis status every few milliseconds until the axis has been
@ -1119,9 +982,9 @@ asynStatus masterMacsAxis::enable(bool on) {
// Read the axis status
usleep(100000);
rw_status = readAxisStatus();
if (rw_status != asynSuccess) {
return rw_status;
status = readAxisStatus();
if (status != asynSuccess) {
return status;
}
if (switchedOn() == on) {
@ -1141,17 +1004,24 @@ asynStatus masterMacsAxis::enable(bool on) {
on ? "enable" : "disable", timeout_enable_disable);
// Output message to user
snprintf(value, sizeof(value), "Failed to %s within %d seconds",
snprintf(msg, sizeof(msg), "Failed to %s within %d seconds",
on ? "enable" : "disable", timeout_enable_disable);
pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(this, motorMessageText, msg);
return asynError;
}
bool masterMacsAxis::needInit() { return pMasterMacsA_->needInit; }
/**
* @brief Instruct the axis to run its init() function during the next poll
*
* @param needInit
*/
void masterMacsAxis::setNeedInit(bool needInit) {
pMasterMacsA_->needInit = needInit;
}
/**
Convert a float to an unint16_t bitset
*/
@ -1181,7 +1051,7 @@ asynStatus masterMacsAxis::readAxisStatus() {
__PRETTY_FUNCTION__, __LINE__);
}
axisStatus_ = toBitset(axisStatus);
pMasterMacsA_->axisStatus = toBitset(axisStatus);
}
return rw_status;
@ -1201,11 +1071,83 @@ asynStatus masterMacsAxis::readAxisError() {
return pC_->couldNotParseResponse("R11", response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
axisError_ = toBitset(axisError);
pMasterMacsA_->axisError = toBitset(axisError);
}
return rw_status;
}
bool masterMacsAxis::readyToBeSwitchedOn() {
return pMasterMacsA_->axisStatus[0];
}
bool masterMacsAxis::switchedOn() { return pMasterMacsA_->axisStatus[1]; }
bool masterMacsAxis::faultConditionSet() {
return pMasterMacsA_->axisStatus[3];
}
bool masterMacsAxis::voltagePresent() { return pMasterMacsA_->axisStatus[4]; }
bool masterMacsAxis::quickStopping() {
return pMasterMacsA_->axisStatus[5] == 0;
}
bool masterMacsAxis::switchOnDisabled() { return pMasterMacsA_->axisStatus[6]; }
bool masterMacsAxis::warning() { return pMasterMacsA_->axisStatus[7]; }
bool masterMacsAxis::remoteMode() { return pMasterMacsA_->axisStatus[9]; }
bool masterMacsAxis::targetReached() { return pMasterMacsA_->axisStatus[10]; }
bool masterMacsAxis::internalLimitActive() {
return pMasterMacsA_->axisStatus[11];
}
bool masterMacsAxis::setEventHasOcurred() {
return pMasterMacsA_->axisStatus[14];
}
bool masterMacsAxis::powerEnabled() { return pMasterMacsA_->axisStatus[15]; }
bool masterMacsAxis::shortCircuit() { return pMasterMacsA_->axisError[1]; }
bool masterMacsAxis::encoderError() { return pMasterMacsA_->axisError[2]; }
bool masterMacsAxis::followingError() { return pMasterMacsA_->axisError[3]; }
bool masterMacsAxis::communicationError() {
return pMasterMacsA_->axisError[4];
}
bool masterMacsAxis::feedbackError() { return pMasterMacsA_->axisError[5]; }
bool masterMacsAxis::positiveLimitSwitch() {
return pMasterMacsA_->axisError[6];
}
bool masterMacsAxis::negativeLimitSwitch() {
return pMasterMacsA_->axisError[7];
}
bool masterMacsAxis::positiveSoftwareLimit() {
return pMasterMacsA_->axisError[8];
}
bool masterMacsAxis::negativeSoftwareLimit() {
return pMasterMacsA_->axisError[9];
}
bool masterMacsAxis::overCurrent() { return pMasterMacsA_->axisError[10]; }
bool masterMacsAxis::overTemperature() { return pMasterMacsA_->axisError[11]; }
bool masterMacsAxis::overVoltage() { return pMasterMacsA_->axisError[12]; }
bool masterMacsAxis::underVoltage() { return pMasterMacsA_->axisError[13]; }
bool masterMacsAxis::stoFault() { return pMasterMacsA_->axisError[15]; }
/***************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */

View File

@ -1,12 +1,10 @@
#ifndef masterMacsAXIS_H
#define masterMacsAXIS_H
#include "masterMacsController.h"
#include "sinqAxis.h"
#include <bitset>
#include <memory>
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
// https://en.cppreference.com/w/cpp/language/class.
class masterMacsController;
struct masterMacsAxisImpl;
class masterMacsAxis : public sinqAxis {
public:
@ -105,22 +103,25 @@ class masterMacsAxis : public sinqAxis {
*/
asynStatus readEncoderType();
protected:
masterMacsController *pC_;
double lastSetSpeed_;
bool waitForHandshake_;
time_t timeAtHandshake_;
/**
* @brief Check if the axis needs to run its initialization function
*
* @return true
* @return false
*/
bool needInit();
bool targetReachedUninitialized_;
/**
* @brief Instruct the axis to run its init() function during the next poll
*
* @param needInit
*/
void setNeedInit(bool needInit);
asynStatus readConfig();
/*
The axis status and axis error of MasterMACS are given as an integer from
the controller. The 16 individual bits contain the actual information.
*/
std::bitset<16> axisStatus_;
std::bitset<16> axisError_;
/**
* @brief Return a pointer to the axis controller
*/
virtual masterMacsController *pController() override { return pC_; };
/**
* @brief Read the Master MACS status with the xR10 command and store the
@ -130,7 +131,7 @@ class masterMacsAxis : public sinqAxis {
asynStatus readAxisStatus();
/*
The functions below read the specified status bit from the axisStatus_
The functions below read the specified status bit from the axisStatus
bitset. Since a bit can either be 0 or 1, the return value is given as a
boolean.
*/
@ -138,68 +139,68 @@ class masterMacsAxis : public sinqAxis {
/**
* @brief Read the property from axisStatus_
*/
bool readyToBeSwitchedOn() { return axisStatus_[0]; }
bool readyToBeSwitchedOn();
/**
* @brief Read the property from axisStatus_
*/
bool switchedOn() { return axisStatus_[1]; }
bool switchedOn();
// Bit 2 is unused
/**
* @brief Read the property from axisStatus_
*/
bool faultConditionSet() { return axisStatus_[3]; }
bool faultConditionSet();
/**
* @brief Read the property from axisStatus_
*/
bool voltagePresent() { return axisStatus_[4]; }
bool voltagePresent();
/**
* @brief Read the property from axisStatus_
*/
bool quickStopping() { return axisStatus_[5] == 0; }
bool quickStopping();
/**
* @brief Read the property from axisStatus_
*/
bool switchOnDisabled() { return axisStatus_[6]; }
bool switchOnDisabled();
/**
* @brief Read the property from axisStatus_
*/
bool warning() { return axisStatus_[7]; }
bool warning();
// Bit 8 is unused
/**
* @brief Read the property from axisStatus_
*/
bool remoteMode() { return axisStatus_[9]; }
bool remoteMode();
/**
* @brief Read the property from axisStatus_
*/
bool targetReached() { return axisStatus_[10]; }
bool targetReached();
/**
* @brief Read the property from axisStatus_
*/
bool internalLimitActive() { return axisStatus_[11]; }
bool internalLimitActive();
// Bits 12 and 13 are unused
/**
* @brief Read the property from axisStatus_
*/
bool setEventHasOcurred() { return axisStatus_[14]; }
bool setEventHasOcurred();
/**
* @brief Read the property from axisStatus_
*/
bool powerEnabled() { return axisStatus_[15]; }
bool powerEnabled();
/**
* @brief Read the Master MACS status with the xR10 command and store the
@ -217,72 +218,76 @@ class masterMacsAxis : public sinqAxis {
/**
* @brief Read the property from axisError_
*/
bool shortCircuit() { return axisError_[1]; }
bool shortCircuit();
/**
* @brief Read the property from axisError_
*/
bool encoderError() { return axisError_[2]; }
bool encoderError();
/**
* @brief Read the property from axisError_
*/
bool followingError() { return axisError_[3]; }
bool followingError();
/**
* @brief Read the property from axisError_
*/
bool communicationError() { return axisError_[4]; }
bool communicationError();
/**
* @brief Read the property from axisError_
*/
bool feedbackError() { return axisError_[5]; }
bool feedbackError();
/**
* @brief Read the property from axisError_
*/
bool positiveLimitSwitch() { return axisError_[6]; }
bool positiveLimitSwitch();
/**
* @brief Read the property from axisError_
*/
bool negativeLimitSwitch() { return axisError_[7]; }
bool negativeLimitSwitch();
/**
* @brief Read the property from axisError_
*/
bool positiveSoftwareLimit() { return axisError_[8]; }
bool positiveSoftwareLimit();
/**
* @brief Read the property from axisError_
*/
bool negativeSoftwareLimit() { return axisError_[9]; }
bool negativeSoftwareLimit();
/**
* @brief Read the property from axisError_
*/
bool overCurrent() { return axisError_[10]; }
bool overCurrent();
/**
* @brief Read the property from axisError_
*/
bool overTemperature() { return axisError_[11]; }
bool overTemperature();
/**
* @brief Read the property from axisError_
*/
bool overVoltage() { return axisError_[12]; }
bool overVoltage();
/**
* @brief Read the property from axisError_
*/
bool underVoltage() { return axisError_[13]; }
bool underVoltage();
/**
* @brief Read the property from axisError_
*/
bool stoFault() { return axisError_[15]; }
bool stoFault();
private:
masterMacsController *pC_;
std::unique_ptr<masterMacsAxisImpl> pMasterMacsA_;
};
#endif

View File

@ -12,6 +12,10 @@
#include <string>
#include <unistd.h>
struct masterMacsControllerImpl {
double comTimeout;
};
/**
* @brief Copy src into dst and replace all NULL terminators up to the carriage
* return with spaces. This allows to print *dst with asynPrint.
@ -59,8 +63,10 @@ masterMacsController::masterMacsController(const char *portName,
// Initialization of local variables
asynStatus status = asynSuccess;
// Initialization of all member variables
comTimeout_ = comTimeout;
pMasterMacsC_ =
std::make_unique<masterMacsControllerImpl>((masterMacsControllerImpl){
.comTimeout = comTimeout,
});
// =========================================================================
@ -130,7 +136,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
// Definition of local variables.
asynStatus status = asynSuccess;
asynStatus pl_status = asynSuccess;
char fullCommand[MAXBUF_] = {0};
char fullResponse[MAXBUF_] = {0};
char drvMessageText[MAXBUF_] = {0};
@ -158,7 +163,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
// Check if a custom timeout has been given
if (comTimeout < 0.0) {
comTimeout = comTimeout_;
comTimeout = pMasterMacsC_->comTimeout;
}
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
@ -192,7 +197,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
msgPrintControlKey comKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (status != asynSuccess) {
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUserSelf)) {
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUserSelf)) {
char printableCommand[MAXBUF_] = {0};
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
@ -202,7 +207,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
stringifyAsynStatus(status), printableCommand);
}
} else {
msgPrintControl_.resetCount(comKey, pasynUserSelf);
getMsgPrintControl().resetCount(comKey, pasynUserSelf);
}
// Create custom error messages for different failure modes
@ -249,41 +254,31 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
// Log the overall status (communication successfull or not)
if (status == asynSuccess) {
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
setAxisParamChecked(axis, motorStatusCommsError, false);
} else {
// 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
pl_status =
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo, __PRETTY_FUNCTION__, __LINE__);
}
/*
Since the communication failed, there is the possibility that the
controller is not connected at all to the network. In that case, we
cannot be sure that the information read out in the init method of the
axis is still up-to-date the next time we get a connection. Therefore,
an info flag is set which the axis object can use at the start of its
poll method to try to initialize itself.
*/
axis->setNeedInit(true);
/*
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
*/
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
if (motorStatusProblem == 0) {
pl_status = axis->setStringParam(motorMessageText_, drvMessageText);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorStatusProblem",
axisNo, __PRETTY_FUNCTION__,
__LINE__);
}
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
axisNo, __PRETTY_FUNCTION__,
__LINE__);
}
setAxisParamChecked(axis, motorMessageText, drvMessageText);
setAxisParamChecked(axis, motorStatusProblem, true);
setAxisParamChecked(axis, motorStatusCommsError, false);
}
}
@ -305,12 +300,22 @@ asynStatus masterMacsController::parseResponse(
bool responseValid = false;
int responseStart = 0;
asynStatus status = asynSuccess;
int prevConnected = 0;
char printableCommand[MAXBUF_] = {0};
char printableResponse[MAXBUF_] = {0};
msgPrintControlKey parseKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
if (axis == nullptr) {
return asynError;
}
// Was the motor previously connected?
getAxisParamChecked(axis, motorConnected, &prevConnected);
// We don't use strlen here since the C string terminator 0x00
// occurs in the middle of the char array.
for (uint32_t i = 0; i < MAXBUF_; i++) {
@ -319,20 +324,57 @@ asynStatus masterMacsController::parseResponse(
} else if (fullResponse[i] == '=') {
*valueStart = i + 1;
} else if (fullResponse[i] == '\x06') {
// ACK
*valueStop = i;
responseValid = true;
break;
} else if (fullResponse[i] == '\x15') {
// NAK
snprintf(drvMessageText, MAXBUF_, "Communication failed.");
if (msgPrintControl_.shouldBePrinted(parseKey, true,
pasynUserSelf)) {
// Motor wasn't connected before -> Update the paramLib entry and PV
// to show it is now connected.
if (prevConnected == 0) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\nCommunication failed.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
msgPrintControl_.getSuffix());
"%d:\nAxis connection status has changed to "
"connected.\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(axis, motorConnected, true);
status = callParamCallbacks();
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\nCould not update parameter library\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
return status;
}
}
break;
} else if (fullResponse[i] == '\x15') {
/*
NAK
This indicates that the axis is not connected. This is not an error!
*/
snprintf(drvMessageText, MAXBUF_, "Axis not connected.");
// Motor was connected before -> Update the paramLib entry and PV
// to show it is now disconnected.
if (prevConnected == 1) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\nAxis connection status has changed to "
"disconnected.\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(axis, motorConnected, false);
status = callParamCallbacks();
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
"%d:\nCould not update parameter library\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
return status;
}
}
break;
} else if (fullResponse[i] == '\x18') {
@ -341,15 +383,15 @@ asynStatus masterMacsController::parseResponse(
"Tried to write with a read-only command. This is a "
"bug, please call the support.");
if (msgPrintControl_.shouldBePrinted(parseKey, true,
pasynUserSelf)) {
if (getMsgPrintControl().shouldBePrinted(parseKey, true,
pasynUserSelf)) {
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
asynPrint(
this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
"write with the read-only command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
printableCommand, msgPrintControl_.getSuffix());
printableCommand, getMsgPrintControl().getSuffix());
}
responseValid = false;
break;
@ -357,7 +399,7 @@ asynStatus masterMacsController::parseResponse(
}
if (responseValid) {
msgPrintControl_.resetCount(parseKey, pasynUserSelf);
getMsgPrintControl().resetCount(parseKey, pasynUserSelf);
// Check if the response matches the expectations. Each response
// contains the string "axisNo R tcpCmd" (including the spaces)
@ -381,15 +423,15 @@ asynStatus masterMacsController::parseResponse(
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
if (msgPrintControl_.shouldBePrinted(parseKey, true,
pasynUserSelf)) {
if (getMsgPrintControl().shouldBePrinted(parseKey, true,
pasynUserSelf)) {
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"Controller \"%s\", axis %d => %s, line "
"%d:\nMismatched "
"response %s to command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
printableResponse, printableCommand,
msgPrintControl_.getSuffix());
getMsgPrintControl().getSuffix());
}
snprintf(drvMessageText, MAXBUF_,
@ -398,15 +440,16 @@ asynStatus masterMacsController::parseResponse(
printableResponse, printableCommand);
return asynError;
} else {
msgPrintControl_.resetCount(responseMatchKey, pasynUserSelf);
getMsgPrintControl().resetCount(responseMatchKey, pasynUserSelf);
}
}
return asynSuccess;
}
asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
asynStatus masterMacsController::readInt32(asynUser *pasynUser,
epicsInt32 *value) {
// masterMacs can be disabled
if (pasynUser->reason == motorCanDisable_) {
if (pasynUser->reason == motorCanDisable()) {
*value = 1;
return asynSuccess;
} else {
@ -414,6 +457,8 @@ asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
}
}
double masterMacsController::comTimeout() { return pMasterMacsC_->comTimeout; }
/***************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */

View File

@ -8,9 +8,16 @@
#ifndef masterMacsController_H
#define masterMacsController_H
#include "masterMacsAxis.h"
#include "sinqAxis.h"
#include "sinqController.h"
#include <memory>
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
// https://en.cppreference.com/w/cpp/language/class.
class masterMacsAxis;
struct masterMacsControllerImpl;
class masterMacsController : public sinqController {
@ -31,6 +38,15 @@ class masterMacsController : public sinqController {
int numAxes, double movingPollPeriod,
double idlePollPeriod, double comTimeout);
/**
* @brief Overloaded version of the sinqController version
*
* @param pasynUser
* @param value
* @return asynStatus
*/
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
/**
* @brief Get the axis object
*
@ -123,13 +139,10 @@ class masterMacsController : public sinqController {
*
* @return double Timeout in seconds
*/
double comTimeout() { return comTimeout_; }
double comTimeout();
private:
/*
Stores the constructor input comTimeout
*/
double comTimeout_;
std::unique_ptr<masterMacsControllerImpl> pMasterMacsC_;
};
#endif /* masterMacsController_H */