Compare commits
4 Commits
1.4.1
...
static-dep
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cc9b1d144 | |||
| 2e42cbc6da | |||
| c5f5cf3065 | |||
| 468ca46010 |
@@ -1,24 +0,0 @@
|
||||
name: Test And Build
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Lint:
|
||||
runs-on: linepics
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: cppcheck
|
||||
run: cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
|
||||
- name: formatting
|
||||
run: clang-format --style=file --Werror --dry-run src/*.cpp
|
||||
Build:
|
||||
runs-on: linepics
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- run: |
|
||||
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
echo -e "\nIGNORE_SUBMODULES += sinqmotor" >> Makefile
|
||||
make install
|
||||
48
.gitlab-ci.yml
Normal file
48
.gitlab-ci.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
default:
|
||||
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- build
|
||||
- test
|
||||
|
||||
cppcheck:
|
||||
stage: lint
|
||||
script:
|
||||
- cppcheck --std=c++17 --addon=cert --addon=misc --suppress=cert-STR07-C --error-exitcode=1 src/*.cpp
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- sinq
|
||||
|
||||
formatting:
|
||||
stage: lint
|
||||
script:
|
||||
- clang-format --style=file --Werror --dry-run src/*.cpp
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- sinq
|
||||
|
||||
build_module:
|
||||
stage: build
|
||||
script:
|
||||
- export SINQMOTOR_VERSION="$(grep 'sinqMotor_VERSION=' Makefile | cut -d= -f2)"
|
||||
- git clone --depth 1 --branch "${SINQMOTOR_VERSION}" https://gitlab-ci-token:${CI_JOB_TOKEN}@git.psi.ch/sinq-epics-modules/sinqmotor.git
|
||||
- pushd sinqmotor
|
||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
- echo "LIBVERSION=${SINQMOTOR_VERSION}" >> Makefile
|
||||
- make install
|
||||
- popd
|
||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
- echo "LIBVERSION=${CI_COMMIT_TAG:-0.0.1}" >> Makefile
|
||||
- make install
|
||||
- cp -rT "/ioc/modules/masterMacs/$(ls -U /ioc/modules/masterMacs/ | head -1)" "./masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
artifacts:
|
||||
name: "masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
paths:
|
||||
- "masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
|
||||
expire_in: 1 week
|
||||
when: always
|
||||
tags:
|
||||
- sinq
|
||||
6
Makefile
6
Makefile
@@ -6,6 +6,9 @@ BUILDCLASSES=Linux
|
||||
EPICS_VERSIONS=7.0.7
|
||||
ARCH_FILTER=RHEL%
|
||||
|
||||
# Additional module dependencies
|
||||
REQUIRED+=sinqMotor
|
||||
|
||||
# Specify the version of asynMotor we want to build against
|
||||
motorBase_VERSION=7.2.2
|
||||
|
||||
@@ -23,10 +26,9 @@ SOURCES += src/masterMacsController.cpp
|
||||
# Store the record files
|
||||
TEMPLATES += sinqMotor/db/asynRecord.db
|
||||
TEMPLATES += sinqMotor/db/sinqMotor.db
|
||||
TEMPLATES += db/masterMacs.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 -Wextra -Werror
|
||||
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wpedantic -Wextra -Werror
|
||||
|
||||
@@ -57,8 +57,6 @@ setThresholdComTimeout("$(NAME)", 100, 1);
|
||||
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||
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("$(masterMacs_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
|
||||
```
|
||||
|
||||
@@ -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,7 +0,0 @@
|
||||
# Call the nodeReset function of the corresponding masterMacsAxis.
|
||||
# This record is coupled to the parameter library via nodeReset_ -> NODE_RESET.
|
||||
record(longout, "$(INSTR)$(M):NodeReset") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) NODE_RESET")
|
||||
field(PINI, "NO")
|
||||
}
|
||||
Submodule sinqMotor updated: 8689c79f19...5689402375
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,14 @@
|
||||
#ifndef masterMacsAXIS_H
|
||||
#define masterMacsAXIS_H
|
||||
#include "masterMacsController.h"
|
||||
#include "sinqAxis.h"
|
||||
#include <memory>
|
||||
#include <bitset>
|
||||
|
||||
struct HIDDEN masterMacsAxisImpl;
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class masterMacsController;
|
||||
|
||||
class HIDDEN masterMacsAxis : public sinqAxis {
|
||||
class masterMacsAxis : public sinqAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new masterMacsAxis
|
||||
@@ -75,27 +77,12 @@ class HIDDEN masterMacsAxis : public sinqAxis {
|
||||
*/
|
||||
asynStatus doReset();
|
||||
|
||||
/**
|
||||
* @brief Performs a "node reset" on the axis as defined in the CANopen
|
||||
* standard
|
||||
*
|
||||
* A "node reset" is a factory reset on the axis which completely deletes
|
||||
* all configured information (e.g. limits or speed) from the axis. The
|
||||
* MasterMACS controller then reapplies the initial configuration to this
|
||||
* axis. It can therefore be seen as a "hard" version of the normal error
|
||||
* reset performed by the `doReset` method.
|
||||
*
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus nodeReset();
|
||||
|
||||
/**
|
||||
* @brief Readout of some values from the controller at IOC startup
|
||||
*
|
||||
* The following steps are performed:
|
||||
* - Read out the motor status, motor position, velocity and
|
||||
* acceleration from the MCU and store this information in the parameter
|
||||
* library.
|
||||
* - Read out the motor status, motor position, velocity and acceleration
|
||||
* from the MCU and store this information in the parameter library.
|
||||
* - Set the enable PV accordint to the initial status of the axis.
|
||||
*
|
||||
* @return asynStatus
|
||||
@@ -111,43 +98,39 @@ class HIDDEN masterMacsAxis : public sinqAxis {
|
||||
asynStatus enable(bool on);
|
||||
|
||||
/**
|
||||
* @brief Read the encoder type (incremental or absolute) for this axis
|
||||
* from the MCU and store the information in the PV ENCODER_TYPE.
|
||||
* @brief Read the encoder type (incremental or absolute) for this axis from
|
||||
* the MCU and store the information in the PV ENCODER_TYPE.
|
||||
*
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus readEncoderType();
|
||||
|
||||
/**
|
||||
* @brief Check if the axis needs to run its initialization function
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool needInit();
|
||||
protected:
|
||||
masterMacsController *pC_;
|
||||
double lastSetSpeed_;
|
||||
bool waitForHandshake_;
|
||||
time_t timeAtHandshake_;
|
||||
|
||||
bool targetReachedUninitialized_;
|
||||
|
||||
asynStatus readConfig();
|
||||
|
||||
/*
|
||||
The axis status and axis error of MasterMACS are given as an integer from
|
||||
the controller. The 16 individual bits contain the actual information.
|
||||
*/
|
||||
std::bitset<16> axisStatus_;
|
||||
std::bitset<16> axisError_;
|
||||
|
||||
/**
|
||||
* @brief Instruct the axis to run its init() function during the next
|
||||
* poll
|
||||
*
|
||||
* @param needInit
|
||||
*/
|
||||
void setNeedInit(bool needInit);
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the axis controller
|
||||
*/
|
||||
virtual masterMacsController *pController() override { return pC_; };
|
||||
|
||||
/**
|
||||
* @brief Read the Master MACS status with the xR10 command and store
|
||||
* the result in axisStatus_
|
||||
* @brief Read the Master MACS status with the xR10 command and store the
|
||||
* result in axisStatus_
|
||||
*
|
||||
*/
|
||||
asynStatus readAxisStatus();
|
||||
|
||||
/*
|
||||
The functions below read the specified status bit from the axisStatus
|
||||
The functions below read the specified status bit from the axisStatus_
|
||||
bitset. Since a bit can either be 0 or 1, the return value is given as a
|
||||
boolean.
|
||||
*/
|
||||
@@ -155,72 +138,72 @@ class HIDDEN masterMacsAxis : public sinqAxis {
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool readyToBeSwitchedOn();
|
||||
bool readyToBeSwitchedOn() { return axisStatus_[0]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool switchedOn();
|
||||
bool switchedOn() { return axisStatus_[1]; }
|
||||
|
||||
// Bit 2 is unused
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool faultConditionSet();
|
||||
bool faultConditionSet() { return axisStatus_[3]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool voltagePresent();
|
||||
bool voltagePresent() { return axisStatus_[4]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool quickStopping();
|
||||
bool quickStopping() { return axisStatus_[5] == 0; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool switchOnDisabled();
|
||||
bool switchOnDisabled() { return axisStatus_[6]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool warning();
|
||||
bool warning() { return axisStatus_[7]; }
|
||||
|
||||
// Bit 8 is unused
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool remoteMode();
|
||||
bool remoteMode() { return axisStatus_[9]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool targetReached();
|
||||
bool targetReached() { return axisStatus_[10]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool internalLimitActive();
|
||||
bool internalLimitActive() { return axisStatus_[11]; }
|
||||
|
||||
// Bits 12 and 13 are unused
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool setEventHasOcurred();
|
||||
bool setEventHasOcurred() { return axisStatus_[14]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisStatus_
|
||||
*/
|
||||
bool powerEnabled();
|
||||
bool powerEnabled() { return axisStatus_[15]; }
|
||||
|
||||
/**
|
||||
* @brief Read the Master MACS status with the xR10 command and store
|
||||
* the result in axisStatus_
|
||||
* @brief Read the Master MACS status with the xR10 command and store the
|
||||
* result in axisStatus_
|
||||
*
|
||||
*/
|
||||
asynStatus readAxisError();
|
||||
@@ -234,76 +217,72 @@ class HIDDEN masterMacsAxis : public sinqAxis {
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool shortCircuit();
|
||||
bool shortCircuit() { return axisError_[1]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool encoderError();
|
||||
bool encoderError() { return axisError_[2]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool followingError();
|
||||
bool followingError() { return axisError_[3]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool communicationError();
|
||||
bool communicationError() { return axisError_[4]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool feedbackError();
|
||||
bool feedbackError() { return axisError_[5]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool positiveLimitSwitch();
|
||||
bool positiveLimitSwitch() { return axisError_[6]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool negativeLimitSwitch();
|
||||
bool negativeLimitSwitch() { return axisError_[7]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool positiveSoftwareLimit();
|
||||
bool positiveSoftwareLimit() { return axisError_[8]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool negativeSoftwareLimit();
|
||||
bool negativeSoftwareLimit() { return axisError_[9]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool overCurrent();
|
||||
bool overCurrent() { return axisError_[10]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool overTemperature();
|
||||
bool overTemperature() { return axisError_[11]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool overVoltage();
|
||||
bool overVoltage() { return axisError_[12]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool underVoltage();
|
||||
bool underVoltage() { return axisError_[13]; }
|
||||
|
||||
/**
|
||||
* @brief Read the property from axisError_
|
||||
*/
|
||||
bool stoFault();
|
||||
|
||||
private:
|
||||
masterMacsController *pC_;
|
||||
std::unique_ptr<masterMacsAxisImpl> pMasterMacsA_;
|
||||
bool stoFault() { return axisError_[15]; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,13 +12,6 @@
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
struct masterMacsControllerImpl {
|
||||
double comTimeout;
|
||||
|
||||
// Indices of additional ParamLib entries
|
||||
int nodeReset;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Copy src into dst and replace all NULL terminators up to the carriage
|
||||
* return with spaces. This allows to print *dst with asynPrint.
|
||||
@@ -66,24 +59,8 @@ masterMacsController::masterMacsController(const char *portName,
|
||||
// Initialization of local variables
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
pMasterMacsC_ =
|
||||
std::make_unique<masterMacsControllerImpl>((masterMacsControllerImpl){
|
||||
.comTimeout = comTimeout,
|
||||
});
|
||||
|
||||
// =========================================================================
|
||||
// Create additional parameter library entries
|
||||
|
||||
status =
|
||||
createParam("NODE_RESET", asynParamInt32, &pMasterMacsC_->nodeReset);
|
||||
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);
|
||||
}
|
||||
// Initialization of all member variables
|
||||
comTimeout_ = comTimeout;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
@@ -137,22 +114,6 @@ masterMacsAxis *masterMacsController::getMasterMacsAxis(int axisNo) {
|
||||
return dynamic_cast<masterMacsAxis *>(asynAxis);
|
||||
}
|
||||
|
||||
asynStatus masterMacsController::writeInt32(asynUser *pasynUser,
|
||||
epicsInt32 value) {
|
||||
int function = pasynUser->reason;
|
||||
|
||||
// =====================================================================
|
||||
|
||||
masterMacsAxis *axis = getMasterMacsAxis(pasynUser);
|
||||
|
||||
// Handle custom PVs
|
||||
if (function == nodeReset()) {
|
||||
return axis->nodeReset();
|
||||
} else {
|
||||
return sinqController::writeInt32(pasynUser, value);
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response,
|
||||
double comTimeout) {
|
||||
return writeRead(axisNo, tcpCmd, NULL, response);
|
||||
@@ -169,6 +130,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
||||
|
||||
// Definition of local variables.
|
||||
asynStatus status = asynSuccess;
|
||||
asynStatus pl_status = asynSuccess;
|
||||
char fullCommand[MAXBUF_] = {0};
|
||||
char fullResponse[MAXBUF_] = {0};
|
||||
char drvMessageText[MAXBUF_] = {0};
|
||||
@@ -196,7 +158,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
||||
|
||||
// Check if a custom timeout has been given
|
||||
if (comTimeout < 0.0) {
|
||||
comTimeout = pMasterMacsC_->comTimeout;
|
||||
comTimeout = comTimeout_;
|
||||
}
|
||||
|
||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||
@@ -230,7 +192,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
||||
msgPrintControlKey comKey =
|
||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
if (status != asynSuccess) {
|
||||
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUserSelf)) {
|
||||
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUserSelf)) {
|
||||
char printableCommand[MAXBUF_] = {0};
|
||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
@@ -240,7 +202,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
||||
stringifyAsynStatus(status), printableCommand);
|
||||
}
|
||||
} else {
|
||||
getMsgPrintControl().resetCount(comKey, pasynUserSelf);
|
||||
msgPrintControl_.resetCount(comKey, pasynUserSelf);
|
||||
}
|
||||
|
||||
// Create custom error messages for different failure modes
|
||||
@@ -287,31 +249,48 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
||||
|
||||
// Log the overall status (communication successfull or not)
|
||||
if (status == asynSuccess) {
|
||||
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||
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
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
|
||||
// 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
|
||||
pl_status =
|
||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
if (motorStatusProblem == 0) {
|
||||
setAxisParamChecked(axis, motorMessageText, drvMessageText);
|
||||
setAxisParamChecked(axis, motorStatusProblem, true);
|
||||
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||
pl_status = axis->setStringParam(motorMessageText_, drvMessageText);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusProblem",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,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;
|
||||
@@ -341,13 +319,12 @@ asynStatus masterMacsController::parseResponse(
|
||||
msgPrintControlKey parseKey =
|
||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||
if (axis == nullptr) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Was the motor previously connected?
|
||||
getAxisParamChecked(axis, motorConnected, &prevConnected);
|
||||
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.
|
||||
@@ -359,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.
|
||||
@@ -371,7 +347,16 @@ asynStatus masterMacsController::parseResponse(
|
||||
"connected.\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
setAxisParamChecked(axis, motorConnected, true);
|
||||
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,
|
||||
@@ -382,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
|
||||
@@ -399,7 +428,16 @@ asynStatus masterMacsController::parseResponse(
|
||||
"disconnected.\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
setAxisParamChecked(axis, motorConnected, false);
|
||||
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,
|
||||
@@ -409,80 +447,33 @@ asynStatus masterMacsController::parseResponse(
|
||||
return status;
|
||||
}
|
||||
}
|
||||
break;
|
||||
return asynDisconnected;
|
||||
} else if (fullResponse[i] == '\x18') {
|
||||
// CAN
|
||||
snprintf(drvMessageText, MAXBUF_,
|
||||
"Tried to write with a read-only command. This is a "
|
||||
"bug, please call the support.");
|
||||
|
||||
if (getMsgPrintControl().shouldBePrinted(parseKey, true,
|
||||
pasynUserSelf)) {
|
||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||
pasynUserSelf)) {
|
||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||
asynPrint(
|
||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
||||
"write with the read-only command %s.%s\n",
|
||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||
printableCommand, getMsgPrintControl().getSuffix());
|
||||
printableCommand, msgPrintControl_.getSuffix());
|
||||
}
|
||||
responseValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (responseValid) {
|
||||
getMsgPrintControl().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 (getMsgPrintControl().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,
|
||||
getMsgPrintControl().getSuffix());
|
||||
}
|
||||
|
||||
snprintf(drvMessageText, MAXBUF_,
|
||||
"Mismatched response %s to command %s. Please call the "
|
||||
"support.",
|
||||
printableResponse, printableCommand);
|
||||
return asynError;
|
||||
} else {
|
||||
getMsgPrintControl().resetCount(responseMatchKey, pasynUserSelf);
|
||||
}
|
||||
}
|
||||
return asynSuccess;
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus masterMacsController::readInt32(asynUser *pasynUser,
|
||||
epicsInt32 *value) {
|
||||
// masterMacs can be disabled
|
||||
if (pasynUser->reason == motorCanDisable()) {
|
||||
if (pasynUser->reason == motorCanDisable_) {
|
||||
*value = 1;
|
||||
return asynSuccess;
|
||||
} else {
|
||||
@@ -490,10 +481,6 @@ asynStatus masterMacsController::readInt32(asynUser *pasynUser,
|
||||
}
|
||||
}
|
||||
|
||||
double masterMacsController::comTimeout() { return pMasterMacsC_->comTimeout; }
|
||||
|
||||
int masterMacsController::nodeReset() { return pMasterMacsC_->nodeReset; }
|
||||
|
||||
/***************************************************************************/
|
||||
/** The following functions are C-wrappers, and can be called directly from
|
||||
* iocsh */
|
||||
|
||||
@@ -8,18 +8,11 @@
|
||||
|
||||
#ifndef masterMacsController_H
|
||||
#define masterMacsController_H
|
||||
#include "masterMacsAxis.h"
|
||||
#include "sinqAxis.h"
|
||||
#include "sinqController.h"
|
||||
#include <memory>
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between the controller and the axis .h-file. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class HIDDEN masterMacsAxis;
|
||||
|
||||
struct HIDDEN masterMacsControllerImpl;
|
||||
|
||||
class HIDDEN masterMacsController : public sinqController {
|
||||
class masterMacsController : public sinqController {
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -38,15 +31,6 @@ class HIDDEN 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
|
||||
*
|
||||
@@ -65,17 +49,6 @@ class HIDDEN masterMacsController : public sinqController {
|
||||
*/
|
||||
masterMacsAxis *getMasterMacsAxis(int axisNo);
|
||||
|
||||
/**
|
||||
* @brief Overloaded function of sinqController
|
||||
*
|
||||
* The function is overloaded to allow resetting the node
|
||||
*
|
||||
* @param pasynUser Specify the axis via the asynUser
|
||||
* @param value New value
|
||||
* @return asynStatus
|
||||
*/
|
||||
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
|
||||
/**
|
||||
* @brief Send a command to the hardware (S mode)
|
||||
*
|
||||
@@ -150,13 +123,15 @@ class HIDDEN masterMacsController : public sinqController {
|
||||
*
|
||||
* @return double Timeout in seconds
|
||||
*/
|
||||
double comTimeout();
|
||||
double comTimeout() { return comTimeout_; }
|
||||
|
||||
// Accessors for additional PVs
|
||||
int nodeReset();
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
|
||||
private:
|
||||
std::unique_ptr<masterMacsControllerImpl> pMasterMacsC_;
|
||||
/*
|
||||
Stores the constructor input comTimeout
|
||||
*/
|
||||
double comTimeout_;
|
||||
};
|
||||
|
||||
#endif /* masterMacsController_H */
|
||||
|
||||
Reference in New Issue
Block a user