From 5083897b16be285ff95032666efdd064720024f7 Mon Sep 17 00:00:00 2001 From: koennecke Date: Thu, 22 Mar 2007 08:53:05 +0000 Subject: [PATCH] - Added a counter driver for MORPHEUS-2D which checks an SPS for an detector overcount condition. --- el737hpdrivsps.c | 704 +++++++++++++++++++++++++++++++++++++++++++++++ make_gen | 2 +- psi.c | 4 + sinqhttp.c | 2 +- 4 files changed, 710 insertions(+), 2 deletions(-) create mode 100644 el737hpdrivsps.c diff --git a/el737hpdrivsps.c b/el737hpdrivsps.c new file mode 100644 index 0000000..b8a91a2 --- /dev/null +++ b/el737hpdrivsps.c @@ -0,0 +1,704 @@ +/*----------------------------------------------------------------------- + This is another driver for the EL737 counter box used at SINQ. The hp in + the name is for high performance, though this only a promise and not yet + proven. This version connects directly to the RS232 port of the counter + box on the terminal server rather then working with David Maden's + SerPortServer program. Other tweaks will be implemented as well, such as + reading the monitors only now and then and not on all calls. + + Mark Koennecke, July 2003 + + This is a special version for MORPHEUS which checks the SPS when in + No Beam state. Because NoBeam can be caused by the shutter being closed + in order to prevent overloading the 2D detector. + + Mark Koennecke, March 2007 + -------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sps.h" + +#define MONTHRESH 20 + +#define STATSEND 0 +#define STATRECEIVE 2 +#define BADTRANGE -117766 +/*----------------------------------------------------------------------- + our own data struture + ------------------------------------------------------------------------*/ +typedef struct { + prs232 controller; + int monitorCount; /* read monitors if this is above MONTHRESH */ + float cachedControl; + int errorCode; + int finishCount; /* need RS = 0 2 times before really sure finished */ + int statusMode; + time_t startRequest; + int lastStatus; /* need to remember last status, otherwise I get oscillating + NoBeam and Counting status if the beam goes off + */ + char *badReply; + int readErrorCount; /* need to remember failed reads: on RDOE, upper level + code will see busy's and thus not catch the case of + multiple failures + */ + pSPS sps; +} EL737hpsps, *pEL737hpsps; +/*--------------------- ERROR CODES -------------------------------------*/ +#define OFFLINE -1 +#define BADRANGE -3 +#define BADCOMMAND -4 +#define BADPARAM -5 +#define NOPARAM -7 +#define TOMANYCOUNTS -8 +#define SYSERROR -9 +#define BADREPLY -10 +#define SELECTFAIL -11 +#define TIMEOUT737 -12 +#define TOMANYREADERRORS -23 +#define DETOVERLOAD -24 +/*---------------------------------------------------------------------*/ +static void setBadReply(pEL737hpsps self, char *reply){ + if(self->badReply != NULL){ + free(self->badReply); + } + self->badReply = strdup(reply); +} +/*----------------------------------------------------------------------- + search errors in a reply from the EL737. Returns 1 on success or a + negative error code in case of trouble. + ------------------------------------------------------------------------*/ +static int checkEL737Error(char *pReply){ + + /* + all error start with a ?, if no ? in reply, answer is OK! + */ + if(strstr(pReply,"?") == NULL){ + return 1; + } + + /* + Now there is an error and we have to identify it + */ + if(strstr(pReply,"?OF") != NULL){ + return OFFLINE; + } else if(strstr(pReply,"?OV") != NULL){ + return OVERFLOW; + } else if(strstr(pReply,"?1") != NULL){ + return BADRANGE; + } else if(strstr(pReply,"?2") != NULL){ + return BADCOMMAND; + } else if(strstr(pReply,"?3") != NULL){ + return BADPARAM; + } else if(strstr(pReply,"?4") != NULL){ + return BADCOUNTER; + } else if(strstr(pReply,"?5") != NULL){ + return NOPARAM; + } else if(strstr(pReply,"?6") != NULL){ + return TOMANYCOUNTS; + } else { + return SYSERROR; + } +} +/*--------------------------------------------------------------- + fixMode checks if we are in STATRECEIVE mode, reads any pending + data and sets the mode to STATSEND. This would fix the problem + if another client wishes to give a command while we are expecting + a status response + ---------------------------------------------------------------*/ +static void fixMode(pEL737hpsps pPriv){ + char pBuffer[256]; + int len = 255; + + if(pPriv->statusMode == STATRECEIVE){ + readRS232TillTerm(pPriv->controller,pBuffer,&len); + pPriv->statusMode = STATSEND; + } +} +/*---------------------------------------------------------------*/ +static int EL737SCommand(pEL737hpsps pPriv, char *pCommand, + char *pReply, int replylen){ + int status; + + status = transactRS232(pPriv->controller,pCommand,strlen(pCommand), + pReply,replylen); + if(status < 0){ + pPriv->errorCode = status; + return 0; + } + status = checkEL737Error(pReply); + if(status < 0){ + pPriv->errorCode = status; + return 0; + } + return 1; +} +/*----------------------------------------------------------------*/ +static int readRS(pEL737hpsps pPriv, int *RS){ + int status, len = 131; + char reply[132]; + + status = readRS232TillTerm(pPriv->controller, + reply,&len); + if(status < 0) { + pPriv->readErrorCount++; + pPriv->errorCode = status; + return 0; + } + status = checkEL737Error(reply); + if(status < 0){ + pPriv->readErrorCount++; + pPriv->errorCode = status; + return 0; + } + status = sscanf(reply,"%d",RS); + if(status < 1){ + pPriv->readErrorCount++; + pPriv->errorCode = BADREPLY; + setBadReply(pPriv,reply); + return 0; + } + pPriv->readErrorCount = 0; + return 1; +} +/*-----------------------------------------------------------------*/ +static int decodeRS(pEL737hpsps pPriv, int RS){ + int returnValue; + + switch(RS){ + case 0: + pPriv->finishCount++; + if(pPriv->finishCount > 2){ + returnValue = HWIdle; + } else { + returnValue = HWBusy; + } + break; + case 1: + case 2: + pPriv->finishCount = 0; + returnValue = HWBusy; + break; + case 5: + case 6: + pPriv->finishCount = 0; + returnValue = HWNoBeam; + break; + default: + pPriv->finishCount = 0; + returnValue = HWPause; + break; + } + return returnValue; +} +/*-----------------------------------------------------------------*/ +static int updateMonitors(struct __COUNTER *self){ + int status; + int m1,m2,m3,m4,m5,m6,m7,m8; + float fTime; + pEL737hpsps pPriv = NULL; + char reply[132]; + + pPriv = (pEL737hpsps)self->pData; + + if(!EL737SCommand(pPriv,"RA\r",reply,131)){ + return 0; + } + + /* + There are two forms of RA replys: new form with 8 monitors + */ + status = sscanf(reply,"%f %d %d %d %d %d %d %d %d", + &fTime,&m1,&m2,&m3,&m4,&m5,&m6,&m7,&m8); + if(status != 9){ + /* + old form with 4 monitors + */ + status = sscanf(reply,"%d %d %d %d %f",&m1,&m2,&m3,&m4,&fTime); + if(status != 5){ + pPriv->errorCode = BADREPLY; + setBadReply(pPriv,reply); + printf("Bad reply to EL737 RA command: %s\n", reply); + return 0; + } + } + self->lCounts[0] = m2; + self->lCounts[1] = m1; + self->lCounts[2] = m3; + self->lCounts[3] = m4; + self->lCounts[4] = m5; + self->lCounts[5] = m6; + self->lCounts[6] = m7; + self->lCounts[7] = m8; + self->fTime = fTime; + + if(self->eMode == eTimer){ + pPriv->cachedControl = fTime; + } else { + pPriv->cachedControl = m1; + } + return 1; +} +/*------------------------------------------------------------------*/ +static int EL737SStatus(struct __COUNTER *self, float *fControl){ + int status, RS, returnValue; + pEL737hpsps pPriv = NULL; + int iBit = 0; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + /* + handle STATSEND mode + */ + if(pPriv->statusMode == STATSEND){ + status = writeRS232(pPriv->controller,"RS\r",3); + if(status < 0){ + pPriv->errorCode = status; + return HWFault; + } + pPriv->statusMode = STATRECEIVE; + pPriv->startRequest = time(NULL); + *fControl = pPriv->cachedControl; + return pPriv->lastStatus; + } + + /* + now we are dealing with STATRECEIVE mode. + Check for timeout first. + */ + if(time(NULL) > pPriv->startRequest + 10){ + pPriv->statusMode = STATSEND; + pPriv->errorCode = TIMEOUT737; + pPriv->readErrorCount++; + return HWFault; + } + + /* + check availability of data + */ + status = availableNetRS232(pPriv->controller); + if(status == 0){ + *fControl = pPriv->cachedControl; + return pPriv->lastStatus; + } else if(status < 0) { + *fControl = pPriv->cachedControl; + pPriv->statusMode = STATSEND; + pPriv->errorCode = SELECTFAIL; + return HWFault; + } + + /* + The snail in the counter box has replied. Read and process + the data + */ + pPriv->statusMode = STATSEND; + if(!readRS(pPriv,&RS)){ + return HWFault; + } + + /* + decode it + */ + returnValue = decodeRS(pPriv,RS); + pPriv->lastStatus = returnValue; + + /* + check for excessive failed reads + */ + if(pPriv->readErrorCount > 3){ + pPriv->errorCode = TOMANYREADERRORS; + return HWFault; + } + + /* + check if we update the monitors and do it + */ + pPriv->monitorCount++; + if(pPriv->monitorCount > MONTHRESH){ + status = updateMonitors(self); + pPriv->monitorCount = 0; + if(!status){ + return HWFault; + } + } + + *fControl = pPriv->cachedControl; + + if(returnValue == HWNoBeam){ + /* ToDo: put in proper bit address when properly known */ + SPSGetStatus(pPriv->sps,79,&iBit); + if(iBit == 1){ + pPriv->errorCode = DETOVERLOAD; + return HWFault; + } + } + + return returnValue; +} +/*-------------------------------------------------------------------*/ +static int EL737SStart(struct __COUNTER *self){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[50], pReply[30]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + pPriv->readErrorCount = 0; + if(self->eMode == ePreset){ + snprintf(pCommand,49,"MP %d\r",(int)self->fPreset); + } else { + if(self->fPreset < .1 || self->fPreset > 200000) + { + self->iErrorCode = BADTRANGE; + return HWFault; + } + snprintf(pCommand,49,"TP %.2f\r", self->fPreset); + } + if(EL737SCommand(pPriv,pCommand,pReply,29) != 1){ + return 0; + } + pPriv->finishCount = 0; + pPriv->lastStatus = HWBusy; + return 1; +} +/* --------------------------------------------------------------------*/ +static int EL737SPause(struct __COUNTER *self){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[50], pReply[30]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + pPriv->lastStatus = HWPause; + return EL737SCommand(pPriv,"PS\r",pReply,29); +} +/*----------------------------------------------------------------------*/ +static int EL737SContinue(struct __COUNTER *self){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[50], pReply[30]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + pPriv->lastStatus = HWBusy; + return EL737SCommand(pPriv,"CO\r",pReply,29); +} +/*---------------------------------------------------------------------*/ +static int EL737SHalt(struct __COUNTER *self){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[50], pReply[30]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + pPriv->lastStatus = HWBusy; + return EL737SCommand(pPriv,"S\r",pReply,29); +} +/*-------------------------------------------------------------------*/ +static int EL737STransfer(struct __COUNTER *self){ + pEL737hpsps pPriv = NULL; + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + return updateMonitors(self); +} +/*--------------------------------------------------------------------*/ +static int EL737SGetError(struct __COUNTER *self, int *iCode, + char *pError, int errLen){ + pEL737hpsps pPriv = NULL; + assert(self); + pPriv = (pEL737hpsps)self->pData; + + *iCode = pPriv->errorCode; + switch(pPriv->errorCode){ + case OFFLINE: + strncpy(pError,"EL737 is offline",errLen); + break; + case OVERFLOW: + strncpy(pError,"EL737 reported overflow, communication problem",errLen); + break; + case BADRANGE: + strncpy(pError,"EL737 parameter is out of range",errLen); + break; + case BADTRANGE: + strncpy(pError,"preset timer out of range",errLen); + break; + case BADCOMMAND: + strncpy(pError,"EL737 received unknown command or is busy",errLen); + break; + case BADPARAM: + strncpy(pError,"EL737 parameter is awful",errLen); + break; + case NOPARAM: + strncpy(pError,"EL737 parameter missing",errLen); + break; + case TOMANYCOUNTS: + strncpy(pError,"EL737 counters overflowed",errLen); + break; + case SYSERROR: + strncpy(pError,"EL737 has an internal system error",errLen); + break; + case BADREPLY: + snprintf(pError,errLen,"EL737 sent an unexpected reply: %s", + pPriv->badReply); + break; + case SELECTFAIL: + strncpy(pError,"select system call failed, network trouble",errLen); + break; + case TIMEOUT737: + strncpy(pError,"timeout or network problem while waiting for status repsonse",errLen); + break; + case TOMANYREADERRORS: + strncpy(pError,"Failed more then three times to read counter box",errLen); + break; + case DETOVERLOAD: + strncpy(pError,"Shutter closed due to detector overload",errLen); + break; + default: + getRS232Error(pPriv->errorCode,pError,errLen); + } + return 1; +} +/*--------------------------------------------------------------------*/ +static int EL737SFixIt(struct __COUNTER *self, int iCode){ + pEL737hpsps pPriv = NULL; + int status; + char pReply[50]; + char buffer[256]; + int dataLen = 255; + int i; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + switch(iCode){ + case BADPARAM: + case NOPARAM: + case BADRANGE: + case BADTRANGE: + case OVERFLOW: + return COREDO; + break; + case BADREPLY: + case TIMEOUT737: + case TIMEOUT: + for(i = 0; i < 3; i++){ + status = readRS232TillTerm(pPriv->controller,buffer,&dataLen); + if(status == 1){ + return COREDO; + } + } + /* + If nothing can be read, the only fixable cause is a network breakdown + Try to fix this. If this does not work: give up + */ + closeRS232(pPriv->controller); + SicsWait(60); + status = initRS232(pPriv->controller); + if(status != 1){ + return COTERM; + } else { + return COREDO; + } + break; + case OFFLINE: + EL737SCommand(pPriv,"RMT 1\r",pReply,49); + EL737SCommand(pPriv,"echo 2\r",pReply,49); + return COREDO; + break; + case BADCOMMAND: /* can be busy, stop it and try again */ + EL737SCommand(pPriv,"S\r",pReply,49); + return COREDO; + break; + case TOMANYCOUNTS: + case SYSERROR: + case DETOVERLOAD: + return COTERM; + break; + default: + /* + network problem; try to reopen + */ + closeRS232(pPriv->controller); + SicsWait(60); + status = initRS232(pPriv->controller); + if(status != 1){ + return COTERM; + } else { + return COREDO; + } + } +} +/*------------------------------------------------------------------------*/ +static int EL737SSet(struct __COUNTER *self, char *name, int iCter, + float fVal){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[80], pReply[50]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + if(strcmp(name,"threshold") == 0){ + sprintf(pCommand,"DL %1.1d %f\r",iCter, fVal); + if(!EL737SCommand(pPriv,pCommand,pReply,49)){ + return 0; + } + sprintf(pCommand,"DR %1.1d\r",iCter); + if(!EL737SCommand(pPriv,pCommand,pReply,49)){ + return 0; + } + return 1; + } else { + self->iErrorCode = UNKNOWNPAR; + return 0; + } +} +/*----------------------------------------------------------------------*/ +static int EL737SGet(struct __COUNTER *self, char *name, int iCter, + float *fVal){ + pEL737hpsps pPriv = NULL; + int status; + char pCommand[80], pReply[50]; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + if(strcmp(name,"threshold") == 0){ + sprintf(pCommand,"DL %1.1d\r",iCter); + if(!EL737SCommand(pPriv,pCommand,pReply,49)){ + return 0; + } + sscanf(pReply,"%f", fVal); + return 1; + } else { + self->iErrorCode = UNKNOWNPAR; + return 0; + } +} +/*--------------------------------------------------------------------*/ +static int EL737SSend(struct __COUNTER *self, char *pText, char *pReply, + int iReplyLen){ + pEL737hpsps pPriv = NULL; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + fixMode(pPriv); + return EL737SCommand(pPriv,pText,pReply,iReplyLen); +} +/*---------------------------------------------------------------------*/ +static void KillHP(pCounterDriver self){ + pEL737hpsps pPriv = NULL; + + assert(self); + pPriv = (pEL737hpsps)self->pData; + + if(!pPriv){ + return; + } + if(pPriv->controller != NULL){ + KillRS232(pPriv->controller); + } + if(pPriv->badReply != NULL){ + free(pPriv->badReply); + } + free(pPriv); +} +/*-------------------------------------------------------------------*/ +pCounterDriver MakeEL737hpsps(SConnection *pCon, char *name, + int argc, char *argv[]){ + pCounterDriver pNew = NULL; + pEL737hpsps pPriv = NULL; + char pHost[132]; + int port, status; + + /* + check arguments + */ + if(argc < 3) { + SCWrite(pCon,"ERROR: insufficient no af arguments to create EL737HPSPS", + eError); + return NULL; + } + if(!isNumeric(argv[1])){ + SCWrite(pCon,"ERROR: expected numeric argument for port number", + eError); + return NULL; + } + port = atoi(argv[1]); + strncpy(pHost,argv[0],131); + + /* + allocate a bank worth of memory ........... + */ + pNew = CreateCounterDriver(name,"EL737HPSPS"); + pPriv = (pEL737hpsps)malloc(sizeof(EL737hpsps)); + if(!pNew || !pPriv){ + return NULL; + } + memset(pPriv,0,sizeof(EL737hpsps)); + pPriv->controller = createRS232(pHost,port); + if(!pPriv->controller){ + DeleteCounterDriver(pNew); + return NULL; + } + pPriv->sps = (pSPS)FindCommandData(pServ->pSics,argv[2],"SPS"); + if(pPriv->sps == NULL){ + SCWrite(pCon,"ERROR: SPS not found",eError); + DeleteCounterDriver(pNew); + return NULL; + } + + /* assign functions */ + pNew->GetStatus = EL737SStatus; + pNew->Start = EL737SStart; + pNew->Halt = EL737SHalt; + pNew->ReadValues = EL737STransfer; + pNew->GetError = EL737SGetError; + pNew->TryAndFixIt = EL737SFixIt; + pNew->Pause = EL737SPause; + pNew->Continue = EL737SContinue; + pNew->Set = EL737SSet; + pNew->Get = EL737SGet; + pNew->Send = EL737SSend; + pNew->KillPrivate = KillHP; + pNew->iNoOfMonitors = 7; + pNew->fTime = 0.; + pNew->pData = pPriv; + + /* + initialize connection + */ + setRS232Debug(pPriv->controller,0); + setRS232ReplyTerminator(pPriv->controller,"\r"); + status = initRS232(pPriv->controller); + status = EL737SCommand(pPriv,"RMT 1\r",pHost,131); + status = EL737SCommand(pPriv,"RMT 1\r",pHost,131); + status = EL737SCommand(pPriv,"ECHO 2\r",pHost,131); + + return pNew; +} + + + diff --git a/make_gen b/make_gen index e01e374..90e6e49 100644 --- a/make_gen +++ b/make_gen @@ -18,7 +18,7 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \ $(MZOBJ) amordrive.o amorset.o tcpdornier.o sinqhttp.o\ dgrambroadcast.o sinq.o tabledrive.o tcpdocho.o julcho.o \ - ritastorage.o poldizug.o audinelib.o delcam.o + ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o MZOBJ=fsm.o logger.o sugar.o pardef.o ease.o strobj.o oxinst.o logreader.o \ ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o arrobj.o \ diff --git a/psi.c b/psi.c index e72d4d0..ef5be59 100644 --- a/psi.c +++ b/psi.c @@ -244,6 +244,8 @@ extern pCounterDriver MakeEL737HP(SConnection *pCon, char *name, int argc, char *argv[]); extern pCounterDriver MakeEL737HPV2(SConnection *pCon, char *name, int argc, char *argv[]); +pCounterDriver MakeEL737hpsps(SConnection *pCon, char *name, + int argc, char *argv[]); /*-------------------------------------------------------------------*/ static pCounterDriver CreatePsiCounterDriver(SConnection *pCon, int argc, @@ -257,6 +259,8 @@ static pCounterDriver CreatePsiCounterDriver(SConnection *pCon, pNew = CreateEL737Counter(pCon,argv[1],argc-3,&argv[3]); } else if(strcmp(argv[2],"el737hp") == 0){ pNew = MakeEL737HP(pCon,argv[1],argc-3,&argv[3]); + } else if(strcmp(argv[2],"el737hpsps") == 0){ + pNew = MakeEL737hpsps(pCon,argv[1],argc-3,&argv[3]); } else if(strcmp(argv[2],"el737hpv2") == 0){ pNew = MakeEL737HPV2(pCon,argv[1],argc-3,&argv[3]); } else if(strcmp(argv[2],"ecb") == 0){ diff --git a/sinqhttp.c b/sinqhttp.c index 17cd186..22e84fe 100644 --- a/sinqhttp.c +++ b/sinqhttp.c @@ -393,8 +393,8 @@ static int SinqHttpStatus(pHistDriver self,SConnection *pCon){ if(httpStatus != ghttp_done){ strncpy(pPriv->hmError,"Reconnect", 511); pPriv->errorCode = SERVERERROR; - return HWFault; pPriv->asyncRunning = 0; + return HWFault; } break; case ghttp_not_done: