File pmacAxis.h:

The default constructor of LiftAxis just forwards to the pmacAxis
constructor, which has an optional argument "autoenable" with the default
value "true". However, we want that argument to be false, hence we provide
an explicit constructor.

File C804Axis.cpp:
Removed a typing error

File Makefile.RHEL8:
Switched compilation target name to 2024-amor-no-autoenable-lift-axis to
not disturb other instruments. The newly created library is meant just
for Amor. if no problems occur, we can upstream the changes to master
at the end of October and create a new library "2023-v3".
This commit is contained in:
2024-10-04 14:57:21 +02:00
parent d44fdbf736
commit 80205727c7
3 changed files with 301 additions and 286 deletions

View File

@ -13,7 +13,7 @@ REQUIRED+=scaler
REQUIRED+=asynMotor
# Release version
LIBVERSION=2024-dev
LIBVERSION=2024-amor-no-autoenable-lift-axis
# DB files to include in the release
TEMPLATES += sinqEPICSApp/Db/dimetix.db

View File

@ -1,14 +1,14 @@
#include "C804Axis.h"
#include "C804Controller.h"
#include <errlog.h>
#include <string.h>
#include <math.h>
#include <cmath>
#include <unistd.h>
#include <errlog.h>
#include <limits>
#include <math.h>
#include <string.h>
#include <unistd.h>
C804Axis::C804Axis(C804Controller *pC, int axisNo) : SINQAxis(pC, axisNo), pC_(pC)
{
C804Axis::C804Axis(C804Controller *pC, int axisNo)
: SINQAxis(pC, axisNo), pC_(pC) {
/*
The superclass constructor SINQAxis calls in turn its superclass constructor
asynMotorAxis. In the latter, a pointer to the constructed object this is
@ -16,13 +16,14 @@ C804Axis::C804Axis(C804Controller *pC, int axisNo) : SINQAxis(pC, axisNo), pC_(p
pC->pAxes_[axisNo] = this;
Therefore, the axes are managed by the controller pC. See C804Controller.cpp for further explanation.
If axisNo is out of bounds, asynMotorAxis prints an error (see
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp, line 40).
However, we want the IOC creation to stop completely, since this is a configuration error.
Therefore, the axes are managed by the controller pC. See C804Controller.cpp
for further explanation. If axisNo is out of bounds, asynMotorAxis prints an
error (see
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp,
line 40). However, we want the IOC creation to stop completely, since this
is a configuration error.
*/
if (axisNo >= pC->numAxes_)
{
if (axisNo >= pC->numAxes_) {
exit(-1);
}
last_position_steps_ = 0;
@ -30,8 +31,7 @@ C804Axis::C804Axis(C804Controller *pC, int axisNo) : SINQAxis(pC, axisNo), pC_(p
last_poll_ = 0.0;
}
C804Axis::~C804Axis(void)
{
C804Axis::~C804Axis(void) {
// Since the controller memory is managed somewhere else, we don't need to
// clean up the pointer pC here.
}
@ -39,47 +39,44 @@ C804Axis::~C804Axis(void)
/*
The polling function informs us about the state of the axis, in particular if it
is currently moving. It is called periodically, with the period defined by
the controller constructor arguments idlePollPeriod and movingPollPeriod depending on
the current axis state.
the controller constructor arguments idlePollPeriod and movingPollPeriod
depending on the current axis state.
*/
asynStatus C804Axis::poll(bool *moving)
{
asynStatus C804Axis::poll(bool *moving) {
// Local variable declaration
static const char *functionName = "C804Axis::poll";
// The poll function is just a wrapper around poll_no_param_lib_update and handles mainly
// the callParamCallbacks() function
// The poll function is just a wrapper around poll_no_param_lib_update and
// handles mainly the callParamCallbacks() function
asynStatus status_poll = C804Axis::poll_no_param_lib_update(moving);
// According to the function documentation of asynMotorAxis::poll, this
// function should be called at the end of a poll implementation.
asynStatus status_callback = callParamCallbacks();
if (status_callback != asynSuccess)
{d
if (status_callback != asynSuccess) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Updating the parameter library failed for axis %d\n", functionName, axisNo_);
"%s: Updating the parameter library failed for axis %d\n",
functionName, axisNo_);
return status_callback;
}
else
{
} else {
return status_poll;
}
}
// Perform the actual poll
asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
{
asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
// Local variable declaration
static const char *functionName = "C804Axis::poll";
asynStatus status;
int axis_status = 0;
// The controller returns the position and velocity in encoder steps.
// This value needs to be converted in user units (engineering units EGU) via
// the record field MRES of the motor record. This field has already been read
// by the constructor into the member variable motorRecResolution_.
// To go from steps to user units, multiply with motorRecResolution_
// Example: If 10 steps correspond to 1 mm, MRES should be 0.1.
// This value needs to be converted in user units (engineering units EGU)
// via the record field MRES of the motor record. This field has already
// been read by the constructor into the member variable
// motorRecResolution_. To go from steps to user units, multiply with
// motorRecResolution_ Example: If 10 steps correspond to 1 mm, MRES should
// be 0.1.
int position_error_steps = 0;
int motor_position_steps = 0;
int motor_velocity_steps = 0;
@ -89,28 +86,28 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
double motor_velocity = .0;
double programmed_motor_velocity = .0;
// The buffer sizes for command and response are defined in the controller (see the corresponding source code files)
// The buffer sizes for command and response are defined in the controller
// (see the corresponding source code files)
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
/*
Cancel the poll if the last poll has "just" happened.
*/
if (time(NULL) < last_poll_ + 0.5 * pC_->movingPollPeriod_)
{
if (time(NULL) < last_poll_ + 0.5 * pC_->movingPollPeriod_) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING,
"%s: Aborted poll since the last poll for axis %d happened a short time ago\n", functionName, axisNo_);
"%s: Aborted poll since the last poll for axis %d happened a "
"short time ago\n",
functionName, axisNo_);
return asynSuccess;
}
else
{
} else {
last_poll_ = time(NULL);
}
/*
The parameter motorRecResolution_ is coupled to the field MRES of the motor
record in the following manner:
- In sinq_asyn_motor.db, the PV (motor_record_pv_name)MOTOR_REC_RESOLUTION is
defined as a copy of the field (motor_record_pv_name).MRES:
- In sinq_asyn_motor.db, the PV (motor_record_pv_name)MOTOR_REC_RESOLUTION
is defined as a copy of the field (motor_record_pv_name).MRES:
record(ao,"$(P)$(M):Resolution") {
field(DESC, "$(M) resolution")
@ -121,27 +118,30 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
field(PREC, "$(PREC)")
}
- The PV name MOTOR_REC_RESOLUTION is coupled in asynMotorController.h to the constant motorRecResolutionString
- ... which in turn is assigned to motorRecResolution_ in asynMotorController.cpp
This way of making the field visible to the driver is described here: https://epics.anl.gov/tech-talk/2020/msg00378.php
This is a one-way coupling, changes to the parameter library via setDoubleParam
are NOT transferred to (motor_record_pv_name).MRES or to (motor_record_pv_name):Resolution.
- The PV name MOTOR_REC_RESOLUTION is coupled in asynMotorController.h to
the constant motorRecResolutionString
- ... which in turn is assigned to motorRecResolution_ in
asynMotorController.cpp This way of making the field visible to the driver
is described here: https://epics.anl.gov/tech-talk/2020/msg00378.php This is
a one-way coupling, changes to the parameter library via setDoubleParam are
NOT transferred to (motor_record_pv_name).MRES or to
(motor_record_pv_name):Resolution.
NOTE: This function must not be called in the constructor (e.g. in order to
save the read result to the member variable earlier), since the parameter library
is updated at a later stage!
save the read result to the member variable earlier), since the parameter
library is updated at a later stage!
*/
pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, &motorRecResolution_);
pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
&motorRecResolution_);
asynPrint(pC_->pasynUserSelf,ASYN_TRACE_FLOW,"Poll axis %d\n", axisNo_);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW, "Poll axis %d\n", axisNo_);
/*
We know that the motor resolution must not be zero. During the startup of the
IOC, polls can happen before the record is fully initialized. In that case,
all values are zero.
We know that the motor resolution must not be zero. During the startup of
the IOC, polls can happen before the record is fully initialized. In that
case, all values are zero.
*/
if (motorRecResolution_ == 0)
{
if (motorRecResolution_ == 0) {
return asynError;
}
@ -154,11 +154,11 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
*/
setIntegerParam(pC_->motorStatusProblem_, false);
// Read out the position error of the axis (delta of target position to actual position)
// Read out the position error of the axis (delta of target position to
// actual position)
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTE", axisNo_);
status = pC_->lowLevelWriteRead(axisNo_, command, response, true);
if (status == asynSuccess)
{
if (status == asynSuccess) {
int parsed_axis;
sscanf(response, "%2dE%10d", &parsed_axis, &position_error_steps);
@ -166,12 +166,12 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
position_error = double(position_error_steps) * motorRecResolution_;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Axis %d, response %s, position error %f\n", functionName, axisNo_, response, position_error);
}
else
{
"%s: Axis %d, response %s, position error %f\n", functionName,
axisNo_, response, position_error);
} else {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Reading the position error failed for axis %d\n", functionName, axisNo_);
"%s: Reading the position error failed for axis %d\n",
functionName, axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
// Stop the evaluation prematurely
@ -180,9 +180,9 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
// Read the current position.
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTP", this->axisNo_);
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess)
{
status =
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess) {
int parsed_axis;
sscanf(response, "%2dP%10d", &parsed_axis, &motor_position_steps);
@ -190,14 +190,14 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
motor_position = double(motor_position_steps) * motorRecResolution_;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Axis %d, response %s, position %f\n", functionName, axisNo_, response, motor_position);
"%s: Axis %d, response %s, position %f\n", functionName,
axisNo_, response, motor_position);
setDoubleParam(pC_->motorPosition_, motor_position);
setDoubleParam(pC_->motorEncoderPosition_, motor_position);
}
else
{
} else {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Reading the position failed for axis %d\n", functionName, axisNo_);
"%s: Reading the position failed for axis %d\n", functionName,
axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
return status;
@ -205,9 +205,9 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
// Read the current velocity
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTV", this->axisNo_);
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess)
{
status =
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess) {
int parsed_axis;
sscanf(response, "%2dV%10d", &parsed_axis, &motor_velocity_steps);
@ -215,12 +215,12 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
motor_velocity = double(motor_velocity_steps) * motorRecResolution_;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Axis %d, response %s, velocity %f\n", functionName, axisNo_, response, motor_velocity);
}
else
{
"%s: Axis %d, response %s, velocity %f\n", functionName,
axisNo_, response, motor_velocity);
} else {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Reading the velocity failed for axis %d\n", functionName, axisNo_);
"%s: Reading the velocity failed for axis %d\n", functionName,
axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
return status;
@ -228,23 +228,25 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
// Read the programmed velocity
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTY", this->axisNo_);
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess)
{
status =
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess) {
int parsed_axis;
sscanf(response, "%2dY%10d", &parsed_axis, &programmed_motor_velocity_steps);
sscanf(response, "%2dY%10d", &parsed_axis,
&programmed_motor_velocity_steps);
// Scale from the encoder resultion to user units
programmed_motor_velocity = double(programmed_motor_velocity_steps) * motorRecResolution_;
programmed_motor_velocity =
double(programmed_motor_velocity_steps) * motorRecResolution_;
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Axis %d, response %s, programmed velocity %f\n", functionName, axisNo_, response, programmed_motor_velocity);
}
else
{
"%s: Axis %d, response %s, programmed velocity %f\n",
functionName, axisNo_, response, programmed_motor_velocity);
} else {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Reading the programmed velocity failed for axis %d\n", functionName, axisNo_);
"%s: Reading the programmed velocity failed for axis %d\n",
functionName, axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
return status;
@ -253,15 +255,13 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
// Read the motor status
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTS", axisNo_);
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
if (status == asynSuccess)
{
if (status == asynSuccess) {
int parsed_axis;
sscanf(response, "%2dS%10d", &parsed_axis, &axis_status);
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Axis %d, response %s, status %d\n", functionName, axisNo_, response, axis_status);
}
else
{
"%s: Axis %d, response %s, status %d\n", functionName,
axisNo_, response, axis_status);
} else {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Reading the motor status %d\n", functionName, axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
@ -270,24 +270,22 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
return status;
}
// Check if the axis is enabled by reading out bit 2 (see https://stackoverflow.com/questions/2249731/how-do-i-get-bit-by-bit-data-from-an-integer-value-in-c)
// Check if the axis is enabled by reading out bit 2 (see
// https://stackoverflow.com/questions/2249731/how-do-i-get-bit-by-bit-data-from-an-integer-value-in-c)
int mask = 1 << 2;
int masked_n = axis_status & mask;
// Is 1 if the axis is disabled
int disabled = masked_n >> 2;
if (disabled)
{
if (disabled) {
enabled_ = false;
}
else
{
} else {
enabled_ = true;
}
/*
Determine if the motor is moving. This is determined by the following criteria:
1) The motor position changes from poll to poll
2) The motor is enabled
Determine if the motor is moving. This is determined by the following
criteria: 1) The motor position changes from poll to poll 2) The motor is
enabled
*/
*moving = enabled_ && motor_position_steps != this->last_position_steps_;
@ -300,22 +298,21 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
moving. If it has spent too much time in a moving state without reaching
the target, stop the motor and return an error.
*/
if (*moving)
{
if (*moving) {
int motorStatusMoving = 0;
pC_->getIntegerParam(axisNo_, pC_->motorStatusMoving_, &motorStatusMoving);
pC_->getIntegerParam(axisNo_, pC_->motorStatusMoving_,
&motorStatusMoving);
// motor is moving, but didn't move in the last poll
if (motorStatusMoving == 0)
{
if (motorStatusMoving == 0) {
time_t current_time = time(NULL);
// Factor 2 of the calculated moving time
estimatedArrivalTime_ = current_time + std::ceil(2 * std::fabs(position_error) / programmed_motor_velocity);
}
else
{
estimatedArrivalTime_ =
current_time + std::ceil(2 * std::fabs(position_error) /
programmed_motor_velocity);
} else {
// /*
// Motor is moving for a longer time than it should: Stop it
// */
@ -323,7 +320,9 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
// {
// snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
// status = pC_->lowLevelWriteRead(axisNo_, command, response);
// asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: Stopped axis %d since it moved for double the time it should to reach its target\n", functionName, axisNo_);
// asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: Stopped
// axis %d since it moved for double the time it should to reach
// its target\n", functionName, axisNo_);
// }
}
}
@ -339,54 +338,58 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
return status;
}
asynStatus C804Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
asynStatus C804Axis::move(double position, int relative, double minVelocity,
double maxVelocity, double acceleration) {
asynStatus status;
static const char *functionName = "C804Axis::move";
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
double position_c_units = 0.0; // Controller units
int position_steps = 0;
// Convert from user coordinates (EGU) to controller coordinates (steps). Check for overflow
if (motorRecResolution_ == 0.0)
{
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: MRES must not be zero. Movement is aborted", functionName);
// Convert from user coordinates (EGU) to controller coordinates (steps).
// Check for overflow
if (motorRecResolution_ == 0.0) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: MRES must not be zero. Movement is aborted",
functionName);
return asynError;
}
position_c_units = position / motorRecResolution_;
// Check for overflow during the division
if (position_c_units * motorRecResolution_ != position)
{
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: could not convert from user units (%f) to controller units (user units divided by resolution MRES %f) due to overflow.",
functionName, position, motorRecResolution_);
if (position_c_units * motorRecResolution_ != position) {
asynPrint(
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: could not convert from user units (%f) to controller units "
"(user units divided by resolution MRES %f) due to overflow.",
functionName, position, motorRecResolution_);
return asynError;
}
// Steps can only be integer values => cast to integer while checking for overflow
if (std::numeric_limits<int>::max() < position_c_units || std::numeric_limits<int>::min() > position_c_units)
{
// Steps can only be integer values => cast to integer while checking for
// overflow
if (std::numeric_limits<int>::max() < position_c_units ||
std::numeric_limits<int>::min() > position_c_units) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: target position %f cannot be converted to int (overflow). Check target value %f and MRES %f",
functionName, position_c_units, position_c_units, motorRecResolution_);
"%s: target position %f cannot be converted to int "
"(overflow). Check target value %f and MRES %f",
functionName, position_c_units, position_c_units,
motorRecResolution_);
return asynError;
}
position_steps = static_cast<int>(position_c_units);
// Convert from relative to absolute values
if (relative)
{
if (relative) {
position_steps += last_position_steps_;
}
// If the axis is currently disabled, enable it
if (!enabled_)
{
if (!enabled_) {
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dGO", axisNo_);
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
if (status != asynSuccess)
{
status =
pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
if (status != asynSuccess) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Enabling axis %d\n failed", functionName, axisNo_);
return status;
@ -396,10 +399,10 @@ asynStatus C804Axis::move(double position, int relative, double minVelocity, dou
// Start movement
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMA%d", axisNo_, position_steps);
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
if (status != asynSuccess)
{
if (status != asynSuccess) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Setting the target position %d failed for axis %d\n", functionName, position_steps, axisNo_);
"%s: Setting the target position %d failed for axis %d\n",
functionName, position_steps, axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
return status;
}
@ -411,14 +414,13 @@ asynStatus C804Axis::move(double position, int relative, double minVelocity, dou
return status;
}
asynStatus C804Axis::moveVelocity(double min_velocity, double max_velocity, double acceleration)
{
asynStatus C804Axis::moveVelocity(double min_velocity, double max_velocity,
double acceleration) {
static const char *functionName = "C804Axis::moveVelocity";
return asynError;
}
asynStatus C804Axis::stop(double acceleration)
{
asynStatus C804Axis::stop(double acceleration) {
asynStatus status = asynSuccess;
static const char *functionName = "C804Axis::stop";
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
@ -426,26 +428,28 @@ asynStatus C804Axis::stop(double acceleration)
bool moving = false;
poll(&moving);
if (moving)
{
if (moving) {
// ST = Stop
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Stop axis %d\n", functionName, axisNo_);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Stop axis %d\n",
functionName, axisNo_);
}
return status;
}
asynStatus C804Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{
asynStatus C804Axis::home(double minVelocity, double maxVelocity,
double acceleration, int forwards) {
asynStatus status = asynSuccess;
static const char *functionName = "C804Axis::home";
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dFE0", axisNo_); // Home to the upper limit of the axis (25 mm)
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dFE0",
axisNo_); // Home to the upper limit of the axis (25 mm)
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Homing axis %d\n", functionName, axisNo_);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Homing axis %d\n",
functionName, axisNo_);
return status;
}
@ -453,23 +457,21 @@ asynStatus C804Axis::home(double minVelocity, double maxVelocity, double acceler
/**
If on is 0, disable the motor, otherwise enable it.
*/
asynStatus C804Axis::enable(int on)
{
asynStatus C804Axis::enable(int on) {
asynStatus status = asynSuccess;
static const char *functionName = "C804Axis::enable";
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
if (on == 0)
{
if (on == 0) {
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMF", axisNo_);
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Disable axis %d\n", functionName, axisNo_);
}
else
{
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE,
"%s: Disable axis %d\n", functionName, axisNo_);
} else {
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMN", axisNo_);
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Enable axis %d\n", functionName, axisNo_);
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE,
"%s: Enable axis %d\n", functionName, axisNo_);
}
return status;
}

View File

@ -1,169 +1,180 @@
/********************************************
* pmacAxis.cpp
*
* PMAC Asyn motor based on the
*
* PMAC Asyn motor based on the
* asynMotorAxis class.
*
*
* Matthew Pearson
* 23 May 2012
*
*
* Modified to use the MsgTxt field for SINQ
*
* Mark Koennecke, January 2019
*
* EXtended with special motor axis for the Selene
* EXtended with special motor axis for the Selene
* guide, Mark Koennecke, February 2020
********************************************/
#ifndef pmacAxis_H
#define pmacAxis_H
#include "SINQController.h"
#include "SINQAxis.h"
#include "SINQController.h"
class pmacController;
class SeleneController;
class pmacAxis : public SINQAxis
{
class pmacAxis : public SINQAxis {
public:
/* These are the methods we override from the base class */
pmacAxis(pmacController *pController, int axisNo, bool enable=true);
virtual ~pmacAxis();
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus enable(int on);
/* These are the methods we override from the base class */
pmacAxis(pmacController *pController, int axisNo, bool enable = true);
virtual ~pmacAxis();
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity,
double acceleration);
asynStatus home(double min_velocity, double max_velocity,
double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus enable(int on);
protected:
pmacController *pC_;
asynStatus getAxisStatus(bool *moving);
asynStatus getAxisInitialStatus(void);
protected:
pmacController *pC_;
double setpointPosition_;
double encoderPosition_;
double currentVelocity_;
double velocity_;
double accel_;
double highLimit_;
double lowLimit_;
double scale_;
double previous_position_;
int previous_direction_;
int encoder_axis_;
int axisErrorCount;
asynStatus getAxisStatus(bool *moving);
asynStatus getAxisInitialStatus(void);
time_t startTime;
time_t status6Time;
int starting;
int homing;
double statusPos;
double setpointPosition_;
double encoderPosition_;
double currentVelocity_;
double velocity_;
double accel_;
double highLimit_;
double lowLimit_;
double scale_;
double previous_position_;
int previous_direction_;
int encoder_axis_;
int axisErrorCount;
time_t next_poll;
time_t startTime;
time_t status6Time;
int starting;
int homing;
double statusPos;
bool autoEnable;
friend class pmacController;
friend class pmacV3Controller;
time_t next_poll;
bool autoEnable;
friend class pmacController;
friend class pmacV3Controller;
};
/*--------------------------------------------------------------------------------------------*/
class SeleneAxis : public pmacAxis
{
class SeleneAxis : public pmacAxis {
public:
SeleneAxis(SeleneController *pController, int axisNo, double limitTarget);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus setPosition(double position);
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
SeleneAxis(SeleneController *pController, int axisNo, double limitTarget);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus setPosition(double position);
asynStatus home(double min_velocity, double max_velocity,
double acceleration, int forwards);
protected:
friend class SeleneController;
friend class pmacController;
private:
double limitTarget;
asynStatus getSeleneAxisInitialStatus(void);
protected:
friend class SeleneController;
friend class pmacController;
private:
double limitTarget;
asynStatus getSeleneAxisInitialStatus(void);
};
/*
Yet another special set of motors for the Selene Guide at AMOR. Each segment can be lifted or tilted. This is
two motors. One acts as a slave and only writes a new target, the other also sets a new target and sends the
actual movement command. Both motors are coordianted in the motor controller in order to avoid tension on
the guide elements. This gaves rise to the function code LIFTSLAVE and LIFTMASTER.
Yet another special set of motors for the Selene Guide at AMOR. Each segment
can be lifted or tilted. This is two motors. One acts as a slave and only
writes a new target, the other also sets a new target and sends the actual
movement command. Both motors are coordianted in the motor controller in order
to avoid tension on the guide elements. This gaves rise to the function code
LIFTSLAVE and LIFTMASTER.
In another mode the whole guide can be lifted or tilted. Then motor 1 and 6 get new values and one of them
sends the drive command. This causes all 6 motors to drive synchronously to their new targets. This is
implemented through the LIFTSEGMENT function code.
In another mode the whole guide can be lifted or tilted. Then motor 1 and 6
get new values and one of them sends the drive command. This causes all 6
motors to drive synchronously to their new targets. This is implemented
through the LIFTSEGMENT function code.
Mark Koennecke, February 2020
Mark Koennecke, February 2020
The axis should not be enabled automatically
Michele Brambilla, February 2020
Michele Brambilla, February 2020
*/
class LiftAxis : public pmacAxis
{
public:
LiftAxis(pmacController *pController, int axisNo) : pmacAxis((pmacController *)pController,axisNo) {};
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus poll(bool *moving);
asynStatus stop(double acceleration);
private:
int waitStart;
class LiftAxis : public pmacAxis {
public:
/*
The default constructor of LiftAxis just forwards to the pmacAxis
constructor, which has an optional argument "autoenable" with the default
value "true". However, we want that argument to be false, hence we provide
an explicit constructor
*/
LiftAxis(pmacController *pController, int axisNo)
: pmacAxis((pmacController *)pController, axisNo, false) {};
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus poll(bool *moving);
asynStatus stop(double acceleration);
private:
int waitStart;
};
/********************************************
/********************************************
* Protocol version 3 requires just some minor change
*
* Michele Brambilla, February 2022
********************************************/
class pmacV3Axis : public pmacAxis {
public:
public:
pmacV3Axis(pmacController *pController, int axisNo);
pmacV3Axis(pmacController *pController, int axisNo);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus poll(bool *moving);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus poll(bool *moving);
protected:
int IsEnable;
double Speed;
protected:
int IsEnable;
double Speed;
asynStatus getAxisStatus(bool *moving);
asynStatus getAxisStatus(bool *moving);
friend class pmacController;
friend class pmacV3Controller;
};
/*----------------------------------------------------------------------------------------------*/
class pmacHRPTAxis : public pmacV3Axis
{
public:
pmacHRPTAxis(pmacController *pController, int axisNo) : pmacV3Axis(pController,axisNo) {};
/**
* Override getAxisStatus in order to read the special parameter indicating a
* slit blade crash at HRPT
*/
asynStatus getAxisStatus(bool *moving);
protected:
friend class pmacController;
friend class pmacController;
friend class pmacV3Controller;
};
/*----------------------------------------------------------------------------------------------*/
class pmacHRPTAxis : public pmacV3Axis {
public:
pmacHRPTAxis(pmacController *pController, int axisNo)
: pmacV3Axis(pController, axisNo) {};
/**
* Override getAxisStatus in order to read the special parameter indicating
* a slit blade crash at HRPT
*/
asynStatus getAxisStatus(bool *moving);
protected:
friend class pmacController;
};
/*
* Special motors for the AMOR detector movement. The whole
* command set is different but on a pmac controller. This implements
* a coordinated movement of cox, coz and ftz in order not to break
* the flight tube which may have been mounted. This is mapped to three
* motors selected via the function code: com, the detector omega, coz,
* motors selected via the function code: com, the detector omega, coz,
* the detector z offset and park, for parking the flightpath.
*/
@ -171,39 +182,41 @@ class pmacHRPTAxis : public pmacV3Axis
#define ADCOZ 2
#define ADPARK 3
class AmorDetectorAxis: public pmacAxis {
public:
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
class AmorDetectorAxis : public pmacAxis {
public:
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus poll(bool *moving);
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus setPosition(double position);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus poll(bool *moving);
asynStatus moveVelocity(double min_velocity, double max_velocity,
double acceleration);
asynStatus home(double min_velocity, double max_velocity,
double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus setPosition(double position);
protected:
int _function;
int det_starting;
time_t det_startTime;
protected:
int _function;
int det_starting;
time_t det_startTime;
};
/*----------------------------------------------------------------------------------------------*/
class GirderAxis: public pmacV3Axis {
class GirderAxis : public pmacV3Axis {
public:
GirderAxis(pmacController *pController, int axisNo);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
protected:
int IsEnable;
friend class pmacController;
friend class pmacV3Controller;
friend class pmacController;
friend class pmacV3Controller;
};
#endif /* pmacAxis_H */