/*-------------------------------------------------------------------------- S P S Implementation file for the SICS module handling Siemens SPS controllers at SinQ. copyright: see copyright.h I cannot imagine that somebody wants this. It is highly special for SINQ. It handles a protocoll tailor made by Siemens for Sinq. I cannot imagine that somebody wants something from Siemens anyway. Mark Koennnecke, Juli 1998 ---------------------------------------------------------------------------*/ #include #include #include #include #include "fortify.h" #include "hardsup/serialsinq.h" #include "sics.h" #include "lld.h" #include "bit.h" #include "sps.i" #include "sps.h" #include "commandlog.h" /*--------------------- some internal defines ----------------------------*/ #define SPSOFFLINE -10 #define COMMDEAD -11 #define COMMRECONNECT -12 #define COMMTMO -13 /*-------------------------------------------------------------------------*/ static float SimRandom(void) { float fVal; fVal = ( (float) rand() / (float)RAND_MAX) * 100.0; return fVal; } /*--------------------- static functions ---------------------------------*/ static int init(pSPS self) { int iRet; assert(self); assert(self->pHost); /* check if in simulation mode */ if(self->iMode) return 1; /* open the port */ iRet = SerialOpen(&self->pData, self->pHost, self->iPort, self->iChannel); if((iRet != 1) || (self->pData == NULL) ) { self->iLastError = COMMDEAD; return 0; } /* configure terminators */ SerialATerm(&self->pData, "1\r\n"); SerialSendTerm(&self->pData,"\r\n"); return 1; } /*-------------------------------------------------------------------------*/ static int SPSCommand(pSPS self, char *pCommand, char *pReply, int iReplyLen) { int iRet, i; char pError[132]; assert(self); assert(pCommand); assert(pReply); /* try at least three times to get the command through before giving up */ for(i = 0; i < 3; i++) { iRet = SerialWriteRead(&self->pData,pCommand,pReply,iReplyLen); if(iRet != 1) { switch(iRet) { case TIMEOUT: self->iLastError = COMMTMO; continue; break; default: self->iLastError = iRet; SerialError(iRet,pError,131); WriteToCommandLog("SYS: SPS-TROUBLE:",pError); SerialClose(&self->pData); iRet = init(self); if(iRet == 0) { return 0; } continue; break; } } /* now we may still have a TMO or OFL message */ if(strstr(pReply,"?TMO") != NULL) { self->iLastError = COMMTMO; continue; } if(strstr(pReply,"?OFL") != NULL) { self->iLastError = SPSOFFLINE; return 0; } return 1; } return 0; } /*--------------------------------------------------------------------------*/ int SPSSetButton(pSPS self, SConnection *pCon, int iByte, int iBit) { Permission perm; char pCommand[30]; char pBueffel[256]; int iRet, iTest,i; assert(self); assert(pCon); /* first check permissions */ iRet = LLDnodePtr2First(self->lPermissions); iTest = 0; while(iRet != 0) { LLDnodeDataTo(self->lPermissions,&perm); if(perm.iByte == iByte) { if(perm.iBit == iBit) { iTest = SCMatchRights(pCon,perm.iPrivilege); break; } } iRet = LLDnodePtr2Next(self->lPermissions); } if(!iTest) { sprintf(pBueffel,"ERROR: you have no permission to flip %d.%d", iByte,iBit); SCWrite(pCon,pBueffel,eError); return 0; } /* if in sim mode, return true */ if(self->iMode) { return 1; } /* format command and send a command to set a bit through the drain in order to simulate a button press */ sprintf(pCommand,"S%3.3d%1.1d",iByte,iBit); iRet = SPSCommand(self,pCommand,pBueffel,255); if(!iRet) { SCWrite(pCon,pBueffel,eError); SCWrite(pCon,"ERROR: Sending flip command failed",eError); return 0; } return 1; } /*--------------------------------------------------------------------------*/ int SPSGetStatus(pSPS self, int iStatus, int *iSet) { int iRet, i, i2, iVal; unsigned char pByte[16]; char pBueffel[256], pNum[10]; char *pPtr; unsigned char cBit, cMask; assert(self); if((iStatus < 0) || (iStatus >= 128) ) { return -1; } /* if in simulation mode, return 1 */ if(self->iMode) { *iSet = 1; return 1; } /* send an R command down to the SPS */ iRet = SPSCommand(self,"R",pBueffel,255); if(!iRet) { return 0; } /* decode the reply into the Byte array */ pPtr = pBueffel; if(*pPtr != 'R') { return -2; } pPtr++; for(i = 0; i < 16; i++) { /* skip the whitespace */ pPtr++; pNum[0] = *pPtr; pPtr++; pNum[1] = *pPtr; pPtr++; pNum[2] = *pPtr; pPtr++; pNum[3] = '\0'; pByte[i] = atoi(pNum); } /* test the bit */ i = iStatus / 8; cBit = pByte[i]; i2 = iStatus % 8; cMask = 1 << i2; /* printf("Byte %d, Value %d, Bit %d, Value: %d\n", i,cBit, i2, (cBit & cMask)); */ if((cBit & cMask) > 0 ) { *iSet = 1; } else { *iSet = 0; } return 1; } /*------------------------------------------------------------------------- This is a special feature for SANS at SINQ. SANS has a collimator and the length of the collimator can only be deduced from the SPS status message by checking each of nine segments separately. For efficiency this is coded into a special function for SANS. This also needs a special function for testing bits. Mark Koennecke, April 1999 */ static int TestBit(unsigned char cByte, int iBit) { unsigned char cMask; assert(iBit >= 0); assert(iBit < 8); cMask = 1 << iBit; if( (cMask & cByte) > 0) { return 1; } else { return 0; } } /*-----------------------------------------------------------------------*/ int SPSGetSANS(pSPS self, float *fLength) { int iRet, i, i2, iVal; unsigned char pByte[16]; char pBueffel[256], pNum[10]; char *pPtr; unsigned char cBit, cMask; float fLang; assert(self); /* if in simulation mode, return a random number */ if(self->iMode) { *fLength = SimRandom(); return 1; } /* send an R command down to the SPS */ iRet = SPSCommand(self,"R",pBueffel,255); if(!iRet) { return 0; } /* decode the reply into the Byte array */ pPtr = pBueffel; if(*pPtr != 'R') { return -2; } pPtr++; for(i = 0; i < 16; i++) { /* skip the whitespace */ pPtr++; pNum[0] = *pPtr; pPtr++; pNum[1] = *pPtr; pPtr++; pNum[2] = *pPtr; pPtr++; pNum[3] = '\0'; pByte[i] = atoi(pNum); } fLang = 189.; if(TestBit(pByte[0],1) > 0) { fLang = 18.; } /* coll 1 15m */ if(TestBit(pByte[0],3) > 0) { fLang = 15.; } /* coll 2 11 m*/ if(TestBit(pByte[0],7) > 0) { fLang = 11.; } /* coll 3 8 m*/ if(TestBit(pByte[1],3) > 0) { fLang -= 3.; } /* coll 4 6m */ if(TestBit(pByte[1],7) > 0) { fLang -= 2.; } /* coll 5 4.5 m */ if(TestBit(pByte[2],3) > 0) { fLang -= 1.5; } /* coll 6 3 m*/ if(TestBit(pByte[2],7) > 0) { fLang -= 1.5; } /* coll 7 */ if(TestBit(pByte[3],3) > 0) { fLang -= 1.; } /* coll 8 */ if(TestBit(pByte[3],6) > 0) { fLang -= 1.; } if(TestBit(pByte[3],7) > 0) { fLang -= 0.6; } *fLength = fLang; return 1; } /*--------------------------------------------------------------------------*/ int SPSGetADC(pSPS self, int iWhich, int *iValue) { int iADC[8]; int i, iRet; char *pPtr, pBueffel[256], pNum[10]; assert(self); /* check iWhich */ if( (iWhich < 0) || (iWhich > 7) ) { return 0; } /* give a random number in simulation mode */ if(self->iMode) { *iValue = (int)SimRandom(); return 1; } /* send an A command to the box */ iRet = SPSCommand(self,"A",pBueffel,255); if(!iRet) { return 0; } /* decode the result */ pPtr = pBueffel; if(*pPtr != 'A') /* a silly answer was returned */ { SICSLogWrite("SPS: Silly answer in SPSGetADC",eError); return 0; } pPtr++; for(i = 0; i < 8; i++) { pPtr++; /* skip whitespace */ strncpy(pNum,pPtr,5); pNum[5] = '\0'; pPtr += 5; iADC[i] = atoi(pNum); } /* now give the value */ *iValue = iADC[iWhich]; return 1; } /*-----------------------------------------------------------------------*/ void SPSAddPermission(pSPS self, int iByte, int iBit, int iRights) { Permission perm; assert(self); perm.iByte = iByte; perm.iBit = iBit; perm.iPrivilege = iRights; LLDnodeAppendFrom(self->lPermissions,&perm); } /*-------------------------------------------------------------------------*/ void RemoveSPS(void *pData) { pSPS self = NULL; self = (pSPS)pData; if(!self) return; if(self->pHost) { free(self->pHost); } SerialClose(&self->pData); if(self->pDes) { DeleteDescriptor(self->pDes); } LLDdelete(self->lPermissions); free(self); } /*---------------------------------------------------------------------------*/ int SPSFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { int iRet, iVal; pSPS pNew = NULL; char pBueffel[256]; assert(pCon); assert(pSics); /* we need at least two extra arguments: name and either host or sim */ if(argc < 3) { SCWrite(pCon, "ERROR: Insufficient number of arguments for installing SPS", eError); return 0; } /* allocate a new SPS */ pNew = (pSPS)malloc(sizeof(SPS)); if(!pNew) { SCWrite(pCon,"ERROR: no memory to allocate SPS",eError); return 0; } memset(pNew,0,sizeof(SPS)); pNew->pDes = CreateDescriptor("SPS"); pNew->lPermissions = LLDcreate(sizeof(Permission)); if( (!pNew->pDes) || (pNew->lPermissions < 0) ) { SCWrite(pCon,"ERROR: no memory to allocate SPS",eError); return 0; } pNew->pHost = strdup(argv[2]); /* check if we go for sim */ strtolower(argv[2]); if(strcmp(argv[2],"sim") == 0) { pNew->iMode = 1; } else /* we are installing a real one and need tons more arguments */ { if(argc < 5) { SCWrite(pCon, "ERROR: Insufficient number of arguments for installing SPS", eError); RemoveSPS(pNew); return 0; } /* get port number */ iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iVal); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for port, got %s", argv[3]); SCWrite(pCon,pBueffel,eError); RemoveSPS(pNew); return 0; } pNew->iPort = iVal; /* get channel number */ iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iVal); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for channel, got %s", argv[4]); SCWrite(pCon,pBueffel,eError); RemoveSPS(pNew); return 0; } pNew->iChannel = iVal; } /* initialise */ iRet = init(pNew); if(!iRet) { SCWrite(pCon,"ERROR: Failure to initialise SPS controller",eError); RemoveSPS(pNew); return 0; } /* install command */ iRet = AddCommand(pSics, argv[1],SPSAction,RemoveSPS,pNew); if(!iRet) { sprintf(pBueffel,"ERROR: duplicate SPS command %s NOT created", argv[1]); SCWrite(pCon,pBueffel,eError); RemoveSPS(pNew); } return 1; } #include "access.c" /*-------------------------------------------------------------------------*/ int SPSAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pSPS self = NULL; char pBueffel[256]; int iByte, iBit, iSet; int iRet, i; float fLang; self = (pSPS)pData; assert(self); /* we need at least 3 arguments */ if(argc < 2) { sprintf(pBueffel,"ERROR: need at least two arguments to %s", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* do something according to key word */ strtolower(argv[1]); if(strcmp(argv[1],"push") == 0) /* operate a button */ { /* four arguments needed */ if(argc < 4) { sprintf(pBueffel,"ERROR: need at least two arguments to %s push", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* convert arguments */ iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iByte); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for byte, got %s", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iBit); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for bit, got %s", argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } /* try it */ iRet = SPSSetButton(self,pCon,iByte,iBit); if(!iRet) { SCWrite(pCon,"ERROR: Pushing button failed",eError); return 0; } else { SCSendOK(pCon); return 1; } } else if(strcmp(argv[1],"status") == 0) /* status bits */ { /* which bit ? */ if(argc < 3) { sprintf(pBueffel,"ERROR: need at least two arguments to %s push", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iByte); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for bit, got %s", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = SPSGetStatus(self,iByte,&iSet); if(iRet <= 0) { sprintf(pBueffel,"ERROR: failed to read status bit %d", iByte); SCWrite(pCon,pBueffel,eError); return 0; } sprintf(pBueffel,"%s.status.%3.3d = %d",argv[0],iByte,iSet); SCWrite(pCon,pBueffel,eValue); return 1; } else if(strcmp(argv[1],"stat2") == 0) /* status bits */ { if(argc < 4) { sprintf(pBueffel,"ERROR: need at least two arguments to %s stat2", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* which bit ? */ iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iByte); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for bit, got %s", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iBit); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for bit, got %s", argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } if( (iByte <= 0) || (iBit < 0) || (iBit > 7) ) { SCWrite(pCon,"ERROR: arguments out of range for stat2",eError); return 0; } iRet = SPSGetStatus(self,((iByte-1)*8 + iBit),&iSet); if(iRet <= 0) { sprintf(pBueffel,"ERROR: failed to read status bit %d", iByte); SCWrite(pCon,pBueffel,eError); return 0; } sprintf(pBueffel,"%s.status.%3.3d.%1.1d = %d",argv[0],iByte,iBit,iSet); SCWrite(pCon,pBueffel,eValue); return 1; } else if(strcmp(argv[1],"adc") == 0) /* ADC values */ { /* which ADC ? */ iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iByte); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for ADC, got %s", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = SPSGetADC(self,iByte,&iSet); if(!iRet) { sprintf(pBueffel,"ERROR: failed to read ADC %d", iByte); SCWrite(pCon,pBueffel,eError); return 0; } sprintf(pBueffel,"%s.ADC.%1.1d = %d",argv[0],iByte,iSet); SCWrite(pCon,pBueffel,eValue); return 1; } else if(strcmp(argv[1],"perm") == 0) { /* only managers may set permissions */ if(!SCMatchRights(pCon,usMugger)) { SCWrite(pCon,"ERROR: Security: Only mangagers may configure SPS buttons", eError); return 0; } /* we need lots of parameters */ if(argc < 5) { sprintf(pBueffel,"ERROR: need at least three arguments to %s perm", argv[0]); SCWrite(pCon,pBueffel,eError); return 0; } /* convert arguments */ iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iByte); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for byte, got %s", argv[2]); SCWrite(pCon,pBueffel,eError); return 0; } iRet = Tcl_GetInt(pSics->pTcl,argv[3],&iBit); if(iRet != TCL_OK) { sprintf(pBueffel,"ERROR: expected integer argument for bit, got %s", argv[3]); SCWrite(pCon,pBueffel,eError); return 0; } /* try to convert user code */ strtolower(argv[4]); iSet = -10; i = 0; while(aCode[i] != NULL) { if(strcmp(aCode[i],argv[4]) == 0) { iSet = i; break; } i++; } if(iSet < 0) { sprintf(pBueffel,"ERROR: %s is not valid user code",argv[4]); SCWrite(pCon,pBueffel,eError); return 0; } /* do it, finally */ SPSAddPermission(self,iByte,iBit,iSet); SCSendOK(pCon); return 1; } /* -------- sans collimator */ else if(strcmp(argv[1],"colli") == 0) { iRet = SPSGetSANS(self,&fLang); if(!iRet) { SCWrite(pCon,"ERROR: cannot read SANS collimator",eError); return 0; } else { sprintf(pBueffel,"SANS.collimator = %f",fLang); SCWrite(pCon,pBueffel,eValue); return 1; } } sprintf(pBueffel,"ERROR: %s does not not understand subcommand %s", argv[0], argv[1]); SCWrite(pCon,pBueffel,eError); return 0; }