Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
55a9fe6f3e | |||
e618b39687 | |||
41dfd1de5a | |||
07cab3ac2a | |||
e194736206 | |||
30af284f5d | |||
6069aa9194 | |||
c475beee66 | |||
b1fe452ed6 | |||
d395c7bbb7 | |||
a6f2890c76 | |||
fef61bc804 | |||
3d984f26bc | |||
2f8ae23d57 | |||
603b3e77af | |||
31ff26cb78 | |||
43df40aaea | |||
bdefc6090d | |||
c2eca33ce8 | |||
87980e403c | |||
b95e782ea8 | |||
cd7cc75eb7 | |||
83aa437b6b | |||
275672aaef | |||
61c5ec749e | |||
1cf4b9ab25 |
@ -20,6 +20,8 @@ void msgPrintControlKey::format(char *buffer, size_t bufferSize) {
|
|||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
|
msgPrintControl::~msgPrintControl() = default;
|
||||||
|
|
||||||
bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
||||||
asynUser *pasynUser) {
|
asynUser *pasynUser) {
|
||||||
|
|
||||||
|
@ -84,6 +84,12 @@ template <> struct hash<msgPrintControlKey> {
|
|||||||
*/
|
*/
|
||||||
class msgPrintControl {
|
class msgPrintControl {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Destroy the msgPrintControl object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~msgPrintControl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the error message associated with "key" has been printed
|
* @brief Checks if the error message associated with "key" has been printed
|
||||||
* more than `this->maxRepetitions_` times in a row. If yes, returns false,
|
* more than `this->maxRepetitions_` times in a row. If yes, returns false,
|
||||||
|
280
src/sinqAxis.cpp
280
src/sinqAxis.cpp
@ -3,199 +3,54 @@
|
|||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
#include "epicsExport.h"
|
#include "epicsExport.h"
|
||||||
#include "iocsh.h"
|
#include "iocsh.h"
|
||||||
|
#include "msgPrintControl.h"
|
||||||
#include "sinqController.h"
|
#include "sinqController.h"
|
||||||
|
#include <epicsTime.h>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// Generic fallback - if the compiler tries to compile this function, it fails.
|
#define getControllerMethod pController
|
||||||
template <typename T>
|
|
||||||
asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), T writeValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
static_assert(
|
|
||||||
sizeof(T) == 0,
|
|
||||||
"no specialization of setAxisParam exists for the given type");
|
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
struct sinqAxisImpl {
|
||||||
asynStatus setAxisParam<int>(sinqAxis *axis, const char *indexName,
|
// Internal variables used in the movement timeout watchdog
|
||||||
int (sinqController::*func)(), int writeValue,
|
time_t expectedArrivalTime;
|
||||||
const char *callerFunctionName, int lineNumber) {
|
time_t offsetMovTimeout;
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->setIntegerParam(indexValue, writeValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
double scaleMovTimeout;
|
||||||
asynStatus setAxisParam<bool>(sinqAxis *axis, const char *indexName,
|
bool watchdogMovActive;
|
||||||
int (sinqController::*func)(), bool writeValue,
|
// Store the motor target position for the movement time calculation
|
||||||
const char *callerFunctionName, int lineNumber) {
|
double targetPosition;
|
||||||
return setAxisParam(axis, indexName, func, static_cast<int>(writeValue),
|
|
||||||
callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
bool wasMoving;
|
||||||
asynStatus
|
|
||||||
setAxisParam<double>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), double writeValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->setDoubleParam(indexValue, writeValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
/*
|
||||||
asynStatus setAxisParam<char *>(sinqAxis *axis, const char *indexName,
|
Store the time since the last poll
|
||||||
int (sinqController::*func)(), char *writeValue,
|
*/
|
||||||
const char *callerFunctionName,
|
epicsTimeStamp lastPollTime;
|
||||||
int lineNumber) {
|
};
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->setStringParam(indexValue, writeValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus setAxisParam<const char *>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(),
|
|
||||||
const char *writeValue,
|
|
||||||
const char *callerFunctionName,
|
|
||||||
int lineNumber) {
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->setStringParam(indexValue, writeValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic fallback - if the compiler tries to compile this function, it fails.
|
|
||||||
template <typename T>
|
|
||||||
asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), T *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
static_assert(
|
|
||||||
sizeof(T) == 0,
|
|
||||||
"no specialization of getAxisParam exists for the given type");
|
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus getAxisParam<int>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), int *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->pController()->getIntegerParam(
|
|
||||||
axis->axisNo(), indexValue, readValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus getAxisParam<bool>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), bool *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
return getAxisParam(axis, indexName, func, (int *)readValue,
|
|
||||||
callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus
|
|
||||||
getAxisParam<double>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), double *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->pController()->getDoubleParam(
|
|
||||||
axis->axisNo(), indexValue, readValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus getAxisParam<char>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), char *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
|
|
||||||
int maxChars = 200;
|
|
||||||
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
asynStatus status = axis->pController()->getStringParam(
|
|
||||||
axis->axisNo(), indexValue, maxChars, readValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t N>
|
|
||||||
asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), char (&readValue)[N],
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
// Decay the array to char*
|
|
||||||
return getAxisParam<char>(axis, indexName, func,
|
|
||||||
static_cast<char *>(readValue),
|
|
||||||
callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
asynStatus
|
|
||||||
getAxisParam<std::string>(sinqAxis *axis, const char *indexName,
|
|
||||||
int (sinqController::*func)(), std::string *readValue,
|
|
||||||
const char *callerFunctionName, int lineNumber) {
|
|
||||||
int indexValue = (axis->pController()->*func)();
|
|
||||||
|
|
||||||
// Convert the pointer to a reference, since getStringParam expects the
|
|
||||||
// latter.
|
|
||||||
std::string &rReadValue = *readValue;
|
|
||||||
|
|
||||||
asynStatus status = axis->pController()->getStringParam(
|
|
||||||
axis->axisNo(), indexValue, rReadValue);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return axis->pController()->paramLibAccessFailed(
|
|
||||||
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
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) {
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
watchdogMovActive_ = false;
|
epicsTimeStamp lastPollTime;
|
||||||
scaleMovTimeout_ = 2.0;
|
epicsTimeGetCurrent(&lastPollTime);
|
||||||
offsetMovTimeout_ = 30;
|
|
||||||
targetPosition_ = 0.0;
|
|
||||||
wasMoving_ = false;
|
|
||||||
|
|
||||||
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
|
/*
|
||||||
// running even though the configuration is incorrect. When failing this
|
This check is also done in asynMotorAxis, but there the IOC continues
|
||||||
// check, the IOC is stopped, since this is definitely a configuration
|
running even though the configuration is incorrect. When failing this check,
|
||||||
// problem.
|
the IOC is stopped, since this is definitely a configuration problem.
|
||||||
|
*/
|
||||||
if ((axisNo < 0) || (axisNo >= pC->numAxes())) {
|
if ((axisNo < 0) || (axisNo >= pC->numAxes())) {
|
||||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
@ -313,6 +168,8 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sinqAxis::~sinqAxis() = default;
|
||||||
|
|
||||||
asynStatus sinqAxis::poll(bool *moving) {
|
asynStatus sinqAxis::poll(bool *moving) {
|
||||||
|
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
@ -346,10 +203,10 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
*/
|
*/
|
||||||
if (adaptivePolling != 0 && pC_->outstandingForcedFastPolls() == 0) {
|
if (adaptivePolling != 0 && pC_->outstandingForcedFastPolls() == 0) {
|
||||||
// Motor wasn't moving during the last poll
|
// Motor wasn't moving during the last poll
|
||||||
if (!wasMoving_) {
|
if (!pSinqA_->wasMoving) {
|
||||||
|
|
||||||
// Add the idle poll period
|
// Add the idle poll period
|
||||||
epicsTimeStamp earliestTimeNextPoll = lastPollTime_;
|
epicsTimeStamp earliestTimeNextPoll = pSinqA_->lastPollTime;
|
||||||
epicsTimeAddSeconds(&earliestTimeNextPoll, pC_->idlePollPeriod());
|
epicsTimeAddSeconds(&earliestTimeNextPoll, pC_->idlePollPeriod());
|
||||||
|
|
||||||
if (epicsTimeLessThanEqual(&earliestTimeNextPoll, &ts) == 0) {
|
if (epicsTimeLessThanEqual(&earliestTimeNextPoll, &ts) == 0) {
|
||||||
@ -360,7 +217,7 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the start time of the last poll
|
// Update the start time of the last poll
|
||||||
lastPollTime_ = ts;
|
pSinqA_->lastPollTime = ts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the "motorMessageText" record currently contains an error message, it
|
If the "motorMessageText" record currently contains an error message, it
|
||||||
@ -411,7 +268,7 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
assumed that the homing procedure is done.
|
assumed that the homing procedure is done.
|
||||||
*/
|
*/
|
||||||
getAxisParamChecked(this, motorStatusHome, &homing);
|
getAxisParamChecked(this, motorStatusHome, &homing);
|
||||||
if (homing == 1 && !(*moving) && wasMoving_) {
|
if (homing == 1 && !(*moving) && pSinqA_->wasMoving) {
|
||||||
setAxisParamChecked(this, motorStatusHome, false);
|
setAxisParamChecked(this, motorStatusHome, false);
|
||||||
setAxisParamChecked(this, motorStatusHomed, true);
|
setAxisParamChecked(this, motorStatusHomed, true);
|
||||||
setAxisParamChecked(this, motorStatusAtHome, true);
|
setAxisParamChecked(this, motorStatusAtHome, true);
|
||||||
@ -419,7 +276,7 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
|
|
||||||
// Update the wasMoving status
|
// Update the wasMoving status
|
||||||
if (pC_->outstandingForcedFastPolls() == 0) {
|
if (pC_->outstandingForcedFastPolls() == 0) {
|
||||||
wasMoving_ = *moving;
|
pSinqA_->wasMoving = *moving;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check and update the watchdog
|
// Check and update the watchdog
|
||||||
@ -467,7 +324,7 @@ asynStatus sinqAxis::move(double position, int relative, double minVelocity,
|
|||||||
|
|
||||||
// Store the target position internally
|
// Store the target position internally
|
||||||
getAxisParamChecked(this, motorRecResolution, &motorRecRes);
|
getAxisParamChecked(this, motorRecResolution, &motorRecRes);
|
||||||
targetPosition_ = position * motorRecRes;
|
pSinqA_->targetPosition = position * motorRecRes;
|
||||||
|
|
||||||
status = doMove(position, relative, minVelocity, maxVelocity, acceleration);
|
status = doMove(position, relative, minVelocity, maxVelocity, acceleration);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -485,7 +342,7 @@ asynStatus sinqAxis::move(double position, int relative, double minVelocity,
|
|||||||
setAxisParamChecked(this, motorStatusAtHome, false);
|
setAxisParamChecked(this, motorStatusAtHome, false);
|
||||||
|
|
||||||
// Needed for adaptive polling
|
// Needed for adaptive polling
|
||||||
wasMoving_ = true;
|
pSinqA_->wasMoving = true;
|
||||||
|
|
||||||
return pC_->callParamCallbacks();
|
return pC_->callParamCallbacks();
|
||||||
}
|
}
|
||||||
@ -507,7 +364,7 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
|
|||||||
setAxisParamChecked(this, motorStatusHome, true);
|
setAxisParamChecked(this, motorStatusHome, true);
|
||||||
setAxisParamChecked(this, motorStatusHomed, false);
|
setAxisParamChecked(this, motorStatusHomed, false);
|
||||||
setAxisParamChecked(this, motorStatusAtHome, false);
|
setAxisParamChecked(this, motorStatusAtHome, false);
|
||||||
wasMoving_ = true;
|
pSinqA_->wasMoving = true;
|
||||||
|
|
||||||
status = assertConnected();
|
status = assertConnected();
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -543,15 +400,7 @@ asynStatus sinqAxis::reset() {
|
|||||||
|
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess) {
|
||||||
// Perform some fast polls
|
// Perform some fast polls
|
||||||
pC_->lock();
|
pC_->wakeupPoller();
|
||||||
bool moving = false;
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
epicsThreadSleep(pC_->movingPollPeriod());
|
|
||||||
if (poll(&moving) == asynSuccess) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pC_->unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status = assertConnected();
|
status = assertConnected();
|
||||||
@ -689,7 +538,7 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
time_t timeAccel = 0;
|
time_t timeAccel = 0;
|
||||||
|
|
||||||
// Activate the watchdog
|
// Activate the watchdog
|
||||||
watchdogMovActive_ = true;
|
pSinqA_->watchdogMovActive = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE: This function must not be called in the constructor (e.g. in order
|
NOTE: This function must not be called in the constructor (e.g. in order
|
||||||
@ -725,8 +574,9 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
motorVelocity = motorVelocityRec * motorRecRes;
|
motorVelocity = motorVelocityRec * motorRecRes;
|
||||||
if (pl_status == asynSuccess) {
|
if (pl_status == asynSuccess) {
|
||||||
|
|
||||||
timeContSpeed = std::ceil(
|
timeContSpeed =
|
||||||
std::fabs(targetPosition_ - motorPos) / motorVelocity);
|
std::ceil(std::fabs(pSinqA_->targetPosition - motorPos) /
|
||||||
|
motorVelocity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,11 +592,11 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the expected arrival time
|
// Calculate the expected arrival time
|
||||||
expectedArrivalTime_ =
|
pSinqA_->expectedArrivalTime =
|
||||||
time(NULL) + offsetMovTimeout_ +
|
time(NULL) + pSinqA_->offsetMovTimeout +
|
||||||
scaleMovTimeout_ * (timeContSpeed + 2 * timeAccel);
|
pSinqA_->scaleMovTimeout * (timeContSpeed + 2 * timeAccel);
|
||||||
} else {
|
} else {
|
||||||
watchdogMovActive_ = false;
|
pSinqA_->watchdogMovActive = false;
|
||||||
}
|
}
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
@ -757,8 +607,8 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
getAxisParamChecked(this, motorEnableMovWatchdog, &enableMovWatchdog);
|
getAxisParamChecked(this, motorEnableMovWatchdog, &enableMovWatchdog);
|
||||||
|
|
||||||
// Not moving or watchdog not active / enabled
|
// Not moving or watchdog not active / enabled
|
||||||
if (enableMovWatchdog == 0 || !moving || !watchdogMovActive_) {
|
if (enableMovWatchdog == 0 || !moving || !pSinqA_->watchdogMovActive) {
|
||||||
watchdogMovActive_ = false;
|
pSinqA_->watchdogMovActive = false;
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,7 +618,7 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
// Check if the expected time of arrival has been exceeded.
|
// Check if the expected time of arrival has been exceeded.
|
||||||
if (expectedArrivalTime_ < time(NULL)) {
|
if (pSinqA_->expectedArrivalTime < time(NULL)) {
|
||||||
// Check the watchdog
|
// Check the watchdog
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(key, true,
|
if (pC_->getMsgPrintControl().shouldBePrinted(key, true,
|
||||||
pC_->pasynUser())) {
|
pC_->pasynUser())) {
|
||||||
@ -776,7 +626,7 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
"Controller \"%s\", axis %d => %s, line %d:\nExceeded "
|
"Controller \"%s\", axis %d => %s, line %d:\nExceeded "
|
||||||
"expected arrival time %ld (current time is %ld).\n",
|
"expected arrival time %ld (current time is %ld).\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
expectedArrivalTime_, time(NULL));
|
pSinqA_->expectedArrivalTime, time(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
setAxisParamChecked(
|
setAxisParamChecked(
|
||||||
@ -791,6 +641,26 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus sinqAxis::setOffsetMovTimeout(time_t offsetMovTimeout) {
|
||||||
|
pSinqA_->offsetMovTimeout = offsetMovTimeout;
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus sinqAxis::setScaleMovTimeout(time_t scaleMovTimeout) {
|
||||||
|
pSinqA_->scaleMovTimeout = scaleMovTimeout;
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sinqAxis::wasMoving() { return pSinqA_->wasMoving; }
|
||||||
|
|
||||||
|
void sinqAxis::setWasMoving(bool wasMoving) { pSinqA_->wasMoving = wasMoving; }
|
||||||
|
|
||||||
|
double sinqAxis::targetPosition() { return pSinqA_->targetPosition; }
|
||||||
|
|
||||||
|
void sinqAxis::setTargetPosition(double targetPosition) {
|
||||||
|
pSinqA_->targetPosition = targetPosition;
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// IOC shell functions
|
// IOC shell functions
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
369
src/sinqAxis.h
369
src/sinqAxis.h
@ -9,9 +9,11 @@ Stefan Mathis, November 2024
|
|||||||
#ifndef sinqAxis_H
|
#ifndef sinqAxis_H
|
||||||
#define sinqAxis_H
|
#define sinqAxis_H
|
||||||
#include "asynMotorAxis.h"
|
#include "asynMotorAxis.h"
|
||||||
#include <epicsTime.h>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
struct sinqAxisImpl;
|
||||||
|
|
||||||
class epicsShareClass sinqAxis : public asynMotorAxis {
|
class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -22,6 +24,13 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
*/
|
*/
|
||||||
sinqAxis(class sinqController *pC_, int axisNo);
|
sinqAxis(class sinqController *pC_, int axisNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the sinqAxis object
|
||||||
|
*
|
||||||
|
* This destructor is necessary in order to use the PIMPL idiom.
|
||||||
|
*/
|
||||||
|
~sinqAxis();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Perform some standardized operations before and after the concrete
|
* @brief Perform some standardized operations before and after the concrete
|
||||||
`doPoll` implementation.
|
`doPoll` implementation.
|
||||||
@ -49,7 +58,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
the parameter library operation fails (in that case, returns the status of
|
the parameter library operation fails (in that case, returns the status of
|
||||||
the failed operation.
|
the failed operation.
|
||||||
*/
|
*/
|
||||||
asynStatus poll(bool *moving);
|
virtual asynStatus poll(bool *moving);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the "proper", device-specific poll method. This
|
* @brief Implementation of the "proper", device-specific poll method. This
|
||||||
@ -79,7 +88,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
the parameter library operation fails (in that case, returns the failed
|
the parameter library operation fails (in that case, returns the failed
|
||||||
operation status).
|
operation status).
|
||||||
*/
|
*/
|
||||||
asynStatus move(double position, int relative, double minVelocity,
|
virtual asynStatus move(double position, int relative, double minVelocity,
|
||||||
double maxVelocity, double acceleration);
|
double maxVelocity, double acceleration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,8 +152,8 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
the parameter library operation fails (in that case, returns the failed
|
the parameter library operation fails (in that case, returns the failed
|
||||||
operation status).
|
operation status).
|
||||||
*/
|
*/
|
||||||
asynStatus home(double minVelocity, double maxVelocity, double acceleration,
|
virtual asynStatus home(double minVelocity, double maxVelocity,
|
||||||
int forwards);
|
double acceleration, int forwards);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the "proper", device-specific home method. This
|
* @brief Implementation of the "proper", device-specific home method. This
|
||||||
@ -240,7 +249,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
used to get the values for the timeout calculation failed, return that
|
used to get the values for the timeout calculation failed, return that
|
||||||
status, otherwise return asynSuccess.
|
status, otherwise return asynSuccess.
|
||||||
*/
|
*/
|
||||||
asynStatus startMovTimeoutWatchdog();
|
virtual asynStatus startMovTimeoutWatchdog();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if the watchdog timed out
|
* @brief Check if the watchdog timed out
|
||||||
@ -274,7 +283,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
* @return asynStatus Return asynError, if the watchdog timed out,
|
* @return asynStatus Return asynError, if the watchdog timed out,
|
||||||
and asynSuccess otherwise.
|
and asynSuccess otherwise.
|
||||||
*/
|
*/
|
||||||
asynStatus checkMovTimeoutWatchdog(bool moving);
|
virtual asynStatus checkMovTimeoutWatchdog(bool moving);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable / disable the watchdog. Also available in the IOC shell
|
* @brief Enable / disable the watchdog. Also available in the IOC shell
|
||||||
@ -297,10 +306,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
* @param offsetMovTimeout Offset (in seconds)
|
* @param offsetMovTimeout Offset (in seconds)
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
virtual asynStatus setOffsetMovTimeout(time_t offsetMovTimeout) {
|
virtual asynStatus setOffsetMovTimeout(time_t offsetMovTimeout);
|
||||||
offsetMovTimeout_ = offsetMovTimeout;
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the scaleMovTimeout. Also available in the IOC shell
|
* @brief Set the scaleMovTimeout. Also available in the IOC shell
|
||||||
@ -311,10 +317,7 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
* @param scaleMovTimeout Scaling factor (in seconds)
|
* @param scaleMovTimeout Scaling factor (in seconds)
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
virtual asynStatus setScaleMovTimeout(time_t scaleMovTimeout) {
|
virtual asynStatus setScaleMovTimeout(time_t scaleMovTimeout);
|
||||||
scaleMovTimeout_ = scaleMovTimeout;
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the axis number of this axis
|
* @brief Return the axis number of this axis
|
||||||
@ -362,34 +365,139 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
asynStatus assertConnected();
|
asynStatus assertConnected();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a pointer to the axis controller
|
* @brief Return a pointer to the axis controller.
|
||||||
|
*
|
||||||
|
* This function should be overriden in derived classes using the `override`
|
||||||
|
* keyword so the macros `getAxisParamChecked` and `setAxisParamChecked`
|
||||||
|
* work correctly:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* class mySpecialAxis : public sinqAxis {
|
||||||
|
public:
|
||||||
|
mySpecialController* getControllerMethod() override {
|
||||||
|
return mySpecialControllerPtr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
sinqController *pController() { return pC_; };
|
virtual sinqController *pController() { return pC_; };
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
// Internal variables used in the movement timeout watchdog
|
* @brief Returns true, if the axis was moving in the last poll cycle, and
|
||||||
time_t expectedArrivalTime_;
|
* false otherwise.
|
||||||
time_t offsetMovTimeout_;
|
*
|
||||||
|
* @return true
|
||||||
double scaleMovTimeout_;
|
* @return false
|
||||||
bool watchdogMovActive_;
|
|
||||||
// Store the motor target position for the movement time calculation
|
|
||||||
double targetPosition_;
|
|
||||||
|
|
||||||
bool wasMoving_;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Store the time since the last poll
|
|
||||||
*/
|
*/
|
||||||
epicsTimeStamp lastPollTime_;
|
bool wasMoving();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override the wasMoving flag (normally, it is automatically updated
|
||||||
|
* during each poll).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void setWasMoving(bool wasMoving);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read out the last received target position in engineering units.
|
||||||
|
*
|
||||||
|
* @return double
|
||||||
|
*/
|
||||||
|
double targetPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override the targetPosition value (normally, it is automatically
|
||||||
|
* updated at every call of the move() method).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void setTargetPosition(double targetPosition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<sinqAxisImpl> pSinqA_;
|
||||||
sinqController *pC_;
|
sinqController *pC_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Helper functions and definitions for the macro setAxisParamChecked
|
// Helper functions and definitions for the macro setAxisParamChecked
|
||||||
|
|
||||||
|
template <typename T> struct TypeTag {};
|
||||||
|
|
||||||
|
// Generic fallback - if the compiler tries to compile this function, it fails.
|
||||||
|
template <typename A, typename C, typename T>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), T writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<void>) {
|
||||||
|
static_assert(sizeof(T) == 0, "Unsupported type for setAxisParamImpl");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), int writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<int>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status = axis->setIntegerParam(indexValue, writeValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), bool writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<bool>) {
|
||||||
|
return setAxisParamImpl(axis, controller, indexName, func,
|
||||||
|
static_cast<int>(writeValue), callerFunctionName,
|
||||||
|
lineNumber, TypeTag<int>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), double writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<double>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status = axis->setDoubleParam(indexValue, writeValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), char *writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<char *>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status = axis->setStringParam(indexValue, writeValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus setAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), const char *writeValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
TypeTag<const char *>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status = axis->setStringParam(indexValue, writeValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to set an integer / double / string parameter for an
|
* @brief Helper function to set an integer / double / string parameter for an
|
||||||
* axis in the paramLib
|
* axis in the paramLib
|
||||||
@ -397,8 +505,11 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
* This function should not be used directly, but rather through its macro
|
* This function should not be used directly, but rather through its macro
|
||||||
* variant `setAxisParamChecked`.
|
* variant `setAxisParamChecked`.
|
||||||
*
|
*
|
||||||
|
* @tparam A
|
||||||
|
* @tparam C
|
||||||
* @tparam T
|
* @tparam T
|
||||||
* @param axis
|
* @param axis
|
||||||
|
* @param controller
|
||||||
* @param indexName
|
* @param indexName
|
||||||
* @param func
|
* @param func
|
||||||
* @param writeValue
|
* @param writeValue
|
||||||
@ -406,10 +517,13 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
* @param lineNumber
|
* @param lineNumber
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename A, typename C, typename T>
|
||||||
asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
asynStatus setAxisParam(A *axis, C *controller, const char *indexName,
|
||||||
int (sinqController::*func)(), T writeValue,
|
int (C::*func)(), T writeValue,
|
||||||
const char *callerFunctionName, int lineNumber);
|
const char *callerFunctionName, int lineNumber) {
|
||||||
|
return setAxisParamImpl(axis, controller, indexName, func, writeValue,
|
||||||
|
callerFunctionName, lineNumber, TypeTag<T>{});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Macro to set an paramLib parameter and error checking the return value
|
* @brief Macro to set an paramLib parameter and error checking the return value
|
||||||
@ -425,10 +539,10 @@ asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
* expands into the following code:
|
* expands into the following code:
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* int indexValue = axis->pController()->motorStatusProblem_();
|
* int indexValue = controller->motorStatusProblem_();
|
||||||
* asynStatus status = axis->setIntegerParam(indexValue, writeValue);
|
* asynStatus status = axis->setIntegerParam(indexValue, writeValue);
|
||||||
* if (status != asynSuccess) {
|
* if (status != asynSuccess) {
|
||||||
* return axis->pController()->paramLibAccessFailed(
|
* return controller->paramLibAccessFailed(
|
||||||
* status, "motorStatusProblem_", axis->axisNo(), __PRETTY_FUNCTION__,
|
* status, "motorStatusProblem_", axis->axisNo(), __PRETTY_FUNCTION__,
|
||||||
* __LINE__);
|
* __LINE__);
|
||||||
* }
|
* }
|
||||||
@ -437,23 +551,116 @@ asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
* ```
|
* ```
|
||||||
* =============================================================================
|
* =============================================================================
|
||||||
*/
|
*/
|
||||||
#define setAxisParamChecked(axis, indexGetterFunction, writeValue) \
|
#define setAxisParamChecked(axis, indexSetterFunction, writeValue) \
|
||||||
{ \
|
do { \
|
||||||
asynStatus setStatus = setAxisParam( \
|
auto *ctrlPtr = (axis)->pController(); \
|
||||||
axis, #indexGetterFunction, \
|
using ControllerType = \
|
||||||
&std::remove_pointer< \
|
typename std::remove_pointer<decltype(ctrlPtr)>::type; \
|
||||||
decltype(axis->pController())>::type::indexGetterFunction, \
|
asynStatus setStatus = \
|
||||||
|
setAxisParam(axis, ctrlPtr, #indexSetterFunction, \
|
||||||
|
static_cast<int (ControllerType::*)()>( \
|
||||||
|
&ControllerType::indexSetterFunction), \
|
||||||
writeValue, __PRETTY_FUNCTION__, __LINE__); \
|
writeValue, __PRETTY_FUNCTION__, __LINE__); \
|
||||||
if (setStatus != asynSuccess) { \
|
if (setStatus != asynSuccess) \
|
||||||
return setStatus; \
|
return setStatus; \
|
||||||
} \
|
} while (0)
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Helper functions and definitions for the macro getAxisParamChecked
|
// Helper functions and definitions for the macro getAxisParamChecked
|
||||||
|
|
||||||
|
// Generic fallback - if the compiler tries to compile this function, it fails.
|
||||||
|
template <typename A, typename C, typename T>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), T *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<void>) {
|
||||||
|
static_assert(
|
||||||
|
sizeof(T) == 0,
|
||||||
|
"no specialization of getAxisParam exists for the given type");
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), int *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<int>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status =
|
||||||
|
controller->getIntegerParam(axis->axisNo(), indexValue, readValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), bool *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<bool>) {
|
||||||
|
int readValueInt = 0;
|
||||||
|
asynStatus status = getAxisParamImpl(axis, controller, indexName, func,
|
||||||
|
&readValueInt, callerFunctionName,
|
||||||
|
lineNumber, msgSize, TypeTag<int>{});
|
||||||
|
*readValue = readValueInt != 0;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), double *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<double>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status =
|
||||||
|
controller->getDoubleParam(axis->axisNo(), indexValue, readValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), char *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<char>) {
|
||||||
|
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
asynStatus status = controller->getStringParam(axis->axisNo(), indexValue,
|
||||||
|
msgSize, readValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename C>
|
||||||
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), std::string *readValue,
|
||||||
|
const char *callerFunctionName, int lineNumber,
|
||||||
|
size_t msgSize, TypeTag<std::string>) {
|
||||||
|
int indexValue = (controller->*func)();
|
||||||
|
|
||||||
|
// Convert the pointer to a reference, since getStringParam expects the
|
||||||
|
// latter.
|
||||||
|
std::string &rReadValue = *readValue;
|
||||||
|
|
||||||
|
asynStatus status =
|
||||||
|
controller->getStringParam(axis->axisNo(), indexValue, rReadValue);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
return controller->paramLibAccessFailed(
|
||||||
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
||||||
|
}
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to set an integer / double / string parameter for an
|
* @brief Helper function to get an integer / double / string parameter for an
|
||||||
* axis in the paramLib
|
* axis in the paramLib
|
||||||
*
|
*
|
||||||
* This function should not be used directly, but rather through its macro
|
* This function should not be used directly, but rather through its macro
|
||||||
@ -461,6 +668,7 @@ asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
*
|
*
|
||||||
* @tparam T
|
* @tparam T
|
||||||
* @param axis
|
* @param axis
|
||||||
|
* @param controller
|
||||||
* @param indexName
|
* @param indexName
|
||||||
* @param func
|
* @param func
|
||||||
* @param readValue
|
* @param readValue
|
||||||
@ -471,17 +679,48 @@ asynStatus setAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
* to.
|
* to.
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename A, typename C, typename T>
|
||||||
asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
|
asynStatus getAxisParam(A *axis, C *controller, const char *indexName,
|
||||||
int (sinqController::*func)(), T *readValue,
|
int (C::*func)(), T *readValue,
|
||||||
const char *callerFunctionName, int lineNumber);
|
const char *callerFunctionName, int lineNumber) {
|
||||||
|
return getAxisParamImpl(axis, controller, indexName, func, readValue,
|
||||||
|
callerFunctionName, lineNumber,
|
||||||
|
controller->msgSize(), TypeTag<T>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper function to get a string parameter for an
|
||||||
|
* axis in the paramLib into a char array
|
||||||
|
*
|
||||||
|
* This function should not be used directly, but rather through its macro
|
||||||
|
* variant `getAxisParamChecked`. It is a specialized variant of the general
|
||||||
|
* getAxisParam defined above for char arrays.
|
||||||
|
*
|
||||||
|
* @tparam A
|
||||||
|
* @tparam C
|
||||||
|
* @tparam N
|
||||||
|
* @param axis
|
||||||
|
* @param controller
|
||||||
|
* @param indexName
|
||||||
|
* @param func
|
||||||
|
* @param callerFunctionName
|
||||||
|
* @param lineNumber
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
template <typename A, typename C, size_t N>
|
||||||
|
asynStatus getAxisParam(A *axis, C *controller, const char *indexName,
|
||||||
|
int (C::*func)(), char (*readValue)[N],
|
||||||
|
const char *callerFunctionName, int lineNumber) {
|
||||||
|
return getAxisParamImpl(axis, controller, indexName, func, *readValue,
|
||||||
|
callerFunctionName, lineNumber, N, TypeTag<char>{});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Macro to get an paramLib parameter and error checking the return value
|
* @brief Macro to get an paramLib parameter and error checking the return value
|
||||||
*
|
*
|
||||||
* This macro is a wrapper around `getIntegerParam` / `getDoubleParam` /
|
* This macro is a wrapper around `getIntegerParam` / `getDoubleParam` /
|
||||||
* `getStringParam` which checks if the operation was successfull. If it wasn't,
|
* `getStringParam` which checks if the operation was successfull. If it wasn't,
|
||||||
* it returns by calling the paramLibAccessFailed function.
|
* it returns by calling the paramLibAccessFailed function. In order
|
||||||
*
|
*
|
||||||
* For example, the following input:
|
* For example, the following input:
|
||||||
* ```
|
* ```
|
||||||
@ -490,10 +729,10 @@ asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
* expands into the following code:
|
* expands into the following code:
|
||||||
* ```
|
* ```
|
||||||
* {
|
* {
|
||||||
* int indexValue = axis->pController()->motorStatusProblem_();
|
* int indexValue = controller->motorStatusProblem_();
|
||||||
* asynStatus status = axis->pController()->getIntegerParam(axis->axisNo(),
|
* asynStatus status = controller->getIntegerParam(axis->axisNo(),
|
||||||
* indexValue, readValue); if (status != asynSuccess) { return
|
* indexValue, readValue); if (status != asynSuccess) { return
|
||||||
* axis->pController()->paramLibAccessFailed( status, "motorStatusProblem_",
|
* controller->paramLibAccessFailed( status, "motorStatusProblem_",
|
||||||
* axis->axisNo(), __PRETTY_FUNCTION__,
|
* axis->axisNo(), __PRETTY_FUNCTION__,
|
||||||
* __LINE__);
|
* __LINE__);
|
||||||
* }
|
* }
|
||||||
@ -503,15 +742,17 @@ asynStatus getAxisParam(sinqAxis *axis, const char *indexName,
|
|||||||
* =============================================================================
|
* =============================================================================
|
||||||
*/
|
*/
|
||||||
#define getAxisParamChecked(axis, indexGetterFunction, readValue) \
|
#define getAxisParamChecked(axis, indexGetterFunction, readValue) \
|
||||||
{ \
|
do { \
|
||||||
asynStatus getStatus = getAxisParam( \
|
auto *ctrlPtr = (axis)->pController(); \
|
||||||
axis, #indexGetterFunction, \
|
using ControllerType = \
|
||||||
&std::remove_pointer< \
|
typename std::remove_pointer<decltype(ctrlPtr)>::type; \
|
||||||
decltype(axis->pController())>::type::indexGetterFunction, \
|
asynStatus getStatus = \
|
||||||
|
getAxisParam(axis, ctrlPtr, #indexGetterFunction, \
|
||||||
|
static_cast<int (ControllerType::*)()>( \
|
||||||
|
&ControllerType::indexGetterFunction), \
|
||||||
readValue, __PRETTY_FUNCTION__, __LINE__); \
|
readValue, __PRETTY_FUNCTION__, __LINE__); \
|
||||||
if (getStatus != asynSuccess) { \
|
if (getStatus != asynSuccess) \
|
||||||
return getStatus; \
|
return getStatus; \
|
||||||
} \
|
} while (0)
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -5,8 +5,12 @@
|
|||||||
#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 "sinqAxis.h"
|
||||||
|
#include <deque>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
|
#include <initHooks.h>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -34,6 +38,65 @@ void sinqController::epicsInithookFunction(initHookState iState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sinqControllerImpl {
|
||||||
|
// Number of fast polls which still need to be performed before adaptive
|
||||||
|
// polling is active again.
|
||||||
|
int outstandingForcedFastPolls;
|
||||||
|
|
||||||
|
// Number of polls forced by wakeupPoller which are still
|
||||||
|
|
||||||
|
// Pointer to the port user which is specified by the char array
|
||||||
|
// `ipPortConfigName` in the constructor
|
||||||
|
asynUser *pasynOctetSyncIOipPort;
|
||||||
|
|
||||||
|
// Message print control
|
||||||
|
msgPrintControl msgPrintC;
|
||||||
|
|
||||||
|
// Internal variables used in the communication timeout frequency watchdog
|
||||||
|
time_t comTimeoutWindow; // Size of the time window
|
||||||
|
size_t maxNumberTimeouts; // Maximum acceptable number of events within the
|
||||||
|
// time window
|
||||||
|
|
||||||
|
// Deque holding the timestamps of the individual events
|
||||||
|
std::deque<time_t> timeoutEvents;
|
||||||
|
|
||||||
|
// Communicate a timeout to the user after it has happened this many times
|
||||||
|
// in a row
|
||||||
|
int maxSubsequentTimeouts;
|
||||||
|
bool maxSubsequentTimeoutsExceeded;
|
||||||
|
|
||||||
|
/*
|
||||||
|
These integers are indices to paramLib entries and are populated when the
|
||||||
|
parameters are created. See the documentation in db/sinqMotor.db.
|
||||||
|
*/
|
||||||
|
int motorMessageText;
|
||||||
|
int motorReset;
|
||||||
|
int motorEnable;
|
||||||
|
int motorEnableRBV;
|
||||||
|
int motorCanDisable;
|
||||||
|
int motorEnableMovWatchdog;
|
||||||
|
int motorCanSetSpeed;
|
||||||
|
int motorLimitsOffset;
|
||||||
|
int motorForceStop;
|
||||||
|
int motorConnected;
|
||||||
|
/*
|
||||||
|
These parameters are here to write values from the hardware to the EPICS
|
||||||
|
motor record. Using motorHighLimit_ / motorLowLimit_ does not work:
|
||||||
|
https://epics.anl.gov/tech-talk/2023/msg00576.php. Therefore, some
|
||||||
|
additional records are introduced which read from these parameters and write
|
||||||
|
into the motor record.
|
||||||
|
*/
|
||||||
|
int motorVeloFromDriver;
|
||||||
|
int motorVbasFromDriver;
|
||||||
|
int motorVmaxFromDriver;
|
||||||
|
int motorAcclFromDriver;
|
||||||
|
int motorHighLimitFromDriver;
|
||||||
|
int motorLowLimitFromDriver;
|
||||||
|
int adaptivePolling;
|
||||||
|
int encoderType;
|
||||||
|
};
|
||||||
|
#define NUM_SINQMOTOR_DRIVER_PARAMS 18
|
||||||
|
|
||||||
sinqController::sinqController(const char *portName,
|
sinqController::sinqController(const char *portName,
|
||||||
const char *ipPortConfigName, int numAxes,
|
const char *ipPortConfigName, int numAxes,
|
||||||
double movingPollPeriod, double idlePollPeriod,
|
double movingPollPeriod, double idlePollPeriod,
|
||||||
@ -49,28 +112,21 @@ sinqController::sinqController(const char *portName,
|
|||||||
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
|
||||||
msgPrintControl_() {
|
{
|
||||||
|
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
// Handle to the asynUser of the IP port asyn driver
|
// The paramLib indices are populated with the calls to createParam
|
||||||
pasynOctetSyncIOipPort_ = nullptr;
|
pSinqC_ = std::make_unique<sinqControllerImpl>(
|
||||||
|
(sinqControllerImpl){.outstandingForcedFastPolls = 0,
|
||||||
// Initial values for the average timeout mechanism, can be overwritten
|
.pasynOctetSyncIOipPort = nullptr,
|
||||||
// later by a FFI function
|
.msgPrintC = msgPrintControl(),
|
||||||
comTimeoutWindow_ = 3600; // seconds
|
.comTimeoutWindow = 3600,
|
||||||
|
.maxNumberTimeouts = 60,
|
||||||
// Number of timeouts which may occur before an error is forwarded to the
|
.timeoutEvents = {},
|
||||||
// user
|
.maxSubsequentTimeouts = 10,
|
||||||
maxNumberTimeouts_ = 60;
|
.maxSubsequentTimeoutsExceeded = false});
|
||||||
|
|
||||||
// Queue holding the timeout event timestamps
|
|
||||||
timeoutEvents_ = {};
|
|
||||||
|
|
||||||
// Inform the user after 10 timeouts in a row (default value)
|
|
||||||
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)
|
||||||
@ -83,9 +139,9 @@ sinqController::sinqController(const char *portName,
|
|||||||
We try to connect to the port via the port name provided by the constructor.
|
We try to connect to the port via the port name provided by the constructor.
|
||||||
If this fails, the function is terminated via exit.
|
If this fails, the function is terminated via exit.
|
||||||
*/
|
*/
|
||||||
pasynOctetSyncIO->connect(ipPortConfigName, 0, &pasynOctetSyncIOipPort_,
|
pasynOctetSyncIO->connect(ipPortConfigName, 0,
|
||||||
NULL);
|
&pSinqC_->pasynOctetSyncIOipPort, NULL);
|
||||||
if (status != asynSuccess || pasynOctetSyncIOipPort_ == nullptr) {
|
if (status != asynSuccess || pSinqC_->pasynOctetSyncIOipPort == nullptr) {
|
||||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
||||||
"connect to MCU controller).\n"
|
"connect to MCU controller).\n"
|
||||||
"Terminating IOC",
|
"Terminating IOC",
|
||||||
@ -98,8 +154,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
// MOTOR_MESSAGE_TEXT corresponds to the PV definition inside sinqMotor.db.
|
// MOTOR_MESSAGE_TEXT corresponds to the PV definition inside sinqMotor.db.
|
||||||
// This text is used to forward status messages to NICOS and in turn to the
|
// This text is used to forward status messages to NICOS and in turn to the
|
||||||
// user.
|
// user.
|
||||||
status =
|
status = createParam("MOTOR_MESSAGE_TEXT", asynParamOctet,
|
||||||
createParam("MOTOR_MESSAGE_TEXT", asynParamOctet, &motorMessageText_);
|
&pSinqC_->motorMessageText);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -109,7 +165,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_ENABLE", asynParamInt32, &motorEnable_);
|
status = createParam("MOTOR_ENABLE", asynParamInt32, &pSinqC_->motorEnable);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -119,7 +175,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_RESET", asynParamInt32, &motorReset_);
|
status = createParam("MOTOR_RESET", asynParamInt32, &pSinqC_->motorReset);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -129,7 +185,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_ENABLE_RBV", asynParamInt32, &motorEnableRBV_);
|
status = createParam("MOTOR_ENABLE_RBV", asynParamInt32,
|
||||||
|
&pSinqC_->motorEnableRBV);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -139,8 +196,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status =
|
status = createParam("MOTOR_CAN_DISABLE", asynParamInt32,
|
||||||
createParam("MOTOR_CAN_DISABLE", asynParamInt32, &motorCanDisable_);
|
&pSinqC_->motorCanDisable);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -150,8 +207,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status =
|
status = createParam("MOTOR_CAN_SET_SPEED", asynParamInt32,
|
||||||
createParam("MOTOR_CAN_SET_SPEED", asynParamInt32, &motorCanSetSpeed_);
|
&pSinqC_->motorCanSetSpeed);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -162,7 +219,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_LIMITS_OFFSET", asynParamFloat64,
|
status = createParam("MOTOR_LIMITS_OFFSET", asynParamFloat64,
|
||||||
&motorLimitsOffset_);
|
&pSinqC_->motorLimitsOffset);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -172,7 +229,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_CONNECTED", asynParamInt32, &motorConnected_);
|
status = createParam("MOTOR_CONNECTED", asynParamInt32,
|
||||||
|
&pSinqC_->motorConnected);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -188,7 +246,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
the declaration of motorHighLimitFromDriver_.
|
the declaration of motorHighLimitFromDriver_.
|
||||||
*/
|
*/
|
||||||
status = createParam("MOTOR_HIGH_LIMIT_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_HIGH_LIMIT_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorHighLimitFromDriver_);
|
&pSinqC_->motorHighLimitFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -199,7 +257,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_LOW_LIMIT_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_LOW_LIMIT_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorLowLimitFromDriver_);
|
&pSinqC_->motorLowLimitFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -210,7 +268,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_ENABLE_MOV_WATCHDOG", asynParamInt32,
|
status = createParam("MOTOR_ENABLE_MOV_WATCHDOG", asynParamInt32,
|
||||||
&motorEnableMovWatchdog_);
|
&pSinqC_->motorEnableMovWatchdog);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -221,7 +279,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_VELO_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_VELO_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorVeloFromDriver_);
|
&pSinqC_->motorVeloFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -232,7 +290,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_VBAS_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_VBAS_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorVbasFromDriver_);
|
&pSinqC_->motorVbasFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -243,7 +301,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_VMAX_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_VMAX_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorVmaxFromDriver_);
|
&pSinqC_->motorVmaxFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -254,7 +312,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_ACCL_FROM_DRIVER", asynParamFloat64,
|
status = createParam("MOTOR_ACCL_FROM_DRIVER", asynParamFloat64,
|
||||||
&motorAcclFromDriver_);
|
&pSinqC_->motorAcclFromDriver);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -264,7 +322,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("ADAPTIVE_POLLING", asynParamInt32, &adaptivePolling_);
|
status = createParam("ADAPTIVE_POLLING", asynParamInt32,
|
||||||
|
&pSinqC_->adaptivePolling);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -274,7 +333,7 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("ENCODER_TYPE", asynParamOctet, &encoderType_);
|
status = createParam("ENCODER_TYPE", asynParamOctet, &pSinqC_->encoderType);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -284,7 +343,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_FORCE_STOP", asynParamInt32, &motorForceStop_);
|
status = createParam("MOTOR_FORCE_STOP", asynParamInt32,
|
||||||
|
&pSinqC_->motorForceStop);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
"Controller \"%s\" => %s, line %d:\nFATAL ERROR (creating a "
|
||||||
@ -351,11 +411,11 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle custom PVs
|
// Handle custom PVs
|
||||||
if (function == motorEnable_) {
|
if (function == motorEnable()) {
|
||||||
return axis->enable(value != 0);
|
return axis->enable(value != 0);
|
||||||
} else if (function == motorReset_) {
|
} else if (function == motorReset()) {
|
||||||
return axis->reset();
|
return axis->reset();
|
||||||
} else if (function == motorForceStop_) {
|
} else if (function == motorForceStop()) {
|
||||||
return axis->stop(0.0);
|
return axis->stop(0.0);
|
||||||
} else {
|
} else {
|
||||||
return asynMotorController::writeInt32(pasynUser, value);
|
return asynMotorController::writeInt32(pasynUser, value);
|
||||||
@ -373,10 +433,10 @@ asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pasynUser->reason == motorEnableRBV_) {
|
if (pasynUser->reason == motorEnableRBV()) {
|
||||||
getAxisParamChecked(axis, motorEnableRBV, value);
|
getAxisParamChecked(axis, motorEnableRBV, value);
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
} else if (pasynUser->reason == motorCanDisable_) {
|
} else if (pasynUser->reason == motorCanDisable()) {
|
||||||
getAxisParamChecked(axis, motorCanDisable, value);
|
getAxisParamChecked(axis, motorCanDisable, value);
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
} else {
|
} else {
|
||||||
@ -389,7 +449,7 @@ asynStatus sinqController::couldNotParseResponse(const char *command,
|
|||||||
int axisNo,
|
int axisNo,
|
||||||
const char *functionName,
|
const char *functionName,
|
||||||
int line) {
|
int line) {
|
||||||
asynPrint(pasynOctetSyncIOipPort_, ASYN_TRACE_ERROR,
|
asynPrint(pasynOctetSyncIOipPort(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
|
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
|
||||||
"response \"%s\" for command \"%s\".\n",
|
"response \"%s\" for command \"%s\".\n",
|
||||||
portName, axisNo, functionName, line, response, command);
|
portName, axisNo, functionName, line, response, command);
|
||||||
@ -418,7 +478,7 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
|||||||
int line) {
|
int line) {
|
||||||
|
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pasynOctetSyncIOipPort_, ASYN_TRACE_ERROR,
|
asynPrint(pasynOctetSyncIOipPort(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\n Accessing the "
|
"Controller \"%s\", axis %d => %s, line %d:\n Accessing the "
|
||||||
"parameter library failed for parameter %s with error %s.\n",
|
"parameter library failed for parameter %s with error %s.\n",
|
||||||
portName, axisNo, functionName, line, parameter,
|
portName, axisNo, functionName, line, parameter,
|
||||||
@ -440,40 +500,42 @@ asynStatus sinqController::checkComTimeoutWatchdog(int axisNo,
|
|||||||
asynStatus paramLibStatus = asynSuccess;
|
asynStatus paramLibStatus = asynSuccess;
|
||||||
|
|
||||||
// Add a new timeout event to the queue
|
// Add a new timeout event to the queue
|
||||||
timeoutEvents_.push_back(time(NULL));
|
pSinqC_->timeoutEvents.push_back(time(NULL));
|
||||||
|
|
||||||
// Remove every event which is older than the time window from the deque
|
// Remove every event which is older than the time window from the deque
|
||||||
while (1) {
|
while (1) {
|
||||||
if (timeoutEvents_.empty()) {
|
if (pSinqC_->timeoutEvents.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (timeoutEvents_[0] + comTimeoutWindow_ <= time(NULL)) {
|
if (pSinqC_->timeoutEvents[0] + pSinqC_->comTimeoutWindow <=
|
||||||
timeoutEvents_.pop_front();
|
time(NULL)) {
|
||||||
|
pSinqC_->timeoutEvents.pop_front();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the maximum allowed number of events has been exceeded
|
// Check if the maximum allowed number of events has been exceeded
|
||||||
bool wantToPrint = timeoutEvents_.size() > maxNumberTimeouts_;
|
bool wantToPrint =
|
||||||
|
pSinqC_->timeoutEvents.size() > pSinqC_->maxNumberTimeouts;
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(portName, axisNo, __PRETTY_FUNCTION__,
|
if (pSinqC_->msgPrintC.shouldBePrinted(portName, axisNo,
|
||||||
__LINE__, wantToPrint,
|
__PRETTY_FUNCTION__, __LINE__,
|
||||||
pasynUserSelf)) {
|
wantToPrint, pasynUserSelf)) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
|
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
|
||||||
"communication timeouts in %ld "
|
"communication timeouts in %ld "
|
||||||
"seconds.%s\n",
|
"seconds.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
maxNumberTimeouts_, comTimeoutWindow_,
|
pSinqC_->maxNumberTimeouts, pSinqC_->comTimeoutWindow,
|
||||||
msgPrintControl_.getSuffix());
|
pSinqC_->msgPrintC.getSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wantToPrint) {
|
if (wantToPrint) {
|
||||||
snprintf(motorMessage, motorMessageSize,
|
snprintf(motorMessage, motorMessageSize,
|
||||||
"More than %ld communication timeouts in %ld seconds. Please "
|
"More than %ld communication timeouts in %ld seconds. Please "
|
||||||
"call the support.",
|
"call the support.",
|
||||||
maxNumberTimeouts_, comTimeoutWindow_);
|
pSinqC_->maxNumberTimeouts, pSinqC_->comTimeoutWindow);
|
||||||
|
|
||||||
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
||||||
if (paramLibStatus != asynSuccess) {
|
if (paramLibStatus != asynSuccess) {
|
||||||
@ -505,8 +567,8 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
|
|||||||
size_t motorMessageSize) {
|
size_t motorMessageSize) {
|
||||||
asynStatus paramLibStatus = asynSuccess;
|
asynStatus paramLibStatus = asynSuccess;
|
||||||
|
|
||||||
if (timeoutNo >= maxSubsequentTimeouts_) {
|
if (timeoutNo >= pSinqC_->maxSubsequentTimeouts) {
|
||||||
if (!maxSubsequentTimeoutsExceeded_) {
|
if (!pSinqC_->maxSubsequentTimeoutsExceeded) {
|
||||||
snprintf(motorMessage, motorMessageSize,
|
snprintf(motorMessage, motorMessageSize,
|
||||||
"Communication timeout between IOC and motor controller. "
|
"Communication timeout between IOC and motor controller. "
|
||||||
"Trying to reconnect ...");
|
"Trying to reconnect ...");
|
||||||
@ -516,7 +578,7 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
|
|||||||
"subsequent communication timeouts. Check whether the "
|
"subsequent communication timeouts. Check whether the "
|
||||||
"controller is still running and connected to the network.\n",
|
"controller is still running and connected to the network.\n",
|
||||||
this->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
this->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
maxSubsequentTimeouts_);
|
pSinqC_->maxSubsequentTimeouts);
|
||||||
|
|
||||||
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
||||||
if (paramLibStatus != asynSuccess) {
|
if (paramLibStatus != asynSuccess) {
|
||||||
@ -524,12 +586,12 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo, int axisNo,
|
|||||||
"motorStatusCommsError_", axisNo,
|
"motorStatusCommsError_", axisNo,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
maxSubsequentTimeoutsExceeded_ = true;
|
pSinqC_->maxSubsequentTimeoutsExceeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return asynError;
|
return asynError;
|
||||||
} else {
|
} else {
|
||||||
maxSubsequentTimeoutsExceeded_ = false;
|
pSinqC_->maxSubsequentTimeoutsExceeded = false;
|
||||||
motorMessage[0] = '\0';
|
motorMessage[0] = '\0';
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
@ -551,8 +613,8 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo,
|
|||||||
asynStatus sinqController::poll() {
|
asynStatus sinqController::poll() {
|
||||||
// Decrement the number of outstanding forced fast polls, if they are not
|
// Decrement the number of outstanding forced fast polls, if they are not
|
||||||
// zero
|
// zero
|
||||||
if (outstandingForcedFastPolls_ > 0) {
|
if (pSinqC_->outstandingForcedFastPolls > 0) {
|
||||||
outstandingForcedFastPolls_--;
|
pSinqC_->outstandingForcedFastPolls--;
|
||||||
}
|
}
|
||||||
return asynMotorController::poll();
|
return asynMotorController::poll();
|
||||||
}
|
}
|
||||||
@ -560,10 +622,86 @@ asynStatus sinqController::poll() {
|
|||||||
asynStatus sinqController::wakeupPoller() {
|
asynStatus sinqController::wakeupPoller() {
|
||||||
// + 1 since outstandingForcedFastPolls_ is reduced once at the start of
|
// + 1 since outstandingForcedFastPolls_ is reduced once at the start of
|
||||||
// a poll cycle
|
// a poll cycle
|
||||||
outstandingForcedFastPolls_ = forcedFastPolls_ + 1;
|
pSinqC_->outstandingForcedFastPolls = forcedFastPolls_ + 1;
|
||||||
return asynMotorController::wakeupPoller();
|
return asynMotorController::wakeupPoller();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus sinqController::setMaxSubsequentTimeouts(int maxSubsequentTimeouts) {
|
||||||
|
pSinqC_->maxSubsequentTimeouts = maxSubsequentTimeouts;
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sinqController::maxSubsequentTimeoutsExceeded() {
|
||||||
|
return pSinqC_->maxSubsequentTimeoutsExceeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a reference to the map used to control the maximum number of
|
||||||
|
* message repetitions. See the documentation of `printRepetitionWatchdog`
|
||||||
|
* in msgPrintControl.h for details.
|
||||||
|
*/
|
||||||
|
msgPrintControl &sinqController::getMsgPrintControl() {
|
||||||
|
return pSinqC_->msgPrintC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the number of outstanding forced fast polls currently
|
||||||
|
* specified
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int sinqController::outstandingForcedFastPolls() {
|
||||||
|
return pSinqC_->outstandingForcedFastPolls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the low-level octet (string) IP Port
|
||||||
|
*
|
||||||
|
* @return asynUser*
|
||||||
|
*/
|
||||||
|
asynUser *sinqController::pasynOctetSyncIOipPort() {
|
||||||
|
return pSinqC_->pasynOctetSyncIOipPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus sinqController::setThresholdComTimeout(time_t comTimeoutWindow,
|
||||||
|
size_t maxNumberTimeouts) {
|
||||||
|
pSinqC_->comTimeoutWindow = comTimeoutWindow;
|
||||||
|
pSinqC_->maxNumberTimeouts = maxNumberTimeouts;
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sinqController::motorMessageText() { return pSinqC_->motorMessageText; }
|
||||||
|
int sinqController::motorReset() { return pSinqC_->motorReset; }
|
||||||
|
int sinqController::motorEnable() { return pSinqC_->motorEnable; }
|
||||||
|
int sinqController::motorEnableRBV() { return pSinqC_->motorEnableRBV; }
|
||||||
|
int sinqController::motorCanDisable() { return pSinqC_->motorCanDisable; }
|
||||||
|
int sinqController::motorEnableMovWatchdog() {
|
||||||
|
return pSinqC_->motorEnableMovWatchdog;
|
||||||
|
}
|
||||||
|
int sinqController::motorCanSetSpeed() { return pSinqC_->motorCanSetSpeed; }
|
||||||
|
int sinqController::motorLimitsOffset() { return pSinqC_->motorLimitsOffset; }
|
||||||
|
int sinqController::motorForceStop() { return pSinqC_->motorForceStop; }
|
||||||
|
int sinqController::motorConnected() { return pSinqC_->motorConnected; }
|
||||||
|
int sinqController::motorVeloFromDriver() {
|
||||||
|
return pSinqC_->motorVeloFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::motorVbasFromDriver() {
|
||||||
|
return pSinqC_->motorVbasFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::motorVmaxFromDriver() {
|
||||||
|
return pSinqC_->motorVmaxFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::motorAcclFromDriver() {
|
||||||
|
return pSinqC_->motorAcclFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::motorHighLimitFromDriver() {
|
||||||
|
return pSinqC_->motorHighLimitFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::motorLowLimitFromDriver() {
|
||||||
|
return pSinqC_->motorLowLimitFromDriver;
|
||||||
|
}
|
||||||
|
int sinqController::adaptivePolling() { return pSinqC_->adaptivePolling; }
|
||||||
|
int sinqController::encoderType() { return pSinqC_->encoderType; }
|
||||||
|
|
||||||
// Static pointers (valid for the entire lifetime of the IOC). The number behind
|
// Static pointers (valid for the entire lifetime of the IOC). The number behind
|
||||||
// the strings gives the integer number of each variant (see also method
|
// the strings gives the integer number of each variant (see also method
|
||||||
// stringifyAsynStatus)
|
// stringifyAsynStatus)
|
||||||
|
@ -11,9 +11,8 @@ Stefan Mathis, November 2024
|
|||||||
#define sinqController_H
|
#define sinqController_H
|
||||||
#include "asynMotorController.h"
|
#include "asynMotorController.h"
|
||||||
#include "msgPrintControl.h"
|
#include "msgPrintControl.h"
|
||||||
#include <deque>
|
|
||||||
#include <initHooks.h>
|
#include <initHooks.h>
|
||||||
#include <unordered_map>
|
#include <memory>
|
||||||
|
|
||||||
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
||||||
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
||||||
@ -21,6 +20,8 @@ Stefan Mathis, November 2024
|
|||||||
#define AbsoluteEncoder "absolute"
|
#define AbsoluteEncoder "absolute"
|
||||||
#define NoEncoder "none"
|
#define NoEncoder "none"
|
||||||
|
|
||||||
|
struct sinqControllerImpl;
|
||||||
|
|
||||||
class epicsShareClass sinqController : public asynMotorController {
|
class epicsShareClass sinqController : public asynMotorController {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -175,11 +176,7 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
virtual asynStatus setThresholdComTimeout(time_t comTimeoutWindow,
|
virtual asynStatus setThresholdComTimeout(time_t comTimeoutWindow,
|
||||||
size_t maxNumberTimeouts) {
|
size_t maxNumberTimeouts);
|
||||||
comTimeoutWindow_ = comTimeoutWindow;
|
|
||||||
maxNumberTimeouts_ = maxNumberTimeouts;
|
|
||||||
return asynSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inform the user, if the number of timeouts exceeds the threshold
|
* @brief Inform the user, if the number of timeouts exceeds the threshold
|
||||||
@ -211,17 +208,23 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
* @param maxSubsequentTimeouts
|
* @param maxSubsequentTimeouts
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus setMaxSubsequentTimeouts(int maxSubsequentTimeouts) {
|
asynStatus setMaxSubsequentTimeouts(int maxSubsequentTimeouts);
|
||||||
maxSubsequentTimeouts_ = maxSubsequentTimeouts;
|
|
||||||
return asynSuccess;
|
/**
|
||||||
}
|
* @brief If true, the maximum number of subsequent communication timeouts
|
||||||
|
* set in `setMaxSubsequentTimeouts` has been exceeded
|
||||||
|
*
|
||||||
|
* @return true
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
|
bool maxSubsequentTimeoutsExceeded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a reference to the map used to control the maximum number of
|
* @brief Get a reference to the map used to control the maximum number of
|
||||||
* message repetitions. See the documentation of `printRepetitionWatchdog`
|
* message repetitions. See the documentation of `printRepetitionWatchdog`
|
||||||
* in msgPrintControl.h for details.
|
* in msgPrintControl.h for details.
|
||||||
*/
|
*/
|
||||||
msgPrintControl &getMsgPrintControl() { return msgPrintControl_; }
|
msgPrintControl &getMsgPrintControl();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
@ -293,25 +296,26 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
int motorRecDirection() { return motorRecDirection_; }
|
int motorRecDirection() { return motorRecDirection_; }
|
||||||
int motorRecOffset() { return motorRecOffset_; }
|
int motorRecOffset() { return motorRecOffset_; }
|
||||||
|
|
||||||
// Accessors for additional PVs defined in sinqController
|
// Accessors for additional PVs defined in sinqController (which are hidden
|
||||||
int motorMessageText() { return motorMessageText_; }
|
// in pSinqC_)
|
||||||
int motorReset() { return motorReset_; }
|
int motorMessageText();
|
||||||
int motorEnable() { return motorEnable_; }
|
int motorReset();
|
||||||
int motorEnableRBV() { return motorEnableRBV_; }
|
int motorEnable();
|
||||||
int motorCanDisable() { return motorCanDisable_; }
|
int motorEnableRBV();
|
||||||
int motorEnableMovWatchdog() { return motorEnableMovWatchdog_; }
|
int motorCanDisable();
|
||||||
int motorCanSetSpeed() { return motorCanSetSpeed_; }
|
int motorEnableMovWatchdog();
|
||||||
int motorLimitsOffset() { return motorLimitsOffset_; }
|
int motorCanSetSpeed();
|
||||||
int motorForceStop() { return motorForceStop_; }
|
int motorLimitsOffset();
|
||||||
int motorConnected() { return motorConnected_; }
|
int motorForceStop();
|
||||||
int motorVeloFromDriver() { return motorVeloFromDriver_; }
|
int motorConnected();
|
||||||
int motorVbasFromDriver() { return motorVbasFromDriver_; }
|
int motorVeloFromDriver();
|
||||||
int motorVmaxFromDriver() { return motorVmaxFromDriver_; }
|
int motorVbasFromDriver();
|
||||||
int motorAcclFromDriver() { return motorAcclFromDriver_; }
|
int motorVmaxFromDriver();
|
||||||
int motorHighLimitFromDriver() { return motorHighLimitFromDriver_; }
|
int motorAcclFromDriver();
|
||||||
int motorLowLimitFromDriver() { return motorLowLimitFromDriver_; }
|
int motorHighLimitFromDriver();
|
||||||
int adaptivePolling() { return adaptivePolling_; }
|
int motorLowLimitFromDriver();
|
||||||
int encoderType() { return encoderType_; }
|
int adaptivePolling();
|
||||||
|
int encoderType();
|
||||||
|
|
||||||
// Additional members
|
// Additional members
|
||||||
int numAxes() { return numAxes_; }
|
int numAxes() { return numAxes_; }
|
||||||
@ -330,7 +334,7 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
*
|
*
|
||||||
* @return asynUser*
|
* @return asynUser*
|
||||||
*/
|
*/
|
||||||
asynUser *pasynOctetSyncIOipPort() { return pasynOctetSyncIOipPort_; }
|
asynUser *pasynOctetSyncIOipPort();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Overloaded version of `asynController::poll` which decreases
|
* @brief Overloaded version of `asynController::poll` which decreases
|
||||||
@ -374,76 +378,26 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
* specified
|
* specified
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int outstandingForcedFastPolls() { return outstandingForcedFastPolls_; }
|
int outstandingForcedFastPolls();
|
||||||
|
|
||||||
// Maximum error message buffer size. This is an empirical value which must
|
/**
|
||||||
// be large enough to avoid overflows for all commands to the device /
|
* @brief Return the maximum error message buffer size
|
||||||
// responses from it.
|
*
|
||||||
|
* This is an empirical value which must be large enough to avoid overflows
|
||||||
|
* for all commands to the device / responses from it.
|
||||||
|
*
|
||||||
|
* @return uint32_t
|
||||||
|
*/
|
||||||
|
uint32_t msgSize() { return MAXBUF_; }
|
||||||
|
|
||||||
|
// Maximum message size
|
||||||
static const uint32_t MAXBUF_ = 200;
|
static const uint32_t MAXBUF_ = 200;
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
protected:
|
|
||||||
// Number of fast polls which still need to be performed before adaptive
|
|
||||||
// polling is active again.
|
|
||||||
int outstandingForcedFastPolls_;
|
|
||||||
|
|
||||||
// Number of polls forced by wakeupPoller which are still
|
|
||||||
|
|
||||||
// Pointer to the port user which is specified by the char array
|
|
||||||
// `ipPortConfigName` in the constructor
|
|
||||||
asynUser *pasynOctetSyncIOipPort_;
|
|
||||||
double movingPollPeriod_;
|
|
||||||
double idlePollPeriod_;
|
|
||||||
msgPrintControl msgPrintControl_;
|
|
||||||
|
|
||||||
// Internal variables used in the communication timeout frequency watchdog
|
|
||||||
time_t comTimeoutWindow_; // Size of the time window
|
|
||||||
size_t maxNumberTimeouts_; // Maximum acceptable number of events within the
|
|
||||||
// time window
|
|
||||||
std::deque<time_t>
|
|
||||||
timeoutEvents_; // Deque holding the timestamps of the individual events
|
|
||||||
|
|
||||||
// Communicate a timeout to the user after it has happened this many times
|
|
||||||
// in a row
|
|
||||||
int maxSubsequentTimeouts_;
|
|
||||||
bool maxSubsequentTimeoutsExceeded_;
|
|
||||||
|
|
||||||
/*
|
|
||||||
See the documentation in db/sinqMotor.db for the following integers
|
|
||||||
*/
|
|
||||||
#define FIRST_SINQMOTOR_PARAM motorMessageText_
|
|
||||||
int motorMessageText_;
|
|
||||||
int motorReset_;
|
|
||||||
int motorEnable_;
|
|
||||||
int motorEnableRBV_;
|
|
||||||
int motorCanDisable_;
|
|
||||||
int motorEnableMovWatchdog_;
|
|
||||||
int motorCanSetSpeed_;
|
|
||||||
int motorLimitsOffset_;
|
|
||||||
int motorForceStop_;
|
|
||||||
int motorConnected_;
|
|
||||||
/*
|
|
||||||
These parameters are here to write values from the hardware to the EPICS
|
|
||||||
motor record. Using motorHighLimit_ / motorLowLimit_ does not work:
|
|
||||||
https://epics.anl.gov/tech-talk/2023/msg00576.php. Therefore, some
|
|
||||||
additional records are introduced which read from these parameters and write
|
|
||||||
into the motor record.
|
|
||||||
*/
|
|
||||||
int motorVeloFromDriver_;
|
|
||||||
int motorVbasFromDriver_;
|
|
||||||
int motorVmaxFromDriver_;
|
|
||||||
int motorAcclFromDriver_;
|
|
||||||
int motorHighLimitFromDriver_;
|
|
||||||
int motorLowLimitFromDriver_;
|
|
||||||
int adaptivePolling_;
|
|
||||||
int encoderType_;
|
|
||||||
#define LAST_SINQMOTOR_PARAM encoderType_
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<sinqControllerImpl> pSinqC_;
|
||||||
static void epicsInithookFunction(initHookState iState);
|
static void epicsInithookFunction(initHookState iState);
|
||||||
};
|
};
|
||||||
#define NUM_SINQMOTOR_DRIVER_PARAMS \
|
|
||||||
(&LAST_SINQMOTOR_PARAM - &FIRST_SINQMOTOR_PARAM + 1)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user