Compare commits
6 Commits
0.7.0
...
static-dep
Author | SHA1 | Date | |
---|---|---|---|
9cc9b1d144 | |||
2e42cbc6da | |||
c5f5cf3065 | |||
468ca46010 | |||
cd57409f3c | |||
21ffcba8be |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "sinqMotor"]
|
||||
path = sinqMotor
|
||||
url = https://gitea.psi.ch/lin-epics-modules/sinqMotor
|
11
Makefile
11
Makefile
@ -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.13.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
|
||||
|
@ -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
1
sinqMotor
Submodule
Submodule sinqMotor added at 5689402375
@ -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
|
||||
|
@ -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,14 +310,22 @@ 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;
|
||||
char printableCommand[MAXBUF_] = {0};
|
||||
char printableResponse[MAXBUF_] = {0};
|
||||
|
||||
msgPrintControlKey parseKey =
|
||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
// Was the motor previously connected?
|
||||
status = getIntegerParam(axisNo, motorConnected(), &prevConnected);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorConnected", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
// We don't use strlen here since the C string terminator 0x00
|
||||
// occurs in the middle of the char array.
|
||||
for (uint32_t i = 0; i < MAXBUF_; i++) {
|
||||
@ -319,22 +334,120 @@ asynStatus masterMacsController::parseResponse(
|
||||
} else if (fullResponse[i] == '=') {
|
||||
*valueStart = i + 1;
|
||||
} else if (fullResponse[i] == '\x06') {
|
||||
// ACK
|
||||
*valueStop = i;
|
||||
responseValid = true;
|
||||
break;
|
||||
} else if (fullResponse[i] == '\x15') {
|
||||
// NAK
|
||||
snprintf(drvMessageText, MAXBUF_, "Communication failed.");
|
||||
|
||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||
pasynUserSelf)) {
|
||||
// Motor wasn't connected before -> Update the paramLib entry and PV
|
||||
// to show it is now connected.
|
||||
if (prevConnected == 0) {
|
||||
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line "
|
||||
"%d:\nCommunication failed.%s\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||
msgPrintControl_.getSuffix());
|
||||
"%d:\nAxis connection status has changed to "
|
||||
"connected.\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||
if (axis == nullptr) {
|
||||
return asynError;
|
||||
}
|
||||
status = axis->setIntegerParam(motorConnected(), 1);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorConnected",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
status = callParamCallbacks();
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line "
|
||||
"%d:\nCould not update parameter library\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
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
|
||||
This indicates that the axis is not connected. This is not an error!
|
||||
*/
|
||||
snprintf(drvMessageText, MAXBUF_, "Axis not connected.");
|
||||
|
||||
// Motor was connected before -> Update the paramLib entry and PV
|
||||
// to show it is now disconnected.
|
||||
if (prevConnected == 1) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line "
|
||||
"%d:\nAxis connection status has changed to "
|
||||
"disconnected.\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||
if (axis == nullptr) {
|
||||
return asynError;
|
||||
}
|
||||
status = axis->setIntegerParam(motorConnected(), 0);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorConnected",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
status = callParamCallbacks();
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line "
|
||||
"%d:\nCould not update parameter library\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return asynDisconnected;
|
||||
} else if (fullResponse[i] == '\x18') {
|
||||
// CAN
|
||||
snprintf(drvMessageText, MAXBUF_,
|
||||
@ -351,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;
|
||||
|
@ -125,6 +125,8 @@ class masterMacsController : public sinqController {
|
||||
*/
|
||||
double comTimeout() { return comTimeout_; }
|
||||
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
|
||||
private:
|
||||
/*
|
||||
Stores the constructor input comTimeout
|
||||
|
Reference in New Issue
Block a user