- 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:
2023-08-28 15:01:48 +02:00
parent 7a81e2c5a0
commit e3ac2962f5
14 changed files with 928 additions and 698 deletions

View File

@ -3,7 +3,7 @@
For documentation see the standard SINQ place for hardware documentation or For documentation see the standard SINQ place for hardware documentation or
Marcel Schildt Marcel Schildt
Mark Koennecke, March 2023 Mark Koennecke, March-August 2023
*/ */
@ -13,6 +13,7 @@
#include <math.h> #include <math.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include <iocsh.h> #include <iocsh.h>
#include <epicsThread.h> #include <epicsThread.h>
@ -23,8 +24,6 @@
#include "MasterMACSDriver.h" #include "MasterMACSDriver.h"
#include <epicsExport.h> #include <epicsExport.h>
#define IDLEPOLL 60
#define CHECK_BIT(var,pos) ((var) & (1 << pos)) #define CHECK_BIT(var,pos) ((var) & (1 << pos))
#define ABS(x) (x < 0 ? -(x) : (x)) #define ABS(x) (x < 0 ? -(x) : (x))
@ -37,8 +36,8 @@
*/ */
MasterMACSController::MasterMACSController(const char *portName, MasterMACSController::MasterMACSController(const char *portName,
const char *MasterMACSPortName, const char *MasterMACSPortName,
int int numAxes,
numAxes):SINQController int idlePoll, int busyPoll):SINQController
(portName, MasterMACSPortName, numAxes) (portName, MasterMACSPortName, numAxes)
{ {
asynStatus status; asynStatus status;
@ -66,8 +65,10 @@ MasterMACSController::MasterMACSController(const char *portName,
createParam(EnableAxisString, asynParamInt32, &enableAxis_); createParam(EnableAxisString, asynParamInt32, &enableAxis_);
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_); createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
callParamCallbacks(); 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] 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] 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] 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 extern "C" int
MasterMACSCreateController(const char *portName, MasterMACSCreateController(const char *portName,
const char *MasterMACSPortName, int numAxes) const char *MasterMACSPortName, int numAxes, int idlePoll, int busyPoll)
{ {
MasterMACSController *pMasterMACSController MasterMACSController *pMasterMACSController
= new MasterMACSController(portName, MasterMACSPortName, numAxes); = new MasterMACSController(portName, MasterMACSPortName, numAxes, idlePoll, busyPoll);
pMasterMACSController = NULL; pMasterMACSController = NULL;
return (asynSuccess); return (asynSuccess);
} }
@ -147,7 +150,7 @@ asynStatus
/* read with a short timeout in order to remove duplicate messages /* read with a short timeout in order to remove duplicate messages
* from the line. This also serves to slow down communication * 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 */ /* pack data for MasterMACS */
len = strlen(command) + 6; len = strlen(command) + 6;
@ -166,7 +169,9 @@ asynStatus
/* 0x03 is appended by asyn */ /* 0x03 is appended by asyn */
/* send the stuff away ... */ /* send the stuff away ... */
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command); if(debug) {
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
}
status = status =
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData, pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
@ -175,8 +180,8 @@ asynStatus
if (status != asynSuccess) { if (status != asynSuccess) {
if (axis != NULL) { if (axis != NULL) {
errlogSevPrintf(errlogMajor, errlogSevPrintf(errlogMajor,
"Lost connection to motor controller, reason %d", "Lost connection to motor controller,a axis %d, reason %d",
reason); axisNo, reason);
axis->updateMsgTxtFromDriver axis->updateMsgTxtFromDriver
("Lost connection to motor controller"); ("Lost connection to motor controller");
return status; return status;
@ -252,6 +257,8 @@ asynStatus
char command[64] = { 0 }; char command[64] = { 0 };
char response[64] = { 0 }; char response[64] = { 0 };
int devStatus; int devStatus;
bool moving;
time_t startTime;
pAxis = (MasterMACSAxis *) this->getAxis(pasynUser); pAxis = (MasterMACSAxis *) this->getAxis(pasynUser);
if (!pAxis) { if (!pAxis) {
@ -268,9 +275,10 @@ asynStatus
*/ */
devStatus = pAxis->readStatus(); devStatus = pAxis->readStatus();
if(devStatus < 900){ if(devStatus < 900){
errlogPrintf("MMACS: Motor %d not ready to switch on\n", pAxis->axisNo_);
return asynError; return asynError;
} }
if (value == 1 && !pAxis->isOn(devStatus) ) { if (value == 1 && !pAxis->isOn(devStatus) ) {
/* download parameters, does not work as of now */ /* download parameters, does not work as of now */
/* /*
sprintf(command, "%dS85=1.", pAxis->axisNo_); sprintf(command, "%dS85=1.", pAxis->axisNo_);
@ -280,64 +288,36 @@ asynStatus
/* actually enable */ /* actually enable */
sprintf(command, "%dS04=1", pAxis->axisNo_); sprintf(command, "%dS04=1", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response); status = transactController(pAxis->axisNo_, command, response);
} else { } else if(pAxis->isOn(devStatus)) {
if(pAxis->isOn(devStatus)) { // only send command when necessary
// only send command when necessary sprintf(command, "%dS04=0", pAxis->axisNo_);
sprintf(command, "%dS04=0", pAxis->axisNo_); status = transactController(pAxis->axisNo_, command, response);
status = transactController(pAxis->axisNo_, command, response); } else {
} // nothing to do
return status;
} }
if (status == asynSuccess) { if (status == asynSuccess) {
pAxis->updateMsgTxtFromDriver(""); pAxis->updateMsgTxtFromDriver("");
} else { } else {
errlogPrintf("Failure to enable or disable axis %d", errlogPrintf("MMACS: Failure to enable or disable axis %d",
pAxis->axisNo_); pAxis->axisNo_);
} }
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;
}
usleep(200);
}
errlogPrintf("MMACS: Failed to enable motor %d within 2 seconds\n", pAxis->axisNo_);
} }
return asynMotorController::writeInt32(pasynUser, value); 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();
return asynSuccess;
}
return asynMotorController::readInt32(pasynUser, value);
}
// These are the MasterMACSAxis methods // These are the MasterMACSAxis methods
@ -351,9 +331,8 @@ MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(p
pC_ pC_
(pC) (pC)
{ {
next_poll = -1;
hasStarted = false; hasStarted = false;
errorReported = 1; active = false;
} }
/** Reports on status of the axis /** Reports on status of the axis
@ -373,17 +352,27 @@ int MasterMACSAxis::readStatus()
{ {
char command[COMLEN], reply[COMLEN], *pPtr; char command[COMLEN], reply[COMLEN], *pPtr;
float fval; 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_); sprintf(command, "%dR10", axisNo_);
status = pC_->transactController(axisNo_, command, reply); status = pC_->transactController(axisNo_, command, reply);
if (status == asynError) { if (status == asynError) {
return -1000; return oldStatus;
} }
pPtr = strstr(reply, "="); pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval); if(pPtr) {
devStatus = (int) fval; sscanf(pPtr + 1, "%f", &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; return status;
} }
hasStarted = true; hasStarted = true;
next_poll = -1;
homing = 0; homing = 0;
errorReported = 0; active = true;
return status; return status;
} }
@ -496,14 +484,13 @@ asynStatus
setIntegerParam(pC_->motorStatusProblem_, false); setIntegerParam(pC_->motorStatusProblem_, false);
updateMsgTxtFromDriver(""); updateMsgTxtFromDriver("");
errorReported = 0;
sprintf(command, "%dS00=9", axisNo_); sprintf(command, "%dS00=9", axisNo_);
homing = 1; homing = 1;
next_poll = -1;
status = pC_->transactController(axisNo_, command, reply); status = pC_->transactController(axisNo_, command, reply);
hasStarted = true; hasStarted = true;
active = true;
return status; return status;
} }
@ -525,16 +512,13 @@ asynStatus MasterMACSAxis::stop(double acceleration)
memset(command, 0, COMLEN * sizeof(char)); memset(command, 0, COMLEN * sizeof(char));
if (errorReported == 0) { devStatus = readStatus();
devStatus = readStatus(); if(!CHECK_BIT(devStatus, 10)) {
if(!CHECK_BIT(devStatus, 10)) { // only try to stop when running ...
// only try to stop when running ... sprintf(command, "%dS00=8", axisNo_);
sprintf(command, "%dS00=8", axisNo_); status = pC_->transactController(axisNo_, command, reply);
status = pC_->transactController(axisNo_, command, reply); errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_); updateMsgTxtFromDriver("Axis interrupted");
updateMsgTxtFromDriver("Axis interrupted");
errorReported = 1;
}
} }
return status; return status;
} }
@ -567,21 +551,33 @@ asynStatus MasterMACSAxis::setClosedLoop(bool closedLoop)
asynStatus MasterMACSAxis::poll(bool * moving) asynStatus MasterMACSAxis::poll(bool * moving)
{ {
asynStatus comStatus = asynSuccess; asynStatus comStatus = asynSuccess;
char command[COMLEN], reply[COMLEN], *pPtr; char command[COMLEN], reply[COMLEN], *pPtr, buffer[80];
float errStatus; float errStatus;
unsigned int errCode, derCode, devStatus; unsigned int errCode, derCode, devStatus;
// protect against excessive polling struct tm* tm_info;
if (time(NULL) < next_poll) { time_t timer;
*moving = false;
return asynSuccess; /*
* 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); setIntegerParam(pC_->motorStatusProblem_, false);
memset(command, 0, COMLEN * sizeof(char)); memset(command, 0, COMLEN * sizeof(char));
// Read the current motor position // Read the current motor position
sprintf(command, "%dR12", axisNo_); sprintf(command, "%dR12", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply); comStatus = pC_->transactController(axisNo_, command, reply);
@ -595,12 +591,20 @@ asynStatus MasterMACSAxis::poll(bool * moving)
} else { } else {
errlogPrintf("Received malformed reply: Axis %d, reply %s\n", errlogPrintf("Received malformed reply: Axis %d, reply %s\n",
axisNo_, reply + 4); axisNo_, reply + 4);
return asynError; comStatus = asynError;
goto skip;
} }
setDoubleParam(pC_->motorPosition_, position * 1000.); setDoubleParam(pC_->motorPosition_, position * 1000.);
setDoubleParam(pC_->motorEncoderPosition_, 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 */ // Read the overall status of this motor */
devStatus = readStatus(); devStatus = readStatus();
@ -614,6 +618,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
position, devStatus); position, devStatus);
} }
setIntegerParam(pC_->axisEnabled_, isOn(devStatus));
if (!isOn(devStatus)) { if (!isOn(devStatus)) {
setIntegerParam(pC_->motorStatusProblem_, true); setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled"); updateMsgTxtFromDriver("Motor disabled");
@ -628,7 +633,6 @@ asynStatus MasterMACSAxis::poll(bool * moving)
if (!hasStarted) { if (!hasStarted) {
*moving = false; *moving = false;
setIntegerParam(pC_->motorStatusDone_, true); setIntegerParam(pC_->motorStatusDone_, true);
next_poll = time(NULL) + IDLEPOLL;
goto skip; goto skip;
} }
@ -636,18 +640,23 @@ asynStatus MasterMACSAxis::poll(bool * moving)
* We may have a valid status bit... * We may have a valid status bit...
*/ */
if (!CHECK_BIT(devStatus, 10)) { if (!CHECK_BIT(devStatus, 10)) {
/* we are still creeping along .... */ /* we are still creeping along .... */
*moving = true; *moving = true;
next_poll = -1; setIntegerParam(pC_->motorStatusDone_, false);
setIntegerParam(pC_->motorStatusDone_, false); if(time(NULL) > lastPositionUpdate + 60) {
goto skip; // 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 */ /*we are done moving */
*moving = false; *moving = false;
active = false;
setIntegerParam(pC_->motorStatusDone_, true); setIntegerParam(pC_->motorStatusDone_, true);
next_poll = time(NULL) + IDLEPOLL;
/* when homing, set the proper flag */ /* when homing, set the proper flag */
if (homing) { if (homing) {
@ -655,7 +664,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
} }
/* check for limit switches*/ /* check for limit switches*/
setIntegerParam(pC_->motorStatusLowLimit_, false); setIntegerParam(pC_->motorStatusLowLimit_, false);
setIntegerParam(pC_->motorStatusHighLimit_, false); setIntegerParam(pC_->motorStatusHighLimit_, false);
if (CHECK_BIT(devStatus, 11)) { if (CHECK_BIT(devStatus, 11)) {
setIntegerParam(pC_->motorStatusProblem_, true); setIntegerParam(pC_->motorStatusProblem_, true);
@ -685,9 +694,15 @@ asynStatus MasterMACSAxis::poll(bool * moving)
goto skip; goto skip;
} }
pPtr = strstr(reply, "="); pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus); if(pPtr) {
errCode = (unsigned int) errStatus; 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_); sprintf(command, "%dR18", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply); comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) { if (comStatus == asynError) {
@ -695,8 +710,14 @@ asynStatus MasterMACSAxis::poll(bool * moving)
goto skip; goto skip;
} }
pPtr = strstr(reply, "="); pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus); if(pPtr) {
derCode = (unsigned int) errStatus; 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) { if(debug) {
errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_, errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_,
@ -784,18 +805,28 @@ static const iocshArg
static const iocshArg static const iocshArg
MasterMACSCreateControllerArg2 = { "Number of axes", iocshArgInt }; MasterMACSCreateControllerArg2 = { "Number of axes", iocshArgInt };
static const iocshArg
MasterMACSCreateControllerArg3 = { "idlePoll", iocshArgInt };
static const iocshArg
MasterMACSCreateControllerArg4 = { "busyPoll", iocshArgInt };
static const iocshArg *const static const iocshArg *const
MasterMACSCreateControllerArgs[] = { &MasterMACSCreateControllerArg0, MasterMACSCreateControllerArgs[] = { &MasterMACSCreateControllerArg0,
&MasterMACSCreateControllerArg1, &MasterMACSCreateControllerArg1,
&MasterMACSCreateControllerArg2 &MasterMACSCreateControllerArg2,
&MasterMACSCreateControllerArg3,
&MasterMACSCreateControllerArg4
}; };
static const iocshFuncDef static const iocshFuncDef
MasterMACSCreateControllerDef = MasterMACSCreateControllerDef =
{ "MasterMACSCreateController", 3, MasterMACSCreateControllerArgs }; { "MasterMACSCreateController", 5, MasterMACSCreateControllerArgs };
static void MasterMACSCreateContollerCallFunc(const iocshArgBuf * args) 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);
} }
/** /**

View File

@ -33,13 +33,18 @@ private:
MasterMACSController *pC_; /**< Pointer to the asynMotorController to which this axis belongs. MasterMACSController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
* Abbreviated because it is used very frequently */ * Abbreviated because it is used very frequently */
double position; double position;
double oldPosition;
time_t lastPositionUpdate;
int homing; int homing;
time_t next_poll;
int errorReported;
int hasStarted; /* The motor status is invalid if the thing has not run once */ int hasStarted; /* The motor status is invalid if the thing has not run once */
int isOn(int axisStatus); int isOn(int axisStatus);
int readStatus(); int readStatus();
int errorCodeFound; int errorCodeFound;
int oldStatus;
bool active;
time_t lastPoll;
friend class MasterMACSController; friend class MasterMACSController;
}; };
@ -49,7 +54,8 @@ friend class MasterMACSController;
class MasterMACSController : public SINQController { class MasterMACSController : public SINQController {
public: 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); void report(FILE *fp, int level);
MasterMACSAxis* getAxis(asynUser *pasynUser); MasterMACSAxis* getAxis(asynUser *pasynUser);
@ -58,9 +64,6 @@ public:
// overloaded because we want to enable/disable the motor // overloaded because we want to enable/disable the motor
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
// overloaded because we want to read the axis state
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
friend class MasterMACSAxis; friend class MasterMACSAxis;
private: private:
asynUser *pasynUserController_; asynUser *pasynUserController_;

View File

@ -377,7 +377,7 @@ asynStatus NanotecAxis::poll(bool *moving)
asynStatus comStatus; asynStatus comStatus;
char command[COMLEN], reply[COMLEN]; char command[COMLEN], reply[COMLEN];
char *pPtr; char *pPtr;
int posVal, statVal; int posVal, statVal, count = 0;
double lowLim, highLim; double lowLim, highLim;
@ -393,11 +393,12 @@ asynStatus NanotecAxis::poll(bool *moving)
if(comStatus) goto skip; if(comStatus) goto skip;
pPtr = strchr(reply,'C'); pPtr = strchr(reply,'C');
pPtr++;
if(pPtr){ if(pPtr){
posVal = atoi(pPtr); pPtr++;
} else { count = sscanf(pPtr,"%d", &posVal);
errlogPrintf("Invalid response %s for #C received for axis %d\n", reply, axisNo_); }
if(pPtr == NULL || count < 1) {
errlogPrintf("Invalid response %s for #C received for axis %d, address %d\n", reply, axisNo_, busAddress);
return asynError; return asynError;
} }
@ -412,11 +413,12 @@ asynStatus NanotecAxis::poll(bool *moving)
if(comStatus) goto skip; if(comStatus) goto skip;
pPtr = strchr(reply,'$'); pPtr = strchr(reply,'$');
pPtr++;
if(pPtr) { if(pPtr) {
statVal = atoi(pPtr); pPtr++;
} else { count = sscanf(pPtr, "%d", &statVal);
errlogPrintf("Invalid response %s for #$ received for axis %d\n", reply, axisNo_); }
if(pPtr == NULL || count < 1) {
errlogPrintf("Invalid response %s for #$ received for axis %d busAddress %d\n", reply, axisNo_, busAddress);
return asynError; return asynError;
} }
//errlogPrintf("Axis %d, reply %s, statVal = %d\n", //errlogPrintf("Axis %d, reply %s, statVal = %d\n",

View File

@ -185,7 +185,7 @@ asynStatus pmacAxis::getAxisInitialStatus(void) {
cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response); cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response);
if (cmdStatus) { if (cmdStatus) {
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: Error: enaabling axis %d failed.\n", functionName, "%s: Error: enabling axis %d failed.\n", functionName,
axisNo_); axisNo_);
return asynError; return asynError;
} }
@ -911,11 +911,6 @@ asynStatus pmacV3Axis::poll(bool *moving) {
static const char *functionName = "pmacV3Axis::poll"; static const char *functionName = "pmacV3Axis::poll";
char message[132]; char message[132];
// Protect against excessive polling
if (time(NULL) < next_poll) {
return asynSuccess;
}
sprintf(message, "%s: Polling axis: %d", functionName, this->axisNo_); sprintf(message, "%s: Polling axis: %d", functionName, this->axisNo_);
pC_->debugFlow(message); pC_->debugFlow(message);
@ -927,12 +922,6 @@ asynStatus pmacV3Axis::poll(bool *moving) {
functionName, pC_->portName, axisNo_); functionName, pC_->portName, axisNo_);
} }
if (*moving) {
next_poll = time(NULL) + BUSYPOLL;
} else {
next_poll = time(NULL) + IDLEPOLL;
}
callParamCallbacks(); callParamCallbacks();
return status ? asynError : asynSuccess; return status ? asynError : asynSuccess;
} }
@ -966,7 +955,7 @@ asynStatus pmacV3Axis::getAxisStatus(bool *moving) {
pmacV3Controller *p3C_ = (pmacV3Controller *)pC_; pmacV3Controller *p3C_ = (pmacV3Controller *)pC_;
IsEnable = axStat != -3; IsEnable = axStat != -3;
asynStatus st = setIntegerParam(p3C_->axisEnabled_, axStat > -1); asynStatus st = setIntegerParam(p3C_->axisEnabled_, IsEnable);
cmdStatus = cmdStatus > st ? cmdStatus : st; cmdStatus = cmdStatus > st ? cmdStatus : st;
int direction = 0; int direction = 0;
@ -993,7 +982,8 @@ asynStatus pmacV3Axis::getAxisStatus(bool *moving) {
previous_direction_ = direction; previous_direction_ = direction;
/* are we done? */ /* are we done? */
if ((axStat == 0 || axStat < 0) && starting == 0) { /* if ((axStat == 0 || axStat < 0) && starting == 0) { */
if (axStat == 0 && starting == 0) {
done = 1; done = 1;
} else { } else {
starting = 0; starting = 0;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
record(asyn,"$(P)$(R)")
{
field(DTYP,"asynRecordDevice")
field(PORT,"$(PORT)")
field(ADDR,"$(ADDR)")
field(OMAX,"$(OMAX)")
field(IMAX,"$(IMAX)")
}

View 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")
}

View 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")
}

View 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
View 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")
}

View 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
View 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","")

View 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}
}

View File

@ -1,4 +1,4 @@
#!/usr/local/bin/iocsh #!/usr/local/bin/iocsh
require sinq,koennecke require sinq,koennecke
require autosave,koennecke require autosave,koennecke
@ -21,13 +21,15 @@ set_pass1_restoreFile("$(TOP)/autosave/test.sav","")
#asynSetTraceMask("macs1", 0, 255) #asynSetTraceMask("macs1", 0, 255)
#drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0) #drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0)
drvAsynIPPortConfigure("macs1", "Marcel1--MACS:1917") drvAsynIPPortConfigure("macs1", "Marcel1--MACS:1917")
MasterMACSCreateController("mota","macs1",7) MasterMACSCreateController("mota","macs1",7, 500, 10000)
MasterMACSCreateAxis("mota",5) MasterMACSCreateAxis("mota",5)
MasterMACSCreateAxis("mota",6) MasterMACSCreateAxis("mota",6)
dbLoadTemplate "mmacs2.sub" dbLoadTemplate "mmacs2.sub"
iocInit() iocInit()
setMovingPollPeriod("mota", .5)
setIdlePollPeriod("mota", 10. )
create_monitor_set("test.req", 10, "") create_monitor_set("test.req", 10, "")