- Many improvements to the MasterMACS driver
- Slowing down the pmac driver - Fixing a bug in the Nanotec driver which caused an IOC crash when the motor sends bad data
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
For documentation see the standard SINQ place for hardware documentation or
|
||||
Marcel Schildt
|
||||
|
||||
Mark Koennecke, March 2023
|
||||
Mark Koennecke, March-August 2023
|
||||
*/
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
@ -23,8 +24,6 @@
|
||||
#include "MasterMACSDriver.h"
|
||||
#include <epicsExport.h>
|
||||
|
||||
#define IDLEPOLL 60
|
||||
|
||||
#define CHECK_BIT(var,pos) ((var) & (1 << pos))
|
||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||
|
||||
@ -37,8 +36,8 @@
|
||||
*/
|
||||
MasterMACSController::MasterMACSController(const char *portName,
|
||||
const char *MasterMACSPortName,
|
||||
int
|
||||
numAxes):SINQController
|
||||
int numAxes,
|
||||
int idlePoll, int busyPoll):SINQController
|
||||
(portName, MasterMACSPortName, numAxes)
|
||||
{
|
||||
asynStatus status;
|
||||
@ -67,7 +66,9 @@ MasterMACSController::MasterMACSController(const char *portName,
|
||||
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
|
||||
callParamCallbacks();
|
||||
|
||||
startPoller(1000. / 1000., IDLEPOLL, 2);
|
||||
startPoller(busyPoll/1000., idlePoll/1000., 1);
|
||||
setIdlePollPeriod(idlePoll/1000.);
|
||||
setMovingPollPeriod(busyPoll/1000.);
|
||||
}
|
||||
|
||||
|
||||
@ -76,13 +77,15 @@ MasterMACSController::MasterMACSController(const char *portName,
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] MasterMACSPortName The name of the drvAsynIPPPort that was created previously to connect to the MasterMACS controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
* \param[in] idlePoll Poll interval when idle in microseconds
|
||||
* \param[in] busyPoll Poll interval when moving in microSeconds
|
||||
*/
|
||||
extern "C" int
|
||||
MasterMACSCreateController(const char *portName,
|
||||
const char *MasterMACSPortName, int numAxes)
|
||||
const char *MasterMACSPortName, int numAxes, int idlePoll, int busyPoll)
|
||||
{
|
||||
MasterMACSController *pMasterMACSController
|
||||
= new MasterMACSController(portName, MasterMACSPortName, numAxes);
|
||||
= new MasterMACSController(portName, MasterMACSPortName, numAxes, idlePoll, busyPoll);
|
||||
pMasterMACSController = NULL;
|
||||
return (asynSuccess);
|
||||
}
|
||||
@ -147,7 +150,7 @@ asynStatus
|
||||
/* read with a short timeout in order to remove duplicate messages
|
||||
* from the line. This also serves to slow down communication
|
||||
*/
|
||||
pasynOctetSyncIO->read(pasynUserController_, mmacsResponse, 35, .4, &in, &reason);
|
||||
pasynOctetSyncIO->read(pasynUserController_, mmacsResponse, 35, .05, &in, &reason);
|
||||
|
||||
/* pack data for MasterMACS */
|
||||
len = strlen(command) + 6;
|
||||
@ -166,7 +169,9 @@ asynStatus
|
||||
/* 0x03 is appended by asyn */
|
||||
|
||||
/* send the stuff away ... */
|
||||
if(debug) {
|
||||
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
|
||||
}
|
||||
|
||||
status =
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
|
||||
@ -175,8 +180,8 @@ asynStatus
|
||||
if (status != asynSuccess) {
|
||||
if (axis != NULL) {
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"Lost connection to motor controller, reason %d",
|
||||
reason);
|
||||
"Lost connection to motor controller,a axis %d, reason %d",
|
||||
axisNo, reason);
|
||||
axis->updateMsgTxtFromDriver
|
||||
("Lost connection to motor controller");
|
||||
return status;
|
||||
@ -252,6 +257,8 @@ asynStatus
|
||||
char command[64] = { 0 };
|
||||
char response[64] = { 0 };
|
||||
int devStatus;
|
||||
bool moving;
|
||||
time_t startTime;
|
||||
|
||||
pAxis = (MasterMACSAxis *) this->getAxis(pasynUser);
|
||||
if (!pAxis) {
|
||||
@ -268,6 +275,7 @@ asynStatus
|
||||
*/
|
||||
devStatus = pAxis->readStatus();
|
||||
if(devStatus < 900){
|
||||
errlogPrintf("MMACS: Motor %d not ready to switch on\n", pAxis->axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
if (value == 1 && !pAxis->isOn(devStatus) ) {
|
||||
@ -280,62 +288,34 @@ asynStatus
|
||||
/* actually enable */
|
||||
sprintf(command, "%dS04=1", pAxis->axisNo_);
|
||||
status = transactController(pAxis->axisNo_, command, response);
|
||||
} else {
|
||||
if(pAxis->isOn(devStatus)) {
|
||||
} else if(pAxis->isOn(devStatus)) {
|
||||
// only send command when necessary
|
||||
sprintf(command, "%dS04=0", pAxis->axisNo_);
|
||||
status = transactController(pAxis->axisNo_, command, response);
|
||||
}
|
||||
} else {
|
||||
// nothing to do
|
||||
return status;
|
||||
}
|
||||
if (status == asynSuccess) {
|
||||
pAxis->updateMsgTxtFromDriver("");
|
||||
} else {
|
||||
errlogPrintf("Failure to enable or disable axis %d",
|
||||
errlogPrintf("MMACS: Failure to enable or disable axis %d",
|
||||
pAxis->axisNo_);
|
||||
}
|
||||
}
|
||||
return asynMotorController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
asynStatus
|
||||
MasterMACSController::readInt32(asynUser * pasynUser,
|
||||
epicsInt32 * value)
|
||||
{
|
||||
|
||||
int function = pasynUser->reason;
|
||||
MasterMACSAxis *pAxis = NULL;
|
||||
char command[128] = { 0 }, reply[128] = {
|
||||
0}, *pPtr;
|
||||
float fval;
|
||||
int devStatus, isOn, comStatus;
|
||||
|
||||
pAxis = (MasterMACSAxis *) (this->getAxis(pasynUser));
|
||||
if (!pAxis) {
|
||||
return asynError;
|
||||
}
|
||||
if (function == axisEnabled_) {
|
||||
// Read the overall status of this motor */
|
||||
sprintf(command, "%dR10", pAxis->axisNo_);
|
||||
comStatus = transactController(pAxis->axisNo_, command, reply);
|
||||
if (comStatus == asynError) {
|
||||
return asynError;
|
||||
}
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &fval);
|
||||
devStatus = (int) fval;
|
||||
} else {
|
||||
devStatus = 0;
|
||||
errlogPrintf(" Bad reply %s when trying to read motor status %d\n", reply, pAxis->axisNo_);
|
||||
}
|
||||
isOn = pAxis->isOn(devStatus);
|
||||
/* errlogPrintf("isOn in readInt32: %d, devStatus = %d\n", isOn, devStatus); */
|
||||
setIntegerParam(axisEnabled_, isOn);
|
||||
*value = isOn;
|
||||
callParamCallbacks();
|
||||
startTime = time(NULL);
|
||||
while(time(NULL) < startTime + 2.){
|
||||
// wait for the change to happen
|
||||
devStatus = pAxis->readStatus();
|
||||
if(pAxis->isOn(devStatus) == value){
|
||||
pAxis->active = true;
|
||||
pAxis->poll(&moving); // to update the Enable_RBV field
|
||||
return asynSuccess;
|
||||
}
|
||||
return asynMotorController::readInt32(pasynUser, value);
|
||||
usleep(200);
|
||||
}
|
||||
errlogPrintf("MMACS: Failed to enable motor %d within 2 seconds\n", pAxis->axisNo_);
|
||||
}
|
||||
return asynMotorController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
|
||||
@ -351,9 +331,8 @@ MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(p
|
||||
pC_
|
||||
(pC)
|
||||
{
|
||||
next_poll = -1;
|
||||
hasStarted = false;
|
||||
errorReported = 1;
|
||||
active = false;
|
||||
}
|
||||
|
||||
/** Reports on status of the axis
|
||||
@ -373,17 +352,27 @@ int MasterMACSAxis::readStatus()
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN], *pPtr;
|
||||
float fval;
|
||||
int devStatus, status;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* The MasterMACS sends invalid responses with a low frequency.
|
||||
* Therefore I send cached status responses in such a case in order
|
||||
* to help the logic evrywhere else in the code.
|
||||
*/
|
||||
sprintf(command, "%dR10", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
if (status == asynError) {
|
||||
return -1000;
|
||||
return oldStatus;
|
||||
}
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &fval);
|
||||
devStatus = (int) fval;
|
||||
return devStatus;
|
||||
oldStatus = (int) fval;
|
||||
return oldStatus;
|
||||
} else {
|
||||
errlogPrintf("MMACS: invalid status reponse %s on axis %d\n", reply, axisNo_);
|
||||
return oldStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -463,9 +452,8 @@ asynStatus
|
||||
return status;
|
||||
}
|
||||
hasStarted = true;
|
||||
next_poll = -1;
|
||||
homing = 0;
|
||||
errorReported = 0;
|
||||
active = true;
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -496,14 +484,13 @@ asynStatus
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
updateMsgTxtFromDriver("");
|
||||
errorReported = 0;
|
||||
|
||||
|
||||
sprintf(command, "%dS00=9", axisNo_);
|
||||
homing = 1;
|
||||
next_poll = -1;
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
hasStarted = true;
|
||||
active = true;
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -525,7 +512,6 @@ asynStatus MasterMACSAxis::stop(double acceleration)
|
||||
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
if (errorReported == 0) {
|
||||
devStatus = readStatus();
|
||||
if(!CHECK_BIT(devStatus, 10)) {
|
||||
// only try to stop when running ...
|
||||
@ -533,8 +519,6 @@ asynStatus MasterMACSAxis::stop(double acceleration)
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
errorReported = 1;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -567,21 +551,33 @@ asynStatus MasterMACSAxis::setClosedLoop(bool closedLoop)
|
||||
asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
{
|
||||
asynStatus comStatus = asynSuccess;
|
||||
char command[COMLEN], reply[COMLEN], *pPtr;
|
||||
char command[COMLEN], reply[COMLEN], *pPtr, buffer[80];
|
||||
float errStatus;
|
||||
unsigned int errCode, derCode, devStatus;
|
||||
|
||||
// protect against excessive polling
|
||||
if (time(NULL) < next_poll) {
|
||||
struct tm* tm_info;
|
||||
time_t timer;
|
||||
|
||||
/*
|
||||
* EPICS always polls all motors on a controller when one motor is active.
|
||||
* In order to reduce load on the controller we check if we are active and
|
||||
* if not return old stuff
|
||||
*/
|
||||
if(active == false && time(NULL) < lastPoll + pC_->idlePollPeriod_) {
|
||||
*moving = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
timer = time(NULL);
|
||||
tm_info = localtime(&timer);
|
||||
|
||||
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
errlogPrintf("poll called at %s on axis %d \n",
|
||||
buffer, axisNo_ );
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(command, "%dR12", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
@ -595,12 +591,20 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
} else {
|
||||
errlogPrintf("Received malformed reply: Axis %d, reply %s\n",
|
||||
axisNo_, reply + 4);
|
||||
return asynError;
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
setDoubleParam(pC_->motorPosition_, position * 1000.);
|
||||
setDoubleParam(pC_->motorEncoderPosition_, position * 1000.);
|
||||
|
||||
/*
|
||||
* keep track of position in order to check for a stuck motor later
|
||||
*/
|
||||
if(ABS(position - oldPosition) > 1){
|
||||
oldPosition = position;
|
||||
lastPositionUpdate = time(NULL);
|
||||
}
|
||||
|
||||
// Read the overall status of this motor */
|
||||
devStatus = readStatus();
|
||||
@ -614,6 +618,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
position, devStatus);
|
||||
}
|
||||
|
||||
setIntegerParam(pC_->axisEnabled_, isOn(devStatus));
|
||||
if (!isOn(devStatus)) {
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Motor disabled");
|
||||
@ -628,7 +633,6 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
if (!hasStarted) {
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
next_poll = time(NULL) + IDLEPOLL;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
@ -638,16 +642,21 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
if (!CHECK_BIT(devStatus, 10)) {
|
||||
/* we are still creeping along .... */
|
||||
*moving = true;
|
||||
next_poll = -1;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
if(time(NULL) > lastPositionUpdate + 60) {
|
||||
// we are detecting a stuck motor
|
||||
errlogPrintf("MMACS: axis %d is STUCK!!\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis STUCK!!");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
}
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
||||
/*we are done moving */
|
||||
*moving = false;
|
||||
active = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
next_poll = time(NULL) + IDLEPOLL;
|
||||
|
||||
/* when homing, set the proper flag */
|
||||
if (homing) {
|
||||
@ -685,9 +694,15 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
goto skip;
|
||||
}
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &errStatus);
|
||||
errCode = (unsigned int) errStatus;
|
||||
|
||||
} else {
|
||||
errlogPrintf("MMACS: axis %d received invalid reply asking for error code \n", axisNo_);
|
||||
updateMsgTxtFromDriver("Invalid reply asking error code R11");
|
||||
errCode = 0;
|
||||
goto skip;
|
||||
}
|
||||
sprintf(command, "%dR18", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus == asynError) {
|
||||
@ -695,8 +710,14 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
goto skip;
|
||||
}
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &errStatus);
|
||||
derCode = (unsigned int) errStatus;
|
||||
} else {
|
||||
errlogPrintf("MMACS: malformed reply for R18: %s, on axis %d\n", reply, axisNo_);
|
||||
derCode = 0;
|
||||
updateMsgTxtFromDriver("Invalid reply asking error code R18");
|
||||
}
|
||||
|
||||
if(debug) {
|
||||
errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_,
|
||||
@ -784,18 +805,28 @@ static const iocshArg
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg2 = { "Number of axes", iocshArgInt };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg3 = { "idlePoll", iocshArgInt };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg4 = { "busyPoll", iocshArgInt };
|
||||
|
||||
|
||||
static const iocshArg *const
|
||||
MasterMACSCreateControllerArgs[] = { &MasterMACSCreateControllerArg0,
|
||||
&MasterMACSCreateControllerArg1,
|
||||
&MasterMACSCreateControllerArg2
|
||||
&MasterMACSCreateControllerArg2,
|
||||
&MasterMACSCreateControllerArg3,
|
||||
&MasterMACSCreateControllerArg4
|
||||
};
|
||||
|
||||
static const iocshFuncDef
|
||||
MasterMACSCreateControllerDef =
|
||||
{ "MasterMACSCreateController", 3, MasterMACSCreateControllerArgs };
|
||||
{ "MasterMACSCreateController", 5, MasterMACSCreateControllerArgs };
|
||||
static void MasterMACSCreateContollerCallFunc(const iocshArgBuf * args)
|
||||
{
|
||||
MasterMACSCreateController(args[0].sval, args[1].sval, args[2].ival);
|
||||
MasterMACSCreateController(args[0].sval, args[1].sval, args[2].ival,
|
||||
args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,13 +33,18 @@ private:
|
||||
MasterMACSController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
double position;
|
||||
double oldPosition;
|
||||
time_t lastPositionUpdate;
|
||||
int homing;
|
||||
time_t next_poll;
|
||||
int errorReported;
|
||||
int hasStarted; /* The motor status is invalid if the thing has not run once */
|
||||
int isOn(int axisStatus);
|
||||
int readStatus();
|
||||
int errorCodeFound;
|
||||
int oldStatus;
|
||||
|
||||
bool active;
|
||||
time_t lastPoll;
|
||||
|
||||
friend class MasterMACSController;
|
||||
};
|
||||
|
||||
@ -49,7 +54,8 @@ friend class MasterMACSController;
|
||||
|
||||
class MasterMACSController : public SINQController {
|
||||
public:
|
||||
MasterMACSController(const char *portName, const char *MasterMACSPortName, int numAxes);
|
||||
MasterMACSController(const char *portName, const char *MasterMACSPortName,
|
||||
int numAxes, int idlePoll, int busyPoll);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
MasterMACSAxis* getAxis(asynUser *pasynUser);
|
||||
@ -58,9 +64,6 @@ public:
|
||||
// overloaded because we want to enable/disable the motor
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
|
||||
// overloaded because we want to read the axis state
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
|
||||
friend class MasterMACSAxis;
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
|
@ -377,7 +377,7 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
asynStatus comStatus;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
char *pPtr;
|
||||
int posVal, statVal;
|
||||
int posVal, statVal, count = 0;
|
||||
double lowLim, highLim;
|
||||
|
||||
|
||||
@ -393,11 +393,12 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
if(comStatus) goto skip;
|
||||
|
||||
pPtr = strchr(reply,'C');
|
||||
pPtr++;
|
||||
if(pPtr){
|
||||
posVal = atoi(pPtr);
|
||||
} else {
|
||||
errlogPrintf("Invalid response %s for #C received for axis %d\n", reply, axisNo_);
|
||||
pPtr++;
|
||||
count = sscanf(pPtr,"%d", &posVal);
|
||||
}
|
||||
if(pPtr == NULL || count < 1) {
|
||||
errlogPrintf("Invalid response %s for #C received for axis %d, address %d\n", reply, axisNo_, busAddress);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
@ -412,11 +413,12 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
if(comStatus) goto skip;
|
||||
|
||||
pPtr = strchr(reply,'$');
|
||||
pPtr++;
|
||||
if(pPtr) {
|
||||
statVal = atoi(pPtr);
|
||||
} else {
|
||||
errlogPrintf("Invalid response %s for #$ received for axis %d\n", reply, axisNo_);
|
||||
pPtr++;
|
||||
count = sscanf(pPtr, "%d", &statVal);
|
||||
}
|
||||
if(pPtr == NULL || count < 1) {
|
||||
errlogPrintf("Invalid response %s for #$ received for axis %d busAddress %d\n", reply, axisNo_, busAddress);
|
||||
return asynError;
|
||||
}
|
||||
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
||||
|
@ -185,7 +185,7 @@ asynStatus pmacAxis::getAxisInitialStatus(void) {
|
||||
cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||
if (cmdStatus) {
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: Error: enaabling axis %d failed.\n", functionName,
|
||||
"%s: Error: enabling axis %d failed.\n", functionName,
|
||||
axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
@ -911,11 +911,6 @@ asynStatus pmacV3Axis::poll(bool *moving) {
|
||||
static const char *functionName = "pmacV3Axis::poll";
|
||||
char message[132];
|
||||
|
||||
// Protect against excessive polling
|
||||
if (time(NULL) < next_poll) {
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
sprintf(message, "%s: Polling axis: %d", functionName, this->axisNo_);
|
||||
pC_->debugFlow(message);
|
||||
|
||||
@ -927,12 +922,6 @@ asynStatus pmacV3Axis::poll(bool *moving) {
|
||||
functionName, pC_->portName, axisNo_);
|
||||
}
|
||||
|
||||
if (*moving) {
|
||||
next_poll = time(NULL) + BUSYPOLL;
|
||||
} else {
|
||||
next_poll = time(NULL) + IDLEPOLL;
|
||||
}
|
||||
|
||||
callParamCallbacks();
|
||||
return status ? asynError : asynSuccess;
|
||||
}
|
||||
@ -966,7 +955,7 @@ asynStatus pmacV3Axis::getAxisStatus(bool *moving) {
|
||||
pmacV3Controller *p3C_ = (pmacV3Controller *)pC_;
|
||||
IsEnable = axStat != -3;
|
||||
|
||||
asynStatus st = setIntegerParam(p3C_->axisEnabled_, axStat > -1);
|
||||
asynStatus st = setIntegerParam(p3C_->axisEnabled_, IsEnable);
|
||||
cmdStatus = cmdStatus > st ? cmdStatus : st;
|
||||
|
||||
int direction = 0;
|
||||
@ -993,7 +982,8 @@ asynStatus pmacV3Axis::getAxisStatus(bool *moving) {
|
||||
previous_direction_ = direction;
|
||||
|
||||
/* are we done? */
|
||||
if ((axStat == 0 || axStat < 0) && starting == 0) {
|
||||
/* if ((axStat == 0 || axStat < 0) && starting == 0) { */
|
||||
if (axStat == 0 && starting == 0) {
|
||||
done = 1;
|
||||
} else {
|
||||
starting = 0;
|
||||
|
@ -27,8 +27,8 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
@ -300,6 +300,8 @@ asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, ch
|
||||
}
|
||||
}
|
||||
|
||||
usleep(20); // slow down communication somewhat
|
||||
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER, "%s: response: %s\n", functionName, response);
|
||||
debugFlow("Received: ");
|
||||
debugFlow(response);
|
||||
@ -847,6 +849,8 @@ asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||
char command[64] = {0};
|
||||
char response[64] = {0};
|
||||
int isOn;
|
||||
time_t startTime;
|
||||
bool moving;
|
||||
static const char *functionName = "pmacV3Controller::writeInt32";
|
||||
|
||||
debugFlow(functionName);
|
||||
@ -864,18 +868,32 @@ asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||
// only send commands when a state change is necessary
|
||||
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
||||
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||
isOn = strtol(response, NULL, 10);
|
||||
if(value == 1 && isOn == 0) {
|
||||
sprintf(command, "M%2.2d=15\n", pAxis->axisNo_);
|
||||
lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||
isOn = strtol(response, NULL, 10) != -3;
|
||||
if(value == 1 && isOn) {
|
||||
sprintf(command, "M%2.2d=15", pAxis->axisNo_);
|
||||
// lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||
}
|
||||
sprintf(command, "M%2.2d14=%d\n", pAxis->axisNo_, value);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -884,7 +902,7 @@ asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||
|
||||
asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||
|
||||
int function = pasynUser->reason;
|
||||
int function = pasynUser->reason, axStat;
|
||||
asynStatus status = asynError;
|
||||
pmacV3Axis *pAxis = NULL;
|
||||
static const char *functionName = "pmacV3Controller::readInt32";
|
||||
@ -901,8 +919,8 @@ asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
||||
status = this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||
*value = strtol(response, NULL, 10);
|
||||
|
||||
int st = setIntegerParam(axisEnabled_, *value);
|
||||
axStat = *value != -3;
|
||||
int st = setIntegerParam(axisEnabled_, axStat);
|
||||
callParamCallbacks();
|
||||
}
|
||||
return pmacController::readInt32(pasynUser, value);
|
||||
|
9
testhuber/db/asynRecord.db
Normal file
9
testhuber/db/asynRecord.db
Normal file
@ -0,0 +1,9 @@
|
||||
record(asyn,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynRecordDevice")
|
||||
field(PORT,"$(PORT)")
|
||||
field(ADDR,"$(ADDR)")
|
||||
field(OMAX,"$(OMAX)")
|
||||
field(IMAX,"$(IMAX)")
|
||||
}
|
||||
|
23
testhuber/db/basic_asyn_motor.db
Normal file
23
testhuber/db/basic_asyn_motor.db
Normal file
@ -0,0 +1,23 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
21
testhuber/db/basic_motor.db
Normal file
21
testhuber/db/basic_motor.db
Normal file
@ -0,0 +1,21 @@
|
||||
grecord(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"#C$(C) S$(S) @")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
}
|
||||
|
18
testhuber/db/motorMessage.db
Normal file
18
testhuber/db/motorMessage.db
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)m$(N)-Resolution"){
|
||||
field(DESC,"m$(N) Resolution")
|
||||
field(DOL,"$(P)m$(N).MRES CP MS")
|
||||
field(OMSL,"closed_loop")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
|
||||
field(PREC,"3")
|
||||
}
|
14
testhuber/db/pmacV3.db
Normal file
14
testhuber/db/pmacV3.db
Normal file
@ -0,0 +1,14 @@
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
47
testhuber/db/sinq_asyn_motor.db
Normal file
47
testhuber/db/sinq_asyn_motor.db
Normal file
@ -0,0 +1,47 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
}
|
||||
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "5 second")
|
||||
}
|
||||
|
33
testhuber/huber.cmd
Executable file
33
testhuber/huber.cmd
Executable file
@ -0,0 +1,33 @@
|
||||
#!/ioc/tools/iocsh
|
||||
|
||||
require motorHuber,brambilla_m
|
||||
|
||||
# epicsEnvSet("TOP","/ioc/sinq-ioc/boa-ioc")
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testhuber")
|
||||
|
||||
epicsEnvSet("STREAM_PROTOCOL_PATH","./db")
|
||||
epicsEnvSet("MOTOR",".")
|
||||
|
||||
# require autosave, koennecke
|
||||
|
||||
# Configure IP Port
|
||||
drvAsynIPPortConfigure("Huber1", "129.129.195.128:1234",0,0,0)
|
||||
|
||||
# Configure Controller
|
||||
asynOctetSetInputEos( "Huber1", -1, "\r")
|
||||
asynOctetSetOutputEos("Huber1", -1, "\r")
|
||||
|
||||
SMC9300CreateController("SMC1", "Huber1", 5, 50, 2000)
|
||||
|
||||
dbLoadTemplate "motor.substitutions.smc9300"
|
||||
|
||||
dbLoadRecords("$(TOP)/db/asynRecord.db","P=SQ:BOA:optics:,R=mcu,PORT=Huber1,ADDR=0,OMAX=80,IMAX=80")
|
||||
|
||||
|
||||
#--------------------------------- restore autosave
|
||||
#set_requestfile_path("$(TOP)", "")
|
||||
#set_savefile_path("$(TOP)/autosave")
|
||||
#save_restoreSet_Debug(0)
|
||||
#set_pass0_restoreFile("$(TOP)/autosave/huber.sav","")
|
||||
#set_pass1_restoreFile("$(TOP)/autosave/huber.sav","")
|
19
testhuber/motor.substitutions.smc9300
Normal file
19
testhuber/motor.substitutions.smc9300
Normal file
@ -0,0 +1,19 @@
|
||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR,DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, RDBD, INIT}
|
||||
{SQ:BOA:optics:, 1, "trans1","asynMotor", SMC1, 1, "translation 1",mm, Pos, 200, 10, 20, 0, 1, .2, 0.0001, 4, 150, -150, 0.1, ""}
|
||||
{SQ:BOA:optics:, 2, "lift1", "asynMotor", SMC1, 2, "lift 1", mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 100, 0, 0.1, ""}
|
||||
{SQ:BOA:optics:, 3, "trans2","asynMotor", SMC1, 3, "translation 2",mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 150, -150, 0.1, ""}
|
||||
{SQ:BOA:optics:, 4, "lift2", "asynMotor", SMC1, 4, "lift 2" ,mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 100, 0, 0.1, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{SQ:BOA:optics:, 1, "trans1", SMC1}
|
||||
{SQ:BOA:optics:, 2, "lift1", SMC1}
|
||||
{SQ:BOA:optics:, 3, "trans2", SMC1}
|
||||
{SQ:BOA:optics:, 4, "lift2", SMC1}
|
||||
}
|
@ -21,13 +21,15 @@ set_pass1_restoreFile("$(TOP)/autosave/test.sav","")
|
||||
#asynSetTraceMask("macs1", 0, 255)
|
||||
#drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0)
|
||||
drvAsynIPPortConfigure("macs1", "Marcel1--MACS:1917")
|
||||
MasterMACSCreateController("mota","macs1",7)
|
||||
MasterMACSCreateController("mota","macs1",7, 500, 10000)
|
||||
MasterMACSCreateAxis("mota",5)
|
||||
MasterMACSCreateAxis("mota",6)
|
||||
|
||||
dbLoadTemplate "mmacs2.sub"
|
||||
|
||||
iocInit()
|
||||
setMovingPollPeriod("mota", .5)
|
||||
setIdlePollPeriod("mota", 10. )
|
||||
|
||||
create_monitor_set("test.req", 10, "")
|
||||
|
||||
|
Reference in New Issue
Block a user