Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
6cf00adb60 | |||
9710d442b8 | |||
8dd1dc4af2 | |||
a758db1211 | |||
a11d10cb6c | |||
ba353c4e5d | |||
55b523ddaa | |||
75292a6a9c | |||
53bbe2aae8 | |||
1597dc34e0 | |||
dde7066f40 | |||
b4d6447b32 | |||
2f83060ec1 | |||
a3e3a79788 | |||
2c5fdc7d0a | |||
7bf31ac256 | |||
63a5fcd518 | |||
47e72d65a9 |
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## Overview
|
## 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
|
## 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.
|
- 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.
|
- 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
|
### IOC startup script
|
||||||
|
|
||||||
turboPmac exports the following IOC shell functions:
|
turboPmac exports the following IOC shell functions:
|
||||||
@ -54,11 +52,11 @@ setMaxSubsequentTimeouts("$(DRIVER_PORT)", 20);
|
|||||||
setThresholdComTimeout("$(DRIVER_PORT)", 300, 10);
|
setThresholdComTimeout("$(DRIVER_PORT)", 300, 10);
|
||||||
|
|
||||||
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||||
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/sinqMotor.db")
|
||||||
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
||||||
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
||||||
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)")
|
||||||
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)")
|
dbLoadRecords("$(turboPmac_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Additional records
|
### Additional records
|
||||||
|
Submodule sinqMotor updated: 5689402375...c2eca33ce8
@ -13,6 +13,14 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#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
|
Contains all instances of turboPmacAxis which have been created and is used in
|
||||||
the initialization hook function.
|
the initialization hook function.
|
||||||
@ -54,10 +62,11 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
|
|||||||
axes.push_back(this);
|
axes.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all member variables
|
pTurboPmacA_ = std::make_unique<turboPmacAxisImpl>(
|
||||||
waitForHandshake_ = false;
|
(turboPmacAxisImpl){.waitForHandshake = false,
|
||||||
timeAtHandshake_ = 0;
|
.timeAtHandshake = 0,
|
||||||
axisStatus_ = 0;
|
.axisStatus = 0,
|
||||||
|
.needInit = false});
|
||||||
|
|
||||||
// Provide initial values for some parameter library entries
|
// Provide initial values for some parameter library entries
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->rereadEncoderPosition(), 0);
|
status = pC_->setIntegerParam(axisNo_, pC_->rereadEncoderPosition(), 0);
|
||||||
@ -71,6 +80,20 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
// turboPmac motors can always be disabled
|
// turboPmac motors can always be disabled
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -79,8 +102,8 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default values for the watchdog timeout mechanism
|
// Default values for the watchdog timeout mechanism
|
||||||
offsetMovTimeout_ = 30; // seconds
|
setOffsetMovTimeout(30.0); // seconds
|
||||||
scaleMovTimeout_ = 2.0;
|
setScaleMovTimeout(2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
turboPmacAxis::~turboPmacAxis(void) {
|
turboPmacAxis::~turboPmacAxis(void) {
|
||||||
@ -144,15 +167,15 @@ asynStatus turboPmacAxis::init() {
|
|||||||
"with controller during IOC initialization. Check if you used "
|
"with controller during IOC initialization. Check if you used "
|
||||||
"\"pmacAsynIPPortConfigure\" instead of the standard "
|
"\"pmacAsynIPPortConfigure\" instead of the standard "
|
||||||
"\"drvAsynIPPortConfigure\" function in the .cmd file in order to "
|
"\"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__);
|
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__);
|
||||||
exit(-1);
|
pTurboPmacA_->needInit = true;
|
||||||
}
|
}
|
||||||
nvals = sscanf(response, "%d %lf %lf %lf %lf %d", &axStatus, &motorPos,
|
nvals = sscanf(response, "%d %lf %lf %lf %lf %d", &axStatus, &motorPos,
|
||||||
&motorVmax, &motorVelocity, &motorAccel, &acoDelay);
|
&motorVmax, &motorVelocity, &motorAccel, &acoDelay);
|
||||||
|
|
||||||
// The acoDelay is given in milliseconds -> Convert to seconds, rounded up
|
// 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
|
// The PMAC electronic specifies the acceleration in m/s^2. Since we
|
||||||
// otherwise work with the base length mm, the acceleration is converted
|
// otherwise work with the base length mm, the acceleration is converted
|
||||||
@ -201,7 +224,12 @@ asynStatus turboPmacAxis::init() {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->readEncoderType();
|
status = this->readEncoderType();
|
||||||
|
if (status == asynSuccess) {
|
||||||
|
pTurboPmacA_->needInit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the actual poll
|
// Perform the actual poll
|
||||||
@ -237,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?
|
// Are we currently waiting for a handshake?
|
||||||
if (waitForHandshake_) {
|
if (pTurboPmacA_->waitForHandshake) {
|
||||||
|
|
||||||
// Check if the handshake takes too long and communicate an error in
|
// Check if the handshake takes too long and communicate an error in
|
||||||
// this case. A handshake should not take more than 5 seconds.
|
// this case. A handshake should not take more than 5 seconds.
|
||||||
time_t currentTime = time(NULL);
|
time_t currentTime = time(NULL);
|
||||||
bool timedOut = (currentTime > timeAtHandshake_ + 5);
|
bool timedOut = (currentTime > pTurboPmacA_->timeAtHandshake + 5);
|
||||||
|
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
|
||||||
@ -253,7 +288,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
"handshake at %ld s and didn't get a positive reply yet "
|
"handshake at %ld s and didn't get a positive reply yet "
|
||||||
"(current time is %ld s).\n",
|
"(current time is %ld s).\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
timeAtHandshake_, currentTime);
|
pTurboPmacA_->timeAtHandshake, currentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timedOut) {
|
if (timedOut) {
|
||||||
@ -265,6 +300,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(command, sizeof(command), "P%2.2d23 P%2.2d01", axisNo_,
|
snprintf(command, sizeof(command), "P%2.2d23 P%2.2d01", axisNo_,
|
||||||
@ -284,11 +320,11 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
// If an error occurred while waiting for the handshake, abort the
|
// If an error occurred while waiting for the handshake, abort the
|
||||||
// waiting procedure and continue with the poll in order to handle
|
// waiting procedure and continue with the poll in order to handle
|
||||||
// the error.
|
// the error.
|
||||||
waitForHandshake_ = false;
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
} else if (handshakePerformed == 1) {
|
} else if (handshakePerformed == 1) {
|
||||||
// Handshake has been performed successfully -> Continue with the
|
// Handshake has been performed successfully -> Continue with the
|
||||||
// poll
|
// poll
|
||||||
waitForHandshake_ = false;
|
pTurboPmacA_->waitForHandshake = false;
|
||||||
} else {
|
} else {
|
||||||
// Still waiting for the handshake - try again in the next busy
|
// Still waiting for the handshake - try again in the next busy
|
||||||
// poll. This is already part of the movement procedure.
|
// poll. This is already part of the movement procedure.
|
||||||
@ -372,7 +408,7 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
lowLimit = lowLimit + limitsOffset;
|
lowLimit = lowLimit + limitsOffset;
|
||||||
|
|
||||||
// Store the axis status
|
// Store the axis status
|
||||||
axisStatus_ = axStatus;
|
pTurboPmacA_->axisStatus = axStatus;
|
||||||
|
|
||||||
// Update the enablement PV
|
// Update the enablement PV
|
||||||
pl_status = setIntegerParam(pC_->motorEnableRBV(),
|
pl_status = setIntegerParam(pC_->motorEnableRBV(),
|
||||||
@ -397,13 +433,6 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
case -5:
|
case -5:
|
||||||
// Axis is deactivated
|
// Axis is deactivated
|
||||||
*moving = false;
|
*moving = false;
|
||||||
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), "Deactivated");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case -4:
|
case -4:
|
||||||
// Emergency stop
|
// Emergency stop
|
||||||
@ -426,19 +455,10 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
// Disabled
|
// Disabled
|
||||||
*moving = false;
|
*moving = false;
|
||||||
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), "Disabled");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
// Idle
|
// Idle
|
||||||
@ -461,13 +481,53 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
|||||||
*moving = true;
|
*moving = true;
|
||||||
break;
|
break;
|
||||||
case 5:
|
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;
|
*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;
|
break;
|
||||||
default:
|
default:
|
||||||
*moving = false;
|
*moving = false;
|
||||||
@ -599,8 +659,7 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
resetError = false;
|
resetError = false;
|
||||||
|
|
||||||
status = setStringParam(pC_->motorMessageText(),
|
status = setStringParam(pC_->motorMessageText(),
|
||||||
"Target position would exceed software "
|
"Target position would exceed software limits");
|
||||||
"limits. Please call the support.");
|
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -783,10 +842,10 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
|||||||
}
|
}
|
||||||
resetError = false;
|
resetError = false;
|
||||||
|
|
||||||
snprintf(userMessage, sizeUserMessage,
|
snprintf(
|
||||||
"Driver hardware error (P%2.2d01 = 13). "
|
userMessage, sizeUserMessage,
|
||||||
"Please call the support.",
|
"Driver hardware error (P%2.2d01 = 13). Please call the support.",
|
||||||
axisNo_);
|
axisNo_);
|
||||||
status = setStringParam(pC_->motorMessageText(), userMessage);
|
status = setStringParam(pC_->motorMessageText(), userMessage);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
@ -965,8 +1024,8 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
|||||||
|
|
||||||
// In the next poll, we will check if the handshake has been performed in a
|
// In the next poll, we will check if the handshake has been performed in a
|
||||||
// reasonable time
|
// reasonable time
|
||||||
waitForHandshake_ = true;
|
pTurboPmacA_->waitForHandshake = true;
|
||||||
timeAtHandshake_ = time(NULL);
|
pTurboPmacA_->timeAtHandshake = time(NULL);
|
||||||
|
|
||||||
// Waiting for a handshake is already part of the movement procedure =>
|
// Waiting for a handshake is already part of the movement procedure =>
|
||||||
// Start the watchdog
|
// Start the watchdog
|
||||||
@ -1008,6 +1067,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;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1042,6 +1105,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;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,22 +1151,7 @@ asynStatus turboPmacAxis::doHome(double min_velocity, double max_velocity,
|
|||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), "Homing");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
return callParamCallbacks();
|
return callParamCallbacks();
|
||||||
} else {
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText(),
|
|
||||||
"Can't home a motor with absolute encoder");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
@ -1271,20 +1323,26 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
// Status of parameter library operations
|
// Status of parameter library operations
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
bool moving = false;
|
|
||||||
rw_status = doPoll(&moving);
|
|
||||||
if (rw_status != asynSuccess) {
|
|
||||||
return rw_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
// If the axis is currently moving, it cannot be disabled. Ignore the
|
||||||
// command and inform the user. We check the last known status of the axis
|
// command and inform the user. We check the last known status of the axis
|
||||||
// instead of "moving", since status -6 is also moving, but the motor can
|
// instead of "moving", since status -6 is also moving, but the motor can
|
||||||
// actually be disabled in this state!
|
// actually be disabled in this state!
|
||||||
if (axisStatus_ == 1 || axisStatus_ == 2 || axisStatus_ == 3 ||
|
int axStatus = pTurboPmacA_->axisStatus;
|
||||||
axisStatus_ == 4 || axisStatus_ == 5) {
|
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,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
||||||
"idle and can therefore not be enabled / disabled.\n",
|
"idle and can therefore not be enabled / disabled.\n",
|
||||||
@ -1304,7 +1362,7 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
|
|
||||||
// Axis is already enabled / disabled and a new enable / disable command
|
// Axis is already enabled / disabled and a new enable / disable command
|
||||||
// was sent => Do nothing
|
// was sent => Do nothing
|
||||||
if ((axisStatus_ != -3) == on) {
|
if ((axStatus != -3) == on) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->pasynUser(), ASYN_TRACE_WARNING,
|
pC_->pasynUser(), ASYN_TRACE_WARNING,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is already %s.\n",
|
"Controller \"%s\", axis %d => %s, line %d\nAxis is already %s.\n",
|
||||||
@ -1327,16 +1385,7 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
"Controller \"%s\", axis %d => %s, line %d\n%s axis\n",
|
"Controller \"%s\", axis %d => %s, line %d\n%s axis\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
on ? "Enable" : "Disable");
|
on ? "Enable" : "Disable");
|
||||||
if (on == 0) {
|
|
||||||
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__);
|
|
||||||
}
|
|
||||||
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
rw_status = pC_->writeRead(axisNo_, command, response, 0);
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
return rw_status;
|
return rw_status;
|
||||||
@ -1354,13 +1403,13 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
nvals = sscanf(response, "%d", &axisStatus_);
|
nvals = sscanf(response, "%d", &pTurboPmacA_->axisStatus);
|
||||||
if (nvals != 1) {
|
if (nvals != 1) {
|
||||||
return pC_->couldNotParseResponse(command, response, axisNo_,
|
return pC_->couldNotParseResponse(command, response, axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((axisStatus_ != -3) == on) {
|
if ((pTurboPmacA_->axisStatus != -3) == on) {
|
||||||
bool moving = false;
|
bool moving = false;
|
||||||
// Perform a poll to update the parameter library
|
// Perform a poll to update the parameter library
|
||||||
poll(&moving);
|
poll(&moving);
|
||||||
@ -1379,7 +1428,7 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
// Output message to user
|
// Output message to user
|
||||||
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
||||||
on ? "enable" : "disable", timeout_enable_disable);
|
on ? "enable" : "disable", timeout_enable_disable);
|
||||||
pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
|
pl_status = setStringParam(pC_->motorMessageText(), command);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -1388,6 +1437,17 @@ asynStatus turboPmacAxis::enable(bool on) {
|
|||||||
return asynError;
|
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
|
/** The following functions are C-wrappers, and can be called directly from
|
||||||
* iocsh */
|
* iocsh */
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#ifndef turboPmacAXIS_H
|
#ifndef turboPmacAXIS_H
|
||||||
#define turboPmacAXIS_H
|
#define turboPmacAXIS_H
|
||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct turboPmacAxisImpl;
|
||||||
|
|
||||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||||
// between the controller and the axis .h-file. See
|
// between the controller and the axis .h-file. See
|
||||||
@ -31,7 +34,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* value is currently not used.
|
* value is currently not used.
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus stop(double acceleration);
|
virtual asynStatus stop(double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `doHome` function from sinqAxis. The
|
* @brief Implementation of the `doHome` function from sinqAxis. The
|
||||||
@ -43,8 +46,8 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* @param forwards
|
* @param forwards
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doHome(double minVelocity, double maxVelocity,
|
virtual asynStatus doHome(double minVelocity, double maxVelocity,
|
||||||
double acceleration, int forwards);
|
double acceleration, int forwards);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `doPoll` function from sinqAxis. The
|
* @brief Implementation of the `doPoll` function from sinqAxis. The
|
||||||
@ -53,7 +56,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* @param moving
|
* @param moving
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doPoll(bool *moving);
|
virtual asynStatus doPoll(bool *moving);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `doMove` function from sinqAxis. The
|
* @brief Implementation of the `doMove` function from sinqAxis. The
|
||||||
@ -66,8 +69,9 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* @param acceleration
|
* @param acceleration
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doMove(double position, int relative, double min_velocity,
|
virtual asynStatus doMove(double position, int relative,
|
||||||
double max_velocity, double acceleration);
|
double min_velocity, double max_velocity,
|
||||||
|
double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Readout of some values from the controller at IOC startup
|
* @brief Readout of some values from the controller at IOC startup
|
||||||
@ -79,7 +83,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus init();
|
virtual asynStatus init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the `doReset` function from sinqAxis.
|
* @brief Implementation of the `doReset` function from sinqAxis.
|
||||||
@ -87,7 +91,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* @param on
|
* @param on
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus doReset();
|
virtual asynStatus doReset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable / disable the axis.
|
* @brief Enable / disable the axis.
|
||||||
@ -95,7 +99,7 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
* @param on
|
* @param on
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus enable(bool on);
|
virtual asynStatus enable(bool on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the encoder type (incremental or absolute) for this axis from
|
* @brief Read the encoder type (incremental or absolute) for this axis from
|
||||||
@ -103,14 +107,14 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus readEncoderType();
|
virtual asynStatus readEncoderType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Trigger a rereading of the encoder position.
|
* @brief Trigger a rereading of the encoder position.
|
||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus rereadEncoder();
|
virtual asynStatus rereadEncoder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Interpret the error code and populate the user message accordingly
|
* @brief Interpret the error code and populate the user message accordingly
|
||||||
@ -122,14 +126,24 @@ class turboPmacAxis : public sinqAxis {
|
|||||||
*/
|
*/
|
||||||
asynStatus handleError(int error, char *userMessage, int sizeUserMessage);
|
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_;
|
turboPmacController *pC_;
|
||||||
|
std::unique_ptr<turboPmacAxisImpl> pTurboPmacA_;
|
||||||
bool waitForHandshake_;
|
|
||||||
time_t timeAtHandshake_;
|
|
||||||
|
|
||||||
// The axis status is used when enabling / disabling the motor
|
|
||||||
int axisStatus_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +31,23 @@ 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;
|
||||||
|
};
|
||||||
|
#define NUM_turboPmac_DRIVER_PARAMS 3
|
||||||
|
|
||||||
turboPmacController::turboPmacController(const char *portName,
|
turboPmacController::turboPmacController(const char *portName,
|
||||||
const char *ipPortConfigName,
|
const char *ipPortConfigName,
|
||||||
int numAxes, double movingPollPeriod,
|
int numAxes, double movingPollPeriod,
|
||||||
@ -47,21 +64,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
|
// Initialization of local variables
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Initialization of all member variables
|
|
||||||
comTimeout_ = comTimeout;
|
|
||||||
|
|
||||||
// Maximum allowed number of subsequent timeouts before the user is
|
// Maximum allowed number of subsequent timeouts before the user is
|
||||||
// informed.
|
// informed.
|
||||||
maxSubsequentTimeouts_ = 10;
|
setMaxSubsequentTimeouts(10);
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Create additional parameter library entries
|
// Create additional parameter library entries
|
||||||
|
|
||||||
status = createParam("REREAD_ENCODER_POSITION", asynParamInt32,
|
status = createParam("REREAD_ENCODER_POSITION", asynParamInt32,
|
||||||
&rereadEncoderPosition_);
|
&pTurboPmacC_->rereadEncoderPosition);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
@ -71,7 +92,8 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("READ_CONFIG", asynParamInt32, &readConfig_);
|
status =
|
||||||
|
createParam("READ_CONFIG", asynParamInt32, &pTurboPmacC_->readConfig);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
@ -81,7 +103,8 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("FLUSH_HARDWARE", asynParamInt32, &flushHardware_);
|
status = createParam("FLUSH_HARDWARE", asynParamInt32,
|
||||||
|
&pTurboPmacC_->flushHardware);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
@ -100,7 +123,7 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
const char *message_from_device =
|
const char *message_from_device =
|
||||||
"\006"; // Hex-code for ACK (acknowledge) -> Each message from the MCU
|
"\006"; // Hex-code for ACK (acknowledge) -> Each message from the MCU
|
||||||
// is terminated by this value
|
// is terminated by this value
|
||||||
status = pasynOctetSyncIO->setInputEos(pasynOctetSyncIOipPort_,
|
status = pasynOctetSyncIO->setInputEos(pasynOctetSyncIOipPort(),
|
||||||
message_from_device,
|
message_from_device,
|
||||||
strlen(message_from_device));
|
strlen(message_from_device));
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -109,7 +132,7 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
"(setting input EOS failed with %s).\nTerminating IOC",
|
"(setting input EOS failed with %s).\nTerminating IOC",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
stringifyAsynStatus(status));
|
stringifyAsynStatus(status));
|
||||||
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort_);
|
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +144,7 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
"with %s).\nTerminating IOC",
|
"with %s).\nTerminating IOC",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
stringifyAsynStatus(status));
|
stringifyAsynStatus(status));
|
||||||
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort_);
|
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,13 +154,15 @@ turboPmacController::turboPmacController(const char *portName,
|
|||||||
We try to connect to the port via the port name provided by the constructor.
|
We try to connect to the port via the port name provided by the constructor.
|
||||||
If this fails, the function is terminated via exit.
|
If this fails, the function is terminated via exit.
|
||||||
*/
|
*/
|
||||||
pasynInt32SyncIO->connect(ipPortConfigName, 0, &pasynInt32SyncIOipPort_,
|
pasynInt32SyncIO->connect(ipPortConfigName, 0,
|
||||||
NULL);
|
&pTurboPmacC_->pasynInt32SyncIOipPort, NULL);
|
||||||
if (status != asynSuccess || pasynInt32SyncIOipPort_ == nullptr) {
|
if (status != asynSuccess ||
|
||||||
|
pTurboPmacC_->pasynInt32SyncIOipPort == nullptr) {
|
||||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
||||||
"connect to MCU controller).\n"
|
"connect to MCU controller).\n"
|
||||||
"Terminating IOC",
|
"Terminating IOC",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__);
|
portName, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,20 +240,20 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
*/
|
*/
|
||||||
status = pasynOctetSyncIO->writeRead(
|
status = pasynOctetSyncIO->writeRead(
|
||||||
pasynOctetSyncIOipPort(), command, commandLength, response, MAXBUF_,
|
pasynOctetSyncIOipPort(), command, commandLength, response, MAXBUF_,
|
||||||
comTimeout_, &nbytesOut, &nbytesIn, &eomReason);
|
pTurboPmacC_->comTimeout, &nbytesOut, &nbytesIn, &eomReason);
|
||||||
|
|
||||||
msgPrintControlKey comKey =
|
msgPrintControlKey comKey =
|
||||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
if (status == asynTimeout) {
|
if (status == asynTimeout) {
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUser())) {
|
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUser())) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
this->pasynUser(), ASYN_TRACE_ERROR,
|
this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nTimeout while "
|
"Controller \"%s\", axis %d => %s, line %d\nTimeout while "
|
||||||
"writing to the controller. Retrying ...%s\n",
|
"writing to the controller. Retrying ...%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
msgPrintControl_.getSuffix());
|
getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText,
|
timeoutStatus = checkComTimeoutWatchdog(axisNo, drvMessageText,
|
||||||
@ -239,13 +264,14 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
checkMaxSubsequentTimeouts(timeoutCounter, axis);
|
checkMaxSubsequentTimeouts(timeoutCounter, axis);
|
||||||
timeoutCounter += 1;
|
timeoutCounter += 1;
|
||||||
|
|
||||||
if (maxSubsequentTimeoutsExceeded_) {
|
if (maxSubsequentTimeoutsExceeded()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pasynOctetSyncIO->writeRead(
|
status = pasynOctetSyncIO->writeRead(
|
||||||
pasynOctetSyncIOipPort(), command, commandLength, response,
|
pasynOctetSyncIOipPort(), command, commandLength, response,
|
||||||
MAXBUF_, comTimeout_, &nbytesOut, &nbytesIn, &eomReason);
|
MAXBUF_, pTurboPmacC_->comTimeout, &nbytesOut, &nbytesIn,
|
||||||
|
&eomReason);
|
||||||
if (status != asynTimeout) {
|
if (status != asynTimeout) {
|
||||||
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
@ -255,16 +281,28 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (status != asynSuccess) {
|
} else if (status != asynSuccess) {
|
||||||
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUser())) {
|
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUser())) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
this->pasynUser(), ASYN_TRACE_ERROR,
|
this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nError %s while "
|
"Controller \"%s\", axis %d => %s, line %d\nError %s while "
|
||||||
"writing to the controller.%s\n",
|
"writing to the controller.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
|
stringifyAsynStatus(status), getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
if (timeoutStatus == asynError) {
|
||||||
@ -301,16 +339,17 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
"string detected\"). Please call the support.",
|
"string detected\"). Please call the support.",
|
||||||
reasonStringified);
|
reasonStringified);
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(terminateKey, true, pasynUser())) {
|
if (getMsgPrintControl().shouldBePrinted(terminateKey, true,
|
||||||
|
pasynUser())) {
|
||||||
|
|
||||||
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nMessage "
|
"Controller \"%s\", axis %d => %s, line %d\nMessage "
|
||||||
"terminated due to reason %s.%s\n",
|
"terminated due to reason %s.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
reasonStringified, msgPrintControl_.getSuffix());
|
reasonStringified, getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msgPrintControl_.resetCount(terminateKey, pasynUser());
|
getMsgPrintControl().resetCount(terminateKey, pasynUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -327,15 +366,15 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
if (numExpectedResponses != numReceivedResponses) {
|
if (numExpectedResponses != numReceivedResponses) {
|
||||||
adjustResponseForPrint(modResponse, response, MAXBUF_);
|
adjustResponseForPrint(modResponse, response, MAXBUF_);
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(numResponsesKey, true,
|
if (getMsgPrintControl().shouldBePrinted(numResponsesKey, true,
|
||||||
pasynUser())) {
|
pasynUser())) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
this->pasynUser(), ASYN_TRACE_ERROR,
|
this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nUnexpected "
|
"Controller \"%s\", axis %d => %s, line %d\nUnexpected "
|
||||||
"response '%s' (carriage returns are replaced with spaces) "
|
"response '%s' (carriage returns are replaced with spaces) "
|
||||||
"for command %s.%s\n",
|
"for command %s.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, modResponse,
|
||||||
command, msgPrintControl_.getSuffix());
|
command, getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(drvMessageText, sizeof(drvMessageText),
|
snprintf(drvMessageText, sizeof(drvMessageText),
|
||||||
@ -345,7 +384,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
modResponse, command);
|
modResponse, command);
|
||||||
status = asynError;
|
status = asynError;
|
||||||
} else {
|
} else {
|
||||||
msgPrintControl_.resetCount(numResponsesKey, pasynUser());
|
getMsgPrintControl().resetCount(numResponsesKey, pasynUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create custom error messages for different failure modes, if no error
|
// Create custom error messages for different failure modes, if no error
|
||||||
@ -384,15 +423,15 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
paramLibStatus =
|
paramLibStatus =
|
||||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
||||||
if (paramLibStatus != asynSuccess) {
|
if (paramLibStatus != asynSuccess) {
|
||||||
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem_",
|
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem",
|
||||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (motorStatusProblem == 0) {
|
if (motorStatusProblem == 0) {
|
||||||
paramLibStatus =
|
paramLibStatus =
|
||||||
axis->setStringParam(motorMessageText_, drvMessageText);
|
axis->setStringParam(motorMessageText(), drvMessageText);
|
||||||
if (paramLibStatus != asynSuccess) {
|
if (paramLibStatus != asynSuccess) {
|
||||||
return paramLibAccessFailed(paramLibStatus, "motorMessageText_",
|
return paramLibAccessFailed(paramLibStatus, "motorMessageText",
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
axisNo, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
@ -407,7 +446,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|||||||
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
||||||
if (paramLibStatus != asynSuccess) {
|
if (paramLibStatus != asynSuccess) {
|
||||||
return paramLibAccessFailed(paramLibStatus,
|
return paramLibAccessFailed(paramLibStatus,
|
||||||
"motorStatusCommsError_", axisNo,
|
"motorStatusCommsError", axisNo,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -421,13 +460,13 @@ asynStatus turboPmacController::doFlushHardware() {
|
|||||||
constant defined in pmacAsynIPPort.c. This reason is then used within
|
constant defined in pmacAsynIPPort.c. This reason is then used within
|
||||||
the write method of pasynInt32SyncIO to select the flush function.
|
the write method of pasynInt32SyncIO to select the flush function.
|
||||||
*/
|
*/
|
||||||
int temp = pasynInt32SyncIOipPort_->reason;
|
int temp = pTurboPmacC_->pasynInt32SyncIOipPort->reason;
|
||||||
pasynInt32SyncIOipPort_->reason = FLUSH_HARDWARE;
|
pTurboPmacC_->pasynInt32SyncIOipPort->reason = FLUSH_HARDWARE;
|
||||||
asynStatus status = (asynStatus)pasynInt32SyncIO->write(
|
asynStatus status = (asynStatus)pasynInt32SyncIO->write(
|
||||||
pasynInt32SyncIOipPort_, 1, comTimeout_);
|
pTurboPmacC_->pasynInt32SyncIOipPort, 1, pTurboPmacC_->comTimeout);
|
||||||
|
|
||||||
// Reset the status afterwards
|
// Reset the status afterwards
|
||||||
pasynInt32SyncIOipPort_->reason = temp;
|
pTurboPmacC_->pasynInt32SyncIOipPort->reason = temp;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,11 +479,11 @@ asynStatus turboPmacController::writeInt32(asynUser *pasynUser,
|
|||||||
turboPmacAxis *axis = getTurboPmacAxis(pasynUser);
|
turboPmacAxis *axis = getTurboPmacAxis(pasynUser);
|
||||||
|
|
||||||
// Handle custom PVs
|
// Handle custom PVs
|
||||||
if (function == rereadEncoderPosition_) {
|
if (function == rereadEncoderPosition()) {
|
||||||
return axis->rereadEncoder();
|
return axis->rereadEncoder();
|
||||||
} else if (function == readConfig_) {
|
} else if (function == readConfig()) {
|
||||||
return axis->init();
|
return axis->init();
|
||||||
} else if (function == flushHardware_) {
|
} else if (function == flushHardware()) {
|
||||||
return doFlushHardware();
|
return doFlushHardware();
|
||||||
} else {
|
} else {
|
||||||
return sinqController::writeInt32(pasynUser, value);
|
return sinqController::writeInt32(pasynUser, value);
|
||||||
@ -462,6 +501,16 @@ asynStatus turboPmacController::couldNotParseResponse(const char *command,
|
|||||||
command, modifiedResponse, axisNo, functionName, lineNumber);
|
command, modifiedResponse, axisNo, functionName, lineNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int turboPmacController::rereadEncoderPosition() {
|
||||||
|
return pTurboPmacC_->rereadEncoderPosition;
|
||||||
|
}
|
||||||
|
int turboPmacController::readConfig() { return pTurboPmacC_->readConfig; }
|
||||||
|
int turboPmacController::flushHardware() { return pTurboPmacC_->flushHardware; }
|
||||||
|
|
||||||
|
asynUser *turboPmacController::pasynInt32SyncIOipPort() {
|
||||||
|
return pTurboPmacC_->pasynInt32SyncIOipPort;
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************************/
|
/*************************************************************************************/
|
||||||
/** The following functions are C-wrappers, and can be called directly from
|
/** The following functions are C-wrappers, and can be called directly from
|
||||||
* iocsh */
|
* iocsh */
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
#include "sinqController.h"
|
#include "sinqController.h"
|
||||||
#include "turboPmacAxis.h"
|
#include "turboPmacAxis.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct turboPmacControllerImpl;
|
||||||
|
|
||||||
class turboPmacController : public sinqController {
|
class turboPmacController : public sinqController {
|
||||||
public:
|
public:
|
||||||
@ -116,36 +119,16 @@ class turboPmacController : public sinqController {
|
|||||||
asynStatus doFlushHardware();
|
asynStatus doFlushHardware();
|
||||||
|
|
||||||
// Accessors for additional PVs
|
// Accessors for additional PVs
|
||||||
int rereadEncoderPosition() { return rereadEncoderPosition_; }
|
int rereadEncoderPosition();
|
||||||
int readConfig() { return readConfig_; }
|
int readConfig();
|
||||||
int flushHardware() { return flushHardware_; }
|
int flushHardware();
|
||||||
|
|
||||||
// Set the maximum buffer size. This is an empirical value which must be
|
asynUser *pasynInt32SyncIOipPort();
|
||||||
// large enough to avoid overflows for all commands to the device /
|
|
||||||
// responses from it.
|
|
||||||
static const uint32_t MAXBUF_ = 200;
|
|
||||||
|
|
||||||
asynUser *pasynInt32SyncIOipPort() { return pasynInt32SyncIOipPort_; }
|
private:
|
||||||
|
std::unique_ptr<turboPmacControllerImpl> pTurboPmacC_;
|
||||||
|
|
||||||
protected:
|
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 */
|
#endif /* turboPmacController_H */
|
||||||
|
Reference in New Issue
Block a user