diff --git a/confvirtmot.h b/confvirtmot.h new file mode 100644 index 00000000..6eb132bc --- /dev/null +++ b/confvirtmot.h @@ -0,0 +1,21 @@ + +/*----------------------------------------------------------------------- + A configurable virtual motor object. At motor start a script is called + which returns the motors and positions to drive as a comma separated + list holding entries of the form mot=value. + + COPYRIGHT: see file COPYRIGHT + + Mark Koennecke, August 2004 +-------------------------------------------------------------------------*/ +#ifndef CONFIGURABLEVIRTUALMOTOR +#define CONFIGURABLEVIRTUALMOTOR + +#include "sics.h" + +int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics, + void *data, int aargc, char *argv[]); +int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics, + void *data, int argc, char *argv[]); +#endif + diff --git a/confvirtmot.i b/confvirtmot.i new file mode 100644 index 00000000..1628cfbf --- /dev/null +++ b/confvirtmot.i @@ -0,0 +1,19 @@ + +/*----------------------------------------------------------------------- + Configurable Virtual Motor. This is an generated file describing the + internal data structure of this object. Do not edit. +-----------------------------------------------------------------------*/ + +typedef struct __CONFVIRTMOT { + pObjectDescriptor pDes; + pIDrivable pDriv; + char *scriptName; + char *readScript; + int motorList; + float targetValue; + int targetReached; + char scriptError[512]; + int parseOK; +}ConfigurableVirtualMotor, *pConfigurableVirtualMotor; + + diff --git a/confvirtualmot.c b/confvirtualmot.c new file mode 100644 index 00000000..59e1aeae --- /dev/null +++ b/confvirtualmot.c @@ -0,0 +1,467 @@ +/*----------------------------------------------------------------------- + A configurable virtual motor object. At motor start a script is called + which returns the motors and positions to drive as a comma separated + list holding entries of the form mot=value. + + This is the implementation file. + + COPYRIGHT: see file COPYRIGHT + + Mark Koennecke, August 2004 +-------------------------------------------------------------------------*/ +#include +#include +#include "fortify.h" +#include +#include "lld.h" +#include "splitter.h" +#include "confvirtmot.h" +#include "confvirtmot.i" + +extern char *stptok(char *s, char *t, int len, char *brk); + +/*--------------------------------------------------------------------------- + An internal data structure which holds information required to control + the real motors +----------------------------------------------------------------------------*/ +typedef struct { + char name[132]; + void *data; + pIDrivable pDriv; + float value; + int running; +} RealMotor, *pRealMotor; +/*---------------------------------------------------------------------*/ +static int HaltMotors(void *pData){ + pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData; + RealMotor tuktuk; + int iRet; + + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0) + { + LLDnodeDataTo(self->motorList,&tuktuk); + tuktuk.pDriv->Halt(tuktuk.data); + iRet = LLDnodePtr2Next(self->motorList); + } + return 1; +} +/*----------------------------------------------------------------------*/ +static char *invokeMotorScript(pConfigurableVirtualMotor self, + float newValue){ + char pBueffel[512]; + Tcl_Interp *pTcl; + int status; + + self->parseOK = 1; + if(self->scriptName == NULL){ + snprintf(self->scriptError,511, + "ERROR: no script configured for configurable virtual motor"); + self->parseOK = 0; + return NULL; + } + + snprintf(pBueffel,510,"%s %f",self->scriptName, newValue); + pTcl = InterpGetTcl(pServ->pSics); + + status = Tcl_Eval(pTcl, pBueffel); + if(status != TCL_OK){ + snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s", + Tcl_GetStringResult(pTcl)); + self->parseOK = 0; + return NULL; + } + return Tcl_GetStringResult(pTcl); +} + + +/*--------------------------------------------------------------------*/ +static int parseEntry(pConfigurableVirtualMotor self, + char *entry){ + RealMotor tuktuk; + char *pPtr = NULL; + char number[80], pError[256]; + CommandList *pCom = NULL; + int status; + + pPtr = entry; + pPtr = stptok(pPtr,tuktuk.name,131,"="); + if(pPtr == NULL){ + snprintf(self->scriptError,510,"ERROR: cannot interpret %s, %s", entry, + "require format: motor=value"); + self->parseOK = 0; + return 0; + } + tuktuk.pDriv = (pIDrivable)FindDrivable(pServ->pSics,tuktuk.name); + pCom = FindCommand(pServ->pSics,tuktuk.name); + if(!pCom){ + snprintf(self->scriptError,510,"ERROR: %s not found",tuktuk.name); + self->parseOK = 0; + return 0; + } + tuktuk.data = pCom->pData; + + if(tuktuk.pDriv == NULL){ + snprintf(self->scriptError,510,"ERROR: %s is not drivable",tuktuk.name); + self->parseOK = 0; + return 0; + } + + pPtr = stptok(pPtr,number,79,"="); + tuktuk.value = atof(number); + + LLDnodeAppendFrom(self->motorList,&tuktuk); + + return 1; +} +/*----------------------------------------------------------------------*/ +static int parseCommandList(pConfigurableVirtualMotor self, + char *commandList){ + char pEntry[256], *pPtr; + int status; + + LLDdelete(self->motorList); + self->motorList = LLDcreate(sizeof(RealMotor)); + + pPtr = commandList; + while((pPtr = stptok(pPtr,pEntry,255,",")) != NULL){ + status = parseEntry(self,pEntry); + if(status != 1){ + return 0; + } + } + return 1; +} +/*-----------------------------------------------------------------------*/ +static int startMotorList(pConfigurableVirtualMotor self, SConnection *pCon){ + RealMotor tuktuk; + int status, iRet; + + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0) + { + LLDnodeDataTo(self->motorList,&tuktuk); + status = tuktuk.pDriv->SetValue(tuktuk.data,pCon,tuktuk.value); + if(status != 1){ + return status; + } + tuktuk.running = 1; + LLDnodeDataFrom(self->motorList,&tuktuk); + iRet = LLDnodePtr2Next(self->motorList); + } + return OKOK; +} +/*------------------------------------------------------------------------*/ +static long ConfSetValue(void *pData, SConnection *pCon, float newValue){ + pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData; + char *commandList = NULL; + int status; + + assert(self != NULL); + + commandList = invokeMotorScript(self,newValue); + if(commandList == NULL){ + SCWrite(pCon,self->scriptError,eError); + return 0; + } + + status = parseCommandList(self,commandList); + if(status != 1){ + SCWrite(pCon,self->scriptError,eError); + return 0; + } + self->targetValue = newValue; + self->targetReached = 0; + + status = startMotorList(self,pCon); + if(status != OKOK){ + HaltMotors(self); + } + return OKOK; +} +/*-----------------------------------------------------------------------*/ +static int ConfCheckLimits(void *pData, float fVal, char *error, int errLen){ + pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData; + char *commandList = NULL; + int status, iRet; + RealMotor tuktuk; + + assert(self != NULL); + + if(self->targetValue != fVal){ + commandList = invokeMotorScript(self,fVal); + if(commandList == NULL){ + strncpy(error,self->scriptError,errLen); + return 0; + } + + status = parseCommandList(self,commandList); + if(status != 1){ + strncpy(error,self->scriptError,errLen); + return 0; + } + } + + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0) + { + LLDnodeDataTo(self->motorList,&tuktuk); + status = tuktuk.pDriv->CheckLimits(tuktuk.data,fVal,error,errLen); + if(status != 1){ + return status; + } + iRet = LLDnodePtr2Next(self->motorList); + } + return 1; +} +/*------------------------------------------------------------------------*/ +static int ConfCheckStatus(void *pData, SConnection *pCon){ + pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData; + RealMotor tuktuk; + int iRet, status, result; + + result = HWIdle; + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0) + { + LLDnodeDataTo(self->motorList,&tuktuk); + if(tuktuk.running == 1){ + status = tuktuk.pDriv->CheckStatus(tuktuk.data, pCon); + switch(status){ + case HWIdle: + tuktuk.running = 0; + LLDnodeDataFrom(self->motorList,&tuktuk); + break; + case HWBusy: + result = HWBusy; + break; + case HWFault: + case HWPosFault: + return status; + break; + default: + /* + this is a programming error and has to be fixed + */ + assert(0); + } + } + iRet = LLDnodePtr2Next(self->motorList); + } + return result; +} +/*---------------------------------------------------------------------*/ +static float invokeReadScript(pConfigurableVirtualMotor self, + SConnection *pCon){ + Tcl_Interp *pTcl; + int status; + + pTcl = InterpGetTcl(pServ->pSics); + + status = Tcl_Eval(pTcl, self->readScript); + if(status != TCL_OK){ + snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s", + Tcl_GetStringResult(pTcl)); + } + return atof(Tcl_GetStringResult(pTcl)); +} +/*---------------------------------------------------------------------*/ +static void checkMotorValues(pConfigurableVirtualMotor self, + SConnection *pCon){ + int iRet; + float value; + RealMotor tuktuk; + char pBueffel[512]; + + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0) + { + LLDnodeDataTo(self->motorList,&tuktuk); + value = tuktuk.pDriv->GetValue(tuktuk.data,pCon); + value -= tuktuk.value; + if(value < .0){ + value *= -1; + } + if(value > .1) { + snprintf(pBueffel,510,"WARNING: motor %s of position by %f", + tuktuk.name,value); + SCWrite(pCon,pBueffel,eWarning); + return; + } + iRet = LLDnodePtr2Next(self->motorList); + } + self->targetReached = 1; +} +/*-----------------------------------------------------------------------*/ +static float ConfGetValue(void *pData, SConnection *pCon){ + pConfigurableVirtualMotor self = (pConfigurableVirtualMotor)pData; + float currentValue = -9999.99; + + assert(self != NULL); + + if(self->readScript != NULL){ + currentValue = invokeReadScript(self,pCon); + } else { + if(self->targetReached == 1){ + return self->targetValue; + } else { + checkMotorValues(self,pCon); + if(self->targetReached){ + currentValue = self->targetValue; + } + } + } + return currentValue; +} +/*-----------------------------------------------------------------------*/ +static void *GetConfigurableVirtualMotorInterface(void *pData, int iID){ + pConfigurableVirtualMotor self = NULL; + + self = (pConfigurableVirtualMotor)pData; + assert(self); + if(iID == DRIVEID){ + return self->pDriv; + } + return NULL; +} +/*-----------------------------------------------------------------------*/ +static void KillConfigurableVirtualMotor(void *data){ + pConfigurableVirtualMotor self = NULL; + + self = (pConfigurableVirtualMotor)data; + if(self != NULL){ + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + self->pDes = NULL; + } + LLDdelete(self->motorList); + if(self->scriptName != NULL){ + free(self->scriptName); + self->scriptName = NULL; + } + if(self->readScript != NULL){ + free(self->readScript); + self->readScript = NULL; + } + free(self); + self = NULL; + } +} +/*------------------------------------------------------------------------*/ +int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics, + void *data, int argc, char *argv[]){ + pConfigurableVirtualMotor pNew = NULL; + char pBueffel[512]; + + if(argc < 2){ + SCWrite(pCon,"ERROR: need name to create configurable motor",eError); + return 0; + } + + pNew = (pConfigurableVirtualMotor)malloc(sizeof(ConfigurableVirtualMotor)); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: no memory to create configurable virtual motor", + eError); + return 0; + } + memset(pNew,0,sizeof(ConfigurableVirtualMotor)); + + pNew->pDes = CreateDescriptor("ConfigurableVirtualMotor"); + pNew->pDriv = CreateDrivableInterface(); + pNew->motorList = LLDcreate(sizeof(RealMotor)); + if(pNew->pDes == NULL || pNew->pDriv == NULL || pNew->motorList < 0){ + SCWrite(pCon,"ERROR: no memory to create configurable virtual motor", + eError); + return 0; + } + + /* + assign functions + */ + pNew->pDes->GetInterface = GetConfigurableVirtualMotorInterface; + pNew->pDriv->Halt = HaltMotors; + pNew->pDriv->CheckLimits = ConfCheckLimits; + pNew->pDriv->SetValue = ConfSetValue; + pNew->pDriv->CheckStatus = ConfCheckStatus; + pNew->pDriv->GetValue = ConfGetValue; + + /* + install command + */ + if( AddCommand(pSics,argv[1],ConfigurableVirtualMotorAction, + KillConfigurableVirtualMotor,pNew) != 1){ + snprintf(pBueffel,510,"ERROR: duplicate command %s not created", + argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } else { + SCSendOK(pCon); + } + + return 1; +} +/*-----------------------------------------------------------------------*/ +int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics, + void *data, int argc, char *argv[]){ + pConfigurableVirtualMotor self = NULL; + char pBueffel[512]; + float value; + + self = (pConfigurableVirtualMotor)data; + assert(self != NULL); + + if(argc > 1){ + strtolower(argv[1]); + if(strcmp(argv[1],"drivescript") == 0){ + if(argc > 2){ + /* set case */ + Arg2Text(argc-2,&argv[2],pBueffel,510); + self->scriptName = strdup(pBueffel); + SCSendOK(pCon); + return 1; + } else { + /* inquiry */ + if(self->scriptName == NULL){ + snprintf(pBueffel,510,"%s.drivescript = UNDEFINED", argv[0]); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + snprintf(pBueffel,510,"%s.drivescript = %s", argv[0], + self->scriptName); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + }else if(strcmp(argv[1],"readscript") == 0){ + if(argc > 2){ + /* set case */ + Arg2Text(argc-2,&argv[2],pBueffel,510); + self->readScript = strdup(pBueffel); + SCSendOK(pCon); + return 1; + } else { + /* inquiry */ + if(self->readScript == NULL){ + snprintf(pBueffel,510,"%s.readscript = UNDEFINED", argv[0]); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + snprintf(pBueffel,510,"%s.readscript = %s", argv[0], + self->readScript); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + } else { + snprintf(pBueffel,5120,"ERROR: subcommand %s to %s unknown", + argv[1],argv[0]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + } else { + value = self->pDriv->GetValue(self,pCon); + snprintf(pBueffel,510,"%s = %f", argv[0],value); + SCWrite(pCon,pBueffel,eValue); + return 1; + } +} diff --git a/confvirtualmot.w b/confvirtualmot.w new file mode 100644 index 00000000..f7eb1c95 --- /dev/null +++ b/confvirtualmot.w @@ -0,0 +1,76 @@ +\subsection{Configurable Virtual Motor} +This is an object which can help in realizing complex scans in space. +In principle this object implements a virtual motor. When this motor is +started a script is called with the desired new position as a parameter. +This script is supposed to either return an error or a comma separated +list of strings motor=value. The name of this script is a configurable +parameter. The object then takes care of starting all the motors (or +better Drivables) and watching over them during the driving operation. + +This objects data structure: +@d confvirt @{ +typedef struct __CONFVIRTMOT { + pObjectDescriptor pDes; + pIDrivable pDriv; + char *scriptName; + char *readScript; + int motorList; + float targetValue; + int targetReached; + char scriptError[512]; + int parseOK; +}ConfigurableVirtualMotor, *pConfigurableVirtualMotor; +@} +The fields are: +\begin{description} +\item[pDes] The standard object descriptor. +\item[pDriv] The drivable interface +\item[scriptName] The name of the program to calculate the new positions +of the real motors. +\item[readScript] A script to read back the current value of the virtual motor. +\item[motorList] A list of the motors to start and control. +\item[targetValue] The target value we wanted to have. +\item[targetReached] A flag which becomes true when a check has showed that +all desired motors have reached their targets. +\item[scriptError] A temporary buffer holding all errors encountered +during processing of the script. +\item[parseOK] a flag which indicates if parsing and execution of the +script went OK. +\end{description} + + +All the magic of this object is hidden in the implementation of the methods +of the drivable interface. Additioanlly there is the standard interpreter +interface. + +@o confvirtmot.i @{ +/*----------------------------------------------------------------------- + Configurable Virtual Motor. This is an generated file describing the + internal data structure of this object. Do not edit. +-----------------------------------------------------------------------*/ +@< confvirt @> + +@} + +@o confvirtmot.h @{ +/*----------------------------------------------------------------------- + A configurable virtual motor object. At motor start a script is called + which returns the motors and positions to drive as a comma separated + list holding entries of the form mot=value. + + COPYRIGHT: see file COPYRIGHT + + Mark Koennecke, August 2004 +-------------------------------------------------------------------------*/ +#ifndef CONFIGURABLEVIRTUALMOTOR +#define CONFIGURABLEVIRTUALMOTOR + +#include "sics.h" + +int MakeConfigurableVirtualMotor(SConnection *pCon, SicsInterp *pSics, + void *data, int aargc, char *argv[]); +int ConfigurableVirtualMotorAction(SConnection *pCon, SicsInterp *pSics, + void *data, int argc, char *argv[]); +#endif + +@} diff --git a/conman.c b/conman.c index 28015567..8066298f 100644 --- a/conman.c +++ b/conman.c @@ -837,7 +837,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) This version writes only to configured log files but not to sockets. Used for automatic file execution for the WWW interface */ - static int SCFileWrite(SConnection *self, char *buffer, int iOut) + int SCFileWrite(SConnection *self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[80]; @@ -1557,6 +1557,54 @@ static void writeToLogFiles(SConnection *self, char *buffer) } return 1; } +/*----------------------------------------------------------------------*/ + int SCUnregisterID(SConnection *pCon, long ID) + { + int iRet; + Item sItem; + + if(!VerifyConnection(pCon)) + { + return 0; + } + iRet = LLDnodePtr2First(pCon->iList); + while(iRet != 0) + { + LLDnodeDataTo(pCon->iList,&sItem); + if(sItem.lID == ID ) + { + LLDnodeDelete(pCon->iList); + LLDnodePtr2Prev(pCon->iList); + } + iRet = LLDnodePtr2Next(pCon->iList); + } + return 1; + } +/*----------------------------------------------------------------------*/ + long SCgetCallbackID(SConnection *pCon, void *pData) + { + int iRet; + Item sItem; + pICallBack pInter; + + if(!VerifyConnection(pCon)) + { + return 0; + } + pInter = (pICallBack)pData; + iRet = LLDnodePtr2First(pCon->iList); + while(iRet != 0) + { + LLDnodeDataTo(pCon->iList,&sItem); + if(sItem.pInterface == pInter) + { + return sItem.lID; + } + iRet = LLDnodePtr2Next(pCon->iList); + } + return -1; + } + /*---------------------- The callback data structure --------------------*/ typedef struct { SConnection *pCon; @@ -1656,7 +1704,8 @@ static void writeToLogFiles(SConnection *self, char *buffer) /* get CallBack interface */ pDum = (pDummy)pCom->pData; assert(pDum); - pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE); + pInterface = (pICallBack)pDum->pDescriptor->GetInterface(pDum, + CALLBACKINTERFACE); if(!pInterface) { sprintf(pBueffel,"ERROR: %s does not support CallBacks", @@ -1772,7 +1821,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) else { SCWrite(self,"ERROR: Bad login",eError); - + printf("Bad login string %s\n", pPtr); } } free(pPtr); diff --git a/conman.h b/conman.h index 9d230daa..b8ef55b2 100644 --- a/conman.h +++ b/conman.h @@ -53,6 +53,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int iGrab; int iErrCode; int parameterChange; + int sicsError; SicsInterp *pSics; /* a FIFO */ @@ -96,11 +97,23 @@ typedef int (*writeFunc)(struct __SConnection *pCon, writeFunc SCGetWriteFunc(SConnection *pCon); void SCSetWriteFunc(SConnection *pCon, writeFunc x); int SCOnlySockWrite(SConnection *self, char *buffer, int iOut); + int SCFileWrite(SConnection *self, char *buffer, int iOut); int SCNotWrite(SConnection *self, char *buffer, int iOut); /************************* CallBack *********************************** */ int SCRegister(SConnection *pCon, SicsInterp *pSics, void *pInter, long lID); int SCUnregister(SConnection *pCon, void *pInter); + /** + * delete a callback with the given ID + */ + int SCUnregisterID(SConnection *pCon, long ID); + /** + * retrieve the ID of a callback on the callback interface + * given in pData. This, together with SCUnregisterID allows to + * ceanly remove all callbacks on a connection + * returns -1 if no ID can be found. + */ + long SCgetCallbackID(SConnection *pCon, void *pData); /******************************* Error **************************************/ void SCSetInterrupt(SConnection *self, int eCode); int SCGetInterrupt(SConnection *self); diff --git a/doc/manager/command.htm b/doc/manager/command.htm index 55204ec2..ba24bbe6 100644 --- a/doc/manager/command.htm +++ b/doc/manager/command.htm @@ -12,6 +12,9 @@ initialisation file. Such special commands are described here.
MakeRuenBuffer
MakeRuenBuffer makes the RünBuffer system available. +
MakeBatchManager [name] +
Installs the new batch buffer management system. If no name is +given, the default will be exe.
MakeDrive
MakeDrive craetes the drive command.
MakeScanCommand name countername headfile recoverfil diff --git a/doc/master.tex b/doc/master.tex index b559b856..dac50192 100644 --- a/doc/master.tex +++ b/doc/master.tex @@ -28,25 +28,33 @@ Author: Mark K\"onnecke This document gives an overview about all the hardware and software systems involved in SINQ instrument control. It describes the relationships between the various pieces and points to additional documentation, if available. -A copy of all documents referred in this paper is stored at: /data/lnslib/distribution/sics/doclib. If they exist in electronic form, this is. The SICS user - and manager information is available on the WWW starting from http://lns00.psi.ch/. +A copy of all documents referred in this paper is stored at: +/afs/psi.ch/project/sinq/commmon/share/sicsdoc. + If they exist in electronic form, this is. The SICS user + and manager information is available on the WWW starting from + http://lns00.psi.ch/. \section{Hardware Overview} For each SINQ instrument the following computing hardware is available: \begin{itemize} -\item A dedicated instrument workstation. Most of them are Compaq Alpha stations - running True64Unix. One workstation is still running OpenVMS. Two instruments, - POLDI and RITA--2, are controlled through Intel--PC's running Linux. +\item A dedicated instrument workstation. Most of them are Intel x86 + machines running Linux. Three instruments use alpha workstations + running Tru64Unix. \item A TCP/IP terminal server providing access to serial ports. \item Optionally, there are 1-3 histogram memory computers installed for those instruments which have area detectors. These histogram memory computers are Motorolla 6800 VME board processors running the vxWorks realtime - operating system. + operating system. Two types of boards are in use: the older Motorolla + MVME1603 boards with 16 MB of memory and MEN-A12 boards with 512MB + memory. +\item Optionally there are National Instruments ENET-100 GPIB/TCPIP + converters in use in order to access GPIB devices, especially those + which came with the Risoe instruments. \end{itemize} -Most instrument hardware is accessed through RS--232 interfaces and the terminal - server. Histogram memories are accessed through the TCP/IP network. Generally - ethernet is used as the main instrument bus. +Most instrument hardware is accessed through RS--232 interfaces and + the terminal server. Histogram memories are accessed through the + TCP/IP network . Generally ethernet is used as the main instrument bus. In addition to the computers at the instrument the following systems are available: @@ -54,8 +62,9 @@ In addition to the computers at the instrument the following systems are \item A True64Unix laboratory server (lnsa15) for data management and primary data anlalysis. \item True64Unix PSI server systems for data processing. +\item A dual processor linux science server (lnsl15). +\item The PSI Linux Login cluster (llc) \item A WWW--server currently installed on lns00. -\item pss123 is a Sun workstation holding the vxWorks development environment. \end{itemize} \section{Software Overview} @@ -75,7 +84,8 @@ The main software component at the instrument is the Sinq Instrument Control debugging. Clients to this SerPortServer such as the SICS server communicate with the server through a special ASCII protocoll transported through TCP/IP. The only documentation - for both the SerPortServer and the ASCII protocoll is the source code. + for both the SerPortServer and the ASCII protocoll is the source + code. And David Maden. There exists another support program, the FileSync server, on any instrument computer. This is a little Java server which listens at a UDP port for a @@ -88,8 +98,8 @@ Then there is the TecsServer. This is a server which maintains and configures Lakeshore temperature controllers used as standard temperature controllers at SINQ. The only documentation for this program is Markus Zolliker. -On many instruments there are histogram memory computers. These usually run the - following programs: +On many instruments there are histogram memory computers. These +usually run the following programs: \begin{description} \item[bootUtil] a utility running when the histogram memory is booted which starts all the other tasks and configures the histogram memory from its @@ -114,30 +124,22 @@ The SICS software is described in a variety of documentation: described in the "SICS Manager Manual". \item The programming concepts of SICS are discussed in the "SICS Programmers Reference". -\item An 90\% complete description of SICS source code modules is available +\item An 97\% complete description of SICS source code modules is available as "SICS Reference Manual". \end{itemize} - -One instrument, TASP, is run with the TASMAD software from ILL which runs - on VMS systems. A user documentation for this system is available at: \newline -\centerline{http://sinq.web.psi.ch/sinq/doc/tasmad.html} -Some configuration issues are explained in this docuement as well. Further - documentation exists only in form of David Maden and an analysis of the - source code. - The RITA--2 instrument from Ris\o{ } runs the TASCOM software. This software is quite well documented in various documents which can be - obtained at WHGA/247 or directly from the Ris\o{ } team and Per Skarup. + obtained at WHGA/112 or directly from the Ris\o{ } team and Per Skarup. -\subsection{Facilities at the Laboratory Server(LNSA15)} +\subsection{Central Facilities} \subsubsection{Central Data Repository} -Under the /data/lnslib/data directory there exists a central storage area for +Under the /afs/psi.ch/project/sinqdata directory there exists a +central storage area for data files measured at the instruments. Newly measured data files are automatically mirrored to this area once a measurement has finished. - Not surprisingly there is a subdirectory for each instrument at SINQ. - These instrument directories contain further subdirectories for each year - of SINQ operation which hold the actual data files. +There are directories for each year of SINQ operation. These contain +subdirectories for the various instruments. \subsubsection{The SINQ File Database} Right early on it was decided to separate the file archival function from the @@ -155,20 +157,15 @@ which is part of the source distribution for the system. Here only an The SINQ File Database consists of the following components: \begin{itemize} -\item The database itself. This is the SQL database system mSQL from - Hughes Technology. -\item Any night the unix utility cron starts a shell script which is - responsible for updating the database. This is done with two special - utility programs: - \begin{itemize} -\item nx\_dbupdate scans a given directory for new files which are not - yet in the database. If such a file is found, the data fields for the - database are extracted and entered into the database. - \item The Java program ScanScan does the same job as nx\_dbupdate for - ASCII files. - \end{itemize} +\item The database itself. The database is installed on the central + database server PSIP0 provided by central computing. The database + software is oracle. +\item Any night a database update program is started as a cron + job. This programs runs on the linux server lnsl15. The program + itself is a tcl script which uses oratcl for accessing the Oracle + database server and nxinter for accessing NeXus files. \item A querying system. Curently the only query interface is a WWW--interface - installed at the WWW--server. + installed at the WWW--server lns00. \end{itemize} @@ -189,28 +186,19 @@ This document also explains how to get hold the source code for most of the software used at SINQ. \subsubsection{Backup} -The laboratory server is also the central backup server for SINQ. Backups are - performed with the Legato networker software onto a tape jukebox holding - 5 tapes with 20GB capacity each. Currently only the /home (holding - user home directories) and the /lnsarchive hierarchy are backed up. -This backup system is a protection against a major harddisk failure. It is no - archive system. Though backup tapes are held as long as possible it - cannot be guaranteed that files older then half a year can be recovered. - The backup software is described in the documentation coming with the - system. No further documentation exists, but the setup can be viewed - through the nwadmin application. +Most user files and the raw data is stored within the AFS network file +system. These files are backed up by central computing. Data files of +older years are additionally archived in the PSI archive system. -The instrument accounts on the instrument computers must be backed up -as well because they sometimes contain valuable scripts. Unfortunately -there are not enough Networker licenses to go round and there is no -reliable linux client software for our version of Legato Networker. -Therefore the data in the instrument accounts is copied nightly to a -special account on lnsa15 which is subjected to the normal -backup. More details: +The instrument and guest accounts on the instrument computers should +be backed up +too because they sometimes contain valuable scripts. These are local +accounts, thus they are not covered through the AFS backup. Data from +these accounts is synchronized nightly onto a special account on the +linux server lnsl15. \begin{itemize} \item There is a script which does the copying. It is {\bf backupinst} -in either /data/lnslib/bin or -/afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf +in /afs/.psi.ch/project/sinq/linux/bin. This script is called with {\bf backupinst INST} where INST must be replaced by the instrument name in capitals. This script essentially calls rsync with appropriate arguments to synchronize the instrument account minus the data @@ -221,8 +209,8 @@ instrument computer must have an entry in crontab reading like: 0 3 * * * /data/lnslib/bin/backupinst TOPSI >/tmp/topsi.log 2>&1 \end{verbatim} Please replace paths and instrument names to match the instrument. -\item The backup account on lnsa15 is named SINQINST, password: -333SINQINST555. It contains a directory for each supported +\item The backup account on lnsl15 is named SINQINST, password: +SINQINSTLNS. It contains a directory for each supported instruments. For backupinst to work properly there must be a line in the .rhosts file of this account for each instrument computer which reads: @@ -237,16 +225,12 @@ linux instrument computers, not the DNS alias. At SINQ the PSI EL--734 motor controllers are used. These motor controllers hold a set of parameters for each motor. As a safeguard against instrument scientists gone wild or a loss of parameters due some electronic or - electrical incident these motor parameters are saved weekly. This happens - on wednesdays mornings. The unix utility crom triggers the process and - starts the script savemot which in turn does all necessary things. The - actual saving of the motor parameters is accomplished with David Maden's - el734 program. The saved parameters end up in the /data/lnslib/motors - hierarchy. There exists a directory for each backup date which in turn - holds a subdirectory for each instrument which holds the files with - the saved parameters. All necessary shell scripts and programs can be - found in the /data/lnslib/motors/bin directory. - + electrical incident these motor parameters should be saved + regularly. To this purpose there exits motor subdirectories in each + instrument account. Motors are either saved into this directory + through a script in this directory or from SICS (TASP, + MORPHEUS). Motor parameter backup is a responsability of the + instrument scientists and must be triggered manually. \subsubsection{License Server} Unfortunately some people use the proprietary IDL programming system. This @@ -275,19 +259,18 @@ Unfortunately some people use the proprietary IDL programming system. This \subsection{Software at the WWW--server} -The WWW--server running at lns00 does not provide static information only but also - active content calculated at runtime. The following services are -implemented: +The WWW--server running at lns00 does not provide static information +only but also active content calculated at runtime. The following +services are implemented: \begin{itemize} \item Keyword search in the SICS documentation. \item Searching the SINQ file database for files matching various criteria. -\item Display of the current instrument status for a couple of instruments. +\item Display of the current instrument status for most instruments. \item An experimental WWW control system for powder diffractometers. \end{itemize} Most of these services are provided through java servlets. In order to do this a servlet engine was needed. The combination Apache WWW-server and Apache - JServ was choosen. However, it is planned to exchange the latter component - by the Jakarta engine in the near future. + Jakarta Tomcat was choosen. The database search servlets are described in more detail in the document: \newline \centerline{The SINQ File Database} @@ -299,8 +282,7 @@ The SICS documentation searching system is built on top of the program SWISH-E w from http://sunsite.berkeley.edu/SWISH-E. The actual search is performed through a TCL--cgi script which calls the swishe application with appropriate parameters. This script can be found as - swishsearch.cgi together with a batch file to start it properly - (swishsearch.bat) in the cgi-bin directory of the WWW hierarchy on lns00. + swishsearch.cgi in the cgi-bin directory of the WWW hierarchy on lns00. Prerequisite for such a search is the existence of an index file. This must be created offline after any major change to the documentation. In order to create this index, cd into the sics directory of the WWW hierarchy and run: @@ -321,12 +303,12 @@ In order to understand the system better it is useful to look at the flow \begin{enumerate} \item Data Files are generated by the instrument control programs at the instrument computer. -\item Data Files are automatically mirrored to the central repository - on the laboratory server lnsa15. This happens through the FileSync server, - a shell script and last not least the unix rsync utility. All this is installed - at the instrument computer. +\item Data Files are automatically mirrored to the central AFS +repository. This happens through the FileSync server, +a shell script and last not least the unix rsync utility. All this is +installed at the instrument computer. \item Nightly new files are scanned for relevant information and their - characteristics are entered into the database system on lnsa15. + characteristics are entered into the database system from lnsl15. \end{enumerate} @@ -341,7 +323,7 @@ The SICS Java clients access the SICS servers on the selected instruments laboratory server lnsa15. \subsection{WWW Services} The file search service on the WWW--server lns00 accesses the database - server running on the laboratory server lnsa15. + server PSIP0. The instrument status display servlets on the WWW--server lns00 access the SICS instrument control servers on the appropriate instrument computers @@ -349,9 +331,6 @@ The instrument status display servlets on the WWW--server lns00 access the \section{Maintainance Tasks} \subsection{Yearly Maintainance} -The only maintainance task at SINQ shutdown is to disable the cron job on - lnsa15 which performs the motor parameter backup. - Whith each new year a couple of things must be done in order to keep the system ship shape: @@ -369,13 +348,10 @@ Whith each new year a couple of things must be done in order to keep the \end{itemize} \item On the laboratory server lnsa15: \begin{itemize} - \item Reenable the motor parameter backup cron job. - \item Create new subdirectories for the new year in the data hierarchy. - \item In /data/lnslib/lib/nxdb create new configuration files for the new - year. Edit them to point to the new years subdirectory. Edit the - updatenxdb shell script to use the newly created configuration files. - Keep the old ones as they may come in handy if the whole database may - require an update. + \item Create a new year hierarchy for the new year. + \item Store the old years data into the PSI archive. + \item Move the old years data into the non backed up AFS area. + \item Make the new year the backed up data on AFS. \end{itemize} \item On the WWW--server lns00: \begin{itemize} @@ -391,10 +367,14 @@ Do these things quite early on in the year. People start measuring background In order to keep up with ageing 1-2 computers have to be exchanged any year. A instrument computer change requires the following adaptions: \begin{enumerate} +\item Start with a PC with the PSI Linux distribution installed. +\item Create two local user accounts: INST and instlnsg. +\item Copy the SICS software to the instrument computer. \item Edit the instrument configuration file and change all occurences of the old computers name to the new name. -\item On lnsa15 as user lnslib: enter the new computer name into the - .rhosts file. This is required for the mirroring to work. +\item Install the cron job for backing up the local instrument + accounts. +\item Make an entry in the .rhosts file of the SINQINST account on lnsl15. \item For the Java clients edit lnet/SINQConfig.java to point to the new computer and rebuild all clients. Redistribute them as well. \item For the WWW status, adapt the sics.conf file on lns00 and restart diff --git a/doc/user/exeman.html b/doc/user/exeman.html new file mode 100644 index 00000000..a41063d8 --- /dev/null +++ b/doc/user/exeman.html @@ -0,0 +1,59 @@ + + +The Batch Buffer Manager + + +

The Batch Buffer Manager

+

+The batch buffer manager handles the execution of batch files. It can +execute batch files directly. Additionally, batch files can be added +into a queue for later processing. The batch buffer manager supports +the following command described below. Please note, that the examples +assume that the batch manager has been configured into SICS under the +name of exe. +

+
exe buffername +
directly load the buffer stored in the file buffername and execute +it. The file is searched in the batch buffer search path. +
exe batchpath [newpath] +
Without an argument, this command lists the directories which are +searched for batch files. With an argument, a new search path is +set. It is possible to specify multiple directories by separating them +with colons. +
exe syspath [newpath] +
Without an argument, this command lists the system directories which are +searched for batch files. With an argument, a new system search path is +set. It is possible to specify multiple directories by separating them +with colons. +
exe info +
prints the name of the currently executing batch buffer +
exe info stack +
prints the stack of nested batch files (i.e. batch files calling +each other). +
exe info range [name] +
Without an argument prints the range of code currently being +executed. With a parameter, prints the range of code executing in +named buffer within the stack of nested buffers. The reply looks like: +number of start character = number of end character = line number. +
exe info text [name] +
Without an argument prints the code text currently being +executed. With a parameter, prints the range of code text executing in the +named buffer within the stack of nested buffers. +
exe enqueue buffername +
Appends buffername to the queue of batch buffers to execute. +
exe clear +
Clears the queue of batch buffers +
exe queue +
Prints the content of the batch buffer queue. +
exe run +
Starts executing the batch buffers in the queue. +
exe print buffername +
Prints the content of the batch buffer buffername to the screen. +
exe interest +
Switches on automatic notification about starting batch files, +executing a new bit of code or for finishing a batch file. This is +most useful for SICS clients watching the progress of the experiment. +
+

+ + diff --git a/doc/user/tricsingle.htm b/doc/user/tricsingle.htm index 15fa387b..94cd2db1 100644 --- a/doc/user/tricsingle.htm +++ b/doc/user/tricsingle.htm @@ -14,23 +14,7 @@ to be solved are:
  • Measure a couple of reflections.
  • Furthermore there are some specialities. -There are two ways to achieve all this: -The older way uses some built in SICS functionality plus some external -programs inherited from the ILL. This is called the ILL operation. -Then a complete -four circle package called DIFRAC from P. White and Eric Gabe was -integrated into SICS. -This is The Difrac way of operation.

    -

    DIFRAC

    -

    -The DIFRAC commands are accessed by prepending the difrac commands -with dif. For example: "dif td" calls the difrac td -command. For more information on DIFRAC commands see the separate -DIFRAC manual. -

    - -

    ILL operation

    Locate Reflections

    If you know x-ray single crystal diffractometers you'll expect sophisticated diff --git a/doc/user/trscan.htm b/doc/user/trscan.htm index 5c3e22de..e6608c93 100644 --- a/doc/user/trscan.htm +++ b/doc/user/trscan.htm @@ -26,7 +26,23 @@ Two special commands have been defined for TRICS with a PSD:

    reads reflection HKL values from file filename and performs tricsscans for each reflection. These will be done eith step width step, the number of steps np with counting mode mode and a preset of -preset. These parameters have the same meaning as described above. +preset. These parameters have the same meaning as described above. If the +{\bf hkl nb 1} command has been given before the invocation of this scan, + reflections will be searched in normal beam geometry. psdrefscan, however, +will only print the normal four circle angles, though. +
    detscan start step np mode preset +
    Detscan performs a scan in two theta. This may be useful for detector +calibrations. Arguments as described above. +
    phscan start step np mode preset +
    Phscan performs a scan in phi. This can be usefule for orienting a +crystal. Arguments as described above. +
    o2tscan2d start step np mode preset +
    O2tscan2d performs a omega - two-theta scan with the PSD. +Arguments as described above. +
    hklscan2d +
    For a scan in reciprocal space with the PSD, see the +documentation for hklscan. Please note that +for a PSD HKL scan, all commans have to start with hklscan2d.
  • diff --git a/event.c b/event.c index 707304b6..4aa11fb1 100644 --- a/event.c +++ b/event.c @@ -60,6 +60,9 @@ "COUNTEND", "FILELOADED", "MOTEND", + "BATCHSTART", + "BATCHAREA", + "BATCHEND", NULL }; diff --git a/event.h b/event.h index 2221a13f..56c75ecd 100644 --- a/event.h +++ b/event.h @@ -1,5 +1,5 @@ -#line 79 "event.w" +#line 85 "event.w" /*---------------------------------------------------------------------------- E V E N T @@ -18,7 +18,7 @@ int Text2Event(char *pText); -#line 92 "event.w" +#line 98 "event.w" @@ -38,19 +38,22 @@ #define COUNTEND 11 #define FILELOADED 12 #define MOTEND 13 +#define BATCHSTART 14 +#define BATCHAREA 15 +#define BATCHEND 16 -#line 94 "event.w" +#line 100 "event.w" /*--------------- Signals for the Signalfunction of each task ------------*/ -#line 64 "event.w" +#line 70 "event.w" #define SICSINT 300 #define SICSBROADCAST 301 #define TOKENGRAB 302 #define TOKENRELEASE 303 -#line 97 "event.w" +#line 103 "event.w" #endif diff --git a/event.tex b/event.tex index 11e36a07..5b230fb1 100644 --- a/event.tex +++ b/event.tex @@ -1,13 +1,3 @@ -\newcommand{\NWtarget}[2]{#2} -\newcommand{\NWlink}[2]{#2} -\newcommand{\NWtxtMacroDefBy}{Macro defined by} -\newcommand{\NWtxtMacroRefIn}{Macro referenced in} -\newcommand{\NWtxtMacroNoRef}{Macro never referenced} -\newcommand{\NWtxtDefBy}{Defined by} -\newcommand{\NWtxtRefIn}{Referenced in} -\newcommand{\NWtxtNoRef}{Not referenced} -\newcommand{\NWtxtFileDefBy}{File defined by} -\newcommand{\NWsep}{${\diamond}$} \subsection{SICS Events} This section lists the callback events known to Sics, their purpose, and their associated event datastructures when applicable. See the @@ -22,17 +12,17 @@ This module defines several event related functions as well. \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap1} -$\langle\,$eFunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ +$\langle$eFunc {\footnotesize ?}$\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@ int Text2Event(char *pText);@\\ -\mbox{}\verb@@{\NWsep} +\mbox{}\verb@@$\diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. +\item Macro referenced in scrap ?. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -41,7 +31,7 @@ if the event code is not known, else the apropriate event code. \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap2} -$\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ +$\langle$VE {\footnotesize ?}$\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -59,12 +49,15 @@ $\langle\,$VE\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \mbox{}\verb@#define COUNTEND 11@\\ \mbox{}\verb@#define FILELOADED 12@\\ \mbox{}\verb@#define MOTEND 13@\\ -\mbox{}\verb@@{\NWsep} +\mbox{}\verb@#define BATCHSTART 14@\\ +\mbox{}\verb@#define BATCHAREA 15@\\ +\mbox{}\verb@#define BATCHEND 16@\\ +\mbox{}\verb@@$\diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. +\item Macro referenced in scrap ?. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -88,6 +81,9 @@ fiffractometer has been measured. operation. \item[COUNTEND] is an event signalling the end of a counting operation. \item[MOTEND] signals the end of a driving operation. +\item[BATCHSTART] signals starting batch processing a new buffer +\item[BATCHAREA] signals that a new area of the batch file is processing. +\item[BATCHEND] signals the end of the batch buffers processing. \end{description} Furthermore event contains system wide signal codes which are interpreted in @@ -98,7 +94,7 @@ possible codes are defined. \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap3} -$\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ +$\langle$VSIG {\footnotesize ?}$\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -106,12 +102,12 @@ $\langle\,$VSIG\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \mbox{}\verb@#define SICSBROADCAST 301@\\ \mbox{}\verb@#define TOKENGRAB 302@\\ \mbox{}\verb@#define TOKENRELEASE 303@\\ -\mbox{}\verb@@{\NWsep} +\mbox{}\verb@@$\diamond$ \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. +\item Macro referenced in scrap ?. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -126,7 +122,7 @@ data is the string to send. \end{description} \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap4} -\verb@"event.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$ +\verb@"event.h"@ {\footnotesize ? }$\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -142,14 +138,14 @@ data is the string to send. \mbox{}\verb@----------------------------------------------------------------------------*/@\\ \mbox{}\verb@#ifndef SICSEVENT@\\ \mbox{}\verb@#define SICSEVENT@\\ -\mbox{}\verb@@\hbox{$\langle\,$eFunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ +\mbox{}\verb@@$\langle$eFunc {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@@\\ -\mbox{}\verb@@\hbox{$\langle\,$VE\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ +\mbox{}\verb@@$\langle$VE {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\ -\mbox{}\verb@@\hbox{$\langle\,$VSIG\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@ @\\ +\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@{\NWsep} +\mbox{}\verb@@$\diamond$ \end{list} \vspace{-2ex} \end{minipage}\\[4ex] diff --git a/event.w b/event.w index 3c96e085..393765c9 100644 --- a/event.w +++ b/event.w @@ -32,6 +32,9 @@ if the event code is not known, else the apropriate event code. #define COUNTEND 11 #define FILELOADED 12 #define MOTEND 13 +#define BATCHSTART 14 +#define BATCHAREA 15 +#define BATCHEND 16 @} \begin{description} \item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the @@ -53,6 +56,9 @@ fiffractometer has been measured. operation. \item[COUNTEND] is an event signalling the end of a counting operation. \item[MOTEND] signals the end of a driving operation. +\item[BATCHSTART] signals starting batch processing a new buffer +\item[BATCHAREA] signals that a new area of the batch file is processing. +\item[BATCHEND] signals the end of the batch buffers processing. \end{description} Furthermore event contains system wide signal codes which are interpreted in diff --git a/exe.w b/exe.w new file mode 100644 index 00000000..cf4dabbf --- /dev/null +++ b/exe.w @@ -0,0 +1,221 @@ +\subsection{The Exe Batch Processing System} +This is a reimplementation of the batch processing scheme in SICS. It +addresses a couple of shortcomings of the fileeval command which is +already implemented. In the long run fileeval should be replaced by +this system. In contrast to fileeval the following feautures will be +provided: \begin{itemize} +\item A list of directories to search for batch files +\item Better feedback about which batch file, which line, which +segement of text is executing. This even for the case when batch files +are nested. +\item Callbacks when batch processing proceeds. This in order to +allow a download mode in sicsed. +\item Means of downloading a batch file. +\end{itemize} + +The source code for this is divided into two parts:\begin{itemize} +\item A buffer handling component. This handles everything for +managing and executing a single buffer. +\item A control module which handles the management of the batch +buffers. +\end{itemize} + +\subsubsection{Single Buffer Handling Code} +For each batch buffer there is a data structure: +@d exebufdat @{ +typedef struct __EXEBUF{ + char *name; + pDynString bufferContent; + int start; + int end; + int lineno; +} ExeBuf; +@} +The items are: +\begin{description} +\item[name] The name of the batch buffer. +\item[bufferContent] The text of the buffer in a dynamic string. +\item[start] The start index of the currently executing part of the text +\item[end] The end index of the currently executing text. +\item[lineno] The currently executing line. +\end{description} + +The interface to this buffer system comprises: +@d exebufint @{ + typedef struct __EXEBUF *pExeBuf; + + /** + * create an exe buffer + * @@param The name to use for the exe buffer + * @@return A new exe buffer or NULL if out of memory + */ + pExeBuf exeBufCreate(char *name); + /** + * delete an exe buffer + * @@param data The exe buffer to delete + */ + void exeBufKill(void *data); + void exeBufDelete(pExeBuf data); + /** + * add a a line to the exe buffer + * @@param self The exe buffer the line is to be added to + * @@param line The text to add + * @@return 1 on success, 0 when out of memory + */ + int exeBufAppend(pExeBuf self, char *line); + /** + * load an exe buffer from a file + * @@param self The exe buffer to load + * @@param filename The name of the file to load + * @@return 1 on success, 0 if the file could not be opened or + * memory is exhausted. + */ + int exeBufLoad(pExeBuf self, char *filename); + /** + * save an exe buffer to a file. + * @@param self The exe buffer to laod + * @@param filename The name of the file to laod + * @@return 1 on success, 0 if the file could not be opened. + */ + int exeBufSave(pExeBuf self, char *filename); + /** + * process an exe buffer + * @@param self The exe buffer to process + * @@param pSics The SICS interpreter to use for processing + * @@param pCon The connection object providing the environment for + * processing this buffer. + * @@pCall The callback interface to use for automatic notifications + * @@return 1 on success, 0 on error + */ + int exeBufProcess(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, pICallBack pCall); + /** + * retrieves the executing range + * @@param self The exe buffer to query + * @@param start The start of the executing range + * @@param end The end of the executing range + * @@param lineno The current line number + */ + void exeBufRange(pExeBuf self, int *start, int *end, int *lineno); + /** + * retrieves some portion of text + * @@param self The exe buffer to query + * @@param start The start index from which to copy + * @@param end The end pointer until which to copy + * @@return A dynamic string holding the currently executing text. It is + * the clients task to delete this buffer sfter use. Or NULL if out of + * memory. + */ + pDynString exeBufText(pExeBuf self, int start, int end); + /** + * retrieves the name of the batch buffer + * @@param self The exe buffer to query + * @@return A pointer to the buffer name. Do not delete! The name + * is still owned by the exe beuffer. + */ + char *exeBufName(pExeBuf self); +@} + + +\subsubsection{Managing exe Buffers} +This section describes the interface to the management module for +batch buffers. This management module is called the exe manager. This +module also provides the interpreter interface to +the batch buffer system. The batch buffer system can operate in two +modes of operation: +\begin{itemize} +\item It keeps track of nested batch buffers, i.e. batch buffers which +call each other through exe calls in the batch buffer itself. +\item The management module also provides a stack for batch +buffers. This stack can be preloaded and then can be executed +sequentially by the exe manager. In order to do this provisions are +made for loading batch buffers from files or through commands. +\end{itemize} +Moreover the exe manager provides commands to view the current stack +and to find out what is currently being executed. + +For all this we need a data structure: +@d exemandat @{ +typedef struct __EXEMAN{ + pObjectDescriptor pDes; + pICallBack pCall; + char *sysPath; + char *batchPath; + pDynar exeStack; + int exeStackPtr; + int runList; + pExeBuf uploadBuffer; +}ExeMan, *pExeMan; +@} +The fields: +\begin{itemize} +\item[pDes] The standard object descriptor. +\item[pCall] A callback interface to allow for automatic notifications +about the operation of this module. +\item[batchPath] The search path for batch buffers. +\item[exeStack] The stack of nested batch buffers. +\item[exeStackPtr] A pointer into exeStack. +\item[runList] The list of buffers to run when running batch buffers. +\item[uploadBuffer] A exe buffer to which data is uploaded. Also serves + as a flag if uploading is possible. In this case uploadBuffer must be +not NULL. +\end{itemize} + +The public interface to the exe manager are the interpreter interface +functions. All the rest are module private functions. + +@d exemanint @{ +int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +@} + +@o exeman.i -d @{ +/*------------------------------------------------------------------- + Internal header file for the exe manager module. Do not edit. This + is automatically generated from exe.w +-------------------------------------------------------------------*/ +@ +@} + +@o exeman.h @{ +/** + * The batch buffer manager module. For more information see exe.tex. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2004 +*/ +#ifndef EXEMAN +#define EXEMAN +@ +#endif +@} + +@o exebuf.i -d @{ +/*-------------------------------------------------------------------- + Internal header file for the exe buffer module. Do not edit. This is + automatically generated from exe.w +---------------------------------------------------------------------*/ +@ + +@} + +@o exebuf.h -d @{ +/** + * Buffer handling code for the Exe Buffer batch file processing + * module. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2004 + */ +#ifndef EXEBUF +#define EXEBUF +#include +#include "dynstring.h" +@ + +#endif +@} diff --git a/exebuf.c b/exebuf.c new file mode 100644 index 00000000..77d1fc33 --- /dev/null +++ b/exebuf.c @@ -0,0 +1,231 @@ +/** + * Implementation file for the exe buffer buffer handling system. + * + * copyright: see file COPYRIGHT + * + * More information in exe.tex + * + * Mark Koennecke, November 2004 + */ + +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "exebuf.h" +#include "dynstring.h" +#include "exebuf.i" +#include "status.h" + +/*-----------------------------------------------------------------------*/ +pExeBuf exeBufCreate(char *name){ + pExeBuf pNew = NULL; + + pNew = (pExeBuf)malloc(sizeof(ExeBuf)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(ExeBuf)); + pNew->name = strdup(name); + pNew->bufferContent = CreateDynString(1024,1024); + if(!pNew->bufferContent){ + return NULL; + } + return pNew; +} +/*----------------------------------------------------------------------*/ +void exeBufKill(void *data){ + exeBufDelete((pExeBuf)data); +} +/*-----------------------------------------------------------------------*/ +void exeBufDelete(pExeBuf self){ + if(self == NULL){ + return; + } + if(self->name != NULL){ + free(self->name); + self->name = NULL; + } + if(self->bufferContent != NULL){ + DeleteDynString(self->bufferContent); + self->bufferContent = NULL; + } + free(self); +} +/*----------------------------------------------------------------------*/ +int exeBufAppend(pExeBuf self, char *line){ + int status; + assert(self); + + status = DynStringConcat(self->bufferContent,line); + DynStringConcatChar(self->bufferContent,'\n'); + return status; +} +/*-----------------------------------------------------------------------*/ +static char *locateName(char *filename){ + char *pPtr; + int i; + + pPtr = filename + strlen(filename) -1; + for(i = strlen(filename) -1; i > 0; i--,pPtr--){ + if(*pPtr == '/'){ + pPtr++; + return pPtr; + } + } + return filename; +} +/*-----------------------------------------------------------------------*/ +int exeBufLoad(pExeBuf self, char *filename){ + char line[256]; + FILE *fd = NULL; + int status; + + assert(self); + fd = fopen(filename,"r"); + if(fd == NULL){ + return 0; + } + while(fgets(line,255,fd) != NULL){ + status = exeBufAppend(self,line); + if(status != 1){ + fclose(fd); + return 0; + } + } + fclose(fd); + if(self->name != NULL){ + free(self->name); + } + self->name = strdup(locateName(filename)); + return 1; +} +/*----------------------------------------------------------------------*/ +int exeBufSave(pExeBuf self, char *filename){ + FILE *fd = NULL; + + fd = fopen(filename,"w"); + if(fd == NULL){ + return 0; + } + fputs(GetCharArray(self->bufferContent),fd); + fclose(fd); + self->name = strdup(locateName(filename)); + return 1; +} +/*================ process batch buffer ==============================*/ +static pDynString findBlockEnd(pExeBuf self){ + pDynString command = NULL; + char *buffer = NULL; + int i; + + assert(self); + + command = CreateDynString(80,80); + if(command == NULL){ + return NULL; + } + buffer = GetCharArray(self->bufferContent); + if(self->end != 0){ + self->start = self->end + 1; + } + for(i = self->start; i < strlen(buffer); i++){ + DynStringConcatChar(command,buffer[i]); + if(buffer[i] == '\n'){ + self->lineno++; + if(Tcl_CommandComplete(GetCharArray(command))){ + self->end = i; + return command; + } + } + } + DeleteDynString(command); + return NULL; +} +/*---------------------------------------------------------------------*/ +int exeBufProcess(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, pICallBack pCall){ + pDynString command = NULL; + Tcl_Interp *pTcl = NULL; + int status; + + assert(self); + assert(pSics); + + self->start = 0; + self->end = 0; + self->lineno = 0; + pTcl = InterpGetTcl(pSics); + + InvokeCallBack(pCall,BATCHSTART,self->name); + + while((command = findBlockEnd(self)) != NULL){ + InvokeCallBack(pCall,BATCHAREA,NULL); + status = Tcl_Eval(pTcl,GetCharArray(command)); + if(status != TCL_OK){ + if(pCon->sicsError == 0){ + /* + Tcl Error + */ + if(strlen(pTcl->result) >= 2){ + SCWrite(pCon,pTcl->result,eError); + } + SCWrite(pCon,"ERROR: Tcl error in block:",eError); + SCWrite(pCon,GetCharArray(command),eError); + SCWrite(pCon,"ERROR: end of Tcl error block",eError); + } else { + /* + SICS error: has already been reported + */ + pCon->sicsError = 0; + } + } + DeleteDynString(command); + if(SCGetInterrupt(pCon) >= eAbortBatch){ + SCWrite(pCon,"ERROR: batch processing interrupted",eError); + SetStatus(eEager); + return 0; + } else { + SCSetInterrupt(pCon,eContinue); + } + } + InvokeCallBack(pCall,BATCHEND,self->name); + return 1; +} +/*------------------------------------------------------------------------*/ +void exeBufRange(pExeBuf self, int *start, int *end, int *lineno){ + assert(self); + *start = self->start; + *end = self->end; + *lineno = self->lineno; +} +/*------------------------------------------------------------------------*/ +pDynString exeBufText(pExeBuf self, int start, int end){ + pDynString result = NULL; + char *pPtr; + int i; + + assert(self); + + result = CreateDynString(256,132); + if(result == NULL){ + return NULL; + } + + pPtr = GetCharArray(self->bufferContent); + if(end >= strlen(pPtr)){ + end = strlen(pPtr) -1; + } + for(i = start; i < end; i++){ + DynStringConcatChar(result,pPtr[i]); + } + return result; +} +/*-----------------------------------------------------------------------*/ +char *exeBufName(pExeBuf self){ + assert(self); + return self->name; +} + + diff --git a/exebuf.h b/exebuf.h new file mode 100644 index 00000000..3a432514 --- /dev/null +++ b/exebuf.h @@ -0,0 +1,95 @@ + +#line 205 "exe.w" + +/** + * Buffer handling code for the Exe Buffer batch file processing + * module. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2004 + */ +#ifndef EXEBUF +#define EXEBUF +#include +#include "dynstring.h" + +#line 44 "exe.w" + + typedef struct __EXEBUF *pExeBuf; + + /** + * create an exe buffer + * @param The name to use for the exe buffer + * @return A new exe buffer or NULL if out of memory + */ + pExeBuf exeBufCreate(char *name); + /** + * delete an exe buffer + * @param data The exe buffer to delete + */ + void exeBufKill(void *data); + void exeBufDelete(pExeBuf data); + /** + * add a a line to the exe buffer + * @param self The exe buffer the line is to be added to + * @param line The text to add + * @return 1 on success, 0 when out of memory + */ + int exeBufAppend(pExeBuf self, char *line); + /** + * load an exe buffer from a file + * @param self The exe buffer to load + * @param filename The name of the file to load + * @return 1 on success, 0 if the file could not be opened or + * memory is exhausted. + */ + int exeBufLoad(pExeBuf self, char *filename); + /** + * save an exe buffer to a file. + * @param self The exe buffer to laod + * @param filename The name of the file to laod + * @return 1 on success, 0 if the file could not be opened. + */ + int exeBufSave(pExeBuf self, char *filename); + /** + * process an exe buffer + * @param self The exe buffer to process + * @param pSics The SICS interpreter to use for processing + * @param pCon The connection object providing the environment for + * processing this buffer. + * @pCall The callback interface to use for automatic notifications + * @return 1 on success, 0 on error + */ + int exeBufProcess(pExeBuf self, SicsInterp *pSics, + SConnection *pCon, pICallBack pCall); + /** + * retrieves the executing range + * @param self The exe buffer to query + * @param start The start of the executing range + * @param end The end of the executing range + * @param lineno The current line number + */ + void exeBufRange(pExeBuf self, int *start, int *end, int *lineno); + /** + * retrieves some portion of text + * @param self The exe buffer to query + * @param start The start index from which to copy + * @param end The end pointer until which to copy + * @return A dynamic string holding the currently executing text. It is + * the clients task to delete this buffer sfter use. Or NULL if out of + * memory. + */ + pDynString exeBufText(pExeBuf self, int start, int end); + /** + * retrieves the name of the batch buffer + * @param self The exe buffer to query + * @return A pointer to the buffer name. Do not delete! The name + * is still owned by the exe beuffer. + */ + char *exeBufName(pExeBuf self); + +#line 218 "exe.w" + + +#endif diff --git a/exebuf.i b/exebuf.i new file mode 100644 index 00000000..11634dbf --- /dev/null +++ b/exebuf.i @@ -0,0 +1,21 @@ + +#line 196 "exe.w" + +/*-------------------------------------------------------------------- + Internal header file for the exe buffer module. Do not edit. This is + automatically generated from exe.w +---------------------------------------------------------------------*/ + +#line 25 "exe.w" + +typedef struct __EXEBUF{ + char *name; + pDynString bufferContent; + int start; + int end; + int lineno; +} ExeBuf; + +#line 201 "exe.w" + + diff --git a/exeman.c b/exeman.c new file mode 100644 index 00000000..b4c370e5 --- /dev/null +++ b/exeman.c @@ -0,0 +1,765 @@ +/** + * Implementation file for the exe buffer buffer manager. + * + * copyright: see file COPYRIGHT + * + * More information in exe.tex + * + * Mark Koennecke, November 2004 + */ + +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "exebuf.h" +#include "exeman.h" +#include "sdynar.h" +#include "dynstring.h" +#include "lld.h" +#include "exeman.i" +#include "splitter.h" + +/*-------------------------------------------------------------------*/ +static void KillExeMan(void *data){ + pExeMan self = (pExeMan)data; + if(!self){ + return; + } + if(self->pDes){ + DeleteDescriptor(self->pDes); + } + if(self->pCall){ + DeleteCallBackInterface(self->pCall); + } + if(self->batchPath){ + free(self->batchPath); + } + if(self->sysPath){ + free(self->sysPath); + } + if(self->exeStack){ + DeleteDynar(self->exeStack); + } + LLDdelete(self->runList); + free(self); +} +/*-----------------------------------------------------------------*/ +static int SaveExeMan(void *data, char *name, FILE *fd){ + pExeMan self = (pExeMan)data; + + if(!self){ + return 0; + } + fprintf(fd,"%s batchpath %s\n",name,self->batchPath); + fprintf(fd,"%s syspath %s\n",name,self->sysPath); + return 1; +} +/*-----------------------------------------------------------------*/ +static void *ExeManInterface(void *data, int interfaceID){ + pExeMan self = (pExeMan)data; + + if(self == NULL){ + return NULL; + } + if(interfaceID == CALLBACKINTERFACE){ + return self->pCall; + } + return NULL; +} +/*------------------------------------------------------------------*/ +int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pExeMan pNew = NULL; + int status; + + pNew = (pExeMan)malloc(sizeof(ExeMan)); + if(!pNew){ + SCWrite(pCon,"ERROR: out of memory creating exe Manager",eError); + return 0; + } + + memset(pNew,0,sizeof(ExeMan)); + pNew->pDes = CreateDescriptor("ExeManager"); + pNew->pCall = CreateCallBackInterface(); + pNew->sysPath = strdup("./"); + pNew->batchPath = strdup("./"); + pNew->exeStack = CreateDynar(1,10,10,exeBufKill); + pNew->exeStackPtr = -1; + pNew->runList = LLDcreate(sizeof(pExeBuf)); + if(!pNew->pDes || !pNew->pCall || ! pNew->batchPath || + !pNew->exeStack || pNew->runList < 0){ + SCWrite(pCon,"ERROR: out of memory creating exe Manager",eError); + return 0; + } + pNew->pDes->SaveStatus = SaveExeMan; + pNew->pDes->GetInterface = ExeManInterface; + + if(argc > 1){ + status = AddCommand(pSics, + argv[1], + ExeManagerWrapper, + KillExeMan, + pNew); + } else { + status = AddCommand(pSics, + "exe", + ExeManagerWrapper, + KillExeMan, + pNew); + } + if(status != 1) { + SCWrite(pCon,"ERROR: duplicate exe manager not created",eError); + return 0; + } + return 1; +} +/*======================== buffer execution ==========================*/ +static int fileExists(char *path){ + FILE *fd = NULL; + int status = 0; + + fd = fopen(path,"r"); + if(fd != NULL){ + fclose(fd); + status = 1; + } + return status; +} +/*--------------------------------------------------------------------*/ +extern char *stptok(char *s, char *t, int len, char *brk); + +static pDynString locateBatchBuffer(pExeMan self, char *name){ + pDynString result = NULL; + char pPath[132], *pPtr = NULL; + + result = CreateDynString(256,256); + if(!result){ + return NULL; + } + + pPtr = self->batchPath; + while((pPtr = stptok(pPtr,pPath,131,":")) != NULL){ + DynStringCopy(result,pPath); + DynStringConcatChar(result,'/'); + DynStringConcat(result,name); + if(fileExists(GetCharArray(result))){ + return result; + } + } + + pPtr = self->sysPath; + while((pPtr = stptok(pPtr,pPath,131,":")) != NULL){ + DynStringCopy(result,pPath); + DynStringConcatChar(result,'/'); + DynStringConcat(result,name); + if(fileExists(GetCharArray(result))){ + return result; + } + } + DeleteDynString(result); + return NULL; +} +/*-------------------------------------------------------------------*/ +static int runBatchBuffer(pExeMan self, SConnection *pCon, + SicsInterp *pSics, char *name){ + pDynString filePath = NULL; + char pBueffel[256]; + pExeBuf buffer = NULL; + int status; + + filePath = locateBatchBuffer(self,name); + if(filePath == NULL){ + snprintf(pBueffel,255,"ERROR: batch buffer %s not found in path", + name); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + buffer = exeBufCreate(name); + if(!buffer){ + DeleteDynString(filePath); + SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError); + return 0; + } + status = exeBufLoad(buffer,GetCharArray(filePath)); + if(!status){ + DeleteDynString(filePath); + SCWrite(pCon,"ERROR: failed to load batch buffer",eError); + return 0; + } + DeleteDynString(filePath); + + self->exeStackPtr++; + DynarPut(self->exeStack,self->exeStackPtr,buffer); + status = exeBufProcess(buffer,pSics,pCon,self->pCall); + self->exeStackPtr--; + return status; +} +/*========================== path management ========================*/ +static int handleBatchPath(pExeMan self, SConnection *pCon, int argc, + char *argv[]){ + char pBuffer[1024]; + + if(strcmp(argv[1],"batchpath") == 0) { + if(argc > 2) { + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + if(self->batchPath != NULL){ + free(self->batchPath); + } + self->batchPath = strdup(argv[2]); + SCSendOK(pCon); + SCparChange(pCon); + return 1; + } else { + snprintf(pBuffer,1023,"%s.batchpath = %s", argv[0],self->batchPath); + SCWrite(pCon,pBuffer,eValue); + return 1; + } + } + if(strcmp(argv[1],"syspath") == 0) { + if(argc > 2) { + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + if(self->sysPath != NULL){ + free(self->sysPath); + } + self->sysPath = strdup(argv[2]); + SCSendOK(pCon); + SCparChange(pCon); + return 1; + } else { + snprintf(pBuffer,1023,"%s.syspath = %s", argv[0],self->sysPath); + SCWrite(pCon,pBuffer,eValue); + return 1; + } + } + return -1; +} +/*=========================== callbacks ==============================*/ +typedef struct { + SConnection *pCon; + pExeMan exe; +}exeInfo, *pExeInfo; +/*------------------------------------------------------------------*/ +static void killExeInfo(void *pData){ + pExeInfo self = (pExeInfo)pData; + if(self != NULL){ + free(self); + } +} +/*-----------------------------------------------------------------*/ +static pExeInfo makeExeInfo(SConnection *pCon, pExeMan self){ + pExeInfo pNew = NULL; + pNew = malloc(sizeof(exeInfo)); + if(pNew == NULL){ + SCWrite(pCon, + "ERROR: failed to allocate info structure for registering callbacks", + eError); + return NULL; + } + pNew->pCon = pCon; + pNew->exe = self; + return pNew; +} +/*------------------------------------------------------------------*/ +static int BufferCallback(int iEvent, void *pEvent, void *pUser){ + pExeInfo self = (pExeInfo)pUser; + char *name = (char *)pEvent; + char pBueffel[132]; + + if(iEvent == BATCHSTART){ + snprintf(pBueffel,131,"BATCHSTART=%s",name); + SCWrite(self->pCon,pBueffel,eWarning); + return 1; + } + if(iEvent == BATCHEND){ + snprintf(pBueffel,131,"BATCHEND=%s",name); + SCWrite(self->pCon,pBueffel,eWarning); + return 1; + } + return 0; +} +/*-------------------------------------------------------------------*/ +static int LineCallBack(int iEvent, void *pEvent, void *pUser){ + pExeInfo self = (pExeInfo)pUser; + char pBueffel[256]; + int start, end, lineno; + void *pPtr = NULL; + pExeBuf buf = NULL; + + assert(self); + if(iEvent == BATCHAREA){ + DynarGet(self->exe->exeStack,self->exe->exeStackPtr,&pPtr); + buf = (pExeBuf)pPtr; + assert(buf); + exeBufRange(buf,&start,&end,&lineno); + snprintf(pBueffel,255,"%s.range = %d = %d",exeBufName(buf), + start,end); + SCWrite(self->pCon,pBueffel,eWarning); + return 1; + } + return 0; +} +/*--------------------------------------------------------------------*/ +static void registerCallbacks(SConnection *pCon, SicsInterp *pSics, + pExeMan self){ + pExeInfo info = NULL; + long lID; + + info = makeExeInfo(pCon,self); + if(info == NULL){ + return; + } + lID = RegisterCallback(self->pCall, BATCHSTART, BufferCallback, + info, killExeInfo); + SCRegister(pCon,pSics, self->pCall,lID); + lID = RegisterCallback(self->pCall, BATCHEND, BufferCallback, + info, NULL); + SCRegister(pCon,pSics, self->pCall,lID); + lID = RegisterCallback(self->pCall, BATCHAREA, LineCallBack, + info, killExeInfo); + SCRegister(pCon,pSics, self->pCall,lID); +} +/*--------------------------------------------------------------------*/ +static void unregisterCallbacks(SConnection *pCon, pExeMan self){ + long lID; + int i; + + for(i = 0; i < 3; i++){ + lID = SCgetCallbackID(pCon,self->pCall); + if(lID >= 0){ + RemoveCallback(self->pCall,lID); + SCUnregisterID(pCon,lID); + } + } +} +/*========================= uploading ===============================*/ +static int startUpload(pExeMan self, SConnection *pCon){ + if(SCGetRights(pCon) > usUser){ + SCWrite(pCon,"ERROR: no permission to upload buffers",eError); + return 0; + } + if(self->uploadBuffer != NULL){ + SCWrite(pCon,"ERRO: another upload is still in progress",eError); + return 0; + } + self->uploadBuffer = exeBufCreate("upload"); + if(self->uploadBuffer == NULL){ + SCWrite(pCon,"ERROR: failed to create upload buffer",eError); + return 0; + } + return 1; +} +/*---------------------------------------------------------------------*/ +static int appendLine(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + char pLine[1024]; + + if(SCGetRights(pCon) > usUser){ + SCWrite(pCon,"ERROR: no permission to upload buffers",eError); + return 0; + } + if(self->uploadBuffer == NULL){ + SCWrite(pCon,"ERROR: no upload in operation",eError); + return 0; + } + Arg2Text(argc-2,&argv[2],pLine,1023); + exeBufAppend(self->uploadBuffer,pLine); + return 1; +} +/*--------------------------------------------------------------------*/ +static int uploadSave(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + int status; + + if(SCGetRights(pCon) > usUser){ + SCWrite(pCon,"ERROR: no permission to save buffers",eError); + return 0; + } + if(argc < 3) { + SCWrite(pCon,"ERROR: no file given to save upload buffer to",eError); + return 0; + } + if(self->uploadBuffer == NULL){ + SCWrite(pCon,"ERROR: no upload buffer to save exists",eError); + return 0; + } + status = exeBufSave(self->uploadBuffer,argv[2]); + if(status == 0){ + SCWrite(pCon,"ERROR: failed to save exe buffer, destroyed...",eError); + } + exeBufDelete(self->uploadBuffer); + self->uploadBuffer = NULL; + return status; +} +/*=========================== info ===================================*/ +static void printExeStack(pExeMan self, SConnection *pCon){ + int i, j; + pDynString txt = NULL; + pExeBuf buf; + void *pPtr = NULL; + + txt = CreateDynString(80,80); + if(txt == NULL){ + SCWrite(pCon,"ERROR: failed to allocate memory in printExeStack",eError); + return; + } + for(i = 0; i <= self->exeStackPtr; i++){ + DynarGet(self->exeStack,i,&pPtr); + buf = (pExeBuf)pPtr; + assert(buf); + for(j = 0; j < i; j++){ + DynStringConcat(txt," "); + } + DynStringConcat(txt,exeBufName(buf)); + DynStringConcatChar(txt,'\n'); + } + SCWrite(pCon,GetCharArray(txt),eValue); + DeleteDynString(txt); +} +/*-----------------------------------------------------------------*/ +static int locateBuffer(pExeMan self, char *name){ + int i; + pExeBuf buf; + void *pPtr = NULL; + + for(i = 0; i <= self->exeStackPtr; i++){ + DynarGet(self->exeStack,i,&pPtr); + buf = (pExeBuf)pPtr; + if(strcmp(name,exeBufName(buf)) == 0) { + return i; + } + } + return -1; +} +/*------------------------------------------------------------------*/ +static void printExeRange(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + int start, end, lineno, bufNo; + pExeBuf buf; + void *pPtr = NULL; + char pBueffel[256]; + + if(argc > 3) { + bufNo = locateBuffer(self,argv[3]); + } else { + bufNo = self->exeStackPtr; + } + if(bufNo < 0){ + SCWrite(pCon,"ERROR: named buffer not found",eError); + return; + } + DynarGet(self->exeStack,bufNo,&pPtr); + buf = (pExeBuf)pPtr; + assert(buf); + exeBufRange(buf,&start,&end,&lineno); + snprintf(pBueffel,255,"%s.range = %d = %d = %d",exeBufName(buf), + start,end,lineno); + SCWrite(pCon,pBueffel,eValue); +} +/*------------------------------------------------------------------*/ +static void printExeText(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + int start, end, lineno, bufNo; + pExeBuf buf; + void *pPtr = NULL; + pDynString txt; + + if(argc > 3) { + bufNo = locateBuffer(self,argv[3]); + } else { + bufNo = self->exeStackPtr; + } + if(bufNo < 0){ + SCWrite(pCon,"ERROR: named buffer not found",eError); + return; + } + DynarGet(self->exeStack,bufNo,&pPtr); + buf = (pExeBuf)pPtr; + assert(buf); + exeBufRange(buf,&start,&end,&lineno); + txt = exeBufText(buf,start,end); + if(txt != NULL){ + SCWrite(pCon,GetCharArray(txt),eValue); + DeleteDynString(txt); + } else { + SCWrite(pCon,"ERROR: failed to allocate text buffer for operation",eError); + } +} +/*------------------------------------------------------------------*/ +static void printQueue(pExeMan self, SConnection *pCon){ + pExeBuf buf= NULL; + pDynString text = NULL; + int status; + + text = CreateDynString(80,80); + if(text == NULL){ + SCWrite(pCon,"ERROR: out of memory",eError); + return; + } + + status = LLDnodePtr2First(self->runList); + while(status != 0) { + LLDnodeDataTo(self->runList,&buf); + if(buf != NULL){ + DynStringConcat(text,exeBufName(buf)); + DynStringConcatChar(text,'\n'); + } + status = LLDnodePtr2Next(self->runList); + } + SCWrite(pCon,GetCharArray(text),eValue); + DeleteDynString(text); +} +/*-------------------------------------------------------------------*/ +static int infoHandler(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + char pBueffel[256]; + pExeBuf buf; + void *pPtr = NULL; + + if(self->exeStackPtr < 0){ + SCWrite(pCon,"Idle",eValue); + return 1; + } + + if(argc < 3){ + if(self->exeStackPtr >= 0){ + DynarGet(self->exeStack,self->exeStackPtr,&pPtr); + buf = (pExeBuf)pPtr; + if(buf != NULL){ + snprintf(pBueffel,255,"Executing %s",exeBufName(buf)); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + } else { + strtolower(argv[2]); + if(strcmp(argv[2],"stack") == 0){ + printExeStack(self,pCon); + return 1; + } else if(strcmp(argv[2],"range") == 0){ + printExeRange(self,pCon,argc,argv); + return 1; + } else if(strcmp(argv[2],"text") == 0){ + printExeText(self,pCon,argc,argv); + return 1; + } else { + SCWrite(pCon,"ERROR: subcommand to info unknown",eError); + } + } +} +/*=========================== print ==================================*/ +static int printBuffer(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + pDynString filePath = NULL; + char pLine[512]; + FILE *fd = NULL; + + if(argc < 3){ + SCWrite(pCon,"ERROR: argument required for exe print",eError); + return 0; + } + filePath = locateBatchBuffer(self,argv[2]); + if(filePath == NULL){ + snprintf(pLine,255,"ERROR: batch buffer %s not found in path", + argv[2]); + SCWrite(pCon,pLine,eError); + return 0; + } + + fd = fopen(GetCharArray(filePath),"r"); + if(fd == NULL){ + SCWrite(pCon,"ERROR: failed to open file for printing",eError); + DeleteDynString(filePath); + return 0; + } + while(fgets(pLine,511,fd) != NULL){ + SCWrite(pCon,pLine,eValue); + } + fclose(fd); + DeleteDynString(filePath); + return 1; +} +/*========================== run stack ===============================*/ +static int enqueueBuffer(pExeMan self, SConnection *pCon, + int argc, char *argv[]){ + pExeBuf buf = NULL; + int status; + pDynString filePath = NULL; + + if(SCGetRights(pCon) > usUser){ + SCWrite(pCon,"ERROR: no permission to enque buffers",eError); + return 0; + } + if(argc < 3) { + SCWrite(pCon,"ERROR: no buffer file given to enqueue ",eError); + return 0; + } + + filePath = locateBatchBuffer(self,argv[2]); + if(filePath == NULL){ + SCWrite(pCon,"ERROR: failed to locate buffer to enqueue",eError); + return 0; + } + + buf = exeBufCreate("enqueue"); + if(buf == NULL){ + SCWrite(pCon,"ERROR: out of memory",eError); + return NULL; + } + status = exeBufLoad(buf,GetCharArray(filePath)); + DeleteDynString(filePath); + if(status != 1) { + SCWrite(pCon,"ERROR: failed to load buffer",eError); + return 0; + } + LLDnodeAppendFrom(self->runList,&buf); + return 1; +} +/*--------------------------------------------------------------------*/ +static void clearQueue(pExeMan self){ + pExeBuf buf = NULL; + int status; + + status = LLDnodePtr2First(self->runList); + while(status != 0) { + LLDnodeDataTo(self->runList,&buf); + if(buf != NULL){ + exeBufDelete(buf); + } + LLDnodeDelete(self->runList); + status = LLDnodePtr2Next(self->runList); + } + /* + A second time round. This is a workaround for some + dodgy behaviour of the list system. + */ + status = LLDnodePtr2First(self->runList); + while(status != 0) { + LLDnodeDataTo(self->runList,&buf); + if(buf != NULL){ + exeBufDelete(buf); + } + LLDnodeDelete(self->runList); + status = LLDnodePtr2Next(self->runList); + } +} +/*--------------------------------------------------------------------*/ +static int execQueue(pExeMan self, SConnection *pCon, SicsInterp *pSics){ + pExeBuf buf = NULL; + int status; + + if(self->exeStackPtr >= 0){ + SCWrite(pCon, + "ERROR: cannot start queue while batch buffers are still running",eError); + return 0; + } + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + while(LLDnodePtr2First(self->runList) != 0){ + LLDnodeDataTo(self->runList,&buf); + LLDnodeDelete(self->runList); + self->exeStackPtr++; + if(buf == NULL){ + SCWrite(pCon, + "ERROR: serious trouble, buffer not in queue, inform programmer",eError); + return 0; + } + DynarPut(self->exeStack,self->exeStackPtr,buf); + status = exeBufProcess(buf,pSics,pCon,self->pCall); + self->exeStackPtr--; + if(SCGetInterrupt(pCon) >= eAbortBatch){ + SCWrite(pCon,"ERROR: queue processing interrupted",eError); + return 0; + } + } + return 1; +} +/*========================== interpreter action =======================*/ +int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pExeMan self = NULL; + char pBufferName[256]; + int status; + + self = (pExeMan)pData; + assert(self != NULL); + + strncpy(pBufferName,argv[1],255); + if(argc > 1){ + strtolower(argv[1]); + status = handleBatchPath(self,pCon,argc,argv); + if(status >= 0){ + return status; + } + if(strcmp(argv[1],"interest") == 0){ + registerCallbacks(pCon,pSics,self); + SCSendOK(pCon); + return 1; + } else if(strcmp(argv[1],"uninterest") == 0){ + unregisterCallbacks(pCon,self); + SCSendOK(pCon); + return 1; + }else if(strcmp(argv[1],"upload") == 0){ + status = startUpload(self,pCon); + if(status){ + SCSendOK(pCon); + } + return status; + }else if(strcmp(argv[1],"append") == 0){ + status = appendLine(self,pCon,argc,argv); + if(status){ + SCSendOK(pCon); + } + return status; + }else if(strcmp(argv[1],"save") == 0){ + status = uploadSave(self,pCon,argc,argv); + if(status){ + SCSendOK(pCon); + } + 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); + return status; + }else if(strcmp(argv[1],"enqueue") == 0){ + status = enqueueBuffer(self,pCon,argc,argv); + if(status){ + SCSendOK(pCon); + } + return status; + }else if(strcmp(argv[1],"clear") == 0){ + clearQueue(self); + SCSendOK(pCon); + return 1; + }else if(strcmp(argv[1],"queue") == 0){ + printQueue(self,pCon); + SCSendOK(pCon); + return 1; + }else if(strcmp(argv[1],"run") == 0){ + status = execQueue(self,pCon,pSics); + if(status){ + SCSendOK(pCon); + } + return status; + } else { + return runBatchBuffer(self,pCon,pSics,pBufferName); + } + } else { + SCWrite(pCon,"ERROR: need argument to manage batch buffers",eError); + return 0; + } + return 1; +} diff --git a/exeman.h b/exeman.h new file mode 100644 index 00000000..5ebbbfc8 --- /dev/null +++ b/exeman.h @@ -0,0 +1,17 @@ + +/** + * The batch buffer manager module. For more information see exe.tex. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, November 2004 +*/ +#ifndef EXEMAN +#define EXEMAN + +int MakeExeManager(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif diff --git a/fitcenter.c b/fitcenter.c index d05fdb99..555403ba 100644 --- a/fitcenter.c +++ b/fitcenter.c @@ -109,13 +109,9 @@ pMot = FindMotor(pServ->pSics,self->pName); if(pMot) { - i = MotorGetPar(pMot,"softzero",&fZero); - i = MotorGetPar(pMot,"sign",&fSign); - assert(i); for(i = 0; i < self->iNP; i++) { - self->fAxis[i] -= fZero; - self->fAxis[i] *= fSign; + self->fAxis[i] = MotorHardToSoftPosition(pMot,self->fAxis[i]); } } } @@ -349,7 +345,8 @@ SCWrite(pCon,"Driving to center done",eStatus); break; default: - SCWrite(pCon,"WARNING: driving to center finished with problems", + SCWrite(pCon, + "WARNING: driving to center finished with problems", eWarning); break; @@ -370,7 +367,8 @@ if(argc < 2) { - SCWrite(pCon,"ERROR: MakeFit expected the name of a scan command as a parameter", + SCWrite(pCon, + "ERROR: MakeFit expected the name of a scan command as a parameter", eError); return 0; } @@ -408,7 +406,8 @@ iRet1 = AddCommand(pSics,"center",CenterWrapper,NULL,self); if(!iRet || !iRet1) { - sprintf(pBueffel,"ERROR: duplicate commands peak and center not created",argv[2]); + sprintf(pBueffel, + "ERROR: duplicate commands peak and center not created",argv[2]); SCWrite(pCon,pBueffel,eError); DeleteFitCenter((void *)self); return 0; @@ -435,11 +434,15 @@ break; case -1: SCWrite(pCon,"WARNING: could not find left hand half width",eWarning); - SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning); + SCWrite(pCon, + "Fit Results most certainly dodgy, SICS suggests measuring a full peak", + eWarning); break; case -2: SCWrite(pCon,"WARNING: could not find right hand half width",eError); - SCWrite(pCon,"Fit Results most certainly dodgy, SICS suggests measuring a full peak",eWarning); + SCWrite(pCon, + "Fit Results most certainly dodgy, SICS suggests measuring a full peak", + eWarning); break; case -3: SCWrite(pCon,"ERROR: No counts found in Fit!",eError); diff --git a/hkl.c b/hkl.c index 5144cf61..f70e5375 100644 --- a/hkl.c +++ b/hkl.c @@ -35,10 +35,7 @@ #include "hkl.h" #include "hkl.i" #include "splitter.h" -/* - the space we leave in omega in order to allow for a scan to be done -*/ -#define SCANBORDER 3. + /* the tolerance in chi we give before we allow to fix omega with phi */ @@ -62,6 +59,7 @@ self->fUB[0], self->fUB[1], self->fUB[2], self->fUB[3], self->fUB[4], self->fUB[5], self->fUB[6], self->fUB[7], self->fUB[8]); fprintf(fd,"%s hm %d\n",name, self->iHM); + fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance); return 1; } @@ -106,6 +104,7 @@ pNew->fUB[4] = 1.; pNew->fUB[8] = 1.; pNew->UBinv = NULL; + pNew->scanTolerance = 2.5; return pNew; } @@ -433,12 +432,12 @@ static int checkBisecting(pHKL self, a omega scan */ MotorGetPar(self->pOmega,"softlowerlim",&fLimit); - if((float)om < fLimit + SCANBORDER){ + if((float)om < fLimit + self->scanTolerance){ iTest = 0; } else { iTest = 1; MotorGetPar(self->pOmega,"softupperlim",&fLimit); - if((float)om > fLimit - SCANBORDER){ + if((float)om > fLimit - self->scanTolerance){ iTest = 0; } else { iTest = 1; @@ -512,11 +511,11 @@ static int tryOmegaTweak(pHKL self, MATRIX z1, double *stt, double *om, omTarget = -9999; MotorGetPar(self->pOmega,"softlowerlim",&fLower); MotorGetPar(self->pOmega,"softupperlim",&fUpper); - if(*om < fLower + SCANBORDER) { - omTarget = fLower + SCANBORDER + .5; + if(*om < fLower + self->scanTolerance) { + omTarget = fLower + self->scanTolerance; } - if(*om > fUpper - SCANBORDER){ - omTarget = fUpper - SCANBORDER - .5; + if(*om > fUpper - self->scanTolerance){ + omTarget = fUpper - self->scanTolerance; } if(omTarget < -7000){ return 0; @@ -1309,6 +1308,9 @@ ente: sprintf(pBueffel,"Last HKL: %f %f %f ", self->fLastHKL[0], self->fLastHKL[1],self->fLastHKL[2]); SCWrite(pCon,pBueffel,eValue); + snprintf(pBueffel,510,"%s.scantolerance = %f", argv[0], + self->scanTolerance); + SCWrite(pCon,pBueffel,eValue); return 1; } /*----------- current */ @@ -1370,8 +1372,9 @@ ente: { if(argc < 3) { - SCWrite(pCon,"ERROR: Insufficient number of arguments to HKL lambda",eError); - return 0; + snprintf(pBueffel,132,"%s.lambda = %f", argv[0],self->fLambda); + SCWrite(pCon,pBueffel,eValue); + return 1; } if(!SCMatchRights(pCon,usUser)) { @@ -1393,6 +1396,16 @@ ente: SCSendOK(pCon); return 1; } +/*------------- getub*/ + else if(strcmp(argv[1],"getub") == 0) + { + snprintf(pBueffel,510,"%s.ub = %f %f %f %f %f %f %f %f %f", + argv[0], self->fUB[0], self->fUB[1], self->fUB[2], + self->fUB[3], self->fUB[4], self->fUB[5], + self->fUB[6], self->fUB[7], self->fUB[8]); + SCWrite(pCon,pBueffel,eValue); + return 1; + } /*------- lambdavar*/ else if(strcmp(argv[1],"lambdavar") == 0) { @@ -1547,6 +1560,30 @@ ente: SCSendOK(pCon); return 1; } +/*------------- scantolerance */ + else if(strcmp(argv[1],"scantolerance") == 0) + { + if(argc < 3) + { + snprintf(pBueffel,510,"%s.scantolerance = %f",argv[0], + self->scanTolerance); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + if(!SCMatchRights(pCon,usUser)) + { + return 0; + } + if(!isNumeric(argv[2])) + { + sprintf(pBueffel,"ERROR: %s was not recognized as a number", argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self->scanTolerance = atof(argv[2]); + SCSendOK(pCon); + return 1; + } /*------------- calculate */ else if(strcmp(argv[1],"calc") == 0) { diff --git a/hkl.i b/hkl.i index 25ae78c0..c1a716e8 100644 --- a/hkl.i +++ b/hkl.i @@ -24,6 +24,7 @@ pMotor pNu; pSelVar pMono; long lID; + float scanTolerance; } HKL; diff --git a/hkl.tex b/hkl.tex index 936f563c..62d1b0ad 100644 --- a/hkl.tex +++ b/hkl.tex @@ -32,6 +32,7 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ pMotor pNu;@\\ \mbox{}\verb@ pSelVar pMono;@\\ \mbox{}\verb@ long lID;@\\ +\mbox{}\verb@ float scanTolerance;@\\ \mbox{}\verb@ } HKL;@\\ \mbox{}\verb@@$\diamond$ \end{list} @@ -61,7 +62,9 @@ checking. \item[pPhi] the phi axis motor. \item[pNu] the nu axis motor for normal beam geometry. This is detector tilt. -\item[pMono] The selector variable doing the wavelength. +\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. \end{description} The wavelength is a bit tricky. As it would be to time consuming to read two diff --git a/hkl.w b/hkl.w index a87ab57f..bd5888ff 100644 --- a/hkl.w +++ b/hkl.w @@ -27,6 +27,7 @@ The object uses the following object data structure: pMotor pNu; pSelVar pMono; long lID; + float scanTolerance; } HKL; @} @@ -49,7 +50,9 @@ checking. \item[pPhi] the phi axis motor. \item[pNu] the nu axis motor for normal beam geometry. This is detector tilt. -\item[pMono] The selector variable doing the wavelength. +\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. \end{description} The wavelength is a bit tricky. As it would be to time consuming to read two diff --git a/lld.c b/lld.c index 4847ae85..2390477b 100644 --- a/lld.c +++ b/lld.c @@ -647,6 +647,11 @@ long LLDnodeLong( int List ) return *((long *) &ListControl[ List ].current->data ); } +float LLDnodeFloat( int List ) +{ + return *((float *) &ListControl[ List ].current->data ); +} + void * LLDnodePtr( int List ) { return *((void **) &ListControl[ List ].current->data ); diff --git a/lld.h b/lld.h index 1bfffd45..c6c6d535 100644 --- a/lld.h +++ b/lld.h @@ -120,6 +120,7 @@ int LLDnodePtr2Prev( int List ); */ int LLDnodeInt( int List ); long LLDnodeLong( int List ); +float LLDnodeFloat( int List ); void * LLDnodePtr( int List ); void FAR * LLDnodeFptr( int List ); diff --git a/macro.c b/macro.c index 7c6a34f5..fea5423c 100644 --- a/macro.c +++ b/macro.c @@ -1,6 +1,6 @@ /*-------------------------------------------------------------------------- - All you need to evaluate macros with SICS. + All you need to evaluate macros with SICS The implmentation for the macro stuff is complex and non intuitive. This is the price to pay for adding the extremly powerful and @@ -138,6 +138,7 @@ pSinter = pSics->pInter; pCon = pSics->pCon[pSics->iStack]; lastCommand = pSics->lastUnknown[pSics->iStack]; + pCon->sicsError = 0; assert(pSinter); assert(pCon); @@ -200,6 +201,7 @@ else { Tcl_SetVar(pInter,SICSERROR,"yes",TCL_GLOBAL_ONLY); + pCon->sicsError = 1; return TCL_ERROR; } } @@ -948,7 +950,6 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, SCWrite(pCon,pStart,eError); } iRet = InterpExecute(pSics,pCon,pCommand); - SicsWait(1); SCWrite(pCon,"TRANSACTIONFINISHED",eError); return iRet; } diff --git a/make_gen b/make_gen index 23c82091..edcc7ab5 100644 --- a/make_gen +++ b/make_gen @@ -22,12 +22,12 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ scan.o fitcenter.o telnet.o token.o wwildcard.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\ + rmtrail.o help.o nxupdate.o confvirtualmot.o \ simchop.o choco.o chadapter.o trim.o scaldate.o \ - hklscan.o xytable.o \ + hklscan.o xytable.o exebuf.o exeman.o\ circular.o maximize.o sicscron.o \ d_sign.o d_mod.o tcldrivable.o \ - synchronize.o definealias.o \ + synchronize.o definealias.o oscillate.o \ hmcontrol.o userscan.o rs232controller.o lomax.o \ fourlib.o motreg.o motreglist.o anticollider.o \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) \ diff --git a/makefile_linux b/makefile_linux index 1a64f442..5abee31c 100644 --- a/makefile_linux +++ b/makefile_linux @@ -6,9 +6,9 @@ # Markus Zolliker, March 2003 #========================================================================== # assign if the National Instrument GPIB driver is available -#NI= -DHAVENI -#NIOBJ= nigpib.o -#NILIB=$(SINQDIR)/linux/lib/cib.o +NI= -DHAVENI +NIOBJ= nigpib.o +NILIB=$(SINQDIR)/linux/lib/cib.o # The variable SRC is needed for the case, where source and objects are # separated. In the case where objects are mixed up with sources, SRC diff --git a/mesure.c b/mesure.c index 9c826efd..98a10541 100644 --- a/mesure.c +++ b/mesure.c @@ -26,14 +26,11 @@ #include "evcontroller.h" #include "mesure.h" #include "nxscript.h" +#include "lld.h" extern void SNXFormatTime(char *pBueffel, int iLen); #define ANGERR 0.2 -/* nxutil.h - */ - - /* #define MESSDEBUG 1 @@ -71,7 +68,16 @@ float fPosition[4]; /* the real positions after driving */ int iCompact; /* true if compact scan ouput. */ int psiMode; /* 1 for psi scan mode, 0 else */ + int stepList; /* a list of stepwidth ranges */ } Mesure; +/*--------------------------------------------------------------------- + Entries for the stepwidth range list + ----------------------------------------------------------------------*/ +typedef struct { + float start; + float end; + float stepWidth; +}StepEntry; /*--------------------------------------------------------------------------*/ pMesure CreateMesure(pHKL pCryst, pScanData pScanner, pMotor pOmega, char *pOm, char *po2t, char *pFileRoot, @@ -121,6 +127,7 @@ pNew->lCounts = (long *)malloc(90*sizeof(long)); #endif pNew->lCounts = (long *)malloc(50*sizeof(long)); + pNew->stepList = LLDcreate(sizeof(StepEntry)); return pNew; } /*------------------------------------------------------------------------*/ @@ -150,6 +157,7 @@ MesureClose(self); if(self->lCounts) free(self->lCounts); + LLDdelete(self->stepList); free(self); } /*------------------------------------------------------------------------*/ @@ -351,12 +359,46 @@ return 1; } +/*------------------------------------------------------------------------*/ +static void addStepRange(pMesure self, float start, float end, float step) +{ + StepEntry se; + assert(self != NULL); + + se.start = start; + se.end = end; + se.stepWidth = step; + LLDnodeAppendFrom(self->stepList,&se); +} +/*------------------------------------------------------------------------*/ +static float determineStepWidth(pMesure self, float two_theta) +{ + float stepWidth; + StepEntry se; + int iRet; + + assert(self != NULL); + + stepWidth = self->fStep; + iRet = LLDnodePtr2First(self->stepList); + while(iRet != 0) + { + LLDnodeDataTo(self->stepList,&se); + if(two_theta > se.start && two_theta < se.end) + { + stepWidth = se.stepWidth; + break; + } + iRet = LLDnodePtr2Next(self->stepList); + } + return stepWidth; +} /*--------------------------------------------------------------------------*/ int MesureReflection(pMesure self, float fHKL[3], float fPsi, SConnection *pCon) { int iRet, i; - float fStart; + float fStart, stepWidth; float fDelta, fSet[4]; char pBueffel[132]; @@ -402,19 +444,25 @@ { return iRet; } - fStart -= (self->np/2)*self->fStep; + stepWidth = determineStepWidth(self,self->fPosition[0]); + if(stepWidth != self->fStep) + { + snprintf(pBueffel,130,"Using stepwidth %f",stepWidth); + SCWrite(pCon,pBueffel,eWarning); + } + fStart -= (self->np/2)*stepWidth; /* set the scan up */ ClearScanVar(self->pScanner); if(self->iMode == 0) { AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega, - fStart, self->fStep); + fStart, stepWidth); } else { AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T, - fStart, self->fStep); + fStart, stepWidth); } /* do the scan */ @@ -435,7 +483,7 @@ { int iRet, i; - float fStart, fDelta; + float fStart, fDelta, stepWidth; char pBueffel[132]; assert(self); @@ -479,19 +527,25 @@ { return iRet; } - fStart -= (self->np/2)*self->fStep; - + stepWidth = determineStepWidth(self,self->fPosition[0]); + if(stepWidth != self->fStep) + { + snprintf(pBueffel,130,"Using stepwidth %f",stepWidth); + SCWrite(pCon,pBueffel,eWarning); + } + fStart -= (self->np/2)*stepWidth; + /* set the scan up */ ClearScanVar(self->pScanner); if(self->iMode == 0) { AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega, - fStart, self->fStep); + fStart, stepWidth); } else { AddScanVar(self->pScanner, pServ->pSics,pCon,self->pO2T, - fStart, self->fStep); + fStart, stepWidth); } /* do the scan */ @@ -1142,7 +1196,7 @@ char pBueffel[1024]; pMesure self = NULL; double d; - float fVal, fHKL[3]; + float fVal, fHKL[3], start, end, step; self = (pMesure)pData; assert(self); @@ -1389,6 +1443,55 @@ return 1; } } + else if(strcmp(argv[1],"addrange") == 0) + { + if(argc < 5) + { + SCWrite(pCon,"ERROR: not enough arguments to addrange",eError); + return 0; + } + if(!SCMatchRights(pCon,usUser)) + { + return 0; + } + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&d); + if(iRet != TCL_OK) + { + snprintf(pBueffel,131, + "ERROR: expected numeric value but got %s",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + start = (float)d; + iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&d); + if(iRet != TCL_OK) + { + snprintf(pBueffel,131, + "ERROR: expected numeric value but got %s",argv[3]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + end = (float)d; + iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&d); + if(iRet != TCL_OK) + { + snprintf(pBueffel,131, + "ERROR: expected numeric value but got %s",argv[4]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + step = (float)d; + addStepRange(self,start,end,step); + SCSendOK(pCon); + return 1; + } + else if(strcmp(argv[1],"clearrange") == 0) + { + LLDdelete(self->stepList); + self->stepList = LLDcreate(sizeof(StepEntry)); + SCSendOK(pCon); + return 1; + } /*------ can be other pars */ else { diff --git a/motor.c b/motor.c index c19f0acd..71c2ce45 100644 --- a/motor.c +++ b/motor.c @@ -271,6 +271,8 @@ static int reportAndFixError(pMotor self, SConnection *pCon) newStatus = statusRunTo(self,pCon); break; case MOTOK: + snprintf(pBueffel,255,"WARNING: %s on %s",pError,self->name); + SCWrite(pCon,pBueffel,eWarning); newStatus = HWIdle; break; default: @@ -954,6 +956,21 @@ extern void KillPiPiezo(void *pData); *fHard = fVal*ObVal(self->ParArray,SIGN); return 0; } +/*------------------------------------------------------------------------*/ + float MotorHardToSoftPosition(pMotor self, float fValue) + { + /* apply zeropoint */ + if(ObVal(self->ParArray,SIGN) < 0.) + { + fValue += ObVal(self->ParArray,SZERO); + } + else + { + fValue -= ObVal(self->ParArray,SZERO); + } + /* apply sign */ + return fValue*ObVal(self->ParArray,SIGN); + } /* ------------------------------------------------------------------------*/ int MotorGetSoftPosition(pMotor self, SConnection *pCon, float *fVal) { @@ -970,7 +987,6 @@ extern void KillPiPiezo(void *pData); *fVal = fValue; return 0; } - /* apply zeropoint */ if(ObVal(self->ParArray,SIGN) < 0.) { @@ -983,7 +999,10 @@ extern void KillPiPiezo(void *pData); *fVal = fValue; /* apply sign */ + /* *fVal = MotorHardToSoftPosition(self,fValue); */ + *fVal = fValue*ObVal(self->ParArray,SIGN); + return 1; } /*---------------------------------------------------------------------------*/ diff --git a/motor.h b/motor.h index 509a3130..f3da109a 100644 --- a/motor.h +++ b/motor.h @@ -46,6 +46,7 @@ /* Where are we ? */ int MotorGetSoftPosition(pMotor self,SConnection *pCon, float *fVal); int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fVal); + float MotorHardToSoftPosition(pMotor self, float fHard); /* creation */ int MotorCreate(SConnection *pCon, SicsInterp *pSics, void *pData, diff --git a/napi.c b/napi.c index 51b91dc8..035325d8 100644 --- a/napi.c +++ b/napi.c @@ -23,13 +23,12 @@ ----------------------------------------------------------------------------*/ -static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /* Revision interted by CVS */ +static const char* rscid = "$Id: napi.c,v 1.8 2004/11/17 10:50:16 cvs Exp $"; /* Revision interted by CVS */ #include #include #include #include -#include "fortify.h" #include "napi.h" /* @@ -71,13 +70,13 @@ static const char* rscid = "$Id: napi.c,v 1.7 2003/05/23 15:06:47 cvs Exp $"; /* /*------------------------------------------------------------------------ HDF-5 cache size special stuff -------------------------------------------------------------------------*/ -static long cacheSize = 1024000; /* 1MB, HDF-5 default */ +long nx_cacheSize = 1024000; /* 1MB, HDF-5 default */ NXstatus CALLING_STYLE NXsetcache(long newVal) { if(newVal > 0) { - cacheSize = newVal; + nx_cacheSize = newVal; return NX_OK; } return NX_ERROR; @@ -98,7 +97,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) /*---------------------------------------------------------------------*/ - void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text)) + NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*NewError)(void *pD, char *text)) { NXpData = pData; NXIReportError = NewError; @@ -126,6 +125,7 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) NXhandle hdf5_handle; NXhandle hdf4_handle; pNexusFunction fHandle; + NXstatus retstat; /* configure fortify iFortifyScope = Fortify_EnterScope(); @@ -165,7 +165,11 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) if (hdf_type==1) { /* HDF4 type */ #ifdef HDF4 - NX4open((const char *)filename,am,&hdf4_handle); + retstat = NX4open((const char *)filename,am,&hdf4_handle); + if(retstat != NX_OK){ + free(fHandle); + return retstat; + } fHandle->pNexusData=hdf4_handle; fHandle->nxclose=NX4close; fHandle->nxflush=NX4flush; @@ -194,13 +198,21 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) fHandle->nxsameID=NX4sameID; fHandle->nxinitgroupdir=NX4initgroupdir; fHandle->nxinitattrdir=NX4initattrdir; -#endif *gHandle = fHandle; - return NX_OK; +#else + NXIReportError (NXpData,"ERROR: Attempt to create HDF4 file when not linked with HDF4"); + *gHandle = NULL; + retstat = NX_ERROR; +#endif /* HDF4 */ + return retstat; } else if (hdf_type==2) { /* HDF5 type */ #ifdef HDF5 - NX5open(filename,am,&hdf5_handle); + retstat = NX5open(filename,am,&hdf5_handle); + if(retstat != NX_OK){ + free(fHandle); + return retstat; + } fHandle->pNexusData=hdf5_handle; fHandle->nxclose=NX5close; fHandle->nxflush=NX5flush; @@ -229,11 +241,16 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) fHandle->nxsameID=NX5sameID; fHandle->nxinitgroupdir=NX5initgroupdir; fHandle->nxinitattrdir=NX5initattrdir; -#endif *gHandle = fHandle; - return NX_OK; +#else + NXIReportError (NXpData,"ERROR: Attempt to create HDF5 file when not linked with HDF5"); + *gHandle = NULL; + retstat = NX_ERROR; +#endif /* HDF5 */ + return retstat; } else { - NXIReportError (NXpData,"ERROR: Format not readable by this NeXus library"); + NXIReportError (NXpData, + "ERROR: Format not readable by this NeXus library"); *gHandle = NULL; return NX_ERROR; } @@ -539,6 +556,229 @@ NXstatus CALLING_STYLE NXsetcache(long newVal) pNexusFunction pFunc = (pNexusFunction)fid; return pFunc->nxinitgroupdir(pFunc->pNexusData); } +/*------------------------------------------------------------------------ + Implementation of NXopenpath. + --------------------------------------------------------------------------*/ +static int isDataSetOpen(NXhandle hfil) +{ + NXlink id; + + /* + This uses the (sensible) feauture that NXgetdataID returns NX_ERROR + when no dataset is open + */ + if(NXgetdataID(hfil,&id) == NX_ERROR) + { + return 0; + } + else + { + return 1; + } +} +/*----------------------------------------------------------------------*/ +static int isRoot(NXhandle hfil) +{ + NXlink id; + + /* + This uses the feauture that NXgetgroupID returns NX_ERROR + when we are at root level + */ + if(NXgetgroupID(hfil,&id) == NX_ERROR) + { + return 1; + } + else + { + return 0; + } +} +/*-------------------------------------------------------------------- + copies the next path element into element. + returns a pointer into path beyond the extracted path + ---------------------------------------------------------------------*/ +static char *extractNextPath(char *path, NXname element) +{ + char *pPtr, *pStart; + int length; + + pPtr = path; + /* + skip over leading / + */ + if(*pPtr == '/') + { + pPtr++; + } + pStart = pPtr; + + /* + find next / + */ + pPtr = strchr(pStart,'/'); + if(pPtr == NULL) + { + /* + this is the last path element + */ + strcpy(element,pStart); + return NULL; + } else { + length = pPtr - pStart; + strncpy(element,pStart,length); + element[length] = '\0'; + } + return pPtr + 1; +} +/*-------------------------------------------------------------------*/ +static NXstatus gotoRoot(NXhandle hfil) +{ + int status; + + if(isDataSetOpen(hfil)) + { + status = NXclosedata(hfil); + if(status == NX_ERROR) + { + return status; + } + } + while(!isRoot(hfil)) + { + status = NXclosegroup(hfil); + if(status == NX_ERROR) + { + return status; + } + } + return NX_OK; +} +/*--------------------------------------------------------------------*/ +static int isRelative(char *path) +{ + if(path[0] == '.' && path[1] == '.') + return 1; + else + return 0; +} +/*------------------------------------------------------------------*/ +static NXstatus moveOneDown(NXhandle hfil) +{ + if(isDataSetOpen(hfil)) + { + return NXclosedata(hfil); + } + else + { + return NXclosegroup(hfil); + } +} +/*------------------------------------------------------------------- + returns a pointer to the remaining path string to move up + --------------------------------------------------------------------*/ +static char *moveDown(NXhandle hfil, char *path, int *code) +{ + int status; + NXname pathElem; + char *pPtr; + + *code = NX_OK; + + if(path[0] == '/') + { + *code = gotoRoot(hfil); + return path; + } + else + { + pPtr = path; + while(isRelative(pPtr)) + { + status = moveOneDown(hfil); + if(status == NX_ERROR) + { + *code = status; + return pPtr; + } + pPtr += 3; + } + return pPtr; + } +} +/*--------------------------------------------------------------------*/ +static NXstatus stepOneUp(NXhandle hfil, char *name) +{ + int status, datatype; + NXname name2, xclass; + char pBueffel[256]; + + /* + catch the case when we are there: i.e. no further stepping + necessary. This can happen with paths like ../ + */ + if(strlen(name) < 1) + { + return NX_OK; + } + + NXinitgroupdir(hfil); + while(NXgetnextentry(hfil,name2,xclass,&datatype) != NX_EOD) + { + + if(strcmp(name2,name) == 0) + { + if(strcmp(xclass,"SDS") == 0) + { + return NXopendata(hfil,name); + } + else + { + return NXopengroup(hfil,name,xclass); + } + } + } + snprintf(pBueffel,255,"ERROR: NXopenpath cannot step into %s",name); + NXIReportError (NXpData, pBueffel); + return NX_ERROR; +} +/*---------------------------------------------------------------------*/ +NXstatus CALLING_STYLE NXopenpath(NXhandle hfil, CONSTCHAR *path) +{ + int status, run = 1; + NXname pathElement; + char *pPtr; + + if(hfil == NULL || path == NULL) + { + NXIReportError(NXpData, + "ERROR: NXopendata needs both a file handle and a path string"); + return NX_ERROR; + } + + pPtr = moveDown(hfil,(char *)path,&status); + if(status != NX_OK) + { + NXIReportError (NXpData, + "ERROR: NXopendata failed to move down in hierarchy"); + return status; + } + + while(run == 1) + { + pPtr = extractNextPath(pPtr, pathElement); + status = stepOneUp(hfil,pathElement); + if(status != NX_OK) + { + return status; + } + if(pPtr == NULL) + { + run = 0; + } + } + return NX_OK; +} /*---------------------------------------------------------------------- F77 - API - Support - Routines ----------------------------------------------------------------------*/ diff --git a/napi.h b/napi.h index 914a9e0f..7e40ac5e 100644 --- a/napi.h +++ b/napi.h @@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA For further information, see + + $Id: napi.h,v 1.7 2004/11/17 10:50:16 cvs Exp $ ----------------------------------------------------------------------------*/ @@ -27,7 +29,7 @@ #define NEXUSAPI /* NeXus HDF45 */ -#define NEXUS_VERSION "2.0.0." /* major.minor.patch */ +#define NEXUS_VERSION "2.1.0" /* major.minor.patch */ #define CONSTCHAR const char @@ -78,6 +80,7 @@ typedef struct { NX_INT32 32 bit integer NX_UINT32 32 bit unsigned integer NX_CHAR 8 bit character + NX_BINARY lump of binary data == NX_UINT8 --------------------------------------------------------------------------*/ @@ -92,6 +95,7 @@ typedef struct { #define NX_INT32 24 #define NX_UINT32 25 #define NX_CHAR 4 +#define NX_BINARY 21 /* Map NeXus compression methods to HDF compression methods */ #define NX_COMP_NONE 100 @@ -141,6 +145,7 @@ typedef struct { # define NXclose MANGLE(nxiclose) # define NXmakegroup MANGLE(nximakegroup) # define NXopengroup MANGLE(nxiopengroup) +# define NXopenpath MANGLE(nxiopenpath) # define NXclosegroup MANGLE(nxiclosegroup) # define NXmakedata MANGLE(nximakedata) # define NXcompmakedata MANGLE(nxicompmakedata) @@ -211,6 +216,7 @@ typedef struct { # define NXflush MANGLE(NXIFLUSH) # define NXmakegroup MANGLE(NXIMAKEGROUP) # define NXopengroup MANGLE(NXIOPENGROUP) +# define NXopenpath MANGLE(NXIOPENPATH) # define NXclosegroup MANGLE(NXICLOSEGROUP) # define NXmakedata MANGLE(NXIMAKEDATA) # define NXcompress MANGLE(NXICOMPRESS) @@ -263,6 +269,8 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXflush(NXhandle* pHandle); NX_EXTERNAL NXstatus CALLING_STYLE NXmakegroup (NXhandle handle, CONSTCHAR *name, char* NXclass); NX_EXTERNAL NXstatus CALLING_STYLE NXopengroup (NXhandle handle, CONSTCHAR *name, char* NXclass); +NX_EXTERNAL NXstatus CALLING_STYLE NXopenpath (NXhandle handle, CONSTCHAR *path); + NX_EXTERNAL NXstatus CALLING_STYLE NXclosegroup(NXhandle handle); NX_EXTERNAL NXstatus CALLING_STYLE NXmakedata (NXhandle handle, CONSTCHAR* label, int datatype, int rank, int dim[]); @@ -301,6 +309,7 @@ NX_EXTERNAL NXstatus CALLING_STYLE NXfree(void** data); A non Nexus standard function to set an error handler */ NX_EXTERNAL void CALLING_STYLE NXMSetError(void *pData, void (*ErrFunc)(void *pD, char *text)); +NX_EXTERNAL void CALLING_STYLE NXNXNXReportError(void *pData,char *text); /* another special function for setting the default cache size for HDF-5 diff --git a/napi5.c b/napi5.c index eff18942..482417c7 100644 --- a/napi5.c +++ b/napi5.c @@ -1,4 +1,3 @@ - /*--------------------------------------------------------------------------- NeXus - Neutron & X-ray Common Data Format @@ -28,6 +27,13 @@ #include #include +/* +#include "napi.h" +#include "napi5.h" +*/ + +extern void *NXpData; + typedef struct __NexusFile5 { struct iStack5 { int *iRefDir; @@ -195,7 +201,7 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); if (am == NXACC_CREATE5) { fapl = H5Pcreate(H5P_FILE_ACCESS); iRet=H5Pget_cache(fapl,&mdc_nelmts,&rdcc_nelmts,&rdcc_nbytes,&rdcc_w0); - rdcc_nbytes=(size_t)cacheSize; + rdcc_nbytes=(size_t)nx_cacheSize; iRet = H5Pset_cache(fapl,mdc_nelmts,rdcc_nelmts,rdcc_nbytes,rdcc_w0); /* setting the close degree is absolutely necessary in HDF5 @@ -211,7 +217,9 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); } else { am1 = H5F_ACC_RDWR; } - pNew->iFID = H5Fopen (filename, am1, H5P_DEFAULT); + fapl = H5Pcreate(H5P_FILE_ACCESS); + H5Pset_fclose_degree(fapl,H5F_CLOSE_STRONG); + pNew->iFID = H5Fopen (filename, am1, fapl); } if (pNew->iFID <= 0) { sprintf (pBuffer, "ERROR: cannot open file: %s", filename); @@ -349,8 +357,8 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); H5Fget_obj_count(pFile->iFID,H5F_OBJ_ALL)); */ iRet = H5Fclose(pFile->iFID); - - /* + + /* Please leave this here, it helps debugging HDF5 resource leakages printf("HDF5 object count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ALL)); @@ -871,8 +879,7 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); iRet = H5Dwrite (pFile->iCurrentD, pFile->iCurrentT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); if (iRet < 0) { - snprintf (pError,511, "ERROR: failure to write data to %s", - pFile->iCurrentLD); + snprintf (pError,511, "ERROR: failure to write data"); NXIReportError (NXpData, pError); return NX_ERROR; } @@ -1072,6 +1079,13 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); pNexusFile5 pFile; pFile = NXI5assert (fid); + + /* + we cannot return ID's when no datset is open + */ + if(pFile->iCurrentD <= 0){ + return NX_ERROR; + } strcpy(sRes->iRef5,pFile->name_ref); strcpy(sRes->iRefd,pFile->iCurrentLD); return NX_OK; @@ -1098,7 +1112,7 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); strcpy(sLink->iTag5,pFile->name_ref); } else { /* group link */ - strcpy(buffer, pFile->name_ref); + strcpy(buffer,pFile->iCurrentLGG); strcat(buffer, sLink->iTag5); strcpy(sLink->iTag5,"/"); strcat(sLink->iTag5,buffer); @@ -1114,9 +1128,6 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); strcat(sLink->iTag5,sLink->iRefd); } status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->iRef5, sLink->iTag5); - if(status < 0){ - return NX_ERROR; - } return NX_OK; } @@ -1273,10 +1284,13 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); if (iRet > 0) { pFile->iStack5[pFile->iStackPtr].iCurrentIDX++; - strcpy(name,op_data.iname); if (op_data.iname != NULL) { + strcpy(name,op_data.iname); free(op_data.iname); - } + } else { + pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; + return NX_EOD; + } if (op_data.type == H5G_GROUP) { strcpy(ph_name,""); @@ -1352,648 +1366,647 @@ NXstatus CALLING_STYLE NX5closegroup (NXhandle fid); *datatype=iPtype; strcpy(nxclass, "SDS"); H5Tclose(atype); - H5Tclose(type); - H5Dclose(grp); - } - return NX_OK; - } - else - { - if (iRet_iNX == 2) { - if (op_data.iname != NULL) { - free(op_data.iname); - } - pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; - return NX_EOD; - } - if (op_data.iname != NULL) { - free(op_data.iname); - } - NXIReportError (NXpData, - "ERROR: Iteration (directory) was not successful"); - return NX_ERROR; - } - } + H5Tclose(type); + H5Dclose(grp); + } + return NX_OK; + } + else + { + if (iRet_iNX == 2) { + if (op_data.iname != NULL) { + free(op_data.iname); + } + pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; + return NX_EOD; + } + if (op_data.iname != NULL) { + free(op_data.iname); + } + NXIReportError (NXpData, + "ERROR: Iteration (directory) was not successful"); + return NX_ERROR; + } + } - /*-------------------------------------------------------------------------*/ + /*-------------------------------------------------------------------------*/ - NXstatus CALLING_STYLE NX5getdata (NXhandle fid, void *data) - { - pNexusFile5 pFile; - int iStart[H5S_MAX_RANK], status; - hid_t data_id, memtype_id, size_id, sign_id; - int dims; + NXstatus CALLING_STYLE NX5getdata (NXhandle fid, void *data) + { + pNexusFile5 pFile; + int iStart[H5S_MAX_RANK], status; + hid_t data_id, memtype_id, size_id, sign_id; + int dims; - pFile = NXI5assert (fid); - /* check if there is an Dataset open */ - if (pFile->iCurrentD == 0) - { + pFile = NXI5assert (fid); + /* check if there is an Dataset open */ + if (pFile->iCurrentD == 0) + { + NXIReportError (NXpData, "ERROR: no Dataset open"); + return NX_ERROR; + } + memset (iStart, 0, H5S_MAX_RANK * sizeof(int)); + /* map datatypes of other plateforms */ + data_id = H5Tget_class(pFile->iCurrentT); + if (data_id==H5T_STRING) + { + dims = H5Tget_size(pFile->iCurrentT); + memtype_id = H5Tcopy(H5T_C_S1); + H5Tset_size(memtype_id, dims); + } + if (data_id==H5T_INTEGER) + { + size_id=H5Tget_size(pFile->iCurrentT); + sign_id=H5Tget_sign(pFile->iCurrentT); + if (size_id==1) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT8; + } else { + memtype_id = H5T_NATIVE_UINT8; + } + } + else if (size_id==2) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT16; + } else { + memtype_id = H5T_NATIVE_UINT16; + } + } + else if (size_id==4) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT32; + } else { + memtype_id = H5T_NATIVE_UINT32; + } + } + } else if (data_id==H5T_FLOAT) + { + size_id=H5Tget_size(pFile->iCurrentT); + if (size_id==4) + { + memtype_id = H5T_NATIVE_FLOAT; + } else if (size_id==8) { + memtype_id = H5T_NATIVE_DOUBLE; + } + } + + /* actually read */ + status = H5Dread (pFile->iCurrentD, memtype_id, + H5S_ALL, H5S_ALL,H5P_DEFAULT, data); + if(data_id == H5T_STRING) + { + H5Tclose(memtype_id); + } + if(status < 0) + { + NXIReportError (NXpData, "ERROR: failed to transfer dataset"); + return NX_ERROR; + + } + return NX_OK; + } + + /*-------------------------------------------------------------------------*/ + + NXstatus CALLING_STYLE NX5getinfo (NXhandle fid, int *rank, int dimension[], int *iType) + { + pNexusFile5 pFile; + int i, iRank, mType, iRet; + hsize_t myDim[H5S_MAX_RANK]; + hid_t data_id,size_id,sign_id; + + pFile = NXI5assert (fid); + /* check if there is an Dataset open */ + if (pFile->iCurrentD == 0) { NXIReportError (NXpData, "ERROR: no Dataset open"); return NX_ERROR; - } - memset (iStart, 0, H5S_MAX_RANK * sizeof(int)); - /* map datatypes of other plateforms */ - data_id = H5Tget_class(pFile->iCurrentT); - if (data_id==H5T_STRING) - { - dims = H5Tget_size(pFile->iCurrentT); - memtype_id = H5Tcopy(H5T_C_S1); - H5Tset_size(memtype_id, dims); - } - if (data_id==H5T_INTEGER) - { + } + + /* read information */ + data_id = H5Tget_class(pFile->iCurrentT); + if (data_id==H5T_STRING) + { + mType=NX_CHAR; + } + if (data_id==H5T_INTEGER) + { size_id=H5Tget_size(pFile->iCurrentT); sign_id=H5Tget_sign(pFile->iCurrentT); if (size_id==1) { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT8; - } else { - memtype_id = H5T_NATIVE_UINT8; - } + if (sign_id==H5T_SGN_2) + { + mType=NX_INT8; + } else { + mType=NX_UINT8; + } } else if (size_id==2) { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT16; - } else { - memtype_id = H5T_NATIVE_UINT16; - } + if (sign_id==H5T_SGN_2) + { + mType=NX_INT16; + } else { + mType=NX_UINT16; + } } else if (size_id==4) { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT32; - } else { - memtype_id = H5T_NATIVE_UINT32; - } + if (sign_id==H5T_SGN_2) + { + mType=NX_INT32; + } else { + mType=NX_UINT32; + } } } else if (data_id==H5T_FLOAT) { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - memtype_id = H5T_NATIVE_FLOAT; - } else if (size_id==8) { - memtype_id = H5T_NATIVE_DOUBLE; - } - } - - /* actually read */ - status = H5Dread (pFile->iCurrentD, memtype_id, - H5S_ALL, H5S_ALL,H5P_DEFAULT, data); - if(data_id == H5T_STRING) - { - H5Tclose(memtype_id); - } - if(status < 0) - { - NXIReportError (NXpData, "ERROR: failed to transfer dataset"); - return NX_ERROR; - - } - return NX_OK; - } - - /*-------------------------------------------------------------------------*/ - - NXstatus CALLING_STYLE NX5getinfo (NXhandle fid, int *rank, int dimension[], int *iType) - { - pNexusFile5 pFile; - int i, iRank, mType, iRet; - hsize_t myDim[H5S_MAX_RANK]; - hid_t data_id,size_id,sign_id; - - pFile = NXI5assert (fid); - /* check if there is an Dataset open */ - if (pFile->iCurrentD == 0) { - NXIReportError (NXpData, "ERROR: no Dataset open"); - return NX_ERROR; - } - - /* read information */ - data_id = H5Tget_class(pFile->iCurrentT); - if (data_id==H5T_STRING) - { - mType=NX_CHAR; - } - if (data_id==H5T_INTEGER) - { - size_id=H5Tget_size(pFile->iCurrentT); - sign_id=H5Tget_sign(pFile->iCurrentT); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT8; - } else { - mType=NX_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT16; - } else { - mType=NX_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - mType=NX_INT32; - } else { - mType=NX_UINT32; - } - } - } else if (data_id==H5T_FLOAT) - { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - mType=NX_FLOAT32; - } - else if (size_id==8) - { - mType=NX_FLOAT64; - } - } - iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); - iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, myDim, NULL); - /* conversion to proper ints for the platform */ - *iType = (int)mType; - if (data_id==H5T_STRING) { - for (i = 0; i < iRank; i++) + size_id=H5Tget_size(pFile->iCurrentT); + if (size_id==4) { - myDim[i] = H5Tget_size(pFile->iCurrentT); - } - } - *rank = (int)iRank; - for (i = 0; i < iRank; i++) - { - dimension[i] = (int)myDim[i]; - } - return NX_OK; - } - - /*-------------------------------------------------------------------------*/ - - NXstatus CALLING_STYLE NX5getslab (NXhandle fid, void *data, int iStart[], int iSize[]) - { - pNexusFile5 pFile; - hssize_t myStart[H5S_MAX_RANK]; - hsize_t mySize[H5S_MAX_RANK]; - hssize_t mStart[H5S_MAX_RANK]; - hid_t memspace, iRet, data_id; - hid_t memtype_id, size_id, sign_id; - char *tmp_data; - char *data1; - int i, dims, iRank, mtype = 0; - - pFile = NXI5assert (fid); - /* check if there is an Dataset open */ - if (pFile->iCurrentD == 0) - { - NXIReportError (NXpData, "ERROR: no Dataset open"); - return NX_ERROR; - } - iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); - for (i = 0; i < iRank; i++) + mType=NX_FLOAT32; + } + else if (size_id==8) { - myStart[i] = (hssize_t)iStart[i]; - mySize[i] = (hsize_t)iSize[i]; - mStart[i] = (hsize_t)0; + mType=NX_FLOAT64; } - data_id = H5Tget_class(pFile->iCurrentT); - if (data_id == H5T_STRING) { - mtype = NX_CHAR; - if (mySize[0] == 1) { - mySize[0] = H5Tget_size(pFile->iCurrentT); - } - tmp_data = (char*) malloc(mySize[0]); - memset(tmp_data,0,sizeof(mySize[0])); - iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, mStart, - NULL, mySize, NULL); - } else { - iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart, - NULL, mySize, NULL); + } + iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); + iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, myDim, NULL); + /* conversion to proper ints for the platform */ + *iType = (int)mType; + if (data_id==H5T_STRING) { + for (i = 0; i < iRank; i++) + { + myDim[i] = H5Tget_size(pFile->iCurrentT); + } + } + *rank = (int)iRank; + for (i = 0; i < iRank; i++) + { + dimension[i] = (int)myDim[i]; } - /* define slab */ - /* deal with HDF errors */ - if (iRet < 0) + return NX_OK; + } + + /*-------------------------------------------------------------------------*/ + + NXstatus CALLING_STYLE NX5getslab (NXhandle fid, void *data, int iStart[], int iSize[]) + { + pNexusFile5 pFile; + hssize_t myStart[H5S_MAX_RANK]; + hsize_t mySize[H5S_MAX_RANK]; + hssize_t mStart[H5S_MAX_RANK]; + hid_t memspace, iRet, data_id; + hid_t memtype_id, size_id, sign_id; + char *tmp_data; + char *data1; + int i, dims, iRank, mtype = 0; + + pFile = NXI5assert (fid); + /* check if there is an Dataset open */ + if (pFile->iCurrentD == 0) { - NXIReportError (NXpData, "ERROR: selecting slab failed"); - return NX_ERROR; + NXIReportError (NXpData, "ERROR: no Dataset open"); + return NX_ERROR; } - - memspace=H5Screate_simple(iRank, mySize, NULL); - iRet = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, mStart, - NULL, mySize, NULL); - if (iRet < 0) - { - NXIReportError (NXpData, "ERROR: Select memspace failed"); - return NX_ERROR; - } - /* map datatypes of other plateforms */ - if (data_id==H5T_STRING) - { - dims = H5Tget_size(pFile->iCurrentT); - memtype_id = H5Tcopy(H5T_C_S1); - H5Tset_size(memtype_id, dims); + iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); + for (i = 0; i < iRank; i++) + { + myStart[i] = (hssize_t)iStart[i]; + mySize[i] = (hsize_t)iSize[i]; + mStart[i] = (hsize_t)0; + } + data_id = H5Tget_class(pFile->iCurrentT); + if (data_id == H5T_STRING) { + mtype = NX_CHAR; + if (mySize[0] == 1) { + mySize[0] = H5Tget_size(pFile->iCurrentT); + } + tmp_data = (char*) malloc(mySize[0]); + memset(tmp_data,0,sizeof(mySize[0])); + iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, mStart, + NULL, mySize, NULL); + } else { + iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart, + NULL, mySize, NULL); } - if (data_id==H5T_INTEGER) - { - size_id=H5Tget_size(pFile->iCurrentT); - sign_id=H5Tget_sign(pFile->iCurrentT); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT8; - } else { - memtype_id = H5T_NATIVE_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT16; - } else { - memtype_id = H5T_NATIVE_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - memtype_id = H5T_NATIVE_INT32; - } else { - memtype_id = H5T_NATIVE_UINT32; - } - } - } else if (data_id==H5T_FLOAT) - { - size_id=H5Tget_size(pFile->iCurrentT); - if (size_id==4) - { - memtype_id = H5T_NATIVE_FLOAT; - } else if (size_id==8) { - memtype_id = H5T_NATIVE_DOUBLE; - } - } - - /* read slab */ - if (mtype == NX_CHAR) { - iRet = H5Dread(pFile->iCurrentD, memtype_id, H5S_ALL, - H5S_ALL, H5P_DEFAULT,tmp_data); - data1 = tmp_data + myStart[0]; - strncpy(data,data1,(hsize_t)iSize[0]); - free(tmp_data); - } else { - iRet = H5Dread(pFile->iCurrentD, memtype_id, memspace, - pFile->iCurrentS, H5P_DEFAULT,data); - } - - if (iRet < 0) + /* define slab */ + /* deal with HDF errors */ + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: selecting slab failed"); + return NX_ERROR; + } + + memspace=H5Screate_simple(iRank, mySize, NULL); + iRet = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, mStart, + NULL, mySize, NULL); + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: Select memspace failed"); + return NX_ERROR; + } + /* map datatypes of other plateforms */ + if (data_id==H5T_STRING) { - NXIReportError (NXpData, "ERROR: Reading slab failed"); - return NX_ERROR; + dims = H5Tget_size(pFile->iCurrentT); + memtype_id = H5Tcopy(H5T_C_S1); + H5Tset_size(memtype_id, dims); + } + if (data_id==H5T_INTEGER) + { + size_id=H5Tget_size(pFile->iCurrentT); + sign_id=H5Tget_sign(pFile->iCurrentT); + if (size_id==1) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT8; + } else { + memtype_id = H5T_NATIVE_UINT8; + } + } + else if (size_id==2) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT16; + } else { + memtype_id = H5T_NATIVE_UINT16; + } + } + else if (size_id==4) + { + if (sign_id==H5T_SGN_2) + { + memtype_id = H5T_NATIVE_INT32; + } else { + memtype_id = H5T_NATIVE_UINT32; + } + } + } else if (data_id==H5T_FLOAT) + { + size_id=H5Tget_size(pFile->iCurrentT); + if (size_id==4) + { + memtype_id = H5T_NATIVE_FLOAT; + } else if (size_id==8) { + memtype_id = H5T_NATIVE_DOUBLE; + } + } + + /* read slab */ + if (mtype == NX_CHAR) { + iRet = H5Dread(pFile->iCurrentD, memtype_id, H5S_ALL, + H5S_ALL, H5P_DEFAULT,tmp_data); + data1 = tmp_data + myStart[0]; + strncpy(data,data1,(hsize_t)iSize[0]); + free(tmp_data); + } else { + iRet = H5Dread(pFile->iCurrentD, memtype_id, memspace, + pFile->iCurrentS, H5P_DEFAULT,data); + } + + if (iRet < 0) + { + NXIReportError (NXpData, "ERROR: Reading slab failed"); + return NX_ERROR; + } + return NX_OK; + } + + /*-------------------------------------------------------------------------*/ + + /* Operator function. */ + + herr_t attr_info(hid_t loc_id, const char *name, void *opdata) + { + *((char**)opdata)=strdup(name); + return 1; + } + + NXstatus CALLING_STYLE NX5getnextattr (NXhandle fileid, NXname pName, + int *iLength, int *iType) + { + pNexusFile5 pFile; + hid_t attr_id,size_id,sign_id; + hid_t iRet, atype, aspace; + int iPType,rank; + char *iname = NULL; + unsigned int idx; + int intern_idx=-1; + + pFile = NXI5assert (fileid); + idx=pFile->iAtt5.iCurrentIDX; + iRet=0; + if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) + { + /* global attribute */ + pFile->iVID=H5Gopen(pFile->iFID,"/"); + intern_idx=H5Aget_num_attrs(pFile->iVID); + if (intern_idx > idx) { + iRet=H5Aiterate(pFile->iVID,&idx,attr_info,&iname); + } + else + { + iRet=0; + } + intern_idx=-1; + if (iRet < 0) { + NXIReportError (NXpData, "ERROR iterating through ROOT Attr. list!"); + return NX_ERROR; + } + } else { + intern_idx=H5Aget_num_attrs(pFile->iCurrentD); + if (intern_idx > idx) { + iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); + } + else + { + iRet=0; + } + intern_idx=-1; + if (iRet < 0) { + NXIReportError (NXpData, "ERROR iterating through Attr. list!"); + return NX_ERROR; + } + } + if (iRet>0) + { + pFile->iAtt5.iCurrentIDX++; + strcpy(pName, iname); + if (iname != NULL) { + free(iname); + } + if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) { + /* global attribute */ + pFile->iCurrentA = H5Aopen_name(pFile->iVID, pName); + } else { + pFile->iCurrentA = H5Aopen_name(pFile->iCurrentD, pName); + } + atype = H5Aget_type(pFile->iCurrentA); + aspace = H5Aget_space(pFile->iCurrentA); + rank = H5Sget_simple_extent_ndims(aspace); + attr_id = H5Tget_class(atype); + if (attr_id==H5T_STRING) { + iPType=NX_CHAR; + rank = H5Tget_size(atype); + } + if (rank == 0) { + rank++; + } + if (attr_id==H5T_INTEGER) + { + size_id=H5Tget_size(atype); + sign_id=H5Tget_sign(atype); + if (size_id==1) + { + if (sign_id==H5T_SGN_2) + { + iPType=NX_INT8; + } else { + iPType=NX_UINT8; + } + } + else if (size_id==2) + { + if (sign_id==H5T_SGN_2) + { + iPType=NX_INT16; + } else { + iPType=NX_UINT16; + } + } + else if (size_id==4) + { + if (sign_id==H5T_SGN_2) + { + iPType=NX_INT32; + } else { + iPType=NX_UINT32; + } + } + } else if (attr_id==H5T_FLOAT) + { + size_id=H5Tget_size(atype); + if (size_id==4) + { + iPType=NX_FLOAT32; + } + else if (size_id==8) + { + iPType=NX_FLOAT64; + } + } + *iType=iPType; + *iLength=rank; + H5Tclose(atype); + H5Sclose(aspace); + H5Aclose(pFile->iCurrentA); + return NX_OK; + } + else + { + if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) + { + /* global attribute */ + intern_idx=H5Aget_num_attrs(pFile->iVID); + } else { + if (pFile->iCurrentD>0){ + intern_idx=H5Aget_num_attrs(pFile->iCurrentD); + } else { + intern_idx=H5Aget_num_attrs(pFile->iCurrentG); + } + } + if ((intern_idx == 0)||(intern_idx == idx)) { + pFile->iAtt5.iCurrentIDX = 0; + if (iname != NULL) { + free(iname); + } + return NX_EOD; + } + NXIReportError (NXpData, + "ERROR: Iteration was not successful"); + return NX_ERROR; + } + } + + + + /*-------------------------------------------------------------------------*/ + + NXstatus CALLING_STYLE NX5getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) + { + pNexusFile5 pFile; + int iNew, iRet; + hid_t type, atype, glob; + char pBuffer[256]; + + pFile = NXI5assert (fid); + type = *iType; + glob = 0; + if (type == NX_CHAR) + { + type=H5T_C_S1; + } + else if (type == NX_INT8) + { + type=H5T_NATIVE_CHAR; + } + else if (type == NX_UINT8) + { + type=H5T_NATIVE_UCHAR; + } + else if (type == NX_INT16) + { + type=H5T_NATIVE_SHORT; + } + else if (type == NX_UINT16) + { + type=H5T_NATIVE_USHORT; + } + else if (type == NX_INT32) + { + type=H5T_NATIVE_INT; + } + else if (type == NX_UINT32) + { + type=H5T_NATIVE_UINT; + } + else if (type == NX_FLOAT32) + { + type=H5T_NATIVE_FLOAT; + } + else if (type == NX_FLOAT64) + { + type=H5T_NATIVE_DOUBLE; + } + /* find attribute */ + if (pFile->iCurrentD != 0) + { + /* Dataset attribute */ + iNew = H5Aopen_name(pFile->iCurrentD, name); + } + else + { + /* globale and group attributes */ + if (pFile->iCurrentG != 0) { + /* group attribute */ + iNew = H5Aopen_name(pFile->iCurrentG, name); + } else { + /* global attributes */ + glob=H5Gopen(pFile->iFID,"/"); + iNew = H5Aopen_name(glob, name); + } + } + if (iNew < 0) { + sprintf (pBuffer, "ERROR: attribute %s not found", name); + NXIReportError (NXpData, pBuffer); + return NX_ERROR; + } + pFile->iCurrentA = iNew; + /* finally read the data */ + if (type==H5T_C_S1) + { + atype=H5Tcopy(type); + H5Tset_size(atype,*datalen); + iRet = H5Aread(pFile->iCurrentA, atype, data); + *datalen=strlen(data); + } else { + iRet = H5Aread(pFile->iCurrentA, type, data); + *datalen=1; + } + + if (iRet < 0) { + sprintf (pBuffer, "ERROR: HDF could not read attribute data"); + NXIReportError (NXpData, pBuffer); + return NX_ERROR; + } + + iRet = H5Aclose(pFile->iCurrentA); + if (glob > 0) + { + H5Gclose(glob); + } + if (type==H5T_C_S1) + { + H5Tclose(atype); + } + return NX_OK; + } + + /*-------------------------------------------------------------------------*/ + + NXstatus CALLING_STYLE NX5getattrinfo (NXhandle fid, int *iN) + { + pNexusFile5 pFile; + char *iname = NULL; + unsigned int idx; + herr_t iRet; + + pFile = NXI5assert (fid); + idx=0; + *iN = idx; + if (pFile->iCurrentD == 0 && pFile->iCurrentG == 0) { + /* + global attribute + */ + pFile->iVID=H5Gopen(pFile->iFID,"/"); + iRet = H5Aiterate(pFile->iVID,&idx,attr_info,&iname); + if (iRet < 0) { + NXIReportError (NXpData, "iterating ERROR!"); + return NX_ERROR; + } + idx=H5Aget_num_attrs(pFile->iVID); + + if (idx > 0) { + *iN = idx; + } else { + *iN = 1; + } + /* + if (iname != NULL) { + free(iname); + } + */ + return NX_OK; + } + else + { + if (pFile->iCurrentD>0) { + iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); + } else { + iRet=H5Aiterate(pFile->iCurrentG,&idx,attr_info,&iname); + } + } + if (iRet<0) { + NXIReportError (NXpData, "Attribute number cannot be fixed!"); + return NX_ERROR; + } + if ((idx==0) && (iRet==0)) { + *iN=idx; + return NX_OK; + } + idx=H5Aget_num_attrs(pFile->iCurrentD); + if (idx > 0) { + *iN = idx; + } else { + *iN = 1; } return NX_OK; - } - - /*-------------------------------------------------------------------------*/ - - /* Operator function. */ - - herr_t attr_info(hid_t loc_id, const char *name, void *opdata) - { - *((char**)opdata)=strdup(name); - return 1; - } - - NXstatus CALLING_STYLE NX5getnextattr (NXhandle fileid, NXname pName, - int *iLength, int *iType) - { - pNexusFile5 pFile; - hid_t attr_id,size_id,sign_id; - hid_t iRet, atype, aspace; - int iPType,rank; - char *iname = NULL; - unsigned int idx; - int intern_idx=-1; - - pFile = NXI5assert (fileid); - idx=pFile->iAtt5.iCurrentIDX; - iRet=0; - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) - { - /* global attribute */ - pFile->iVID=H5Gopen(pFile->iFID,"/"); - intern_idx=H5Aget_num_attrs(pFile->iVID); - if (intern_idx > idx) { - iRet=H5Aiterate(pFile->iVID,&idx,attr_info,&iname); - } - else - { - iRet=0; - } - intern_idx=-1; - if (iRet < 0) { - NXIReportError (NXpData, "ERROR iterating through ROOT Attr. list!"); - return NX_ERROR; - } - } else { - intern_idx=H5Aget_num_attrs(pFile->iCurrentD); - if (intern_idx > idx) { - iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); - } - else - { - iRet=0; - } - intern_idx=-1; - if (iRet < 0) { - NXIReportError (NXpData, "ERROR iterating through Attr. list!"); - return NX_ERROR; - } - } - if (iRet>0) - { - pFile->iAtt5.iCurrentIDX++; - strcpy(pName, iname); - if (iname != NULL) { - free(iname); - } - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) { - /* global attribute */ - pFile->iCurrentA = H5Aopen_name(pFile->iVID, pName); - } else { - pFile->iCurrentA = H5Aopen_name(pFile->iCurrentD, pName); - } - atype = H5Aget_type(pFile->iCurrentA); - aspace = H5Aget_space(pFile->iCurrentA); - rank = H5Sget_simple_extent_ndims(aspace); - attr_id = H5Tget_class(atype); - if (attr_id==H5T_STRING) { - iPType=NX_CHAR; - rank = H5Tget_size(atype); - } - if (rank == 0) { - rank++; - } - if (attr_id==H5T_INTEGER) - { - size_id=H5Tget_size(atype); - sign_id=H5Tget_sign(atype); - if (size_id==1) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT8; - } else { - iPType=NX_UINT8; - } - } - else if (size_id==2) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT16; - } else { - iPType=NX_UINT16; - } - } - else if (size_id==4) - { - if (sign_id==H5T_SGN_2) - { - iPType=NX_INT32; - } else { - iPType=NX_UINT32; - } - } - } else if (attr_id==H5T_FLOAT) - { - size_id=H5Tget_size(atype); - if (size_id==4) - { - iPType=NX_FLOAT32; - } - else if (size_id==8) - { - iPType=NX_FLOAT64; - } - } - *iType=iPType; - *iLength=rank; - H5Tclose(atype); - H5Sclose(aspace); - H5Aclose(pFile->iCurrentA); - return NX_OK; - } - else - { - if ((pFile->iCurrentD == 0) && (pFile->iCurrentG==0)) - { - /* global attribute */ - intern_idx=H5Aget_num_attrs(pFile->iVID); - } else { - if (pFile->iCurrentD>0){ - intern_idx=H5Aget_num_attrs(pFile->iCurrentD); - } else { - intern_idx=H5Aget_num_attrs(pFile->iCurrentG); - } - } - if ((intern_idx == 0)||(intern_idx == idx)) { - pFile->iAtt5.iCurrentIDX = 0; - if (iname != NULL) { - free(iname); - } - return NX_EOD; - } - NXIReportError (NXpData, - "ERROR: Iteration was not successful"); - return NX_ERROR; - } - } - - - /*-------------------------------------------------------------------------*/ - - NXstatus CALLING_STYLE NX5getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) - { - pNexusFile5 pFile; - int iNew, iRet; - hid_t type, atype, glob; - char pBuffer[256]; - - pFile = NXI5assert (fid); - type = *iType; - glob = 0; - if (type == NX_CHAR) - { - type=H5T_C_S1; - } - else if (type == NX_INT8) - { - type=H5T_NATIVE_CHAR; - } - else if (type == NX_UINT8) - { - type=H5T_NATIVE_UCHAR; - } - else if (type == NX_INT16) - { - type=H5T_NATIVE_SHORT; - } - else if (type == NX_UINT16) - { - type=H5T_NATIVE_USHORT; - } - else if (type == NX_INT32) - { - type=H5T_NATIVE_INT; - } - else if (type == NX_UINT32) - { - type=H5T_NATIVE_UINT; - } - else if (type == NX_FLOAT32) - { - type=H5T_NATIVE_FLOAT; - } - else if (type == NX_FLOAT64) - { - type=H5T_NATIVE_DOUBLE; - } - /* find attribute */ - if (pFile->iCurrentD != 0) - { - /* Dataset attribute */ - iNew = H5Aopen_name(pFile->iCurrentD, name); - } - else - { - /* globale and group attributes */ - if (pFile->iCurrentG != 0) { - /* group attribute */ - iNew = H5Aopen_name(pFile->iCurrentG, name); - } else { - /* global attributes */ - glob=H5Gopen(pFile->iFID,"/"); - iNew = H5Aopen_name(glob, name); - } - } - if (iNew < 0) { - sprintf (pBuffer, "ERROR: attribute %s not found", name); - NXIReportError (NXpData, pBuffer); - return NX_ERROR; - } - pFile->iCurrentA = iNew; - /* finally read the data */ - if (type==H5T_C_S1) - { - atype=H5Tcopy(type); - H5Tset_size(atype,*datalen); - iRet = H5Aread(pFile->iCurrentA, atype, data); - *datalen=strlen(data); - } else { - iRet = H5Aread(pFile->iCurrentA, type, data); - *datalen=1; - } - - if (iRet < 0) { - sprintf (pBuffer, "ERROR: HDF could not read attribute data"); - NXIReportError (NXpData, pBuffer); - return NX_ERROR; - } - - iRet = H5Aclose(pFile->iCurrentA); - if (glob > 0) - { - H5Gclose(glob); - } - if (type==H5T_C_S1) - { - H5Tclose(atype); - } - return NX_OK; - } - - /*-------------------------------------------------------------------------*/ - - NXstatus CALLING_STYLE NX5getattrinfo (NXhandle fid, int *iN) - { - pNexusFile5 pFile; - char *iname = NULL; - unsigned int idx; - herr_t iRet; - - pFile = NXI5assert (fid); - idx=0; - *iN = idx; - if (pFile->iCurrentD == 0 && pFile->iCurrentG == 0) { - /* - global attribute - */ - pFile->iVID=H5Gopen(pFile->iFID,"/"); - iRet = H5Aiterate(pFile->iVID,&idx,attr_info,&iname); - if (iRet < 0) { - NXIReportError (NXpData, "iterating ERROR!"); - return NX_ERROR; - } - idx=H5Aget_num_attrs(pFile->iVID); - - if (idx > 0) { - *iN = idx; - } else { - *iN = 1; - } - /* - if (iname != NULL) { - free(iname); - } - */ - return NX_OK; - } - else - { - if (pFile->iCurrentD>0) { - iRet=H5Aiterate(pFile->iCurrentD,&idx,attr_info,&iname); - } else { - iRet=H5Aiterate(pFile->iCurrentG,&idx,attr_info,&iname); - } - } - if (iRet<0) { - NXIReportError (NXpData, "Attribute number cannot be fixed!"); - return NX_ERROR; - } - if ((idx==0) && (iRet==0)) { - *iN=idx; - return NX_OK; - } - idx=H5Aget_num_attrs(pFile->iCurrentD); - if (idx > 0) { - *iN = idx; - } else { - *iN = 1; - } - return NX_OK; - - } + } - /*-------------------------------------------------------------------------*/ - - NXstatus CALLING_STYLE NX5getgroupID (NXhandle fileid, NXlink* sRes) + /*-------------------------------------------------------------------------*/ + NXstatus CALLING_STYLE NX5getgroupID (NXhandle fileid, NXlink* sRes) { pNexusFile5 pFile; int u; diff --git a/network.c b/network.c index 701b407d..1231df49 100644 --- a/network.c +++ b/network.c @@ -472,7 +472,7 @@ int NETReadTillTermNew(mkChannel *self, int timeout, return -1; } - maxTime = time(NULL) + (time_t)ceil((double)timeout/1000); + maxTime = time(NULL) + (time_t)ceil((double)timeout/1000 +1); length = strlen(pTerm); memset(pBuffer,0,iBufLen); @@ -503,6 +503,8 @@ int NETReadTillTermNew(mkChannel *self, int timeout, } pBuffer[bufPtr] = c; bufPtr++; + } else { + return -1; } /* wait for more data diff --git a/nread.c b/nread.c index db5e3436..26477257 100644 --- a/nread.c +++ b/nread.c @@ -321,6 +321,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */ else { pEnd++; + pPtr = pEnd; } break; } diff --git a/nxscript.c b/nxscript.c index 1d450d3d..3e5b26c6 100644 --- a/nxscript.c +++ b/nxscript.c @@ -856,6 +856,7 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics, pNXScript self, int argc, char *argv[]){ int status; + char pBueffel[256]; if(argc < 4){ SCWrite(pCon,"ERROR: insufficient number of arguments to makelink", @@ -866,7 +867,9 @@ static void makeLink(SConnection *pCon, SicsInterp *pSics, status = NXDaliaslink(self->fileHandle, self->dictHandle, argv[2],argv[3]); if(status != NX_OK){ - SCWrite(pCon,"ERROR: linking failed",eError); + snprintf(pBueffel,255,"ERROR: linking %s against %s failed", + argv[2], argv[3]); + SCWrite(pCon,pBueffel,eError); return; } diff --git a/ofac.c b/ofac.c index cac85299..e5fc980a 100644 --- a/ofac.c +++ b/ofac.c @@ -104,6 +104,9 @@ #include "help.h" #include "site.h" #include "nxupdate.h" +#include "confvirtmot.h" +#include "exeman.h" +#include "oscillate.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -279,6 +282,13 @@ AddCommand(pInter,"DrivableInvoke", TclDrivableInvoke,NULL,NULL); AddCommand(pInter,"UpdateFactory",UpdateFactory,NULL,NULL); AddCommand(pInter,"allowexec",AllowExec,NULL,NULL); + AddCommand(pInter,"MakeConfigurableMotor", + MakeConfigurableVirtualMotor,NULL,NULL); + AddCommand(pInter,"MakeBatchManager", + MakeExeManager,NULL,NULL); + AddCommand(pInter,"MakeOscillator", + MakeOscillator,NULL,NULL); + /* install site specific commands @@ -335,6 +345,9 @@ RemoveCommand(pSics,"MakeTclInt"); RemoveCommand(pSics,"UpdateFactory"); RemoveCommand(pSics,"allowexec"); + RemoveCommand(pSics,"MakeConfigurableMotor"); + RemoveCommand(pSics,"MakeBatchManager"); + RemoveCommand(pSics,"MakeOscillator"); /* remove site specific installation commands diff --git a/oscillate.c b/oscillate.c new file mode 100644 index 00000000..6c912704 --- /dev/null +++ b/oscillate.c @@ -0,0 +1,231 @@ +/*----------------------------------------------------------------------- + Oscillator runs a motor back and forth between its software limits. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +------------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "task.h" +#include "oscillate.h" +/*================== real work =========================================*/ +static void StopOscillation(pOscillator self){ + assert(self != NULL); + if(self->taskID > 0){ + self->pMot->pDriver->Halt(self->pMot->pDriver); + self->stopFlag = 1; + MotorSetPar(self->pMot,self->pCon,"accesscode",(float)self->oldRights); + self->taskID = -1; + } +} +/*---------------------------------------------------------------------*/ +static int OscillationTask(void *data){ + pOscillator self = (pOscillator)data; + int status, code, errStatus; + char error[256]; + float pos; + + + assert(self); + if(self->stopFlag == 1){ + return 0; + } + + status = self->pMot->pDriver->GetStatus(self->pMot->pDriver); + switch(status){ + case HWFault: + case HWPosFault: + self->pMot->pDriver->GetError(self->pMot->pDriver,&code,error,255); + SCWrite(self->pCon,error,eError); + if(self->nextTargetFlag == 1){ + pos = self->lowerLimit; + } else { + pos = self->upperLimit; + } + errStatus = self->pMot->pDriver->TryAndFixIt(self->pMot->pDriver,code,pos); + self->errorCount++; + if(errStatus == MOTFAIL){ + MotorRun(self->pMot,self->pCon,pos); + } + break; + case HWBusy: + break; + case HWIdle: + if(self->nextTargetFlag == 1){ + pos = self->upperLimit; + self->nextTargetFlag = 0; + } else { + pos = self->lowerLimit; + self->nextTargetFlag = 1; + } + MotorRun(self->pMot,self->pCon,pos); + } + return 1; +} +/*--------------------------------------------------------------------*/ +static int StartOscillation(pOscillator self, SConnection *pCon){ + float fval; + int status; + char error[80], pBueffel[255]; + + assert(self); + + if(self->taskID > 0){ + SCWrite(pCon,"ERROR: oscillation already running",eError); + return 1; + } + + MotorGetPar(self->pMot,"softlowerlim",&self->lowerLimit); + self->lowerLimit += .5; + MotorGetPar(self->pMot,"softupperlim",&self->upperLimit); + self->upperLimit -= .5; + MotorGetPar(self->pMot,"accesscode",&fval); + self->oldRights = (int)fval; + MotorSetPar(self->pMot,self->pCon,"accesscode",(float)usInternal); + self->nextTargetFlag = 0; + self->errorCount = 0; + self->stopFlag = 0; + + /* + check reachability of limits + */ + status = MotorCheckBoundary(self->pMot,self->lowerLimit,&fval,error,79); + if(!status){ + snprintf(pBueffel,255,"ERROR: cannot reach %f: %s reported", + self->lowerLimit,error); + SCWrite(pCon,pBueffel,eError); + return 0; + } + status = MotorCheckBoundary(self->pMot,self->upperLimit,&fval,error,79); + if(!status){ + snprintf(pBueffel,255,"ERROR: cannot reach %f: %s reported", + self->upperLimit,error); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + /* + start task + */ + self->taskID = TaskRegister(pServ->pTasker, + OscillationTask, + NULL, + NULL, + self, + 10); + if(self->taskID < 0){ + SCWrite(pCon,"ERROR: failed to start oscillation task",eError); + return 0; + } + return 1; +} +/*===================== life and death =================================*/ +static void KillOscillator(void *data){ + pOscillator self = (pOscillator)data; + if(self != NULL){ + StopOscillation(self); + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + if(self->pCon != NULL){ + SCDeleteConnection(self->pCon); + } + free(self); + } +} +/*========================================================================*/ +int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pOscillator pNew = NULL; + pMotor pMot = NULL; + char pBueffel[132]; + int status; + + if(argc < 3){ + SCWrite(pCon,"ERROR: insufficient number of arguments to MakeOscilator", + eError); + return 0; + } + + pMot = FindMotor(pSics,argv[2]); + if(pMot == NULL){ + snprintf(pBueffel,131,"ERROR: %s is no motor",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + + pNew = (pOscillator)malloc(sizeof(Oscillator)); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory creating oscillator",eError); + return 0; + } + memset(pNew,0,sizeof(Oscillator)); + pNew->pDes = CreateDescriptor("Oscillator"); + pNew->pMot = pMot; + pNew->pCon = SCCreateDummyConnection(pSics); + if(!pNew->pDes || !pNew->pCon){ + SCWrite(pCon,"ERROR: out of memory creating oscillator",eError); + return 0; + } + SCSetWriteFunc(pNew->pCon,SCFileWrite); + SCSetRights(pNew->pCon,usInternal); + + status = AddCommand(pSics,argv[1], + OscillatorWrapper, + KillOscillator, + pNew); + if(!status){ + snprintf(pBueffel,131,"ERROR: duplicate command %s not created",argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + return 1; +} +/*========================================================================*/ +int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pOscillator self = (pOscillator)pData; + char pBueffel[256]; + + assert(self); + if(argc < 2){ + SCWrite(pCon,"ERROR: need start/stop argument for oscillator",eError); + return 0; + } + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"start") == 0){ + return StartOscillation(self,pCon); + } else if(strcmp(argv[1],"stop") == 0) { + StopOscillation(self); + snprintf(pBueffel,255,"Oscillation stopped with %d errors, %s", + self->errorCount, + "see commandlog for details"); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else if(strcmp(argv[1],"status") == 0) { + if(self->taskID > 0){ + snprintf(pBueffel,255,"Oscillation running, %d errors so far, %s", + self->errorCount, + " error details in commandlog"); + } else { + snprintf(pBueffel,255,"Oscillation stopped"); + } + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + SCWrite(pCon,"ERROR: invalid sub command for oscillator requested", + eError); + return 0; + } + return 1; +} + diff --git a/oscillate.h b/oscillate.h new file mode 100644 index 00000000..08754924 --- /dev/null +++ b/oscillate.h @@ -0,0 +1,34 @@ + +/*----------------------------------------------------------------------- + Oscillator runs a motor back and forth between its software limits. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +------------------------------------------------------------------------*/ +#ifndef SICSOSCILLATOR +#define SICSOSCILLATOR +#include "motor.h" + + +typedef struct { + pObjectDescriptor pDes; + pMotor pMot; + int oldRights; + float upperLimit; + float lowerLimit; + int nextTargetFlag; + long taskID; + int stopFlag; + SConnection *pCon; + int errorCount; + } Oscillator, *pOscillator; + +/*---------------------------------------------------------------------*/ +int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif + diff --git a/oscillate.w b/oscillate.w new file mode 100644 index 00000000..b0cf2246 --- /dev/null +++ b/oscillate.w @@ -0,0 +1,70 @@ +\subsection{Motor Oscillation} +This module allows to oscillate a motor, i.e. drive between two +positions back and forth automatically. This is required for instance +in order to control a radial collimator or in order to prevent +preferred orientation effects in powder measurements. The oscialltion +can be started and stoped through commands. When starting, this module +takes over the motor in order to prevent it being driven by a +user. The limits of the oscillation are given through the current +software limits. When running, a special SICS task watches the motor +and makes it run the other way when it has arrived at one of its +boundaries. When oscillation is stopped, the motor is stopped, the +task stopped and the control of the motor is returned to the user. + +In order to this, a data structure the following data structure is +required: +@d oscdat @{ +typedef struct { + pObjectDescriptor pDes; + pMotor pMot; + int oldRights; + float upperLimit; + float lowerLimit; + int nextTargetFlag; + long taskID; + int stopFlag; + SConnection *pCon; + int errorCount; + } Oscillator, *pOscillator; +@} +The fields: +\begin{description} +\item[pDes] The SICS object descriptor. +\item[pMot] The motor controlled through this module. +\item[oldRights] The old user rights code for the motor. Must be saved +in order to restore when stopping the oscillation. +\item[upperLimit] The uper limit of the oscillation. +\item[lowerLimit] the lower limits of the oscillation. +\item[nextTargetFlag] A flag which decides which limit is the next one +to drive to. +\item[taskID] The ID of the control task. +\item[stopFlag] A flag to signal the control task to stop. +\item[pCon] A dummy connection object to use for writing. Is +configured to write to log files. +\end{description} + +The interface to this module is just the interpreter interface. The +rest is module local. + +@o oscillate.h @{ +/*----------------------------------------------------------------------- + Oscillator runs a motor back and forth between its software limits. + + copyright: see file COPYRIGHT + + Mark Koennecke, November 2004 +------------------------------------------------------------------------*/ +#ifndef SICSOSCILLATOR +#define SICSOSCILLATOR +#include "motor.h" + +@ +/*---------------------------------------------------------------------*/ +int MakeOscillator(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int OscillatorWrapper(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif + +@} diff --git a/rs232controller.c b/rs232controller.c index 08b17a8b..08d638a1 100644 --- a/rs232controller.c +++ b/rs232controller.c @@ -228,6 +228,7 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){ } else if(iRet == -1) { + printf("Incomplete read: %s\n", (char *)data); return INCOMPLETE; } *datalen = strlen((char *)data); @@ -592,7 +593,7 @@ int RS232Action(SConnection *pCon, SicsInterp *pSics, } else if(strcmp(argv[1],"timeout") == 0) { - if(checkSet(pCon,argc,usMugger)) + if(checkSet(pCon,argc,usUser)) { setRS232Timeout(self,atoi(argv[2])); SCSendOK(pCon); diff --git a/scan.c b/scan.c index 24bbb806..c49d1079 100644 --- a/scan.c +++ b/scan.c @@ -290,6 +290,8 @@ static char *fixExtension(char *filename) self->lPos = ftell(self->fd); fclose(fd); + fclose(self->fd); + self->fd = NULL; return 1; } /*--------------------------------------------------------------------------*/