735 lines
28 KiB
C++
735 lines
28 KiB
C++
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
/*
|
|
This class extends asynMotorAxis by some features used in SINQ.
|
|
|
|
Stefan Mathis, November 2024
|
|
*/
|
|
|
|
#ifndef sinqAxis_H
|
|
#define sinqAxis_H
|
|
#include "asynMotorAxis.h"
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
struct sinqAxisImpl;
|
|
|
|
class epicsShareClass sinqAxis : public asynMotorAxis {
|
|
public:
|
|
/**
|
|
* @brief Construct a new sinqAxis object
|
|
*
|
|
* @param pC_ Pointer to the controller of the axis
|
|
* @param axis Index of the axis
|
|
*/
|
|
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
|
|
`doPoll` implementation.
|
|
*
|
|
* Wrapper around `doPoll` which performs the following operations:
|
|
|
|
- Call the `doPoll` method
|
|
|
|
- Reset motorStatusProblem_, motorStatusCommsError_ and motorMessageText_ if
|
|
doPoll returned asynSuccess
|
|
|
|
- If the movement timeout watchdog has been started, check it.
|
|
|
|
- The flags `motorStatusHome_`, `motorStatusHomed_` and
|
|
`motorStatusAtHome_` are set to their idle values (0, 1 and 1 respectively)
|
|
in the `poll()` method once the homing procedure is finished. See the
|
|
documentation of the `home()` method for more details.
|
|
|
|
- Run `callParamCallbacks()`
|
|
|
|
- Return the status of `doPoll`
|
|
*
|
|
* @param moving Forwarded to `doPoll`.
|
|
* @return asynStatus Forward the status of `doPoll`, unless one of
|
|
the parameter library operation fails (in that case, returns the status of
|
|
the failed operation.
|
|
*/
|
|
virtual asynStatus poll(bool *moving);
|
|
|
|
/**
|
|
* @brief Implementation of the "proper", device-specific poll method. This
|
|
method should be implemented by a child class of sinqAxis.
|
|
*
|
|
* @param moving Should be set to true, if the axis is moving,
|
|
* and false otherwise.
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus doPoll(bool *moving);
|
|
|
|
/**
|
|
* @brief Perform some standardized operations before and after the concrete
|
|
`doMove` implementation.
|
|
|
|
* Wrapper around `doMove` which calculates the (absolute) target position
|
|
and stores it in the member variable `targetPosition_`. This member variable
|
|
is e.g. used for the movement watchdog. Afterwards, it calls and returns
|
|
`doMove`.
|
|
*
|
|
* @param position Forwarded to `doMove`.
|
|
* @param relative Forwarded to `doMove`.
|
|
* @param minVelocity Forwarded to `doMove`.
|
|
* @param maxVelocity Forwarded to `doMove`.
|
|
* @param acceleration Forwarded to `doMove`.
|
|
* @return asynStatus Forward the status of `doMove`, unless one of
|
|
the parameter library operation fails (in that case, returns the failed
|
|
operation status).
|
|
*/
|
|
virtual asynStatus move(double position, int relative, double minVelocity,
|
|
double maxVelocity, double acceleration);
|
|
|
|
/**
|
|
* @brief Implementation of the "proper", device-specific move method. This
|
|
method should be implemented by a child class of sinqAxis.
|
|
*
|
|
* @param position Target position `VAL` from the motor record
|
|
* @param relative Specifies, whether the target position is
|
|
relative or absolute.
|
|
* @param minVelocity Minimum velocity VMIN from the motor record
|
|
* @param maxVelocity Maximum velocity VMAX from the motor record
|
|
* @param acceleration Acceleration ACCEL from the motor record
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus doMove(double position, int relative, double minVelocity,
|
|
double maxVelocity, double acceleration);
|
|
|
|
/**
|
|
* @brief Wrapper around doHome which handles the homing-related flags
|
|
*
|
|
* The homing procedure of the motor record is controlled by the following
|
|
* parameter library flags:
|
|
*
|
|
* - `motorMoveToHome_`: Setting this flag to `1` indicates to EPICS that a
|
|
homing procedure should start and can therefore be used to start homing from
|
|
within the driver.
|
|
|
|
* - `motorStatusHome_`: This flag should be set to `1` while the motor is
|
|
actively moving toward its home position and to `0` when the home position
|
|
is reached.
|
|
*
|
|
* - `motorStatusHomed_`: This flag should be set to `0` at the start of a
|
|
homing command and to 1 once the home position is reached.
|
|
*
|
|
* - `motorStatusAtHome_`: This flag is similar to `motorStatusHomed_`, but
|
|
in addition it should also be `1` when the motor is at its home position,
|
|
but wasn't actively homed in order to get there.
|
|
*
|
|
* This function performs the following operations in the given order:
|
|
*
|
|
* - Call `doHome()` and forward the parameters
|
|
*
|
|
* - If `doHome()` returned asynSuccess: Set `motorStatusHome_` to `1`,
|
|
`motorStatusHomed_` to `0` and `motorStatusAtHome_` to `0`.
|
|
*
|
|
* - If `doHome()` returned asynError: This means that the motor cannot be
|
|
homed because the encoder is absolute. Set a corresponding error message,
|
|
but return asynSuccess in order to avoid any automatic retries by asyn.
|
|
|
|
* - If `doHome()` returned anything else: Forward the status.
|
|
*
|
|
* The flags `motorStatusHome_`, `motorStatusHomed_` and
|
|
`motorStatusAtHome_` are set to their idle values (0, 1 and 1 respectively)
|
|
in the `poll()` method once the homing procedure is finished.
|
|
*
|
|
* @param minVelocity Forwarded to `doHome`.
|
|
* @param maxVelocity Forwarded to `doHome`.
|
|
* @param acceleration Forwarded to `doHome`.
|
|
* @param forwards Forwarded to `doHome`.
|
|
* @return asynStatus Forward the status of `doHome`, unless one of
|
|
the parameter library operation fails (in that case, returns the failed
|
|
operation status).
|
|
*/
|
|
virtual asynStatus home(double minVelocity, double maxVelocity,
|
|
double acceleration, int forwards);
|
|
|
|
/**
|
|
* @brief Implementation of the "proper", device-specific home method. This
|
|
method should be implemented by a child class of sinqAxis. If the motor
|
|
cannot be homed because it has an absolute encoder, this function should
|
|
return asynError.
|
|
*
|
|
* @param minVelocity Minimum velocity VMIN from the motor record
|
|
* @param maxVelocity Maximum velocity VMAX from the motor record
|
|
* @param acceleration Acceleration ACCEL from the motor record
|
|
* @param forwards Is 1, if the motor record field HOMF was used
|
|
to trigger the homing, and 0, if HOMR was used.
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus doHome(double minVelocity, double maxVelocity,
|
|
double acceleration, int forwards);
|
|
|
|
/**
|
|
* @brief This function is called when the PV "$(INSTR)$(M):Reset" is set to
|
|
* any value. It calls `doReset` (which ought to be implemented by a child
|
|
* class) and then performs da defined number of consecutive fast polls. If
|
|
* one of the polls returns asynSuccess, it returns immediately.
|
|
*
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus reset();
|
|
|
|
/**
|
|
* @brief Implementation of the "proper", device-specific `reset` method.
|
|
This method should be implemented by a child class of sinqAxis. If the
|
|
motor cannot be reset, this function should return asynError.
|
|
*
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus doReset();
|
|
|
|
/**
|
|
* @brief This function enables / disables an axis. It should be implemented
|
|
* by a child class of sinqAxis.
|
|
*
|
|
* The concrete implementation should (but doesn't need to) follow the
|
|
* convention that a value of 0 disables the axis and any other value
|
|
* enables it.
|
|
*
|
|
* @param on
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus enable(bool on);
|
|
|
|
/**
|
|
* @brief Populate the motor record fields VELO, VBAS and VMAX
|
|
*
|
|
* Populates the speed fields of the motor record. If the param lib
|
|
* entry motorCanSetSpeed_ (connected to the PV x:VariableSpeed) is set to
|
|
* 1, VBAS and VMAX are set to min and max respectively. Otherwise, they are
|
|
* set to val. Additionally, the speed itself is set to VELO.
|
|
*
|
|
* The units of the inputs are engineering units (EGU) per second (e.g. mm/s
|
|
* if the EGU is mm).
|
|
*
|
|
* If the given configuration is invalid (min > max, velo < min, velo > max)
|
|
* and the motor is configured as a variable speed motor (param lib entry
|
|
* motorCanSetSpeed_ is 1), this function returns an asynError.
|
|
*
|
|
* @param velo Actual velocity (EGU / s)
|
|
* @param vbas Minimum allowed velocity (EGU / s)
|
|
* @param velo Maximum allowed velocity (EGU / s)
|
|
*
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus setVeloFields(double velo, double vbas, double vmax);
|
|
|
|
/**
|
|
* @brief Populate the ACCL field of the motor record
|
|
*
|
|
* Populates the acceleration field of the motor record with the given
|
|
* value. If accl is not positive, this function does not set the value and
|
|
* returns an asynError.
|
|
*
|
|
* The unit of the input is engineering units (EGU) per second squared (e.g.
|
|
* mm/s^2 if the EGU is mm).
|
|
*
|
|
* @param accl Actual acceleration (EGU / s^2)
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus setAcclField(double accl);
|
|
|
|
/**
|
|
* @brief Start the watchdog for the movement, if the watchdog is not
|
|
disabled. See the documentation of checkMovTimeoutWatchdog for more details.
|
|
*
|
|
* @return asynStatus If one of the parameter library operations
|
|
used to get the values for the timeout calculation failed, return that
|
|
status, otherwise return asynSuccess.
|
|
*/
|
|
virtual asynStatus startMovTimeoutWatchdog();
|
|
|
|
/**
|
|
* @brief Check if the watchdog timed out
|
|
*
|
|
Manages a timeout mechanism for the movement:
|
|
If the axis is moving and the movement takes too long, create an error
|
|
message and return asynError. The watchdog is started when moving switches
|
|
from "false" to "true" and stopped when moving switches from "true" to
|
|
"false". At the watchdog start, the estimated movement time is calculated as
|
|
|
|
t = offsetMovTimeout_ + scaleMovTime_ * [timeContSpeed + 2*timeAccel]
|
|
|
|
with
|
|
|
|
timeContSpeed = abs(targetPosition - motorPosition) / motorVelBase
|
|
timeAcc = motorVelBase / motorAccel
|
|
|
|
The values motorVelBase, motorAccel and positionAtMovementStart are taken
|
|
from the parameter library. Therefore it is necessary to populate them
|
|
before using this function. If they are not given, both speed and velocity
|
|
are assumed to be infinite. This means that timeContSpeed and/or timeAcc are
|
|
set to zero. targetPosition is populated automatically when using the doMove
|
|
function.
|
|
|
|
The values offsetMovTimeout_ and scaleMovTimeout_ can be set directly from
|
|
the IOC shell with the functions setScaleMovTimeout and setOffsetMovTimeout,
|
|
if sinqMotor is loaded via the "require" mechanism.
|
|
*
|
|
* @param moving Should be the "moving" status from `poll` /
|
|
`doPoll`.
|
|
* @return asynStatus Return asynError, if the watchdog timed out,
|
|
and asynSuccess otherwise.
|
|
*/
|
|
virtual asynStatus checkMovTimeoutWatchdog(bool moving);
|
|
|
|
/**
|
|
* @brief Enable / disable the watchdog. Also available in the IOC shell
|
|
* (see "extern C" section in sinqController.cpp).
|
|
*
|
|
* If enable is set to false and the watchdog is currently running, this
|
|
* function stops it immediately.
|
|
*
|
|
* @param enabled
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus setWatchdogEnabled(bool enable);
|
|
|
|
/**
|
|
* @brief Set the offsetMovTimeout. Also available in the IOC shell
|
|
* (see "extern C" section in sinqController.cpp).
|
|
*
|
|
* See documentation of `checkMovTimeoutWatchdog` for details.
|
|
*
|
|
* @param offsetMovTimeout Offset (in seconds)
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus setOffsetMovTimeout(time_t offsetMovTimeout);
|
|
|
|
/**
|
|
* @brief Set the scaleMovTimeout. Also available in the IOC shell
|
|
* (see "extern C" section in sinqController.cpp).
|
|
*
|
|
See documentation of `checkMovTimeoutWatchdog` for details.
|
|
*
|
|
* @param scaleMovTimeout Scaling factor (in seconds)
|
|
* @return asynStatus
|
|
*/
|
|
virtual asynStatus setScaleMovTimeout(time_t scaleMovTimeout);
|
|
|
|
/**
|
|
* @brief Return the axis number of this axis
|
|
*
|
|
* @return int
|
|
*/
|
|
int axisNo() { return axisNo_; }
|
|
|
|
/**
|
|
* @brief Read the motor position from the paramLib, adjusted for the
|
|
* motorRecResolution
|
|
*
|
|
* The motorPosition value in the paramLib is the encoder position
|
|
* divided by the motorRecResolution (see README.md). This function
|
|
* fetches the paramLib value and multiplies it with motorRecResolution
|
|
* (also fetched from the paramLib).
|
|
*
|
|
* @param motorPositon
|
|
* @return asynStatus
|
|
*/
|
|
asynStatus motorPosition(double *motorPositon);
|
|
|
|
/**
|
|
* @brief Write the motor position in the paramLib, adjusted for the
|
|
* motorRecResolution
|
|
*
|
|
* The motorPosition value in the paramLib is the encoder position
|
|
* divided by the motorRecResolution (see README.md). This function takes
|
|
* the input value and divides it with motorRecResolution (fetched from
|
|
* the paramLib).
|
|
*
|
|
* @param motorPosition
|
|
* @return asynStatus
|
|
*/
|
|
asynStatus setMotorPosition(double motorPosition);
|
|
|
|
/**
|
|
* @brief Check if the axis is not connected and print a corresponding error
|
|
* message
|
|
*
|
|
* This method is meant to be used at the end of "interactive" function
|
|
* calls such as move, home, stop etc which can be manually triggered from
|
|
* the IOC shell or from the channel access protocol.
|
|
*/
|
|
asynStatus assertConnected();
|
|
|
|
/**
|
|
* @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;
|
|
}
|
|
};
|
|
* ```
|
|
*/
|
|
virtual sinqController *pController() { return pC_; };
|
|
|
|
/**
|
|
* @brief Returns true, if the axis was moving in the last poll cycle, and
|
|
* false otherwise.
|
|
*
|
|
* @return true
|
|
* @return false
|
|
*/
|
|
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:
|
|
std::unique_ptr<sinqAxisImpl> pSinqA_;
|
|
sinqController *pC_;
|
|
};
|
|
|
|
// =============================================================================
|
|
// 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
|
|
* axis in the paramLib
|
|
*
|
|
* This function should not be used directly, but rather through its macro
|
|
* variant `setAxisParamChecked`.
|
|
*
|
|
* @tparam T
|
|
* @param axis
|
|
* @param controller
|
|
* @param indexName
|
|
* @param func
|
|
* @param writeValue
|
|
* @param callerFunctionName
|
|
* @param lineNumber
|
|
* @return asynStatus
|
|
*/
|
|
template <typename A, typename C, typename T>
|
|
asynStatus setAxisParam(A *axis, C *controller, const char *indexName,
|
|
int (C::*func)(), T writeValue,
|
|
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
|
|
*
|
|
* This macro is a wrapper around `setIntegerParam` / `setDoubleParam` /
|
|
* `setStringParam` which checks if the operation was successfull. If it wasn't,
|
|
* it returns by calling the paramLibAccessFailed function.
|
|
*
|
|
* For example, the following input:
|
|
* ```
|
|
* setAxisParamChecked(this, motorStatusProblem_, false)
|
|
* ```
|
|
* expands into the following code:
|
|
* ```
|
|
* {
|
|
* int indexValue = controller->motorStatusProblem_();
|
|
* asynStatus status = axis->setIntegerParam(indexValue, writeValue);
|
|
* if (status != asynSuccess) {
|
|
* return controller->paramLibAccessFailed(
|
|
* status, "motorStatusProblem_", axis->axisNo(), __PRETTY_FUNCTION__,
|
|
* __LINE__);
|
|
* }
|
|
* return asynSuccess;
|
|
* }
|
|
* ```
|
|
* =============================================================================
|
|
*/
|
|
#define setAxisParamChecked(axis, indexSetterFunction, writeValue) \
|
|
do { \
|
|
auto *ctrlPtr = (axis)->pController(); \
|
|
using ControllerType = \
|
|
typename std::remove_pointer<decltype(ctrlPtr)>::type; \
|
|
asynStatus setStatus = \
|
|
setAxisParam(axis, ctrlPtr, #indexSetterFunction, \
|
|
static_cast<int (ControllerType::*)()>( \
|
|
&ControllerType::indexSetterFunction), \
|
|
writeValue, __PRETTY_FUNCTION__, __LINE__); \
|
|
if (setStatus != asynSuccess) \
|
|
return setStatus; \
|
|
} while (0)
|
|
|
|
// =============================================================================
|
|
// 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,
|
|
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,
|
|
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,
|
|
TypeTag<bool>) {
|
|
return getAxisParamImpl(axis, indexName, func, (int *)readValue,
|
|
callerFunctionName, lineNumber);
|
|
}
|
|
|
|
template <typename A, typename C>
|
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
|
int (C::*func)(), double *readValue,
|
|
const char *callerFunctionName, int lineNumber,
|
|
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,
|
|
TypeTag<char>) {
|
|
|
|
int indexValue = (controller->*func)();
|
|
asynStatus status = controller->getStringParam(
|
|
axis->axisNo(), indexValue, controller->msgSize(), readValue);
|
|
if (status != asynSuccess) {
|
|
return controller->paramLibAccessFailed(
|
|
status, indexName, axis->axisNo(), callerFunctionName, lineNumber);
|
|
}
|
|
return asynSuccess;
|
|
}
|
|
|
|
template <typename A, typename C, size_t N>
|
|
asynStatus getAxisParamImpl(A *axis, C *controller, const char *indexName,
|
|
int (C::*func)(), char (*readValue)[N],
|
|
const char *callerFunctionName, int lineNumber,
|
|
TypeTag<char>) {
|
|
// Decay the array to char*
|
|
return getAxisParamImpl(axis, controller, indexName, func,
|
|
static_cast<char *>(readValue), callerFunctionName,
|
|
lineNumber);
|
|
}
|
|
|
|
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,
|
|
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
|
|
* axis in the paramLib
|
|
*
|
|
* This function should not be used directly, but rather through its macro
|
|
* variant `getAxisParamChecked`.
|
|
*
|
|
* @tparam T
|
|
* @param axis
|
|
* @param controller
|
|
* @param indexName
|
|
* @param func
|
|
* @param readValue
|
|
* @param callerFunctionName
|
|
* @param lineNumber
|
|
* @param maxChars Only used when readValue is a char*. Specifies the maximum
|
|
* number of characters which can be placed into the buffer the pointer points
|
|
* to.
|
|
* @return asynStatus
|
|
*/
|
|
template <typename A, typename C, typename T>
|
|
asynStatus getAxisParam(A *axis, C *controller, const char *indexName,
|
|
int (C::*func)(), T *readValue,
|
|
const char *callerFunctionName, int lineNumber) {
|
|
return getAxisParamImpl(axis, controller, indexName, func, readValue,
|
|
callerFunctionName, lineNumber, TypeTag<T>{});
|
|
}
|
|
|
|
/**
|
|
* @brief Macro to get an paramLib parameter and error checking the return value
|
|
*
|
|
* This macro is a wrapper around `getIntegerParam` / `getDoubleParam` /
|
|
* `getStringParam` which checks if the operation was successfull. If it wasn't,
|
|
* it returns by calling the paramLibAccessFailed function. In order
|
|
*
|
|
* For example, the following input:
|
|
* ```
|
|
* getAxisParamChecked(this, motorStatusProblem_, &readValue)
|
|
* ```
|
|
* expands into the following code:
|
|
* ```
|
|
* {
|
|
* int indexValue = controller->motorStatusProblem_();
|
|
* asynStatus status = controller->getIntegerParam(axis->axisNo(),
|
|
* indexValue, readValue); if (status != asynSuccess) { return
|
|
* controller->paramLibAccessFailed( status, "motorStatusProblem_",
|
|
* axis->axisNo(), __PRETTY_FUNCTION__,
|
|
* __LINE__);
|
|
* }
|
|
* return asynSuccess;
|
|
* }
|
|
* ```
|
|
* =============================================================================
|
|
*/
|
|
#define getAxisParamChecked(axis, indexGetterFunction, readValue) \
|
|
do { \
|
|
auto *ctrlPtr = (axis)->pController(); \
|
|
using ControllerType = \
|
|
typename std::remove_pointer<decltype(ctrlPtr)>::type; \
|
|
asynStatus getStatus = \
|
|
getAxisParam(axis, ctrlPtr, #indexGetterFunction, \
|
|
static_cast<int (ControllerType::*)()>( \
|
|
&ControllerType::indexGetterFunction), \
|
|
readValue, __PRETTY_FUNCTION__, __LINE__); \
|
|
if (getStatus != asynSuccess) \
|
|
return getStatus; \
|
|
} while (0)
|
|
|
|
#endif |