diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e8d403e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "sinqmotor"] + path = sinqmotor + url = https://gitea.psi.ch/lin-epics-modules/sinqmotor +[submodule "sinqMotor"] + path = sinqMotor + url = https://gitea.psi.ch/lin-epics-modules/sinqMotor diff --git a/Makefile b/Makefile index 1c9fa85..f3382bf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Use the PSI build system +# Include the external Makefile include /ioc/tools/driver.makefile MODULE=turboPmac @@ -8,28 +8,30 @@ ARCH_FILTER=RHEL% # Additional module dependencies REQUIRED+=motorBase -REQUIRED+=sinqMotor # Specify the version of motorBase we want to build against motorBase_VERSION=7.2.2 -# Specify the version of sinqMotor we want to build against -sinqMotor_VERSION=mathis_s - # These headers allow to depend on this library for derived drivers. HEADERS += src/pmacAsynIPPort.h HEADERS += src/turboPmacAxis.h HEADERS += src/turboPmacController.h # Source files to build +SOURCES += sinqMotor/src/msgPrintControl.cpp +SOURCES += sinqMotor/src/sinqAxis.cpp +SOURCES += sinqMotor/src/sinqController.cpp SOURCES += src/pmacAsynIPPort.c SOURCES += src/turboPmacAxis.cpp SOURCES += src/turboPmacController.cpp # Store the record files +TEMPLATES += sinqMotor/db/asynRecord.db +TEMPLATES += sinqMotor/db/sinqMotor.db TEMPLATES += db/turboPmac.db # This file registers the motor-specific functions in the IOC shell. +DBDS += sinqMotor/src/sinqMotor.dbd DBDS += src/turboPmac.dbd -USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings +USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings \ No newline at end of file diff --git a/README.md b/README.md index 71d0f6d..a6cf3d1 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ setMaxSubsequentTimeouts("$(DRIVER_PORT)", 20); setThresholdComTimeout("$(DRIVER_PORT)", 300, 10); # Parametrize the EPICS record database with the substitution file named after the MCU. -epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db") +epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/sinqMotor.db") dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)") epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db") dbLoadTemplate("$(TOP)/$(DRIVER_PORT).substitutions", "INSTR=$(INSTR)$(DRIVER_PORT):,CONTROLLER=$(DRIVER_PORT)") -dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)") +dbLoadRecords("$(turboPmac_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(IP_PORT)") ``` ### Additional records @@ -73,4 +73,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. diff --git a/sinqMotor b/sinqMotor new file mode 160000 index 0000000..e088bfb --- /dev/null +++ b/sinqMotor @@ -0,0 +1 @@ +Subproject commit e088bfbbcb0e078113661fc08f775286a82393a5 diff --git a/src/turboPmacAxis.cpp b/src/turboPmacAxis.cpp index 23c942c..39c1530 100644 --- a/src/turboPmacAxis.cpp +++ b/src/turboPmacAxis.cpp @@ -71,6 +71,20 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo, exit(-1); } + // 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); + } + // turboPmac motors can always be disabled status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1); if (status != asynSuccess) { @@ -397,13 +411,6 @@ asynStatus turboPmacAxis::doPoll(bool *moving) { case -5: // Axis is deactivated *moving = false; - - pl_status = setStringParam(pC_->motorMessageText(), "Deactivated"); - if (pl_status != asynSuccess) { - return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", - axisNo_, __PRETTY_FUNCTION__, - __LINE__); - } break; case -4: // Emergency stop @@ -426,19 +433,10 @@ asynStatus turboPmacAxis::doPoll(bool *moving) { axisNo_, __PRETTY_FUNCTION__, __LINE__); } - break; case -3: // Disabled *moving = false; - - pl_status = setStringParam(pC_->motorMessageText(), "Disabled"); - if (pl_status != asynSuccess) { - return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", - axisNo_, __PRETTY_FUNCTION__, - __LINE__); - } - break; case 0: // Idle @@ -599,8 +597,7 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage, resetError = false; status = setStringParam(pC_->motorMessageText(), - "Target position would exceed software " - "limits. Please call the support."); + "Target position would exceed software limits"); if (status != asynSuccess) { return pC_->paramLibAccessFailed(status, "motorMessageText_", axisNo_, __PRETTY_FUNCTION__, @@ -783,10 +780,10 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage, } resetError = false; - snprintf(userMessage, sizeUserMessage, - "Driver hardware error (P%2.2d01 = 13). " - "Please call the support.", - axisNo_); + snprintf( + userMessage, sizeUserMessage, + "Driver hardware error (P%2.2d01 = 13). Please call the support.", + axisNo_); status = setStringParam(pC_->motorMessageText(), userMessage); if (status != asynSuccess) { return pC_->paramLibAccessFailed(status, "motorMessageText_", @@ -1084,22 +1081,7 @@ asynStatus turboPmacAxis::doHome(double min_velocity, double max_velocity, axisNo_, __PRETTY_FUNCTION__, __LINE__); } - - pl_status = setStringParam(pC_->motorMessageText(), "Homing"); - if (pl_status != asynSuccess) { - return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", - axisNo_, __PRETTY_FUNCTION__, - __LINE__); - } return callParamCallbacks(); - } else { - pl_status = setStringParam(pC_->motorMessageText(), - "Can't home a motor with absolute encoder"); - if (pl_status != asynSuccess) { - return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", - axisNo_, __PRETTY_FUNCTION__, - __LINE__); - } } return asynSuccess; @@ -1271,6 +1253,14 @@ asynStatus turboPmacAxis::enable(bool on) { // Status of parameter library operations asynStatus pl_status = asynSuccess; + bool moving = false; + rw_status = doPoll(&moving); + if (rw_status != asynSuccess) { + return rw_status; + } + + // ========================================================================= + /* 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 @@ -1280,8 +1270,6 @@ asynStatus turboPmacAxis::enable(bool on) { bool moving = false; doPoll(&moving); - // ========================================================================= - // If the axis is currently moving, it cannot be disabled. Ignore the // command and inform the user. We check the last known status of the axis // instead of "moving", since status -6 is also moving, but the motor can @@ -1330,16 +1318,7 @@ asynStatus turboPmacAxis::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__); - } + rw_status = pC_->writeRead(axisNo_, command, response, 0); if (rw_status != asynSuccess) { return rw_status; @@ -1382,7 +1361,7 @@ asynStatus turboPmacAxis::enable(bool on) { // Output message to user snprintf(command, sizeof(command), "Failed to %s within %d seconds", on ? "enable" : "disable", timeout_enable_disable); - pl_status = setStringParam(pC_->motorMessageText(), "Enabling ..."); + pl_status = setStringParam(pC_->motorMessageText(), command); if (pl_status != asynSuccess) { return pC_->paramLibAccessFailed(pl_status, "motorMessageText_", axisNo_, __PRETTY_FUNCTION__, diff --git a/src/turboPmacController.h b/src/turboPmacController.h index 74cc97f..9636d24 100644 --- a/src/turboPmacController.h +++ b/src/turboPmacController.h @@ -120,17 +120,10 @@ class turboPmacController : public sinqController { int readConfig() { return readConfig_; } int flushHardware() { return flushHardware_; } - // Set the maximum buffer size. This is an empirical value which must be - // large enough to avoid overflows for all commands to the device / - // responses from it. - static const uint32_t MAXBUF_ = 200; - asynUser *pasynInt32SyncIOipPort() { return pasynInt32SyncIOipPort_; } protected: - /* - Timeout for the communication process in seconds - */ + // Timeout for the communication process in seconds double comTimeout_; char lastResponse[MAXBUF_];