diff --git a/SCinter.c b/SCinter.c index 29daf5e9..450751e7 100644 --- a/SCinter.c +++ b/SCinter.c @@ -421,7 +421,12 @@ extern char *SkipSpace(char *pPtr); pTcl = (Tcl_Interp *)self->pTcl; if(pTcl) { + /* + uncommented: the current versions of Tcl (8.3,4) dump core with a + memory problem deep in the Tcl library. This causes a core dump on + each SICS restart and breaks the use of external tools. Tcl_DeleteInterp(pTcl); + */ } free(self); diff --git a/choco.c b/choco.c index c4db12ab..4df78fc8 100644 --- a/choco.c +++ b/choco.c @@ -161,8 +161,6 @@ { self->pDriv->Close(self->pDriv); self->pDriv->Delete(self->pDriv); - if(self->pDriv->pParList) - free(self->pDriv->pParList); free(self->pDriv); } if(self->pDes) diff --git a/commandlog.c b/commandlog.c index 7f60b573..a001f343 100644 --- a/commandlog.c +++ b/commandlog.c @@ -27,8 +27,6 @@ /* in conman.c */ int TelnetWrite(mkChannel *pSock, char *pText); - - /*-------------------- the command log file pointer ---------------------*/ static FILE *fd = NULL; static FILE *fauto = NULL; @@ -122,6 +120,13 @@ fprintf(fauto,"%s %s\n",prompt, pText); } } + + /* to all listening sockets. The check is necessary to resolve a shutdown problem */ + if(pServ->pTasker != NULL) + { + TaskSignal(pServ->pTasker,COMLOG,pText); + } + /* tail buffer */ if(pTail != NULL) { diff --git a/conman.c b/conman.c index 8f8e3c4a..110b90b0 100644 --- a/conman.c +++ b/conman.c @@ -103,6 +103,7 @@ extern pServer pServ; memset(pCon,0,sizeof(SConnection)); pCon->ident = 0; pCon->next = freeConnections; + pCon->listening = 0; freeConnections = pCon; } /*--------------------------------------------------------------------------*/ @@ -174,6 +175,7 @@ extern pServer pServ; pRes->eInterrupt = eContinue; pRes->lMagic = CONMAGIC; pRes->iLogin = 0; + pRes->listening = 0; pRes->conStart = time(NULL); pRes->write = SCNormalWrite; for(i = 0; i < 10; i++) @@ -203,11 +205,6 @@ extern pServer pServ; pRes->iUserRights = iUser; pRes->iGrab = TokenGrabActive(); - NETInfo(pRes->pSock,pHost,131); - sprintf(pBueffel,"Accepted connection on socket %d from %s", - pRes->pSock->sockid, pHost); - SICSLogWrite(pBueffel,eInternal); - WriteToCommandLog("SYS >", pBueffel); return pRes; @@ -395,7 +392,7 @@ extern pServer pServ; } /* log the kill */ - if(pVictim->pSock) + if(pVictim->pSock && pVictim->iLogin == 1) { sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid); WriteToCommandLog("SYS>",pBueffel); @@ -599,7 +596,9 @@ static int doSockWrite(SConnection *self, char *buffer) if(!iRet) { SCnoSock(self); - WriteToCommandLog("SYS> ","Connection broken on send"); + if(!self->listening && self->iLogin == 1){ + WriteToCommandLog("SYS> ","Connection broken on send"); + } } } else @@ -1358,6 +1357,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) config Rights User Password sets and verifies new user rights config File Filename Logs to another file config output normal | withcode Sets output mode + config listen 0 | 1 enables commandlog listen mode ---------------------------------------------------------------------------*/ int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -1402,6 +1402,27 @@ static void writeToLogFiles(SConnection *self, char *buffer) SCWrite(pCon,pBueffel,eValue); return 1; } + else if(strcmp(argv[1],"listen") == 0) + { + if(argc < 3) + { + snprintf(pBueffel,511,"listen = %d", pCon->listening); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + else + { + pCon->listening = atoi(argv[2]); + if(pCon->listening != 0 && pCon->listening != 1) + { + pCon->listening = 0; + SCWrite(pCon,"ERROR: config listen only accepts 0 or 1 as arguments",eError); + return 0; + } + SCSendOK(pCon); + return 1; + } + } /* check no or args */ if(argc < 3) @@ -1747,6 +1768,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) char *pPtr = NULL; int iRet; char *pUser = NULL, *pPassword = NULL; + char pHost[132], pBueffel[512]; self = (SConnection *)pData; if(!VerifyConnection(self)) @@ -1810,6 +1832,11 @@ static void writeToLogFiles(SConnection *self, char *buffer) SCWrite(self,"Login OK",eError); self->iLogin = 1; SCSetRights(self,iRet); + NETInfo(self->pSock,pHost,131); + sprintf(pBueffel,"Accepted connection on socket %d from %s", + self->pSock->sockid, pHost); + SICSLogWrite(pBueffel,eInternal); + WriteToCommandLog("SYS >", pBueffel); free(pPtr); return 1; } @@ -1863,11 +1890,19 @@ static void writeToLogFiles(SConnection *self, char *buffer) else if(iSignal == SICSBROADCAST) { pPtr = (char *)pSigData; - if(pPtr) + if(pPtr != NULL) { SCWrite(self,pPtr,eWarning); } } + else if(iSignal == COMLOG && self->listening == 1) + { + pPtr = (char *)pSigData; + if(pPtr != NULL) + { + doSockWrite(self,pPtr); + } + } else if(iSignal == TOKENRELEASE) { self->iGrab = 0; diff --git a/conman.h b/conman.h index 3b4d76d0..68a2c781 100644 --- a/conman.h +++ b/conman.h @@ -49,6 +49,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int iOutput; writeFunc write; /* function doing writing */ + int listening; /* for listening to commandlog or other data */ /* execution context */ int eInterrupt; @@ -72,8 +73,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon, */ int iLogin; time_t conStart; - - } SConnection; + } SConnection; #include "nserver.h" diff --git a/counter.c b/counter.c index b5feb33e..396ebd25 100644 --- a/counter.c +++ b/counter.c @@ -103,6 +103,7 @@ if(iRet == OKOK) { self->isUpToDate = 0; + self->badStatusCount = 0; self->tStart = time(&tX); InvokeCallBack(self->pCall,COUNTSTART,pCon); return iRet; @@ -224,11 +225,12 @@ eCt = self->pDriv->GetStatus(self->pDriv,&fControl); if(eCt == HWFault) { + self->badStatusCount++; iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79); sprintf(pBueffel,"WARNING: %s ",pError); SCWrite(pCon,pBueffel,eError); iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr); - if(iRet == COTERM) + if(iRet == COTERM || self->badStatusCount > 3) { SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError); SCSetInterrupt(pCon,eAbortBatch); @@ -247,6 +249,7 @@ sMon.fCurrent = fControl; sMon.fPreset = self->pDriv->fPreset; sMon.pName = self->name; + self->badStatusCount = 0; /* clear: we managed to read OK */ if(self->iCallbackCounter > 20) { InvokeCallBack(self->pCall,MONITOR,&sMon); diff --git a/counter.h b/counter.h index bdefc49c..a91e8241 100644 --- a/counter.h +++ b/counter.h @@ -23,6 +23,7 @@ pICallBack pCall; unsigned long tStart; int iCallbackCounter; + int badStatusCount; } Counter, *pCounter; /*----------------------------- birth & death -----------------------------*/ diff --git a/diffscan.c b/diffscan.c new file mode 100644 index 00000000..91d5b809 --- /dev/null +++ b/diffscan.c @@ -0,0 +1,365 @@ +/*------------------------------------------------------------------- + diffscan is an operator which can perform a fast differential scan + while a motor is running. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +---------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "diffscan.h" +#include "drive.h" +#include "counter.h" + +#define DIFFMONITOR 0 +#define SKIP 1 + +/*-------------------------------------------------------------------*/ +static void KillDiffScan(void *data){ + pDiffScan self = (pDiffScan)data; + + if(self == NULL){ + return; + } + + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + if(self->parArray != NULL){ + ObParDelete(self->parArray); + } + free(self); +} +/*---------------------------------------------------------------------*/ +static int SaveDiffScan(void *data, char *name, FILE *fd){ + pDiffScan self = (pDiffScan)data; + if(self == NULL){ + return 0; + } + fprintf(fd,"%s monitor %f\n",name,ObVal(self->parArray,DIFFMONITOR)); + fprintf(fd,"%s skip %f\n",name,ObVal(self->parArray,SKIP)); + return 1; +} +/*----------------------------------------------------------------------*/ +int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pDiffScan pNew = NULL; + int status; + + pNew = (pDiffScan)malloc(sizeof(DiffScan)); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory creating differential scan", + eError); + return 0; + } + memset(pNew,0,sizeof(DiffScan)); + pNew->pDes = CreateDescriptor("DiffScan"); + pNew->parArray = ObParCreate(2); + if(!pNew->pDes || !pNew->parArray){ + SCWrite(pCon,"ERROR: out of memory creating differential scan", + eError); + KillDiffScan(pNew); + return 0; + } + ObParInit(pNew->parArray, DIFFMONITOR,"monitor",4.0,usUser); + ObParInit(pNew->parArray, SKIP,"skip",.0,usUser); + pNew->pDes->SaveStatus = SaveDiffScan; + + if(argc > 1) { + status = AddCommand(pSics,argv[2], + DiffScanWrapper, + KillDiffScan, + pNew); + + } else { + status = AddCommand(pSics,"diffscan", + DiffScanWrapper, + KillDiffScan, + pNew); + + } + if(status != 1){ + SCWrite(pCon,"ERROR: duplicate diffscan not created",eError); + return 0; + } + return 1; +} +/*----------------------------------------------------------------------*/ +int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pDiffScan self = NULL; + pScanData pScan = NULL; + ObPar *par = NULL; + char pBueffel[255]; + int status; + + self = (pDiffScan)pData; + assert(self); + + if(argc < 2){ + SCWrite(pCon,"ERROR: need arguments to diffscan",eError); + return 0; + } + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + /* + first try to find a scan object and to run + */ + strtolower(argv[1]); + pScan = (pScanData)FindCommandData(pSics,argv[1],"ScanObject"); + if(pScan != NULL && argc > 2){ + status = RunDiffScan(self,pScan,pCon, atof(argv[2])); + return status; + } + + /* + if we end here we are treating variables + */ + if(argc > 2){ + /* + set case + */ + return ObParSet(self->parArray,argv[0],argv[1],atof(argv[2]),pCon); + } else { + /* + get case + */ + par = ObParFind(self->parArray,argv[1]); + if(par != NULL){ + snprintf(pBueffel,255,"%s.%s = %f",argv[0],argv[1],par->fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + snprintf(pBueffel,255,"ERROR: parameter %s not found",argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + } + return 1; +} +/*--------------------------------------------------------------------*/ +static int StartDiffScan(pDiffScan self, pScanData pScan, + SConnection *pCon, float fEnd){ + pVarEntry pVar = NULL; + void *pPtr = NULL; + pCounter pCount = NULL; + char pBueffel[255]; + int status; + + /* + error checks + */ + if(pScan->iScanVar < 1) { + SCWrite(pCon,"ERROR: no scan variable to diffscan",eError); + return 0; + } + if(pScan->iScanVar > 1) { + snprintf(pBueffel,255, + "WARNING: diffscan handles only first scan variable, %d %s", + pScan->iScanVar - 1, + "scan variables ignored"); + SCWrite(pCon,pBueffel, eWarning); + } + + /* + initialize data structure + */ + self->scanObject = pScan; + self->scanObject->pCon = pCon; + self->skip = (int)ObVal(self->parArray,SKIP); + self->scaleMonitor = (int)ObVal(self->parArray,DIFFMONITOR); + self->normalizationScale = -1; + pScan->iCounts = 0; + + /* + get variable + */ + DynarGet(pScan->pScanVar,0,&pPtr); + pVar = (pVarEntry)pPtr; + if(pVar == NULL){ + SCWrite(pCon,"ERROR: cannot access scan variable",eError); + return 0; + } + + /* + drive to start position + */ + status = Drive(pCon,pServ->pSics,ScanVarName(pVar),ScanVarStart(pVar)); + if(status != 1){ + return 0; + } + + /* + Configure counter. We operate in timer mode with a very long + preset mode. Stopping is done explicitly in the diffscan task + */ + SetCounterMode(pScan->pCounterData,eTimer); + SetCounterPreset(pScan->pCounterData,3600.); + + /* + start motor and counter + */ + status = pVar->pInter->SetValue(pVar->pObject,pCon,fEnd); + if(status != OKOK){ + /* + errors will already have been reported in SetValue + */ + return 0; + } + pCount = (pCounter)pScan->pCounterData; + assert(pCount); + status = pCount->pCountInt->StartCount(pCount,pCon); + if(status != OKOK){ + return 0; + } + return 1; +} +/*--------------------------------------------------------------------*/ +static float normalizeEntry(pCountEntry pCount, pCountEntry last, + long monValue, int scaleMon){ + int i; + float fScale; + float value; + long diff; + + /* + calculate scale + */ + diff = pCount->Monitors[scaleMon-1] - last->Monitors[scaleMon-1]; + if(diff > 0) { + fScale = (float)monValue/(float)diff; + } else { + fScale = 0.; + } + value = ((float)(pCount->lCount - last->lCount))*fScale; + pCount->lCount = (long)value; + for(i = 0; i < 10; i++){ + pCount->Monitors[i] = (pCount->Monitors[i] - last->Monitors[i])*fScale; + } + return value; +} +/*--------------------------------------------------------------------*/ +static void copyCountData(pCountEntry last, pCountEntry pCount){ + memcpy(last,pCount,sizeof(CountEntry)); +} +/*---------------------------------------------------------------------*/ +static int DiffScanTask(void *pData){ + pCounter pCount = NULL; + pCountEntry data; + pVarEntry pVar = NULL; + void *pPtr = NULL; + float fPos, countValue; + int status, finish = 1, count; + char pBueffel[255]; + long rawCount, rawMon; + CountEntry rawCopy; + + pDiffScan self = (pDiffScan)pData; + + /* + manage skip + */ + if(self->skip > 0){ + if(self->skipCount > self->skip){ + self->skipCount = 0; + } else { + self->skipCount++; + return 1; + } + } + + /* + read motor status + */ + DynarGet(self->scanObject->pScanVar,0,&pPtr); + pVar = (pVarEntry)pPtr; + status = pVar->pInter->CheckStatus(pVar->pObject,self->scanObject->pCon); + if(status != HWBusy) { + finish = 0; + } + + /* + read values + */ + status = GetDrivablePosition(pVar->pObject,self->scanObject->pCon, + &fPos); + if(status == 0){ + return finish; + } + AppendScanVar(pVar,fPos); + pCount = (pCounter)self->scanObject->pCounterData; + pCount->pCountInt->TransferData(pCount,self->scanObject->pCon); + CollectCounterData(self->scanObject); + + /* + normalize (or not) + */ + DynarGet(self->scanObject->pCounts,self->scanObject->iCounts-1,&pPtr); + data = (pCountEntry)pPtr; + copyCountData(&rawCopy,data); + if(self->normalizationScale < 0){ + countValue = (float)data->lCount; + rawCount = data->lCount; + rawMon = data->Monitors[self->scaleMonitor-1]; + self->normalizationScale = data->Monitors[self->scaleMonitor-1]; + } else { + if(data->Monitors[self->scaleMonitor -1] - + self->last.Monitors[self->scaleMonitor-1] < 5) { + SCWrite(self->scanObject->pCon, + "WARNING: low count rate",eWarning); + } + rawCount = data->lCount; + rawMon = data->Monitors[self->scaleMonitor-1]; + countValue = normalizeEntry(data,&self->last, + self->normalizationScale, + self->scaleMonitor); + } + copyCountData(&self->last,&rawCopy); + + /* + print progress + */ + snprintf(pBueffel,255,"%5d %12.4f %12.4f RAW: %10d %10d", + self->scanObject->iCounts -1, + fPos, countValue, rawCount, + rawMon); + SCWrite(self->scanObject->pCon,pBueffel,eWarning); + InvokeCallBack(self->scanObject->pCall,SCANPOINT,self->scanObject); + + /* + check for interrupt + */ + if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){ + finish = 0; + } + + return finish; +} +/*----------------------------------------------------------------------*/ +int RunDiffScan(pDiffScan self, pScanData pScan, + SConnection *pCon, float fEnd){ + long lID; + pCounter pCount = NULL; + + if(StartDiffScan(self,pScan,pCon,fEnd) != 1) { + return 0; + } + InvokeCallBack(self->scanObject->pCall,SCANSTART,self->scanObject); + + + lID = TaskRegister(pServ->pTasker,DiffScanTask,NULL,NULL,self,10); + TaskWait(pServ->pTasker,lID); + + + pCount = (pCounter)self->scanObject->pCounterData; + pCount->pCountInt->Halt(pCount); + InvokeCallBack(self->scanObject->pCall,SCANEND,self->scanObject); + + return 1; +} diff --git a/diffscan.h b/diffscan.h new file mode 100644 index 00000000..17fa5e4f --- /dev/null +++ b/diffscan.h @@ -0,0 +1,47 @@ + +/*------------------------------------------------------------------- + diffscan is an operator which can perform a fast differential scan + while a motor is running. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +---------------------------------------------------------------------*/ +#ifndef SICSDIFFSCAN +#define SICSDIFFSCAN +#include "obpar.h" +#include "scan.h" +#include "scan.i" + +typedef struct { + pObjectDescriptor pDes; + ObPar *parArray; + int normalizationScale; + int scaleMonitor; + CountEntry last; + int skip; + int skipCount; + pScanData scanObject; + } DiffScan, *pDiffScan; + +/*==================================================================*/ + + /** + * RunDiffScan runs a differential scan. + * @param self The Diffscan object to use + * @param pScan The scan object to use for configuration and for + * for storing the results. + * @param pCon The connection to use for output and errors. + * @param fEnd The end value for the diffscan + */ + int RunDiffScan(pDiffScan self, pScanData pScan, + SConnection *pCon, float fEnd); +/*==================== interpreter wrappers ==========================*/ + int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + + +#endif diff --git a/diffscan.w b/diffscan.w new file mode 100644 index 00000000..b99348bf --- /dev/null +++ b/diffscan.w @@ -0,0 +1,97 @@ +\subsection{Differential Scan} +This is a special very fast but inaccurate scan method. The scan motor is +set into motion and counts are collected on the fly, while the motor +is moving. As neither the motor speed, nor the counters response nor +the source stability can be relied upon to result in equally spaced +and well defined counts, the counts have to be scaled according to the +difference in monitor counts towards the previous count. This is why +this is called differential scan. This is not a +precise scan. But is a very fast one which helps locating peaks or +during alignment. + +This is implemented as an operator on top of the standard scan +module. All scan details, scan variables etc have to be configured in +the main scan module. This object then just runs the diff scan and +stores the result in the main scan object for further processing. For +instance peak location. The end of the scan is calculated from the +start, step and NP of the main scan module. be aware that these values +have no well defined meaning during this kind of scan, NP will be +corrected to account for the points actually measured. + +As motors cannot be guaranteed to run simulataneously, only one scan +variable is suported for this. + +The actual control of this scan is hidden in a task function which is +responsible for storing the data and stopping when the motor has +finished driving. + +In order to do a differential scan a data structure is required: +@d diffscandat @{ +typedef struct { + pObjectDescriptor pDes; + ObPar *parArray; + int normalizationScale; + int scaleMonitor; + CountEntry last; + int skip; + int skipCount; + pScanData scanObject; + } DiffScan, *pDiffScan; +@} +The fields: +\begin{description} +\item[pDes] The standard object descriptor. +\item[parArray] An array of parameters for the module. +\item[normalizationScale] The scale to which to scale counts during +counting.This will be the monitor difference between the first and the +second point. +\item[lastMonitor] is the last monitor read for caluclating differences. +\item[scaleMonitor] The monitor to use for scaling. This should better +be a monitor with a high count rate for acurate scaling. +\item[skip] How many cycles of the main loop to skip between +recordings. +\item[skipCount] Counter for skipped cycles. Together with skip this +is a means to limit the sampling rate of diffscan. +\item[scanObject] The scan object we are operating upon. +\end{description} + +The external interface to this module is like this: +@d diffscanint @{ + /** + * RunDiffScan runs a differential scan. + * @@param self The Diffscan object to use + * @@param pScan The scan object to use for configuration and for + * for storing the results. + * @@param pCon The connection to use for output and errors. + * @@param fEnd The end value for the diffscan + */ + int RunDiffScan(pDiffScan self, pScanData pScan, + SConnection *pCon, float fEnd); +/*==================== interpreter wrappers ==========================*/ + int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +@} + +@o diffscan.h @{ +/*------------------------------------------------------------------- + diffscan is an operator which can perform a fast differential scan + while a motor is running. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +---------------------------------------------------------------------*/ +#ifndef SICSDIFFSCAN +#define SICSDIFFSCAN +#include "obpar.h" +#include "scan.h" +#include "scan.i" +@ +/*==================================================================*/ +@ +#endif +@} \ No newline at end of file diff --git a/event.h b/event.h index ca2d5ee4..4e588698 100644 --- a/event.h +++ b/event.h @@ -1,5 +1,5 @@ -#line 88 "event.w" +#line 89 "event.w" /*---------------------------------------------------------------------------- E V E N T @@ -18,7 +18,7 @@ int Text2Event(char *pText); -#line 101 "event.w" +#line 102 "event.w" @@ -43,7 +43,7 @@ #define BATCHEND 16 #define DRIVSTAT 17 -#line 103 "event.w" +#line 104 "event.w" /*--------------- Signals for the Signalfunction of each task ------------*/ @@ -54,7 +54,8 @@ #define SICSBROADCAST 301 #define TOKENGRAB 302 #define TOKENRELEASE 303 +#define COMLOG 304 -#line 106 "event.w" +#line 107 "event.w" #endif diff --git a/event.tex b/event.tex index 17c7796a..b19694ee 100644 --- a/event.tex +++ b/event.tex @@ -105,6 +105,7 @@ $\langle$VSIG {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@#define SICSBROADCAST 301@\\ \mbox{}\verb@#define TOKENGRAB 302@\\ \mbox{}\verb@#define TOKENRELEASE 303@\\ +\mbox{}\verb@#define COMLOG 304@\\ \mbox{}\verb@@$\diamond$ \end{list} \vspace{-1ex} @@ -121,7 +122,7 @@ number which ocurred. data is the string to send. \item[TOKENGRAB] A connection has successfully grabbed the control token. \item[TOKENRELEASE] A connection has released the control token. - +\item[COMLOG] A command log message. This is to implement listen mode to the command log. \end{description} \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap4} diff --git a/event.w b/event.w index c993b009..b165cf6a 100644 --- a/event.w +++ b/event.w @@ -75,6 +75,7 @@ possible codes are defined. #define SICSBROADCAST 301 #define TOKENGRAB 302 #define TOKENRELEASE 303 +#define COMLOG 304 @} \begin{description} \item[SICSINT] An interrupt has ocurred. The signal data is the interrupt @@ -83,7 +84,7 @@ number which ocurred. data is the string to send. \item[TOKENGRAB] A connection has successfully grabbed the control token. \item[TOKENRELEASE] A connection has released the control token. - +\item[COMLOG] A command log message. This is to implement listen mode to the command log. \end{description} @o event.h -d @{ /*---------------------------------------------------------------------------- diff --git a/exebuf.c b/exebuf.c index 77d1fc33..1246e144 100644 --- a/exebuf.c +++ b/exebuf.c @@ -59,7 +59,9 @@ int exeBufAppend(pExeBuf self, char *line){ assert(self); status = DynStringConcat(self->bufferContent,line); - DynStringConcatChar(self->bufferContent,'\n'); + if(strrchr(line,(int)'\n') == NULL){ + DynStringConcatChar(self->bufferContent,'\n'); + } return status; } /*-----------------------------------------------------------------------*/ diff --git a/exeman.c b/exeman.c index e9e98a5b..d0969818 100644 --- a/exeman.c +++ b/exeman.c @@ -169,6 +169,9 @@ static int runBatchBuffer(pExeMan self, SConnection *pCon, pExeBuf buffer = NULL; int status; + if(!SCMatchRights(pCon,usUser)) { + return 0; + } filePath = locateBatchBuffer(self,name); if(filePath == NULL){ snprintf(pBueffel,255,"ERROR: batch buffer %s not found in path", @@ -558,13 +561,24 @@ static int printBuffer(pExeMan self, SConnection *pCon, int argc, char *argv[]){ pDynString filePath = NULL; char pLine[512]; + pExeBuf buf; + void *pPtr = NULL; FILE *fd = NULL; if(argc < 3){ - SCWrite(pCon,"ERROR: argument required for exe print",eError); - return 0; + if(self->exeStackPtr >= 0) { + DynarGet(self->exeStack,self->exeStackPtr,&pPtr); + buf = (pExeBuf) pPtr; + if(buf != NULL){ + filePath = locateBatchBuffer(self,exeBufName(buf)); + } + } else { + SCWrite(pCon,"ERROR: no default buffer to print, argument required",eError); + return 0; + } + } else { + filePath = locateBatchBuffer(self,argv[2]); } - filePath = locateBatchBuffer(self,argv[2]); if(filePath == NULL){ snprintf(pLine,255,"ERROR: batch buffer %s not found in path", argv[2]); @@ -610,7 +624,7 @@ static int enqueueBuffer(pExeMan self, SConnection *pCon, buf = exeBufCreate("enqueue"); if(buf == NULL){ SCWrite(pCon,"ERROR: out of memory",eError); - return NULL; + return 0; } status = exeBufLoad(buf,GetCharArray(filePath)); DeleteDynString(filePath); @@ -727,9 +741,6 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, return status; }else if(strcmp(argv[1],"info") == 0){ status = infoHandler(self,pCon,argc,argv); - if(status){ - SCSendOK(pCon); - } return status; }else if(strcmp(argv[1],"print") == 0){ status = printBuffer(self,pCon,argc,argv); @@ -755,7 +766,11 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, } return status; } else { - return runBatchBuffer(self,pCon,pSics,pBufferName); + status = runBatchBuffer(self,pCon,pSics,pBufferName); + if(self->exeStackPtr < 0){ + SCWrite(pCon,"EXE TERMINATED",eWarning); + } + return status; } } else { SCWrite(pCon,"ERROR: need argument to manage batch buffers",eError); diff --git a/fomerge.c b/fomerge.c index 2a9c1e64..8d32a8e5 100644 --- a/fomerge.c +++ b/fomerge.c @@ -488,12 +488,12 @@ static int *calculateSum(HistInt *data, int iDet, int iTime) int i, j, iIndex; int *sum = NULL; - sum = (int *)malloc(iDet*sizeof(int)); + sum = (int *)malloc(iTime*sizeof(int)); if(!sum) { return NULL; } - memset(sum,0,iDet*sizeof(int)); + memset(sum,0,iTime*sizeof(int)); for(i = 0; i < iDet; i++) { @@ -593,14 +593,14 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, /* copy sum to make compiler happy */ - lSum = (long *)malloc(iDet*sizeof(long)); + lSum = (long *)malloc(iTime*sizeof(long)); if(lSum == NULL) { - SCWrite(pCon,"ERROR: out of memory in putElastc",eError); + SCWrite(pCon,"ERROR: out of memory in putElastic",eError); free(sum); return NX_ERROR; } - for(i = 0; i < iDet; i++) + for(i = 0; i < iTime; i++) { lSum[i] = sum[i]; } diff --git a/histmem.c b/histmem.c index 8b704e1f..5f1a2362 100644 --- a/histmem.c +++ b/histmem.c @@ -542,7 +542,7 @@ strtolower(name); return StringDictGet(self->pOption,name, result,iLen); } -/*-----------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ int HistSetOption(pHistMem self, char *name, char *value) { int status; @@ -555,6 +555,7 @@ { return StringDictAddPair(self->pOption,name, value); } + return 1; } /*-----------------------------------------------------------------------*/ int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics) @@ -1055,6 +1056,8 @@ static int checkHMEnd(pHistMem self, char *text){ SCWrite(pCon,pBueffel,eError); return 0; } + SCSendOK(pCon); + return 1; } else if(strcmp(argv[1],"preset") == 0) /* preset */ { diff --git a/histsim.c b/histsim.c index c1b0703a..20952150 100644 --- a/histsim.c +++ b/histsim.c @@ -49,9 +49,9 @@ #include "HistDriv.i" #include "histsim.h" -/* #define TESTVAL 128 +/* define TESTVAL to set the simulated histogram to a fixed value for testing @@ -175,7 +175,7 @@ #ifdef TESTVAL for(ii = iStart; ii < iEnd; ii++) { - lData[ii] = TESTVAL; + lData[ii-iStart] = TESTVAL; } #else if(iSet == 1) diff --git a/hkl.c b/hkl.c index f70e5375..d86d5a74 100644 --- a/hkl.c +++ b/hkl.c @@ -1205,8 +1205,20 @@ ente: return 1; } -/*--------------------------------------------------------------------------*/ - +/*---------------------------------------------------------------------------*/ + int GetHKLFromAngles(pHKL self, SConnection *pCon, float fHKL[3]) + { + int status; + float fAng[4]; + + status = GetCurrentPosition(self,pCon,fAng); + if(status == 1) + { + angle2HKL(self,fAng[0], fAng[1], fAng[2], fAng[3],fHKL); + return 1; + } + return 0; + } /*--------------------------------------------------------------------------*/ static int GetCommandData(int argc, char *argv[], float fHKL[3], float *fPsi, int *iHamil, SConnection *pCon) diff --git a/hkl.h b/hkl.h index 4de19957..867f68ea 100644 --- a/hkl.h +++ b/hkl.h @@ -34,6 +34,7 @@ int GetLambda(pHKL self, float *fVal); int GetCurrentHKL(pHKL self, float fVal[3]); int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]); + int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]); int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil, float fSet[4],SConnection *pCon); diff --git a/hkl.i b/hkl.i index c1a716e8..14cbaed0 100644 --- a/hkl.i +++ b/hkl.i @@ -25,6 +25,8 @@ pSelVar pMono; long lID; float scanTolerance; + float targetHKL[3]; + int targetDirty; } HKL; diff --git a/hkl.tex b/hkl.tex index 62d1b0ad..8eb331f4 100644 --- a/hkl.tex +++ b/hkl.tex @@ -8,6 +8,9 @@ provided by Jean Allibon, ILL with the MAD four circle diffractometer control program in ANSI-C. For theory, see the contribution by W.C. Hamilton in the International Tables for Crystallography, 1974 edition. +There is a sister object to HKL which uses HKL to implement virtual motors for +H, K, and L. See below for the description + The object uses the following object data structure: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap1} @@ -33,6 +36,8 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ pSelVar pMono;@\\ \mbox{}\verb@ long lID;@\\ \mbox{}\verb@ float scanTolerance;@\\ +\mbox{}\verb@ float targetHKL[3];@\\ +\mbox{}\verb@ int targetDirty;@\\ \mbox{}\verb@ } HKL;@\\ \mbox{}\verb@@$\diamond$ \end{list} @@ -64,7 +69,10 @@ checking. This is detector tilt. \item[pMono] The selector variable doing the wavelength. \item[scanTolerance] The hkl module refuses to position a reflection if it is -to close to omega limits for scanning. This is the tolerance to use. +to close to omega limits for scanning. This is the tolerance to use. +\item[targetHKL] The target HKL values to support the H, K, L virtual motors +\item[targetDirty] A flag which is set when the virtual motors have to recalculate the + settings and to drive. \end{description} The wavelength is a bit tricky. As it would be to time consuming to read two @@ -102,6 +110,7 @@ $\langle$hklint {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int GetLambda(pHKL self, float *fVal);@\\ \mbox{}\verb@ int GetCurrentHKL(pHKL self, float fVal[3]);@\\ \mbox{}\verb@ int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);@\\ +\mbox{}\verb@ int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]); @\\ \mbox{}\verb@@\\ \mbox{}\verb@ int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,@\\ \mbox{}\verb@ float fSet[4],SConnection *pCon);@\\ @@ -166,6 +175,7 @@ pointer to the connection object doing the command for error messages and everything. The error returns are the same as with CalculateSettings well. With the addition of HKJMOTFAIL, which means that a motor failed to drive properly. +\item[GetHKLFromAngles] calculates the current HKL from Angles. \item[DriveSettings] drives to the the settings given in fSet. \item[HKLAction] is the interpreter wrapper function for the HKL object. \end{description} @@ -220,3 +230,79 @@ drive properly. \vspace{-2ex} \end{minipage}\\[4ex] \end{flushleft} +\subsubsection{The Crystallographic Virtual Motor Object} +This module implements virtual motors H, K and L on top of the HKL object. It was choosen to implement this +in a separate module because the hkl module is already big and complex enough. The problem is how to +keep track of the necessary settings for HKL because the motors are interrelated. This is solved in the +following scheme: +\begin{itemize} +\item Starting any of the motors H, K or L results in new values to be set in the HKL internal data + structure and a dirty flag to be set. +\item On a call to the drivable interfaces status function the dirty flag is checked and, if + appropriate, the motor positions are recalculated and the motors started. +\item H, K and L values are recalculated from motors on each read. +\end{itemize} +For each virtual motor an internal data structure is required: +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap5} +$\langle$hklmotdat {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct __HKLMOT {@\\ +\mbox{}\verb@ pObjectDescriptor pDes;@\\ +\mbox{}\verb@ pHKL pHkl;@\\ +\mbox{}\verb@ pIDrivable pDriv;@\\ +\mbox{}\verb@ int index;@\\ +\mbox{}\verb@ }HKLMot, *pHKLMot;@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The fields are:\begin{description} +\item[pDes] The required object descriptor. +\item[pHkl] The HKL object to use for calculations. +\item[pDriv] The drivable interface. +\item[index] The index of the motors target in the targetHKL array in the HKL structure. +\end{description} +The target HKL and the dirty flag is in the main HKL data structure. + +There is no external interface to this, all the functionality is hidden in the drivable interface +functions. The interpreter interface is minimal: only a value request is supported. There is + however a factory function in order to install the HKL motors into the interpreter. + +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap6} +\verb@"hklmot.h"@ {\footnotesize ? }$\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@/*------------------------------------------------------------------------------------------------------@\\ +\mbox{}\verb@ Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.@\\ +\mbox{}\verb@ Requires a HKL object for calculations.@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ copyright: see file COPYRIGHT@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ Mark Koennecke, February 2005@\\ +\mbox{}\verb@--------------------------------------------------------------------------------------------------------*/@\\ +\mbox{}\verb@#ifndef SICSHKLMOT@\\ +\mbox{}\verb@#define SICSHKLMOT@\\ +\mbox{}\verb@/*====================== data structure ==============================================================*/@\\ +\mbox{}\verb@@$\langle$hklmotdat {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@/*======================= interpreter interface ======================================================*/@\\ +\mbox{}\verb@int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);@\\ +\mbox{}\verb@int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@#endif@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-2ex} +\end{minipage}\\[4ex] +\end{flushleft} diff --git a/hkl.w b/hkl.w index bd5888ff..31d8f583 100644 --- a/hkl.w +++ b/hkl.w @@ -8,6 +8,9 @@ provided by Jean Allibon, ILL with the MAD four circle diffractometer control program in ANSI-C. For theory, see the contribution by W.C. Hamilton in the International Tables for Crystallography, 1974 edition. +There is a sister object to HKL which uses HKL to implement virtual motors for +H, K, and L. See below for the description + The object uses the following object data structure: @d hkldat @{ typedef struct __HKL { @@ -28,6 +31,8 @@ The object uses the following object data structure: pSelVar pMono; long lID; float scanTolerance; + float targetHKL[3]; + int targetDirty; } HKL; @} @@ -52,7 +57,10 @@ checking. This is detector tilt. \item[pMono] The selector variable doing the wavelength. \item[scanTolerance] The hkl module refuses to position a reflection if it is -to close to omega limits for scanning. This is the tolerance to use. +to close to omega limits for scanning. This is the tolerance to use. +\item[targetHKL] The target HKL values to support the H, K, L virtual motors +\item[targetDirty] A flag which is set when the virtual motors have to recalculate the + settings and to drive. \end{description} The wavelength is a bit tricky. As it would be to time consuming to read two @@ -85,6 +93,7 @@ module: int GetLambda(pHKL self, float *fVal); int GetCurrentHKL(pHKL self, float fVal[3]); int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]); + int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]); int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil, float fSet[4],SConnection *pCon); @@ -141,6 +150,7 @@ pointer to the connection object doing the command for error messages and everything. The error returns are the same as with CalculateSettings well. With the addition of HKJMOTFAIL, which means that a motor failed to drive properly. +\item[GetHKLFromAngles] calculates the current HKL from Angles. \item[DriveSettings] drives to the the settings given in fSet. \item[HKLAction] is the interpreter wrapper function for the HKL object. \end{description} @@ -178,3 +188,58 @@ drive properly. @ #endif @} + +\subsubsection{The Crystallographic Virtual Motor Object} +This module implements virtual motors H, K and L on top of the HKL object. It was choosen to implement this +in a separate module because the hkl module is already big and complex enough. The problem is how to +keep track of the necessary settings for HKL because the motors are interrelated. This is solved in the +following scheme: +\begin{itemize} +\item Starting any of the motors H, K or L results in new values to be set in the HKL internal data + structure and a dirty flag to be set. +\item On a call to the drivable interfaces status function the dirty flag is checked and, if + appropriate, the motor positions are recalculated and the motors started. +\item H, K and L values are recalculated from motors on each read. +\end{itemize} +For each virtual motor an internal data structure is required: +@d hklmotdat @{ +typedef struct __HKLMOT { + pObjectDescriptor pDes; + pHKL pHkl; + pIDrivable pDriv; + int index; + }HKLMot, *pHKLMot; +@} +The fields are:\begin{description} +\item[pDes] The required object descriptor. +\item[pHkl] The HKL object to use for calculations. +\item[pDriv] The drivable interface. +\item[index] The index of the motors target in the targetHKL array in the HKL structure. +\end{description} +The target HKL and the dirty flag is in the main HKL data structure. + +There is no external interface to this, all the functionality is hidden in the drivable interface +functions. The interpreter interface is minimal: only a value request is supported. There is + however a factory function in order to install the HKL motors into the interpreter. + +@o hklmot.h @{ +/*------------------------------------------------------------------------------------------------------ + Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer. + Requires a HKL object for calculations. + + copyright: see file COPYRIGHT + + Mark Koennecke, February 2005 +--------------------------------------------------------------------------------------------------------*/ +#ifndef SICSHKLMOT +#define SICSHKLMOT +/*====================== data structure ==============================================================*/ +@ +/*======================= interpreter interface ======================================================*/ +int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); +int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); + +#endif + + +@} diff --git a/hklmot.c b/hklmot.c new file mode 100644 index 00000000..85be94c1 --- /dev/null +++ b/hklmot.c @@ -0,0 +1,247 @@ +/*------------------------------------------------------------------------------------------------------ + Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer. + Requires a HKL object for calculations. + + copyright: see file COPYRIGHT + + Mark Koennecke, February 2005 +--------------------------------------------------------------------------------------------------------*/ +#include +#include +#include "sics.h" +#include "fortify.h" +#include "motor.h" +#include "matrix/matrix.h" +#include "hkl.h" +#include "hkl.i" +#include "hklmot.h" +/*=================== Object Descriptor Interface ===================================================*/ +static void *HKLGetInterface(void *pData, int iID){ + pHKLMot self = NULL; + + self = (pHKLMot)pData; + if(self == NULL){ + return NULL; + } + if(iID == DRIVEID){ + return self->pDriv; + } + return NULL; +} +/*=================== Drivable Interface ============================================================*/ +static int HKLHalt(void *pData){ + pHKLMot self = NULL; + + self = (pHKLMot)pData; + assert(self != NULL); + + self->pHkl->pTheta->pDrivInt->Halt(self->pHkl->pTheta); + self->pHkl->pOmega->pDrivInt->Halt(self->pHkl->pOmega); + if(self->pHkl->iNOR == 1){ + self->pHkl->pNu->pDrivInt->Halt(self->pHkl->pNu); + } else { + self->pHkl->pChi->pDrivInt->Halt(self->pHkl->pChi); + self->pHkl->pPhi->pDrivInt->Halt(self->pHkl->pPhi); + } + return 1; +} +/*-----------------------------------------------------------------------------------------------------*/ +static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){ + /* + There is no meaningful implementation here. This gets called when starting the motor. + At that stage not all other values may be known. If the calculation failes, this will die + at status check time. + */ + return 1; +} +/*----------------------------------------------------------------------------------------------------*/ +static long HKLSetValue(void *pData, SConnection *pCon, float fVal){ + pHKLMot self = NULL; + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + self = (pHKLMot)pData; + assert(self != NULL); + + self->pHkl->targetHKL[self->index] = fVal; + self->pHkl->targetDirty = 1; + return OKOK; +} +/*---------------------------------------------------------------------------------------------------*/ +static int checkMotors(pHKLMot self, SConnection *pCon){ + int status; + + status = self->pHkl->pTheta->pDrivInt->CheckStatus(self->pHkl->pTheta, pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + status = self->pHkl->pOmega->pDrivInt->CheckStatus(self->pHkl->pOmega, pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + if(self->pHkl->iNOR == 1){ + status = self->pHkl->pNu->pDrivInt->CheckStatus(self->pHkl->pNu, pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + } else { + status = self->pHkl->pChi->pDrivInt->CheckStatus(self->pHkl->pChi, pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + status = self->pHkl->pPhi->pDrivInt->CheckStatus(self->pHkl->pPhi, pCon); + if(status != HWIdle && status != OKOK){ + return status; + } + } + return HWIdle; +} +/*-----------------------------------------------------------------------------------------------------*/ +static int HKLCheckStatus(void *pData, SConnection *pCon){ + pHKLMot self = NULL; + int status; + + self = (pHKLMot)pData; + assert(self != NULL); + if(self->pHkl->targetDirty == 1){ + status = RunHKL(self->pHkl,self->pHkl->targetHKL,.0,0,pCon); + if(status != 1){ + return HWFault; + } + self->pHkl->targetDirty = 0; + return HWBusy; + } else { + return checkMotors(self,pCon); + } +} +/*-----------------------------------------------------------------------------------------------------*/ +static float HKLGetValue(void *pData, SConnection *pCon){ + pHKLMot self = NULL; + float fVal[3]; + int status; + + self = (pHKLMot)pData; + assert(self != NULL); + + + status = GetHKLFromAngles(self->pHkl,pCon,fVal); + if(status != 1){ + SCWrite(pCon,"ERROR: failed to read positions or convert to HKL",eError); + return -9999.99; + } + return fVal[self->index]; +} +/*=============================== Live and Death ====================================*/ +static pHKLMot MakeHKLMot(pHKL pHkl, int index){ + pHKLMot self = NULL; + + assert(pHkl != NULL); + assert(index >= 0 && index < 3); + + self = (pHKLMot)malloc(sizeof(HKLMot)); + if(self == NULL){ + return NULL; + } + memset(self,0,sizeof(HKLMot)); + self->pDes = CreateDescriptor("HKLMot"); + self->pDriv = CreateDrivableInterface(); + if(self->pDes == NULL || self->pDriv == NULL){ + free(self); + return NULL; + } + self->pDes->GetInterface = HKLGetInterface; + self->pDriv->Halt = HKLHalt; + self->pDriv->CheckLimits = HKLCheckLimits; + self->pDriv->SetValue = HKLSetValue; + self->pDriv->CheckStatus = HKLCheckStatus; + self->pDriv->GetValue = HKLGetValue; + self->pHkl = pHkl; + self->index = index; + return self; +} +/*----------------------------------------------------------------------------------*/ +static void KillHklMot(void *pData){ + pHKLMot self = NULL; + + self = (pHKLMot)pData; + if(self == NULL){ + return; + } + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + if(self->pDriv){ + free(self->pDriv); + } + free(self); +} +/*=============================== Interpreter Interface ============================*/ +int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ + pHKLMot self = NULL; + float value; + char pBuffer[132]; + + self = (pHKLMot)pData; + assert(self != NULL); + + value = self->pDriv->GetValue(self,pCon); + if(value < -9000.){ + snprintf(pBuffer,131,"ERROR: failed to read %s",argv[0]); + SCWrite(pCon,pBuffer,eError); + return 0; + } + snprintf(pBuffer,131,"%s = %f", argv[0], value); + SCWrite(pCon,pBuffer,eValue); + return 1; +} +/*------------------------------------------------------------------------------------------*/ +int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ + pHKL pHkl; + pHKLMot pMot = NULL; + char pBuffer[131]; + + if(argc < 2){ + SCWrite(pCon,"ERROR: Insifficient number of arguments to HKLMotInstall",eError); + return 0; + } + strtolower(argv[1]); + pHkl = (pHKL)FindCommandData(pSics,argv[1],"4-Circle-Calculus"); + if(pHkl == NULL){ + snprintf(pBuffer,131,"ERROR: %s is not present or no HKL object",argv[1]); + SCWrite(pCon,pBuffer,eError); + return 0; + } + + pMot = MakeHKLMot(pHkl, 0); + if(pMot == NULL){ + SCWrite(pCon,"ERROR: out of memory creating H Motor",eError); + return 0; + } + if(!AddCommand(pSics,"H",HKLMotAction,KillHklMot,pMot)){ + SCWrite(pCon,"ERROR: duplicate command H not created",eError); + return 0; + } + + pMot = MakeHKLMot(pHkl, 1); + if(pMot == NULL){ + SCWrite(pCon,"ERROR: out of memory creating K Motor",eError); + return 0; + } + if(!AddCommand(pSics,"K",HKLMotAction,KillHklMot,pMot)){ + SCWrite(pCon,"ERROR: duplicate command K not created",eError); + return 0; + } + + pMot = MakeHKLMot(pHkl, 2); + if(pMot == NULL){ + SCWrite(pCon,"ERROR: out of memory creating L Motor",eError); + return 0; + } + if(!AddCommand(pSics,"L",HKLMotAction,KillHklMot,pMot)){ + SCWrite(pCon,"ERROR: duplicate command L not created",eError); + return 0; + } + return 1; +} diff --git a/hklmot.h b/hklmot.h new file mode 100644 index 00000000..d3aae155 --- /dev/null +++ b/hklmot.h @@ -0,0 +1,27 @@ + +/*------------------------------------------------------------------------------------------------------ + Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer. + Requires a HKL object for calculations. + + copyright: see file COPYRIGHT + + Mark Koennecke, February 2005 +--------------------------------------------------------------------------------------------------------*/ +#ifndef SICSHKLMOT +#define SICSHKLMOT +/*====================== data structure ==============================================================*/ + +typedef struct __HKLMOT { + pObjectDescriptor pDes; + pHKL pHkl; + pIDrivable pDriv; + int index; + }HKLMot, *pHKLMot; + +/*======================= interpreter interface ======================================================*/ +int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); +int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); + +#endif + + diff --git a/macro.c b/macro.c index a9200b4e..258e8bb6 100644 --- a/macro.c +++ b/macro.c @@ -129,7 +129,7 @@ SConnection *pCon = NULL; CommandList *pCommand = NULL; char *lastCommand = NULL, comBuffer[132]; - int iRet,i; + int iRet = 0,i; int iMacro; /* get the datastructures */ @@ -194,7 +194,7 @@ } /* finish */ - if(iRet) + if(iRet == 1) { return TCL_OK; } @@ -322,12 +322,16 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, pUnbekannt = pUnknown; Tcl_CreateCommand(pInter,"unknown",SicsUnknownProc, pUnknown, UnknownKill); - + /* delete dangers */ Tcl_DeleteCommand(pInter,"exit"); Tcl_DeleteCommand(pInter,"socket"); Tcl_DeleteCommand(pInter,"vwait"); Tcl_DeleteCommand(pInter,"exec"); + + /* + install protected exec command + */ Tcl_CreateObjCommand(pInter,"exec",ProtectedExec,NULL,KillExec); return pInter; @@ -847,8 +851,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, iRet = Tcl_Eval(pTcl,pBueffel); if(iRet == TCL_OK) - { /* possibly a bug here */ - SCWrite(pCon,pTcl->result,eStatus); + { + strncpy(pBueffel,pTcl->result,1023); + SCWrite(pCon,pBueffel,eStatus); return 1; } else @@ -862,7 +867,8 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, else { Tcl_UnsetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY); - SCWrite(pCon,pTcl->result,eError); + strncpy(pBueffel,pTcl->result,1023); + SCWrite(pCon,pBueffel,eError); } return 0; } diff --git a/make_gen b/make_gen index 66852b76..7ee43f56 100644 --- a/make_gen +++ b/make_gen @@ -19,7 +19,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ histmem.o histdriv.o histsim.o interface.o callback.o \ event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \ danu.o nxdict.o varlog.o stptok.o nread.o \ - scan.o fitcenter.o telnet.o token.o wwildcard.o\ + scan.o fitcenter.o telnet.o token.o wwildcard.o hklmot.o\ tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \ mesure.o uubuffer.o commandlog.o udpquieck.o \ rmtrail.o help.o nxupdate.o confvirtualmot.o \ diff --git a/network.c b/network.c index 140d39e1..b49c29c8 100644 --- a/network.c +++ b/network.c @@ -169,7 +169,7 @@ CreateSocketAdress( assert(self != NULL); - if(timeout > 0) + if(timeout >= 0) { /* select first */ tmo.tv_usec = (timeout % 1000) * 1000; @@ -256,13 +256,15 @@ CreateSocketAdress( free(pRes); return NULL; } + /* i = sizeof(struct linger); lili.l_onoff = 1; lili.l_linger = 1; -/* setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i); + setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i); i = 1; setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int)); -*/ pRes->iType = SOCKET; + */ + pRes->iType = SOCKET; pRes->lMagic = NETMAGIC; return pRes; } @@ -386,7 +388,7 @@ CreateSocketAdress( return 0; } - if(timeout > 0) + if(timeout >= 0) { /* setup for select first */ tmo.tv_usec = (timeout % 1000) *1000; @@ -739,7 +741,7 @@ This old version may be removed in some stage. It has two problems: } assert(self->iType == UDP); - if(timeout > 0) + if(timeout >= 0) { /* setup for select first */ tmo.tv_usec = (timeout % 1000) *1000; diff --git a/nread.c b/nread.c index eb9963e5..d9491924 100644 --- a/nread.c +++ b/nread.c @@ -86,7 +86,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */ assert(pTask); assert(iPasswdTimeout > 0); - assert(iReadTimeout > 0); + assert(iReadTimeout >= 0); pNew = (pNetRead)malloc(sizeof(NetReader)); if(!pNew) diff --git a/nserver.c b/nserver.c index 9cff04fd..48021717 100644 --- a/nserver.c +++ b/nserver.c @@ -349,7 +349,7 @@ IFDeleteOptions(pSICSOptions); if(self->pSics) { - DeleteInterp(self->pSics); + DeleteInterp(self->pSics); self->pSics = NULL; } diff --git a/nxscript.c b/nxscript.c index 3e5b26c6..4b104a11 100644 --- a/nxscript.c +++ b/nxscript.c @@ -160,7 +160,7 @@ static int handleFileOperations(SConnection *pCon, pNXScript self, if(argc < 4){ SCWrite(pCon,"ERROR: insufficient number of arguments for file operation", eError); - return 1; + return -1; } /* be considerate: close files left open @@ -180,11 +180,13 @@ static int handleFileOperations(SConnection *pCon, pNXScript self, if(status != NX_OK){ sprintf(buffer,"ERROR: failed to open %s",argv[2]); SCWrite(pCon,buffer,eError); + return -1; } status = NXDinitfromfile(argv[3],&self->dictHandle); if(status != NX_OK){ sprintf(buffer,"ERROR: failed to open dictionary %s",argv[3]); SCWrite(pCon,buffer,eError); + return -1; } SCSendOK(pCon); return 1; @@ -261,6 +263,7 @@ static void putCounter(SConnection *pCon, SicsInterp *pSics, pNXScript self, eError); return; } + memset(dummy,0,80*sizeof(char)); /* find counter @@ -897,6 +900,8 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pNXScript self = (pNXScript)pData; char *pFile = NULL; + int status; + /* preliminary checks */ @@ -934,7 +939,10 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData, - if(handleFileOperations(pCon,self,argc,argv)){ + status = handleFileOperations(pCon,self,argc,argv); + if(status < 0){ + return 0; + } else if(status == 1){ return 1; } diff --git a/ofac.c b/ofac.c index c5070f4a..9375868f 100644 --- a/ofac.c +++ b/ofac.c @@ -108,6 +108,7 @@ #include "exeman.h" #include "oscillate.h" #include "diffscan.h" +#include "hklmot.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -291,6 +292,8 @@ MakeOscillator,NULL,NULL); AddCommand(pInter,"MakeDiffScan", MakeDiffScan,NULL,NULL); + AddCommand(pInter,"MakeHKLMot", + HKLMotInstall,NULL,NULL); /* @@ -352,6 +355,7 @@ RemoveCommand(pSics,"MakeBatchManager"); RemoveCommand(pSics,"MakeOscillator"); RemoveCommand(pSics,"MakeDiffScan"); + RemoveCommand(pSics,"MakeHKLMot"); /* remove site specific installation commands diff --git a/rs232controller.c b/rs232controller.c index bfc80d4f..c472c809 100644 --- a/rs232controller.c +++ b/rs232controller.c @@ -134,6 +134,10 @@ int writeRS232(prs232 self, void *data, int dataLen) if(pPtr != NULL) free(pPtr); + if(iRet != 1){ + return BADSEND; + } + return iRet; } /*----------------------------------------------------------------------*/ @@ -213,17 +217,21 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){ replylen = *datalen; iRet = NETReadTillTermNew(self->pSock,self->timeout,self->replyTerminator, (char *)data, replylen); - if(self->debug > 0) + if(self->debug > 0 && iRet == 1) { printf("RS232 IN/TERM : %s",(char *)data); if(strchr((char *)data,'\n') == NULL) { - puts(""); + puts(""); } fflush(stdout); } if(iRet == 0) { + if(self->debug > 0) + { + printf("RS232 IN/TERM : TIMEOUT:%s\n",(char *)data); + } return TIMEOUT; } else if(iRet == -1) @@ -307,9 +315,9 @@ int transactRS232(prs232 self, void *send, int sendLen, write data */ iRet = writeRS232(self,send,sendLen); - if(iRet < 0) + if(iRet <= 0) { - return iRet; + return BADSEND; } /* @@ -320,12 +328,23 @@ int transactRS232(prs232 self, void *send, int sendLen, reply, replyLen); if(self->debug > 0) { - printf("RS232 IN/TRANS: %s",(char *)reply); - if(strchr((char *)reply,'\n') == NULL) + if(iRet == 1) { - puts(""); + printf("RS232 IN/TRANS: %s",(char *)reply); + if(strchr((char *)reply,'\n') == NULL) + { + puts(""); + } + fflush(stdout); + } + else if(iRet == 0) + { + printf("RS232 IN/TRANS: TIMEOUT\n"); + } + else + { + printf("RS232 IN/TRANS/INCOMPLETE: %s",(char *)reply); } - fflush(stdout); } if(iRet == 0) { @@ -362,7 +381,7 @@ void getRS232Error(int iCode, char *errorBuffer, break; case TIMEOUT: strncpy(errorBuffer, - "Timeout reading data", + "Timeout or network error when reading data", errorBufferLen); break; case FAILEDCONNECT: @@ -374,6 +393,9 @@ void getRS232Error(int iCode, char *errorBuffer, strncpy(errorBuffer,"Did not find terminator in read buffer", errorBufferLen); break; + case BADSEND: + strncpy(errorBuffer,"Network problem: failed to send",errorBufferLen); + break; default: strncpy(errorBuffer,strerror(errno), errorBufferLen); @@ -407,6 +429,21 @@ int initRS232(prs232 self) return 1; } } +/*--------------------------------------------------------------------*/ +void closeRS232(prs232 self) +{ + assert(self); + + if(self->pSock != NULL) + { + if(pServ->pReader != NULL){ + NetReadRemoveUserSocket(pServ->pReader,self->pSock->sockid); + } + NETClosePort(self->pSock); + free(self->pSock); + self->pSock = NULL; + } +} /*------------------------------------------------------------------*/ prs232 createRS232(char *host, int iPort) { diff --git a/rs232controller.h b/rs232controller.h index f6f466ff..130babc0 100644 --- a/rs232controller.h +++ b/rs232controller.h @@ -22,6 +22,8 @@ #define TIMEOUT -2702 #define FAILEDCONNECT -2703 #define INCOMPLETE -2704 +#define BADREAD -2705 +#define BADSEND -2706 /*----------------------- a data structure ----------------------------*/ @@ -63,6 +65,7 @@ int errorBufferLen); int initRS232(prs232 self); + void closeRS232(prs232 self); prs232 createRS232(char *host, int iPort); void KillRS232(void *pData); diff --git a/rs232controller.w b/rs232controller.w index 71554276..420560c0 100644 --- a/rs232controller.w +++ b/rs232controller.w @@ -69,6 +69,7 @@ The following interface functions are provided: int errorBufferLen); int initRS232(prs232 self); + void closeRS232(prs232 self); prs232 createRS232(char *host, int iPort); void KillRS232(void *pData); @} @@ -102,6 +103,7 @@ directly followed by a read. iCode. \item[initRS232] tries to close and reopen the RS232 connection. This is useful for the automatic fixing of communication problems encountered. +\item[closeRS232] closes a network connection but does not delete the datastructure. \item[createRS232] creates a new rs232 data structure with all parameters at default values. The connection is NOT opened. \end{description} @@ -130,6 +132,8 @@ parameters at default values. The connection is NOT opened. #define TIMEOUT -2702 #define FAILEDCONNECT -2703 #define INCOMPLETE -2704 +#define BADREAD -2705 +#define BADSEND -2706 /*----------------------- a data structure ----------------------------*/ @ diff --git a/sans2.tcl b/sans2.tcl index 38a11ab5..1b12b091 100644 --- a/sans2.tcl +++ b/sans2.tcl @@ -1,33 +1,48 @@ # -------------------------------------------------------------------------- # Initialization script for the instrument SANSII at SINQ # -# Dr. Mark Koennecke, January - ???? 2003 +# Dr. Mark Koennecke, January - March 2003 +# +# Changes: +# Pavel Strunz, 15.04.2003: - changed backlash dz (0.15 --> 0.005) +# Pavel Strunz, 16.04.2003: - changed NVS forbiden gaps according to the actual NVS037 +# Pavel Strunz, 23.04.2003: - changed backlash for all ecb motors +# Pavel Strunz, 29.04.2003: - hakle.tcl sourced +# Pavel Strunz, 20.11.2003: - source sans2geometry, sans2measurement +# Pavel Strunz, 03.12.2003: - source scan_a, sans2wavelength, nvs interrupt changed from 3 to 0 #--------------------------------------------------------------------------- # O P T I O N S -set root "/afs/psi.ch/user/k/koennecke/src/sics" +set root "/home/SANS2" + +set scriptroot $root/sans2_sics + + # first all the server options are set -ServerOption SaveFile $root/tmp/sans2stat.tcl +ServerOption statusfile $root/data/2003/sans2stat.tcl # File to save the status of the instrument too -ServerOption ReadTimeOut 10 +ServerOption ReadTimeOut 5 # timeout when checking for commands. In the main loop SICS checks for -# pending commands on each connection with the above timeout, has +# pending commands on each connection with the above timeout, has # PERFORMANCE impact! -ServerOption AcceptTimeOut 10 +ServerOption AcceptTimeOut 5 # timeout when checking for connection req. # Similar to above, but for connections -ServerOption ReadUserPasswdTimeout 500000 -# time to wiat for a user/passwd to be sent from a client. Increase this +ServerOption ReadUserPasswdTimeout 500000 +# time to wait for a user/passwd to be sent from a client. Increase this # if there is a problem connecting to a server due to network overload\ -ServerOption LogFileBaseName $root/tmp/sans2log +ServerOption LogFileBaseName $root/log/sans2log # the path and base name of the internal server logfile to which all # activity will be logged. -ServerOption ServerPort 2915 +ServerOption LogFileDir $root/log +# This is where log files from command log go + +ServerOption ServerPort 2911 # the port number the server is going to listen at. The client MUST know # this number in order to connect. It is in client.ini @@ -46,9 +61,11 @@ TokenInit connan # than the SICS users are specified # Syntax: SicsUser name password userRightsCode -SicsUser Manager Joachim 1 -SicsUser User Kohl 2 -SicsUser Spy 007 1 +SicsUser Manager Manager 1 +SicsUser lnsmanager lnsSICSlns 1 +SicsUser User Looser 2 +SicsUser sans2user 04lns1 2 +SicsUser Spy 007 3 #-------------------------------------------------------------------------- # S I M P L E V A R I A B L E S @@ -58,8 +75,8 @@ SicsUser Spy 007 1 # type can be one of: Text, Int, Float #access can be one of: Internal, Mugger, user, Spy -VarMake Instrument Text Internal -Instrument "SANS-II at SINQ,PSI" +VarMake Instrument Text Internal +Instrument "SANS-II at SINQ,PSI" #initialisation Instrument lock @@ -68,7 +85,7 @@ VarMake User Text User VarMake SubTitle Text User VarMake environment Text User VarMake comment Text User -VarMake samplename Text User +#VarMake samplename Text User VarMake email Text User VarMake fax Text User VarMake phone Text User @@ -77,20 +94,21 @@ VarMake sample Text User VarMake BatchRoot Text User VarMake starttime Text User BatchRoot $root +#BatchRoot $root/command VarMake sampletable Text User #----------- Initialize data storage stuff VarMake SicsDataPath Text Mugger -SicsDataPath $root/tmp/ +SicsDataPath $root/data/2004/ SicsDataPath lock VarMake SicsDataPrefix Text Mugger -SicsDataPrefix sansII +SicsDataPrefix sans2 SicsDataPrefix lock VarMake SicsDataPostFix Text Mugger SicsDataPostFix ".hdf" SicsDataPostFix lock -MakeDataNumber SicsDataNumber $root/tmp/DataNumber +MakeDataNumber SicsDataNumber $root/data/2004/DataNumber #========================================================================= # Initialize ECB system @@ -99,8 +117,8 @@ MakeDataNumber SicsDataNumber $root/tmp/DataNumber #--------- GPIB Controller with National Instruments driver MakeGPIB gpib ni -#-------- MakeECB name gpib-controller board-number gpib-address -MakeECB ecb1 gpib 0 5 +#-------- MakeECB name gpib-controller board-number gpib-address +MakeECB ecb1 gpib 0 5 #--------- Function to switch ecb to automatic control proc ecbauto {} { @@ -113,7 +131,7 @@ ecbauto #-------------- ECB Motors # Motor name ecb ecb-controller ecb-motor-index hardlowerlimit hardupperlimit -Motor sr ecb ecb1 1 -10000. 10000. +Motor sr ecb ecb1 1 -17500. 17500. sr encoder 0 sr control 0 sr range 1 @@ -130,7 +148,7 @@ sr offset 0 sr dtolerance .01 sr step2deg 1 sr step2dig 0 -sr backlash .15 +sr backlash 500 Motor stx ecb ecb1 2 -16000. 16000. stx encoder 0 @@ -149,7 +167,7 @@ stx offset 0 stx dtolerance .01 stx step2deg 1 stx step2dig 0 -stx backlash .15 +stx backlash 500 Motor stz ecb ecb1 3 6500. 20000. stz encoder 0 @@ -168,7 +186,7 @@ stz offset 0 stz dtolerance .01 stz step2deg 1 stz step2dig 0 -stz backlash .15 +stz backlash 500 Motor sc ecb ecb1 4 -2000. 70000. sc encoder 0 @@ -187,7 +205,7 @@ sc offset 0 sc dtolerance .01 sc step2deg 1 sc step2dig 0 -sc backlash .15 +sc backlash 1000 Motor gu ecb ecb1 5 -10000. 10000. gu encoder 0 @@ -206,7 +224,7 @@ gu offset 0 gu dtolerance .02 gu step2deg 1 gu step2dig 0 -gu backlash .15 +gu backlash 100 Motor gl ecb ecb1 6 -10000. 10000. gl encoder 0 @@ -225,7 +243,7 @@ gl offset 0 gl dtolerance .02 gl step2deg 1 gl step2dig 0 -gl backlash .15 +gl backlash 100 Motor tu ecb ecb1 7 -10000. 10000. @@ -245,7 +263,7 @@ tu offset 0 tu dtolerance .01 tu step2deg 1 tu step2dig 0 -tu backlash .15 +tu backlash 100 Motor tl ecb ecb1 8 -10000. 10000. @@ -265,7 +283,7 @@ tl offset 0 tl dtolerance .01 tl step2deg 1 tl step2dig 0 -tl backlash .15 +tl backlash 100 Motor om ecb ecb1 9 -10000. 10000. om encoder 1 @@ -284,7 +302,7 @@ om offset 0 om dtolerance .01 om step2deg 1 om step2dig 10 -om backlash .15 +om backlash 100 Motor sz ecb ecb1 10 -10000. 10000. sz encoder 0 @@ -303,7 +321,7 @@ sz offset 0 sz dtolerance .001 sz step2deg 1 sz step2dig 0 -sz backlash .15 +sz backlash 100 Motor sx ecb ecb1 11 -10000. 10000. sx encoder 0 @@ -322,7 +340,7 @@ sx offset 0 sx dtolerance .01 sx step2deg 1 sx step2dig 0 -sx backlash .15 +sx backlash 100 Motor sy ecb ecb1 12 -10000. 10000. sy encoder 0 @@ -341,9 +359,9 @@ sy offset 0 sy dtolerance .001 sy step2deg 1 sy step2dig 0 -sy backlash .15 +sy backlash 100 -Motor dz ecb ecb1 13 1.05 6.0 +Motor dz ecb ecb1 13 0.905 6.015 dz encoder 0 dz control 0 dz range 1 @@ -360,9 +378,9 @@ dz offset 0 dz dtolerance .001 dz step2deg 53076 dz step2dig 0 -dz backlash .15 +dz backlash .005 -Motor dh ecb ecb1 14 -14000. 16000. +Motor dh ecb ecb1 14 -10100. 16400. dh encoder 0 dh control 0 dh range 1 @@ -379,9 +397,9 @@ dh offset 0 dh dtolerance .001 dh step2deg 1 dh step2dig 0 -dh backlash .15 +dh backlash 100 -Motor dv ecb ecb1 15 -14000. 25000. +Motor dv ecb ecb1 15 -14600. 25400. dv encoder 0 dv control 0 dv range 1 @@ -398,7 +416,7 @@ dv offset 0 dv dtolerance .001 dv step2deg 1 dv step2dig 0 -dv backlash .15 +dv backlash 100 Motor az1 ecb ecb1 16 -3900. 0. az1 encoder 0 @@ -417,7 +435,7 @@ az1 offset 0 az1 dtolerance .001 az1 step2deg 1 az1 step2dig 0 -az1 backlash .15 +az1 backlash 200 Motor atz ecb ecb1 17 -3900. 0. atz encoder 0 @@ -436,15 +454,15 @@ atz offset 0 atz dtolerance .001 atz step2deg 1 atz step2dig 0 -atz backlash .15 +atz backlash 200 #=========================================================================== # The ECB system has the drawback that only one out of 8 motors in a rack # can run at any given time. Access to such motors has to be serialized. # This is done through the anticollision system originally developed for # TRICS. This system registers requests from motors to run and then calls -# a script which serializes the running of motors. This system is used at -# SANS to deal with the rack logic. This section installs the necessary +# a script which serializes the running of motors. This system is used at +# SANS to deal with the rack logic. This section installs the necessary # scripts and configures the system. #=========================================================================== AntiCollisionInstall @@ -531,12 +549,16 @@ proc sans2rack args { } return } -Publish sans2rack User #---------for testing purposes +Publish sans2rack User anticollision script sans2rack #====================== PSI Motoren =================================== -Motor ome EL734 sans2 4000 2 1 -Motor chi EL734 sans2 4000 2 2 -Motor tilt EL734 sans2 4000 3 1 +Motor ome EL734 sans2 4000 3 1 +Motor chi EL734 sans2 4000 3 2 +Motor phi EL734 sans2 4000 3 3 +Motor tilt EL734 sans2 4000 2 1 + +SicsAlias ome traz "These motors are used to drive SANS I translation table" +SicsAlias chi trax "while ome is sample z and chi is sample x (TG070704)" #====================== Multi Motor Setup ============================== MakeMulti detector detector alias dz x @@ -565,9 +587,9 @@ gonio endconfig MakeMulti table table alias om om table alias sz z -table alias sx x +table alias sx x table alias sy y -table endconfig +table endconfig# #====================== HISTOGRAM MEMORY ================================ MakeCounter counter ecb ecb1 MakeECB tdc gpib 0 7 @@ -587,27 +609,57 @@ banana init banana exponent 6 banana CountMode timer banana preset 100 -#=========================== velocity selector ======================== -VelocitySelector nvs tilt SIM +=========================== velocity selector ======================== +set dorn(Host) psts233 +set dorn(Port) 3004 +set dorn(Channel) 4 +set dorn(Timeout) 20000 +set dorn(MinControl) 6500 +VelocitySelector nvs tilt dornier2003 dorn +#VelocitySelector nvs tilt SIM nvs add -20 28800 -nvs add 3600 4300 -nvs add 7600 9600 -nvs add 13400 13450 -nvs add 24200 24250 +nvs add 3600 4500 +nvs add 7800 10500 +nvs add 21500 23500 +nvs status +nvs interrupt 0 MakeSANSWave lambda nvs emon unregister nvswatch #===================================== auxiliary hardware ============== set distoCON [gpib attach 0 14 0 13 0 1] + +#--------- for the Hakle Feucht +MakeRS232Controller h50 psts233 3005 #===================================== data file writing ================ MakeNXScript #===================================== install commands ================== MakeDrive MakeRuenBuffer commandlog auto -#=================================== load specific command file =========== -source $root/sans2com.tcl +MakePSDFrame +SerialInit +#--------- drive command +MakeDrive +SicsAlias drive dr +#----------- for adding scripted content to the status file +MakeTclInt bckintern +#----- alias for temperature +DefineAlias tt temperature +#=================================== load specific command files =========== +source $scriptroot/sans2com.tcl +source $scriptroot/hakle.tcl +source $scriptroot/hakle50.tcl +source $scriptroot/HaakeSetup.tcl +source $scriptroot/A1931Setup.tcl +source $scriptroot/sans2geometry.tcl +source $scriptroot/sans2measurement.tcl +source $scriptroot/sans2wavelength.tcl +source $scriptroot/scan_a.tcl +# initialisation for IPS-120 superconducting magnet power supply +# this definition does not harm other devices used through the same channel +ips init localhost 4000 7 #=================================== load display definition ============= -source $root/sans2dis.tcl - - +#source $scriptroot/sans2dis.tcl +#======================================================================= +disto diff --git a/scanvar.h b/scanvar.h index 93303639..d8e59150 100644 --- a/scanvar.h +++ b/scanvar.h @@ -40,7 +40,7 @@ *name, float start, float step); /** * InitScanVar clears the list of scan points - * @param pvar The scna variable to clear + * @param pvar The scan variable to clear */ void InitScanVar(pVarEntry pVar); /** diff --git a/stringdict.c b/stringdict.c index c5d32026..10219bfe 100644 --- a/stringdict.c +++ b/stringdict.c @@ -161,6 +161,10 @@ SDE sVal; int iRet; + if(pResult != NULL) + { + pResult[0] = '\0'; + } iRet = LLDnodePtr2First(self->iList); while(iRet != 0) { diff --git a/telnet.c b/telnet.c index e426a197..2399b5f0 100644 --- a/telnet.c +++ b/telnet.c @@ -96,7 +96,7 @@ char *pPtr = NULL; char *pLogin = NULL; char *pUser = NULL, *pPasswd = NULL; - char pBuffer[512]; + char pBuffer[512], pHost[131]; int iRet; time_t shit; @@ -178,6 +178,11 @@ } else { + NETInfo(self->pCon->pSock,pHost,131); + sprintf(pBuffer,"Accepted connection on socket %d from %s", + self->pCon->pSock->sockid, pHost); + SICSLogWrite(pBuffer,eInternal); + WriteToCommandLog("SYS >", pBuffer); SendWelcome(self->pCon); SCSetRights(self->pCon,iRet); self->iLogin = 1;