From 3ba5f28b65de5d6ba96e2cdfb5bc2aa962cb75d5 Mon Sep 17 00:00:00 2001 From: cvs Date: Wed, 14 Aug 2002 14:24:00 +0000 Subject: [PATCH] - First working version of the TRICS collision protection module --- Busy.c | 115 +++++++++++++++ Busy.h | 28 ++++ Busy.w | 41 ++++++ Makefile | 2 +- SCinter.c | 19 +++ SCinter.h | 8 ++ anticollider.c | 375 +++++++++++++++++++++++++++++++++++++++++++++++++ anticollider.h | 25 ++++ anticollider.w | 275 ++++++++++++++++++++++++++++++++++++ danu.dat | 2 +- devexec.c | 27 +++- devexec.h | 19 ++- devexec.tex | 28 +++- devexec.w | 14 +- drive.c | 4 +- event.h | 1 + interface.h | 26 ++-- interface.tex | 1 + interface.w | 1 + motor.c | 66 ++++++++- motor.h | 1 + motreg.c | 125 +++++++++++++++++ motreg.h | 52 +++++++ motreglist.c | 86 ++++++++++++ motreglist.h | 27 ++++ nxamor.c | 8 ++ obdes.c | 9 ++ obdes.h | 5 +- obpar.c | 2 +- ofac.c | 3 + polterwrite.c | 4 +- sics.h | 1 + sicsstatus.tcl | 101 ++++++++----- status.c | 2 + status.h | 1 + 35 files changed, 1427 insertions(+), 77 deletions(-) create mode 100644 Busy.c create mode 100644 Busy.h create mode 100644 Busy.w create mode 100644 anticollider.c create mode 100644 anticollider.h create mode 100644 anticollider.w create mode 100644 motreg.c create mode 100644 motreg.h create mode 100644 motreglist.c create mode 100644 motreglist.h 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,