From 1969980f0f79c5c9052688a6057d91c27e524f9f Mon Sep 17 00:00:00 2001 From: cvs Date: Fri, 14 Mar 2003 16:14:31 +0000 Subject: [PATCH] - Added code to read SANS TOF frames from a) files and b) from HM - Fixed an bug causing core dumps on bad Tcl scripts - Started on a syntax checker for SICS --- Makefile | 2 +- amorstat.c | 9 +- amortest.tcl | 7 +- commandlog.c | 32 ++++- conman.c | 8 +- conman.h | 4 +- devexec.c | 11 +- frame.c | 239 ++++++++++++++++++++++++++++++++++ frame.h | 22 ++++ frame.w | 32 +++++ macro.c | 5 +- nread.c | 1 + nxdata.c | 12 +- ofac.c | 3 + sinqhm/SinqHM_def.h | 3 + sinqhm/SinqHM_srv_routines.c | 81 ++++++++++++ telnet.c | 2 +- utils/check/sicssyntax.tex | 86 ++++++++++++ utils/check/sicssyntaxlib.tcl | 168 ++++++++++++++++++++++++ 19 files changed, 700 insertions(+), 27 deletions(-) create mode 100644 frame.c create mode 100644 frame.h create mode 100644 frame.w create mode 100644 utils/check/sicssyntax.tex create mode 100644 utils/check/sicssyntaxlib.tcl diff --git a/Makefile b/Makefile index 8ee274a4..3757225c 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ hmcontrol.o userscan.o slsmagnet.o rs232controller.o lomax.o \ polterwrite.o fourlib.o motreg.o motreglist.o anticollider.o \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o \ - ecbcounter.o hmdata.o tdchm.o nxscript.o A1931.o + ecbcounter.o hmdata.o tdchm.o nxscript.o A1931.o frame.o MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/amorstat.c b/amorstat.c index 539993ef..1b2b9d3a 100644 --- a/amorstat.c +++ b/amorstat.c @@ -503,7 +503,7 @@ /* get size of our problem */ GetHistDim(self->pHM,iDim,&i3); - assert(i3 == 3); + /* assert(i3 == 3); */ /* allocate some data */ length = 2 + iDim[0]*iDim[1]; @@ -546,7 +546,7 @@ iImage[i] = htonl(iImage[i]); } /* - printf("Collpased maximum: %d\n",iMax); + printf("Collapsed maximum: %d\n",iMax); */ if(status != 1) { @@ -557,14 +557,15 @@ else { /* - we are in simulation and justcreate some random numbers + we are in simulation and just create some random numbers */ for(i = 0; i < iDim[0]; i++) { for(i2 = 0; i2 < iDim[1]; i2++) { iIdx = i*iDim[1] + i2; - iImage[iIdx+2] = htonl(random()); + iImage[iIdx+2] = htonl(random()); + /* iImage[iIdx+2] = htonl(77);*/ } } } diff --git a/amortest.tcl b/amortest.tcl index c26db223..6905ff7c 100644 --- a/amortest.tcl +++ b/amortest.tcl @@ -185,18 +185,17 @@ Motor COX SIM -100. 100. .1 2. # counter x ClientPut "Motors initialized" #======================== histogram memory -MakeHM hm SinqHM -#MakeHM hm SIM +#MakeHM hm SinqHM +MakeHM hm SIM hm configure OverFlowMode Ceil hm configure HistMode PSD -hm configure Rank 1 +hm configure Rank 2 hm configure dim0 256 hm configure dim1 256 hm configure xfac 10 hm configure yfac 10 hm configure xoff 128 hm configure yoff 128 -hm configure Length 65536 hm configure BinWidth 4 hm preset 100. hm CountMode Timer diff --git a/commandlog.c b/commandlog.c index 675050e6..4135c737 100644 --- a/commandlog.c +++ b/commandlog.c @@ -37,10 +37,29 @@ static pCircular pTail = NULL; #define MAXTAIL 1000 /*----------------------------------------------------------------------*/ - void WriteToCommandLog(char *prompt,char *pText) + void WriteToCommandLog(char *prompt,char *text) { int iNL = 0, iPos; - char *pPtr = NULL; + char *pPtr = NULL, *pCopy = NULL, *pText = NULL; + char myBuffer[1024]; + + /* + we change the text, so we need to make a local copy. A copy + is dynamically allocated only if it does not fit into + myBuffer. + */ + if(strlen(text) > 1023){ + pCopy = (char *)malloc((strlen(text)+2)*sizeof(char)); + if(pCopy == NULL){ + return; + } + memset(pCopy,0,(strlen(text)+2)*sizeof(char)); + strcpy(pCopy,text); + pText = pCopy; + } else { + strcpy(myBuffer,text); + pText = myBuffer; + } /* figure out if we have to do a newline with pText as well */ pPtr = strrchr(pText,'\n'); @@ -56,6 +75,9 @@ /* supress status messages */ if(strstr(pText,"status =") != NULL) { + if(pCopy != NULL){ + free(pCopy); + } return; } @@ -64,6 +86,9 @@ */ if(strstr(pText,"TRANSACTIONFINISHED") != NULL) { + if(pCopy != NULL){ + free(pCopy); + } return; } @@ -108,6 +133,9 @@ setCircular(pTail,strdup(pText)); nextCircular(pTail); } + if(pCopy != NULL){ + free(pCopy); + } } /*------------------------------------------------------------------------*/ static void PrintTail(int iNum, SConnection *pCon) diff --git a/conman.c b/conman.c index 0d27705b..0017aa27 100644 --- a/conman.c +++ b/conman.c @@ -22,6 +22,9 @@ Added compressed writing method. Mark Koennecke, October 2000 + Added simulation mode + Mark Koennecke, March 2003 + Copyright: see copyright.h -----------------------------------------------------------------------------*/ #include "fortify.h" @@ -1169,7 +1172,8 @@ void SCSetWriteFunc(SConnection *self, writeFunc x) } if(pCon->iGrab) { - sprintf(pBueffel,"ERROR: Request refused, control has been grabbed by somebody else"); + sprintf(pBueffel, + "ERROR: Request refused, control has been grabbed by somebody else"); SCWrite(pCon,pBueffel,eError); return 0; } @@ -1390,7 +1394,7 @@ void SCSetWriteFunc(SConnection *self, writeFunc x) SCWrite(pCon,pBueffel,eValue); return 1; } - + /* check no or args */ if(argc < 3) { diff --git a/conman.h b/conman.h index 93011394..9dae9d1e 100644 --- a/conman.h +++ b/conman.h @@ -113,7 +113,9 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int SCMatchRights(SConnection *pCon, int iCode); int SCGetOutClass(SConnection *self); int SCGetGrab(SConnection *pCon); - +/********************* simulation mode ************************************/ + void SCSetSimMode(SConnection *pCon, int value); + int SCinSimMode(SConnection *pCon); /* **************************** Invocation ******************************** */ int SCInvoke(SConnection *self,SicsInterp *pInter,char *pCommand); diff --git a/devexec.c b/devexec.c index 954f87b3..c6016277 100644 --- a/devexec.c +++ b/devexec.c @@ -162,7 +162,7 @@ { pDevEntry pNew = NULL; int iRet; - char pBueffel[132]; + char pBueffel[132], pError[80]; pIDrivable pDrivInt = NULL; pICountable pCountInt = NULL; @@ -199,16 +199,16 @@ return 0; } - /* start it */ + /* start it */ pDrivInt = pDes->GetInterface(pData,DRIVEID); pCountInt = pDes->GetInterface(pData,COUNTID); if(pDrivInt) { - iRet = pDrivInt->SetValue(pData,pCon,fNew); + iRet = pDrivInt->SetValue(pData,pCon,fNew); } else if(pCountInt) { - iRet = pCountInt->StartCount(pData,pCon); + iRet = pCountInt->StartCount(pData,pCon); } else { /* this is a programmers error */ @@ -356,6 +356,9 @@ return 1; } + /* + check the status of all registered devices. Remove when finished + */ iRet = LLDnodePtr2First(self->iList); while(iRet != 0) { diff --git a/frame.c b/frame.c new file mode 100644 index 00000000..e9fdb8bb --- /dev/null +++ b/frame.c @@ -0,0 +1,239 @@ +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. The result is sent to the demanding client in UUencoded + format. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +---------------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "stringdict.h" +#include "counter.h" +#include "HistMem.h" +#include "HistMem.i" +#include "HistDriv.i" +#include "hardsup/sinqhm.h" +#include "sinqhmdriv.i" +#include "nxdict.h" +#include "frame.h" +/*======================================================================*/ +static int readHMFrame(SConnection *pCon, pHistMem pHM, int nFrame){ + HistInt *buffer = NULL; + int iDim[MAXDIM], rank, length, status, i; + pSINQHM pHist; + SinqHMDriv *pTata; + + /* + find dimensions and allocate data + */ + GetHistDim(pHM,iDim,&rank); + if(rank < 2){ + SCWrite(pCon,"ERROR: no PSD data present, cannot send frame",eError); + return 0; + } + length = iDim[0]*iDim[1]; + buffer = (HistInt *)malloc((length + 2)*sizeof(HistInt)); + if(!buffer){ + SCWrite(pCon,"ERROR: out of memory in readHMFrame",eError); + return 0; + } + memset(buffer,0,(length+2)*sizeof(HistInt)); + + /* + first two values are dimensions + */ + buffer[0] = htonl(iDim[0]); + buffer[1] = htonl(iDim[1]); + + if(isSINQHMDriv(pHM->pDriv) && rank == 3) { + /* + read from HM. The 5 is PROJECT__FRAME in Sinqhm_def.h + Again: be friendly: fix out of range frames + */ + if(nFrame < 0){ + nFrame = 0; + } + if(nFrame >= iDim[2]){ + nFrame = iDim[2]-1; + } + pTata = (SinqHMDriv *)pHM->pDriv->pPriv; + pHist = (pSINQHM)pTata->pMaster; + status = SINQHMProject(pHist, 5, 0, nFrame, + 0, iDim[1], buffer+2,length*sizeof(HistInt)); + if(status != 1){ + SCWrite(pCon,"ERROR: SINQHM refused to deliver frame",eError); + free(buffer); + return 0; + } + } else { + /* + be friendly, just read the 2D data which is there + */ + status = GetHistogram(pHM,pCon,0,0,length,buffer+2,length*sizeof(HistInt)); + if(!status){ + free(buffer); + return status; + } + } + + /* + enforce network byte order + */ + for(i = 0; i < length; i++){ + buffer[i+2] = htonl(buffer[i+2]); + } + + SCWriteUUencoded(pCon,"framedata", buffer,(length+2)*sizeof(HistInt)); + free(buffer); + + return 1; +} +/*=======================================================================*/ +static int readFileFrame(SConnection *pCon, + char *file, char *dictFile, + char *alias, int nFrame){ + int status, iDim[NX_MAXRANK], rank = 0, type = 0; + int iStart[3], iSize[3], length, i; + int *buffer = NULL; + NXhandle fileHandle; + NXdict dictHandle; + char error[512]; + + status = NXopen(file,NXACC_READ,&fileHandle); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open %s", file); + SCWrite(pCon,error,eError); + return 0; + } + status = NXDinitfromfile(dictFile, &dictHandle); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open dictionary %s", dictFile); + NXclose(&fileHandle); + SCWrite(pCon,error,eError); + return 0; + } + + status = NXDopenalias(fileHandle,dictHandle,alias); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open alias %s", alias); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,error,eError); + return 0; + } + + status = NXgetinfo(fileHandle,&rank,iDim,&type); + if(type != NX_INT32 && type != NX_UINT32)type = -1; + if(status != NX_OK || rank < 2 || type < 0 ){ + sprintf(error,"ERROR: Dataset does not match!"); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,error,eError); + return 0; + } + + /* + allocate space + */ + length = iDim[0]*iDim[1]; + buffer = (int *)malloc((length+2)*sizeof(int)); + if(!buffer){ + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,"ERROR: out of memory in readFrameFromFile",eError); + return 0; + } + memset(buffer,0,(length+2)*sizeof(int)); + + /* + first two values: dimensions + */ + buffer[0] = htonl(iDim[0]); + buffer[1] = htonl(iDim[1]); + + if(rank == 2){ + /* + be friendly + */ + status = NXgetdata(fileHandle,buffer+2); + } else { + iStart[0] = iStart[1] = 0; + iStart[2] = nFrame; + iSize[0] = iDim[0]; + iSize[1] = iDim[1]; + iSize[2] = 1; + status = NXgetslab(fileHandle,buffer+2,iStart,iSize); + } + if(status != NX_OK){ + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + free(buffer); + SCWrite(pCon,"ERROR: failed to read data",eError); + return 0; + } + + /* + enforce network byte order + */ + for(i = 0; i < length; i++){ + buffer[2+i] = htonl(buffer[2+i]); + } + + SCWriteUUencoded(pCon,"framedata",buffer,(length+2)*sizeof(int)); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + free(buffer); + return 1; +} +/*=======================================================================*/ +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHistMem pHM; + int nFrame; + + if(argc < 2){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame", + eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"hm") == 0){ + if(argc < 4){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame", + eError); + return 0; + } + pHM = (pHistMem)FindCommandData(pSics,argv[2],"HistMem"); + if(pHM == NULL){ + SCWrite(pCon,"ERROR: Did not find histogram memory",eError); + return 0; + } + nFrame = atoi(argv[3]); + return readHMFrame(pCon,pHM,nFrame); + } else if(strcmp(argv[1],"file") == 0){ + if(argc < 6 ){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDframe file", + eError); + return 0; + } + nFrame = atoi(argv[5]); + return readFileFrame(pCon,argv[2],argv[3],argv[4],nFrame); + } else { + SCWrite(pCon,"ERROR: subcommand to PSDframe not recognised",eError); + return 0; + } +} +/*======================================================================*/ +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + return AddCommand(pSics,"PSDframe",PSDFrameAction,NULL,NULL); +} + diff --git a/frame.h b/frame.h new file mode 100644 index 00000000..af5a1efd --- /dev/null +++ b/frame.h @@ -0,0 +1,22 @@ + +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +*/ +#ifndef SICSFRAME +#define SICSFRAME + +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif diff --git a/frame.w b/frame.w new file mode 100644 index 00000000..c2bcfe29 --- /dev/null +++ b/frame.w @@ -0,0 +1,32 @@ +\subsection{Frame} +This module allows to retrieve data frames from a 3D histogram (PSD plus +time dimension). This can be done either from a Sinq histogram memory +and old data files visible from the SICS server. + +This module has no data structure and only implements the usual +interpreter interface functions. + + +@o frame.h @{ +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +*/ +#ifndef SICSFRAME +#define SICSFRAME + +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif +@} \ No newline at end of file diff --git a/macro.c b/macro.c index 45980b0e..33460618 100644 --- a/macro.c +++ b/macro.c @@ -438,8 +438,9 @@ SCWrite(pCon,pTcl->result,eError); } pCom = Tcl_DStringValue(&command); - sprintf(pBueffel,"ERROR: in Tcl line: %s",pCom); - SCWrite(pCon,pBueffel,eError); + SCWrite(pCon,"ERROR: in Tcl block:",eError); + SCWrite(pCon,pCom,eError); + SCWrite(pCon,"ERROR: end of Tcl error block",eError); } else /* SICS error */ { diff --git a/nread.c b/nread.c index 4a6b3c97..461bf3d1 100644 --- a/nread.c +++ b/nread.c @@ -494,6 +494,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */ case '\r': case '\n': iStat = CostaTop(pItem->pCon->pStack,pItem->pHold); + /* printf("%s\n",pItem->pHold); */ if(!iStat) { SCWrite(pItem->pCon,"ERROR: Busy",eError); diff --git a/nxdata.c b/nxdata.c index eb4b2a5b..80764f47 100644 --- a/nxdata.c +++ b/nxdata.c @@ -726,12 +726,8 @@ NXclosedata(Nfil); /* histogram Length */ - iStat = HistGetOption(pHist,"Length",pBuffer,131); - if(!iStat) - { - return 0; - } - iVal = atoi(pBuffer); + GetHistDim(pHist,iDim,&iVal); + iVal = iDim[0]; if(iVal < 1) { return 0; @@ -831,6 +827,10 @@ SNputdata1att(Nfil,"sample_mur",NX_FLOAT32, 1,&pVar->fVal, "Units","???"); } + /* do a3 */ + SNPutMotor(Nfil,pSics,pCon,"a3", + "sample_table_rotation","degree"); + /* write sample environment here */ pCom = FindCommand(pSics,"temperature"); if(pCom) diff --git a/ofac.c b/ofac.c index 1deb7b9b..a62c0a7a 100644 --- a/ofac.c +++ b/ofac.c @@ -111,6 +111,7 @@ #include "gpibcontroller.h" #include "ecb.h" #include "nxscript.h" +#include "frame.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -297,6 +298,7 @@ AddCommand(pInter,"MakeGPIB",MakeGPIB,NULL,NULL); AddCommand(pInter,"MakeECB",MakeECB,NULL,NULL); AddCommand(pInter,"MakeNXScript",MakeNXScript,NULL,NULL); + AddCommand(pInter,"MakePSDFrame",MakeFrameFunc,NULL,NULL); } /*---------------------------------------------------------------------------*/ static void KillIniCommands(SicsInterp *pSics) @@ -360,6 +362,7 @@ RemoveCommand(pSics,"MakeGPIB"); RemoveCommand(pSics,"MakeECB"); RemoveCommand(pSics,"MakeNXScript"); + RemoveCommand(pSics,"MakePSDFrame"); } diff --git a/sinqhm/SinqHM_def.h b/sinqhm/SinqHM_def.h index bdea8b80..b7860eb9 100755 --- a/sinqhm/SinqHM_def.h +++ b/sinqhm/SinqHM_def.h @@ -118,6 +118,9 @@ #define PROJECT__SAMPLE 0x0004 /* sum a rectangular part of the PSD detector in time */ +#define PROJECT__FRAME 0x0005 /* select a frame from a 3D histogram: + 2 position dims plus time binning + */ /* ** ---------------------------------------------------------- ** Definition of bits in of TOF edge-array diff --git a/sinqhm/SinqHM_srv_routines.c b/sinqhm/SinqHM_srv_routines.c index 79fb8dfe..834b60b5 100755 --- a/sinqhm/SinqHM_srv_routines.c +++ b/sinqhm/SinqHM_srv_routines.c @@ -2203,6 +2203,80 @@ extern PART_ID sysHighMemPart; exit (KER__BAD_VALUE); } } +/** + * -------------------------------------------------------------------------- + * project_frame reads one time frame of a TOF or PSD histogram + */ +static int project_frame(int rw_skt, int pkt_size, int nx){ + struct rply_buff_struct rply; + uint *buffer = NULL; + uchar *bufPtr; + int i, bytesToSend, nSend, bytesSent; + register union { + void *base; + uchar *ch; + usint *i2; + uint *i4; + } hm_pntr; + + printf("PROJECT: Trying to retrieve time frame: %d\n", nx); + + /* + check arguments + */ + if(nx < 0 || nx >= N_bins){ + printf("PROJECT FRAME: bad time frame requested: 0 < %d < %d\n", + nx,N_bins); + rply_status_setup (&rply, KER__BAD_VALUE, 0, "Bad argument"); + rply_status_send (rw_skt, &rply); + return OK; + } + + /* + allocate space + */ + buffer = (uint *)malloc(N_hists*sizeof(uint)); + if(!buffer){ + printf ("\n\007 -- SQHM_PROJECT-FRAME: failed to get buffer!\n"); + rply_status_setup_and_send (rw_skt, &rply, KER__BAD_ALLOC, 0, + "Failed to get buffer for projecting data"); + return OK; + } + + /* + fill buffer + FIX: This works only OK with 4 byte HM data. + */ + hm_pntr.i4 = Hist_base_addr; + for(i = 0; i < N_hists;i++){ + buffer[i] = htonl(*(hm_pntr.i4 + (i*N_bins) + nx)); + } + + /* + build reply and send data + */ + rply.bigend = 0x12345678; + rply.u.project.n_bins = htonl(N_hists); + rply.u.project.bytes_per_bin = htonl(4); + rply.u.project.cnts_lo = 0; + rply.u.project.cnts_hi = 0; + rply_status_setup_and_send (rw_skt, &rply, KER__SUCCESS, 0, NULL); + bufPtr = (uchar *)buffer; + bytesToSend = N_hists*4; + while(bytesToSend > 0){ + nSend = (bytesToSend > pkt_size) ? pkt_size : bytesToSend; + bytesSent = send(rw_skt,bufPtr,nSend,0); + if(bytesSent > 0){ + bytesToSend -= bytesSent; + bufPtr += bytesSent; + } else { + return ERROR; + } + } + free(buffer); + + return OK; +} /* **--------------------------------------------------------------------------*/ int do_project ( @@ -2322,6 +2396,9 @@ extern PART_ID sysHighMemPart; break; /*-----------------------------------------------------------*/ case SQHM__TOF: /* Time-of-Flight Mode */ + if( (sub_code & PROJECT__FRAME) == 0){ + return project_frame(rw_skt,pkt_size,nx); + } if ((sub_code & PROJECT__1_DIM) != 0) { printf ("\n\007%s -- SQHM_PROJECT: SQHM__TOF+PROJECT__1_DIM not yet " @@ -2389,6 +2466,10 @@ extern PART_ID sysHighMemPart; /* ** code for TRICS, AMOR PSD */ + if( (sub_code & PROJECT__FRAME) == 0){ + return project_frame(rw_skt,pkt_size,nx); + } + if(sub_code == PROJECT__COLL){ my_nbins = psdXSize * psdYSize; nTime = Tof_edges[0]->n_bins; diff --git a/telnet.c b/telnet.c index ba483ff3..b0f5db36 100644 --- a/telnet.c +++ b/telnet.c @@ -78,7 +78,7 @@ SCWrite(pCon,"Continuing here seriously compromises hacker's ethics",eError); SCWrite(pCon,"You will NOT find valuable data here!",eError); SCWrite(pCon,"The SICS server does NOT allow you to spawn to the system",eError); - SCWrite(pCon,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",eError); + SCWrite(pCon,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",eError); } /*-------------------------------------------------------------------------*/ static void SendGA(SConnection *pCon) diff --git a/utils/check/sicssyntax.tex b/utils/check/sicssyntax.tex new file mode 100644 index 00000000..06824807 --- /dev/null +++ b/utils/check/sicssyntax.tex @@ -0,0 +1,86 @@ +\documentclass[12pt,a4paper]{article} +%%\usepackage[dvips]{graphics} +%%\usepackage{epsf} +\setlength{\textheight}{24cm} +\setlength{\textwidth}{16cm} +\setlength{\headheight}{0cm} +\setlength{\headsep}{0cm} +\setlength{\topmargin}{0cm} +\setlength{\oddsidemargin}{0cm} +\setlength{\evensidemargin}{0cm} +\setlength{\hoffset}{0cm} +\setlength{\marginparwidth}{0cm} + +\begin{document} +\begin{center} +\begin{Large} +SICS Syntax Checker\\ +Implementation Notes\\ +\end{Large} +Mark K\"onnecke\\ +Mark.Koennecke@psi.ch\\ +March/April 2003\\ +Laboratory for Neutron Scattering\\ +Paul Scherrer Institute\\ +CH--5232 Villigen--PSI +Switzerland +\end{center} + +Users wish to check their batch files for syntax errors before +submitting them to SICS for the weekend or the night. Unfortunately +checking SICS syntax is not so easy as it consists of Tcl syntax plus +SICS commands. In order to implement a syntax checker various +possibilities exist:\begin{itemize} +\item Implement the syntax checker as a calculation mode within +SICS. This has the disadvantage that the syntax check can only be run +by one person and only when the SICS server is not performing an +experiment. This is due to the fact, that SICS has only one set of +variables which may be changed dureing the syntax check. In order to +prevent corruption the security measures stated above are necessary. +\item Use a SICServer with simulated hardware. This would +work. Problems are that this is very time consuming to set up and the +synchronisation of parameter values with the main SICServer. This has +been solved through the sync command and thus this option is available +for complex scripts. +\item Use a Tcl interpreter with dummy SICS commands as a syntax +checker. In many cases batch files are fairly simple and a complete +simulation is not needed. The such a option would be sufficient. +\end{itemize} +\end{document} + +\section{The Tcl Syntax Checker} +This section describes the syntax checker built from a Tcl interpreter +with dummy routines testing SICS syntax. The dummy procedures only +have to test the syntax and else do nothing. Not many such proecdures +have to be implemented but a means is needed for mapping names, for +instance motor names, to a suitable procedure for checking the syntax. + +This syntax checker can be used in a variety of situations: +\begin{itemize} +\item Standalone: the preferred mode of operation +\item Within SICS: SICS would need to have a second Tcl interpreter +for this purpose in order to prevent corruption of the main +interpreter. Even then a rogue script could go into an endless loop +and thus hang the SICS server. Thus this second interpreter would have +to run as a separate process or thread. +\item This syntax checker could also help debugging SICS scripts. +\end{itemize} + +For each instrument two files are needed for this syntax checker. The +first is a common library file which implements the syntax checking +procedures and the sics_alias procedure which maps names to +procedures. The second is a mapping file which defines the instrument +and enables those names the instrument provides. This is much like the +instrument initialization file for the main SICS program. + +In order to help in script debugging, a global array with parameter +values defined through the user script will be maintained. + +In a latter stage a connection to the main SICS could be added to the +system. Through this connection the actual configuration of the +instrument could be queried. Also parameter values can be updated in +order to help in debugging sophisticated scripts. Moreover this +connection could be used to check limit violations. + + + diff --git a/utils/check/sicssyntaxlib.tcl b/utils/check/sicssyntaxlib.tcl new file mode 100644 index 00000000..12f5f41c --- /dev/null +++ b/utils/check/sicssyntaxlib.tcl @@ -0,0 +1,168 @@ +#----------------------------------------------------------------------------- +# This is the library file for the Tcl syntax checker for SICS commands. +# The basic idea is this: +# - SICS commands are replaced by Tcl procedures with the same name which +# implement the actual syntax check for this command. +# - As many SICS commands are object commands a facility is needed to map +# syntax checking procedures to names. +# +# copyright: see file COPYRIGHT +# +# Mark Koennecke, March 2003 +#--------------------------------------------------------------------------- +# sicsSyntaxMap maps the procedure syntaxProc to the name name. The name +# is prepended to the argument list in order to make the name available +# in the syntax checking procedure as the first argument +# This means syntax check procedures have two arguments: +# - the name +# - the list of remaining parameters as a string. Use syntaxListify +# to convert the list to a proper list for further processing +#--------------------------------------------------------------------------- +proc sicsSyntaxMap {name syntaxProc} { + append newProc "proc " $name " args " \{ $syntaxProc " " + append newProc $name " " "\$args" \} + eval $newProc +} +#-------------------------------------------------------------------------- +# a helper procedure which tests a value if it is numeric +#-------------------------------------------------------------------------- +proc syntaxNumeric {val} { + set ret [catch {expr $val *1.} msg] + if { $ret == 0} { + return 1 + } else { + return 0 + } +} +#-------------------------------------------------------------------------- +# a helper procedure which converts a stringified list back into a proper +# list +#-------------------------------------------------------------------------- +proc syntaxListify {uff} { + set l [string trim $uff "{}"] + return [split $l] +} +#-------------------------------------------------------------------------- +# a helper procedure which gets a parameter from the global parameter +# array or replaces it by the default 77 if it does not exist +#------------------------------------------------------------------------- +proc syntaxGet {name} { + global sicsPar + if { [info exists sicsPar($name)] == 1} { + return [format "%s = %s" $name \ + $sicsPar($name)] + } else { + return [format " %s = 77" $name] + } +} +#------------------------------------------------------------------------ +# syntaxCounterMode tests if par is a valid counter mode +#----------------------------------------------------------------------- +proc syntaxCounterMode {par} { + set p [string trim [string tolower $par]] + switch $p{ + monitor { return 1} + timer {return 1} + default { return 0} + } +} +#--------------------------------------------------------------------------- +# syntaxDummy is a syntax checking procedure which does nothing. This is a +# quick fix for SICS commands for which no syntax checking procedure has yet +# been defined. +#------------------------------------------------------------------------- +proc syntaxDummy {name args} { + set args [syntaxListify $args] + return +} +#----------------------------------------------------------------------- +# syntaxTextPar is a syntax handling procedure for simple text variables +#---------------------------------------------------------------------- +proc syntaxTextPar {name args} { + global sicsPar + + set args [syntaxListify $args] + if { [llength $args] > 0} { + set sicsPar($name) [join $args] + } else { + if { [info exists sicsPar($name)] == 1} { + return [format "%s = %s" $name \ + $sicsPar($name)] + } else { + return [format " %s = UNKNOWN" $name] + } + } +} +#------------------------------------------------------------------------ +# syntaxNumPar is a syntax handling procedure for a numeric variable +#----------------------------------------------------------------------- +proc syntaxNumPar {name args} { + global sicsPar + + set args [syntaxListify $args] + if { [llength $args] > 0} { + if { [syntaxNumeric [lindex $args 0]] == 1} { + set sicsPar($name) [lindex $args 0] + } else { + error [format \ + "ERROR: expected numeric argument for %s, received: %s" \ + $name [lindex $args 0]] + } + } else { + return [syntaxGet $name] + } +} +#-------------------------------------------------------------------------- +# syntaxMotor handles the syntax for a SICS motor +#------------------------------------------------------------------------- +lappend motSubKey list reset interest uninterest position hardposition +lappend motSub hardlowerlim hardupperlim softlowerlim +lappend motSub softupperlim softzero fixed interruptmode precision +lappend motSub accessmode sign failafter + +proc syntaxMotor {name args} { + global sicsPar motSub motSubKey + + set args [syntaxListify $args] +#----- value request + if { [llength $args] == 0} { + return [syntaxGet $name] + } +#---------- keywords + set subcommand [string tolower [lindex $args 0]] + if { [lsearch $motSubKey $subcommand] >= 0} { + return + } +#---------- parameters + if { [lsearch $motSub $subcommand] < 0} { + error [format "ERROR: motor %s does not know subcommand %s" \ + $name $subcommand] + } else { + if { [llength $args] > 1 } { + set val [lindex $args 1] + if { [syntaxNumeric $val] == 0 } { + error [format "ERROR: %s.%s expected number, received %s" \ + $name $subcommand $val] + } else { + set sicsPar($name.$subcommand) $val + } + } else { + return [syntaxGet $name.$subcommand] + } + } +} +#--------------------------------------------------------------------------- +# syntaxCounter deals with the syntax for a single counter +#--------------------------------------------------------------------------- +proc syntaxCounter {name args} { + global sicsPar motSub motSubKey + + set args [syntaxListify $args] + if { [llength $args == 0} { + error [format "ERROR: subcommand expected to %s" $name] + } +#--------- get command + set subcommand [string trim [string tolower [lindex $args 0]]] + switch $subcommand { + } +} \ No newline at end of file