Updated EuromoveDriver to work with Prologix GPIB-Ethernet

Improved threshold handling on EL737
Minor changes
This commit is contained in:
2021-06-17 09:30:28 +02:00
parent 6de4a878ef
commit efbd0e19cf
7 changed files with 102 additions and 49 deletions

View File

@ -4,10 +4,12 @@ include /ioc/tools/driver.makefile
MODULE=sinq MODULE=sinq
LIBVERSION=koennecke LIBVERSION=koennecke
BUILDCLASSES=Linux BUILDCLASSES=Linux
EPICS_VERSIONS=3.14.12
# additional module dependencies # additional module dependencies
REQUIRED+=SynApps REQUIRED+=SynApps
REQUIRED+=stream REQUIRED+=stream
REQUIRED+=scaler
# using a test version # using a test version
scaler_VERSION=koennecke scaler_VERSION=koennecke

View File

@ -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) #drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0)
EuroMoveCreateController("llb","serial1",1); EuroMoveCreateController("llb","serial1", 10, 1);
### Motors ### Motors

View File

@ -147,7 +147,7 @@ asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN],
pasynOctetSyncIO->flush(pasynUserController_); pasynOctetSyncIO->flush(pasynUserController_);
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command), status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason); reply,COMLEN, 2.,&out,&in,&reason);
if(status != asynSuccess){ if(status != asynSuccess){
if(axis!= NULL){ if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller"); axis->updateMsgTxtFromDriver("Lost connection to motor controller");
@ -409,17 +409,19 @@ asynStatus EL734Axis::poll(bool *moving)
} }
count = sscanf(reply,"%lf", &position); count = sscanf(reply,"%lf", &position);
if(count != 1) { if(count != 1) {
snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_); if(!homing) {
setIntegerParam(pC_->motorStatusProblem_, true); snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_);
errorReported = 1; setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver(errTxt); errorReported = 1;
comStatus = asynError; updateMsgTxtFromDriver(errTxt);
goto skip; 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 // Read the moving status of this motor
sprintf(command,"msr %d",axisNo_); sprintf(command,"msr %d",axisNo_);

View File

@ -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 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. 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] 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 * \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) : SINQController(portName, EuroMovePortName,numAxis+1)
{ {
asynStatus status; asynStatus status;
static const char *functionName = "EuroMoveController::EuroMoveController"; static const char *functionName = "EuroMoveController::EuroMoveController";
size_t out, in;
int reason;
char command[80], reply[80];
/* Connect to EuroMove controller */ /* Connect to EuroMove controller */
status = pasynOctetSyncIO->connect(EuroMovePortName, 0, &pasynUserController_, NULL); 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", "%s: cannot connect to EuroMove controller\n",
functionName); functionName);
} }
const char *terminator = "\r"; const char *terminator = "\r\n";
pasynOctetSyncIO->setOutputEos(pasynUserController_,terminator,strlen(terminator)); 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++){ for(int i = 0; i < numAxis; i++){
new EuroMoveAxis(this, i+1); new EuroMoveAxis(this, i+1);
@ -59,12 +83,13 @@ EuroMoveController::EuroMoveController(const char *portName, const char *EuroMov
/** Creates a new EuroMoveController object. /** Creates a new EuroMoveController object.
* Configuration command, called directly or from iocsh * 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] 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 * \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); return(asynSuccess);
} }
@ -119,7 +144,17 @@ asynStatus EuroMoveController::transactController(int axisNo,char command[COMLEN
pasynOctetSyncIO->flush(pasynUserController_); 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), status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,sizeof(reply), 10.,&out,&in,&reason); reply,sizeof(reply), 10.,&out,&in,&reason);
if(status != asynSuccess){ if(status != asynSuccess){
@ -606,15 +641,17 @@ static void EuroMoveConfigCallFunc(const iocshArgBuf *args)
/** Code for iocsh registration */ /** Code for iocsh registration */
static const iocshArg EuroMoveCreateControllerArg0 = {"Port name", iocshArgString}; static const iocshArg EuroMoveCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg EuroMoveCreateControllerArg1 = {"EuroMove 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, static const iocshArg * const EuroMoveCreateControllerArgs[] = {&EuroMoveCreateControllerArg0,
&EuroMoveCreateControllerArg1, &EuroMoveCreateControllerArg1,
&EuroMoveCreateControllerArg2 &EuroMoveCreateControllerArg2,
&EuroMoveCreateControllerArg3
}; };
static const iocshFuncDef EuroMoveCreateControllerDef = {"EuroMoveCreateController", 3, EuroMoveCreateControllerArgs}; static const iocshFuncDef EuroMoveCreateControllerDef = {"EuroMoveCreateController", 4, EuroMoveCreateControllerArgs};
static void EuroMoveCreateControllerCallFunc(const iocshArgBuf *args) 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) static void EuroMoveRegister(void)

View File

@ -53,7 +53,7 @@ private:
class EuroMoveController : public SINQController { class EuroMoveController : public SINQController {
public: 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); void report(FILE *fp, int level);
EuroMoveAxis* getAxis(asynUser *pasynUser); EuroMoveAxis* getAxis(asynUser *pasynUser);
@ -63,6 +63,8 @@ public:
friend class EuroMoveAxis; friend class EuroMoveAxis;
private: private:
asynUser *pasynUserController_; asynUser *pasynUserController_;
unsigned int gpibAddr;
char addrCommand[50];
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]); asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);

View File

@ -27,7 +27,7 @@
* *
* Mark Koennecke, February 2013 * 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. * to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message.
* *
* Mark Koennecke, July 2017 * 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 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. 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); dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL);
if(dbStatus != 0){ if(dbStatus != 0){
errSymLookup(dbStatus,errName,sizeof(errName)); errSymLookup(dbStatus,errName,sizeof(errName));
@ -425,34 +425,44 @@ static void runEvents(EL737priv *priv)
we have to set the threshold we have to set the threshold
*/ */
dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL); dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL);
if(dbStatus != 0){ if(dbStatus != 0) {
errSymLookup(dbStatus,errName,sizeof(errName)); errSymLookup(dbStatus,errName,sizeof(errName));
errlogPrintf("Reading thresholdCounter failed with %s\n", errName); errlogPrintf("Reading thresholdCounter failed with %s\n", errName);
} else { } else {
sprintf(command,"DL %d %d", (int)threshCounter, if(threshCounter > 0) {
(int)myThreshold); /* The threshCounter is valid */
//errlogPrintf("Sending threshold command %s\n", command); sprintf(command,"DL %d %d", (int)threshCounter,
status = el737_transactCommand(priv,command,reply); (int)myThreshold);
sprintf(command,"DR %d", (int)threshCounter); errlogPrintf("Sending threshold command %s\n", command);
status = el737_transactCommand(priv, command,reply); status = el737_transactCommand(priv,command,reply);
if(status == asynSuccess){ sprintf(command,"DR %d", (int)threshCounter);
priv->sendThreshold = 0; status = el737_transactCommand(priv, command,reply);
priv->thresholdValue = myThreshold; if(status == asynSuccess){
priv->sendThreshold = 0;
priv->thresholdValue = myThreshold;
}
} else {
errlogPrintf("Invalid threshold monitor %ld, no threshold sent", threshCounter);
} }
} }
} }
} }
} }
if(priv->sendThreshold == 1){ if(priv->sendThreshold == 1) {
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON], // fallback when we do not have the DB fields or threshCounter is invalid
(int)priv->presets[THRESHVAL]); if(priv->presets[THRESHMON] <= 0) {
//errlogPrintf("Sending threshold command %s\n", command); errlogPrintf("Invalid threshold monitor %ld, no threshold sent", priv->presets[THRESHMON]);
status = el737_transactCommand(priv,command,reply); } else {
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]); sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
status = el737_transactCommand(priv, command,reply); (int)priv->presets[THRESHVAL]);
if(status == asynSuccess){ errlogPrintf("Sending threshold from presets, command %s\n", command);
priv->sendThreshold = 0; 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); evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout);
//errlogPrintf("EL737 thread woke up with %d\n", evStatus); //errlogPrintf("EL737 thread woke up with %d\n", evStatus);
if(evStatus == epicsEventWaitOK) { if(evStatus == epicsEventWaitOK) {
/* /*
FEAR: we received a command!!!! FEAR: we received a command!!!!

View File

@ -594,7 +594,7 @@ asynStatus pmacHRPTAxis::getAxisStatus(bool *moving)
/*================================= SeleneAxis code ======================================================*/ /*================================= SeleneAxis code ======================================================*/
SeleneAxis::SeleneAxis(SeleneController *pC, int axisNo, double limitTarget) SeleneAxis::SeleneAxis(SeleneController *pC, int axisNo, double limitTarget)
: pmacAxis(pC, axisNo) : pmacAxis(pC, axisNo, false)
{ {
static const char *functionName = "pmacAxis::pmacAxis"; static const char *functionName = "pmacAxis::pmacAxis";