diff --git a/Busy.c b/Busy.c new file mode 100644 index 00000000..55e7c817 --- /dev/null +++ b/Busy.c @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------ + A busy flag module for SICS. + + Mark Koennecke, July 2002 +-------------------------------------------------------------------------*/ +#include +#include +#include "fortify.h" +#include "sics.h" + +/*----------------------------------------------------------------------*/ +typedef struct BUSY__ { + pObjectDescriptor pDes; + int iBusy; + }Busy; +/*---------------------------------------------------------------------*/ +busyPtr makeBusy(void){ + busyPtr result = NULL; + + result = (busyPtr)malloc(sizeof(Busy)); + if(!result){ + return NULL; + } + result->pDes = CreateDescriptor("BusyFlag"); + if(!result->pDes){ + free(result); + return NULL; + } + result->iBusy = 0; + return result; +} +/*---------------------------------------------------------------------*/ +void killBusy(void *self){ + busyPtr busy; + if(self != NULL){ + busy = (busyPtr)self; + if(busy->pDes != NULL){ + DeleteDescriptor(busy->pDes); + } + free(busy); + } +} +/*---------------------------------------------------------------------*/ +void incrementBusy(busyPtr self){ + assert(self != NULL); + self->iBusy++; +} +/*--------------------------------------------------------------------*/ +void decrementBusy(busyPtr self){ + assert(self != NULL); + self->iBusy--; + if(self->iBusy < 0){ + self->iBusy = 0; + } +} +/*--------------------------------------------------------------------*/ +void clearBusy(busyPtr self){ + assert(self != NULL); + self->iBusy = 0; +} +/*--------------------------------------------------------------------*/ +void setBusy(busyPtr self, int val){ + assert(self != NULL); + self->iBusy = val; +} +/*--------------------------------------------------------------------*/ +int isBusy(busyPtr self){ + assert(self != NULL); + return self->iBusy; +} +/*--------------------------------------------------------------------*/ +int BusyAction(SConnection *pCon,SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + busyPtr self = NULL; + char pBuffer[80]; + + self = (busyPtr)pData; + assert(self != NULL); + + if(argc > 1){ + strtolower(argv[1]); + if(usUser < SCGetRights(pCon)){ + SCWrite(pCon,"ERROR: no privilege to manipulate busy flag",eError); + return 0; + } + if(strcmp(argv[1],"incr") == 0){ + incrementBusy(self); + SCSendOK(pCon); + return 1; + } else if(strcmp(argv[1],"decr") == 0){ + decrementBusy(self); + SCSendOK(pCon); + return 1; + } else if(strcmp(argv[1],"clear") == 0){ + clearBusy(self); + SCSendOK(pCon); + return 1; + } + } + + sprintf(pBuffer,"Busy = %d", isBusy(self)); + SCWrite(pCon,pBuffer,eValue); + return 1; +} +/*---------------------------------------------------------------------*/ +busyPtr findBusy(SicsInterp *pInter){ + CommandList *pCom = NULL; + + pCom = FindCommand(pInter,"busy"); + if(pCom != NULL){ + return (busyPtr)pCom->pData; + } +} + + diff --git a/Busy.h b/Busy.h new file mode 100644 index 00000000..6718146d --- /dev/null +++ b/Busy.h @@ -0,0 +1,28 @@ + +/*------------------------------------------------------------------------ + A busy flag module for SICS. + + Mark Koennecke, July 2002 +-------------------------------------------------------------------------*/ +#ifndef SICSBUSY +#define SICSBUSY + + +typedef struct BUSY__ *busyPtr; + +busyPtr makeBusy(void); +void killBusy(void *self); + +void incrementBusy(busyPtr self); +void decrementBusy(busyPtr self); +void clearBusy(busyPtr self); +void setBusy(busyPtr self, int val); + +int isBusy(busyPtr self); + +int BusyAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +busyPtr findBusy(SicsInterp *pInter); +#endif + diff --git a/Busy.w b/Busy.w new file mode 100644 index 00000000..083208ad --- /dev/null +++ b/Busy.w @@ -0,0 +1,41 @@ +\subsection{Busy} +This class implements a busy flag which should be set when the interpreter +is busy doing something, like scanning for instance. The primary use +is for AMOR where operations are possible while writing data. This is +not caught by the normal device executor logic. In the long run, this +should become the standard way to control access to the +interpreter. In order to ensure access control, a test for the busy +flag is included into the SCMatchRights procedure. The busy flag is + installed into the interpreter. + +@o Busy.h @{ +/*------------------------------------------------------------------------ + A busy flag module for SICS. + + Mark Koennecke, July 2002 +-------------------------------------------------------------------------*/ +#ifndef SICSBUSY +#define SICSBUSY + + +typedef struct BUSY__ *busyPtr; + +busyPtr makeBusy(void); +void killBusy(void *self); + +void incrementBusy(busyPtr self); +void decrementBusy(busyPtr self); +void clearBusy(busyPtr self); +void setBusy(busyPtr self, int val); + +int isBusy(busyPtr self); + +int BusyAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +busyPtr findBusy(SicsInterp *pInter); +#endif + +@} + + diff --git a/Makefile b/Makefile index a66eda37..c390d520 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ tasinit.o tasutil.o t_rlp.o t_conv.o d_sign.o d_mod.o \ tasdrive.o tasscan.o synchronize.o definealias.o swmotor.o t_update.o \ hmcontrol.o userscan.o slsmagnet.o rs232controller.o lomax.o \ - polterwrite.o fourlib.o + polterwrite.o fourlib.o motreg.o motreglist.o anticollider.o MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/SCinter.c b/SCinter.c index 79020144..9d464003 100644 --- a/SCinter.c +++ b/SCinter.c @@ -51,9 +51,13 @@ #include "splitter.h" #include "servlog.h" #include "macro.h" +#include "interface.h" +#include "obdes.h" + /* M.Z. */ #include "definealias.h" + #define MAXLEN 256 #define MAXPAR 100 @@ -545,4 +549,19 @@ extern char *SkipSpace(char *pPtr); } return NULL; } +/*------------------------------------------------------------------------*/ +void *FindDrivable(SicsInterp *pSics, char *name){ + pIDrivable pDriv; + pDummy pDum = NULL; + CommandList *pCom = NULL; + pCom = FindCommand(pSics,name); + if(pCom != NULL){ + pDum = (pDummy)pCom->pData; + if(pDum != NULL){ + return pDum->pDescriptor->GetInterface(pDum,DRIVEID); + } + } + + return NULL; +} diff --git a/SCinter.h b/SCinter.h index f9f372a3..e5ae3dce 100644 --- a/SCinter.h +++ b/SCinter.h @@ -133,5 +133,13 @@ typedef struct __SINTER */ void *FindCommandData(SicsInterp *pSics, char *name, char *comclass); +/*------------------------------------------------------------------------ + FindDrivable tries to find Drivable object by the name given. Returns a + pointer to the drivable interface in the case of success, NULL in + case of failure. In order to save me fixing header files the pointer must + be cast to the drivable interface pointer. + ------------------------------------------------------------------------*/ + +void *FindDrivable(SicsInterp *pics, char *name); #endif diff --git a/anticollider.c b/anticollider.c new file mode 100644 index 00000000..eb5d54cb --- /dev/null +++ b/anticollider.c @@ -0,0 +1,375 @@ +/*---------------------------------------------------------------------- + This is the implementation file for the AntiCollider, a complex movements + control module for SICS. See anticoliider.tex for more information. + + copyright: see file copyright + + Mark Koennecke, August 2002 +------------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include "lld.h" +#include "motreglist.h" +#include "anticollider.i" +#include "anticollider.h" + +/*--------------------------------------------------------------------- + As there should be only one AntiCollider in a system, I use a static + pointer to the AntiCollider here in order to facilitate access. + Otherwise more complex mechanisms must be divised in order to pass this + pointer into ColliderSetValue and ColliderCheckStatus + ----------------------------------------------------------------------*/ +static pAntiCollider myCollider = NULL; + +/*-------------------------------------------------------------------- + the replacement function for the motor's drivable interface SetValue + function. It enters the new target into the motor list. + ---------------------------------------------------------------------*/ +static long ReplacementSetValue(void *pData, SConnection *pCon, float fTarget){ + pMotReg pMot = NULL; + + assert(myCollider != NULL); + + pMot = FindMotFromDataStructure(myCollider->motorList,pData); + if(pMot != NULL){ + SetRegMotTarget(pMot,fTarget); + myCollider->isDirty = 1; + } else { + return 0; + } + + return 1; +} +/*--------------------------------------------------------------------- + The replacement CheckStatus function for controlled motors. + Start AntiCollider if not running and finish. Rest of work done by + AntiCollider. + -----------------------------------------------------------------------*/ +static int ReplacementCheckStatus(void *pData, SConnection *pCon){ + pMotReg pMot = NULL; + + assert(myCollider != NULL); + + if(myCollider->isDirty == 1){ + myCollider->isDirty = 0; + StartDevice(pServ->pExecutor, + "anticollider", + myCollider->pDes, + myCollider, + pCon, + 77.77); + return HWIdle; + } else { + return HWIdle; + } +} +/*------------------------------------------------------------------------ + The collider SetValue function + -------------------------------------------------------------------------*/ +static long ColliderSetValue(void *pData, SConnection *pCon, float fTarget){ + pAntiCollider self = (pAntiCollider) pData; + int iRet; + pMotReg pMot = NULL; + char pBueffel[80]; + char *ruenBuffer = NULL; + + Tcl_DString command; + + /* + build command list + */ + if(self->colliderScript == NULL){ + SCWrite(pCon,"ERROR: no collider script defined",eError); + return 0; + } + + Tcl_DStringInit(&command); + Tcl_DStringAppend(&command,self->colliderScript,-1); + iRet = LLDnodePtr2First(self->motorList); + while(iRet != 0){ + LLDnodeDataTo(self->motorList,&pMot); + if(pMot != NULL){ + if(pMot->iActive){ + CreateTargetString(pMot,pBueffel); + Tcl_DStringAppend(&command, pBueffel,-1); + pMot->iActive = 0; + } + } + iRet = LLDnodePtr2Next(self->motorList); + } + printf("%s\n", Tcl_DStringValue(&command)); + + /* + kill old collider sequence + */ + LLDdelete(self->sequenceList); + self->sequenceList = LLDcreate(sizeof(Sequence)); + self->level = 0; + + /* + evaluate colliderScript + */ + iRet = Tcl_Eval(pServ->pSics->pTcl,Tcl_DStringValue(&command)); + if(iRet != TCL_OK){ + SCWrite(pCon,"ERROR: Movement not possible or bad collider script",eError); + /* + SCWrite(pCon,pServ->pSics->pTcl->result,eError); + */ + SCSetInterrupt(pCon,eAbortOperation); + return 0; + } + + /* + we are set + */ + Tcl_DStringFree(&command); + return 1; +} +/*---------------------------------------------------------------------- + The Collider CheckStatus function + -----------------------------------------------------------------------*/ +static int ColliderCheckStatus(void *pData, SConnection *pCon){ + int count = 0; + pAntiCollider self = (pAntiCollider) pData; + + assert(self); + + if(SCGetInterrupt(pCon) != eContinue){ + return HWIdle; + } + + count = CheckAllMotors(self->motorList,pCon); + if(count == 0){ + self->level++; + count = StartLevel(self->level, + self->sequenceList, + self->motorList, + pCon); + if(count == 0){ + /* + no more levels. All done + */ + return HWIdle; + } else { + return HWBusy; + } + } else { + return HWBusy; + } +} +/*---------------------------------------------------------------------- + Most of these are dummies........ + -----------------------------------------------------------------------*/ +static int ColliderHalt(void *pData){ + StopExe(pServ->pExecutor,"all"); + return 1; +} +/*---------------------------------------------------------------------*/ +static int ColliderLimits(void *self, float fVal, char *error, + int iErren){ + return 1; +} +/*--------------------------------------------------------------------*/ +static float ColliderGetValue(void *self, SConnection *pCon){ + return 77.77; +} +/*--------------------------------------------------------------------*/ +int StartLevel(int level, int sequenceList, int motorList, SConnection *pCon){ + Sequence seq; + pMotReg pMot = NULL; + int iRet; + int count = 0; + char pBueffel[132]; + + iRet = LLDnodePtr2First(sequenceList); + while(iRet != 0){ + LLDnodeDataTo(sequenceList,&seq); + if(seq.level == level){ + pMot = FindMotEntry(motorList,seq.pMotor); + if(pMot){ + StartRegMot(pMot,pCon,seq.target); + count++; + } else { + sprintf(pBueffel,"ERROR: motor %s, requested from anticollider script", + seq.pMotor); + SCWrite(pCon,pBueffel,eError); + SCWrite(pCon,"ERROR: motor NOT found, fix script!",eError); + } + } + iRet = LLDnodePtr2Next(sequenceList); + } + return count; +} +/*--------------------------------------------------------------------*/ +static void ListSequence(int sequenceList, SConnection *pCon){ + Sequence seq; + int iRet; + char pBueffel[132]; + + SCWrite(pCon,"level motor target",eValue); + iRet = LLDnodePtr2First(sequenceList); + while(iRet != 0){ + LLDnodeDataTo(sequenceList,&seq); + sprintf(pBueffel,"%d %s %f",seq.level,seq.pMotor,seq.target); + SCWrite(pCon,pBueffel,eValue); + iRet = LLDnodePtr2Next(sequenceList); + } +} +/*-------------------------------------------------------------------------*/ +static void *ColliderGetInterface(void *pData, int iID) { + pAntiCollider self = NULL; + + self = (pAntiCollider)pData; + assert(self); + + if(iID == DRIVEID){ + return self->pDriv; + } + return NULL; +} +/*----------------------------------------------------------------------*/ +void KillCollider(void *pData){ + pAntiCollider self = (pAntiCollider)pData; + + if(self == NULL){ + return; + } + + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + if(self->pDriv != NULL){ + free(self->pDriv); + } + if(self->colliderScript != NULL){ + free(self->colliderScript); + } + if(self->motorList > 0){ + KillMotList(self->motorList); + } + if(self->sequenceList > 0){ + LLDdelete(self->sequenceList); + } + free(self); + myCollider = NULL; +} +/*-----------------------------------------------------------------------*/ +int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]){ + + myCollider = (pAntiCollider)malloc(sizeof(AntiCollider)); + if(myCollider == NULL){ + SCWrite(pCon,"ERROR: out of memory when generating AntiCollider",eError); + return 0; + } + memset(myCollider,0,sizeof(AntiCollider)); + + myCollider->pDes = CreateDescriptor("AntiCollider"); + myCollider->pDriv = CreateDrivableInterface(); + if(!myCollider->pDes || !myCollider->pDriv){ + KillCollider(myCollider); + SCWrite(pCon,"ERROR: out of memory when generating AntiCollider",eError); + return 0; + } + + myCollider->pDes->GetInterface = ColliderGetInterface; + myCollider->pDriv->Halt = ColliderHalt; + myCollider->pDriv->CheckLimits = ColliderLimits; + myCollider->pDriv->SetValue = ColliderSetValue; + myCollider->pDriv->CheckStatus = ColliderCheckStatus; + myCollider->pDriv->GetValue = ColliderGetValue; + + myCollider->motorList = LLDcreate(sizeof(void *)); + myCollider->sequenceList = LLDcreate(sizeof(Sequence)); + + AddCommand(pSics,"anticollision",AntiColliderAction, + KillCollider, + myCollider); + + return 1; +} +/*------------------------------------------------------------------------*/ +int AntiColliderAction(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]){ + pAntiCollider self = (pAntiCollider)pData; + Sequence seq; + char pBueffel[256]; + pMotReg pMot = NULL; + + assert(self != NULL); + + if(argc > 1){ + if(strcmp(argv[1],"clear") == 0){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + LLDdelete(self->sequenceList); + self->sequenceList = LLDcreate(sizeof(Sequence)); + SCSendOK(pCon); + return 1; + } else if(strcmp(argv[1],"list") == 0){ + ListSequence(self->sequenceList,pCon); + return 1; + } + } + + if(argc < 3){ + SCWrite(pCon,"ERROR : insufficient number of arguments to anticollision", + eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"script") == 0){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + if(self->colliderScript != NULL){ + free(self->colliderScript); + } + self->colliderScript = strdup(argv[2]); + SCSendOK(pCon); + return 1; + } else if(strcmp(argv[1],"register") == 0){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + if(FindDrivable(pSics,argv[2]) == NULL){ + sprintf(pBueffel,"ERROR: %s is NOT drivable, cannot register",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + pMot = RegisterMotor(argv[2],pSics, + ReplacementSetValue, + ReplacementCheckStatus); + if(pMot){ + LLDnodeAppendFrom(self->motorList,&pMot); + SCSendOK(pCon); + return 1; + } else { + SCWrite(pCon,"ERROR: out of memory registering motor",eError); + return 0; + } + } else if(strcmp(argv[1],"add") == 0){ + if(argc < 5){ + SCWrite(pCon, + "ERROR: InsUfficient number of arguments to anticollicion add", + eError); + return 0; + } + seq.level = atoi(argv[2]); + strncpy(seq.pMotor,argv[3],79); + seq.target = atof(argv[4]); + LLDnodeAppendFrom(self->sequenceList,&seq); + SCSendOK(pCon); + return 1; + } + SCWrite(pCon,"ERROR: anticollider command not understood",eError); + return 0; +} + + diff --git a/anticollider.h b/anticollider.h new file mode 100644 index 00000000..f526789c --- /dev/null +++ b/anticollider.h @@ -0,0 +1,25 @@ + +/*---------------------------------------------------------------------- + This is the header file for the AntiCollider, a complex movements + control module for SICS. See anticoliider.tex for more information. + + copyright: see file copyright + + Mark Koennecke, August 2002 +------------------------------------------------------------------------*/ +#ifndef ANTICOLLIDER +#define ANTICOLLIDER + + + int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + int AntiColliderAction(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + + +#endif + + + diff --git a/anticollider.w b/anticollider.w new file mode 100644 index 00000000..4790bf10 --- /dev/null +++ b/anticollider.w @@ -0,0 +1,275 @@ +\subsubsection{The Anti Collider} +In some cases certain instrument positions can only be reached through +special sequences of drive instructions. Usually because some concrete +blocks or unduly bulky sample environment devices are in the path of +the instrument. Such cases can not be handled through primitive motor +limits. Handling such cases is the objective of the Anti Collider. + +The first thing needed is that motors involved with such complex +movements are registered with the Anti Collider. In this stage the +Anti Collider will take over the SetValue and CheckStatus functions of +the drivable interface of the motor. SetValue will be replaced by a +function which will register the drive request with the Anti +Collider. CheckStatus will be replaced by a version which checks with +the Anti Collider if the complex movement has finished. + +It is expected that coordinated and complex movements are initiated +within a single command. The first checkpoint where the complex +movement can be analyzed and coordinated the is when the device +executor calls CheckStatus for the first time. CheckStatus will detect +this condition and proceeds to call a Tcl procedure which then has to +create a r\"unb\"uffer which holds the necessary commands to drive the +complex movement. Or returns an error if the movement is not +possible. This scheme allows the instrument scientist to adapt the +way how the instrument moves to new sample environment devices, new +ideas or the growth of experience. Moreover this scheme allows to +handle all instruments with just a single module. As the Anti Collider +has taken over the SetValue method of the drivable interface of the +motor a command is provided which allows to start the actual motor. + +The user supplied Tcl script receives as arguments a list of motor and +target values to be driven. The script then has to return either an +error if the movement is not possible or the name of a r\"unb\"uffer +which performs the movement. + +The first thing needed for all this is a data structure which holds +the registration information and status of the controlled motor. This +information will be kept in a list holding the data tsrucutre given +below: + +@d motreg @{ + +typedef struct __MOTREG { + void *motorData; + char *motorName; + float targetPosition; + long (*originalSetValue)(void *motorData, + SConnection *pCon, + float fTarget); + int (*originalCheckStatus)(void *motorData, + SConnection *pCon); + int iActive; + } MotReg, *pMotReg; +@} +The fields are: +\begin{description} +\item[motorData] The motor data structure. +\item[motorName] The name of the motor operating. +\item[targetPosition] The requested target position for this motor. +\item[originalSetValue] the original motor starting function. +\item[originalCheckStatus] The original status checking function. +\item[iActive] A flag denoting if the motor has been started by the +Anti Collider. This causes the motors status to be checked which +checking status. If the motor becomes idle, this is set to 0 again. +\end{description} + + +The following interface functions are defined for this datastructure: +@d motregint @{ + pMotReg RegisterMotor(char *name, SicsInterp *pSics, + long (*SetValue)(void *pData, SConnection *pCon, float + fTarget), + int (*CheckStatus)(void *pData, SConnection *pCon)); + void KillRegMot(void *self); + + void SetRegMotTarget(pMotReg self, float target); + void CreateTargetString(pMotReg self, char pBueffel[80]); + + int RegMotMatch(pMotReg self, char *name); + + int StartRegMot(pMotReg self, SConnection *pCon, float fValue); + + int CheckRegMot(pMotReg self, SConnection *pCon); + +@} + +The functions in detail: +\begin{description} +\item[RegisterMotor] tries to find the motor name in the interpreter +pSics. Then all necessary manipulations are performed in order to +register the motor. In ths case of success a pointer to a new RegMot +data structure is returned. In the event of failure, NULL is +returned. Of course this function has to take the function pointers to +the drivable interface functions to replace as parameters. +\item[KillRegMot] kills a RegMot structure. +\item[SetRegMotTarget] sets a new target for a complex movement. +\item[CreateTragetString] creates in pBueffel this motors contribution +to a complex movement. +\item[RegMotMatch] returns 1 (true) if the string name matches the name stored +for this motor. Else 0. This will be used when searching for a +registered motor in the list. +\item[StartRegMot] will actually cause a real motor to start driving +towards the target given in fValue. The return value is the result of +the original motors SetValue method. +\item[CheckRegMot] checks for error conditions on the motor. +\end{description} + +Moreover it is convenient to define a couple of convenience functions +for handling the list of registered motors. The actual list is +managed through the lld functions as everywhere within SICS. + +@d motlist @{ + int MakeMotList(); + pMotReg FindMotEntry(int iList,char *name); + pMotReg FindMotFromDataStructure(int iList, void *pData); + int CheckAllMotors(int iList, SConnection *pCon); + void KillMotList(int iList); +@} +The functions: +\begin{description} +\item[MakeMotList] creates a new list for MotReg structures and +returns the handle for it. +\item[FindMotEntry] locates a motor in the list by name. If a matching +motor can be found, this function returns a pointer to the motors +MotReg structure. In the case of failure NULL is returned. +\item[FindMotFromDataStructure] locates a motor in the list through + the pointer to its data structure. . If a matching +motor can be found, this function returns a pointer to the motors +MotReg structure. In the case of failure NULL is returned. +\item[CheckAllMotors] checks all the active motors for the finished +condition. The number of running motors is returned. 0 if none is running. +\item[KillMotList] kills the list and all entries in it. +\end{description} + +In order to know how the anticollider has to run the motors a means is +needed to hold the sequence of motors to drive. This information must +be configured from the anticollider script. The information is held in +another list in a special data structure. + +@d seqlist @{ + typedef struct { + int level; + char pMotor[80]; + float target; + }Sequence; + + int StartLevel(int level, int sequenceList, int motorList, + SConnection *pCon); + +@} +The fields and functions are: +\begin{description} +\item[level] The level at which this motor shall be started. +\item[pMotor] The name of the motor to start. +\item[target] The target value for the motor. +\item[StartLevel] starts all motors belonging to a the level +specified. Returns the number of motors started or ) if none is +started. This last condition is also the condition when levels are +exhausted and we need to finish running the anticollider. +\end{description} + + +The anticollider itself is characterized through the following data +structure: +@d antidat @{ + typedef struct __ANTICOLLIDER{ + pObjectDescriptor pDes; + pIDrivable pDriv; + int motorList; + int sequenceList; + char *colliderScript; + int isDirty; + int level; + }AntiCollider, *pAntiCollider; +@} +The fields are: +\begin{description} +\item[pDes] The object descriptor required by SICS. +\item[motorList] The list of registered motors. +\item[colliderScript] the Tcl script called to calculate the movement. +\item[iDirty] a flag which is set to 1 (true) when a new movement must + be calculated. +\end{description} + +Most of the anticolliders functionality is implemented in interface +functions. The interface to the outside world is purely defined +through the interpreter functions. + +@d antiint @{ + int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + int AntiColliderAction(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); +@} + + +@o motreg.h @{ +/*------------------------------------------------------------------------- + R e g M o t + + This is a helper module for the Anti Collider. It handles all the + stuff necessary for dealing with a single motor. For more + information see the file anticollider.tex. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-----------------------------------------------------------------------*/ +#ifndef REGMOT +#define REGMOT +#include "sics.h" + +@ + +/*----------------------------------------------------------------------*/ +@ + +#endif + +@} + +@o motreglist.h @{ +/*----------------------------------------------------------------------- + A couple of utility functions for handling a list of MotReg + structures . This is a helper module for the anticollider collision + control system. See anticollider.tex for more details. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-------------------------------------------------------------------------*/ +#ifndef MOTREGLIST +#define MOTREGLIST + +#include "motreg.h" + +@ + + +#endif + + +@} + + +@o anticollider.i @{ +/*------------------------------------------------------------------------- + Anticollider internal data structure definition. Generated from + anticollider.w. Do not edit. +-------------------------------------------------------------------------*/ +@ +@ + +@} + +@o anticollider.h @{ +/*---------------------------------------------------------------------- + This is the header file for the AntiCollider, a complex movements + control module for SICS. See anticoliider.tex for more information. + + copyright: see file copyright + + Mark Koennecke, August 2002 +------------------------------------------------------------------------*/ +#ifndef ANTICOLLIDER +#define ANTICOLLIDER + +@ + +#endif + + + +@} \ No newline at end of file diff --git a/danu.dat b/danu.dat index f126a7a8..4d167238 100644 --- a/danu.dat +++ b/danu.dat @@ -1,3 +1,3 @@ - 226 + 231 NEVER, EVER modify or delete this file You'll risk eternal damnation and a reincarnation as a cockroach!|n \ No newline at end of file diff --git a/devexec.c b/devexec.c index 6a54c5f0..d0becf37 100644 --- a/devexec.c +++ b/devexec.c @@ -7,6 +7,7 @@ Substantial rewrite: Mark Koennecke, February 1997 revised: Mark Koennecke, June 1997 revised for use with tasker: Mark Koennecke, September 1997 + Locking added: Mark Koennecke, August 2002 Copyright: @@ -103,6 +104,7 @@ int iEnd; long lTask; pTaskMan pTask; + int iLock; } ExeList; static pExeList pExecutor = NULL; @@ -136,6 +138,7 @@ pRes->iStatus = DEVDONE; pRes->pTask = pTask; pRes->lTask = -1; + pRes->iLock = 0; return pRes; } /*-------------------------------------------------------------------------*/ @@ -181,7 +184,12 @@ { self->pOwner = pCon; } - + if(self->iLock == 1) + { + SCWrite(pCon,"ERROR: instrument is locked",eError); + return 0; + } + /* well create a new entry */ self->iStop = 0; pNew = CreateDevEntry(pDes,pData,fNew,name); @@ -478,7 +486,7 @@ /* do nothing if not running */ if(self->lTask < 0) { - printf("Wait4Success finished very, very badly\n"); + printf("Nothing to wait for....\n"); return self->iStatus; } @@ -749,6 +757,7 @@ self->iEnd = 1; self->lTask = -1; self->iRun = 0; + self->iLock = 0; } /*-------------------------------------------------------------------------*/ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -922,7 +931,19 @@ } } } - +/*--------------------------------------------------------------------*/ +void LockDeviceExecutor(pExeList self) +{ + assert(self); + self->iLock = 1; +} +/*--------------------------------------------------------------------*/ +void UnlockDeviceExecutor(pExeList self) +{ + assert(self); + self->iLock = 0; +} + diff --git a/devexec.h b/devexec.h index e464dd32..b6ece632 100644 --- a/devexec.h +++ b/devexec.h @@ -1,5 +1,5 @@ -#line 184 "devexec.w" +#line 195 "devexec.w" /*---------------------------------------------------------------------------- @@ -54,7 +54,7 @@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon, char *name); -#line 228 "devexec.w" +#line 239 "devexec.w" /*------------------------------------------------------------------------*/ @@ -73,7 +73,7 @@ void DevExecSignal(void *pEL, int iSignal, void *pSigData); -#line 230 "devexec.w" +#line 241 "devexec.w" /* @@ -115,7 +115,7 @@ int ContinueExecution(pExeList self); -#line 248 "devexec.w" +#line 259 "devexec.w" /*-------------------------- Commands ------------------------------------*/ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData, @@ -137,7 +137,16 @@ connection with non blocking operation such as motors started with run. */ - +/*--------------------------- Locking ---------------------------------*/ + +#line 183 "devexec.w" + + void LockDeviceExecutor(pExeList self); + void UnlockDeviceExecutor(pExeList self); + + +#line 281 "devexec.w" + /* -------------------------- Executor management -------------------------*/ pExeList GetExecutor(void); diff --git a/devexec.tex b/devexec.tex index 1f0a8c99..3fdef4fb 100644 --- a/devexec.tex +++ b/devexec.tex @@ -212,6 +212,29 @@ take care of invoking the apropriate commands on all registered counting devices. +\subsubsection{Locking the Device Executor} +In some instances user code may wish to lock the device executor. An +example is a long running data saving operation. In order to do this +two functions are provided: + +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap4} +$\langle$devlock {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\ +\mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} \subsubsection{The Rest} The rest of the interface includes initialisation and deletion routines and some access routines. With the devexec being such an important system @@ -219,7 +242,7 @@ component a function {\bf GetExecutor} is provided which retrieves a pointer to the global SICS device executor. \begin{flushleft} \small -\begin{minipage}{\linewidth} \label{scrap4} +\begin{minipage}{\linewidth} \label{scrap5} \verb@"devexec.h"@ {\footnotesize ? }$\equiv$ \vspace{-1ex} \begin{list}{}{} \item @@ -308,7 +331,8 @@ to the global SICS device executor. \mbox{}\verb@ connection with non blocking operation such as motors started@\\ \mbox{}\verb@ with run.@\\ \mbox{}\verb@ */@\\ -\mbox{}\verb@ @\\ +\mbox{}\verb@/*--------------------------- Locking ---------------------------------*/@\\ +\mbox{}\verb@ @$\langle$devlock {\footnotesize ?}$\rangle$\verb@ @\\ \mbox{}\verb@/* -------------------------- Executor management -------------------------*/@\\ \mbox{}\verb@ @\\ \mbox{}\verb@ pExeList GetExecutor(void);@\\ diff --git a/devexec.w b/devexec.w index d7ae34fe..48320103 100644 --- a/devexec.w +++ b/devexec.w @@ -175,6 +175,17 @@ take care of invoking the apropriate commands on all registered counting devices. +\subsubsection{Locking the Device Executor} +In some instances user code may wish to lock the device executor. An +example is a long running data saving operation. In order to do this +two functions are provided: + +@d devlock @{ + void LockDeviceExecutor(pExeList self); + void UnlockDeviceExecutor(pExeList self); + +@} + \subsubsection{The Rest} The rest of the interface includes initialisation and deletion routines and some access routines. With the devexec being such an important system @@ -266,7 +277,8 @@ to the global SICS device executor. connection with non blocking operation such as motors started with run. */ - +/*--------------------------- Locking ---------------------------------*/ + @ /* -------------------------- Executor management -------------------------*/ pExeList GetExecutor(void); diff --git a/drive.c b/drive.c index 1761c42e..4af6f72a 100644 --- a/drive.c +++ b/drive.c @@ -237,7 +237,7 @@ } } /*------------------------------------------------------------------------- - This is meant to be called specially from DriveWrapper at at stage when + This is meant to be called specially from DriveWrapper at a stage when we already know, that name is a drivable motor. Thus no error checking is performed. Do not use this in any other context!!!! */ @@ -253,7 +253,7 @@ char pBueffel[132]; /* - treat motors separatetly in order to correct for zero points + treat motors separately in order to correct for zero points Sighh......... */ pMot = FindMotor(pSics,name); diff --git a/event.h b/event.h index 416d6991..27a547d8 100644 --- a/event.h +++ b/event.h @@ -26,6 +26,7 @@ #define VALUECHANGE 0 #define MOTDRIVE 1 +#define MOTEND 13 #define MONITOR 2 #define ROTSTART 3 #define ROTMOVE 4 diff --git a/interface.h b/interface.h index fba9b139..b501949f 100644 --- a/interface.h +++ b/interface.h @@ -1,5 +1,5 @@ -#line 345 "interface.w" +#line 346 "interface.w" /*--------------------------------------------------------------------------- I N T E R F A C E S @@ -26,7 +26,7 @@ /* ----------------------- The drivable interface -----------------------*/ -#line 116 "interface.w" +#line 117 "interface.w" typedef struct { @@ -44,14 +44,14 @@ pIDrivable GetDrivableInterface(void *pObject); -#line 370 "interface.w" +#line 371 "interface.w" pIDrivable CreateDrivableInterface(void); /* ------------------------ The countable interface ---------------------*/ -#line 176 "interface.w" +#line 177 "interface.w" typedef struct { int ID; @@ -68,23 +68,23 @@ pICountable GetCountableInterface(void *pObject); -#line 375 "interface.w" +#line 376 "interface.w" pICountable CreateCountableInterface(void); /* ------------------------- The CallBack Interface --------------------*/ -#line 229 "interface.w" +#line 230 "interface.w" typedef void (*KillFuncIT)(void *pData); typedef int (*SICSCallBack)(int iEvent, void *pEventData, void *pUserData); -#line 380 "interface.w" +#line 381 "interface.w" -#line 251 "interface.w" +#line 252 "interface.w" typedef struct __ICallBack *pICallBack; @@ -99,11 +99,11 @@ int RemoveCallback(pICallBack pInterface, long iID); int RemoveCallback2(pICallBack pInterface, void *pUserData); -#line 381 "interface.w" +#line 382 "interface.w" /*---------------------- The Environment Interface --------------------*/ -#line 309 "interface.w" +#line 310 "interface.w" typedef enum { EVIdle, EVDrive, EVMonitor, EVError } EVMode; typedef struct { @@ -113,13 +113,13 @@ int (*HandleError)(void *self); } EVInterface, *pEVInterface; -#line 383 "interface.w" +#line 384 "interface.w" -#line 335 "interface.w" +#line 336 "interface.w" pEVInterface CreateEVInterface(void); -#line 384 "interface.w" +#line 385 "interface.w" #endif diff --git a/interface.tex b/interface.tex index 724888b9..a21afda1 100644 --- a/interface.tex +++ b/interface.tex @@ -60,6 +60,7 @@ $\langle$obdes {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ /*---------------------------------------------------------------------------*/@\\ \mbox{}\verb@ pObjectDescriptor CreateDescriptor(char *name);@\\ \mbox{}\verb@ void DeleteDescriptor(pObjectDescriptor self);@\\ +\mbox{}\verb@ pObjectDescriptor FindDescriptor(void *pData);@\\ \mbox{}\verb@ @\\ \mbox{}\verb@/*============================================================================@\\ \mbox{}\verb@ Objects which do not carry data need a dummy descriptor. Otherwise@\\ diff --git a/interface.w b/interface.w index 5e106038..9c515433 100644 --- a/interface.w +++ b/interface.w @@ -55,6 +55,7 @@ Let's start with the objectdescriptor: /*---------------------------------------------------------------------------*/ pObjectDescriptor CreateDescriptor(char *name); void DeleteDescriptor(pObjectDescriptor self); + pObjectDescriptor FindDescriptor(void *pData); /*============================================================================ Objects which do not carry data need a dummy descriptor. Otherwise diff --git a/motor.c b/motor.c index 0e9a5026..f951adeb 100644 --- a/motor.c +++ b/motor.c @@ -9,6 +9,7 @@ Mark Koennecke, November 1996 revised: Mark Koennecke, June 1997 callback added: Mark Koennecke, August 1997 + endscript facility added: Mark Koennecke, August 2002 Copyright: @@ -195,7 +196,9 @@ SCSetInterrupt(pCon,iVal); } } -/*--------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- + Refactor + --------------------------------------------------------------------------*/ static int MotorStatus(void *sulf, SConnection *pCon) { float fHard; @@ -250,6 +253,8 @@ /* motor thinks he is done */ if( (iRet == OKOK) || (iRet == HWIdle)) { + MotorGetSoftPosition(self,pCon,&sCall.fVal); + InvokeCallBack(self->pCall, MOTEND, &sCall); self->fPosition = fHard; if(absf(fHard - self->fTarget) > ObVal(self->ParArray,PREC)) { @@ -342,8 +347,7 @@ iRetry = 0; return iRet; } -/*---------------------------------------------------------------------------*/ - pMotor MotorInit(char *drivername, char *name, MotorDriver *pDriv) +/*---------------------------------------------------------------------------*/ pMotor MotorInit(char *drivername, char *name, MotorDriver *pDriv) { pMotor pM = NULL; @@ -380,6 +384,7 @@ ObParInit(pM->ParArray,ECOUNT,"failafter",3.0,usMugger); pDriv->GetPosition(pDriv,&(pM->fPosition)); pM->fTarget = pM->fPosition; + pM->endScriptID = 0; /* copy arguments */ pM->pDriver = pDriv; @@ -1027,7 +1032,32 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); SCWrite(pInfo->pCon,pBueffel,eValue); return 1; } - +/*------------------------------------------------------------------------*/ + static void KillScript(void *pData) + { + if(pData != NULL) + { + free(pData); + } + } +/*------------------------ The endscript callback function ----------------*/ + static int EndScriptCallback(int iEvent, void *pEvent, void *pUser) + { + char *pScript = NULL; + MotCallback *psCall; + char pCommand[1024]; + int iRet; + + assert(pEvent); + assert(pUser); + + psCall = (MotCallback *)pEvent; + pScript = (char *)pUser; + + sprintf(pCommand,"%s %f",pScript,psCall->fVal); + iRet = Tcl_Eval(pServ->pSics->pTcl,pCommand); + return iRet; + } /*---------------------------------------------------------------------------- The wrapper function for a motor. Commands currently supported are: @@ -1037,6 +1067,8 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); motorname reset : puts softlimits to default motorname interest : starts sending automatic notifications when driving + motorname endscript : script to call when motor + finishes driving -----------------------------------------------------------------------------*/ int MotorAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -1122,7 +1154,6 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); DeleteTokenList(pList); SCSendOK(pCon); return 1; - } else if(strcmp(pCurrent->text,"uninterest") == 0) { @@ -1131,6 +1162,31 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); DeleteTokenList(pList); return 1; } + else if(strcmp(pCurrent->text,"endscript") == 0) /* endscript */ + { + if(!SCMatchRights(pCon,usMugger)) + { + return 0; + } + if(self->endScriptID != 0) + { + RemoveCallback(self->pCall, self->endScriptID); + self->endScriptID = 0; + } + pCurrent = pCurrent->pNext; + if(!pCurrent) + { + SCWrite(pCon,"ERROR: scriptname argument missing",eError); + return 0; + } + self->endScriptID = + RegisterCallback(self->pCall, MOTEND, EndScriptCallback, + strdup(pCurrent->text), KillScript); + SCRegister(pCon,pSics, self->pCall,self->endScriptID); + DeleteTokenList(pList); + SCSendOK(pCon); + return 1; + } else /* one of the parameter commands or error left now */ { pName = pCurrent; diff --git a/motor.h b/motor.h index 139038f8..32f7afb7 100644 --- a/motor.h +++ b/motor.h @@ -24,6 +24,7 @@ MotorDriver *pDriver; float fTarget; float fPosition; + long endScriptID; } Motor; typedef Motor *pMotor; /*-------------------------------------------------------------------------*/ diff --git a/motreg.c b/motreg.c new file mode 100644 index 00000000..7fbeb0be --- /dev/null +++ b/motreg.c @@ -0,0 +1,125 @@ +/*------------------------------------------------------------------------- + R e g M o t + + This is a helper module for the Anti Collider. It handles all the + stuff necessary for dealing with a single motor. For more + information see the file anticollider.tex. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-----------------------------------------------------------------------*/ +#include +#include +#include "fortify.h" +#include "motreg.h" + +/*--------------------------------------------------------------------*/ +pMotReg RegisterMotor(char *name, SicsInterp *pSics, + long (*NewSetValue)(void *pData, SConnection *pCon, + float farget), + int (*NewCheckStatus)(void *pData,SConnection *pCon) ){ + CommandList *pCom = NULL; + pIDrivable pDriv = NULL; + pMotReg pNew = NULL; + + /* + find motor data structures + */ + pCom = FindCommand(pSics,name); + if(pCom == NULL){ + return NULL; + } + pDriv = GetDrivableInterface(pCom->pData); + if(pDriv == NULL){ + return NULL; + } + + /* + everything seems OK. Allocate data structure and initialize + */ + pNew = (pMotReg)malloc(sizeof(MotReg)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(MotReg)); + + pNew->motorData = pCom->pData; + pNew->motorName = strdup(name); + pNew->originalSetValue = pDriv->SetValue; + pNew->originalCheckStatus = pDriv->CheckStatus; + pNew->iActive = 0; + + pDriv->SetValue = NewSetValue; + pDriv->CheckStatus = NewCheckStatus; + + return pNew; +} +/*---------------------------------------------------------------------*/ +void KillRegMot(void *pData){ + pMotReg self = (pMotReg)pData; + + if(self == NULL){ + return; + } + if(self->motorName != NULL){ + free(self->motorName); + } + free(self); +} +/*------------------------------------------------------------------------*/ +void SetRegMotTarget(pMotReg self, float fValue){ + assert(self); + + self->targetPosition = fValue; + self->iActive = 1; +} +/*------------------------------------------------------------------------*/ +void CreateTargetString(pMotReg self, char pBueffel[80]) { + assert(self); + + if(strlen(self->motorName) + 20 < 80) { + sprintf(pBueffel," %s %12.4f ", self->motorName, self->targetPosition); + } +} +/*-----------------------------------------------------------------------*/ +int RegMotMatch(pMotReg self, char *name){ + assert(self); + if(strcmp(self->motorName, name) == 0) { + return 1; + } + return 0; +} +/*----------------------------------------------------------------------*/ +int StartRegMot(pMotReg self, SConnection *pCon, float fValue){ + int ret; + long (*oldSet)(void *pmotorData, SConnection *pCon, float fValue); + pIDrivable pDriv = NULL; + + + assert(self); + pDriv = GetDrivableInterface(self->motorData); + assert(pDriv); + oldSet = pDriv->SetValue; + pDriv->SetValue = self->originalSetValue; + ret = StartDevice(pServ->pExecutor, self->motorName, + FindDescriptor(self->motorData), + self->motorData, + pCon, + fValue); + + pDriv->SetValue = oldSet; + self->iActive = 1; + return ret; +} +/*----------------------------------------------------------------------*/ +int CheckRegMot(pMotReg self, SConnection *pCon){ + int stat; + + assert(self); + stat = self->originalCheckStatus(self->motorData,pCon); + if(stat != HWBusy){ + self->iActive = 0; + } + return stat; +} diff --git a/motreg.h b/motreg.h new file mode 100644 index 00000000..457abb97 --- /dev/null +++ b/motreg.h @@ -0,0 +1,52 @@ + +/*------------------------------------------------------------------------- + R e g M o t + + This is a helper module for the Anti Collider. It handles all the + stuff necessary for dealing with a single motor. For more + information see the file anticollider.tex. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-----------------------------------------------------------------------*/ +#ifndef REGMOT +#define REGMOT +#include "sics.h" + + + +typedef struct __MOTREG { + void *motorData; + char *motorName; + float targetPosition; + long (*originalSetValue)(void *motorData, + SConnection *pCon, + float fTarget); + int (*originalCheckStatus)(void *motorData, + SConnection *pCon); + int iActive; + } MotReg, *pMotReg; + + +/*----------------------------------------------------------------------*/ + + pMotReg RegisterMotor(char *name, SicsInterp *pSics, + long (*SetValue)(void *pData, SConnection *pCon, float + fTarget), + int (*CheckStatus)(void *pData, SConnection *pCon)); + void KillRegMot(void *self); + + void SetRegMotTarget(pMotReg self, float target); + void CreateTargetString(pMotReg self, char pBueffel[80]); + + int RegMotMatch(pMotReg self, char *name); + + int StartRegMot(pMotReg self, SConnection *pCon, float fValue); + + int CheckRegMot(pMotReg self, SConnection *pCon); + + + +#endif + diff --git a/motreglist.c b/motreglist.c new file mode 100644 index 00000000..468c200f --- /dev/null +++ b/motreglist.c @@ -0,0 +1,86 @@ +/*----------------------------------------------------------------------- + A couple of utility functions for handling a list of MotReg + structures . This is a helper module for the anticollider collision + control system. See anticollider.tex for more details. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-------------------------------------------------------------------------*/ +#include +#include +#include "fortify.h" +#include "lld.h" +#include "motreglist.h" + +/*-----------------------------------------------------------------------*/ +int MakeMotList(){ + return LLDcreate(sizeof(pMotReg)); +} +/*----------------------------------------------------------------------*/ +pMotReg FindMotEntry(int iList, char *name){ + int iRet; + pMotReg pMot = NULL; + + iRet = LLDnodePtr2First(iList); + while(iRet != 0){ + LLDnodeDataTo(iList,&pMot); + if(pMot != NULL){ + if(RegMotMatch(pMot,name)){ + return pMot; + } + } + iRet = LLDnodePtr2Next(iList); + } + return NULL; +} +/*-----------------------------------------------------------------------*/ +pMotReg FindMotFromDataStructure(int iList, void *pData){ + int iRet; + pMotReg pMot = NULL; + + iRet = LLDnodePtr2First(iList); + while(iRet != 0){ + LLDnodeDataTo(iList,&pMot); + if(pMot != NULL){ + if(pMot->motorData == pData){ + return pMot; + } + } + iRet = LLDnodePtr2Next(iList); + } + return NULL; +} +/*----------------------------------------------------------------------*/ +int CheckAllMotors(int iList, SConnection *pCon){ + int iRet, count = 0; + pMotReg pMot = NULL; + + iRet = LLDnodePtr2First(iList); + while(iRet != 0){ + LLDnodeDataTo(iList,&pMot); + if(pMot != NULL){ + CheckRegMot(pMot,pCon); + if(pMot->iActive){ + count++; + } + } + iRet = LLDnodePtr2Next(iList); + } + return count; +} +/*----------------------------------------------------------------------*/ +void KillMotList(int iList){ + int iRet; + pMotReg pMot = NULL; + + iRet = LLDnodePtr2First(iList); + while(iRet != 0){ + LLDnodeDataTo(iList,&pMot); + if(pMot != NULL){ + KillRegMot(pMot); + } + iRet = LLDnodePtr2Next(iList); + } + LLDdelete(iList); +} diff --git a/motreglist.h b/motreglist.h new file mode 100644 index 00000000..a148e708 --- /dev/null +++ b/motreglist.h @@ -0,0 +1,27 @@ + +/*----------------------------------------------------------------------- + A couple of utility functions for handling a list of MotReg + structures . This is a helper module for the anticollider collision + control system. See anticollider.tex for more details. + + copyright: see file copyright + + Mark Koennecke, August 2002 +-------------------------------------------------------------------------*/ +#ifndef MOTREGLIST +#define MOTREGLIST + +#include "motreg.h" + + + int MakeMotList(); + pMotReg FindMotEntry(int iList,char *name); + pMotReg FindMotFromDataStructure(int iList, void *pData); + int CheckAllMotors(int iList, SConnection *pCon); + void KillMotList(int iList); + + + +#endif + + diff --git a/nxamor.c b/nxamor.c index 178acde7..57f97733 100644 --- a/nxamor.c +++ b/nxamor.c @@ -24,6 +24,7 @@ #include "nxamor.h" #include "obpar.h" #include "motor.h" +#include "status.h" #define MAXMOT 13 /* must be same as in amor2t.c */ #include "amor2t.i" @@ -662,6 +663,7 @@ static int WriteTOFDetector(char *name, pHistMem pHM, int *iDim, { char pBueffel[512], *pFile = NULL; int iRet, iFlag; + Status oldStatus; /* if arguments, check for psdsave @@ -685,11 +687,17 @@ static int WriteTOFDetector(char *name, pHistMem pHM, int *iDim, pFile = SNXMakeFileName(pSics,pCon); sprintf(pBueffel,"Writing file %s .....",pFile); SCWrite(pCon,pBueffel,eWarning); + + oldStatus = GetStatus(); + SetStatus(eWriting); + LockDeviceExecutor(pServ->pExecutor); iRet = WriteAmorHeader(pFile,pCon); if(iRet) { iRet = WriteAmorTOF(pFile,pCon,pMeme); } + SetStatus(oldStatus); + UnlockDeviceExecutor(pServ->pExecutor); free(pFile); SCSendOK(pCon); return iRet; diff --git a/obdes.c b/obdes.c index bc547bf7..44a562c7 100644 --- a/obdes.c +++ b/obdes.c @@ -133,3 +133,12 @@ } return 0; } +/*------------------------------------------------------------------------*/ +pObjectDescriptor FindDescriptor(void *pData) +{ + pDummy pDum = NULL; + + assert(pData); + pDum = (pDummy)pData; + return pDum->pDescriptor; +} diff --git a/obdes.h b/obdes.h index 249dc2a0..76443e59 100644 --- a/obdes.h +++ b/obdes.h @@ -1,5 +1,5 @@ -#line 341 "interface.w" +#line 342 "interface.w" #line 29 "interface.w" @@ -32,6 +32,7 @@ /*---------------------------------------------------------------------------*/ pObjectDescriptor CreateDescriptor(char *name); void DeleteDescriptor(pObjectDescriptor self); + pObjectDescriptor FindDescriptor(void *pData); /*============================================================================ Objects which do not carry data need a dummy descriptor. Otherwise @@ -51,5 +52,5 @@ typedef struct { #endif -#line 342 "interface.w" +#line 343 "interface.w" diff --git a/obpar.c b/obpar.c index 26f5f6e2..ad24d09d 100644 --- a/obpar.c +++ b/obpar.c @@ -167,7 +167,7 @@ eStat = GetStatus(); if(!((eStat == eEager) || (eStat == eBatch)) ) { - sprintf(pBueffel,"ERROR: Cannot cahnge parameter while running"); + sprintf(pBueffel,"ERROR: Cannot change parameter while running"); SCWrite(pCon, pBueffel,eError); return 0; } diff --git a/ofac.c b/ofac.c index 5079f931..e5d37508 100644 --- a/ofac.c +++ b/ofac.c @@ -107,6 +107,7 @@ #include "rs232controller.h" #include "lomax.h" #include "polterwrite.h" +#include "anticollider.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -289,6 +290,7 @@ AddCommand(pInter,"MakeRS232Controller",RS232Factory,NULL,NULL); AddCommand(pInter,"MakeMaxDetector",LoMaxFactory,NULL,NULL); AddCommand(pInter,"PolterInstall",PolterInstall,NULL,NULL); + AddCommand(pInter,"AntiCollisionInstall",AntiColliderFactory,NULL,NULL); } /*---------------------------------------------------------------------------*/ static void KillIniCommands(SicsInterp *pSics) @@ -348,6 +350,7 @@ RemoveCommand(pSics,"MakeRS232Controller"); RemoveCommand(pSics,"MakeMaxDetector"); RemoveCommand(pSics,"PolterInstall"); + RemoveCommand(pSics,"AntiColliderInstall"); } diff --git a/polterwrite.c b/polterwrite.c index 0bc0b627..76ed92f2 100644 --- a/polterwrite.c +++ b/polterwrite.c @@ -489,8 +489,8 @@ static int PoldiStart(pPolterdi self, SConnection *pCon) long lVal; /* open everything again */ - NXopen(self->pFile,NXACC_RDWR,&hfil); - if(!self->pFile) + status = NXopen(self->pFile,NXACC_RDWR,&hfil); + if(status != NX_OK) { SCWrite(pCon,"ERROR: cannot reopen data file ",eError); return; diff --git a/sics.h b/sics.h index 1e3a3e24..ebc9c1ce 100644 --- a/sics.h +++ b/sics.h @@ -29,6 +29,7 @@ #include "emon.h" #include "nserver.h" #include "servlog.h" + extern pServer pServ; diff --git a/sicsstatus.tcl b/sicsstatus.tcl index 9d303acc..3e28b14c 100644 --- a/sicsstatus.tcl +++ b/sicsstatus.tcl @@ -1,48 +1,75 @@ -a5l.length 80.000000 -flightpathlength 0.000000 -flightpathlength setAccess 1 -flightpath 0.000000 -flightpath setAccess 1 -delay 2500.000000 -delay setAccess 1 -hm CountMode timer -hm preset 100.000000 -hm genbin 120.000000 35.000000 512 -hm init -datafile focus-1001848.hdf -datafile setAccess 3 +yfactor 1.420000 +yfactor setAccess 1 +xfactor 0.715000 +xfactor setAccess 1 +ps.listfile peaksearch.dat +ps.listfile setAccess 2 +ps.scansteps 24 +ps.scansteps setAccess 2 +ps.scanpreset 1000000.000000 +ps.scanpreset setAccess 2 +ps.preset 1000.000000 +ps.preset setAccess 2 +ps.countmode monitor +ps.countmode setAccess 2 +ps.cogcontour 0.200000 +ps.cogcontour setAccess 2 +ps.cogwindow 60 +ps.cogwindow setAccess 2 +ps.window 7 +ps.window setAccess 2 +ps.steepness 3 +ps.steepness setAccess 2 +ps.threshold 30 +ps.threshold setAccess 2 +ps.sttstep 3.000000 +ps.sttstep setAccess 2 +ps.sttend 70.000000 +ps.sttend setAccess 2 +ps.sttstart 5.000000 +ps.sttstart setAccess 2 +ps.omstep 3.000000 +ps.omstep setAccess 2 +ps.omend 30.000000 +ps.omend setAccess 2 +ps.omstart 0.000000 +ps.omstart setAccess 2 +ps.chistep 12.000000 +ps.chistep setAccess 2 +ps.chiend 180.000000 +ps.chiend setAccess 2 +ps.chistart 0.000000 +ps.chistart setAccess 2 +ps.phistep 3.000000 +ps.phistep setAccess 2 +ps.phiend 180.000000 +ps.phiend setAccess 2 +ps.phistart 0.000000 +ps.phistart setAccess 2 +hm3 CountMode timer +hm3 preset 10.000000 hm2 CountMode timer -hm2 preset 3600.000000 +hm2 preset 10.000000 hm1 CountMode timer -hm1 preset 3600.000000 -dbfile UNKNOWN -dbfile setAccess 2 -# Motor th -th sign 1.000000 -th SoftZero 0.000000 -th SoftLowerLim 4.000000 -th SoftUpperLim 113.000000 -th Fixed -1.000000 -th InterruptMode 0.000000 -th AccessCode 2.000000 +hm1 preset 10.000000 #Crystallographic Settings hkl lambda 1.179000 hkl setub -0.017880 -0.074923 0.028280 -0.007008 -0.036800 -0.057747 0.160912 -0.009928 0.000627 hkl hm 0 -det3dist 300.000000 -det3dist setAccess 1 +detdist3 0.000000 +detdist3 setAccess 1 det3zeroy 128.000000 det3zeroy setAccess 1 det3zerox 128.000000 det3zerox setAccess 1 -det2dist 300.000000 -det2dist setAccess 1 +detdist2 0.000000 +detdist2 setAccess 1 det2zeroy 128.000000 det2zeroy setAccess 1 det2zerox 128.000000 det2zerox setAccess 1 -det1dist 300.000000 -det1dist setAccess 1 +detdist1 0.000000 +detdist1 setAccess 1 det1zeroy 128.000000 det1zeroy setAccess 1 det1zerox 128.000000 @@ -71,7 +98,7 @@ stt AccessCode 2.000000 ch sign 1.000000 ch SoftZero 0.000000 ch SoftLowerLim 0.000000 -ch SoftUpperLim 212.000000 +ch SoftUpperLim 190.000000 ch Fixed -1.000000 ch InterruptMode 0.000000 ch AccessCode 1.000000 @@ -127,7 +154,7 @@ phi AccessCode 2.000000 chi sign 1.000000 chi SoftZero 0.000000 chi SoftLowerLim 0.000000 -chi SoftUpperLim 212.000000 +chi SoftUpperLim 190.000000 chi Fixed -1.000000 chi InterruptMode 0.000000 chi AccessCode 1.000000 @@ -149,8 +176,6 @@ twotheta InterruptMode 0.000000 twotheta AccessCode 2.000000 lastscancommand cscan a4 10. .1 10 5 lastscancommand setAccess 2 -banana CountMode timer -banana preset 100.000000 sample_mur 0.000000 sample_mur setAccess 2 email UNKNOWN @@ -428,13 +453,11 @@ a1 SoftUpperLim 120.000000 a1 Fixed -1.000000 a1 InterruptMode 0.000000 a1 AccessCode 2.000000 -batchroot /data/koenneck/src/sics -batchroot setAccess 2 user Uwe Filges user setAccess 2 sample D20 30K SNP Okt 2001 GS sample setAccess 2 -title snp gs apd 30K +title endtest called with 23.000000 :Driving: title setAccess 2 -starttime 2002-04-23 10:49:18 +starttime 2002-08-07 08:09:45 starttime setAccess 2 diff --git a/status.c b/status.c index 5a411c6c..767bf759 100644 --- a/status.c +++ b/status.c @@ -59,6 +59,7 @@ "Driving", "Running", "Running a scan", + "Writing data", "Processing a batch file", "Halted", "Dead", @@ -74,6 +75,7 @@ "driving", "running", "scanning", + "writing", "batch", "halt", "dead", diff --git a/status.h b/status.h index c789ae15..1d924560 100644 --- a/status.h +++ b/status.h @@ -17,6 +17,7 @@ eDriving, eRunning, eScanning, + eWriting, eBatch, eHalted, eDead,