|
|
|
@ -498,24 +498,20 @@ return pAxes_[axisNo];
|
|
|
|
|
/** Polls the controller, rather than individual axis.*/
|
|
|
|
|
asynStatus pmacController::poll()
|
|
|
|
|
{
|
|
|
|
|
static const char *functionName = "pmacController::poll";
|
|
|
|
|
static const char *functionName = "pmacController::poll";
|
|
|
|
|
|
|
|
|
|
debugFlow(functionName);
|
|
|
|
|
debugFlow(functionName);
|
|
|
|
|
|
|
|
|
|
if (!lowLevelPortUser_) {
|
|
|
|
|
setIntegerParam(this->motorStatusCommsError_, 1);
|
|
|
|
|
return asynError;
|
|
|
|
|
if (!lowLevelPortUser_) {
|
|
|
|
|
setIntegerParam(this->motorStatusCommsError_, 1);
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
asynMotorController::poll();
|
|
|
|
|
|
|
|
|
|
return callParamCallbacks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
asynMotorController::poll();
|
|
|
|
|
|
|
|
|
|
callParamCallbacks();
|
|
|
|
|
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************************/
|
|
|
|
|
/** The following functions have C linkage, and can be called directly or from iocsh */
|
|
|
|
|
|
|
|
|
@ -571,17 +567,22 @@ createParam(MotorSetPositionString, asynParamFloat64, &se
|
|
|
|
|
callParamCallbacks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pmacV3Controller::pmacV3Controller(const char *portName,
|
|
|
|
|
const char *lowLevelPortName,
|
|
|
|
|
int lowLevelPortAddress, int numAxes,
|
|
|
|
|
double movingPollPeriod,
|
|
|
|
|
double idlePollPeriod,
|
|
|
|
|
const int &extraParams) :
|
|
|
|
|
pmacController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod, idlePollPeriod, extraParams) {
|
|
|
|
|
static const char *functionName = "pmacV3Controller::pmacV3Controller";
|
|
|
|
|
createParam(EnableAxisString, asynParamInt32, &enableAxis_);
|
|
|
|
|
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
|
|
|
|
|
callParamCallbacks();
|
|
|
|
|
pmacV3Controller::pmacV3Controller(
|
|
|
|
|
const char *portName,
|
|
|
|
|
const char *lowLevelPortName,
|
|
|
|
|
int lowLevelPortAddress, int numAxes,
|
|
|
|
|
double movingPollPeriod,
|
|
|
|
|
double idlePollPeriod,
|
|
|
|
|
const int &extraParams
|
|
|
|
|
) : pmacController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod, idlePollPeriod, extraParams) {
|
|
|
|
|
|
|
|
|
|
static const char *functionName = "pmacV3Controller::pmacV3Controller";
|
|
|
|
|
createParam(EnableAxisString, asynParamInt32, &enableAxis_);
|
|
|
|
|
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
|
|
|
|
|
createParam(ReReadEncoderPositionString, asynParamInt32, &rereadEncoderPosition_);
|
|
|
|
|
createParam(ReReadEncoderPositionString_RBV, asynParamInt32, &rereadEncoderPositionRBV_);
|
|
|
|
|
callParamCallbacks();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -871,19 +872,20 @@ return status;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
|
|
|
|
int function = pasynUser->reason;
|
|
|
|
|
asynStatus status = asynSuccess;
|
|
|
|
|
pmacV3Axis *pAxis = NULL;
|
|
|
|
|
char command[64] = {0};
|
|
|
|
|
char response[64] = {0};
|
|
|
|
|
int isOn;
|
|
|
|
|
time_t startTime;
|
|
|
|
|
bool moving;
|
|
|
|
|
static const char *functionName = "pmacV3Controller::writeInt32";
|
|
|
|
|
|
|
|
|
|
int function = pasynUser->reason;
|
|
|
|
|
asynStatus status = asynSuccess;
|
|
|
|
|
pmacV3Axis *pAxis = NULL;
|
|
|
|
|
char command[64] = {0};
|
|
|
|
|
char response[64] = {0};
|
|
|
|
|
int isOn;
|
|
|
|
|
time_t startTime;
|
|
|
|
|
bool moving;
|
|
|
|
|
static const char *functionName = "pmacV3Controller::writeInt32";
|
|
|
|
|
|
|
|
|
|
debugFlow(functionName);
|
|
|
|
|
|
|
|
|
|
pAxis = (pmacV3Axis*)this->getAxis(pasynUser);
|
|
|
|
|
pAxis = (pmacV3Axis*) this->getAxis(pasynUser);
|
|
|
|
|
if (!pAxis) {
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
@ -893,43 +895,125 @@ static const char *functionName = "pmacV3Controller::writeInt32";
|
|
|
|
|
pAxis->setIntegerParam(function, value);
|
|
|
|
|
|
|
|
|
|
if (function == enableAxis_) {
|
|
|
|
|
// only send commands when a state change is necessary
|
|
|
|
|
|
|
|
|
|
// Get Current Status
|
|
|
|
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
isOn = strtol(response, NULL, 10) != -3;
|
|
|
|
|
/* This was an attempt at automatically reading the encoder.
|
|
|
|
|
This is disabled as it did not work.
|
|
|
|
|
*/
|
|
|
|
|
if(value == 1 && isOn) {
|
|
|
|
|
sprintf(command, "M%2.2d=15", pAxis->axisNo_);
|
|
|
|
|
// lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
}
|
|
|
|
|
// Valid code continues here
|
|
|
|
|
sprintf(command, "M%2.2d14=%d", pAxis->axisNo_, value);
|
|
|
|
|
pAxis->updateMsgTxtFromDriver("");
|
|
|
|
|
if(isOn != value) {
|
|
|
|
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
|
|
|
"%s: Enable axis on controller %s, axis %d enable=%d\n",
|
|
|
|
|
functionName, portName, pAxis->axisNo_, value);
|
|
|
|
|
lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
startTime = time(NULL);
|
|
|
|
|
while(time(NULL) < startTime + 2.){
|
|
|
|
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
isOn = strtol(response, NULL, 10) != -3;
|
|
|
|
|
if(value == isOn){
|
|
|
|
|
pAxis->poll(&moving); // to update enable status
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
}
|
|
|
|
|
usleep(100);
|
|
|
|
|
}
|
|
|
|
|
errlogPrintf("PMAC: failed to switch axis %d enable status within 2 seconds\n",
|
|
|
|
|
pAxis->axisNo_);
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
|
|
|
"%s: Axis %d on controller %s %s on\n",
|
|
|
|
|
functionName, pAxis->axisNo_, portName, isOn ? "is" : "isn't");
|
|
|
|
|
usleep(100);
|
|
|
|
|
|
|
|
|
|
return pmacController::writeInt32(pasynUser, value);
|
|
|
|
|
if (isOn == value) {
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Switch On/Off
|
|
|
|
|
snprintf(command, sizeof(command), "M%2.2d14=%d", pAxis->axisNo_, value);
|
|
|
|
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
|
|
|
"%s: %s axis %d on controller %s\n",
|
|
|
|
|
functionName, value ? "Enable" : "Disable", pAxis->axisNo_, portName);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
|
|
|
|
|
// Wait for motor status to change
|
|
|
|
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
|
|
|
|
startTime = time(NULL);
|
|
|
|
|
while (time(NULL) < startTime + 2.) {
|
|
|
|
|
usleep(100);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
isOn = strtol(response, NULL, 10) != -3;
|
|
|
|
|
if(isOn == value) {
|
|
|
|
|
pAxis->poll(&moving); // to update enable status
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errlogPrintf(
|
|
|
|
|
"PMAC: Failed to %s axis %d on controller %s within 2 seconds\n",
|
|
|
|
|
value ? "enable" : "disable", pAxis->axisNo_, portName);
|
|
|
|
|
return asynError;
|
|
|
|
|
|
|
|
|
|
} else if (function == rereadEncoderPosition_) {
|
|
|
|
|
// This is not a command that can always be run when enabling a motor as it
|
|
|
|
|
// also causes relative encoders to reread a position necessitating
|
|
|
|
|
// recalibration. We only want it to run on absolute encoders. We also want
|
|
|
|
|
// it to be clear to instrument scientists, that power has to be cut to the
|
|
|
|
|
// motor, in order to reread the encoder as not all motors have breaks and
|
|
|
|
|
// they may start to move when disabled. For that reason, we don't
|
|
|
|
|
// automatically disable the motors to run the command and instead require
|
|
|
|
|
// that the scientists first disable the motor.
|
|
|
|
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if this is an aboslute encoder
|
|
|
|
|
snprintf(command, sizeof(command), "I%2.2X04", pAxis->axisNo_);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
|
|
|
|
|
int reponse_length = strlen(response);
|
|
|
|
|
if (reponse_length < 3) {
|
|
|
|
|
errlogPrintf(
|
|
|
|
|
"%s: Unexpected reponse '%s' from axis %d on controller %s while rereading encoder. Aborting...\n",
|
|
|
|
|
functionName, response, pAxis->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;
|
|
|
|
|
sscanf(response + (reponse_length - 3), "%2X", &encoder_id);
|
|
|
|
|
|
|
|
|
|
snprintf(command, sizeof(command), "P46", pAxis->axisNo_);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
int number_of_axes = strtol(response, NULL, 10);
|
|
|
|
|
|
|
|
|
|
if (encoder_id <= number_of_axes) {
|
|
|
|
|
errlogPrintf(
|
|
|
|
|
"%s: Trying to reread absolute encoder of axis %d on controller %s, but it is a relative encoder. Aborting...\n",
|
|
|
|
|
functionName, pAxis->axisNo_, portName);
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get Current Status
|
|
|
|
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
isOn = strtol(response, NULL, 10) != -3;
|
|
|
|
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
|
|
|
"%s: Axis %d on controller %s %s on\n",
|
|
|
|
|
functionName, pAxis->axisNo_, portName, isOn ? "is" : "isn't");
|
|
|
|
|
|
|
|
|
|
if (isOn) {
|
|
|
|
|
errlogPrintf(
|
|
|
|
|
"%s: First disable axis %d on controller %s to reread encoder position\n",
|
|
|
|
|
functionName, pAxis->axisNo_, portName);
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reread current absolute position if possible
|
|
|
|
|
sprintf(command, "M%2.2d=15", pAxis->axisNo_);
|
|
|
|
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
|
|
|
|
"%s: Rereading Absolute Encoder of axis %d on controller %s via command %s\n",
|
|
|
|
|
functionName, pAxis->axisNo_, portName, command);
|
|
|
|
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
|
|
|
|
|
|
|
|
|
// Switching on the axis while the rereading process is still ongoing
|
|
|
|
|
// causes it to fail. We currently have no way to check if it is actually
|
|
|
|
|
// finished, so we instead wait for 0.5 seconds.
|
|
|
|
|
usleep(500000);
|
|
|
|
|
|
|
|
|
|
// turn off parameter as finished rereading
|
|
|
|
|
// this will only be immediately noticed in the read back variable though
|
|
|
|
|
pAxis->setIntegerParam(function, 0);
|
|
|
|
|
|
|
|
|
|
return asynSuccess;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
return pmacController::writeInt32(pasynUser, value);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
|
|
|
@ -954,7 +1038,12 @@ asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
|
|
|
|
axStat = *value != -3;
|
|
|
|
|
int st = setIntegerParam(axisEnabled_, axStat);
|
|
|
|
|
callParamCallbacks();
|
|
|
|
|
} else if (function == rereadEncoderPositionRBV_) {
|
|
|
|
|
getIntegerParam(pAxis->axisNo_, rereadEncoderPosition_, value);
|
|
|
|
|
setIntegerParam(pAxis->axisNo_, rereadEncoderPositionRBV_, *value);
|
|
|
|
|
return callParamCallbacks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pmacController::readInt32(pasynUser, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|