4 Commits

6 changed files with 97 additions and 98 deletions

View File

@ -31,4 +31,4 @@ TEMPLATES += sinqMotor/db/sinqMotor.db
DBDS += sinqMotor/src/sinqMotor.dbd
DBDS += src/masterMacs.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wextra -Werror
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wpedantic -Wextra -Werror

View File

@ -55,11 +55,9 @@ setMaxSubsequentTimeouts("$(NAME)", 20);
setThresholdComTimeout("$(NAME)", 100, 1);
# Parametrize the EPICS record database with the substitution file named after the MCU.
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/sinqMotor.db")
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/masterMacs.db")
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
dbLoadRecords("$(masterMacs_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
```
### Versioning
@ -68,4 +66,4 @@ Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-e
### How to build it
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
This driver can be compiled and installed by running `make install` from the same directory where the Makefile is located. However, since it uses the git submodule sinqMotor, make sure that the correct version of the submodule repository is checked out AND the change is commited (`git status` shows no non-committed changes). Please see the section "Usage as static dependency" in https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md for more details.

View File

@ -60,9 +60,9 @@ void appendErrorMessage(char *fullMessage, size_t capacityFullMessage,
// fullMessage suffices. We need capacity for one additional character
// because of the linebreak.
if (lenFullMessage + lenToBeAppended + 1 < capacityFullMessage) {
// Append the linebreak and readd the null terminator behind it
// fullMessage[lenFullMessage] = '\n';
// fullMessage[lenFullMessage + 1] = '\0';
// Append the linebreak and set the null terminator behind it
fullMessage[lenFullMessage] = '\n';
fullMessage[lenFullMessage + 1] = '\0';
// We check before that the capacity of fullMessage is sufficient
strcat(fullMessage, toBeAppended);
@ -138,20 +138,6 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
}
// Even though this happens already in sinqAxis, a default value for
// motorMessageText is set here again, because apparently the sinqAxis
// constructor is not run before the string is accessed?
status = setStringParam(pC_->motorMessageText(), "");
if (status != asynSuccess) {
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
"(setting a parameter value failed "
"with %s)\n. Terminating IOC",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
pC_->stringifyAsynStatus(status));
exit(-1);
}
}
masterMacsAxis::~masterMacsAxis(void) {
@ -474,7 +460,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// This buffer must be initialized to zero because we build the
// error message by appending strings.
char errorMessage[pC_->MAXBUF_] = {0};
char userMessage[pC_->MAXBUF_] = {0};
char shellMessage[pC_->MAXBUF_] = {0};
// Concatenate all other errors
@ -482,7 +468,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Short circuit fault.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Short circuit error. Please call the support.");
poll_status = asynError;
@ -491,7 +477,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (encoderError()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Encoder error.");
appendErrorMessage(errorMessage, sizeof(errorMessage),
appendErrorMessage(userMessage, sizeof(userMessage),
"Encoder error. Please call the support.");
poll_status = asynError;
@ -502,7 +488,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
shellMessage, sizeof(shellMessage),
"Maximum callowed following error exceeded.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Maximum allowed following error exceeded.Check if "
"movement range is blocked. Otherwise please call the "
"support.");
@ -513,7 +499,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (feedbackError()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Feedback error.");
appendErrorMessage(errorMessage, sizeof(errorMessage),
appendErrorMessage(userMessage, sizeof(userMessage),
"Feedback error. Please call the support.");
poll_status = asynError;
@ -549,7 +535,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Generic error message for user
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Software limits or end switch hit. Try homing the motor, "
"moving in the opposite direction or check the SPS for "
"errors (if available). Otherwise please call the "
@ -562,7 +548,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overcurrent error.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Overcurrent error. Please call the support.");
poll_status = asynError;
@ -572,7 +558,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overtemperature error.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Overtemperature error. Please call the support.");
poll_status = asynError;
@ -582,7 +568,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Overvoltage error.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Overvoltage error. Please call the support.");
poll_status = asynError;
@ -592,7 +578,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"Undervoltage error.");
appendErrorMessage(
errorMessage, sizeof(errorMessage),
userMessage, sizeof(userMessage),
"Undervoltage error. Please call the support.");
poll_status = asynError;
@ -601,7 +587,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (stoFault()) {
appendErrorMessage(shellMessage, sizeof(shellMessage),
"STO input is on disable state.");
appendErrorMessage(errorMessage, sizeof(errorMessage),
appendErrorMessage(userMessage, sizeof(userMessage),
"STO fault. Please call the support.");
poll_status = asynError;
@ -619,7 +605,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
}
}
pl_status = setStringParam(pC_->motorMessageText(), errorMessage);
pl_status = setStringParam(pC_->motorMessageText(), userMessage);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
@ -933,6 +919,16 @@ asynStatus masterMacsAxis::doReset() {
}
}
rw_status = pC_->write(axisNo_, 85, "");
if (rw_status != asynSuccess) {
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
}
return rw_status;
}
@ -1107,6 +1103,16 @@ asynStatus masterMacsAxis::enable(bool on) {
"Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
on ? "Enable" : "Disable");
if (on == 0) {
pl_status = setStringParam(pC_->motorMessageText(), "Disabling ...");
} else {
pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
}
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,
__LINE__);
}
// The answer to the enable command on MasterMACS might take some time,
// hence we wait for a custom timespan in seconds instead of
@ -1152,7 +1158,7 @@ asynStatus masterMacsAxis::enable(bool on) {
// Output message to user
snprintf(value, sizeof(value), "Failed to %s within %d seconds",
on ? "enable" : "disable", timeout_enable_disable);
pl_status = setStringParam(pC_->motorMessageText(), value);
pl_status = setStringParam(pC_->motorMessageText(), "Enabling ...");
if (pl_status != asynSuccess) {
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
axisNo_, __PRETTY_FUNCTION__,

View File

@ -250,7 +250,14 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
// Log the overall status (communication successfull or not)
if (status == asynSuccess) {
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
if (pl_status != asynSuccess) {
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
axisNo, __PRETTY_FUNCTION__, __LINE__);
}
} else if (status == asynDisconnected) {
// Do nothing
} else {
// Set the error status bits only if the axis is not disconnected
// Check if the axis already is in an error communication mode. If
// it is not, upstream the error. This is done to avoid "flooding"
@ -303,7 +310,6 @@ asynStatus masterMacsController::parseResponse(
const char *fullCommand, const char *fullResponse, char *drvMessageText,
int *valueStart, int *valueStop, int axisNo, int tcpCmd, bool isRead) {
bool responseValid = false;
int responseStart = 0;
asynStatus status = asynSuccess;
int prevConnected = 0;
@ -330,7 +336,6 @@ asynStatus masterMacsController::parseResponse(
} else if (fullResponse[i] == '\x06') {
// ACK
*valueStop = i;
responseValid = true;
// Motor wasn't connected before -> Update the paramLib entry and PV
// to show it is now connected.
@ -362,7 +367,51 @@ asynStatus masterMacsController::parseResponse(
}
}
break;
msgPrintControl_.resetCount(parseKey, pasynUserSelf);
// Check if the response matches the expectations. Each response
// contains the string "axisNo R tcpCmd" (including the spaces)
char expectedResponseSubstring[MAXBUF_] = {0};
// The response does not contain a leading 0 if tcpCmd only has
// a single digit!
if (isRead) {
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d R %d",
axisNo, tcpCmd);
} else {
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d S %d",
axisNo, tcpCmd);
}
msgPrintControlKey responseMatchKey = msgPrintControlKey(
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (strstr(&fullResponse[responseStart],
expectedResponseSubstring) == NULL) {
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
if (msgPrintControl_.shouldBePrinted(parseKey, true,
pasynUserSelf)) {
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"Controller \"%s\", axis %d => %s, line "
"%d:\nMismatched "
"response %s to command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
printableResponse, printableCommand,
msgPrintControl_.getSuffix());
}
snprintf(
drvMessageText, MAXBUF_,
"Mismatched response %s to command %s. Please call the "
"support.",
printableResponse, printableCommand);
return asynError;
} else {
msgPrintControl_.resetCount(responseMatchKey, pasynUserSelf);
}
return asynSuccess;
} else if (fullResponse[i] == '\x15') {
/*
NAK
@ -398,7 +447,7 @@ asynStatus masterMacsController::parseResponse(
return status;
}
}
break;
return asynDisconnected;
} else if (fullResponse[i] == '\x18') {
// CAN
snprintf(drvMessageText, MAXBUF_,
@ -415,57 +464,10 @@ asynStatus masterMacsController::parseResponse(
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
printableCommand, msgPrintControl_.getSuffix());
}
responseValid = false;
break;
}
}
if (responseValid) {
msgPrintControl_.resetCount(parseKey, pasynUserSelf);
// Check if the response matches the expectations. Each response
// contains the string "axisNo R tcpCmd" (including the spaces)
char expectedResponseSubstring[MAXBUF_] = {0};
// The response does not contain a leading 0 if tcpCmd only has
// a single digit!
if (isRead) {
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d R %d", axisNo,
tcpCmd);
} else {
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d S %d", axisNo,
tcpCmd);
}
msgPrintControlKey responseMatchKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
if (strstr(&fullResponse[responseStart], expectedResponseSubstring) ==
NULL) {
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
if (msgPrintControl_.shouldBePrinted(parseKey, true,
pasynUserSelf)) {
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
"Controller \"%s\", axis %d => %s, line "
"%d:\nMismatched "
"response %s to command %s.%s\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
printableResponse, printableCommand,
msgPrintControl_.getSuffix());
}
snprintf(drvMessageText, MAXBUF_,
"Mismatched response %s to command %s. Please call the "
"support.",
printableResponse, printableCommand);
return asynError;
} else {
msgPrintControl_.resetCount(responseMatchKey, pasynUserSelf);
}
}
return asynSuccess;
return asynError;
}
asynStatus masterMacsController::readInt32(asynUser *pasynUser,

View File

@ -31,15 +31,6 @@ class masterMacsController : public sinqController {
int numAxes, double movingPollPeriod,
double idlePollPeriod, double comTimeout);
/**
* @brief Overloaded version of the sinqController version
*
* @param pasynUser
* @param value
* @return asynStatus
*/
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
/**
* @brief Get the axis object
*
@ -134,6 +125,8 @@ class masterMacsController : public sinqController {
*/
double comTimeout() { return comTimeout_; }
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
private:
/*
Stores the constructor input comTimeout