Compare commits

..

11 Commits
1.4.0 ... 1.5.5

Author SHA1 Message Date
6dc2b131f7 Exempt EPICS libraries from -Weffc++
Some checks failed
Test And Build / Build (push) Failing after 6s
Test And Build / Lint (push) Successful in 26s
2025-09-17 12:33:58 +02:00
902b18d038 Excempt EPICS libraries from -Weffc++
All checks were successful
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 7s
2025-09-17 12:18:06 +02:00
0e10bcf69d Fixed some more warnings
All checks were successful
Test And Build / Lint (push) Successful in 5s
Test And Build / Build (push) Successful in 6s
2025-09-17 11:28:12 +02:00
cb4adb068c Fixed some warnings
All checks were successful
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 5s
2025-09-17 11:24:15 +02:00
d7c9d009ee Better solution for suppressing unused variable warning
All checks were successful
Test And Build / Lint (push) Successful in 5s
Test And Build / Build (push) Successful in 5s
2025-09-17 11:08:24 +02:00
3ab40a8bf5 Fixed compiler warnings
Some checks failed
Test And Build / Lint (push) Failing after 2s
Test And Build / Build (push) Successful in 7s
2025-09-17 10:52:56 +02:00
0478854007 Added compiler flags to improve code quality 2025-09-17 10:25:50 +02:00
9a32532c22 Expanded error messageto give users the ability to help themselves
All checks were successful
Test And Build / Lint (push) Successful in 5s
Test And Build / Build (push) Successful in 6s
2025-09-17 10:24:07 +02:00
cff64f5ecf Added new feature to set deadband
All checks were successful
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 12s
The field SPDB can now be populated via either the substitutions file or
from inside the driver (using the motorPositionDeadband paramLib entry).
2025-09-09 16:50:26 +02:00
7a0de4e9d9 Perform callParamCallbacks even if movement watchdog timed out
All checks were successful
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 5s
2025-08-14 17:15:21 +02:00
566728c57c Fixed error in README.md
All checks were successful
Test And Build / Lint (push) Successful in 5s
Test And Build / Build (push) Successful in 5s
2025-08-12 09:15:55 +02:00
9 changed files with 237 additions and 89 deletions

View File

@@ -26,6 +26,7 @@ TEMPLATES += db/sinqMotor.db
# This file registers the motor-specific functions in the IOC shell. # This file registers the motor-specific functions in the IOC shell.
DBDS += src/sinqMotor.dbd DBDS += src/sinqMotor.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result # -Werror USR_CFLAGS += -Wall -Wextra -Wunused-result # -Werror
USR_CXXFLAGS += -Wall -Wextra -Wunused-result
# MISCS would be the place to keep the stream device template files # MISCS would be the place to keep the stream device template files

View File

@@ -257,7 +257,7 @@ This method should not be called in the driver code itself if a poll is needed -
- `startMovTimeoutWatchdog`: Starts a watchdog for the movement time. This watchdog compares the actual time spent in a movement operation with an expected time, which is calculated based on the distance of the current and the target position. - `startMovTimeoutWatchdog`: Starts a watchdog for the movement time. This watchdog compares the actual time spent in a movement operation with an expected time, which is calculated based on the distance of the current and the target position.
- `checkMovTimeoutWatchdog`: Check if the watchdog timed out. - `checkMovTimeoutWatchdog`: Check if the watchdog timed out.
- `setWatchdogEnabled`: Enables / disables the watchdog. This function is also available in the IOC shell. - `setWatchdogEnabled`: Enables / disables the watchdog. This function is also available in the IOC shell.
- `setOffsetMovTimeout`: Set a linear offset for the expected movement time. This function is also available in the IOC shell. - `setOffsetMovTimeout`: Set a constant offset for the expected movement time. This function is also available in the IOC shell.
- `setScaleMovTimeout`: Set a scaling factor for the expected movement time. This function is also available in the IOC shell. - `setScaleMovTimeout`: Set a scaling factor for the expected movement time. This function is also available in the IOC shell.
#### msgPrintControl.h #### msgPrintControl.h

View File

@@ -41,6 +41,7 @@ record(motor,"$(INSTR)$(M)")
field(PINI,"NO") field(PINI,"NO")
field(DHLM, "$(DHLM=0)") field(DHLM, "$(DHLM=0)")
field(DLLM, "$(DLLM=0)") field(DLLM, "$(DLLM=0)")
field(SPDB, "$(SPDB=0)")
field(TWV,"1") field(TWV,"1")
field(RTRY,"0") field(RTRY,"0")
field(RDBD, "$(RDBD=10e300)") # Suppress retries and overshoot stop commands field(RDBD, "$(RDBD=10e300)") # Suppress retries and overshoot stop commands
@@ -238,6 +239,27 @@ record(ao, "$(INSTR)$(M):PushDLLM2Field") {
field(PINI, "NO") field(PINI, "NO")
} }
# This record pair reads the parameter library value for "motorPositionDeadband"
# and pushes it to the motor record field "SPDP". This can be used to the position
# deadband from the hardware
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
# This record is coupled to the parameter library via motorPositionDeadband -> MOTOR_POSITION_DEADBAND.
record(ai, "$(INSTR)$(M):SPDB_RBV")
{
field(DTYP, "asynFloat64")
field(VAL, "$(SPDP=0)")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_POSITION_DEADBAND")
field(SCAN, "I/O Intr")
field(FLNK, "$(INSTR)$(M):PushSPDB2Field")
field(PINI, "NO")
}
record(ao, "$(INSTR)$(M):PushSPDB2Field") {
field(DOL, "$(INSTR)$(M):SPDB_RBV NPP")
field(OUT, "$(INSTR)$(M).SPDB")
field(OMSL, "closed_loop")
field(PINI, "NO")
}
# This record pair reads the parameter library value for "motorVeloFromDriver_" # This record pair reads the parameter library value for "motorVeloFromDriver_"
# and pushes it to the motor record field "VELO". This can be used to read the speed value # and pushes it to the motor record field "VELO". This can be used to read the speed value
# from the hardware and correspondingly update the motor record from the driver. # from the hardware and correspondingly update the motor record from the driver.

View File

@@ -5,21 +5,19 @@
msgPrintControlKey::msgPrintControlKey(char *controller, int axisNo, msgPrintControlKey::msgPrintControlKey(char *controller, int axisNo,
const char *functionName, int line, const char *functionName, int line,
size_t maxRepetitions) { size_t maxRepetitions)
controller_ = controller; : controller_(controller), axisNo_(axisNo), functionName_(functionName),
axisNo_ = axisNo; line_(line), maxRepetitions_(maxRepetitions) {}
line_ = line;
functionName_ = functionName;
maxRepetitions_ = maxRepetitions;
}
void msgPrintControlKey::format(char *buffer, size_t bufferSize) { void msgPrintControlKey::format(char *buffer, size_t bufferSize) {
snprintf(buffer, bufferSize, "controller %s, axis %d, function %s, line %d", snprintf(buffer, bufferSize, "controller %s, axis %d, function %s, line %d",
controller_.c_str(), axisNo_, functionName_, line_); controller_.c_str(), axisNo_, functionName_.c_str(), line_);
} }
// ============================================================================= // =============================================================================
msgPrintControl::msgPrintControl() : map_(), suffix_{} {}
msgPrintControl::~msgPrintControl() = default; msgPrintControl::~msgPrintControl() = default;
bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint, bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
@@ -78,8 +76,8 @@ bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
pasynUser, ASYN_TRACE_ERROR, pasynUser, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\nError " "Controller \"%s\", axis %d => %s, line %d\nError "
"associated with key \"%s\" has been resolved.\n", "associated with key \"%s\" has been resolved.\n",
key.controller_.c_str(), key.axisNo_, key.functionName_, key.controller_.c_str(), key.axisNo_,
key.line_, formattedKey); key.functionName_.c_str(), key.line_, formattedKey);
} }
map_[key] = 0; map_[key] = 0;
} }
@@ -92,8 +90,8 @@ bool msgPrintControl::shouldBePrinted(char *portName, int axisNo,
const char *functionName, int line, const char *functionName, int line,
bool wantToPrint, asynUser *pasynUser, bool wantToPrint, asynUser *pasynUser,
size_t maxRepetitions) { size_t maxRepetitions) {
msgPrintControlKey key = msgPrintControlKey key = msgPrintControlKey(portName, axisNo, functionName,
msgPrintControlKey(portName, axisNo, functionName, __LINE__); line, maxRepetitions);
return shouldBePrinted(key, wantToPrint, pasynUser); return shouldBePrinted(key, wantToPrint, pasynUser);
} }
@@ -107,7 +105,7 @@ void msgPrintControl::resetCount(msgPrintControlKey &key, asynUser *pasynUser) {
"Controller \"%s\", axis %d => %s, line %d\nError " "Controller \"%s\", axis %d => %s, line %d\nError "
"associated with key \"%s\" has been resolved.\n", "associated with key \"%s\" has been resolved.\n",
key.controller_.c_str(), key.axisNo_, key.controller_.c_str(), key.axisNo_,
key.functionName_, key.line_, formattedKey); key.functionName_.c_str(), key.line_, formattedKey);
} }
map_[key] = 0; map_[key] = 0;
} }

View File

@@ -5,8 +5,15 @@
#define DefaultMaxRepetitions 4 #define DefaultMaxRepetitions 4
#include <asynDriver.h> // The EPICS libaries do not follow -Weffc++
#include <macros.h> #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "asynDriver.h"
#include "macros.h"
#pragma GCC diagnostic pop
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@@ -18,12 +25,23 @@
*/ */
class HIDDEN msgPrintControlKey { class HIDDEN msgPrintControlKey {
public: public:
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
int line, size_t maxRepetitions = DefaultMaxRepetitions);
bool operator==(const msgPrintControlKey &other) const {
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
functionName_ == other.functionName_ &&
controller_ == other.controller_;
}
void format(char *buffer, size_t bufferSize);
std::string controller_; std::string controller_;
// -1 indicates a non-axis specific message // -1 indicates a non-axis specific message
int axisNo_; int axisNo_;
const char *functionName_; std::string functionName_;
int line_; int line_;
/** /**
@@ -32,17 +50,6 @@ class HIDDEN msgPrintControlKey {
* *
*/ */
size_t maxRepetitions_; size_t maxRepetitions_;
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
int line, size_t maxRepetitions = DefaultMaxRepetitions);
bool operator==(const msgPrintControlKey &other) const {
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
strcmp(functionName_, other.functionName_) == 0 &&
controller_ == other.controller_;
}
void format(char *buffer, size_t bufferSize);
}; };
/** /**
@@ -55,7 +62,7 @@ template <> struct hash<msgPrintControlKey> {
// Combine the hashes of the members (x and y) // Combine the hashes of the members (x and y)
size_t h1 = std::hash<std::string>{}(obj.controller_); size_t h1 = std::hash<std::string>{}(obj.controller_);
size_t h2 = hash<int>{}(obj.axisNo_); size_t h2 = hash<int>{}(obj.axisNo_);
size_t h3 = std::hash<const char *>{}(obj.functionName_); size_t h3 = std::hash<std::string>{}(obj.functionName_);
size_t h4 = hash<int>{}(obj.line_); size_t h4 = hash<int>{}(obj.line_);
// Combine the hashes (simple XOR and shifting technique) // Combine the hashes (simple XOR and shifting technique)
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3); return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
@@ -85,6 +92,12 @@ template <> struct hash<msgPrintControlKey> {
*/ */
class HIDDEN msgPrintControl { class HIDDEN msgPrintControl {
public: public:
/**
* @brief Construct a new msgPrintControl object
*
*/
msgPrintControl();
/** /**
* @brief Destroy the msgPrintControl object * @brief Destroy the msgPrintControl object
* *

View File

@@ -1,12 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
#include "sinqAxis.h" // The EPICS libaries do not follow -Weffc++
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "epicsExport.h" #include "epicsExport.h"
#include "iocsh.h" #include "iocsh.h"
#include "msgPrintControl.h"
#include "sinqController.h"
#include <epicsTime.h> #include <epicsTime.h>
#include <errlog.h> #include <errlog.h>
#pragma GCC diagnostic pop
#include "msgPrintControl.h"
#include "sinqAxis.h"
#include "sinqController.h"
#include <math.h> #include <math.h>
#include <unistd.h> #include <unistd.h>
@@ -31,21 +38,22 @@ struct sinqAxisImpl {
}; };
sinqAxis::sinqAxis(class sinqController *pC, int axisNo) sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
: asynMotorAxis((asynMotorController *)pC, axisNo), pC_(pC) { : asynMotorAxis((asynMotorController *)pC, axisNo), pC_(pC), pSinqA_([] {
epicsTimeStamp lastPollTime;
epicsTimeGetCurrent(&lastPollTime);
return std::make_unique<sinqAxisImpl>(sinqAxisImpl{
.expectedArrivalTime = 0,
.offsetMovTimeout = 30,
.scaleMovTimeout = 2.0,
.watchdogMovActive = false,
.targetPosition = 0.0,
.wasMoving = false,
.lastPollTime = lastPollTime,
});
}()) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
epicsTimeStamp lastPollTime;
epicsTimeGetCurrent(&lastPollTime);
pSinqA_ = std::make_unique<sinqAxisImpl>(
(sinqAxisImpl){.expectedArrivalTime = 0,
.offsetMovTimeout = 30,
.scaleMovTimeout = 2.0,
.watchdogMovActive = false,
.targetPosition = 0.0,
.wasMoving = false,
.lastPollTime = lastPollTime});
/* /*
This check is also done in asynMotorAxis, but there the IOC continues This check is also done in asynMotorAxis, but there the IOC continues
running even though the configuration is incorrect. When failing this check, running even though the configuration is incorrect. When failing this check,
@@ -283,9 +291,12 @@ asynStatus sinqAxis::forcedPoll(bool *moving) {
pSinqA_->wasMoving = *moving; pSinqA_->wasMoving = *moving;
} }
// Check and update the watchdog // Check and update the watchdog as well as the general poll status IF the
if (checkMovTimeoutWatchdog(*moving) != asynSuccess) { // poll did not fail already.
return asynError; if (poll_status == asynSuccess) {
if (checkMovTimeoutWatchdog(*moving) != asynSuccess) {
poll_status = asynError;
}
} }
// According to the function documentation of asynMotorAxis::poll, this // According to the function documentation of asynMotorAxis::poll, this
@@ -315,7 +326,12 @@ asynStatus sinqAxis::forcedPoll(bool *moving) {
return poll_status; return poll_status;
} }
asynStatus sinqAxis::doPoll(bool *moving) { return asynSuccess; } asynStatus sinqAxis::doPoll(bool *moving) {
// Suppress unused variable warning - this is just a default fallback
// function.
(void)moving;
return asynSuccess;
}
asynStatus sinqAxis::move(double position, int relative, double minVelocity, asynStatus sinqAxis::move(double position, int relative, double minVelocity,
double maxVelocity, double acceleration) { double maxVelocity, double acceleration) {
@@ -353,6 +369,13 @@ asynStatus sinqAxis::move(double position, int relative, double minVelocity,
asynStatus sinqAxis::doMove(double position, int relative, double minVelocity, asynStatus sinqAxis::doMove(double position, int relative, double minVelocity,
double maxVelocity, double acceleration) { double maxVelocity, double acceleration) {
// Suppress unused variable warning - this is just a default fallback
// function.
(void)position;
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
return asynSuccess; return asynSuccess;
} }
@@ -396,6 +419,12 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
asynStatus sinqAxis::doHome(double minVelocity, double maxVelocity, asynStatus sinqAxis::doHome(double minVelocity, double maxVelocity,
double acceleration, int forwards) { double acceleration, int forwards) {
// Suppress unused variable warning - this is just a default fallback
// function.
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
(void)forwards;
return asynSuccess; return asynSuccess;
} }
@@ -417,7 +446,12 @@ asynStatus sinqAxis::reset() {
asynStatus sinqAxis::doReset() { return asynError; } asynStatus sinqAxis::doReset() { return asynError; }
asynStatus sinqAxis::enable(bool on) { return asynSuccess; } asynStatus sinqAxis::enable(bool on) {
// Suppress unused variable warning - this is just a default fallback
// function.
(void)on;
return asynSuccess;
}
asynStatus sinqAxis::motorPosition(double *motorPos) { asynStatus sinqAxis::motorPosition(double *motorPos) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@@ -479,9 +513,9 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
"vmax=%lf.\n", "vmax=%lf.\n",
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
vbas, vmax); vbas, vmax);
setAxisParamChecked( setAxisParamChecked(this, motorMessageText,
this, motorMessageText, "Lower speed limit must not be smaller than "
"Lower speed limit must not be smaller than upper speed limit"); "upper speed limit. Please call the support.");
return asynError; return asynError;
} }
if (velo < vbas || velo > vmax) { if (velo < vbas || velo > vmax) {
@@ -492,8 +526,10 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
velo, vbas, vmax); velo, vbas, vmax);
setAxisParamChecked(this, motorMessageText, setAxisParamChecked(
"Speed is not inside limits"); this, motorMessageText,
"Speed is not inside limits. Set a new valid speed and try "
"to move the motor. Otherwise, please call the support.");
return asynError; return asynError;
} }
@@ -706,8 +742,9 @@ static const iocshArg setWatchdogEnabledArg2 = {
"Enabling / disabling the watchdog", iocshArgInt}; "Enabling / disabling the watchdog", iocshArgInt};
static const iocshArg *const setWatchdogEnabledArgs[] = { static const iocshArg *const setWatchdogEnabledArgs[] = {
&setWatchdogEnabledArg0, &setWatchdogEnabledArg1, &setWatchdogEnabledArg2}; &setWatchdogEnabledArg0, &setWatchdogEnabledArg1, &setWatchdogEnabledArg2};
static const iocshFuncDef setWatchdogEnabledDef = {"setWatchdogEnabled", 3, static const iocshFuncDef setWatchdogEnabledDef = {
setWatchdogEnabledArgs}; "setWatchdogEnabled", 3, setWatchdogEnabledArgs,
"Set to 0 to disable the watchdog and to any other value to enable it."};
static void setWatchdogEnabledCallFunc(const iocshArgBuf *args) { static void setWatchdogEnabledCallFunc(const iocshArgBuf *args) {
setWatchdogEnabled(args[0].sval, args[1].ival, args[2].ival); setWatchdogEnabled(args[0].sval, args[1].ival, args[2].ival);
@@ -753,8 +790,9 @@ static const iocshArg setOffsetMovTimeoutArg2 = {"Offset timeout for movement",
static const iocshArg *const setOffsetMovTimeoutArgs[] = { static const iocshArg *const setOffsetMovTimeoutArgs[] = {
&setOffsetMovTimeoutArg0, &setOffsetMovTimeoutArg1, &setOffsetMovTimeoutArg0, &setOffsetMovTimeoutArg1,
&setOffsetMovTimeoutArg2}; &setOffsetMovTimeoutArg2};
static const iocshFuncDef setOffsetMovTimeoutDef = {"setOffsetMovTimeout", 3, static const iocshFuncDef setOffsetMovTimeoutDef = {
setOffsetMovTimeoutArgs}; "setOffsetMovTimeout", 3, setOffsetMovTimeoutArgs,
"Specify an offset (in seconds) for the movement timeout watchdog"};
static void setOffsetMovTimeoutCallFunc(const iocshArgBuf *args) { static void setOffsetMovTimeoutCallFunc(const iocshArgBuf *args) {
setOffsetMovTimeout(args[0].sval, args[1].ival, args[2].dval); setOffsetMovTimeout(args[0].sval, args[1].ival, args[2].dval);
@@ -800,8 +838,9 @@ static const iocshArg setScaleMovTimeoutArg2 = {
"Multiplier for calculated move time", iocshArgDouble}; "Multiplier for calculated move time", iocshArgDouble};
static const iocshArg *const setScaleMovTimeoutArgs[] = { static const iocshArg *const setScaleMovTimeoutArgs[] = {
&setScaleMovTimeoutArg0, &setScaleMovTimeoutArg1, &setScaleMovTimeoutArg2}; &setScaleMovTimeoutArg0, &setScaleMovTimeoutArg1, &setScaleMovTimeoutArg2};
static const iocshFuncDef setScaleMovTimeoutDef = {"setScaleMovTimeout", 3, static const iocshFuncDef setScaleMovTimeoutDef = {
setScaleMovTimeoutArgs}; "setScaleMovTimeout", 3, setScaleMovTimeoutArgs,
"Set a scaling factor for the maximum expected movement time."};
static void setScaleMovTimeoutCallFunc(const iocshArgBuf *args) { static void setScaleMovTimeoutCallFunc(const iocshArgBuf *args) {
setScaleMovTimeout(args[0].sval, args[1].ival, args[2].dval); setScaleMovTimeout(args[0].sval, args[1].ival, args[2].dval);

View File

@@ -8,8 +8,16 @@ Stefan Mathis, November 2024
#ifndef sinqAxis_H #ifndef sinqAxis_H
#define sinqAxis_H #define sinqAxis_H
// The EPICS libaries do not follow -Weffc++
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "asynMotorAxis.h" #include "asynMotorAxis.h"
#include <macros.h> #include "macros.h"
#pragma GCC diagnostic pop
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
@@ -32,6 +40,13 @@ class HIDDEN sinqAxis : public asynMotorAxis {
*/ */
~sinqAxis(); ~sinqAxis();
/**
* @brief Delete the copy and copy assignment constructors, because this
* class should not be copied (it is tied to hardware!)
*/
sinqAxis(const sinqAxis &) = delete;
sinqAxis &operator=(const sinqAxis &) = delete;
/** /**
* @brief Check if a poll should be performed. If yes, call `forcedPoll`. * @brief Check if a poll should be performed. If yes, call `forcedPoll`.
* *
@@ -606,7 +621,7 @@ template <typename A, typename C>
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName, asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
int (C::*func)(), int *readValue, int (C::*func)(), int *readValue,
const char *callerFunctionName, int lineNumber, const char *callerFunctionName, int lineNumber,
size_t msgSize, TypeTag<int>) { size_t /*msgSize*/, TypeTag<int>) {
int indexValue = (controller->*func)(); int indexValue = (controller->*func)();
asynStatus status = asynStatus status =
controller->getIntegerParam(axis->axisNo(), indexValue, readValue); controller->getIntegerParam(axis->axisNo(), indexValue, readValue);
@@ -634,7 +649,7 @@ template <typename A, typename C>
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName, asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
int (C::*func)(), double *readValue, int (C::*func)(), double *readValue,
const char *callerFunctionName, int lineNumber, const char *callerFunctionName, int lineNumber,
size_t msgSize, TypeTag<double>) { size_t /*msgSize*/, TypeTag<double>) {
int indexValue = (controller->*func)(); int indexValue = (controller->*func)();
asynStatus status = asynStatus status =
controller->getDoubleParam(axis->axisNo(), indexValue, readValue); controller->getDoubleParam(axis->axisNo(), indexValue, readValue);
@@ -665,7 +680,7 @@ template <typename A, typename C>
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName, asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
int (C::*func)(), std::string *readValue, int (C::*func)(), std::string *readValue,
const char *callerFunctionName, int lineNumber, const char *callerFunctionName, int lineNumber,
size_t msgSize, TypeTag<std::string>) { size_t /*msgSize*/, TypeTag<std::string>) {
int indexValue = (controller->*func)(); int indexValue = (controller->*func)();
// Convert the pointer to a reference, since getStringParam expects the // Convert the pointer to a reference, since getStringParam expects the

View File

@@ -1,15 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
#include "sinqController.h" // The EPICS libaries do not follow -Weffc++
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "asynMotorController.h" #include "asynMotorController.h"
#include "asynOctetSyncIO.h" #include "asynOctetSyncIO.h"
#include "epicsExport.h" #include "epicsExport.h"
#include "iocsh.h" #include "iocsh.h"
#include "msgPrintControl.h"
#include "sinqAxis.h"
#include <deque>
#include <errlog.h> #include <errlog.h>
#include <initHooks.h> #include <initHooks.h>
#pragma GCC diagnostic pop
#include "msgPrintControl.h"
#include "sinqAxis.h"
#include "sinqController.h"
#include <deque>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@@ -92,6 +99,7 @@ struct sinqControllerImpl {
int motorAcclFromDriver; int motorAcclFromDriver;
int motorHighLimitFromDriver; int motorHighLimitFromDriver;
int motorLowLimitFromDriver; int motorLowLimitFromDriver;
int motorPositionDeadband;
int adaptivePolling; int adaptivePolling;
int encoderType; int encoderType;
}; };
@@ -111,23 +119,40 @@ sinqController::sinqController(const char *portName,
0, // No additional interfaces beyond those in base class 0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class 0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE, ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect 1, // autoconnect
0, 0) // Default priority and stack size 0, 0), // Default priority and stack size
{ pSinqC_(std::make_unique<sinqControllerImpl>((sinqControllerImpl){
.outstandingForcedFastPolls = 0,
.pasynOctetSyncIOipPort = nullptr,
.msgPrintC = msgPrintControl(),
.comTimeoutWindow = 3600,
.maxNumberTimeouts = 60,
.timeoutEvents = {},
.maxSubsequentTimeouts = 10,
.maxSubsequentTimeoutsExceeded = false,
.motorMessageText = 0,
.motorReset = 0,
.motorEnable = 0,
.motorEnableRBV = 0,
.motorCanDisable = 0,
.motorEnableMovWatchdog = 0,
.motorCanSetSpeed = 0,
.motorLimitsOffset = 0,
.motorForceStop = 0,
.motorConnected = 0,
.motorVeloFromDriver = 0,
.motorVbasFromDriver = 0,
.motorVmaxFromDriver = 0,
.motorAcclFromDriver = 0,
.motorHighLimitFromDriver = 0,
.motorLowLimitFromDriver = 0,
.motorPositionDeadband = 0,
.adaptivePolling = 0,
.encoderType = 0,
})) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
// The paramLib indices are populated with the calls to createParam
pSinqC_ = std::make_unique<sinqControllerImpl>(
(sinqControllerImpl){.outstandingForcedFastPolls = 0,
.pasynOctetSyncIOipPort = nullptr,
.msgPrintC = msgPrintControl(),
.comTimeoutWindow = 3600,
.maxNumberTimeouts = 60,
.timeoutEvents = {},
.maxSubsequentTimeouts = 10,
.maxSubsequentTimeoutsExceeded = false});
// Store the poll period information. The poller itself will be started // Store the poll period information. The poller itself will be started
// later (after the IOC is running in epicsInithookFunction) // later (after the IOC is running in epicsInithookFunction)
movingPollPeriod_ = movingPollPeriod; movingPollPeriod_ = movingPollPeriod;
@@ -267,6 +292,17 @@ sinqController::sinqController(const char *portName,
exit(-1); exit(-1);
} }
status = createParam("MOTOR_POSITION_DEADBAND", asynParamFloat64,
&pSinqC_->motorPositionDeadband);
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);
}
status = createParam("MOTOR_ENABLE_MOV_WATCHDOG", asynParamInt32, status = createParam("MOTOR_ENABLE_MOV_WATCHDOG", asynParamInt32,
&pSinqC_->motorEnableMovWatchdog); &pSinqC_->motorEnableMovWatchdog);
if (status != asynSuccess) { if (status != asynSuccess) {
@@ -699,6 +735,9 @@ int sinqController::motorHighLimitFromDriver() {
int sinqController::motorLowLimitFromDriver() { int sinqController::motorLowLimitFromDriver() {
return pSinqC_->motorLowLimitFromDriver; return pSinqC_->motorLowLimitFromDriver;
} }
int sinqController::motorPositionDeadband() {
return pSinqC_->motorPositionDeadband;
}
int sinqController::adaptivePolling() { return pSinqC_->adaptivePolling; } int sinqController::adaptivePolling() { return pSinqC_->adaptivePolling; }
int sinqController::encoderType() { return pSinqC_->encoderType; } int sinqController::encoderType() { return pSinqC_->encoderType; }
@@ -809,7 +848,8 @@ static const iocshArg *const setThresholdComTimeoutArgs[] = {
&setThresholdComTimeoutArg0, &setThresholdComTimeoutArg1, &setThresholdComTimeoutArg0, &setThresholdComTimeoutArg1,
&setThresholdComTimeoutArg2}; &setThresholdComTimeoutArg2};
static const iocshFuncDef setThresholdComTimeoutDef = { static const iocshFuncDef setThresholdComTimeoutDef = {
"setThresholdComTimeout", 3, setThresholdComTimeoutArgs}; "setThresholdComTimeout", 3, setThresholdComTimeoutArgs,
"Set the communication timeout threshold in seconds"};
static void setThresholdComTimeoutCallFunc(const iocshArgBuf *args) { static void setThresholdComTimeoutCallFunc(const iocshArgBuf *args) {
setThresholdComTimeout(args[0].sval, args[1].ival, args[2].ival); setThresholdComTimeout(args[0].sval, args[1].ival, args[2].ival);
@@ -870,7 +910,9 @@ static const iocshArg SetMaxSubsequentTimeoutsArg1 = {
static const iocshArg *const SetMaxSubsequentTimeoutsArgs[] = { static const iocshArg *const SetMaxSubsequentTimeoutsArgs[] = {
&SetMaxSubsequentTimeoutsArg0, &SetMaxSubsequentTimeoutsArg1}; &SetMaxSubsequentTimeoutsArg0, &SetMaxSubsequentTimeoutsArg1};
static const iocshFuncDef setMaxSubsequentTimeoutsDef = { static const iocshFuncDef setMaxSubsequentTimeoutsDef = {
"setMaxSubsequentTimeouts", 2, SetMaxSubsequentTimeoutsArgs}; "setMaxSubsequentTimeouts", 2, SetMaxSubsequentTimeoutsArgs,
"Set the maximum number of subsequent timeouts before the user receives an "
"error message"};
static void setMaxSubsequentTimeoutsCallFunc(const iocshArgBuf *args) { static void setMaxSubsequentTimeoutsCallFunc(const iocshArgBuf *args) {
setMaxSubsequentTimeouts(args[0].sval, args[1].ival); setMaxSubsequentTimeouts(args[0].sval, args[1].ival);
} }
@@ -924,13 +966,15 @@ asynStatus setForcedFastPolls(const char *portName, int forcedFastPolls) {
static const iocshArg SetForcedFastPollsArg0 = {"Controller name (e.g. mcu1)", static const iocshArg SetForcedFastPollsArg0 = {"Controller name (e.g. mcu1)",
iocshArgString}; iocshArgString};
static const iocshArg SetForcedFastPollsArg1 = { static const iocshArg SetForcedFastPollsArg1 = {
"Number of fast polls after \"waking\" the poller (e.g. after issueing a " "Number of fast polls after \"waking\" the poller (e.g. after issuing a "
"move command).", "move command).",
iocshArgInt}; iocshArgInt};
static const iocshArg *const SetForcedFastPollsArgs[] = { static const iocshArg *const SetForcedFastPollsArgs[] = {
&SetForcedFastPollsArg0, &SetForcedFastPollsArg1}; &SetForcedFastPollsArg0, &SetForcedFastPollsArg1};
static const iocshFuncDef setForcedFastPollsDef = {"setForcedFastPolls", 2, static const iocshFuncDef setForcedFastPollsDef = {
SetForcedFastPollsArgs}; "setForcedFastPolls", 2, SetForcedFastPollsArgs,
"Set the number of fast polls after \"waking\" the poller (e.g. after "
"issuing a move command)."};
static void setForcedFastPollsCallFunc(const iocshArgBuf *args) { static void setForcedFastPollsCallFunc(const iocshArgBuf *args) {
setForcedFastPolls(args[0].sval, args[1].ival); setForcedFastPolls(args[0].sval, args[1].ival);
} }

View File

@@ -9,10 +9,18 @@ Stefan Mathis, November 2024
#ifndef sinqController_H #ifndef sinqController_H
#define sinqController_H #define sinqController_H
// The EPICS libaries do not follow -Weffc++
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "asynMotorController.h" #include "asynMotorController.h"
#include "msgPrintControl.h" #include "msgPrintControl.h"
#include <initHooks.h> #include <initHooks.h>
#include <macros.h> #include <macros.h>
#pragma GCC diagnostic pop
#include <memory> #include <memory>
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER" #define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
@@ -58,6 +66,13 @@ class HIDDEN sinqController : public asynMotorController {
*/ */
virtual ~sinqController(void); virtual ~sinqController(void);
/**
* @brief Delete the copy and copy assignment constructors, because this
* class should not be copied (it is tied to hardware!)
*/
sinqController(const sinqController &) = delete;
sinqController &operator=(const sinqController &) = delete;
/** /**
* @brief Overloaded function of asynMotorController * @brief Overloaded function of asynMotorController
* *
@@ -315,6 +330,7 @@ class HIDDEN sinqController : public asynMotorController {
int motorAcclFromDriver(); int motorAcclFromDriver();
int motorHighLimitFromDriver(); int motorHighLimitFromDriver();
int motorLowLimitFromDriver(); int motorLowLimitFromDriver();
int motorPositionDeadband();
int adaptivePolling(); int adaptivePolling();
int encoderType(); int encoderType();