4 Commits

7 changed files with 93 additions and 66 deletions

3
.gitmodules vendored Normal file
View File

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

View File

@ -12,18 +12,23 @@ REQUIRED+=sinqMotor
# Specify the version of asynMotor we want to build against
motorBase_VERSION=7.2.2
# Specify the version of sinqMotor we want to build against
sinqMotor_VERSION=0.14.0
# These headers allow to depend on this library for derived drivers.
HEADERS += src/masterMacsAxis.h
HEADERS += src/masterMacsController.h
# Source files to build
SOURCES += sinqMotor/src/msgPrintControl.cpp
SOURCES += sinqMotor/src/sinqAxis.cpp
SOURCES += sinqMotor/src/sinqController.cpp
SOURCES += src/masterMacsAxis.cpp
SOURCES += src/masterMacsController.cpp
# Store the record files
TEMPLATES += sinqMotor/db/asynRecord.db
TEMPLATES += sinqMotor/db/sinqMotor.db
# This file registers the motor-specific functions in the IOC shell.
DBDS += sinqMotor/src/sinqMotor.dbd
DBDS += src/masterMacs.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wpedantic -Wextra -Werror

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.

1
sinqMotor Submodule

Submodule sinqMotor added at 5689402375

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);
@ -919,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;
}
@ -1035,8 +1045,6 @@ asynStatus masterMacsAxis::enable(bool on) {
// Status of parameter library operations
asynStatus pl_status = asynSuccess;
bool moving = false;
// =========================================================================
/*
@ -1046,6 +1054,13 @@ asynStatus masterMacsAxis::enable(bool on) {
*/
targetReachedUninitialized_ = true;
/*
Continue regardless of the status returned by the poll; we just want to
find out whether the motor is currently moving or not. If the poll
function fails before it can determine that, it is assumed that the motor
is not moving.
*/
bool moving = false;
doPoll(&moving);
// If the axis is currently moving, it cannot be disabled. Ignore the

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,60 +464,14 @@ 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 sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
asynStatus masterMacsController::readInt32(asynUser *pasynUser,
epicsInt32 *value) {
// masterMacs can be disabled
if (pasynUser->reason == motorCanDisable_) {
*value = 1;

View File

@ -125,6 +125,8 @@ class masterMacsController : public sinqController {
*/
double comTimeout() { return comTimeout_; }
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
private:
/*
Stores the constructor input comTimeout