diff --git a/motorApp/Db/Makefile b/motorApp/Db/Makefile index fc331c8d..d2d06c0f 100644 --- a/motorApp/Db/Makefile +++ b/motorApp/Db/Makefile @@ -26,6 +26,7 @@ DB += XPSAuxBo.db DB += XPSAuxLi.db DB += XPSAuxLo.db DB += XPS_extra.db +DB += XPSTclScript.template DB += HXP_extra.db DB += HXP_coords.db DB += ACRAux.template diff --git a/motorApp/Db/XPSTclScript.template b/motorApp/Db/XPSTclScript.template new file mode 100755 index 00000000..ccd2b3f5 --- /dev/null +++ b/motorApp/Db/XPSTclScript.template @@ -0,0 +1,44 @@ +#################################################### +# +# Template for executing TCL script on an XPS. +# Uses parameters in model 3 XPS driver (XPSController). +# +# Matthew Pearson +# July 2013 +# +# Macros: +# $(P) - PV name prefix +# $(R) - PV base record name +# $(PORT) - asyn port for the controller +# $(ADDR) - asyn address (normally 0) +# $(TIMEOUT) - asyn timeout +# +#################################################### + +# /// +# /// Name of the TCL script to execute +# /// +record(waveform, "$(P)$(R)TCLScript") +{ + field(DESC, "Name of the TCL script") + field(PINI, "YES") + field(DTYP, "asynOctetWrite") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_TCL_SCRIPT") + field(FTVL, "CHAR") + field(NELM, "256") + info(autosaveFields, "VAL") +} + +# /// +# /// Execute the TCL script (non blocking) +# /// +record(bo, "$(P)$(R)TCLScriptExecute") +{ + field(DESC, "Execute TCL Script") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_TCL_SCRIPT_EXECUTE") + field(ZNAM, "TCL Execute") + field(ONAM, "TCL Execute") +} + + diff --git a/motorApp/NewportSrc/XPSAxis.cpp b/motorApp/NewportSrc/XPSAxis.cpp index aed67d0f..17f970b2 100644 --- a/motorApp/NewportSrc/XPSAxis.cpp +++ b/motorApp/NewportSrc/XPSAxis.cpp @@ -577,28 +577,37 @@ asynStatus XPSAxis::poll(bool *moving) * homing, jogging, etc. However, this information is about the group, not the axis, so if one * motor in the group was moving, then they all appeared to be moving. This is not what we want, because * the EPICS motor record required the first motor to stop before the second motor could be moved. - * Instead we look for a response on the moveSocket_ to see when the motor motion was complete */ + * Instead we look for a response on the moveSocket_ to see when the motor motion was complete. + NOTE: by default this mode is disabled. To enable it use the XPSController::enableMovingMode() function.*/ /* If the group is not moving then the axis is not moving */ - if ((axisStatus_ < 43) || (axisStatus_ > 48)) moving_ = false; + if ((axisStatus_ < 43) || (axisStatus_ > 48)) { + moving_ = false; + } else { + if (!pC_->enableMovingMode_) { + moving_ = true; + } + } /* If the axis is moving then read from the moveSocket to see if it is done * We currently assume the move is complete if we get any response, we don't * check the actual response. */ - if (moving_) { - status = ReadXPSSocket(moveSocket_, readResponse, sizeof(readResponse), 0); - if (status < 0) { - asynPrint(pasynUser_, ASYN_TRACE_ERROR, - "%s:%s: [%s,%d]: error calling ReadXPSSocket status=%d\n", - driverName, functionName, pC_->portName, axisNo_, status); - goto done; - } - if (status > 0) { - asynPrint(pasynUser_, ASYN_TRACE_FLOW, - "%s:%s: [%s,%d]: readXPSSocket returned nRead=%d, [%s]\n", - driverName, functionName, pC_->portName, axisNo_, status, readResponse); - status = 0; - moving_ = false; + if (pC_->enableMovingMode_) { + if (moving_) { + status = ReadXPSSocket(moveSocket_, readResponse, sizeof(readResponse), 0); + if (status < 0) { + asynPrint(pasynUser_, ASYN_TRACE_ERROR, + "%s:%s: [%s,%d]: error calling ReadXPSSocket status=%d\n", + driverName, functionName, pC_->portName, axisNo_, status); + goto done; + } + if (status > 0) { + asynPrint(pasynUser_, ASYN_TRACE_FLOW, + "%s:%s: [%s,%d]: readXPSSocket returned nRead=%d, [%s]\n", + driverName, functionName, pC_->portName, axisNo_, status, readResponse); + status = 0; + moving_ = false; + } } } diff --git a/motorApp/NewportSrc/XPSController.cpp b/motorApp/NewportSrc/XPSController.cpp index 4f5e853d..c678132e 100644 --- a/motorApp/NewportSrc/XPSController.cpp +++ b/motorApp/NewportSrc/XPSController.cpp @@ -169,6 +169,8 @@ XPSController::XPSController(const char *portName, const char *IPAddress, int IP createParam(XPSProfileGroupNameString, asynParamOctet, &XPSProfileGroupName_); createParam(XPSTrajectoryFileString, asynParamOctet, &XPSTrajectoryFile_); createParam(XPSStatusString, asynParamInt32, &XPSStatus_); + createParam(XPSTclScriptString, asynParamOctet, &XPSTclScript_); + createParam(XPSTclScriptExecuteString, asynParamInt32, &XPSTclScriptExecute_); // This socket is used for polling by the controller and all axes pollSocket_ = TCP_ConnectToServer((char *)IPAddress, IPPort, XPS_POLL_TIMEOUT); @@ -209,6 +211,10 @@ XPSController::XPSController(const char *portName, const char *IPAddress, int IP /* Flag used to turn off setting MSTA problem bit when the axis is disabled.*/ noDisableError_ = 0; + /* Flag to disable a mode to change the moving state determination for an axis.*/ + /* See function XPSController::enableMovingMode().*/ + enableMovingMode_ = false; + } void XPSController::report(FILE *fp, int level) @@ -235,6 +241,51 @@ void XPSController::report(FILE *fp, int level) asynMotorController::report(fp, level); } +asynStatus XPSController::writeInt32(asynUser *pasynUser, epicsInt32 value) +{ + int function = pasynUser->reason; + int status = asynSuccess; + XPSAxis *pAxis; + static const char *functionName = "writeInt32"; + + pAxis = this->getAxis(pasynUser); + if (!pAxis) return asynError; + + /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the + * status at the end, but that's OK */ + status = pAxis->setIntegerParam(function, value); + + if (function == XPSTclScriptExecute_) { + /* Execute the TCL script */ + char fileName[MAX_FILENAME_LEN]; + getStringParam(XPSTclScript_, (int)sizeof(fileName), fileName); + if (fileName != NULL) { + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "Executing TCL script %s on XPS: %s\n", + fileName, this->portName); + status = TCLScriptExecute(pAxis->moveSocket_, + fileName,"0","0"); + if (status != 0) { + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "TCLScriptExecute returned error %d, on XPS: %s\n", + status, this->portName); + status = asynError; + } + } else { + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "TCL script name has not been set on XPS: %s\n", + this->portName); + status = asynError; + } + } else { + /* Call base class method */ + status = asynMotorController::writeInt32(pasynUser, value); + } + + return (asynStatus)status; + +} + /** * Perform a deferred move (a coordinated group move) on all the axes in a group. * @param groupName Pointer to string naming the group on which to perform the group move. @@ -1158,6 +1209,18 @@ asynStatus XPSController::noDisableError() return asynSuccess; } +/* Function to enable a mode where the XPSAxis poller will check the moveSocket response + to determine motion done. It does not rely on the axis state in this case. This prevents + axes in multipleAxis groups being in 'moving state' when another axis in the same + group is moving. This allows the motor record to move the axis when another axis in the + same group is moving. However, this has the consequence that a moving state is not + detected if the move is externally generated. So by default this mode is turned off. It + can be enabled by calling this function. */ +asynStatus XPSController::enableMovingMode() +{ + enableMovingMode_ = true; + return asynSuccess; +} @@ -1257,6 +1320,22 @@ asynStatus XPSNoDisableError(const char *XPSName) return pC->noDisableError(); } +asynStatus XPSEnableMovingMode(const char *XPSName) +{ + XPSController *pC; + static const char *functionName = "XPSEnableMovingMode"; + + pC = (XPSController*) findAsynPortDriver(XPSName); + if (!pC) { + printf("%s:%s: Error port %s not found\n", driverName, functionName, XPSName); + return asynError; + } + + return pC->enableMovingMode(); +} + + + /* Code for iocsh registration */ @@ -1342,6 +1421,16 @@ static void noDisableErrorCallFunc(const iocshArgBuf *args) XPSNoDisableError(args[0].sval); } +/* XPSEnableMovingMode */ +static const iocshArg XPSEnableMovingModeArg0 = {"Controller port name", iocshArgString}; +static const iocshArg * const XPSEnableMovingModeArgs[] = {&XPSEnableMovingModeArg0}; +static const iocshFuncDef enableMovingMode = {"XPSEnableMovingMode", 1, XPSEnableMovingModeArgs}; + +static void enableMovingModeCallFunc(const iocshArgBuf *args) +{ + XPSEnableMovingMode(args[0].sval); +} + static void XPSRegister3(void) { @@ -1350,6 +1439,7 @@ static void XPSRegister3(void) iocshRegister(&configXPSProfile, configXPSProfileCallFunc); iocshRegister(&disableAutoEnable, disableAutoEnableCallFunc); iocshRegister(&noDisableError, noDisableErrorCallFunc); + iocshRegister(&enableMovingMode, enableMovingModeCallFunc); } epicsExportRegistrar(XPSRegister3); diff --git a/motorApp/NewportSrc/XPSController.h b/motorApp/NewportSrc/XPSController.h index 92a3fa02..a74023cd 100644 --- a/motorApp/NewportSrc/XPSController.h +++ b/motorApp/NewportSrc/XPSController.h @@ -25,6 +25,8 @@ USAGE... Newport XPS EPICS asyn motor device driver #define XPSProfileGroupNameString "XPS_PROFILE_GROUP_NAME" #define XPSTrajectoryFileString "XPS_TRAJECTORY_FILE" #define XPSStatusString "XPS_STATUS" +#define XPSTclScriptString "XPS_TCL_SCRIPT" +#define XPSTclScriptExecuteString "XPS_TCL_SCRIPT_EXECUTE" class XPSController : public asynMotorController { @@ -34,6 +36,7 @@ class XPSController : public asynMotorController { int enableSetPosition, double setPositionSettlingTime); /* These are the methods that we override from asynMotorDriver */ + asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); void report(FILE *fp, int level); XPSAxis* getAxis(asynUser *pasynUser); XPSAxis* getAxis(int axisNo); @@ -60,6 +63,11 @@ class XPSController : public asynMotorController { /* Function to disable the MSTA problem bit in the event of an XPS Disable state 20 */ asynStatus noDisableError(); + /* Function to enable a mode where the XPSAxis poller will check the moveSocket response + to determine motion done. */ + asynStatus enableMovingMode(); + + protected: XPSAxis **pAxes_; /**< Array of pointers to axis objects */ @@ -73,7 +81,9 @@ class XPSController : public asynMotorController { int XPSProfileGroupName_; int XPSTrajectoryFile_; int XPSStatus_; - #define LAST_XPS_PARAM XPSStatus_ + int XPSTclScript_; + int XPSTclScriptExecute_; + #define LAST_XPS_PARAM XPSTclScriptExecute_ private: bool enableSetPosition_; /**< Enable/disable setting the position from EPICS */ @@ -89,6 +99,7 @@ class XPSController : public asynMotorController { epicsEventId profileExecuteEvent_; int autoEnable_; int noDisableError_; + bool enableMovingMode_; friend class XPSAxis; };