Commit first working version of the new PMAC-V3 driver. This version has
been tested on the SINQTEST instrument. However, some important improvements (such as central polling in the controller) are still missing. They will be implemented in the next commit.
This commit is contained in:
@ -13,7 +13,7 @@ REQUIRED+=scaler
|
||||
REQUIRED+=asynMotor
|
||||
|
||||
# Release version
|
||||
LIBVERSION=2024-dev
|
||||
LIBVERSION=2024-newPmacV3
|
||||
|
||||
# DB files to include in the release
|
||||
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
||||
@ -38,6 +38,9 @@ SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/C804Axis.cpp
|
||||
SOURCES += sinqEPICSApp/src/C804Controller.cpp
|
||||
SOURCES += sinqEPICSApp/src/newPmacV3Axis.cpp
|
||||
SOURCES += sinqEPICSApp/src/newPmacV3Controller.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||
|
||||
USR_CFLAGS += -Wall -Wextra # -Werror
|
||||
|
||||
|
@ -46,9 +46,9 @@ 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
|
||||
// The poll function is just a wrapper around pollNoUpdate and
|
||||
// handles mainly the callParamCallbacks() function
|
||||
asynStatus status_poll = C804Axis::poll_no_param_lib_update(moving);
|
||||
asynStatus status_poll = C804Axis::pollNoUpdate(moving);
|
||||
|
||||
// According to the function documentation of asynMotorAxis::poll, this
|
||||
// function should be called at the end of a poll implementation.
|
||||
@ -64,7 +64,7 @@ asynStatus C804Axis::poll(bool *moving) {
|
||||
}
|
||||
|
||||
// Perform the actual poll
|
||||
asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
||||
asynStatus C804Axis::pollNoUpdate(bool *moving) {
|
||||
// Local variable declaration
|
||||
static const char *functionName = "C804Axis::poll";
|
||||
asynStatus status;
|
||||
|
@ -1,40 +1,43 @@
|
||||
#ifndef C804Axis_H
|
||||
#define C804Axis_H
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
#include "SINQController.h"
|
||||
|
||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||
// between C804Controller.h and C804Axis.h. See https://en.cppreference.com/w/cpp/language/class.
|
||||
// between C804Controller.h and C804Axis.h. See
|
||||
// https://en.cppreference.com/w/cpp/language/class.
|
||||
class C804Controller;
|
||||
|
||||
class C804Axis : public SINQAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
C804Axis(C804Controller *pController, int axisNo);
|
||||
virtual ~C804Axis();
|
||||
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 stop(double acceleration);
|
||||
asynStatus home(double minVelocity, double maxVelocity, double acceleration, int forwards);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus poll_no_param_lib_update(bool *moving);
|
||||
asynStatus enable(int on);
|
||||
class C804Axis : public SINQAxis {
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
C804Axis(C804Controller *pController, int axisNo);
|
||||
virtual ~C804Axis();
|
||||
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 stop(double acceleration);
|
||||
asynStatus home(double minVelocity, double maxVelocity, double acceleration,
|
||||
int forwards);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus pollNoUpdate(bool *moving);
|
||||
asynStatus enable(int on);
|
||||
|
||||
protected:
|
||||
C804Controller *pC_;
|
||||
protected:
|
||||
C804Controller *pC_;
|
||||
|
||||
void checkBounds(C804Controller *pController, int axisNo);
|
||||
int last_position_steps_;
|
||||
double motorRecResolution_;
|
||||
time_t estimatedArrivalTime_;
|
||||
time_t last_poll_;
|
||||
int errorReported_;
|
||||
bool enabled_;
|
||||
void checkBounds(C804Controller *pController, int axisNo);
|
||||
int last_position_steps_;
|
||||
double motorRecResolution_;
|
||||
time_t estimatedArrivalTime_;
|
||||
time_t last_poll_;
|
||||
int errorReported_;
|
||||
bool enabled_;
|
||||
|
||||
private:
|
||||
friend class C804Controller;
|
||||
private:
|
||||
friend class C804Controller;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,15 +14,13 @@ class newPmacV3Axis : public asynMotorAxis {
|
||||
virtual ~newPmacV3Axis();
|
||||
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 stop(double acceleration);
|
||||
// asynStatus home(double minVelocity, double maxVelocity, double
|
||||
// acceleration,
|
||||
// int forwards);
|
||||
asynStatus home(double minVelocity, double maxVelocity, double acceleration,
|
||||
int forwards);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus poll_no_param_lib_update(bool *moving);
|
||||
// asynStatus enable(int on);
|
||||
asynStatus pollNoUpdate(bool *moving);
|
||||
asynStatus enable(int on);
|
||||
asynStatus readEncoderType();
|
||||
|
||||
protected:
|
||||
newPmacV3Controller *pC_;
|
||||
@ -30,6 +28,9 @@ class newPmacV3Axis : public asynMotorAxis {
|
||||
void checkBounds(newPmacV3Controller *pController, int axisNo);
|
||||
asynStatus readConfig();
|
||||
bool initial_poll_;
|
||||
bool waitForHandshake_;
|
||||
time_t timeAtHandshake_;
|
||||
time_t handshakeTimeout_;
|
||||
time_t time_at_init_poll_;
|
||||
time_t timeout_param_lib_init_;
|
||||
|
||||
|
@ -85,7 +85,7 @@ newPmacV3Controller::newPmacV3Controller(const char *portName,
|
||||
// NICOS and in turn to the user
|
||||
status = createParam("MOTOR_MESSAGE_TEXT", asynParamOctet, &messageText_);
|
||||
if (status != asynSuccess) {
|
||||
paramLibAccessFailed(status, "messageText_");
|
||||
paramLibAccessFailed(status, functionName, "messageText_");
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: FATAL ERROR: unable to create parameter (%s). "
|
||||
"Terminating IOC.\n",
|
||||
@ -111,6 +111,15 @@ newPmacV3Controller::newPmacV3Controller(const char *portName,
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
status = createParam("ENCODER_TYPE", asynParamOctet, &encoderType_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: FATAL ERROR: unable to create parameter (%s). "
|
||||
"Terminating IOC.\n",
|
||||
functionName, stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
status = createParam("REREAD_ENCODER_POSITION", asynParamInt32,
|
||||
&rereadEncoderPosition_);
|
||||
if (status != asynSuccess) {
|
||||
@ -140,6 +149,16 @@ newPmacV3Controller::newPmacV3Controller(const char *portName,
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
status =
|
||||
createParam("MOTOR_POSITION_RBV", asynParamFloat64, &motorPositionRBV_);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: FATAL ERROR: unable to create parameter (%s). "
|
||||
"Terminating IOC.\n",
|
||||
functionName, stringifyAsynStatus(status));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
Define the end-of-string of a message coming from the device to EPICS.
|
||||
It is not necessary to append a terminator to outgoing messages, since
|
||||
@ -230,14 +249,14 @@ Sends the given command to the axis specified by axisNo and returns the response
|
||||
of the axis.
|
||||
*/
|
||||
asynStatus newPmacV3Controller::writeRead(int axisNo, const char *command,
|
||||
char *response) {
|
||||
char *response,
|
||||
bool expect_response) {
|
||||
// Definition of local variables.
|
||||
static const char *functionName = "newPmacV3Controller::writeRead";
|
||||
asynStatus status = asynSuccess;
|
||||
asynStatus pl_status = asynSuccess;
|
||||
char full_command[MAXBUF_] = {0};
|
||||
char user_message[MAXBUF_] = {0};
|
||||
int motorStatusCommsError = 0;
|
||||
int motorStatusProblem = 0;
|
||||
|
||||
// Send the message and block the thread until either a response has been
|
||||
@ -294,15 +313,48 @@ asynStatus newPmacV3Controller::writeRead(int axisNo, const char *command,
|
||||
"%s: Sending command: %s\n", functionName, full_command);
|
||||
|
||||
// Perform the actual writeRead
|
||||
// status =
|
||||
// pasynOctetSyncIO->write(lowLevelPortUser_, full_command,
|
||||
// commandLength + offset, TIMEOUT_,
|
||||
// &nbytesOut);
|
||||
|
||||
status = pasynOctetSyncIO->writeRead(
|
||||
lowLevelPortUser_, full_command, commandLength + offset, response,
|
||||
MAXBUF_, TIMEOUT_, &nbytesOut, &nbytesIn, &eomReason);
|
||||
|
||||
/*
|
||||
If we expect a response, check if we got one. If no response was received,
|
||||
flush the PMAC and try again. If that fails as well, return an error
|
||||
*/
|
||||
if (expect_response && strlen(response) == 0) {
|
||||
// Flush message as defined in Turbo PMAC User Manual, p. 430:
|
||||
// \x40\xB3000
|
||||
// VR_DOWNLOAD = \x40
|
||||
// VR_PMAC_FLUSH = \xB3
|
||||
char flush_msg[5] = {0};
|
||||
flush_msg[0] = '\x40';
|
||||
flush_msg[1] = '\xB3';
|
||||
size_t nbytesOut = 0;
|
||||
status = pasynOctetSyncIO->write(lowLevelPortUser_, flush_msg, 5,
|
||||
TIMEOUT_, &nbytesOut);
|
||||
|
||||
// Wait after the flush so the MCU has time to prepare for the
|
||||
// next command
|
||||
usleep(100000);
|
||||
|
||||
if (status == asynSuccess) {
|
||||
// If flushing the MCU succeded, try to send the command again
|
||||
status = pasynOctetSyncIO->writeRead(
|
||||
lowLevelPortUser_, full_command, commandLength + offset,
|
||||
response, MAXBUF_, TIMEOUT_, &nbytesOut, &nbytesIn, &eomReason);
|
||||
|
||||
// If the command returned an empty string for the second time, give
|
||||
// up and propagate the error.
|
||||
if (strlen(response) == 0) {
|
||||
status = asynError;
|
||||
}
|
||||
} else {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: Unable to flush MCU (%s).\n", functionName,
|
||||
stringifyAsynStatus(status));
|
||||
}
|
||||
}
|
||||
|
||||
// Create custom error messages for different failure modes
|
||||
switch (status) {
|
||||
case asynSuccess:
|
||||
@ -312,22 +364,19 @@ asynStatus newPmacV3Controller::writeRead(int axisNo, const char *command,
|
||||
"connection timeout for axis %d", axisNo);
|
||||
break;
|
||||
case asynDisconnected:
|
||||
snprintf(user_message, sizeof(user_message), "axis %d is not connected",
|
||||
axisNo);
|
||||
snprintf(user_message, sizeof(user_message), "axis is not connected");
|
||||
break;
|
||||
case asynDisabled:
|
||||
snprintf(user_message, sizeof(user_message), "axis %d is disabled",
|
||||
axisNo);
|
||||
snprintf(user_message, sizeof(user_message), "axis is disabled");
|
||||
break;
|
||||
default:
|
||||
snprintf(user_message, sizeof(user_message),
|
||||
"Communication with axis %d failed (%s)", axisNo,
|
||||
stringifyAsynStatus(status));
|
||||
"Communication failed (%s)", stringifyAsynStatus(status));
|
||||
break;
|
||||
}
|
||||
|
||||
if (status != asynSuccess) {
|
||||
// Check if the axis aleady is in an error communication mode. If it is
|
||||
// Check if the axis already is in an error communication mode. If it is
|
||||
// not, upstream the error. This is done to avoid "flooding" the user
|
||||
// with different error messages if more than one error ocurred before
|
||||
// an error-free communication
|
||||
@ -335,13 +384,15 @@ asynStatus newPmacV3Controller::writeRead(int axisNo, const char *command,
|
||||
pl_status =
|
||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusProblem_");
|
||||
return paramLibAccessFailed(pl_status, functionName,
|
||||
"motorStatusProblem_");
|
||||
}
|
||||
|
||||
if (motorStatusProblem == 0) {
|
||||
pl_status = axis->setStringParam(this->messageText_, user_message);
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "messageText_");
|
||||
return paramLibAccessFailed(pl_status, functionName,
|
||||
"messageText_");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -360,8 +411,10 @@ asynStatus newPmacV3Controller::writeRead(int axisNo, const char *command,
|
||||
}
|
||||
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_");
|
||||
return paramLibAccessFailed(pl_status, functionName,
|
||||
"motorStatusCommsError_");
|
||||
}
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
@ -370,10 +423,7 @@ asynStatus newPmacV3Controller::writeInt32(asynUser *pasynUser,
|
||||
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynSuccess;
|
||||
char command[MAXBUF_] = {0};
|
||||
char response[MAXBUF_] = {0};
|
||||
static const char *functionName = "newPmacV3Controller::writeInt32";
|
||||
int nvals = 0;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
@ -385,92 +435,12 @@ asynStatus newPmacV3Controller::writeInt32(asynUser *pasynUser,
|
||||
|
||||
// Handle custom PVs
|
||||
if (function == enableMotor_) {
|
||||
|
||||
int ax_status = 0;
|
||||
asynStatus pl_status = asynSuccess;
|
||||
int timeout_enable_disable = 2;
|
||||
char message[MAXBUF_] = {0};
|
||||
|
||||
// =====================================================================
|
||||
|
||||
// Check if the axis is currently enabled
|
||||
snprintf(command, sizeof(command), "P%2.2d00", axis->axisNo_);
|
||||
status = writeRead(axis->axisNo_, command, response);
|
||||
nvals = sscanf(response, "%d", &ax_status);
|
||||
if (checkNumExpectedReads(1, nvals, functionName, axis->axisNo_) !=
|
||||
asynSuccess) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Axis is already enabled / disabled and a new enable / disable command
|
||||
// was sent => Do nothing
|
||||
if ((ax_status != -3) == value) {
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
// Enable / disable the axis
|
||||
snprintf(command, sizeof(command), "M%2.2d14=%d", axis->axisNo_, value);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||
"%s: %s axis %d on controller %s\n", functionName,
|
||||
value ? "Enable" : "Disable", axis->axisNo_, portName);
|
||||
if (value == 0) {
|
||||
pl_status = setStringParam(messageText_, "Disabling ...");
|
||||
} else {
|
||||
pl_status = setStringParam(messageText_, "Enabling ...");
|
||||
}
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "messageText_");
|
||||
}
|
||||
status = writeRead(axis->axisNo_, command, response);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Query the axis status every few milliseconds until the axis has been
|
||||
// enabled or until the timeout has been reached
|
||||
snprintf(command, sizeof(command), "P%2.2d00", axis->axisNo_);
|
||||
int startTime = time(NULL);
|
||||
while (time(NULL) < startTime + timeout_enable_disable) {
|
||||
|
||||
// Read the axis status
|
||||
usleep(100);
|
||||
status = writeRead(axis->axisNo_, command, response);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
nvals = sscanf(response, "%d", &ax_status);
|
||||
if (checkNumExpectedReads(1, nvals, functionName, axis->axisNo_) !=
|
||||
asynSuccess) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
if ((ax_status != -3) == value) {
|
||||
bool moving = false;
|
||||
// Perform a poll to update the parameter library
|
||||
axis->poll(&moving);
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to change axis status within timeout_enable_disable => Send a
|
||||
// corresponding message
|
||||
asynPrint(
|
||||
this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||
"%s: Failed to %s axis %d on controller %s within %d seconds\n",
|
||||
functionName, value ? "enable" : "disable", axis->axisNo_, portName,
|
||||
timeout_enable_disable);
|
||||
|
||||
// Output message to user
|
||||
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
||||
value ? "enable" : "disable", timeout_enable_disable);
|
||||
pl_status = setStringParam(messageText_, "Enabling ...");
|
||||
if (pl_status != asynSuccess) {
|
||||
return paramLibAccessFailed(pl_status, "messageText_");
|
||||
}
|
||||
return asynError;
|
||||
return axis->enable(value);
|
||||
|
||||
} else if (function == rereadEncoderPosition_) {
|
||||
|
||||
char encoderType[MAXBUF_] = {0};
|
||||
|
||||
/*
|
||||
This is not a command that can always be run when enabling a
|
||||
motor as it also causes relative encoders to reread a position
|
||||
@ -488,68 +458,56 @@ asynStatus newPmacV3Controller::writeInt32(asynUser *pasynUser,
|
||||
|
||||
// Poll the current status of the axis
|
||||
bool moving = false;
|
||||
axis->poll(&moving);
|
||||
status = axis->poll(&moving);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Check if this is an absolute encoder
|
||||
snprintf(command, sizeof(command), "I%2.2X04", axis->axisNo_);
|
||||
status = writeRead(axis->axisNo_, command, response);
|
||||
status = axis->readEncoderType();
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
int reponse_length = strlen(response);
|
||||
if (reponse_length < 3) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: Unexpected reponse '%s' from axis %d on "
|
||||
"controller %s while rereading encoder. Aborting...\n",
|
||||
functionName, response, axis->axisNo_, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// We are only interested in the last two digits and the last value in
|
||||
// the string before the terminator is \r
|
||||
int encoder_id = 0;
|
||||
nvals = sscanf(response + (reponse_length - 3), "%2X", &encoder_id);
|
||||
if (checkNumExpectedReads(1, nvals, functionName, axis->axisNo_) !=
|
||||
asynSuccess) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
snprintf(command, sizeof(command), "P46");
|
||||
status = writeRead(axis->axisNo_, command, response);
|
||||
status = getStringParam(axis->axisNo_, encoderType_, encoderType);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
return paramLibAccessFailed(status, functionName, "encoderType_");
|
||||
}
|
||||
|
||||
int number_of_axes = strtol(response, NULL, 10);
|
||||
if (encoder_id <= number_of_axes) {
|
||||
asynPrint(
|
||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: Trying to reread absolute encoder of axis %d on "
|
||||
"controller %s, but it is a relative encoder. Aborting...\n",
|
||||
functionName, axis->axisNo_, portName);
|
||||
// Abort if the axis is incremental
|
||||
if (strcmp(encoderType, IncrementalEncoder) == 0) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_WARNING,
|
||||
"%s: Trying to reread absolute encoder of axis %d on "
|
||||
"controller %s, but it is a relative encoder.\n",
|
||||
functionName, axis->axisNo_, portName);
|
||||
status = setStringParam(messageText_,
|
||||
"Cannot reread an incremental encoder.");
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, functionName,
|
||||
"messageText_");
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
// Check if the axis is disabled. If not, inform the user that this is
|
||||
// necessary
|
||||
// Check if the axis is disabled. If not, inform the user that this
|
||||
// is necessary
|
||||
int enabled = 0;
|
||||
status = getIntegerParam(axis->axisNo_, motorEnabled_, &enabled);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorEnabled_");
|
||||
return paramLibAccessFailed(status, functionName, "motorEnabled_");
|
||||
}
|
||||
|
||||
if (enabled == 1) {
|
||||
asynPrint(
|
||||
this->pasynUserSelf, ASYN_TRACE_WARNING,
|
||||
"%s: Trying to reread absolute encoder of axis %d on "
|
||||
"controller %s, but it is a relative encoder. Aborting...\n",
|
||||
functionName, axis->axisNo_, portName);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_WARNING,
|
||||
"%s: Axis %d on controller %s must be disabled before "
|
||||
"rereading the encoder.\n",
|
||||
functionName, axis->axisNo_, portName);
|
||||
status = setStringParam(
|
||||
messageText_,
|
||||
"Axis must be disabled before rereading the encoder.");
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "messageText_");
|
||||
return paramLibAccessFailed(status, functionName,
|
||||
"messageText_");
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
@ -564,7 +522,8 @@ asynStatus newPmacV3Controller::writeInt32(asynUser *pasynUser,
|
||||
// though
|
||||
status = axis->setIntegerParam(rereadEncoderPosition_, 0);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "rereadEncoderPosition_");
|
||||
return paramLibAccessFailed(status, functionName,
|
||||
"rereadEncoderPosition_");
|
||||
}
|
||||
return asynSuccess;
|
||||
|
||||
@ -581,11 +540,9 @@ and "rereading the encoder" must be covered.
|
||||
asynStatus newPmacV3Controller::readInt32(asynUser *pasynUser,
|
||||
epicsInt32 *value) {
|
||||
|
||||
int function = pasynUser->reason, axStat;
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynError;
|
||||
static const char *functionName = "newPmacV3Controller::readInt32";
|
||||
char command[MAXBUF_];
|
||||
char response[MAXBUF_];
|
||||
|
||||
// =====================================================================
|
||||
|
||||
@ -595,42 +552,22 @@ asynStatus newPmacV3Controller::readInt32(asynUser *pasynUser,
|
||||
return asynError;
|
||||
}
|
||||
|
||||
if (function == motorEnabled_) {
|
||||
// Readback value for motorEnabled
|
||||
|
||||
snprintf(command, sizeof(command), "P%2.2d00", axis->axisNo_);
|
||||
status = this->writeRead(axis->axisNo_, command, response);
|
||||
if (status != asynSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
int nvals = sscanf(response, "%d", value);
|
||||
if (checkNumExpectedReads(1, nvals, functionName, axis->axisNo_) !=
|
||||
asynSuccess) {
|
||||
return asynError;
|
||||
}
|
||||
status = setIntegerParam(motorEnabled_, (*value != -3));
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "motorEnabled_");
|
||||
}
|
||||
return callParamCallbacks(); // Update the PVs from the parameter
|
||||
// library
|
||||
|
||||
} else if (function == rereadEncoderPositionRBV_) {
|
||||
if (function == rereadEncoderPositionRBV_) {
|
||||
// Readback value for rereadEncoderPosition
|
||||
|
||||
status = getIntegerParam(axis->axisNo_, rereadEncoderPosition_, value);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "HERE\n");
|
||||
return paramLibAccessFailed(status, "rereadEncoderPosition_");
|
||||
return paramLibAccessFailed(status, functionName,
|
||||
"rereadEncoderPosition_");
|
||||
}
|
||||
status =
|
||||
setIntegerParam(axis->axisNo_, rereadEncoderPositionRBV_, *value);
|
||||
if (status != asynSuccess) {
|
||||
return paramLibAccessFailed(status, "rereadEncoderPositionRBV_");
|
||||
return paramLibAccessFailed(status, functionName,
|
||||
"rereadEncoderPositionRBV_");
|
||||
}
|
||||
return callParamCallbacks(); // Update the PVs from the parameter
|
||||
// library
|
||||
|
||||
// Update the PVs from the parameter library
|
||||
return callParamCallbacks();
|
||||
} else {
|
||||
return asynMotorController::readInt32(pasynUser, value);
|
||||
}
|
||||
@ -676,6 +613,7 @@ const char *newPmacV3Controller::stringifyAsynStatus(asynStatus status) {
|
||||
}
|
||||
|
||||
asynStatus newPmacV3Controller::paramLibAccessFailed(asynStatus status,
|
||||
const char *functionName,
|
||||
const char *parameter) {
|
||||
char message[MAXBUF_] = {0};
|
||||
snprintf(message, sizeof(message),
|
||||
@ -684,23 +622,27 @@ asynStatus newPmacV3Controller::paramLibAccessFailed(asynStatus status,
|
||||
parameter, stringifyAsynStatus(status));
|
||||
|
||||
// Log the error message and try to propagate it
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, message);
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: %s", functionName,
|
||||
message);
|
||||
setStringParam(messageText_, message);
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus newPmacV3Controller::checkNumExpectedReads(int expected, int read,
|
||||
const char *functionName,
|
||||
const char *command,
|
||||
const char *response,
|
||||
int axisNo_) {
|
||||
if (expected == read) {
|
||||
return asynSuccess;
|
||||
} else {
|
||||
char message[MAXBUF_] = {0};
|
||||
snprintf(message, sizeof(message),
|
||||
"Could not interpret controller response in function %s for "
|
||||
"axis %d. This is a bug, please inform the software support.",
|
||||
functionName, axisNo_);
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, message);
|
||||
"Could not interpret response %s for command %s (axis %d). "
|
||||
"This is a bug.",
|
||||
response, command, axisNo_);
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: %s", functionName,
|
||||
message);
|
||||
setStringParam(messageText_, message);
|
||||
setIntegerParam(motorStatusCommsError_, 1);
|
||||
return asynError;
|
||||
@ -868,4 +810,4 @@ epicsExportRegistrar(newPmacV3ControllerRegister);
|
||||
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "asynMotorController.h"
|
||||
#include "newPmacV3Axis.h"
|
||||
|
||||
#define IncrementalEncoder "Incremental encoder"
|
||||
#define AbsoluteEncoder "Absolute encoder"
|
||||
|
||||
class newPmacV3Controller : public asynMotorController {
|
||||
|
||||
public:
|
||||
@ -31,17 +34,25 @@ class newPmacV3Controller : public asynMotorController {
|
||||
// overloaded because we want to read the axis state
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
|
||||
// // Overloaded to read configuration details from the motor records
|
||||
// asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo,
|
||||
// const char **pptypeName, size_t *psize);
|
||||
|
||||
protected:
|
||||
asynUser *lowLevelPortUser_;
|
||||
|
||||
asynStatus writeRead(int axisNo, const char *command, char *response);
|
||||
asynStatus writeRead(int axisNo, const char *command, char *response,
|
||||
bool expect_response);
|
||||
|
||||
// Create a descriptive string out of an asynStatus which can be used for
|
||||
// logging or communicating with the user
|
||||
const char *stringifyAsynStatus(asynStatus status);
|
||||
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter);
|
||||
asynStatus paramLibAccessFailed(asynStatus status, const char *functionName,
|
||||
const char *parameter);
|
||||
asynStatus checkNumExpectedReads(int expected, int read,
|
||||
const char *function, int axisNo_);
|
||||
const char *functionName,
|
||||
const char *command, const char *response,
|
||||
int axisNo_);
|
||||
newPmacV3Axis *castToAxis(asynMotorAxis *asynAxis);
|
||||
|
||||
private:
|
||||
@ -58,14 +69,24 @@ class newPmacV3Controller : public asynMotorController {
|
||||
*/
|
||||
static const double TIMEOUT_;
|
||||
|
||||
// Indices of additional PVs
|
||||
int messageText_;
|
||||
int enableMotor_;
|
||||
int motorEnabled_;
|
||||
int rereadEncoderPosition_;
|
||||
int rereadEncoderPositionRBV_;
|
||||
int readConfig_;
|
||||
int encoderType_;
|
||||
int motorPositionRBV_;
|
||||
|
||||
/*
|
||||
If the time between two sent messages is too short, the MCU communication
|
||||
module might "lose" an answer. To prevent this, a small delay is introduced
|
||||
in EPICS after each message exchange. Unit is microseconds.
|
||||
*/
|
||||
int afterMessageSleep_;
|
||||
|
||||
friend class newPmacV3Axis;
|
||||
};
|
||||
|
||||
#endif /* pmacV3Controller_H */
|
||||
#endif /* pmacV3Controller_H */
|
||||
|
Reference in New Issue
Block a user