|
|
|
@ -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,17 +166,21 @@ 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
turboPmacController::~turboPmacController() {}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Access one of the axes of the controller via the axis adress stored in asynUser.
|
|
|
|
|
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
|
|
|
@ -167,7 +206,6 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|
|
|
|
|
|
|
|
|
// Definition of local variables.
|
|
|
|
|
asynStatus status = asynSuccess;
|
|
|
|
|
asynStatus paramLibStatus = asynSuccess;
|
|
|
|
|
asynStatus timeoutStatus = asynSuccess;
|
|
|
|
|
// char fullCommand[MAXBUF_] = {0};
|
|
|
|
|
char drvMessageText[MAXBUF_] = {0};
|
|
|
|
@ -215,20 +253,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 +277,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 +294,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 +352,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 +379,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 +397,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
|
|
|
|
@ -375,41 +427,18 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
|
|
|
|
|
|
|
|
|
// Log the overall status (communication successfull or not)
|
|
|
|
|
if (status == asynSuccess) {
|
|
|
|
|
paramLibStatus = 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
|
|
|
|
|
paramLibStatus =
|
|
|
|
|
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
|
|
|
|
if (paramLibStatus != asynSuccess) {
|
|
|
|
|
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem_",
|
|
|
|
|
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
|
|
|
|
|
|
|
|
|
|
if (motorStatusProblem == 0) {
|
|
|
|
|
paramLibStatus =
|
|
|
|
|
axis->setStringParam(motorMessageText_, drvMessageText);
|
|
|
|
|
if (paramLibStatus != asynSuccess) {
|
|
|
|
|
return paramLibAccessFailed(paramLibStatus, "motorMessageText_",
|
|
|
|
|
axisNo, __PRETTY_FUNCTION__,
|
|
|
|
|
__LINE__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
|
|
|
if (paramLibStatus != asynSuccess) {
|
|
|
|
|
return paramLibAccessFailed(paramLibStatus,
|
|
|
|
|
"motorStatusProblem", axisNo,
|
|
|
|
|
__PRETTY_FUNCTION__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
|
|
|
if (paramLibStatus != asynSuccess) {
|
|
|
|
|
return paramLibAccessFailed(paramLibStatus,
|
|
|
|
|
"motorStatusCommsError_", axisNo,
|
|
|
|
|
__PRETTY_FUNCTION__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
setAxisParamChecked(axis, motorMessageText, drvMessageText);
|
|
|
|
|
setAxisParamChecked(axis, motorStatusProblem, true);
|
|
|
|
|
setAxisParamChecked(axis, motorStatusCommsError, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
@ -421,13 +450,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 +469,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 +491,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 */
|
|
|
|
|