From efbd0e19cf8b9b1a4e8a3f21b3909ff94449d2ef Mon Sep 17 00:00:00 2001 From: koennecke Date: Thu, 17 Jun 2021 09:30:28 +0200 Subject: [PATCH] Updated EuromoveDriver to work with Prologix GPIB-Ethernet Improved threshold handling on EL737 Minor changes --- Makefile.RHEL7 | 2 + iocBoot/iocsinqEPICS/euromovetest.cmd | 5 ++- sinqEPICSApp/src/EL734Driver.cpp | 24 ++++++----- sinqEPICSApp/src/EuroMoveDriver.cpp | 59 ++++++++++++++++++++++----- sinqEPICSApp/src/EuroMoveDriver.h | 4 +- sinqEPICSApp/src/devScalerEL737.c | 55 ++++++++++++++----------- sinqEPICSApp/src/pmacAxis.cpp | 2 +- 7 files changed, 102 insertions(+), 49 deletions(-) diff --git a/Makefile.RHEL7 b/Makefile.RHEL7 index 9875c20..f8f70e2 100644 --- a/Makefile.RHEL7 +++ b/Makefile.RHEL7 @@ -4,10 +4,12 @@ include /ioc/tools/driver.makefile MODULE=sinq LIBVERSION=koennecke BUILDCLASSES=Linux +EPICS_VERSIONS=3.14.12 # additional module dependencies REQUIRED+=SynApps REQUIRED+=stream +REQUIRED+=scaler # using a test version scaler_VERSION=koennecke diff --git a/iocBoot/iocsinqEPICS/euromovetest.cmd b/iocBoot/iocsinqEPICS/euromovetest.cmd index 565cd46..70a2a9e 100755 --- a/iocBoot/iocsinqEPICS/euromovetest.cmd +++ b/iocBoot/iocsinqEPICS/euromovetest.cmd @@ -9,9 +9,10 @@ cd ${TOP} -drvAsynIPPortConfigure("serial1", "amor-ts:3002",0,0,0) +drvAsynIPPortConfigure("serial1", "129.129.195.83:1234",0,0,0) +#drvAsynIPPortConfigure("serial1", "amor-ts:3002",0,0,0) #drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0) -EuroMoveCreateController("llb","serial1",1); +EuroMoveCreateController("llb","serial1", 10, 1); ### Motors diff --git a/sinqEPICSApp/src/EL734Driver.cpp b/sinqEPICSApp/src/EL734Driver.cpp index ca6fda1..e2dc846 100644 --- a/sinqEPICSApp/src/EL734Driver.cpp +++ b/sinqEPICSApp/src/EL734Driver.cpp @@ -147,7 +147,7 @@ asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN], pasynOctetSyncIO->flush(pasynUserController_); status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command), - reply,COMLEN, 1.,&out,&in,&reason); + reply,COMLEN, 2.,&out,&in,&reason); if(status != asynSuccess){ if(axis!= NULL){ axis->updateMsgTxtFromDriver("Lost connection to motor controller"); @@ -409,17 +409,19 @@ asynStatus EL734Axis::poll(bool *moving) } count = sscanf(reply,"%lf", &position); if(count != 1) { - snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_); - setIntegerParam(pC_->motorStatusProblem_, true); - errorReported = 1; - updateMsgTxtFromDriver(errTxt); - comStatus = asynError; - goto skip; + if(!homing) { + snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_); + setIntegerParam(pC_->motorStatusProblem_, true); + errorReported = 1; + updateMsgTxtFromDriver(errTxt); + comStatus = asynError; + goto skip; + } + } else { + //errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position); + setDoubleParam(pC_->motorPosition_, position*1000); + //setDoubleParam(pC_->motorEncoderPosition_, position); } - //errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position); - setDoubleParam(pC_->motorPosition_, position*1000); - //setDoubleParam(pC_->motorEncoderPosition_, position); - // Read the moving status of this motor sprintf(command,"msr %d",axisNo_); diff --git a/sinqEPICSApp/src/EuroMoveDriver.cpp b/sinqEPICSApp/src/EuroMoveDriver.cpp index e19819b..67da0fb 100644 --- a/sinqEPICSApp/src/EuroMoveDriver.cpp +++ b/sinqEPICSApp/src/EuroMoveDriver.cpp @@ -5,6 +5,9 @@ USAGE... Motor driver support for the EuroMove motor controller from LLB. This is a driver for the EuroMove motor controller from LLB. This device talks to us either via GPIB or USB. The controller is fairly simple. It can control quite a number of motors. +Reworked in 06/2021 to work with the Prologix GPIV-Ethernte converter + +mark.koennecke@psi.ch */ @@ -32,11 +35,14 @@ GPIB or USB. The controller is fairly simple. It can control quite a number of m * \param[in] EuroMovePortName The name of the drvAsynSerialPort that was created previously to connect to the EuroMove controller * \param[in] numAxes The number of axes that this controller supports */ -EuroMoveController::EuroMoveController(const char *portName, const char *EuroMovePortName, int numAxis) +EuroMoveController::EuroMoveController(const char *portName, const char *EuroMovePortName, int gpibAddr, int numAxis) : SINQController(portName, EuroMovePortName,numAxis+1) { asynStatus status; static const char *functionName = "EuroMoveController::EuroMoveController"; + size_t out, in; + int reason; + char command[80], reply[80]; /* Connect to EuroMove controller */ status = pasynOctetSyncIO->connect(EuroMovePortName, 0, &pasynUserController_, NULL); @@ -45,9 +51,27 @@ EuroMoveController::EuroMoveController(const char *portName, const char *EuroMov "%s: cannot connect to EuroMove controller\n", functionName); } - const char *terminator = "\r"; + const char *terminator = "\r\n"; pasynOctetSyncIO->setOutputEos(pasynUserController_,terminator,strlen(terminator)); - pasynOctetSyncIO->setInputEos(pasynUserController_,terminator,strlen(terminator)); + const char *repTerminator = "\r"; + pasynOctetSyncIO->setInputEos(pasynUserController_,repTerminator,strlen(repTerminator)); + + /* Save gpib address and prepare addr string */ + this->gpibAddr = gpibAddr; + snprintf(addrCommand,strlen(addrCommand), "++addr %d", gpibAddr); + + /* + Configure the Prologix interface to our liking + The thing sends no response on configuration commands + */ + strcpy(command,"++mode 1"); /* Make it a controller */ + status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out); + strcpy(command,"++auto 1"); /* ask for response automatically */ + status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out); + strcpy(command,"++eos 1"); /* CR */ + status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out); + + for(int i = 0; i < numAxis; i++){ new EuroMoveAxis(this, i+1); @@ -59,12 +83,13 @@ EuroMoveController::EuroMoveController(const char *portName, const char *EuroMov /** Creates a new EuroMoveController object. * Configuration command, called directly or from iocsh * \param[in] portName The name of the asyn port that will be created for this driver - * \param[in] EuroMovePortName The name of the drvAsynIPPPort that was created previously to connect to the EuroMove controller + * \param[in] EuroMovePortName The name of the drvAsynIPPPort that was created previously to connect to the EuroMove controller + * \param[in] gpibAddr The address of the controller on the GPIB bus * \param[in] numAxes The number of axes that this controller supports */ -extern "C" int EuroMoveCreateController(const char *portName, const char *EuroMovePortName, const int numAxis) +extern "C" int EuroMoveCreateController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int numAxis) { - new EuroMoveController(portName, EuroMovePortName, numAxis); + new EuroMoveController(portName, EuroMovePortName, gpibAddr, numAxis); return(asynSuccess); } @@ -119,7 +144,17 @@ asynStatus EuroMoveController::transactController(int axisNo,char command[COMLEN pasynOctetSyncIO->flush(pasynUserController_); - + /* set address first */ + status = pasynOctetSyncIO->write(pasynUserController_, this->addrCommand, strlen(this->addrCommand), 2, &out); + if(status != asynSuccess){ + if(axis!= NULL){ + axis->updateMsgTxtFromDriver("Lost connection to motor controller"); + errlogPrintf("Lost connection to motor controller\n"); + } + return status; + } + + /* now the actual command */ status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command), reply,sizeof(reply), 10.,&out,&in,&reason); if(status != asynSuccess){ @@ -606,15 +641,17 @@ static void EuroMoveConfigCallFunc(const iocshArgBuf *args) /** Code for iocsh registration */ static const iocshArg EuroMoveCreateControllerArg0 = {"Port name", iocshArgString}; static const iocshArg EuroMoveCreateControllerArg1 = {"EuroMove port name", iocshArgString}; -static const iocshArg EuroMoveCreateControllerArg2 = {"Number of axis", iocshArgInt}; +static const iocshArg EuroMoveCreateControllerArg2 = {"GPIB Address", iocshArgInt}; +static const iocshArg EuroMoveCreateControllerArg3 = {"Number of axis", iocshArgInt}; static const iocshArg * const EuroMoveCreateControllerArgs[] = {&EuroMoveCreateControllerArg0, &EuroMoveCreateControllerArg1, - &EuroMoveCreateControllerArg2 + &EuroMoveCreateControllerArg2, + &EuroMoveCreateControllerArg3 }; -static const iocshFuncDef EuroMoveCreateControllerDef = {"EuroMoveCreateController", 3, EuroMoveCreateControllerArgs}; +static const iocshFuncDef EuroMoveCreateControllerDef = {"EuroMoveCreateController", 4, EuroMoveCreateControllerArgs}; static void EuroMoveCreateControllerCallFunc(const iocshArgBuf *args) { - EuroMoveCreateController(args[0].sval, args[1].sval, args[2].ival); + EuroMoveCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival); } static void EuroMoveRegister(void) diff --git a/sinqEPICSApp/src/EuroMoveDriver.h b/sinqEPICSApp/src/EuroMoveDriver.h index 3bd41a7..990a224 100644 --- a/sinqEPICSApp/src/EuroMoveDriver.h +++ b/sinqEPICSApp/src/EuroMoveDriver.h @@ -53,7 +53,7 @@ private: class EuroMoveController : public SINQController { public: - EuroMoveController(const char *portName, const char *EuroMovePortName, const int nAxis); + EuroMoveController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int nAxis); void report(FILE *fp, int level); EuroMoveAxis* getAxis(asynUser *pasynUser); @@ -63,6 +63,8 @@ public: friend class EuroMoveAxis; private: asynUser *pasynUserController_; + unsigned int gpibAddr; + char addrCommand[50]; asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]); diff --git a/sinqEPICSApp/src/devScalerEL737.c b/sinqEPICSApp/src/devScalerEL737.c index 1cd8d60..bb7a204 100644 --- a/sinqEPICSApp/src/devScalerEL737.c +++ b/sinqEPICSApp/src/devScalerEL737.c @@ -27,7 +27,7 @@ * * Mark Koennecke, February 2013 * - * Enhanced by adding an addtional external pause and status flag in the databse and code in here + * Enhanced by adding an addtional external pause and status flag in the database and code in here * to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message. * * Mark Koennecke, July 2017 @@ -414,7 +414,7 @@ static void runEvents(EL737priv *priv) This is the better way to set the threshold rather then the old way below which uses presets for that function. This one uses separate fields. */ - if(priv->dbInit == 1) { + if(priv->dbInit == 1 && priv->sendThreshold) { dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL); if(dbStatus != 0){ errSymLookup(dbStatus,errName,sizeof(errName)); @@ -425,34 +425,44 @@ static void runEvents(EL737priv *priv) we have to set the threshold */ dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL); - if(dbStatus != 0){ + if(dbStatus != 0) { errSymLookup(dbStatus,errName,sizeof(errName)); errlogPrintf("Reading thresholdCounter failed with %s\n", errName); } else { - sprintf(command,"DL %d %d", (int)threshCounter, - (int)myThreshold); - //errlogPrintf("Sending threshold command %s\n", command); - status = el737_transactCommand(priv,command,reply); - sprintf(command,"DR %d", (int)threshCounter); - status = el737_transactCommand(priv, command,reply); - if(status == asynSuccess){ - priv->sendThreshold = 0; - priv->thresholdValue = myThreshold; + if(threshCounter > 0) { + /* The threshCounter is valid */ + sprintf(command,"DL %d %d", (int)threshCounter, + (int)myThreshold); + errlogPrintf("Sending threshold command %s\n", command); + status = el737_transactCommand(priv,command,reply); + sprintf(command,"DR %d", (int)threshCounter); + status = el737_transactCommand(priv, command,reply); + if(status == asynSuccess){ + priv->sendThreshold = 0; + priv->thresholdValue = myThreshold; + } + } else { + errlogPrintf("Invalid threshold monitor %ld, no threshold sent", threshCounter); } } } } - } + } - if(priv->sendThreshold == 1){ - sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], - (int)priv->presets[THRESHVAL]); - //errlogPrintf("Sending threshold command %s\n", command); - status = el737_transactCommand(priv,command,reply); - sprintf(command,"DR %d", (int)priv->presets[THRESHMON]); - status = el737_transactCommand(priv, command,reply); - if(status == asynSuccess){ - priv->sendThreshold = 0; + if(priv->sendThreshold == 1) { + // fallback when we do not have the DB fields or threshCounter is invalid + if(priv->presets[THRESHMON] <= 0) { + errlogPrintf("Invalid threshold monitor %ld, no threshold sent", priv->presets[THRESHMON]); + } else { + sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], + (int)priv->presets[THRESHVAL]); + errlogPrintf("Sending threshold from presets, command %s\n", command); + status = el737_transactCommand(priv,command,reply); + sprintf(command,"DR %d", (int)priv->presets[THRESHMON]); + status = el737_transactCommand(priv, command,reply); + if(status == asynSuccess) { + priv->sendThreshold = 0; + } } } @@ -542,7 +552,6 @@ static void el737Thread(void *param) evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout); //errlogPrintf("EL737 thread woke up with %d\n", evStatus); - if(evStatus == epicsEventWaitOK) { /* FEAR: we received a command!!!! diff --git a/sinqEPICSApp/src/pmacAxis.cpp b/sinqEPICSApp/src/pmacAxis.cpp index e9f4aa2..56af745 100644 --- a/sinqEPICSApp/src/pmacAxis.cpp +++ b/sinqEPICSApp/src/pmacAxis.cpp @@ -594,7 +594,7 @@ asynStatus pmacHRPTAxis::getAxisStatus(bool *moving) /*================================= SeleneAxis code ======================================================*/ SeleneAxis::SeleneAxis(SeleneController *pC, int axisNo, double limitTarget) - : pmacAxis(pC, axisNo) + : pmacAxis(pC, axisNo, false) { static const char *functionName = "pmacAxis::pmacAxis";