Compare commits

...

9 Commits

Author SHA1 Message Date
eca513f3a0 Updated sinqMotor version to 1.1 2025-06-10 14:11:48 +02:00
26175290bf Added flag to disable reading the limits from the hardware 2025-06-10 13:53:39 +02:00
e316fcf67b Changed priority of IOC shell message 2025-06-06 11:20:50 +02:00
6cf00adb60 Ready for release 1.0 2025-05-23 12:27:31 +02:00
9710d442b8 Removed exit(-1) from init
When the initialization fails, the motor will now try again during each
poll.
2025-05-23 11:56:45 +02:00
8dd1dc4af2 Fixed poller bug in sinqMotor 2025-05-23 11:20:20 +02:00
a758db1211 Change to latest sinqMotor version 2025-05-23 10:11:27 +02:00
a11d10cb6c Updated sinqMotor to 0.15.2 2025-05-16 16:03:30 +02:00
ba353c4e5d Fixed remote git link in repo. 2025-05-16 15:58:17 +02:00
7 changed files with 282 additions and 110 deletions

View File

@ -4,7 +4,7 @@
## Overview
This is a driver for the Turbo PMAC 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 Turbo PMAC motion controller with the SINQ communication protocol. It is based on the sinqMotor shared library (https://gitea.psi.ch/lin-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.
## User guide
@ -14,8 +14,6 @@ The folder "utils" contains utility scripts for working with pmac motor controll
- writeRead.py: Allows sending commands to and receiving commands from a pmac controller over an ethernet connection.
- analyzeTcpDump.py: Parse the TCP communication between an IOC and a MCU and format it into a dictionary. "demo.py" shows how this data can be easily visualized for analysis.
### IOC startup script
turboPmac exports the following IOC shell functions:

View File

@ -31,3 +31,14 @@ record(longout, "$(INSTR)FlushHardware") {
field(PINI, "NO")
field(VAL, "1")
}
# If this PV is set to 1 (default), the position limits are read out from the
# controller. Otherwise, the limits given in the substitution file (DHLM and
# DLLM) are used.
# This record is coupled to the parameter library via limFromHardware -> LIM_FROM_HARDWARE.
record(longout, "$(INSTR)$(M):LimFromHardware") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIM_FROM_HARDWARE")
field(PINI, "YES")
field(VAL, "$(LIMFROMHARDWARE=1)")
}

View File

@ -13,6 +13,14 @@
#include <unistd.h>
#include <vector>
struct turboPmacAxisImpl {
bool waitForHandshake;
time_t timeAtHandshake;
// The axis status is used when enabling / disabling the motor
int axisStatus;
bool needInit;
};
/*
Contains all instances of turboPmacAxis which have been created and is used in
the initialization hook function.
@ -54,10 +62,11 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
axes.push_back(this);
}
// Initialize all member variables
waitForHandshake_ = false;
timeAtHandshake_ = 0;
axisStatus_ = 0;
pTurboPmacA_ = std::make_unique<turboPmacAxisImpl>(
(turboPmacAxisImpl){.waitForHandshake = false,
.timeAtHandshake = 0,
.axisStatus = 0,
.needInit = false});
// Provide initial values for some parameter library entries
status = pC_->setIntegerParam(axisNo_, pC_->rereadEncoderPosition(), 0);
@ -93,8 +102,8 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
}
// Default values for the watchdog timeout mechanism
offsetMovTimeout_ = 30; // seconds
scaleMovTimeout_ = 2.0;
setOffsetMovTimeout(30.0); // seconds
setScaleMovTimeout(2.0);
}
turboPmacAxis::~turboPmacAxis(void) {
@ -158,15 +167,15 @@ asynStatus turboPmacAxis::init() {
"with controller during IOC initialization. Check if you used "
"\"pmacAsynIPPortConfigure\" instead of the standard "
"\"drvAsynIPPortConfigure\" function in the .cmd file in order to "
"create the port driver.\nTerminating IOC.\n",
"create the port driver.\n",
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__);
exit(-1);
pTurboPmacA_->needInit = true;
}
nvals = sscanf(response, "%d %lf %lf %lf %lf %d", &axStatus, &motorPos,
&motorVmax, &motorVelocity, &motorAccel, &acoDelay);
// The acoDelay is given in milliseconds -> Convert to seconds, rounded up
offsetMovTimeout_ = std::ceil(acoDelay / 1000.0);
setOffsetMovTimeout(std::ceil(acoDelay / 1000.0));
// The PMAC electronic specifies the acceleration in m/s^2. Since we
// otherwise work with the base length mm, the acceleration is converted
@ -215,7 +224,12 @@ asynStatus turboPmacAxis::init() {
return status;
}
return this->readEncoderType();
status = this->readEncoderType();
if (status == asynSuccess) {
pTurboPmacA_->needInit = false;
}
return status;
}
// Perform the actual poll
@ -251,13 +265,20 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
// =========================================================================
if (pTurboPmacA_->needInit) {
rw_status = init();
if (rw_status != asynSuccess) {
return rw_status;
}
}
// Are we currently waiting for a handshake?
if (waitForHandshake_) {
if (pTurboPmacA_->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 > pTurboPmacA_->timeAtHandshake + 5);
if (pC_->getMsgPrintControl().shouldBePrinted(
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
@ -267,7 +288,7 @@ asynStatus turboPmacAxis::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);
pTurboPmacA_->timeAtHandshake, currentTime);
}
if (timedOut) {
@ -279,6 +300,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
pTurboPmacA_->waitForHandshake = false;
}
snprintf(command, sizeof(command), "P%2.2d23 P%2.2d01", axisNo_,
@ -298,11 +320,11 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
// If an error occurred while waiting for the handshake, abort the
// waiting procedure and continue with the poll in order to handle
// the error.
waitForHandshake_ = false;
pTurboPmacA_->waitForHandshake = false;
} else if (handshakePerformed == 1) {
// Handshake has been performed successfully -> Continue with the
// poll
waitForHandshake_ = false;
pTurboPmacA_->waitForHandshake = false;
} else {
// Still waiting for the handshake - try again in the next busy
// poll. This is already part of the movement procedure.
@ -386,7 +408,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
lowLimit = lowLimit + limitsOffset;
// Store the axis status
axisStatus_ = axStatus;
pTurboPmacA_->axisStatus = axStatus;
// Update the enablement PV
pl_status = setIntegerParam(pC_->motorEnableRBV(),
@ -459,13 +481,53 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
*moving = true;
break;
case 5:
// Motor is moving normally
*moving = true;
break;
case 6:
// Jog start
*moving = true;
break;
case 7:
// Jog forward
*moving = true;
break;
case 8:
// Jog backward
*moving = true;
break;
case 9:
// Jog break
*moving = true;
break;
case 10:
// Jog step forward
*moving = true;
break;
case 11:
// Jog step backward
*moving = true;
break;
case 12:
// Jog stop
*moving = true;
break;
case 13:
// Backlash
*moving = true;
break;
case 14:
// Move order out of range - this is also handled as an error
*moving = false;
break;
case 15:
// Move is interrupted, but the motor is not ready to receive another
// move command. Therefore it is treated as still moving.
*moving = true;
break;
case 16:
// Move is resumed
*moving = true;
asynPrint(
pC_->pasynUser(), ASYN_TRACE_FLOW,
"Controller \"%s\", axis %d => %s, line %d\nAxis is moving\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
break;
default:
*moving = false;
@ -547,19 +609,30 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
__LINE__);
}
pl_status = pC_->setDoubleParam(axisNo_, pC_->motorHighLimitFromDriver(),
highLimit);
int limFromHardware = 0;
pl_status =
pC_->getIntegerParam(axisNo_, pC_->limFromHardware(), &limFromHardware);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorHighLimitFromDriver_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
return pC_->paramLibAccessFailed(pl_status, "limFromHardware", 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__);
if (limFromHardware != 0) {
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__);
}
}
pl_status = setMotorPosition(currentPosition);
@ -962,8 +1035,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
// In the next poll, we will check if the handshake has been performed in a
// reasonable time
waitForHandshake_ = true;
timeAtHandshake_ = time(NULL);
pTurboPmacA_->waitForHandshake = true;
pTurboPmacA_->timeAtHandshake = time(NULL);
// Waiting for a handshake is already part of the movement procedure =>
// Start the watchdog
@ -1005,6 +1078,10 @@ asynStatus turboPmacAxis::stop(double acceleration) {
}
}
// Reset the driver to idle state and move out of the handshake wait loop,
// if we're currently inside it.
pTurboPmacA_->waitForHandshake = false;
return rw_status;
}
@ -1039,6 +1116,10 @@ asynStatus turboPmacAxis::doReset() {
}
}
// Reset the driver to idle state and move out of the handshake wait loop,
// if we're currently inside it.
pTurboPmacA_->waitForHandshake = false;
return rw_status;
}
@ -1268,8 +1349,11 @@ asynStatus turboPmacAxis::enable(bool on) {
// command and inform the user. We check the last known status of the axis
// instead of "moving", since status -6 is also moving, but the motor can
// actually be disabled in this state!
if (axisStatus_ == 1 || axisStatus_ == 2 || axisStatus_ == 3 ||
axisStatus_ == 4 || axisStatus_ == 5) {
int axStatus = pTurboPmacA_->axisStatus;
if (axStatus == 1 || axStatus == 2 || axStatus == 3 || axStatus == 4 ||
axStatus == 5 || axStatus == 6 || axStatus == 7 || axStatus == 8 ||
axStatus == 9 || axStatus == 10 || axStatus == 11 || axStatus == 12 ||
axStatus == 13 || axStatus == 15 || axStatus == 16) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
"idle and can therefore not be enabled / disabled.\n",
@ -1289,7 +1373,7 @@ asynStatus turboPmacAxis::enable(bool on) {
// Axis is already enabled / disabled and a new enable / disable command
// was sent => Do nothing
if ((axisStatus_ != -3) == on) {
if ((axStatus != -3) == on) {
asynPrint(
pC_->pasynUser(), ASYN_TRACE_WARNING,
"Controller \"%s\", axis %d => %s, line %d\nAxis is already %s.\n",
@ -1330,13 +1414,13 @@ asynStatus turboPmacAxis::enable(bool on) {
if (rw_status != asynSuccess) {
return rw_status;
}
nvals = sscanf(response, "%d", &axisStatus_);
nvals = sscanf(response, "%d", &pTurboPmacA_->axisStatus);
if (nvals != 1) {
return pC_->couldNotParseResponse(command, response, axisNo_,
__PRETTY_FUNCTION__, __LINE__);
}
if ((axisStatus_ != -3) == on) {
if ((pTurboPmacA_->axisStatus != -3) == on) {
bool moving = false;
// Perform a poll to update the parameter library
poll(&moving);
@ -1346,7 +1430,7 @@ asynStatus turboPmacAxis::enable(bool on) {
// Failed to change axis status within timeout_enable_disable => Send a
// corresponding message
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nFailed to %s axis "
"within %d seconds\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
@ -1364,6 +1448,17 @@ asynStatus turboPmacAxis::enable(bool on) {
return asynError;
}
bool turboPmacAxis::needInit() { return pTurboPmacA_->needInit; }
/**
* @brief Instruct the axis to run its init() function during the next poll
*
* @param needInit
*/
void turboPmacAxis::setNeedInit(bool needInit) {
pTurboPmacA_->needInit = needInit;
}
/*************************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */

View File

@ -1,6 +1,9 @@
#ifndef turboPmacAXIS_H
#define turboPmacAXIS_H
#include "sinqAxis.h"
#include <memory>
struct turboPmacAxisImpl;
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
@ -123,14 +126,24 @@ class turboPmacAxis : public sinqAxis {
*/
asynStatus handleError(int error, char *userMessage, int sizeUserMessage);
protected:
/**
* @brief Check if the axis needs to run its initialization function
*
* @return true
* @return false
*/
bool needInit();
/**
* @brief Instruct the axis to run its init() function during the next poll
*
* @param needInit
*/
void setNeedInit(bool needInit);
private:
turboPmacController *pC_;
bool waitForHandshake_;
time_t timeAtHandshake_;
// The axis status is used when enabling / disabling the motor
int axisStatus_;
std::unique_ptr<turboPmacAxisImpl> pTurboPmacA_;
};
#endif

View File

@ -31,6 +31,24 @@ void adjustResponseForPrint(char *dst, const char *src, size_t buf_length) {
}
}
struct turboPmacControllerImpl {
// Timeout for the communication process in seconds
double comTimeout;
char lastResponse[sinqController::MAXBUF_];
// User for writing int32 values to the port driver.
asynUser *pasynInt32SyncIOipPort;
// Indices of additional PVs
int rereadEncoderPosition;
int readConfig;
int flushHardware;
int limFromHardware;
};
#define NUM_turboPmac_DRIVER_PARAMS 3
turboPmacController::turboPmacController(const char *portName,
const char *ipPortConfigName,
int numAxes, double movingPollPeriod,
@ -47,21 +65,25 @@ turboPmacController::turboPmacController(const char *portName,
{
// The paramLib indices are populated with the calls to createParam
pTurboPmacC_ =
std::make_unique<turboPmacControllerImpl>((turboPmacControllerImpl){
.comTimeout = comTimeout,
.lastResponse = {0},
});
// Initialization of local variables
asynStatus status = asynSuccess;
// Initialization of all member variables
comTimeout_ = comTimeout;
// Maximum allowed number of subsequent timeouts before the user is
// informed.
maxSubsequentTimeouts_ = 10;
setMaxSubsequentTimeouts(10);
// =========================================================================
// Create additional parameter library entries
status = createParam("REREAD_ENCODER_POSITION", asynParamInt32,
&rereadEncoderPosition_);
&pTurboPmacC_->rereadEncoderPosition);
if (status != asynSuccess) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
@ -71,7 +93,8 @@ turboPmacController::turboPmacController(const char *portName,
exit(-1);
}
status = createParam("READ_CONFIG", asynParamInt32, &readConfig_);
status =
createParam("READ_CONFIG", asynParamInt32, &pTurboPmacC_->readConfig);
if (status != asynSuccess) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
@ -81,7 +104,19 @@ turboPmacController::turboPmacController(const char *portName,
exit(-1);
}
status = createParam("FLUSH_HARDWARE", asynParamInt32, &flushHardware_);
status = createParam("FLUSH_HARDWARE", asynParamInt32,
&pTurboPmacC_->flushHardware);
if (status != asynSuccess) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
"parameter failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
exit(-1);
}
status = createParam("LIM_FROM_HARDWARE", asynParamInt32,
&pTurboPmacC_->limFromHardware);
if (status != asynSuccess) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
@ -100,7 +135,7 @@ turboPmacController::turboPmacController(const char *portName,
const char *message_from_device =
"\006"; // Hex-code for ACK (acknowledge) -> Each message from the MCU
// is terminated by this value
status = pasynOctetSyncIO->setInputEos(pasynOctetSyncIOipPort_,
status = pasynOctetSyncIO->setInputEos(pasynOctetSyncIOipPort(),
message_from_device,
strlen(message_from_device));
if (status != asynSuccess) {
@ -109,7 +144,7 @@ turboPmacController::turboPmacController(const char *portName,
"(setting input EOS failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort_);
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
exit(-1);
}
@ -121,7 +156,7 @@ turboPmacController::turboPmacController(const char *portName,
"with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort_);
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
exit(-1);
}
@ -131,13 +166,15 @@ turboPmacController::turboPmacController(const char *portName,
We try to connect to the port via the port name provided by the constructor.
If this fails, the function is terminated via exit.
*/
pasynInt32SyncIO->connect(ipPortConfigName, 0, &pasynInt32SyncIOipPort_,
NULL);
if (status != asynSuccess || pasynInt32SyncIOipPort_ == nullptr) {
pasynInt32SyncIO->connect(ipPortConfigName, 0,
&pTurboPmacC_->pasynInt32SyncIOipPort, NULL);
if (status != asynSuccess ||
pTurboPmacC_->pasynInt32SyncIOipPort == nullptr) {
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
"connect to MCU controller).\n"
"Terminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__);
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
exit(-1);
}
}
@ -215,20 +252,20 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
*/
status = pasynOctetSyncIO->writeRead(
pasynOctetSyncIOipPort(), command, commandLength, response, MAXBUF_,
comTimeout_, &nbytesOut, &nbytesIn, &eomReason);
pTurboPmacC_->comTimeout, &nbytesOut, &nbytesIn, &eomReason);
msgPrintControlKey comKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (status == asynTimeout) {
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUser())) {
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUser())) {
asynPrint(
this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nTimeout while "
"writing to the controller. Retrying ...%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
msgPrintControl_.getSuffix());
getMsgPrintControl().getSuffix());
}
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText,
@ -239,13 +276,14 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
checkMaxSubsequentTimeouts(timeoutCounter, axis);
timeoutCounter += 1;
if (maxSubsequentTimeoutsExceeded_) {
if (maxSubsequentTimeoutsExceeded()) {
break;
}
status = pasynOctetSyncIO->writeRead(
pasynOctetSyncIOipPort(), command, commandLength, response,
MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason);
MAXBUF_, pTurboPmacC_->comTimeout, &nbytesOut, &nbytesIn,
&eomReason);
if (status != asynTimeout) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
@ -255,16 +293,28 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
}
}
} else if (status != asynSuccess) {
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUser())) {
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUser())) {
asynPrint(
this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nError %s while "
"writing to the controller.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
stringifyAsynStatus(status), getMsgPrintControl().getSuffix());
}
} else {
msgPrintControl_.resetCount(comKey, pasynUser());
getMsgPrintControl().resetCount(comKey, pasynUser());
}
if (status != asynSuccess) {
/*
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);
}
if (timeoutStatus == asynError) {
@ -301,16 +351,17 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
"string detected\"). Please call the support.",
reasonStringified);
if (msgPrintControl_.shouldBePrinted(terminateKey, true, pasynUser())) {
if (getMsgPrintControl().shouldBePrinted(terminateKey, true,
pasynUser())) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nMessage "
"terminated due to reason %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
reasonStringified, msgPrintControl_.getSuffix());
reasonStringified, getMsgPrintControl().getSuffix());
}
} else {
msgPrintControl_.resetCount(terminateKey, pasynUser());
getMsgPrintControl().resetCount(terminateKey, pasynUser());
}
/*
@ -327,15 +378,15 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
if (numExpectedResponses != numReceivedResponses) {
adjustResponseForPrint(modResponse, response, MAXBUF_);
if (msgPrintControl_.shouldBePrinted(numResponsesKey, true,
pasynUser())) {
if (getMsgPrintControl().shouldBePrinted(numResponsesKey, true,
pasynUser())) {
asynPrint(
this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nUnexpected "
"response '%s' (carriage returns are replaced with spaces) "
"for command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse,
command, msgPrintControl_.getSuffix());
command, getMsgPrintControl().getSuffix());
}
snprintf(drvMessageText, sizeof(drvMessageText),
@ -345,7 +396,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
modResponse, command);
status = asynError;
} else {
msgPrintControl_.resetCount(numResponsesKey, pasynUser());
getMsgPrintControl().resetCount(numResponsesKey, pasynUser());
}
// Create custom error messages for different failure modes, if no error
@ -384,15 +435,15 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
paramLibStatus =
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
if (paramLibStatus != asynSuccess) {
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem_",
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem",
axisNo, __PRETTY_FUNCTION__, __LINE__);
}
if (motorStatusProblem == 0) {
paramLibStatus =
axis->setStringParam(motorMessageText_, drvMessageText);
axis->setStringParam(motorMessageText(), drvMessageText);
if (paramLibStatus != asynSuccess) {
return paramLibAccessFailed(paramLibStatus, "motorMessageText_",
return paramLibAccessFailed(paramLibStatus, "motorMessageText",
axisNo, __PRETTY_FUNCTION__,
__LINE__);
}
@ -407,7 +458,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
if (paramLibStatus != asynSuccess) {
return paramLibAccessFailed(paramLibStatus,
"motorStatusCommsError_", axisNo,
"motorStatusCommsError", axisNo,
__PRETTY_FUNCTION__, __LINE__);
}
}
@ -421,13 +472,13 @@ asynStatus turboPmacController::doFlushHardware() {
constant defined in pmacAsynIPPort.c. This reason is then used within
the write method of pasynInt32SyncIO to select the flush function.
*/
int temp = pasynInt32SyncIOipPort_->reason;
pasynInt32SyncIOipPort_->reason = FLUSH_HARDWARE;
int temp = pTurboPmacC_->pasynInt32SyncIOipPort->reason;
pTurboPmacC_->pasynInt32SyncIOipPort->reason = FLUSH_HARDWARE;
asynStatus status = (asynStatus)pasynInt32SyncIO->write(
pasynInt32SyncIOipPort_, 1, comTimeout_);
pTurboPmacC_->pasynInt32SyncIOipPort, 1, pTurboPmacC_->comTimeout);
// Reset the status afterwards
pasynInt32SyncIOipPort_->reason = temp;
pTurboPmacC_->pasynInt32SyncIOipPort->reason = temp;
return status;
}
@ -440,11 +491,11 @@ asynStatus turboPmacController::writeInt32(asynUser *pasynUser,
turboPmacAxis *axis = getTurboPmacAxis(pasynUser);
// Handle custom PVs
if (function == rereadEncoderPosition_) {
if (function == rereadEncoderPosition()) {
return axis->rereadEncoder();
} else if (function == readConfig_) {
} else if (function == readConfig()) {
return axis->init();
} else if (function == flushHardware_) {
} else if (function == flushHardware()) {
return doFlushHardware();
} else {
return sinqController::writeInt32(pasynUser, value);
@ -462,6 +513,19 @@ asynStatus turboPmacController::couldNotParseResponse(const char *command,
command, modifiedResponse, axisNo, functionName, lineNumber);
}
int turboPmacController::rereadEncoderPosition() {
return pTurboPmacC_->rereadEncoderPosition;
}
int turboPmacController::readConfig() { return pTurboPmacC_->readConfig; }
int turboPmacController::flushHardware() { return pTurboPmacC_->flushHardware; }
int turboPmacController::limFromHardware() {
return pTurboPmacC_->limFromHardware;
}
asynUser *turboPmacController::pasynInt32SyncIOipPort() {
return pTurboPmacC_->pasynInt32SyncIOipPort;
}
/*************************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */

View File

@ -11,6 +11,9 @@
#include "sinqAxis.h"
#include "sinqController.h"
#include "turboPmacAxis.h"
#include <memory>
struct turboPmacControllerImpl;
class turboPmacController : public sinqController {
public:
@ -116,29 +119,17 @@ class turboPmacController : public sinqController {
asynStatus doFlushHardware();
// Accessors for additional PVs
int rereadEncoderPosition() { return rereadEncoderPosition_; }
int readConfig() { return readConfig_; }
int flushHardware() { return flushHardware_; }
int rereadEncoderPosition();
int readConfig();
int flushHardware();
int limFromHardware();
asynUser *pasynInt32SyncIOipPort() { return pasynInt32SyncIOipPort_; }
asynUser *pasynInt32SyncIOipPort();
private:
std::unique_ptr<turboPmacControllerImpl> pTurboPmacC_;
protected:
// Timeout for the communication process in seconds
double comTimeout_;
char lastResponse[MAXBUF_];
// User for writing int32 values to the port driver.
asynUser *pasynInt32SyncIOipPort_;
// Indices of additional PVs
#define FIRST_turboPmac_PARAM rereadEncoderPosition_
int rereadEncoderPosition_;
int readConfig_;
int flushHardware_;
#define LAST_turboPmac_PARAM flushHardware_
};
#define NUM_turboPmac_DRIVER_PARAMS \
(&LAST_turboPmac_PARAM - &FIRST_turboPmac_PARAM + 1)
#endif /* turboPmacController_H */