From b3138f1197f06346d6e9b0fbb2e1cce90000f377 Mon Sep 17 00:00:00 2001 From: koennecke Date: Thu, 22 Dec 2005 22:16:10 +0000 Subject: [PATCH] - Added Sycamore protocol and command context to SICS - Added sinfo to SICS - Added driver for TCP/IP Astrium velocity selector - Added driver for TCP/IP Astrium chopper controller SKIPPED: psi/amor2t.c psi/amorstat.c psi/dornier2.c psi/ecb.c psi/el734hp.c psi/fowrite.c psi/libpsi.a psi/make_gen psi/nextrics.c psi/pardef.c psi/pimotor.c psi/pipiezo.c psi/polterwrite.c psi/psi.c psi/scontroller.c psi/serial.c psi/tasinit.c psi/tasscan.c psi/tcpdocho.c psi/tcpdornier.c psi/tricssupport.c psi/velodornier.c --- SCinter.c | 305 ++++++++- SCinter.h | 1 - Scommon.h | 3 + callback.c | 14 +- commandcontext.h | 16 + configfu.h | 6 +- conman.c | 166 ++++- conman.h | 26 + counter.c | 7 +- danu.c | 8 +- devexec.c | 66 +- doc/user/velocity.htm | 2 + evcontroller.c | 40 +- event.h | 3 +- exeman.c | 18 +- fourlib.c | 53 ++ fourlib.h | 6 +- histmem.c | 104 +++- hkl.c | 35 +- ifile.c | 22 + ifile.h | 2 + interface.c | 1 + interface.h | 41 +- interface.tex | 137 +++-- interface.w | 21 +- lin2ang.c | 44 +- lin2ang.w | 2 + linux_def | 2 +- macro.c | 13 +- make_gen | 3 +- makefile_linux | 15 +- mcstas/dmc/DataNumber | 2 +- mcstas/dmc/mcsupport.tcl | 17 +- mcstas/dmc/vdmc.tcl | 18 +- mcstas/dmc/vdmccom.tcl | 10 +- mcstas/dmc/vdmcstatus.tcl | 6 +- motor.c | 61 +- nserver.c | 34 +- nxupdate.c | 10 +- obdes.c | 88 ++- obdes.h | 52 +- ofac.c | 10 +- outcode.c | 5 +- perfmon.c | 8 +- protocol.c | 616 +++++++++++++++++++ protocol.h | 34 ++ rs232controller.c | 51 ++ rs232controller.h | 2 + scan.c | 43 +- selvar.c | 13 +- servlog.c | 110 ++-- sicsstat.tcl | 230 ------- sicvar.c | 21 +- sinfo.tcl | 387 ++++++++++++ sinfox.c | 1221 +++++++++++++++++++++++++++++++++++++ sinfox.h | 115 ++++ status.c | 8 +- stptok.h | 18 + sycFormat.tcl | 91 +++ sycamore.tcl | 219 +++++++ task.c | 2 +- task.h | 2 +- tclmotdriv.c | 395 ++++++++++++ tclmotdriv.h | 41 ++ velo.c | 207 +++---- velo.h | 1 - viscom.tcl | 2 +- 67 files changed, 4650 insertions(+), 682 deletions(-) create mode 100644 commandcontext.h create mode 100644 protocol.c create mode 100644 protocol.h create mode 100644 sinfo.tcl create mode 100644 sinfox.c create mode 100644 sinfox.h create mode 100644 stptok.h create mode 100644 sycFormat.tcl create mode 100644 sycamore.tcl create mode 100644 tclmotdriv.c create mode 100644 tclmotdriv.h diff --git a/SCinter.c b/SCinter.c index 328222ff..4e08874f 100644 --- a/SCinter.c +++ b/SCinter.c @@ -2,8 +2,6 @@ Implementation file for the SICS-interpreter. - - Mark Koennecke, November 1996 Made ListObjects more intelligent: list objects according to interface etc. @@ -42,6 +40,16 @@ M. Zolliker, Sept 2000, introduced formal aliases, modifications marked M.Z Mark Koennecke, August 2001, modified SicsWriteStatus to write motor positions on demand. + + Made ListObjects moe intelligent: list objects according to interface etc. + Mark Koennecke, December 2003 + + Extended 'dir' command (function ListObjects) to list via typename from + object descriptor. For completeness, added function PrintAllTypes. + Paul Hathaway, May 2004 + + Modified printXXX functions to fix duplicate write of last buffer line. + Paul Hathaway, May 2004 ---------------------------------------------------------------------------*/ #include #include @@ -61,6 +69,15 @@ /* M.Z. */ #include "definealias.h" +/* pvh */ +#include "lld_str.h" +static void printList(SConnection *pCon, int listID); +static void freeList(int listID); +int compareStringNode(void *pStr1, void **ppStr2); + +#define MAXLEN 256 +#define MAXPAR 100 +#define MAXBUF 128 /*--------------------------------------------------------------------------*/ SicsInterp *InitInterp(void) @@ -219,22 +236,11 @@ return 1; } - -/*------------------------------------------------------------------------*/ - void RemoveStartupCommands(void) - { - CommandList *pCurrent, *pNext; - pCurrent = pServ->pSics->pCList; - while(pCurrent) - { - pNext = pCurrent->pNext; - if (pCurrent->startupOnly) { - RemoveCommand(pServ->pSics, pCurrent->pName); - } - pCurrent = pNext; - } - } -/*------------------------------------------------------------------------*/ +#define MAXLEN 256 +#define MAXCOM 50 +extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk); +extern char *SkipSpace(char *pPtr); +/*-----------------------------------------------------------------------*/ int InterpExecute(SicsInterp *self,SConnection *pCon, char *pText) { int iCount = 0; @@ -275,6 +281,7 @@ iRet = 1; goto deleteArgv; } + if(argv[0] == NULL) { SCWrite(pCon,"ERROR: failed to parse command",eError); @@ -298,7 +305,13 @@ self->eOut = eStatus; Tcl_ResetResult((Tcl_Interp *)self->pTcl); MacroPush(pCon); + SCWrite(pCon, "", eStart); + pCon->conStatus = 0; iRet = pCommand->OFunc(pCon, self, pCommand->pData, argc, argv); + /* If a task is registered with the dev exec then conStatus is HWBusy*/ + if (pCon->conStatus != HWBusy) { + SCWrite(pCon,"",eFinish); + } MacroPop(); deleteArgv: @@ -519,6 +532,74 @@ static void printAll(SicsInterp *pSics, SConnection *pCon) SCWrite(pCon,pBueffel,eStatus); } } +/*------------------------------------------------------------------------ + printAllTypes prints the list of types of objects instantiated on the + CommandList. + iFiltered=0 gives all objects including interpreter command objects + iFiltered=1 gives types where object name is not the same as its type + -------------------------------------------------------------------------*/ +static void printAllTypes(SicsInterp *pSics, SConnection *pCon, int iFiltered) +{ + CommandList *pCurrent = NULL; + char pBueffel[256]; + char pName_lc[256]; + char pType_lc[256]; + char *pType; + Dummy *pTest; + int typeListID; + + assert(pSics); + assert(pCon); + + pBueffel[0] = '\0'; + + typeListID = LLDstringCreate(); + if(-1==typeListID) + { + strcpy(pBueffel,"ERROR: Cannot generate list of object types\r\n"); + SCWrite(pCon,pBueffel,eStatus); + return; + } + + pCurrent = pSics->pCList; + while(pCurrent) + { + if(NULL != pCurrent->pData) + { + pTest = (pDummy)pCurrent->pData; + if(NULL != pTest->pDescriptor) + { + pType = pTest->pDescriptor->name; + strcpy(pType_lc,pType); + strtolower(pType_lc); + + LLDnodePtr2First(typeListID); + + /* int LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr ); */ + /* */ + /* Find *DataPtr in the List using the *Compare function. */ + /* Returns the return value of *Compare. */ + /* 0 == equal == found. */ + /* non-zero == not found. Current node is set to found node. */ + /* Returns 2 for an empty list. */ + /* NB: First checked node is current node, then search to end of list*/ + + if(0!=LLDnodeFind(typeListID,compareStringNode,(void *)pType)) + { /* empty list or 'typename' not found */ + strcpy(pName_lc, pCurrent->pName); + strtolower(pName_lc); + if((0==iFiltered)||((1==iFiltered)&&(0!=strcmp(pType_lc,pName_lc)))) + { /*ie Add if unfiltered or pass filter(name!=typename) */ + LLDstringAdd(typeListID,pType); + } + } + } + } + pCurrent = pCurrent->pNext; + } + printList(pCon,typeListID); + freeList(typeListID); +} /*----------------------------------------------------------------------- printInterface prints only those objects which implement an interface as specified bi the id given @@ -625,9 +706,9 @@ static void printMatch(SicsInterp *pSics, SConnection *pCon, char *mask) SCWrite(pCon,pBueffel,eStatus); } /*----------------------------------------------------------------------- - printType prints only those objects which match the type given + printType prints only those objects whose descriptor match the type given -------------------------------------------------------------------------*/ -static void printType(SicsInterp *pSics, SConnection *pCon, char *type) +static void printType(SicsInterp *pSics, SConnection *pCon, char *typeName) { CommandList *pCurrent; Tcl_DString txt; @@ -644,7 +725,7 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *type) { if(pCurrent->pData != NULL) { - if(iHasType(pCurrent->pData,type)) + if(iHasType(pCurrent->pData,typeName)) { if(iNum == 0) { @@ -680,6 +761,8 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *type) int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { + char pType[256]; + int i; if(argc < 2) { @@ -701,6 +784,13 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *type) printType(pSics,pCon,"Motor"); return 1; } + /* Start Mod by Paul Hathaway May 2004 */ + if(0 == strcmp(argv[1],"types")) + { + printAllTypes(pSics,pCon,1); + return 1; + } + /* End Mod by Paul Hathaway May 2004*/ /* @@ -745,6 +835,33 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *type) printMatch(pSics,pCon,argv[2]); return 1; } + + /* Start Mod by Paul Hathaway May 2004 */ + /* + * type-based dir + */ + if(0 == strcmp(argv[1],"type")) + { + if(0==strcmp(argv[2],"*")) + { + printAllTypes(pSics,pCon,0); + return 1; + } + strcpy(pType,argv[2]); + /* Cater for multi-word types eg 'Environment Monitor' */ + if(argc > 3) + { + for(i=3;i retCode) { + retCode = LLDstringData(listID,pBueffel); + strcat(pBueffel,"\r\n"); + SCWrite(pCon,pBueffel,eStatus); + } + } while(0!=LLDnodePtr2Next(listID)); + } +} + +/*------------------------------------------------------------------------*/ +static void freeList(int listID) +{ + do { + LLDstringDelete(listID); + } while(0!=LLDnodePtr2First(listID)); + LLDdelete(listID); +} + +/*------------------------------------------------------------------------*/ +/* compareStringNode wraps strcmp for use in findNode(LLD module) calls */ +int compareStringNode(void *pStr1, void **ppStr2) +{ + return strcmp((char *)pStr1,(char *)(*ppStr2)); +} +/*------------------------------------------------------------------------*/ + void RemoveStartupCommands(void) + { + CommandList *pCurrent, *pNext; + pCurrent = pServ->pSics->pCList; + while(pCurrent) + { + pNext = pCurrent->pNext; + if (pCurrent->startupOnly) { + RemoveCommand(pServ->pSics, pCurrent->pName); + } + pCurrent = pNext; + } + } +/*----------------------------------------------------------------------*/ +static int handleGet(SConnection *pCon,SicsInterp *pSics, int argc, + char *argv[]){ + CommandList *obj = NULL; + pDummy pDum = NULL; + char pBueffel[512]; + char *pPtr = NULL; + + if(argc < 4){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to SicsAtt get", + eError); + return 0; + } + + obj = FindCommand(pSics,argv[2]); + if(obj == NULL){ + snprintf(pBueffel,511,"ERROR: object %s not found",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + pDum = obj->pData; + if(pDum == NULL){ + snprintf(pBueffel,511,"%s has no data, is command", argv[2]); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + strtolower(argv[3]); + if(strcmp(argv[3],"type") == 0){ + snprintf(pBueffel,511, "%s.type = %s", argv[2], pDum->pDescriptor->name); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + pPtr = GetDescriptorKey(pDum->pDescriptor, argv[3]); + if(pPtr == NULL){ + snprintf(pBueffel,511,"%s.%s = Undefined", argv[0], argv[3]); + } else { + snprintf(pBueffel,511,"%s.%s = %s", argv[0], argv[3], pPtr); + } + SCWrite(pCon,pBueffel,eValue); + return 1; + } +} +/*----------------------------------------------------------------------*/ +static int handleSet(SConnection *pCon,SicsInterp *pSics, int argc, + char *argv[]){ + CommandList *obj = NULL; + pDummy pDum = NULL; + char pBueffel[512]; + char *pPtr = NULL; + + if(argc < 5){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to SicsAtt set", + eError); + return 0; + } + + obj = FindCommand(pSics,argv[2]); + if(obj == NULL){ + snprintf(pBueffel,511,"ERROR: object %s not found",argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + pDum = obj->pData; + if(pDum == NULL){ + snprintf(pBueffel,511,"%s has no data, is command", argv[2]); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + strtolower(argv[3]); + pDum->pDescriptor->pKeys = IFSetOption(pDum->pDescriptor->pKeys, argv[3], argv[4]); + SCSendOK(pCon); + return 1; +} +/*-----------------------------------------------------------------------*/ +int SicsAtt(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + CommandList *current = NULL; + pDummy pDum = NULL; + + if(argc < 2){ + SCWrite(pCon,"ERROR: insufficient number of argumens to SicsAtt",eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"get") == 0) { + return handleGet(pCon, pSics, argc, argv); + } else if(strcmp(argv[1],"set") == 0){ + return handleSet(pCon,pSics,argc, argv); + } + return 0; +} diff --git a/SCinter.h b/SCinter.h index 3d759c22..dacaf28d 100644 --- a/SCinter.h +++ b/SCinter.h @@ -87,7 +87,6 @@ typedef struct __SINTER If the command is found, 1 is returned on success, 0 on failure in the command. ----------------------------------------------------------------------------*/ - CommandList *FindCommand(SicsInterp *pInterp, char *name); /* Searches the Interpreters pInterp command list for a command diff --git a/Scommon.h b/Scommon.h index c5b25368..6b466d14 100644 --- a/Scommon.h +++ b/Scommon.h @@ -46,6 +46,9 @@ typedef enum { eInError, eStatus, eValue, + eStart, + eFinish, + eEvent, eWarning, eError } OutCode; diff --git a/callback.c b/callback.c index a407fb5f..beffabab 100644 --- a/callback.c +++ b/callback.c @@ -64,6 +64,7 @@ void *pUserData; KillFuncIT pKill; int iEvent; + commandContext comCon; } CallBackItem, *pCallBackItem; /*------------------------------------------------------------------------*/ static int CheckPointer(pICallBack self) @@ -140,7 +141,7 @@ LLDnodeDataTo(self->iList,&sItem); if(sItem.iEvent == iEvent) { - iRet = sItem.pFunc(iEvent, pEventData,sItem.pUserData); + iRet = sItem.pFunc(iEvent, pEventData,sItem.pUserData,sItem.comCon); if(!iRet) { iResult = 0; @@ -153,7 +154,7 @@ /*--------------------------------------------------------------------------*/ static long lCount = 1L; - long RegisterCallback(pICallBack self, int iEvent, + long RegisterCallback(pICallBack self, commandContext comCon, int iEvent, SICSCallBack pFunc, void *pUserData, KillFunc pKFunc) { @@ -170,7 +171,8 @@ sItem.iEvent = iEvent; sItem.pUserData = pUserData; sItem.pKill = pKFunc; - + sItem.comCon = comCon; + LLDnodeAppendFrom(self->iList,&sItem); return sItem.iID; } @@ -244,7 +246,8 @@ static int CallbackWrite(SConnection *pCon,char *message, int outCode) /*----------------------------------------------------------------------- the actual callback function invoking the script ------------------------------------------------------------------------*/ -static int ScriptCallback(int iEvent, void *pEventData, void *pUserData) +static int ScriptCallback(int iEvent, void *pEventData, void *pUserData, + commandContext cc) { SConnection *pCon = NULL; Tcl_Interp *pTcl; @@ -332,7 +335,8 @@ int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData, return 0; } Arg2Text(argc-4,&argv[4],pBuffer,131); - lID = RegisterCallback(pCall,iEvent,ScriptCallback, + lID = RegisterCallback(pCall,SCGetContext(pCon), + iEvent,ScriptCallback, strdup(pBuffer),free); sprintf(pBuffer,"callback = %ld", lID); SCWrite(pCon,pBuffer,eValue); diff --git a/commandcontext.h b/commandcontext.h new file mode 100644 index 00000000..1a293ba9 --- /dev/null +++ b/commandcontext.h @@ -0,0 +1,16 @@ +/*------------------------------------------------- + This file holds the command context structure which + is needed to make the sycamore protocol work. + + Mark Koennecke, December 2005 + -------------------------------------------------*/ +#ifndef SICSCOMCONTEXT +#define SICSCOMCONTEXT + +typedef struct{ + int transID; + char deviceID[256]; + }commandContext, *pCommandContext; +#define SCDEVIDLEN 256 + +#endif diff --git a/configfu.h b/configfu.h index 6b9e252b..998e7567 100644 --- a/configfu.h +++ b/configfu.h @@ -19,8 +19,12 @@ int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); - /* lists all avialable objects. Realised in Scinter.c */ + int SicsAtt(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + /* + handling of SICS object attributes. In SCinter.c + */ #endif diff --git a/conman.c b/conman.c index 29cd99c0..27822689 100644 --- a/conman.c +++ b/conman.c @@ -88,7 +88,6 @@ extern pServer pServ; /*------------- a number for generating automatic names --------------------*/ static int iName = 0; - static int SCNormalWrite(SConnection *self, char *buffer, int iOut); static SConnection *freeConnections = NULL; static long lastIdent = 0; /*===========================================================================*/ @@ -167,25 +166,31 @@ extern pServer pServ; return NULL; } - pRes->iOutput = eInError; /* gets everything except internal messages */ - pRes->iFiles = 0; /* default: no logfiles */ - pRes->inUse = 0; - pRes->iMacro = 0; - pRes->iTelnet = 0; - pRes->eInterrupt = eContinue; - pRes->lMagic = CONMAGIC; - pRes->iLogin = 0; - pRes->listening = 0; - pRes->conStart = time(NULL); - pRes->write = SCNormalWrite; - for(i = 0; i < 10; i++) - { - pRes->pFiles[i] = NULL; - } - - /* install command */ - AddCommand(pSics, ConName(pRes->ident), ConSicsAction, NULL,pRes); - return pRes; + pRes->iOutput = eInError; /* gets everything except internal messages */ + pRes->iFiles = 0; /* default: no logfiles */ + pRes->inUse = 0; + pRes->iMacro = 0; + pRes->iTelnet = 0; + pRes->eInterrupt = eContinue; + pRes->lMagic = CONMAGIC; + pRes->iLogin = 0; + pRes->listening = 0; + pRes->conStart = time(NULL); + pRes->write = SCNormalWrite; + for(i = 0; i < 10; i++) + { + pRes->pFiles[i] = NULL; + } + + /* initialise context variables */ + pRes->iCmdCtr = 0; + pRes->conEventType=-1; + pRes->conStatus=-1; + pRes->contextStack = LLDcreate(sizeof(commandContext)); + + /* install command */ + AddCommand(pSics, ConName(pRes->ident), ConSicsAction, NULL,pRes); + return pRes; } /*--------------------------------------------------------------------------*/ @@ -436,8 +441,11 @@ extern pServer pServ; { DeleteCommandStack(pVictim->pStack); } + + pVictim->lMagic=0; /* make a write to a freed connection harmless */ /* finally free pVictim*/ + LLDdelete(pVictim->contextStack); FreeConnection(pVictim); } /*---------------------------------------------------------------------------*/ @@ -531,6 +539,15 @@ extern pServer pServ; } return self->write(self,pBuffer,iOut); } +/*-----------------------------------------------------------------------*/ +int SCWriteInContext(SConnection *pCon, char *pBuffer, int out, commandContext cc) +{ + int status; + SCPushContext2(pCon,cc); + status = SCWrite(pCon,pBuffer,out); + SCPopContext(pCon); + return status; +} /*-------------------------------------------------------------------------*/ int SCPrintf(SConnection *self, int iOut, char *fmt, ...) { @@ -632,7 +649,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) } } /*--------------------------------------------------------------------------*/ - static int SCNormalWrite(SConnection *self, char *buffer, int iOut) + int SCNormalWrite(SConnection *self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[80]; @@ -686,7 +703,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) return 1; } /*--------------------------------------------------------------------------*/ - static int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut) + int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut) { int i, iPtr, iRet, length; char pBueffel[80]; @@ -1343,7 +1360,14 @@ static void writeToLogFiles(SConnection *self, char *buffer) self->inUse++; self->eInterrupt = eContinue; self->parameterChange = 0; + /* + get first word of command + */ + memset(pBueffel,0,80); + stptok(trim(pCommand),pBueffel,79," "); + SCAdvanceContext(self,pBueffel); iRet = InterpExecute(pInter,self,pCommand); + SCPopContext(self); if(self->parameterChange == 1) { /* @@ -1658,7 +1682,8 @@ static void writeToLogFiles(SConnection *self, char *buffer) The callback function for connection callbacks. Invokes command given at registration time. */ - static int ConCallBack(int iEvent, void *pEventData, void *pUserData) + static int ConCallBack(int iEvent, void *pEventData, void *pUserData, + commandContext cc) { pCBAction self = NULL; @@ -1667,7 +1692,9 @@ static void writeToLogFiles(SConnection *self, char *buffer) if(self->pAction) { + SCPushContext2(self->pCon,cc); InterpExecute(pServ->pSics,self->pCon,self->pAction); + SCPopContext(self->pCon); } return 1; } @@ -1755,7 +1782,7 @@ static void writeToLogFiles(SConnection *self, char *buffer) pCB->pSics = pSics; pCB->pAction = strdup(pBueffel); sItem.pInterface = pInterface; - sItem.lID = RegisterCallback(pInterface, iEvent, ConCallBack, + sItem.lID = RegisterCallback(pInterface, SCGetContext(pCB->pCon), iEvent, ConCallBack, pCB, CBKill); LLDnodeAppendFrom(self->iList,&sItem); SCSendOK(pCon); @@ -1961,6 +1988,48 @@ SConnection *SCLoad(SCStore *con) { } return pCon; } +/* --------------------------------------------------------------------------*/ +long SCTagContext(SConnection *self, char *tagName) +{ + commandContext a; + if(NULL==self) return -1; + /* + return SCSetContext(self,self->iCmdID,tagName); + */ + a = SCGetContext(self); + strncpy(a.deviceID,tagName,SCDEVIDLEN); + /* + SCGetContext will already have advanced the stack pointer to the + last position + */ + LLDnodeDataTo(self->contextStack, &a); +} +/* --------------------------------------------------------------------------*/ +long SCAdvanceContext(SConnection *self, char *tagName) +{ + if(NULL==self) return -1; + self->iCmdCtr++; + if(999999iCmdCtr) + { + self->iCmdCtr = 0; + } + return SCPushContext(self, self->iCmdCtr, tagName); +} +/*------------------------------------------------------------------------*/ +int SCVerifyConnection(SConnection *self) +{ + return VerifyConnection(self); +} +/*------------------------------------------------------------------------*/ +void SCWriteToLogFiles(SConnection *self, char *buffer) +{ + writeToLogFiles(self,buffer); +} +/*------------------------------------------------------------------------*/ +int SCDoSockWrite(SConnection *self, char *buffer) +{ + return doSockWrite(self,buffer); +} /*--------------------------------------------------------------------------*/ void KillFreeConnections(void) { SConnection *next; @@ -1970,3 +2039,52 @@ void KillFreeConnections(void) { freeConnections = next; } } +/*-------------------------------------------------------------------------*/ +int SCPushContext(SConnection *self, int ID, char *deviceID) +{ + commandContext neu; + + if(!VerifyConnection(self)) + { + return 0; + } + + neu.transID = ID; + strncpy(neu.deviceID,deviceID,SCDEVIDLEN); + LLDnodeAppendFrom(self->contextStack,&neu); + return 1; +} +/*------------------------------------------------------*/ +int SCPushContext2(SConnection *self, commandContext cc) +{ + return SCPushContext(self,cc.transID, cc.deviceID); +} +/*------------------------------------------------------*/ +commandContext SCGetContext(SConnection *pCon) +{ + commandContext neu; + neu.transID = 0; + strcpy(neu.deviceID,"Undefined"); + + if(!VerifyConnection(pCon)) + { + return neu; + } + if(LLDnodePtr2Last(pCon->contextStack) == 1){ + LLDnodeDataTo(pCon->contextStack, &neu); + } + return neu; +} +/*-----------------------------------------------------*/ +int SCPopContext(SConnection *pCon) +{ + if(!VerifyConnection(pCon)) + { + return 0; + } + if(LLDnodePtr2Last(pCon->contextStack) != 0) + { + LLDnodeDelete(pCon->contextStack); + } + return 1; +} diff --git a/conman.h b/conman.h index 502d0e24..17928a5b 100644 --- a/conman.h +++ b/conman.h @@ -23,6 +23,7 @@ #include "SCinter.h" #include "network.h" #include "obdes.h" +#include "commandcontext.h" #define MAXLOGFILES 10 @@ -59,6 +60,16 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int parameterChange; int sicsError; + /* + stuff supporting the sycamore protocol and a + command context + */ + long iCmdCtr; + int conEventType; + int conStatus; /* should use status enum ffr */ + int iProtocolID; + int contextStack; + /* a FIFO */ pCosta pStack; @@ -103,6 +114,8 @@ typedef int (*writeFunc)(struct __SConnection *pCon, int SCOnlySockWrite(SConnection *self, char *buffer, int iOut); int SCFileWrite(SConnection *self, char *buffer, int iOut); int SCNotWrite(SConnection *self, char *buffer, int iOut); + int SCNormalWrite(SConnection *self, char *buffer, int iOut); + int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut); /************************* CallBack *********************************** */ int SCRegister(SConnection *pCon, SicsInterp *pSics, void *pInter, long lID); @@ -158,4 +171,17 @@ SConnection *SCLoad(SCStore *con); void KillFreeConnections(void); +/*------------------------------------------------------------------------*/ +int SCVerifyConnection(SConnection *self); +void SCWriteToLogFiles(SConnection *self, char *buffer); +int SCDoSockWrite(SConnection *self, char *buffer); +int SCWriteInContext(SConnection *pCon, char *buffer, int code, commandContext cc); + +long SCTagContext(SConnection *self, char *tagName); +long SCAdvanceContext(SConnection *self, char *tagName); +int SCPushContext(SConnection *pCon, int ID, char *deviceID); +int SCPushContext2(SConnection *pCon, commandContext cc); +int SCPopContext(SConnection *pCon); +commandContext SCGetContext(SConnection *pCon); #endif + diff --git a/counter.c b/counter.c index 690786cf..a29a443f 100644 --- a/counter.c +++ b/counter.c @@ -708,7 +708,8 @@ return 1; } /*-----------------------------------------------------------------------*/ - static int CounterInterest(int iEvent, void *pEvent, void *pUser) + static int CounterInterest(int iEvent, void *pEvent, void *pUser, + commandContext cc) { SConnection *pCon = NULL; pMonEvent pMon = NULL; @@ -731,7 +732,7 @@ */ rights = SCGetRights(pCon); SCSetRights(pCon,usSpy); - SCWrite(pCon,pBueffel,eWarning); + SCWriteInContext(pCon,pBueffel,eWarning,cc); SCSetRights(pCon,rights); return 1; } @@ -896,7 +897,7 @@ SCWrite(pCon,pBueffel,eValue); return 1; case 9: /* interest */ - lID = RegisterCallback(self->pCall, MONITOR, CounterInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), MONITOR, CounterInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); diff --git a/danu.c b/danu.c index 0ab8206e..d77f3dea 100644 --- a/danu.c +++ b/danu.c @@ -95,7 +95,8 @@ static int writeDataNumber(pDataNumber self, int iNum) return 1; } /*------------------- The CallBack function for interest ------------------*/ - static int InterestCallback(int iEvent, void *pEvent, void *pUser) + static int InterestCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { pDataNumber self = NULL; SConnection *pCon = NULL; @@ -120,7 +121,7 @@ static int writeDataNumber(pDataNumber self, int iNum) if(iNum > 0) { snprintf(pBueffel,131,"sicsdatanumber = %d", iNum); - SCWrite(pCon,pBueffel,eValue); + SCWriteInContext(pCon,pBueffel,eValue,cc); } return 1; } @@ -330,7 +331,8 @@ int NewThousand(pDataNumber self) } if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, VALUECHANGE, InterestCallback, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + VALUECHANGE, InterestCallback, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); diff --git a/devexec.c b/devexec.c index d814d830..82388ff2 100644 --- a/devexec.c +++ b/devexec.c @@ -62,6 +62,7 @@ pObjectDescriptor pDescriptor; float fVal; char *name; + commandContext comCon; } DevEntry, *pDevEntry; /*-------------------------------------------------------------------------*/ static pDevEntry CreateDevEntry(pObjectDescriptor pDes, void *pData, @@ -80,6 +81,7 @@ pNew->pData = pData; pNew->name = strdup(name); pNew->fVal = fVal; + memset(&pNew->comCon,0,sizeof(commandContext)); return pNew; } /*-------------------------------------------------------------------------*/ @@ -228,7 +230,9 @@ SCWrite(pCon,"ERROR: memory exhausted in Device Executor ",eError); return 0; } - + pNew->comCon = SCGetContext(pCon); + strncpy(pNew->comCon.deviceID,name,SCDEVIDLEN); + /* start it */ pDrivInt = pDes->GetInterface(pData,DRIVEID); pCountInt = pDes->GetInterface(pData,COUNTID); @@ -250,7 +254,12 @@ if(iRet == OKOK) { LLDnodeAppendFrom(self->iList,&pNew); - ExeInterest(self, pNew, "started"); + sprintf(pBueffel,"started"); + if(NULL!=pNew->comCon.deviceID) + { + snprintf(pBueffel,130,"started (%s)",pNew->comCon.deviceID); + } + ExeInterest(self, pNew, pBueffel); self->iRun = 1; self->iStatus = DEVDONE; /* if no task: start it */ @@ -263,6 +272,7 @@ self, 1); self->iEnd = 0; + pCon->conStatus = HWBusy; } return 1; } @@ -373,7 +383,10 @@ pIDrivable pDrivInt = NULL; int eCode; int isCounting=0, isDriving=0; - + char pBueffel[512]; + SConnection *pCon; + pCon = self->pOwner; + assert(self); /* Sometimes this gets called, though nothing is running. There are @@ -397,6 +410,11 @@ LLDnodeDataTo(self->iList,&pDev); if(pDev) { + /* + SCSetContext(self->pOwner,pDev->cmdID,pDev->name); + */ + SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID); + pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData,DRIVEID); pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID); @@ -423,10 +441,12 @@ ExeInterest(self, pDev, "finished"); DeleteDevEntry(pDev); LLDnodeDelete(self->iList); + SCWrite(pCon, "", eFinish); iRet = LLDnodePtr2Prev(self->iList); if(SCGetInterrupt(self->pOwner) != eContinue) { self->iStatus = DEVINT; + SCPopContext(self->pOwner); return -1; } self->iStatus = DEVDONE; @@ -435,6 +455,7 @@ ExeInterest(self, pDev, "finished with problem"); DeleteDevEntry(pDev); pDev = NULL; + SCWrite(pCon, "", eFinish); LLDnodeDataTo(self->iList,&pDev); LLDnodeDelete(self->iList); iRet = LLDnodePtr2Prev(self->iList); @@ -446,6 +467,7 @@ if(SCGetInterrupt(self->pOwner) != eContinue) { self->iStatus = DEVINT; + SCPopContext(self->pOwner); return -1; } break; @@ -455,6 +477,7 @@ { SetStatus(eEager); self->iStatus = DEVINT; + SCPopContext(self->pOwner); return -1; } break; @@ -464,6 +487,7 @@ { ContinueExecution(self); self->iStatus = DEVINT; + SCPopContext(self->pOwner); return -1; } break; @@ -482,6 +506,7 @@ ExeInterest(self, pDev, "finished with problem"); DeleteDevEntry(pDev); LLDnodeDelete(self->iList); + SCWrite(pCon, "", eFinish); self->iStatus = DEVERROR; if(pDrivInt) { @@ -490,10 +515,12 @@ if(SCGetInterrupt(self->pOwner) != eContinue) { self->iStatus = DEVINT; + SCPopContext(self->pOwner); return -1; } break; } + SCPopContext(self->pOwner); } iRet = LLDnodePtr2Next(self->iList); } @@ -641,7 +668,9 @@ } iRet = LLDnodePtr2Next(self->iList); } + SCPushContext(self->pOwner,0,"system"); SCWrite(self->pOwner,"ERROR: Full Stop called!!",eError); + SCPopContext(self->pOwner); if(SCGetInterrupt(self->pOwner) > eContinue) { self->iStatus = DEVINT; @@ -666,7 +695,7 @@ } else if(pCountInt) { - pDrivInt->Halt(pDev->pData); + pCountInt->Halt(pDev->pData); } return 1; } @@ -699,6 +728,8 @@ pDev = (pDevEntry)LLDnodePtr(self->iList); if(pDev) { + SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID); + pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID); if(pCountInt) { @@ -709,7 +740,8 @@ } } - } + } + SCPopContext(self->pOwner); iRet = LLDnodePtr2Next(self->iList); } SetStatus(ePaused); @@ -735,7 +767,6 @@ { return 1; } - } iRet = LLDnodePtr2Next(self->iList); } @@ -760,11 +791,13 @@ pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID); if(pCountInt) { + SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID); iRet = pCountInt->Continue(pDev->pData,self->pOwner); if(!iRet) { iRes = 0; } + SCPopContext(self->pOwner); } } @@ -842,12 +875,15 @@ return iRet; } /*------------------- The CallBack function for interest ------------------*/ - static int DrivStatCallback(int iEvent, void *text, void *pCon) + static int DrivStatCallback(int iEvent, void *text, void *pCon, + commandContext cc) { assert(pCon); assert(text); + SCPushContext2(pCon,cc); SCWrite(pCon, text, eValue); + SCPopContext(pCon); return 1; } /*--------------------------------------------------------------------------*/ @@ -866,7 +902,8 @@ if (argc == 2) { if (strcmp(argv[1], "interest") == 0) { - list = RegisterCallback(self->pCall, DRIVSTAT, DrivStatCallback, + list = RegisterCallback(self->pCall, SCGetContext(pCon), + DRIVSTAT, DrivStatCallback, pCon, NULL); SCRegister(pCon, pSics, self->pCall,list); SCSendOK(pCon); @@ -1025,15 +1062,6 @@ { if(iInterrupt > 1) { - /* M.Z: it seems that this warning is redundant - a) because it was erroenous - b) it would be emitted for every driveable obj to be stopped - - Interrupt2Text(iInterrupt,pInterrupt,79); - snprintf(pBueffel,131,"ERROR: interrupt %s triggered", - pInterrupt); - SCWrite(self->pOwner,pBueffel, eError); - */ StopExe(self,"all"); } #ifdef DEBUG @@ -1077,10 +1105,12 @@ { if(self->pOwner) { + SCPushContext(self->pOwner,0,"system"); SCWrite(self->pOwner, "ERROR: Interrupting Current Hardware Operation", eError); - SCSetInterrupt(self->pOwner,*iInt); + SCSetInterrupt(self->pOwner,*iInt); + SCPopContext(self->pOwner); } StopExe(self,"all"); } diff --git a/doc/user/velocity.htm b/doc/user/velocity.htm index 52039207..a60bc536 100644 --- a/doc/user/velocity.htm +++ b/doc/user/velocity.htm @@ -51,6 +51,8 @@ is set, without the current value is printed.
nvs loss
Starts a loss current measurement on the velocity selector and prints the result. +
nvs forbidden +
Prints a list of forbidden speed regions for this selector.
nvs status
Prints a status summary of the velocity selector. diff --git a/evcontroller.c b/evcontroller.c index e5fbbba9..00a6ecb3 100644 --- a/evcontroller.c +++ b/evcontroller.c @@ -173,6 +173,16 @@ eError); return -999.; } + + static void notifyStatus(pEVControl self, SConnection *pCon, int status) { + if (self->pDrivInt->drivableStatus!=status) { + ((SConnection *)pCon)->conEventType=STATUS; + ((SConnection *)pCon)->conStatus=status; + SCWrite(pCon, "", eEvent); + self->pDrivInt->drivableStatus=status; + } + } + /*---------------------------------------------------------------------------*/ static int EVIStatus(void *pData, SConnection *pCon) { @@ -191,6 +201,7 @@ /* go to idle when stopped */ if(self->iStop) { + notifyStatus(self, pCon, HWIdle); return HWIdle; } @@ -209,16 +220,19 @@ case DEVFAULT: sprintf(pBueffel,"ERROR: %s",pError); SCWrite(pCon,pBueffel,eError); + notifyStatus(self, pCon, HWFault); return HWFault; case DEVREDO: sprintf(pBueffel,"WARNING: Fixing problem %s",pError); SCWrite(pCon,pBueffel,eWarning); + notifyStatus(self, pCon, HWBusy); return HWBusy; break; } } else if(iRet == -1 ) /* pending */ { + notifyStatus(self, pCon, HWBusy); return HWBusy; } @@ -228,6 +242,7 @@ self->pName); SCWrite(pCon,pBueffel,eError); self->eMode = EVIdle; + notifyStatus(self, pCon, HWFault); return HWFault; } @@ -254,6 +269,7 @@ self->pName); SCWrite(pCon,pBueffel,eError); self->eMode = EVMonitor; + notifyStatus(self, pCon, HWIdle); return HWIdle; } tol = ObVal(self->pParam, TOLERANCE); @@ -272,13 +288,16 @@ self->pName, (self->lastt + tmo - now)*1.0); SCWrite(pCon,pBueffel,eStatus); } + notifyStatus(self, pCon, HWBusy); return HWBusy; } if (now > self->lastt + tmo) { self->eMode = EVMonitor; + notifyStatus(self, pCon, HWIdle); return HWIdle; } + notifyStatus(self, pCon, HWBusy); return HWBusy; } else @@ -289,6 +308,7 @@ SCWrite(pCon,pBueffel,eStatus); self->lastt -= now; } + notifyStatus(self, pCon, HWBusy); return HWBusy; } } @@ -1009,7 +1029,8 @@ static void ErrReport(pEVControl self) return 1; } /*-------------------------------------------------------------------------*/ - static int EVCallBack(int iEvent, void *pEventData, void *pUserData) + static int EVCallBack(int iEvent, void *pEventData, void *pUserData, + commandContext cc) { char *pBuf = (char *)pEventData; SConnection *pCon = (SConnection *)pUserData; @@ -1017,7 +1038,8 @@ static void ErrReport(pEVControl self) if(iEvent == VALUECHANGE) { - SCWrite(pCon,pBuf,eValue); + pCon->conEventType=POSITION; + SCWriteInContext(pCon,pBuf,eEvent,cc); return 1; } return 1; @@ -1075,7 +1097,8 @@ static void ErrReport(pEVControl self) /* install automatic notification */ else if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, VALUECHANGE, EVCallBack, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + VALUECHANGE, EVCallBack, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -1414,13 +1437,14 @@ int RemoveEVController(SConnection *pCon, char *name) { SCWrite(pCon,"ERROR: cannot delete while running",eError); return 0; } - if (!FindCommandData(pServ->pSics, name, "Environment Controller")) { - SCPrintf(pCon,eError,"ERROR: no environment controller %s found",name); + EVUnregister(FindEMON(pServ->pSics),name); + iRet = RemoveCommand(pServ->pSics,name); + if(!iRet) + { + sprintf(pBueffel,"ERROR: %s not found, NOT deleted",name); + SCWrite(pCon,pBueffel,eError); return 0; } - - EVUnregister(FindEMON(pServ->pSics),name); - RemoveCommand(pServ->pSics,name); return 1; } /*------------------------------------------------------------------------- diff --git a/event.h b/event.h index 4e588698..a990d827 100644 --- a/event.h +++ b/event.h @@ -42,7 +42,8 @@ #define BATCHAREA 15 #define BATCHEND 16 #define DRIVSTAT 17 - +#define STATUS 18 +#define POSITION 19 /* Position event for motors - ffr */ #line 104 "event.w" diff --git a/exeman.c b/exeman.c index 8368e2a6..468062b1 100644 --- a/exeman.c +++ b/exeman.c @@ -284,25 +284,27 @@ static pExeInfo makeExeInfo(SConnection *pCon, pExeMan self){ return pNew; } /*------------------------------------------------------------------*/ -static int BufferCallback(int iEvent, void *pEvent, void *pUser){ +static int BufferCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc){ pExeInfo self = (pExeInfo)pUser; char *name = (char *)pEvent; char pBueffel[132]; if(iEvent == BATCHSTART){ snprintf(pBueffel,131,"BATCHSTART=%s",name); - SCWrite(self->pCon,pBueffel,eWarning); + SCWriteInContext(self->pCon,pBueffel,eWarning,cc); return 1; } if(iEvent == BATCHEND){ snprintf(pBueffel,131,"BATCHEND=%s",name); - SCWrite(self->pCon,pBueffel,eWarning); + SCWriteInContext(self->pCon,pBueffel,eWarning,cc); return 1; } return 0; } /*-------------------------------------------------------------------*/ -static int LineCallBack(int iEvent, void *pEvent, void *pUser){ +static int LineCallBack(int iEvent, void *pEvent, void *pUser, + commandContext cc){ pExeInfo self = (pExeInfo)pUser; char pBueffel[256]; int start, end, lineno; @@ -317,7 +319,7 @@ static int LineCallBack(int iEvent, void *pEvent, void *pUser){ exeBufRange(buf,&start,&end,&lineno); snprintf(pBueffel,255,"%s.range = %d = %d",exeBufName(buf), start,end); - SCWrite(self->pCon,pBueffel,eWarning); + SCWriteInContext(self->pCon,pBueffel,eWarning,cc); return 1; } return 0; @@ -332,13 +334,13 @@ static void registerCallbacks(SConnection *pCon, SicsInterp *pSics, if(info == NULL){ return; } - lID = RegisterCallback(self->pCall, BATCHSTART, BufferCallback, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),BATCHSTART, BufferCallback, info, killExeInfo); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, BATCHEND, BufferCallback, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),BATCHEND, BufferCallback, info, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, BATCHAREA, LineCallBack, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),BATCHAREA, LineCallBack, info, NULL); SCRegister(pCon,pSics, self->pCall,lID); } diff --git a/fourlib.c b/fourlib.c index 90314f73..a1a916ef 100644 --- a/fourlib.c +++ b/fourlib.c @@ -450,6 +450,59 @@ double sign(double a, double b){ return -ABS(a); } } +/*--------------------------------------------------------------------*/ +static void makeNull(double *gamma, double *om, double *nu){ + *gamma = .0; + *om = .0; + *nu = .0; +} +/*---------------------------------------------------------------------*/ +int z1mToNormalBeam(double lambda, MATRIX z1m, double *gamma, double *om, double *nu){ + MATRIX dum, znew; + double d, a, b, sint, theta, omdeg; + int status; + + status = calcTheta(lambda,z1m,&d,&theta); + if(!status){ + makeNull(gamma,om,nu); + return status; + } + + /* Everything on omega axis is blind: test for this */ + a = sqrt(z1m[0][0] * z1m[0][0] + z1m[1][0] * z1m[1][0]); + if(ABS(a) < .0001) { + makeNull(gamma,om,nu); + return 0; + } + + sint = sin(theta/RD); + b = 2.*sint*sint/(lambda*a); + if(b >= 1.) { + makeNull(gamma,om,nu); + return 0; + } + a = -atan2(z1m[1][0], -z1m[0][0]); + b = -asin(b); + *om = a + b; + omdeg = *om*RD; + dum = mat_creat(3,3,ZERO_MATRIX); + phimat(dum,omdeg); + znew = mat_mul(dum,z1m); + if(znew[0][0] < 0) { + *om = *om -2.*atan2(-znew[0][0], -znew[2][0]); + omdeg = *om * RD; + } + b = (sign(180.,omdeg)+ omdeg)/360.; + /* omdeg = omdeg - 360. * floor(b); */ + *nu = asin(lambda*z1m[2][0]); + *gamma = acos(cos(2.*(theta/RD)))/cos(*nu); + *om = omdeg; + *nu = *nu * RD; + *gamma = *gamma * RD; + mat_free(dum); + mat_free(znew); + return 1; +} /*----------------------------------------------------------------------*/ int bisToNormalBeam(double twotheta, double omega, double chi, double phi, double *omeganb, double *gamma, double *nu){ diff --git a/fourlib.h b/fourlib.h index d7d3db70..c9b5e251 100644 --- a/fourlib.h +++ b/fourlib.h @@ -70,7 +70,7 @@ void pol2det(psdDescription *psd, double gamma, double nu, int *x, int *y); Z1 = UB *h ------------------------------------------------------------------------*/ /** - * calculate stt, om, chi and phi in order to put z1 into the bissecting + * calculate stt, om, chi and phi in order to put z1 into the bissecting * diffraction condition. Returns 1 on success and 0 if z1 and lambda * were invalid. The m version acts upon a matrix. */ @@ -122,6 +122,10 @@ void z1FromAngles(double lambda, double stt, double om, */ int bisToNormalBeam(double twotheta, double omega, double chi, double phi, double *omeganb, double *gamma, double *nu); +/** + * calculate normal beam angles from z1 + */ +int z1mToNormalBeam(double lambda, MATRIX z1, double *gamma, double *om, double *nu); /** * calculate the vector z1 from the normal beam angles omega, gamma and nu. diff --git a/histmem.c b/histmem.c index 2f59e4ac..4d7c50be 100644 --- a/histmem.c +++ b/histmem.c @@ -439,6 +439,7 @@ free(pNew); return NULL; } + StringDictAddPair(pNew->pOption,"driver",driver); StringDictAddPair(pNew->pOption,"update","0"); /* initialise driver */ @@ -531,6 +532,8 @@ SCWrite(pCon,pBueffel,eError); return 0; } + + StringDictAddPair(pNew->pOption,"name",argv[1]); /* install HM as command */ iRet = AddCommand(pSics,argv[1],HistAction,DeleteHistMemory,(void *)pNew); @@ -918,7 +921,8 @@ void HistDirty(pHistMem self) return 0; } /*----------------------------------------------------------------------*/ - static int HMCountInterest(int iEvent, void *pEvent, void *pUser) + static int HMCountInterest(int iEvent, void *pEvent, void *pUser, + commandContext cc) { SConnection *pCon = NULL; char pBueffel[512]; @@ -927,14 +931,14 @@ void HistDirty(pHistMem self) { pCon = (SConnection *)pUser; assert(pCon); - SCWrite(pCon,"HMCOUNTSTART",eWarning); + SCWriteInContext(pCon,"HMCOUNTSTART",eWarning,cc); return 1; } else if(iEvent == COUNTEND) { pCon = (SConnection *)pUser; assert(pCon); - SCWrite(pCon,"HMCOUNTEND",eWarning); + SCWriteInContext(pCon,"HMCOUNTEND",eWarning,cc); return 1; } return 0; @@ -955,6 +959,89 @@ static int checkHMEnd(pHistMem self, char *text){ } } } +/*--------------------------------------------------------------------------*/ + void HMListOption(pHistMem self, SConnection *pCon) + { + char pBuffer[512]; + char name[20]; + char pValue[128]; + const char *pKey; + int i,iRet,iLen,iRank,iDiscard,tofMode; + float fVal; + char *pMode[] = {"timer","monitor",NULL}; + + memset(pBuffer, 0, sizeof(pBuffer)); + memset(pValue, 0, sizeof(pValue)); + memset(name, 0, sizeof(name)); + + iRet = StringDictGet(self->pOption,"name",name,19); + if(0==iRet) { + strcpy(name,"*"); + } + iRet = StringDictGet(self->pOption,"driver",pValue,sizeof(pValue)-1); + if(0pOption,"update",&fVal); + if(0pOption,"rank",&fVal); + if(0pOption,pValue,&fVal); + if(0pOption,pValue,sizeof(pValue)-1); + while(pKey != NULL) { + iDiscard=0; + if(0==strcmp("name",pKey)) iDiscard=1; + if(0==strcmp("driver",pKey)) iDiscard=1; + if(0==strcmp("update",pKey)) iDiscard=1; + if(0==strcmp("rank",pKey)) iDiscard=1; + if(NULL!=strstr(pKey,"dim")) iDiscard=1; + if(0==iDiscard) { + sprintf(pBuffer,"%s.%s = %s",name,pKey,pValue,sizeof(pValue)-1); + SCWrite(pCon,pBuffer,eStatus); + } + pKey = StringDictGetNext(self->pOption,pValue,sizeof(pValue)-1); + } + + /* Display Count Mode */ + sprintf(pBuffer,"%s.CountMode = %s",name,pMode[self->pDriv->eCount]); + SCWrite(pCon,pBuffer,eStatus); + + /* Display Preset */ + sprintf(pBuffer,"%s.preset = %f",name,self->pDriv->fCountPreset); + SCWrite(pCon,pBuffer,eStatus); + + if(self->pDriv->data->nTimeChan > 2) { + tofMode = 1; + } else { + tofMode = 0; + } + sprintf(pBuffer,"%s.tofMode = %d",name,tofMode); + SCWrite(pCon,pBuffer,eStatus); + } +/*--------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------*/ int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -998,10 +1085,12 @@ static int checkHMEnd(pHistMem self, char *text){ strtolower(argv[1]); if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, COUNTSTART, HMCountInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + COUNTSTART, HMCountInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, COUNTEND, HMCountInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + COUNTEND, HMCountInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -1165,6 +1254,11 @@ static int checkHMEnd(pHistMem self, char *text){ return 0; } } + else if(strcmp(argv[1],"list") == 0) + { + HMListOption(self,pCon); + return 1; + } /* normal counting*/ else if(strcmp(argv[1],"count") == 0) { diff --git a/hkl.c b/hkl.c index f93fec5f..44d1f52d 100644 --- a/hkl.c +++ b/hkl.c @@ -205,7 +205,8 @@ #include "selvar.i" /*---------------------------------------------------------------------------*/ - static int HKLCallback(int iEvent, void *pEvent, void *pUser) + static int HKLCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { pHKL self = NULL; pSelVar pVar = NULL; @@ -236,6 +237,7 @@ pICallBack pCall = NULL, pCall2 = NULL; pDummy pDum = NULL; float fVal; + commandContext comCon; assert(pCon); assert(self); @@ -264,7 +266,10 @@ } /* install new callback */ + comCon.transID = 0; + strncpy(comCon.deviceID,"internal",SCDEVIDLEN); self->lID = RegisterCallback(pCall2, + comCon, WLCHANGE, HKLCallback, self, @@ -673,7 +678,7 @@ static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon, float fSet[4], double myPsi, int iRetry) { int i, iTest; - double stt, om, chi, phi, gamma, nu, psi; + double stt, om, chi, phi, gamma, nu, psi, omnb; float currentPhi, currentChi; double ompsi, chipsi, phipsi; MATRIX chim, phim, z4, z3; @@ -694,6 +699,7 @@ static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon, { return 0; } + /* phim = mat_creat(3,3,ZERO_MATRIX); phimat(phim,(double)currentPhi); z4 = mat_mul(phim,z1); @@ -703,6 +709,31 @@ static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon, mat_free(phim); mat_free(chim); mat_free(z4); + */ + + if(!z1mToNormalBeam(self->fLambda, z1, &gamma, &omnb, &nu)){ + return 0; + } + if(checkNormalBeam(omnb, &gamma, nu,fSet,pCon,self)){ + return 1; + } else { + return 0; + } + + if(!z1mToBisecting(self->fLambda,z1,&stt,&om,&chi,&phi)) + { + return 0; + } + if(bisToNormalBeam(stt,om,chi,phi, + &omnb, &gamma, &nu)) + { + /* om = -om + 180.; */ + if(checkNormalBeam(omnb, &gamma, nu,fSet,pCon,self)) + { + return 1; + } + } + return 0; /* do the bisecting angles first diff --git a/ifile.c b/ifile.c index 6154860f..458d41b0 100644 --- a/ifile.c +++ b/ifile.c @@ -153,6 +153,28 @@ { return CreateNewEntry(name,value,pList); } + +/*--------------------------------------------------------------------------*/ + IPair *IFSetOption(IPair *pList,char *name, char *value) + { + IPair *pCurrent; + if(NULL!=pList) + { + pCurrent = pList; + while((NULL!=pCurrent) && (0!=strcmp(name,pCurrent->name))) + { + pCurrent = pCurrent->pNext; + } + if(NULL!=pCurrent) + { /* replace value */ + free(pCurrent->value); + pCurrent->value = strdup(value); + return pCurrent; + } + } + return CreateNewEntry(name,value,pList); + } + /*-------------------------------------------------------------------------*/ int IFSaveOptions(IPair *pList,FILE *fd) diff --git a/ifile.h b/ifile.h index f6cfd471..69b3d819 100644 --- a/ifile.h +++ b/ifile.h @@ -25,6 +25,8 @@ typedef struct __IFileE /* returns a value for a name */ IPair *IFAddOption(IPair *pList,char *name, char *value); + IPair *IFSetOption(IPair *pList,char *name, char *value); + int IFSaveOptions(IPair *pList,FILE *fp); void IFDeleteOptions(IPair *pList); diff --git a/interface.c b/interface.c index 5c77abbf..11c08415 100644 --- a/interface.c +++ b/interface.c @@ -83,6 +83,7 @@ static float EmptyGet(void *self, SConnection *pCon){ pRes->SetValue = EmptyValue; pRes->CheckStatus = EmptyStatus; pRes->GetValue = EmptyGet; + pRes->drivableStatus=HWIdle; return pRes; } /*-------------------------------------------------------------------------*/ diff --git a/interface.h b/interface.h index 13dd8a97..b4d3c19e 100644 --- a/interface.h +++ b/interface.h @@ -1,8 +1,8 @@ -#line 365 "interface.w" +#line 381 "interface.w" /*--------------------------------------------------------------------------- - I N T E R F A C E S + I N T E R F A C E S Any object in SICS has to adhere to the object descriptor interface (see file obdes.h). Furthermore SICS objects may choose to support other @@ -17,6 +17,7 @@ #ifndef SICSINTERFACES #define SICSINTERFACES +#include "commandcontext.h" /* interface ID's used to recognize an interface */ #define DRIVEID 513 @@ -26,7 +27,7 @@ /* ----------------------- The drivable interface -----------------------*/ -#line 117 "interface.w" +#line 121 "interface.w" typedef struct { @@ -39,21 +40,22 @@ int (*CheckStatus)(void *self, SConnection *pCon); float (*GetValue)(void *self, SConnection *pCon); int iErrorCount; + int drivableStatus; } IDrivable, *pIDrivable; pIDrivable GetDrivableInterface(void *pObject); - int GetDrivablePosition(void *pObject, SConnection *pCon, - float *fPos); + int GetDrivablePosition(void *pObject, SConnection *pCon, + float *fPos); -#line 390 "interface.w" +#line 407 "interface.w" pIDrivable CreateDrivableInterface(void); /* ------------------------ The countable interface ---------------------*/ -#line 183 "interface.w" +#line 188 "interface.w" typedef struct { int ID; @@ -70,23 +72,23 @@ pICountable GetCountableInterface(void *pObject); -#line 395 "interface.w" +#line 412 "interface.w" pICountable CreateCountableInterface(void); /* ------------------------- The CallBack Interface --------------------*/ -#line 236 "interface.w" +#line 241 "interface.w" typedef void (*KillFuncIT)(void *pData); typedef int (*SICSCallBack)(int iEvent, void *pEventData, - void *pUserData); + void *pUserData, commandContext cc); -#line 400 "interface.w" +#line 417 "interface.w" -#line 258 "interface.w" +#line 263 "interface.w" typedef struct __ICallBack *pICallBack; @@ -96,21 +98,22 @@ int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData); /* callback client side */ - long RegisterCallback(pICallBack pInterface, int iEvent, SICSCallBack pFunc, + long RegisterCallback(pICallBack pInterface, commandContext comCon, + int iEvent, SICSCallBack pFunc, void *pUserData, KillFuncIT pKill); int RemoveCallback(pICallBack pInterface, long iID); int RemoveCallback2(pICallBack pInterface, void *pUserData); int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData, - int argc, char *argv[]); + int argc, char *argv[]); pICallBack GetCallbackInterface(void *pData); -#line 401 "interface.w" +#line 418 "interface.w" /*---------------------- The Environment Interface --------------------*/ -#line 329 "interface.w" +#line 335 "interface.w" typedef enum { EVIdle, EVDrive, EVMonitor, EVError } EVMode; typedef struct { @@ -120,13 +123,13 @@ int (*HandleError)(void *self); } EVInterface, *pEVInterface; -#line 403 "interface.w" +#line 420 "interface.w" -#line 355 "interface.w" +#line 361 "interface.w" pEVInterface CreateEVInterface(void); -#line 404 "interface.w" +#line 421 "interface.w" #endif diff --git a/interface.tex b/interface.tex index a49e9625..d6ef7978 100644 --- a/interface.tex +++ b/interface.tex @@ -1,3 +1,13 @@ +\newcommand{\NWtarget}[2]{#2} +\newcommand{\NWlink}[2]{#2} +\newcommand{\NWtxtMacroDefBy}{Macro defined by} +\newcommand{\NWtxtMacroRefIn}{Macro referenced in} +\newcommand{\NWtxtMacroNoRef}{Macro never referenced} +\newcommand{\NWtxtDefBy}{Defined by} +\newcommand{\NWtxtRefIn}{Referenced in} +\newcommand{\NWtxtNoRef}{Not referenced} +\newcommand{\NWtxtFileDefBy}{File defined by} +\newcommand{\NWsep}{${\diamond}$} \subsection{Object interfaces}\label{inter} In order to present themselves to the system SICS objects need to adhere to certyain interfaces. These interfaces are described in this @@ -28,33 +38,37 @@ Let's start with the objectdescriptor: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap1} -$\langle$obdes {\footnotesize ?}$\rangle\equiv$ +$\langle\,$obdes\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@/*--------------------------------------------------------------------------@\\ -\mbox{}\verb@ In SICS there is the to find out what an@\\ -\mbox{}\verb@ object is capable of at runtime. If this has been done a general@\\ -\mbox{}\verb@ way to access those capabilities is needed. In order to do all@\\ -\mbox{}\verb@ this each SICS-object is required to carry an object descriptor@\\ -\mbox{}\verb@ struct as first parameter in its class/object struct. Additionslly@\\ -\mbox{}\verb@ it is required to initialize this struct to something sensible.@\\ -\mbox{}\verb@ @\\ -\mbox{}\verb@ This file defines this struct. Additionally a few functions of@\\ -\mbox{}\verb@ general use are prototyped.@\\ -\mbox{}\verb@ @\\ -\mbox{}\verb@ Mark Koennecke, June, 1997@\\ -\mbox{}\verb@ @\\ -\mbox{}\verb@ copyrigth: see implementation file @\\ +\mbox{}\verb@ In SICS there is the to find out what an@\\ +\mbox{}\verb@ object is capable of at runtime. If this has been done a general@\\ +\mbox{}\verb@ way to access those capabilities is needed. In order to do all@\\ +\mbox{}\verb@ this each SICS-object is required to carry an object descriptor@\\ +\mbox{}\verb@ struct as first parameter in its class/object struct. Additionslly@\\ +\mbox{}\verb@ it is required to initialize this struct to something sensible.@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ This file defines this struct. Additionally a few functions of@\\ +\mbox{}\verb@ general use are prototyped.@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ Mark Koennecke, June, 1997@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ copyrigth: see implementation file @\\ \mbox{}\verb@----------------------------------------------------------------------------*/@\\ \mbox{}\verb@#ifndef SICSDESCRIPTOR@\\ \mbox{}\verb@#define SICSDESCRIPTOR@\\ \mbox{}\verb@#include @\\ +\mbox{}\verb@#include @\\ \mbox{}\verb@@\\ \mbox{}\verb@ typedef struct {@\\ \mbox{}\verb@ char *name;@\\ \mbox{}\verb@ int (*SaveStatus)(void *self, char *name,FILE *fd);@\\ \mbox{}\verb@ void *(*GetInterface)(void *self, int iInterfaceID);@\\ +\mbox{}\verb@ char *description;@\\ +\mbox{}\verb@ char *group;@\\ +\mbox{}\verb@ IPair *pKeys;@\\ \mbox{}\verb@ } ObjectDescriptor, *pObjectDescriptor;@\\ \mbox{}\verb@@\\ \mbox{}\verb@ /*---------------------------------------------------------------------------*/@\\ @@ -63,9 +77,9 @@ $\langle$obdes {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ pObjectDescriptor FindDescriptor(void *pData);@\\ \mbox{}\verb@ @\\ \mbox{}\verb@/*============================================================================@\\ -\mbox{}\verb@ Objects which do not carry data need a dummy descriptor. Otherwise@\\ -\mbox{}\verb@ drive or scan will protection fault when trying to drive something@\\ -\mbox{}\verb@ which should not be driven. This is defined below.@\\ +\mbox{}\verb@ Objects which do not carry data need a dummy descriptor. Otherwise@\\ +\mbox{}\verb@ drive or scan will protection fault when trying to drive something@\\ +\mbox{}\verb@ which should not be driven. This is defined below.@\\ \mbox{}\verb@*/@\\ \mbox{}\verb@@\\ \mbox{}\verb@typedef struct {@\\ @@ -74,17 +88,17 @@ $\langle$obdes {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ @\\ \mbox{}\verb@@\\ \mbox{}\verb@ pDummy CreateDummy(char *name);@\\ -\mbox{}\verb@ void KillDummy(void *pData); @\\ +\mbox{}\verb@ void KillDummy(void *pData); @\\ \mbox{}\verb@@\\ \mbox{}\verb@ int iHasType(void *pData, char *Type);@\\ \mbox{}\verb@ @\\ \mbox{}\verb@#endif @\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -128,7 +142,7 @@ environment controllers fit this bill as well. \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap2} -$\langle$driv {\footnotesize ?}$\rangle\equiv$ +$\langle\,$driv\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -143,18 +157,19 @@ $\langle$driv {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int (*CheckStatus)(void *self, SConnection *pCon);@\\ \mbox{}\verb@ float (*GetValue)(void *self, SConnection *pCon); @\\ \mbox{}\verb@ int iErrorCount;@\\ +\mbox{}\verb@ int drivableStatus;@\\ \mbox{}\verb@ } IDrivable, *pIDrivable;@\\ \mbox{}\verb@@\\ \mbox{}\verb@ pIDrivable GetDrivableInterface(void *pObject); @\\ -\mbox{}\verb@ int GetDrivablePosition(void *pObject, SConnection *pCon,@\\ -\mbox{}\verb@ float *fPos);@\\ +\mbox{}\verb@ int GetDrivablePosition(void *pObject, SConnection *pCon,@\\ +\mbox{}\verb@ float *fPos);@\\ \mbox{}\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -207,7 +222,7 @@ This is an interface for interacting with anything which counts. \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap3} -$\langle$count {\footnotesize ?}$\rangle\equiv$ +$\langle\,$count\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -225,12 +240,12 @@ $\langle$count {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@@\\ \mbox{}\verb@ pICountable GetCountableInterface(void *pObject); @\\ \mbox{}\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -272,19 +287,19 @@ The first thing to define for such an interface is the type of the callback function: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap4} -$\langle$callfunc {\footnotesize ?}$\rangle\equiv$ +$\langle\,$callfunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@ typedef void (*KillFuncIT)(void *pData);@\\ \mbox{}\verb@ typedef int (*SICSCallBack)(int iEvent, void *pEventData, @\\ -\mbox{}\verb@ void *pUserData);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@ void *pUserData, commandContext cc);@\\ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -306,7 +321,7 @@ interface: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap5} -$\langle$cifunc {\footnotesize ?}$\rangle\equiv$ +$\langle\,$cifunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -318,21 +333,22 @@ $\langle$cifunc {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData); @\\ \mbox{}\verb@@\\ \mbox{}\verb@ /* callback client side */@\\ -\mbox{}\verb@ long RegisterCallback(pICallBack pInterface, int iEvent, SICSCallBack pFunc,@\\ +\mbox{}\verb@ long RegisterCallback(pICallBack pInterface, commandContext comCon, @\\ +\mbox{}\verb@ int iEvent, SICSCallBack pFunc,@\\ \mbox{}\verb@ void *pUserData, KillFuncIT pKill);@\\ \mbox{}\verb@ int RemoveCallback(pICallBack pInterface, long iID);@\\ \mbox{}\verb@ int RemoveCallback2(pICallBack pInterface, void *pUserData);@\\ \mbox{}\verb@@\\ \mbox{}\verb@ int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ -\mbox{}\verb@ int argc, char *argv[]); @\\ +\mbox{}\verb@ int argc, char *argv[]); @\\ \mbox{}\verb@@\\ \mbox{}\verb@ pICallBack GetCallbackInterface(void *pData); @\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -389,7 +405,7 @@ This interface is used by the environment monitor in order to monitor the status of a environment controller. The interface looks like this: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap6} -$\langle$envir {\footnotesize ?}$\rangle\equiv$ +$\langle\,$envir\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ @@ -400,12 +416,12 @@ $\langle$envir {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@ int (*IsInTolerance)(void *self);@\\ \mbox{}\verb@ int (*HandleError)(void *self);@\\ \mbox{}\verb@ } EVInterface, *pEVInterface;@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -428,17 +444,17 @@ in question. The environment interface has just one function associated with it: \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap7} -$\langle$envfunc {\footnotesize ?}$\rangle\equiv$ +$\langle\,$envfunc\nobreak\ {\footnotesize \NWtarget{nuweb?}{?}}$\,\rangle\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@ pEVInterface CreateEVInterface(void);@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex} \begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} -\item Macro referenced in scrap ?. +\item \NWtxtMacroRefIn\ \NWlink{nuweb?}{?}. \end{list} \end{minipage}\\[4ex] \end{flushleft} @@ -446,24 +462,34 @@ $\langle$envfunc {\footnotesize ?}$\rangle\equiv$ \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap8} -\verb@"obdes.h"@ {\footnotesize ? }$\equiv$ +\verb@"obdes.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ -\mbox{}\verb@@$\langle$obdes {\footnotesize ?}$\rangle$\verb@@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@\hbox{$\langle\,$obdes\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ +\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\ +\mbox{}\verb@/* Additional properties used by the ANSTO site to provide more information@\\ +\mbox{}\verb@ * about each object instance, especially devices.@\\ +\mbox{}\verb@ */@\\ +\mbox{}\verb@ void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *value);@\\ +\mbox{}\verb@ void SetDescriptorGroup(pObjectDescriptor self, char *group);@\\ +\mbox{}\verb@ void SetDescriptorDescription(pObjectDescriptor self, char *description);@\\ +\mbox{}\verb@ char * GetDescriptorKey(pObjectDescriptor self, char *keyName);@\\ +\mbox{}\verb@ char * GetDescriptorGroup(pObjectDescriptor self);@\\ +\mbox{}\verb@ char * GetDescriptorDescription(pObjectDescriptor self);@\\ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-2ex} \end{minipage}\\[4ex] \end{flushleft} \begin{flushleft} \small \begin{minipage}{\linewidth} \label{scrap9} -\verb@"interface.h"@ {\footnotesize ? }$\equiv$ +\verb@"interface.h"@\nobreak\ {\footnotesize \NWtarget{nuweb?}{?} }$\equiv$ \vspace{-1ex} \begin{list}{}{} \item \mbox{}\verb@@\\ \mbox{}\verb@/*---------------------------------------------------------------------------@\\ -\mbox{}\verb@ I N T E R F A C E S@\\ +\mbox{}\verb@ I N T E R F A C E S@\\ \mbox{}\verb@@\\ \mbox{}\verb@ Any object in SICS has to adhere to the object descriptor interface (see@\\ \mbox{}\verb@ file obdes.h). Furthermore SICS objects may choose to support other@\\ @@ -478,6 +504,7 @@ $\langle$envfunc {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@@\\ \mbox{}\verb@#ifndef SICSINTERFACES@\\ \mbox{}\verb@#define SICSINTERFACES@\\ +\mbox{}\verb@#include "commandcontext.h"@\\ \mbox{}\verb@@\\ \mbox{}\verb@/* interface ID's used to recognize an interface */@\\ \mbox{}\verb@#define DRIVEID 513@\\ @@ -486,23 +513,23 @@ $\langle$envfunc {\footnotesize ?}$\rangle\equiv$ \mbox{}\verb@#define ENVIRINTERFACE 949@\\ \mbox{}\verb@@\\ \mbox{}\verb@/* ----------------------- The drivable interface -----------------------*/@\\ -\mbox{}\verb@@$\langle$driv {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$driv\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@ pIDrivable CreateDrivableInterface(void);@\\ \mbox{}\verb@@\\ \mbox{}\verb@/* ------------------------ The countable interface ---------------------*/@\\ -\mbox{}\verb@@$\langle$count {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$count\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ \mbox{}\verb@@\\ \mbox{}\verb@ pICountable CreateCountableInterface(void);@\\ \mbox{}\verb@@\\ \mbox{}\verb@/* ------------------------- The CallBack Interface --------------------*/@\\ -\mbox{}\verb@@$\langle$callfunc {\footnotesize ?}$\rangle$\verb@@\\ -\mbox{}\verb@@$\langle$cifunc {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$callfunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$cifunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ \mbox{}\verb@/*---------------------- The Environment Interface --------------------*/@\\ -\mbox{}\verb@@$\langle$envir {\footnotesize ?}$\rangle$\verb@@\\ -\mbox{}\verb@@$\langle$envfunc {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$envir\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ +\mbox{}\verb@@\hbox{$\langle\,$envfunc\nobreak\ {\footnotesize \NWlink{nuweb?}{?}}$\,\rangle$}\verb@@\\ \mbox{}\verb@#endif@\\ -\mbox{}\verb@@$\diamond$ +\mbox{}\verb@@{\NWsep} \end{list} \vspace{-2ex} \end{minipage}\\[4ex] diff --git a/interface.w b/interface.w index 4daa749f..e8f3727d 100644 --- a/interface.w +++ b/interface.w @@ -45,11 +45,15 @@ Let's start with the objectdescriptor: #ifndef SICSDESCRIPTOR #define SICSDESCRIPTOR #include +#include typedef struct { char *name; int (*SaveStatus)(void *self, char *name,FILE *fd); void *(*GetInterface)(void *self, int iInterfaceID); + char *description; + char *group; + IPair *pKeys; } ObjectDescriptor, *pObjectDescriptor; /*---------------------------------------------------------------------------*/ @@ -126,6 +130,7 @@ environment controllers fit this bill as well. int (*CheckStatus)(void *self, SConnection *pCon); float (*GetValue)(void *self, SConnection *pCon); int iErrorCount; + int drivableStatus; } IDrivable, *pIDrivable; pIDrivable GetDrivableInterface(void *pObject); @@ -236,7 +241,7 @@ function: @d callfunc @{ typedef void (*KillFuncIT)(void *pData); typedef int (*SICSCallBack)(int iEvent, void *pEventData, - void *pUserData); + void *pUserData, commandContext cc); @} The callback function is meant to return 0 for failure or 1 for success. @@ -264,7 +269,8 @@ interface: int InvokeCallBack(pICallBack pInterface, int iEvent, void *pEventData); /* callback client side */ - long RegisterCallback(pICallBack pInterface, int iEvent, SICSCallBack pFunc, + long RegisterCallback(pICallBack pInterface, commandContext comCon, + int iEvent, SICSCallBack pFunc, void *pUserData, KillFuncIT pKill); int RemoveCallback(pICallBack pInterface, long iID); int RemoveCallback2(pICallBack pInterface, void *pUserData); @@ -360,6 +366,16 @@ The environment interface has just one function associated with it: @o obdes.h -d @{ @ +/*--------------------------------------------------------------------------*/ +/* Additional properties used by the ANSTO site to provide more information + * about each object instance, especially devices. + */ + void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *value); + void SetDescriptorGroup(pObjectDescriptor self, char *group); + void SetDescriptorDescription(pObjectDescriptor self, char *description); + char * GetDescriptorKey(pObjectDescriptor self, char *keyName); + char * GetDescriptorGroup(pObjectDescriptor self); + char * GetDescriptorDescription(pObjectDescriptor self); @} @o interface.h -d @{ @@ -379,6 +395,7 @@ The environment interface has just one function associated with it: #ifndef SICSINTERFACES #define SICSINTERFACES +#include "commandcontext.h" /* interface ID's used to recognize an interface */ #define DRIVEID 513 diff --git a/lin2ang.c b/lin2ang.c index 2badd666..671e5838 100644 --- a/lin2ang.c +++ b/lin2ang.c @@ -8,6 +8,9 @@ copyright: see copyright.h Mark Koennecke, February 2000 + + added zero point handling for the Jochen + Mark Koennecke, December 2005 ---------------------------------------------------------------------------*/ #include #include @@ -25,12 +28,13 @@ pIDrivable pDriv; pMotor lin; float length; + float zero; }Lin2Ang, *pLin2Ang; /*-------------------------- conversion routines -------------------------*/ static float ang2x(pLin2Ang self, float fAngle) { - return self->length*sin(fAngle/RD); + return self->length*sin((fAngle+self->zero)/RD); } /*-----------------------------------------------------------------------*/ static float x2ang(pLin2Ang self, float fX) @@ -40,7 +44,7 @@ assert(self->length > 0.); dt = fX/self->length; - return RD*asin(dt); + return RD*asin(dt) - self->zero; } /*============== functions in the interface ============================*/ static void *Lin2AngGetInterface(void *pData, int iID) @@ -65,7 +69,8 @@ if(!self) return 0; - fprintf(fd,"%s.length %f\n",name, self->length); + fprintf(fd,"%s length %f\n",name, self->length); + fprintf(fd,"%s zero %f\n",name, self->zero); return 1; } @@ -99,9 +104,7 @@ self = (pLin2Ang)pData; assert(self); - fX = self->lin->pDrivInt->GetValue(self->lin,pCon); - MotorGetPar(self->lin,"softzero",&zero); - fX -= zero; + MotorGetSoftPosition(self->lin,pCon,&fX); return x2ang(self,fX); } /*------------------------------------------------------------------------*/ @@ -271,6 +274,35 @@ return 1; } } +/* zero point */ + if(strcmp(argv[1],"zero") == 0) + { + if(argc >= 3) + { + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); + if(iRet != TCL_OK) + { + SCWrite(pCon,"ERROR: zero parameter not recognised as number", + eError); + return 0; + } + if(!SCMatchRights(pCon,usUser)) + { + SCWrite(pCon,"ERROR: Insufficient privilege to change zero point", + eError); + return 0; + } + self->zero = dVal; + SCSendOK(pCon); + return 1; + } + else + { + sprintf(pBueffel,"%s.zero = %f",argv[0],self->zero); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } /* limits */ if(strstr(argv[1],"lim") != NULL) { diff --git a/lin2ang.w b/lin2ang.w index e7fbea79..4a9b34eb 100644 --- a/lin2ang.w +++ b/lin2ang.w @@ -13,6 +13,7 @@ lin2ang's datastructure is quite simple: pIDrivable pDriv; pMotor lin; float length; + float zero; }Lin2Ang; \end{verbatim} The fields are: @@ -22,6 +23,7 @@ The fields are: functionality of this object. \item[lin] The translation table motor to use for driving the angle. \item[length] The length of the arm around which the angle pivots. +\item[zero] The angular zero point of this virtual motor. \end{description} The interface to this is quite simple, most of the functionality is diff --git a/linux_def b/linux_def index ea3a5a18..4feb8a3b 100644 --- a/linux_def +++ b/linux_def @@ -9,4 +9,4 @@ MFLAGS=-f makefile_linux$(DUMMY) -HDFROOT=/afs/psi.ch/project/sinq/linux +HDFROOT=/usr/local diff --git a/macro.c b/macro.c index 7ba4d3e8..77358a13 100644 --- a/macro.c +++ b/macro.c @@ -707,6 +707,15 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, eOut = eWarning; break; case 7: + eOut = eFinish; + break; + case 8: + eOut = eEvent; + break; + case 9: + eOut = eWarning; + break; + case 10: eOut = eError; break; default: @@ -868,7 +877,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, length += 10; pPtr = (char *)malloc(length*sizeof(char)); if(pPtr == NULL){ - SCWrite(pCon,"ERROR: out of memory in TclAction",eError); + SCWrite(pCon, + "ERROR: out of memory in TclAction", + eError); return 0; } memset(pPtr,0,length*sizeof(char)); diff --git a/make_gen b/make_gen index 641f2a3f..88ff0742 100644 --- a/make_gen +++ b/make_gen @@ -29,7 +29,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ fourlib.o motreg.o motreglist.o anticollider.o nxdataset.o \ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\ hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ - mcstashm.o initializer.o remob.o + mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ + sinfox.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/makefile_linux b/makefile_linux index 5dd940c6..660eef3a 100644 --- a/makefile_linux +++ b/makefile_linux @@ -7,14 +7,15 @@ #========================================================================== # assign if the National Instrument GPIB driver is available SINQDIR=/afs/psi.ch/project/sinq -NI= -DHAVENI -NIOBJ= nigpib.o -NILIB=$(SINQDIR)/linux/lib/cib.o +NI= +#NI= -DHAVENI +#NIOBJ= nigpib.o +#NILIB=$(SINQDIR)/linux/lib/cib.o include linux_def CC = gcc -CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) \ +CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 -DNXXML $(NI) \ -Ipsi/hardsup -I. \ -fwritable-strings -DCYGNUS -DNONINTF -g $(DFORTIFY) @@ -22,10 +23,10 @@ BINTARGET = bin EXTRA=nintf.o SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \ psi/tecs/libtecsl.a -LIBS = -static -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ - -ltcl8.3 $(HDFROOT)/lib/libhdf5.a \ +LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ + -ltcl8.4 -lmxml $(HDFROOT)/lib/libhdf5.a \ $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ - $(HDFROOT)/lib/libjpeg.a -ldl -lz -lm -lc + -ljpeg -ldl -lz -lm -lc include make_gen diff --git a/mcstas/dmc/DataNumber b/mcstas/dmc/DataNumber index 9b513bdd..d25e80ac 100644 --- a/mcstas/dmc/DataNumber +++ b/mcstas/dmc/DataNumber @@ -1,3 +1,3 @@ - 106 + 119 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/mcstas/dmc/mcsupport.tcl b/mcstas/dmc/mcsupport.tcl index 6ad4db41..029a2a77 100644 --- a/mcstas/dmc/mcsupport.tcl +++ b/mcstas/dmc/mcsupport.tcl @@ -38,7 +38,8 @@ proc mcstasdump {pid} { error "Trying to dump invalid PID: $pid" } clientput "Dumping ..." - catch {eval exec /usr/bin/kill -USR2 $pid} +# catch {eval exec /usr/bin/kill -USR2 $pid} + catch {eval exec /bin/kill -USR2 $pid} wait $mcwaittime } #----------------------------------------------------------------------- @@ -49,7 +50,9 @@ proc mcstasdump {pid} { # the Unix FAQ this is the best solution...... #---------------------------------------------------------------------- proc readPID {pid} { - set f [ open "| /bin/ps -up $pid" r] +# set f [ open "| /bin/ps -up $pid" r] +# This is system dependent. The above works for SL, below for Suse + set f [ open "| /bin/ps up $pid" r] set pstxt [read $f] close $f return $pstxt @@ -57,12 +60,14 @@ proc readPID {pid} { #---------------------------------------------------------------------- proc mcstasisrunning {pid} { global runningCount runningLast - + +# clientput "Checking McStas PID $pid" if { $pid <= 0} { return 0 } set pstxt " " set ret [catch {set pstxt [readPID $pid]} msg] +# clientput "pstext = $pstxt" set pslist [split $pstxt "\n"] if { [llength $pslist] < 2} { return 0 @@ -84,13 +89,17 @@ proc mcstaskill {pid} { error "Trying to kill invalid PID $pid" } clientput "Killing $pid" - catch {eval exec /usr/bin/kill -TERM $pid} +# catch {eval exec /usr/bin/kill -TERM $pid} msg +# On Suse kill is /bin/kill, on others it is /usr/bin/kill + catch {eval exec /bin/kill -TERM $pid} msg + clientput "Kill message $msg" # catch {mccontrol finish} wait 10 } #----------------------------------------------------------------------- proc mcinstall {} { allowexec /usr/bin/kill + allowexec /bin/kill allowexec /bin/ps Publish mcstasdump User Publish mcstasisrunning User diff --git a/mcstas/dmc/vdmc.tcl b/mcstas/dmc/vdmc.tcl index 4772c0ee..0a0b78ba 100644 --- a/mcstas/dmc/vdmc.tcl +++ b/mcstas/dmc/vdmc.tcl @@ -1,4 +1,4 @@ -# -------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Initialization script for a virtual DMC instrument using a McStas # simulationas a data source # @@ -6,12 +6,12 @@ #--------------------------------------------------------------------------- # O P T I O N S -set home $env(HOME)/src/workspace/sics/mcstas/dmc +set home $env(HOME)/psi/sics/mcstas/dmc #--------------------------------- first all the server options are set #ServerOption RedirectFile $home/stdcdmc -ServerOption ReadTimeOut 1 -ServerOption AcceptTimeOut 1 +ServerOption ReadTimeOut 10 +ServerOption AcceptTimeOut 10 ServerOption ReadUserPasswdTimeout 500000 ServerOption LogFileBaseName "$home/vdmclog" ServerOption LogFileDir $home/ @@ -137,3 +137,13 @@ source $home/vdmccom.tcl #-------------------- configure commandlog commandlog auto commandlog intervall 5 + +#----------- enable sycamore +InstallProtocolHandler +InstallSinfox +source sycFormat.tcl +source /usr/lib/tcllib1.6.1/stooop/stooop.tcl +namespace import stooop::* +source sinfo.tcl +source sycamore.tcl +Publish sinfo Spy diff --git a/mcstas/dmc/vdmccom.tcl b/mcstas/dmc/vdmccom.tcl index 5f264348..2e38ae18 100644 --- a/mcstas/dmc/vdmccom.tcl +++ b/mcstas/dmc/vdmccom.tcl @@ -6,7 +6,7 @@ source $home/mcsupport.tcl if { [info exists vdmcinit] == 0 } { - set vdmcinit 1 + set vdmcinit 1f Publish LogBook Spy Publish count User Publish Repeat User @@ -187,10 +187,9 @@ proc copydmcdata { } { mcreader insertmon \ "/$mcversion/DMC_diff/dmc.xml/PSD_sample/values" \ counter 1 [expr 1./350] - mcreader insertmon \ - "/$mcversion/DMC_diff/dmc.xml/Det9/det9.dat/values" \ - counter 4 - set hmScale [SplitReply [counter getmonitor 4]] +# mcreader insertmon \ +# "/$mcversion/DMC_diff/dmc.xml/Det9/det9.dat/values" \ +# counter 4 set val [mcreader getfield\ "/$mcversion/DMC_diff/dmc.xml/Det9/det9.dat/values"] set l [split $val] @@ -212,7 +211,6 @@ proc dmcdump {pid} { #--do nothing: progress is doing it for us } #-------------------------------------------------------------------------- -#mccontrol configure mcstart rundmcsim mccontrol configure mcstart rundmcoptsim mccontrol configure mccopydata copydmcdata mccontrol configure update 30 diff --git a/mcstas/dmc/vdmcstatus.tcl b/mcstas/dmc/vdmcstatus.tcl index d93288ef..c746d305 100644 --- a/mcstas/dmc/vdmcstatus.tcl +++ b/mcstas/dmc/vdmcstatus.tcl @@ -201,13 +201,13 @@ a9 precision 0.010000 a9 ignorefault 0.000000 a9 AccessCode 2.000000 a9 movecount 10.000000 -title UNKNOWN +title D3C title setAccess 2 user UNKNOWN user setAccess 2 collimation UNKNOWN collimation setAccess 2 -sampleintern na2ca3al2f14 +sampleintern D3C sampleintern setAccess 2 comment1 UNKNOWN comment1 setAccess 2 @@ -215,7 +215,7 @@ comment2 UNKNOWN comment2 setAccess 2 comment3 UNKNOWN comment3 setAccess 2 -starttime 2005-10-19 11:11:44 +starttime 2005-12-20 05:13:05 starttime setAccess 2 adress UNKNOWN adress setAccess 2 diff --git a/motor.c b/motor.c index 85a34ede..84286166 100644 --- a/motor.c +++ b/motor.c @@ -52,6 +52,7 @@ #include "splitter.h" #include "status.h" #include "servlog.h" +#include "tclmotdriv.h" #include "site.h" /*------------------------------------------------------------------------- some lokal defines @@ -385,6 +386,12 @@ static void handleMoveCallback(pMotor self, SConnection *pCon) self = (pMotor)sulf; status = evaluateStatus(self,pCon); + if (self->pDrivInt->drivableStatus!=status) { + ((SConnection *)pCon)->conEventType=STATUS; + ((SConnection *)pCon)->conStatus=status; + SCWrite(pCon, "", eEvent); + self->pDrivInt->drivableStatus=status; + } if(status == HWBusy) { handleMoveCallback(self,pCon); @@ -741,7 +748,7 @@ extern void KillPiPiezo(void *pData); iRet = MotorCheckBoundary(self,fNew,&fHard,pBueffel,511); if(!iRet) { - SCWrite(pCon,pBueffel,eWarning); + SCWrite(pCon,pBueffel,eStatus); SCSetInterrupt(pCon,eAbortOperation); return 0; } @@ -1000,6 +1007,21 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); SCWrite(pCon,pBueffel,eError); return 0; } + }else if (strcmp(argv[2],"tclmot") == 0) + { + pDriver = CreateTclMotDriv(pCon,argc,argv); + if(!pDriver) + { + return 0; + } + /* create the motor */ + pNew = MotorInit("TCLMOT",argv[1],pDriver); + if(!pNew) + { + sprintf(pBueffel,"Failure to create motor %s",argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } } else { @@ -1034,8 +1056,8 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); int i, iLen; iLen = ObParLength(self->ParArray); - sprintf(pBueffel,"Parameter Listing for motor %s\n",self->name); - SCWrite(pCon,pBueffel,eStatus); + sprintf(pBueffel,"Parameter Listing for motor %s",self->name); + SCWrite(pCon,pBueffel,eValue); snprintf(pBueffel,511,"%s.hardupperlim = %f",self->name, self->pDriver->fUpper); SCWrite(pCon,pBueffel,eValue); @@ -1073,6 +1095,7 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); typedef struct { char *pName; SConnection *pCon; + float lastValue; } MotInfo, *pMotInfo; /*-----------------------------------------------------------------------*/ static void KillInfo(void *pData) @@ -1088,7 +1111,8 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); free(self); } /*------------------- The CallBack function for interest ------------------*/ - static int InterestCallback(int iEvent, void *pEvent, void *pUser) + static int InterestCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { pMotInfo pInfo = NULL; char pBueffel[80]; @@ -1099,9 +1123,13 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); psCall = (MotCallback *)pEvent; pInfo = (MotInfo *)pUser; - - sprintf(pBueffel,"%s.position = %f ", pInfo->pName, psCall->fVal); - SCWrite(pInfo->pCon,pBueffel,eValue); + + if (pInfo->lastValue != psCall->fVal) { + pInfo->lastValue = psCall->fVal; + (pInfo->pCon)->conEventType=POSITION; + sprintf(pBueffel,"%s.position = %f ", pInfo->pName, pInfo->lastValue); + SCWriteInContext(pInfo->pCon,pBueffel,eEvent,cc); + } return 1; } /*------------------------------------------------------------------------*/ @@ -1113,7 +1141,8 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); } } /*------------------------ The endscript callback function ----------------*/ - static int EndScriptCallback(int iEvent, void *pEvent, void *pUser) + static int EndScriptCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { char *pScript = NULL; MotCallback *psCall; @@ -1178,7 +1207,7 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); if(!iRet) { sprintf(pBueffel,"Error obtaining position for %s",argv[0]); - SCWrite(pCon,pBueffel,eValue); + SCWrite(pCon,pBueffel,eError); DeleteTokenList(pList); return 0; } @@ -1220,7 +1249,17 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); } pMoti->pName = strdup(argv[0]); pMoti->pCon = pCon; - lID = RegisterCallback(self->pCall, MOTDRIVE, InterestCallback, + iRet = MotorGetSoftPosition(self,pCon,&fValue); + if(!iRet) + { + sprintf(pBueffel,"Failed to register interest, Reason:Error obtaining current position for %s",argv[0]); + SCWrite(pCon,pBueffel,eError); + DeleteTokenList(pList); + return 0; + } + pMoti->lastValue = fValue; + + lID = RegisterCallback(self->pCall, SCGetContext(pCon),MOTDRIVE, InterestCallback, pMoti, KillInfo); SCRegister(pCon,pSics, self->pCall,lID); DeleteTokenList(pList); @@ -1252,7 +1291,7 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); return 0; } self->endScriptID = - RegisterCallback(self->pCall, MOTEND, EndScriptCallback, + RegisterCallback(self->pCall, SCGetContext(pCon),MOTEND, EndScriptCallback, strdup(pCurrent->text), KillScript); SCRegister(pCon,pSics, self->pCall,self->endScriptID); DeleteTokenList(pList); diff --git a/nserver.c b/nserver.c index 10aba0c9..fddfde42 100644 --- a/nserver.c +++ b/nserver.c @@ -6,11 +6,9 @@ Mark Koennecke, October 1996 Revised for use with tasker: Mark Koennecke, September 1997 + Added code to redirect stdout/sterr to file, Mark Koennecke, May 2000 + Define handler in InitServer to ignore SIGPIPE. Paul Hathaway, May 2004 - Added code to redirect stdout/sterr to file. - - Mark Koennecke, May 2000 - Copyright: see copyright.h ----------------------------------------------------------------------------*/ #define NEEDDINTINIT @@ -19,6 +17,7 @@ #include #include #include +#include #include #include #include "sics.h" @@ -93,6 +92,8 @@ memset(self,0,sizeof(SicsServer)); *pServ = self; + /* define any signal handlers */ + signal(SIGPIPE,SIG_IGN); /* configure fortify */ iFortifyScope = Fortify_EnterScope(); @@ -458,7 +459,7 @@ /*-------------------------------------------------------------------------- UserWait: the user command for waiting, expects one arg: time to wait in seconds -*/ +---------------------------------------------------------------------------*/ int UserWait(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { @@ -517,7 +518,7 @@ } } /*------------------------------------------------------------------------*/ - int SicsWait(long lTime) + int SicsWaitOld(long lTime) { WaitStruct sWait; pTaskMan pTasker = NULL; @@ -537,7 +538,28 @@ TaskWait(pTasker,lID); return 1; } +/*------------------------------------------------------------------------ + The new SicsWait is still on probation. It prevents commands to be + executed on the same task on which the Sicswait is acting. + M.K. December 2005 + -------------------------------------------------------------------------*/ + int SicsWait(long lTime) + { + pTaskMan pTasker = NULL; + time_t endTime; + if(pServ->simMode) + { + return 1; + } + pTasker = GetTasker(); + endTime = time(NULL) + lTime; + while(time(NULL) < endTime) + { + TaskYield(pTasker); + } + return 1; + } /*-------------------------------------------------------------------------*/ void ServerWriteGlobal(char *pMessage,int iOut) { diff --git a/nxupdate.c b/nxupdate.c index f72b998a..0bd0e028 100644 --- a/nxupdate.c +++ b/nxupdate.c @@ -46,7 +46,8 @@ static int UpdateTask(void *pData){ } } /*--------------------------------------------------------------------*/ -static int CountCallback(int iEvent, void *pEventData, void *pUser){ +static int CountCallback(int iEvent, void *pEventData, void *pUser, + commandContext cc){ pNXupdate self = NULL; SConnection *pCon = NULL; @@ -257,6 +258,7 @@ int UpdateFactory(SConnection *pCon, SicsInterp *pSics, void *pData, char pBueffel[256]; pNXupdate self = NULL; CommandList *pCom = NULL; + commandContext comCon; if(argc < 3){ SCWrite(pCon,"ERROR: insuffcient number of argument to UpdateFactory", @@ -309,9 +311,11 @@ int UpdateFactory(SConnection *pCon, SicsInterp *pSics, void *pData, /* register callbacks */ - RegisterCallback(pCall,COUNTSTART,CountCallback, + comCon.transID = 0; + strncpy(comCon.deviceID,"internal",SCDEVIDLEN); + RegisterCallback(pCall,comCon,COUNTSTART,CountCallback, self,NULL); - RegisterCallback(pCall,COUNTEND,CountCallback, + RegisterCallback(pCall,comCon,COUNTEND,CountCallback, self,NULL); AddCommand(pSics,argv[1],UpdateAction,KillUpdate,self); diff --git a/obdes.c b/obdes.c index 44a562c7..92c0040d 100644 --- a/obdes.c +++ b/obdes.c @@ -66,6 +66,9 @@ return NULL; } pRes->name = strdup(name); + pRes->pKeys = NULL; + pRes->description = NULL; + pRes->group = NULL; pRes->SaveStatus = DefaultSave; pRes->GetInterface = DefaultGetInterface; return pRes; @@ -74,10 +77,10 @@ void DeleteDescriptor(pObjectDescriptor self) { assert(self); - - if(self->name) - free(self->name); - + if(self->name) free(self->name); + if(self->description) free(self->description); + if(self->group) free(self->group); + if(self->pKeys) IFDeleteOptions(self->pKeys); free(self); } @@ -134,11 +137,72 @@ return 0; } /*------------------------------------------------------------------------*/ -pObjectDescriptor FindDescriptor(void *pData) -{ - pDummy pDum = NULL; - - assert(pData); - pDum = (pDummy)pData; - return pDum->pDescriptor; -} + pObjectDescriptor FindDescriptor(void *pData) + { + pDummy pDum = NULL; + + assert(pData); + pDum = (pDummy)pData; + return pDum->pDescriptor; + } +/*--------------------------------------------------------------------------*/ + void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *eltValue) + { + if(NULL!=self) + { + IFSetOption(self->pKeys,keyName,eltValue); + } + } +/*--------------------------------------------------------------------------*/ + void SetDescriptorGroup(pObjectDescriptor self, char *group) + { + if(NULL==self) + { + return; + } + if(NULL != self->group) + { + free(self->group); + } + self->group = strdup(group); + } +/*--------------------------------------------------------------------------*/ + void SetDescriptorDescription(pObjectDescriptor self, char *description) + { + if(NULL==self) + { + return; + } + if(NULL != self->description) + { + free(self->description); + } + self->description = strdup(description); + } + /*--------------------------------------------------------------------------*/ + char * GetDescriptorKey(pObjectDescriptor self, char *keyName) + { + if(NULL==self) + { + return NULL; + } + return IFindOption(self->pKeys,keyName); + } +/*--------------------------------------------------------------------------*/ + char * GetDescriptorGroup(pObjectDescriptor self) + { + if(NULL==self) + { + return NULL; + } + return self->group; + } +/*--------------------------------------------------------------------------*/ + char * GetDescriptorDescription(pObjectDescriptor self) + { + if(NULL==self) + { + return NULL; + } + return self->description; + } diff --git a/obdes.h b/obdes.h index ccb363d9..3f700d6f 100644 --- a/obdes.h +++ b/obdes.h @@ -1,32 +1,36 @@ -#line 361 "interface.w" +#line 367 "interface.w" #line 29 "interface.w" /*-------------------------------------------------------------------------- - In SICS there is the to find out what an - object is capable of at runtime. If this has been done a general - way to access those capabilities is needed. In order to do all - this each SICS-object is required to carry an object descriptor - struct as first parameter in its class/object struct. Additionslly - it is required to initialize this struct to something sensible. - - This file defines this struct. Additionally a few functions of - general use are prototyped. - - Mark Koennecke, June, 1997 - - copyrigth: see implementation file + In SICS there is the to find out what an + object is capable of at runtime. If this has been done a general + way to access those capabilities is needed. In order to do all + this each SICS-object is required to carry an object descriptor + struct as first parameter in its class/object struct. Additionslly + it is required to initialize this struct to something sensible. + + This file defines this struct. Additionally a few functions of + general use are prototyped. + + Mark Koennecke, June, 1997 + + copyrigth: see implementation file ----------------------------------------------------------------------------*/ #ifndef SICSDESCRIPTOR #define SICSDESCRIPTOR #include +#include typedef struct { char *name; int (*SaveStatus)(void *self, char *name,FILE *fd); void *(*GetInterface)(void *self, int iInterfaceID); + char *description; + char *group; + IPair *pKeys; } ObjectDescriptor, *pObjectDescriptor; /*---------------------------------------------------------------------------*/ @@ -35,9 +39,9 @@ pObjectDescriptor FindDescriptor(void *pData); /*============================================================================ - Objects which do not carry data need a dummy descriptor. Otherwise - drive or scan will protection fault when trying to drive something - which should not be driven. This is defined below. + Objects which do not carry data need a dummy descriptor. Otherwise + drive or scan will protection fault when trying to drive something + which should not be driven. This is defined below. */ typedef struct { @@ -46,11 +50,21 @@ typedef struct { pDummy CreateDummy(char *name); - void KillDummy(void *pData); + void KillDummy(void *pData); int iHasType(void *pData, char *Type); #endif -#line 362 "interface.w" +#line 368 "interface.w" +/*--------------------------------------------------------------------------*/ +/* Additional properties used by the ANSTO site to provide more information + * about each object instance, especially devices. + */ + void SetDescriptorKey(pObjectDescriptor self, char *keyName, char *value); + void SetDescriptorGroup(pObjectDescriptor self, char *group); + void SetDescriptorDescription(pObjectDescriptor self, char *description); + char * GetDescriptorKey(pObjectDescriptor self, char *keyName); + char * GetDescriptorGroup(pObjectDescriptor self); + char * GetDescriptorDescription(pObjectDescriptor self); diff --git a/ofac.c b/ofac.c index 071779c0..00f1759c 100644 --- a/ofac.c +++ b/ofac.c @@ -114,6 +114,8 @@ #include "tasscanub.h" #include "mcreader.h" #include "mccontrol.h" +#include "protocol.h" +#include "sinfox.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -237,6 +239,7 @@ AddCommand(pInter,"sicsdatafactory",SICSDataFactory,NULL,NULL); AddCommand(pInter,"scriptcallback",CallbackScript,NULL,NULL); AddCommand(pInter,"help",SicsHelp,KillHelp,NULL); + AddCommand(pInter,"sicsatt",SicsAtt,NULL,NULL); /* commands to do with the executor. Only StopExe carries the DeleteFunction in order to avoid double deletion. All the @@ -311,6 +314,10 @@ McStasReaderFactory,NULL,NULL); AddCommand(pInter,"MakeMcStasController", McStasControllerFactory,NULL,NULL); + AddCommand(pInter,"InstallProtocolHandler", + InstallProtocol,NULL,NULL); + AddCommand(pInter,"InstallSinfox", + InstallSinfox,NULL,NULL); /* install site specific commands @@ -376,7 +383,8 @@ RemoveCommand(pSics,"MakeTasUB"); RemoveCommand(pSics,"MakeTasScan"); RemoveCommand(pSics,"MakemcStasReader"); - + RemoveCommand(pSics,"InstallProtocolHandler"); + RemoveCommand(pSics,"InstallSinfox"); /* remove site specific installation commands */ diff --git a/outcode.c b/outcode.c index eb9ae53b..e52f6f58 100644 --- a/outcode.c +++ b/outcode.c @@ -15,8 +15,11 @@ "inerror", "status", "value", + "start", + "finish", + "event", "warning", "error", NULL }; - static int iNoCodes = 7; + static int iNoCodes = 10; #endif diff --git a/perfmon.c b/perfmon.c index e43cfaac..7fd72800 100644 --- a/perfmon.c +++ b/perfmon.c @@ -147,7 +147,8 @@ return self->fCPS; } /*------------------- The CallBack function for interest ------------------*/ - static int InterestCallback(int iEvent, void *pEvent, void *pUser) + static int InterestCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { float *fPos; SConnection *pCon; @@ -160,7 +161,7 @@ pCon = (SConnection *)pUser; sprintf(pBueffel,"Performance = %f", *fPos); - SCWrite(pCon,pBueffel,eValue); + SCWriteInContext(pCon,pBueffel,eValue,cc); return 1; } /*---------------------------------------------------------------------------- @@ -206,7 +207,8 @@ if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, VALUECHANGE, InterestCallback, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + VALUECHANGE, InterestCallback, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); diff --git a/protocol.c b/protocol.c new file mode 100644 index 00000000..fc052127 --- /dev/null +++ b/protocol.c @@ -0,0 +1,616 @@ +/*-------------------------------------------------------------------------- + ANSTO Protocol Command Object + Paul Hathaway, November, 2004 + Copyright: See copyright.txt +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "protocol.h" + +#define MAXMSG 1024 +#define INIT_STR_SIZE 256 +#define STR_RESIZE_LENGTH 256 + +typedef struct __Protocol { + pObjectDescriptor pDes; /* required as first field */ + char *name; /* protocol handler name */ + char *version; /* protocol version string */ + int iNumPros; /* number of valid protocols? */ + writeFunc defaultWriter; /* default write function */ + int isDefaultSet; + char *pProList[5]; /* list of valid protocols? */ +} Protocol; + +char *pEventType[]={ +"VALUECHANGE", /* 0 */ +"MOTDRIVE", /* 1 */ +"MONITOR", /* 2 */ +"ROTSTART", /* 3 */ +"ROTMOVE", /* 4 */ +"SCANEND", /* 5 */ +"SCANSTART", /* 6 */ +"SCANPOINT", /* 7 */ +"WLCHANGE", /* 8 */ +"REFLECTIONDONE", /* 9 */ +"COUNTSTART", /* 10 */ +"COUNTEND", /* 11 */ +"FILELOADED", /* 12 */ +"MOTEND", /* 13 */ +"BATCHSTART", /* 14 */ +"BATCHAREA", /* 15 */ +"BATCHEND", /* 16 */ +"DRIVSTAT", /* 17 */ +"STATUS", /* 18 */ +"POSITION" /* 19 Motor position events, ffr */ +}; + +char *pStatus[]={ +"UNSET", +"OKOK", /* 1 */ +"HWIdle", /* 2 */ +"HWBusy", /* 3 */ +"HWFault", /* 4 */ +"HWPosFault", /* 5 */ +"HWCrash", /* 6 */ +"NOMEMORY", /* 7 */ +"HWNoBeam", /* 8 */ +"HWPause", /* 9 */ +"HWWarn", /* 10 */ +"HWRedo", /* 11 */ +}; + +typedef struct __Protocol *pProtocol; + +/* alternate implementation of protocol list if data hiding in + * Protocol struct via CreateProtocol does not work + * static char *pPros[] = { + * "default", + * "outcodes", + * "sycamore" + * NULL }; + * static int iNumPros = 3 + */ + +pProtocol CreateProtocol(void); +static int ProtocolOptions(SConnection* pCon, pProtocol pPro); +static int ProtocolHelp(SConnection* pCon, Protocol* pPro); +static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName); +static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, + int *pIndex); +static int ProtocolList(SConnection* pCon, Protocol* pPro); +int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +static int EnumChoice(char *pList[], int iLength, char *pInput); +static int InitDefaultProtocol(SConnection* pCon, Protocol *pPro); + +/* Signatures for protocol writers implemented in this file */ +int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); + +/*--------------------------------------------------------------------------*/ +pProtocol CreateProtocol(void) +{ + int i, iNumPros = 4; + char *pPros[5] = {"default", + "normal", + "withcode", + "sycamore", + NULL + }; + pProtocol pNew = NULL; + + pNew = (pProtocol)malloc(sizeof(Protocol)); + if(!pNew) + { + return NULL; + } + pNew->pDes = CreateDescriptor("Protocol"); + if(!pNew->pDes) + { + free(pNew); + return NULL; + } + + pNew->name = strdup("protocol"); + pNew->version = strdup("1.0"); + pNew->iNumPros = iNumPros; +// pNew->pProList = (char *)malloc(sizeof(pPros)); + for(i=0;ipProList[i] = strdup(pPros[i]); + } + pNew->pProList[i] = NULL; + pNew->isDefaultSet = 0; + + return pNew; +} + +/*-------------------------------------------------------------------------*/ +void DeleteProtocol(void *self) +{ + int i; + pProtocol pOld = (pProtocol)self; + + if(NULL==pOld) + { + return; + } + if(pOld->name) + { + free(pOld->name); + } + if(pOld->pDes) + { + DeleteDescriptor(pOld->pDes); + } + if(pOld->version) + { + free(pOld->version); + } + if(pOld->pProList) + { + i = 0; + while(NULL!=pOld->pProList[i]) + { + free(pOld->pProList[i]); + i++; + } + } + free(pOld); +} +/*------------------------------------------------------------------*/ +static int ContextDo(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + commandContext comCon; + char command[1024]; + int status; + + if(argc < 3){ + SCWrite(pCon,"ERROR: insufficient arguments to contextdo",eError); + return 0; + } + + status = Tcl_GetInt(pSics->pTcl,argv[1],&comCon.transID); + if(status != TCL_OK){ + snprintf(command,1023,"ERROR: failed to convert %s to transaction ID", argv[1]); + SCWrite(pCon,command,eError); + return 0; + } + strncpy(comCon.deviceID,argv[2],SCDEVIDLEN); + memset(command,0,1024*sizeof(char)); + Arg2Text(argc-2,&argv[2],command,1023); + + SCPushContext2(pCon,comCon); + status = InterpExecute(pSics,pCon,command); + SCPopContext(pCon); + return status; +} +/*--------------------------------------------------------------------------*/ +int InstallProtocol(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) +{ + pProtocol pNew = NULL; + pNew = CreateProtocol(); + if(NULL==pNew) + { + SCWrite(pCon,"No memory to create Protocol",eError); + return 0; + } + AddCommand(pSics,"Protocol",ProtocolAction,DeleteProtocol,pNew); + AddCommand(pSics,"contextdo",ContextDo,NULL,NULL); + SCSendOK(pCon); + return 1; +} + +/*------------------------------------------------------------------------*/ +static int ProtocolOptions(SConnection* pCon, pProtocol pPro) +{ + int i; + char pBuffer[80]; + for(i=0;iiNumPros;i++) + { + sprintf(pBuffer,"Protocol[%d] = %s",i,pPro->pProList[i]); + SCWrite(pCon,pBuffer,eStatus); + } + return 1; +} + +/*------------------------------------------------------------------------*/ +static int ProtocolHelp(SConnection* pCon, Protocol* pPro) +{ + SCWrite(pCon, + "Usage: protocol {help|list|options|reset} | set protocolName", + eStatus); + return 1; +} + +/*------------------------------------------------------------------------*/ +static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName) +{ + int proID; + if(!SCVerifyConnection(pCon)) + { + return 0; + } + + /* lazy initialisation of defaultWriter since connection is verified */ + InitDefaultProtocol(pCon,pPro); + + /* Do not die if no data */ + if(NULL == pProName) + { + return 0; + } + + /* check list of protocols for valid name and assign functions based */ + /* on match of pProName */ + proID = EnumChoice(pPro->pProList,pPro->iNumPros,pProName); + switch(proID) + { + case -1: /* invalid */ + return 0; + break; + + case 1: /* normal (connection start default) */ + SCSetWriteFunc(pCon,SCNormalWrite); + break; + + case 2: /* outcodes */ + SCSetWriteFunc(pCon,SCWriteWithOutcode); + break; + + case 3: /* sycamore */ + SCSetWriteFunc(pCon,SCWriteSycamore); + break; + + case 0: /* default = psi_sics */ + default: + SCSetWriteFunc(pCon,pPro->defaultWriter); + break; + } + pCon->iProtocolID = proID; + SCSendOK(pCon); + return 1; +} + +/*------------------------------------------------------------------------*/ +static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, + int *pIndex) +{ + if(!SCVerifyConnection(pCon)) + { + return 0; + } + + /* lazy initialisation of defaultWriter since connection is verified */ + if(0==pPro->isDefaultSet) + { + pPro->defaultWriter = SCGetWriteFunc(pCon); + pPro->isDefaultSet = 1; + pCon->iProtocolID = 0; + } + + *pIndex = (int)malloc(sizeof(int)); + *pIndex = pCon->iProtocolID; + + /* check list of protocols for valid name */ + switch(*pIndex) + { + case 0: /* default = psi_sics */ + case 1: /* normal (connection start default) */ + case 2: /* outcodes */ + case 3: /* sycamore */ + pProName = strdup(pPro->pProList[*pIndex]); + return 1; + break; + default: + return 0; + break; + } +} + +/*------------------------------------------------------------------------*/ +static int ProtocolList(SConnection* pCon, Protocol* pPro) +{ + SCWrite(pCon, + "Usage: protocol {help|list|options|reset} | set protocolName", + eStatus); + return 1; +} + +/*-------------------------------------------------------------------------*/ +int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) +{ + int iRet; + char **argx; + FuPaResult PaRes; + pProtocol pPro = NULL; + + const int iNumCmds = 5; + FuncTemplate CommandTemplate[] = { + {"help",0,{0,0}}, + {"list",0,{0,0}}, + {"options",0,{0,0}}, + {"set",1,{FUPATEXT}}, + {"reset",0,{0,0}}, + NULL + }; + + assert(pCon); + assert(pSics); + pPro = (pProtocol)pData; + assert(pPro); + + /* You need to have User level access rights to use this facility */ + if(!SCMatchRights(pCon,usUser)) + { + return 0; + } + + /* parse function args */ + argtolower(argc,argv); + argx = &argv[1]; + iRet = EvaluateFuPa((pFuncTemplate)&CommandTemplate,iNumCmds,argc-1,argx,&PaRes); + + /* if invalid (iRet < 0) then default to "help" command */ + + switch(iRet) + { + case 1: /* list */ + iRet = ProtocolList(pCon,pPro); + break; + case 2: /* options */ + iRet = ProtocolOptions(pCon,pPro); + break; + case 3: /* set */ + iRet = ProtocolSet(pCon,pPro,PaRes.Arg[0].text); + break; + case 4: /* reset */ + iRet = ProtocolSet(pCon,pPro,"default"); + break; + case 0: /* help */ + default: + iRet = ProtocolHelp(pCon,pPro); + break; + } + return iRet; +} + +/*-------------------------------------------------------------------------*/ +static int EnumChoice(char *pList[], int iLength, char *pInput) +{ + int i; + int iRet = -1; + + for(i=0;iisDefaultSet) + { + pPro->defaultWriter = SCGetWriteFunc(pCon); + pPro->isDefaultSet = 1; + pCon->iProtocolID = 0; + } + return pPro->isDefaultSet; +} +/*---------------------------------------------------------------------*/ +int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut) +{ + int i, iPtr, iRet; + int bDevIDdone = 0; + int bFlagDone = 0; + char pBueffel[MAXMSG]; + long taskID = 0; +/* char pPrefix[40];*/ + pDynString pMsg = NULL; + pDynString pMsgOut = NULL; + pDynString parseCmd = NULL; + SicsInterp *pSics; + TokenList *pList = NULL; + TokenList *pCurrent; + commandContext comCon; + char *savedTclResult = NULL; + +/* For calling sycParse from interpreter */ + char **argv = NULL; + int argc; + char *parser = "sycformat "; + char batchName[50]; + strcpy(batchName,"::ansto::batch::next"); + CommandList *pCommand = NULL; + + if(!SCVerifyConnection(pCon)) + { + DeleteDynString(parseCmd); + return 0; + } + + comCon = SCGetContext(pCon); + + if (strcmp(comCon.deviceID, batchName) == 0) { + DeleteDynString(parseCmd); + return 1; + } + /* Return 0 without dying if no message data */ + if(pBuffer == NULL) + { + DeleteDynString(parseCmd); + return 0; + } + + /* + build the Tcl-command to execute for formatting the + data into a sycamore string + */ + pSics = GetInterpreter(); + taskID = comCon.transID; + taskID = taskID % 1000000; + + pMsg = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); + pBueffel[0] = '\0'; + + sprintf(pBueffel,"con%4.4d",pCon->ident); /* field 1: connID */ + DynStringConcat(pMsg,pBueffel); + sprintf(pBueffel," t%6.6d",taskID); /* field 2: taskID */ + DynStringConcat(pMsg,pBueffel); + DynStringConcatChar(pMsg,' '); + /* deviceID */ + DynStringConcat(pMsg,comCon.deviceID); + DynStringConcatChar(pMsg,' '); + +/* msgFlag */ + switch(iOut) { + case 5: /* eValue */ + DynStringConcat(pMsg,"out"); + break; + default: + DynStringConcat(pMsg,pCode[iOut]); + break; + } + DynStringConcatChar(pMsg,' '); + DynStringConcat(pMsg, " { "); + DynStringConcat(pMsg, comCon.deviceID); + DynStringConcat(pMsg, " } {"); + if (iOut == eStart){ + DynStringConcat(pMsg, comCon.deviceID); + } + parseCmd = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); + DynStringCopy(parseCmd, parser); + DynStringConcat(parseCmd,GetCharArray(pMsg)); + DynStringConcat(parseCmd,pBuffer); + + if (iOut == eEvent) { + DynStringConcat(parseCmd, " type."); + DynStringConcat(parseCmd, pEventType[pCon->conEventType]); + DynStringConcat(parseCmd, " status."); + DynStringConcat(parseCmd, pStatus[pCon->conStatus]); + } + DynStringConcatChar(parseCmd, '}'); + savedTclResult = strdup(Tcl_GetStringResult(pSics->pTcl)); + Tcl_Eval(pSics->pTcl, GetCharArray(parseCmd)); + pMsgOut = CreateDynString(INIT_STR_SIZE, STR_RESIZE_LENGTH); + DynStringCopy(pMsgOut, (char *)Tcl_GetStringResult(pSics->pTcl)); + if(savedTclResult != NULL){ + Tcl_SetResult(pSics->pTcl,savedTclResult,TCL_VOLATILE); + free(savedTclResult); + } + + /* log it for any case */ + if(pCon->pSock) + { + iRet = pCon->pSock->sockid; + } + else + { + iRet = 0; + } + sprintf(pBueffel,"Next line intended for socket: %d",iRet); + SICSLogWrite(pBueffel,eInternal); + SICSLogWrite(GetCharArray(pMsgOut),iOut); + + /* write to commandlog if user or manager privilege */ + if(SCGetRights(pCon) <= usUser) + { + sprintf(pBueffel,"To sock %d :",iRet); + WriteToCommandLog(pBueffel,GetCharArray(pMsgOut)); + } + + /* put it into the interpreter if present */ + if(SCinMacro(pCon)) + { + InterpWrite(pSics,pBuffer); + iRet = SCDoSockWrite(pCon,GetCharArray(pMsgOut)); + } + else /* not in interpreter, normal logic */ + { + /* is this really to be printed ? */ + if(iOut < pCon->iOutput) + { + DeleteDynString(parseCmd); + DeleteDynString(pMsg); + DeleteDynString(pMsgOut); + return 0; + } + /* first the socket */ + /*strcat(pMsg, pBueffel);*/ + iRet = SCDoSockWrite(pCon,GetCharArray(pMsgOut)); + SCWriteToLogFiles(pCon,GetCharArray(pMsgOut)); + } + if(pMsgOut != NULL){ + DeleteDynString(pMsgOut); + } + DeleteDynString(parseCmd); + DeleteDynString(pMsg); + return 1; +} + +/*------------------------------------------------------------------------*/ +/* Protocol API */ +char * GetProtocolName(SConnection* pCon) +{ + pProtocol pPro; + pSicsInterp pSics; + + if(!SCVerifyConnection(pCon)) + { + return NULL; + } + + pSics = GetInterpreter(); + if(!pSics) return NULL; + + pPro = FindCommandData(pSics,"protocol","Protocol"); + if(!pPro) return NULL; + + InitDefaultProtocol(pCon,pPro); + + /* check list of protocols for valid name */ + switch(pCon->iProtocolID) + { + case 0: /* default = psi_sics */ + case 1: /* normal (connection start default) */ + case 2: /* outcodes */ + case 3: /* sycamore */ + return strdup(pPro->pProList[pCon->iProtocolID]); + break; + default: + return strdup("invalid"); + break; + } +} + +/*----------------------------------*/ +int GetProtocolID(SConnection* pCon) +{ + if(NULL!=pCon) + { + return pCon->iProtocolID; + } + return -1; +} diff --git a/protocol.h b/protocol.h new file mode 100644 index 00000000..c3b8c585 --- /dev/null +++ b/protocol.h @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------- +----------------------------------------------------------------------------*/ +#ifndef ANSTO_PROTOCOL +#define ANSTO_PROTOCOL +#include +#include + +static const int iNumProTags = 2; +static char *pProTags[3] = { + "start", + "finish", + NULL +}; + +#define esStart -1 +#define esFinish -2 + +/*--------------------- lifecycle -------------------------------------- */ +int InstallProtocol(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +void DeleteProtocol(void *pSelf); + +/*--------------------- operations --------------------------------------*/ +int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +/*--------------------- implement protocol sycamore ---------------------*/ +int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut); + +/*--------------------- implement protocol API -----------------------*/ +char * GetProtocolName(SConnection *pCon); +int GetProtocolID(SConnection *pCon); +/*-----------------------------------------------------------------------*/ +#endif diff --git a/rs232controller.c b/rs232controller.c index b26bf234..92934823 100644 --- a/rs232controller.c +++ b/rs232controller.c @@ -250,6 +250,32 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){ } return 1; } +/*----------------------------------------------------------------------*/ +int readRS232UntilWord(prs232 self, + char *buffer, int buflen, char *word){ + time_t endTime; + int status; + int bytesRead = 0; + + endTime = time(NULL) + self->timeout; + memset(buffer,0,buflen); + while(time(NULL) < endTime){ + if(availableRS232(self)){ + bytesRead = recv(self->pSock->sockid,buffer + bytesRead, + buflen - bytesRead - 1,0); + if(bytesRead < 0){ + return BADREAD; + } + if(strstr(buffer,word) != NULL) { + return 1; + } + } else { + SicsWait(1); + } + } + + return 0; +} /*-----------------------------------------------------------------------*/ int availableRS232(prs232 self) { @@ -736,6 +762,31 @@ int RS232Action(SConnection *pCon, SicsInterp *pSics, SCWrite(pCon,pBuffer,eValue); return 1; } + else if(strcmp(argv[1],"readchar") == 0){ + if(argc < 3){ + SCWrite(pCon,"ERROR: need number of chars to read",eError); + return 0; + } + iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iRead); + if(iRet != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to number",eError); + return 0; + } + if(!availableRS232(self)) + { + SCWrite(pCon,"Nothing to read!",eError); + return 1; + } + iRet = readRS232(self,pBuffer,&iRead); + if(iRet < 0) + { + getRS232Error(iRet,pError,255); + SCWrite(pCon,pError,eError); + return 0; + } + SCWrite(pCon,pBuffer,eValue); + return 1; + } else if(strcmp(argv[1],"available") == 0) { iRet = availableRS232(self); diff --git a/rs232controller.h b/rs232controller.h index 92ec9722..beddb2d2 100644 --- a/rs232controller.h +++ b/rs232controller.h @@ -56,6 +56,8 @@ int writeRS232(prs232 self, void *data, int dataLen); int readRS232(prs232 self, void *data, int *dataLen); int readRS232TillTerm(prs232 self, void *data, int *datalen); + int readRS232UntilWord(prs232 self, + char *buffer, int buflen, char *word); int availableRS232(prs232 self); int availableNetRS232(prs232 self); int transactRS232(prs232 self, void *send, int sendLen, diff --git a/scan.c b/scan.c index 730bedec..911649af 100644 --- a/scan.c +++ b/scan.c @@ -1236,7 +1236,8 @@ int isScanVarSoft(pScanData self){ return 1; } /*--------------------------------------------------------------------------*/ - static int ScanInterest(int iEvent, void *pEventData, void *pUser) + static int ScanInterest(int iEvent, void *pEventData, void *pUser, + commandContext cc) { pScanData self = NULL; SConnection *pCon = NULL; @@ -1253,12 +1254,12 @@ int isScanVarSoft(pScanData self){ if(iEvent == SCANSTART) { - SCWrite(pCon,"NewScan",eWarning); + SCWriteInContext(pCon,"NewScan",eWarning,cc); return 1; } else if(iEvent == SCANEND) { - SCWrite(pCon,"ScanEnd",eWarning); + SCWriteInContext(pCon,"ScanEnd",eWarning,cc); return 1; } else if(iEvent == SCANPOINT) @@ -1299,7 +1300,8 @@ int isScanVarSoft(pScanData self){ return 1; } /*--------------------------------------------------------------------------*/ - static int ScanDynInterest(int iEvent, void *pEventData, void *pUser) + static int ScanDynInterest(int iEvent, void *pEventData, void *pUser, + commandContext cc) { pScanData self = NULL; SConnection *pCon = NULL; @@ -1319,12 +1321,12 @@ int isScanVarSoft(pScanData self){ if(iEvent == SCANSTART) { - SCWrite(pCon,"NewScan",eWarning); + SCWriteInContext(pCon,"NewScan",eWarning,cc); return 1; } else if(iEvent == SCANEND) { - SCWrite(pCon,"ScanEnd",eWarning); + SCWriteInContext(pCon,"ScanEnd",eWarning,cc); return 1; } else if(iEvent == SCANPOINT) @@ -1346,12 +1348,13 @@ int isScanVarSoft(pScanData self){ } snprintf(pBueffel,255,"%s.scanpoint = {%d %f %ld}", self->objectName,i,fVal,lVal); - SCWrite(pCon,pBueffel,eValue); + SCWriteInContext(pCon,pBueffel,eValue,cc); } return 1; } /*--------------------------------------------------------------------------*/ - static int ScanUUInterest(int iEvent, void *pEventData, void *pUser) + static int ScanUUInterest(int iEvent, void *pEventData, void *pUser, + commandContext cc) { pScanData self = NULL; SConnection *pCon = NULL; @@ -1368,12 +1371,12 @@ int isScanVarSoft(pScanData self){ if(iEvent == SCANSTART) { - SCWrite(pCon,"NewScan",eWarning); + SCWriteInContext(pCon,"NewScan",eWarning,cc); return 1; } else if(iEvent == SCANEND) { - SCWrite(pCon,"ScanEnd",eWarning); + SCWriteInContext(pCon,"ScanEnd",eWarning,cc); return 1; } else if(iEvent == SCANPOINT) @@ -1395,7 +1398,9 @@ int isScanVarSoft(pScanData self){ { iData[i] = htonl((int)lData[i]); } + SCPushContext2(pCon,cc); SCWriteUUencoded(pCon,"ScanData",iData,self->iNP*sizeof(int)); + SCPopContext(pCon); free(lData); free(iData); return 1; @@ -1896,13 +1901,13 @@ static int DumpScan(pScanData self, SConnection *pCon) /*-------- interest */ else if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, SCANSTART, ScanInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANSTART, ScanInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANEND, ScanInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANEND, ScanInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANPOINT, ScanInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANPOINT, ScanInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -1911,13 +1916,13 @@ static int DumpScan(pScanData self, SConnection *pCon) /*-------- interest */ else if(strcmp(argv[1],"dyninterest") == 0) { - lID = RegisterCallback(self->pCall, SCANSTART, ScanDynInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANSTART, ScanDynInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANEND, ScanDynInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), SCANEND, ScanDynInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANPOINT, ScanDynInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANPOINT, ScanDynInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -1926,13 +1931,13 @@ static int DumpScan(pScanData self, SConnection *pCon) /*-------- uuinterest */ else if(strcmp(argv[1],"uuinterest") == 0) { - lID = RegisterCallback(self->pCall, SCANSTART, ScanUUInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANSTART, ScanUUInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANEND, ScanUUInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANEND, ScanUUInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, SCANPOINT, ScanUUInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon),SCANPOINT, ScanUUInterest, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); diff --git a/selvar.c b/selvar.c index 609603ea..492dec11 100644 --- a/selvar.c +++ b/selvar.c @@ -474,7 +474,8 @@ return 1; } /*------------------------------------------------------------------------*/ - static int WaveLengthCallBack(int iEvent, void *pEvent, void *pUser) + static int WaveLengthCallBack(int iEvent, void *pEvent, void *pUser, + commandContext cc) { SConnection *pCon = NULL; pSelVar self = NULL; @@ -488,7 +489,7 @@ fVal = GetSelValue(self,pCon); sprintf(pBueffel,"%s.value = %f", self->name, fVal); - SCWrite(pCon,pBueffel,eValue); + SCWriteInContext(pCon,pBueffel,eValue,cc); return 1; } /*-------------------------------------------------------------------------- @@ -520,7 +521,8 @@ strtolower(argv[1]); if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, WLCHANGE, WaveLengthCallBack, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + WLCHANGE, WaveLengthCallBack, pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -589,8 +591,9 @@ strtolower(argv[1]); if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(self->pCall, WLCHANGE, WaveLengthCallBack, - pCon, NULL); + lID = RegisterCallback(self->pCall, SCGetContext(pCon), + WLCHANGE, WaveLengthCallBack, + pCon, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); return 1; diff --git a/servlog.c b/servlog.c index 8c03e171..82936710 100644 --- a/servlog.c +++ b/servlog.c @@ -39,6 +39,13 @@ IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + + Modified: Paul Hathaway, June 2004 + SICSLogWrite + - no longer asserts existence of the log file, writing + to stderr and skipping further file writes. + - NETWrites log message (if enabled) before attempt to write to file + - uses OpenVerifyLogFile helper function (removed duplicate code) -----------------------------------------------------------------------------*/ #include "fortify.h" #include @@ -223,7 +230,38 @@ static FILE *fLogFile = NULL; static int iFile = 0; static int iLineCount = 0; + static int iLogUsable = 1; +/*---------------------------------------------------------------------------*/ + int OpenVerifyLogFile() + { + char pFile[256]; + char *pChar = NULL; + + pChar = IFindOption(pSICSOptions,"LogFileBaseName"); + if(!pChar) + { /* Try to write to file "server" in*/ + strcpy(pFile,"server"); + } + else + { + strcpy(pFile,pChar); + } + sprintf(pFile,"%s%2.2d.log",pFile, iFile); + fLogFile = fopen(pFile,"w"); + if(!fLogFile) + { + fprintf(stderr,"ERROR: Cannot open logfile %s for writing\n",pFile); + fLogFile = NULL; + return 0; + } + else + { + return 1; + } + } + +/*---------------------------------------------------------------------------*/ void SICSLogWrite(char *pText, OutCode eOut) { char pFile[256]; @@ -234,67 +272,47 @@ #ifdef NOLOG return ; #endif - if(fLogFile == NULL) /* first time of */ + + /* do all captured */ + pCurrent = pCapture; + while(pCurrent) + { + if( (pCurrent->iOut == eOut) || (pCurrent->iAllFlag == 1) ) + { + NETWrite(pCurrent->pCon->pSock,pText,strlen(pText)); + } + pCurrent = pCurrent->pNext; + } + + if(0 == iLogUsable) return; + + if(fLogFile == NULL) /* first time of use*/ { /* no options: startup or serious trouble, print to stdout*/ if(!pSICSOptions) { - printf(" %s \n",pText); + printf("WARNING: Cannot log(%s)\n",pText); return; } - - /* get the filename */ - pChar = IFindOption(pSICSOptions,"LogFileBaseName"); - if(!pChar) - { - strcpy(pFile,"server"); - } - else - { - strcpy(pFile,pChar); - } - sprintf(pFile,"%s%2.2d.log",pFile, iFile); - fLogFile = fopen(pFile,"w"); - if(!fLogFile) - { - printf("ERROR: cannot open logfile %s for writing\n", - pFile); - fLogFile = NULL; - return; - } - } + iLogUsable = OpenVerifyLogFile(); + } - /* switch file if to many lines */ - if(iLineCount == MAXLOG) + /* switch file if too many lines */ + if(iLineCount >= MAXLOG) { fclose(fLogFile); fLogFile = NULL; iFile++; + iLineCount = 0; if(iFile >= MAXFILES) { iFile = 0; } - pChar = IFindOption(pSICSOptions,"LogFileBaseName"); - if(!pChar) - { - strcpy(pFile,"server"); + iLogUsable = OpenVerifyLogFile(); } - else - { - strcpy(pFile,pChar); - } - sprintf(pFile,"%s%1d.log",pFile, iFile); - fLogFile = fopen(pFile,"w"); - if(!fLogFile) - { - printf("ERROR: cannot open logfile %s for writing\n", - pFile); - fLogFile = NULL; - return; - } - iLineCount = 0; - } - + + if(1 == iLogUsable) + { fprintf(fLogFile,"%s\n",pText); fflush(fLogFile); iLineCount++; @@ -309,5 +327,5 @@ } pCurrent = pCurrent->pNext; } + } } - diff --git a/sicsstat.tcl b/sicsstat.tcl index 38b3e2f7..e69de29b 100644 --- a/sicsstat.tcl +++ b/sicsstat.tcl @@ -1,230 +0,0 @@ -exe batchpath ./ -exe syspath ./ -#---- tasUB module tasub -tasub mono dd 3.350000 -tasub mono hb1 1.000000 -tasub mono hb2 1.000000 -tasub mono vb1 1.000000 -tasub mono vb2 1.000000 -tasub mono ss 1 -tasub ana dd 3.350000 -tasub ana hb1 1.000000 -tasub ana hb2 1.000000 -tasub ana vb1 1.000000 -tasub ana vb2 1.000000 -tasub ana ss 1 -tasub cell 1.000000 1.000000 1.000000 90.000000 90.000000 90.000000 -tasub clear -tasub const ki -tasub ss 1 - tasub setub 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 - tasub setnormal 0.000000 0.000000 0.000000 -tasub settarget 0.000000 0.000000 0.000000 0.000000 0.000000 -tasub update -scaninfo 0,Unknown,1.0,.1 -scaninfo setAccess 0 -polfile UNKNOWN -polfile setAccess 2 -local UNKNOWN -local setAccess 2 -output UNKNOWN -output setAccess 2 -lastcommand UNKNOWN -lastcommand setAccess 2 -user Albert von Villigen -user setAccess 2 -title UNKNOWN -title setAccess 2 -# Counter counter -counter SetPreset 10.000000 -counter SetMode Timer -# Motor agl -agl sign 1.000000 -agl SoftZero 0.000000 -agl SoftLowerLim -10.000000 -agl SoftUpperLim 10.000000 -agl Fixed -1.000000 -agl InterruptMode 0.000000 -agl precision 0.010000 -agl AccessCode 2.000000 -agl movecount 10.000000 -# Motor sgu -sgu sign 1.000000 -sgu SoftZero 0.000000 -sgu SoftLowerLim -16.000000 -sgu SoftUpperLim 16.000000 -sgu Fixed -1.000000 -sgu InterruptMode 0.000000 -sgu precision 0.010000 -sgu AccessCode 2.000000 -sgu movecount 10.000000 -# Motor sgl -sgl sign 1.000000 -sgl SoftZero 0.000000 -sgl SoftLowerLim -16.000000 -sgl SoftUpperLim 16.000000 -sgl Fixed -1.000000 -sgl InterruptMode 0.000000 -sgl precision 0.010000 -sgl AccessCode 2.000000 -sgl movecount 10.000000 -# Motor mgl -mgl sign 1.000000 -mgl SoftZero 0.000000 -mgl SoftLowerLim -10.000000 -mgl SoftUpperLim 10.000000 -mgl Fixed -1.000000 -mgl InterruptMode 0.000000 -mgl precision 0.010000 -mgl AccessCode 2.000000 -mgl movecount 10.000000 -# Motor atu -atu sign 1.000000 -atu SoftZero 0.000000 -atu SoftLowerLim -17.000000 -atu SoftUpperLim 16.879999 -atu Fixed -1.000000 -atu InterruptMode 0.000000 -atu precision 0.010000 -atu AccessCode 2.000000 -atu movecount 10.000000 -# Motor atl -atl sign 1.000000 -atl SoftZero 0.000000 -atl SoftLowerLim -17.000000 -atl SoftUpperLim 17.000000 -atl Fixed -1.000000 -atl InterruptMode 0.000000 -atl precision 0.010000 -atl AccessCode 2.000000 -atl movecount 10.000000 -# Motor stu -stu sign 1.000000 -stu SoftZero 0.000000 -stu SoftLowerLim -30.000000 -stu SoftUpperLim 30.000000 -stu Fixed -1.000000 -stu InterruptMode 0.000000 -stu precision 0.010000 -stu AccessCode 2.000000 -stu movecount 10.000000 -# Motor stl -stl sign 1.000000 -stl SoftZero 0.000000 -stl SoftLowerLim -30.000000 -stl SoftUpperLim 30.000000 -stl Fixed -1.000000 -stl InterruptMode 0.000000 -stl precision 0.010000 -stl AccessCode 2.000000 -stl movecount 10.000000 -# Motor mtu -mtu sign 1.000000 -mtu SoftZero 0.000000 -mtu SoftLowerLim -17.000000 -mtu SoftUpperLim 17.000000 -mtu Fixed -1.000000 -mtu InterruptMode 0.000000 -mtu precision 0.010000 -mtu AccessCode 2.000000 -mtu movecount 10.000000 -# Motor mtl -mtl sign 1.000000 -mtl SoftZero 0.000000 -mtl SoftLowerLim -17.000000 -mtl SoftUpperLim 17.000000 -mtl Fixed -1.000000 -mtl InterruptMode 0.000000 -mtl precision 0.010000 -mtl AccessCode 2.000000 -mtl movecount 10.000000 -# Motor ach -ach sign 1.000000 -ach SoftZero 0.000000 -ach SoftLowerLim -0.500000 -ach SoftUpperLim 11.500000 -ach Fixed -1.000000 -ach InterruptMode 0.000000 -ach precision 0.010000 -ach AccessCode 2.000000 -ach movecount 10.000000 -# Motor sro -sro sign 1.000000 -sro SoftZero 0.000000 -sro SoftLowerLim 0.000000 -sro SoftUpperLim 351.000000 -sro Fixed -1.000000 -sro InterruptMode 0.000000 -sro precision 0.010000 -sro AccessCode 2.000000 -sro movecount 10.000000 -# Motor mcv -mcv sign 1.000000 -mcv SoftZero 0.000000 -mcv SoftLowerLim -9.000000 -mcv SoftUpperLim 124.000000 -mcv Fixed -1.000000 -mcv InterruptMode 0.000000 -mcv precision 0.010000 -mcv AccessCode 2.000000 -mcv movecount 10.000000 -# Motor a6 -a6 sign 1.000000 -a6 SoftZero 0.000000 -a6 SoftLowerLim -116.000000 -a6 SoftUpperLim 166.000000 -a6 Fixed -1.000000 -a6 InterruptMode 0.000000 -a6 precision 0.010000 -a6 AccessCode 2.000000 -a6 movecount 10.000000 -# Motor a5 -a5 sign 1.000000 -a5 SoftZero 0.000000 -a5 SoftLowerLim -200.000000 -a5 SoftUpperLim 200.000000 -a5 Fixed -1.000000 -a5 InterruptMode 0.000000 -a5 precision 0.010000 -a5 AccessCode 2.000000 -a5 movecount 10.000000 -# Motor a4 -a4 sign 1.000000 -a4 SoftZero 0.000000 -a4 SoftLowerLim -135.100006 -a4 SoftUpperLim 123.400002 -a4 Fixed -1.000000 -a4 InterruptMode 0.000000 -a4 precision 0.010000 -a4 AccessCode 2.000000 -a4 movecount 10.000000 -# Motor a3 -a3 sign 1.000000 -a3 SoftZero 0.000000 -a3 SoftLowerLim -177.300003 -a3 SoftUpperLim 177.300003 -a3 Fixed -1.000000 -a3 InterruptMode 0.000000 -a3 precision 0.010000 -a3 AccessCode 2.000000 -a3 movecount 10.000000 -# Motor a2 -a2 sign 1.000000 -a2 SoftZero 0.000000 -a2 SoftLowerLim -129.100006 -a2 SoftUpperLim -22.000000 -a2 Fixed -1.000000 -a2 InterruptMode 0.000000 -a2 precision 0.010000 -a2 AccessCode 2.000000 -a2 movecount 10.000000 -# Motor a1 -a1 sign 1.000000 -a1 SoftZero 0.000000 -a1 SoftLowerLim -87.000000 -a1 SoftUpperLim 6.100000 -a1 Fixed -1.000000 -a1 InterruptMode 0.000000 -a1 precision 0.010000 -a1 AccessCode 2.000000 -a1 movecount 10.000000 diff --git a/sicvar.c b/sicvar.c index 6b5d50bd..4d351a38 100644 --- a/sicvar.c +++ b/sicvar.c @@ -374,12 +374,13 @@ } } /*--------------------------------------------------------------------*/ - static int VarInterestCallback(int iEvent, void *pEvent, void *pUser) + static int VarInterestCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { SConnection *pCon; char pBueffel[512]; pSicsVariable pVar = NULL; - int iVal; + int iVal, status; float fVal; char *pText; @@ -388,18 +389,21 @@ pVar = (pSicsVariable)pEvent; pCon = (SConnection *)pUser; + SCPushContext2(pCon,cc); switch(pVar->eType) { case veInt: VarGetInt(pVar,&iVal); sprintf(pBueffel,"%s = %d",pVar->name,iVal); SCWrite(pCon,pBueffel,eValue); - return 1; + status = 1; + break; case veFloat: VarGetFloat(pVar,&fVal); sprintf(pBueffel,"%s = %f",pVar->name,fVal); SCWrite(pCon,pBueffel,eValue); - return 1; + status = 1; + break; case veText: VarGetText(pVar,&pText); sprintf(pBueffel,"%s = %s", pVar->name,pText); @@ -408,9 +412,11 @@ { free(pText); } - return 1; + status = 1; + break; } - return 1; + SCPopContext(pCon); + return status; } /*----------------------------------------------------------------------*/ static int VarSetFromText(pSicsVariable self, SConnection *pCon, char *text) @@ -559,7 +565,8 @@ static int VarSetFromText(pSicsVariable self, SConnection *pCon, char *text) } else if(strcmp(pCurrent->text,"interest") == 0) /* interest */ { - lID = RegisterCallback(pVar->pCall, VALUECHANGE, VarInterestCallback, + lID = RegisterCallback(pVar->pCall, SCGetContext(pCon), + VALUECHANGE, VarInterestCallback, pCon, NULL); SCRegister(pCon,pInterp, pVar->pCall,lID); DeleteTokenList(pList); diff --git a/sinfo.tcl b/sinfo.tcl new file mode 100644 index 00000000..c2d13bac --- /dev/null +++ b/sinfo.tcl @@ -0,0 +1,387 @@ +# requires stooop package from tcllib +# loaded from sycamore.tcl + + proc arga argStr { + set args [ split $argStr ] + set argc [llength $args] + # syc::debug "arga.argc = %s" $argc + set objName "" + set key "" + set name "" + set val "" + set bObj [expr $argc > 0] + set bKey [expr $argc > 1] + set bName [expr $argc > 2] + set bVal [expr $argc > 3] + if $bObj { + set objName [string tolower [lindex $args 0]] + #syc::debug "arga.objName = %s" $objName + } + if $bKey { + set key [string tolower [lindex $args 1]] + #syc::debug "arga.key = %s" $key + } + if $bName { + set name [string tolower [lindex $args 2]] + } + if $bVal { + set val [string tolower [lindex $args 3]] + } +# ? cannot get 'array set' to work in the form: +# array set argv { +# argc $argc +# objName $objName +# ... etcetera +# } + set argv(argc) $argc + set argv(bObj) $bObj + set argv(bKey) $bKey + set argv(bName) $bName + set argv(bVal) $bVal + set argv(objName) $objName + set argv(key) $key + set argv(name) $name + set argv(val) $val + # would like to return associative array + # for now, settle for list + # syc::debug "arga.argv = { %s }" [array get argv] + return [array get argv] + } + +# ----------------------------------------------------------------------------- +class sinfo { ;# base class definition + proc sinfo {this} { ;# base class constructor + # non-static data member initialisation + set ($this,objectID) $this + } + + proc ~sinfo {this} {} ;# base class destructor + + proc id {this} { + return [format "sin.objectID = \{ %s \}" $($this,objectID)] + } + + # static data member variables + # set File default.dat + set delimiter ", " + set debug 0 + set init 0 + set name "sinfo" + set usage {sinfo init|diag|config|server|device|command [parameter]} + set version 0.6 + + class server { + proc server {this name} { + set ($this,name) $name + + proc name {this} { + return [format "server.name = \{ %s \}" $($this,name)] + } + } + proc ~server {this} {} + } + + class sinfot { + proc sinfot {this} {} + proc ~sinfot {this} {} + } + + proc helpMsgStr args { + return [formatMsg $sinfo::name "usage" $sinfo::usage] + } + + proc debug args { + if {$sinfo::debug < 1} { + return + } + set l [llength $args] + set dMsg "Script code event" + set dVal " " + if {$l > 0} { + set dMsg [lindex $args 0] + if {$l > 1} { + set dVal [lindex $args 1] + } + } + sinWrite [format "sinfo::debug: %s" [format $dMsg $dVal]] "value" + } + + proc diag args { + set flag [lindex $args 0] + set msg [format "diag=%s" $flag] + switch $flag { + "on" { + set sinfo::debug 1 + } + "off" { + set sinfo::debug 0 + } + default { + if {1 == $sinfo::debug} { + set msg "diag=on" + } else { + set msg "diag=off" + } + } + } + return [format "sinfo.diag = \{ %s \}" $msg] + } + + proc formatMsg {objName parName msg} { +# return [format "%s.%s = \{ %s \}" $objName $parName $msg] +# set msgStr [format "%s.%s = %s " $objName $parName $msg] + #sinWrite "DEBUG formatMsg: msg = $msg" "value" + return "$objName.$parName=$msg" + } + + proc writeObjPar {objName parName} { + return [format "%s.%s = \{ %s \}" \ + $objName $parName [set ::$objName::$parName]] + } + + proc writeError {objName msg} { +# return [format "%s.error = \{ %s \}" $objName $msg] + set msg [format "%s.error = \{ %s \}" $objName $msg] + sinWrite $msg "error" + return $msg + } + + proc writeNspPar {objName parName} { + set result :: + append result $objName :: $parName +# return [format "%s.%s = \{ %s \}" $objName $parName [set $result]] + sinWrite [format "%s" [set $result]] "value" + } + + proc writeList {objName parName parList} { +# return [format "%s.%s = %s " $objName $parName \ +# [join $parList $sinfo::delimiter]] + set msg [format "%s" [join $parList $sinfo::delimiter]] + sinWrite $msg "value" + #return $msg + } + + proc writeNamespaceChildren {obj key nsp} { + set chList {} + set nameList {} + set chList [namespace children $nsp] + set l [llength $chList] + for {set i 0} {$i < $l} {incr i} { + lappend nameList [namespace tail [lindex $chList $i]] + } + writeList $obj $key $nameList + } + + proc writeNamespaceList {obj key nsp} { + set nameList {} + foreach v [info vars ${nsp}::*] { + lappend nameList [namespace tail $v] + } + writeList $obj $key $nameList + } +} + +proc sinfo::server args { + array set argv [arga $args] + debug "sinfo::server, server.argv = { %s }" [array get argv] + set parSet {} + set parNames {} + if {$argv(bKey)} { + set key $argv(key) + debug "sinfo::server, key = $key" + switch $key { + "connection" - + "experiment" - + "help" - + "key" - + "list" + { + debug "sinfo::server, in switch $key, sinfox list server $key" + set nameList [sinfox list server $key] + sinfo::writeList "server" $key $nameList + } + "command" - + "device" - + "devicetype" - + "group" - + "interface" + { + if {$argv(bName)} { + set name $argv(name) + debug "sinfo::server, using name $name" + #sinWrite [format "DEBUG: if bname, key = %s, name = %s" $key $name] "value" + set nameList [sinfox list server $key $name] + sinfo::writeList "server" $name $nameList + #todo: improve response for unknown name + # eg server.error={device=foo} + } else { + set nameList [sinfox list server $key] + debug "sinfo::server, key=$key, nameList = $nameList" + sinfo::writeList "server" $key $nameList + } + } + + "gtdevice" + { + if {$argv(bName)} { + set name $argv(name) + if [info exists ::server::gtDeviceList::$name] { + sinfo::writeNspPar server::gtDeviceList $name + } else { + set msg [format "key=%s.%s" "server" $key] + return [sinfo::writeList "server" error $msg] + } + } else { + writeList "server" $key [gumtree::gtDeviceList] +# sinfo::writeNamespaceList "server" $key \ +# [ ::server::gtDeviceList + } + } + + default { + puts default + if [info exists ::server::$key] { + sinfo::writeNspPar server $key + } else { + set msg [format "key=%s.%s" "server" $key] + return [sinfo::writeList "server" error $msg] + } + } + } + } else { + # writeNamespaceList $objName + set nameList [sinfox list server list] + writeList "server" "list" $nameList + } +} + +proc sinfo::checkType {objName} { + if { [string compare -nocase $objName server] == 0 } then { + set return "server" + } elseif { [string compare -nocase $objName sequencer] == 0 } then { + set return "sequencer" + } else { + switch [SICSType $objName] { + COUNT - + DRIV { return "device" } + COM { return "command" } + TEXT { return "object" } + default { return "unknown" } + } + } +} + +proc sinfo::list args { + array set argv [arga $args] + debug "sinfo.argv = { %s }" [array get argv] + set argc [llength $args] + set objName $argv(objName) + set key $argv(key) + set name $argv(name) + sinfo::debug "sinfo.numargs = %s" $argc + if {$argc < 1} { + sinWrite [sinfo::helpMsgStr] "value" + return + } + sinfo::debug "object = %s" $argv(objName) + if $argv(bKey) { + sinfo::debug "key = %s" $argv(key) + } + if $argv(bName) { + sinfo::debug "name = %s" $argv(name) + } + + set parList {} + set numPars 0 + + set objType [checkType $objName] + sinfo::debug "sinfo.objectType = %s" $objType + + switch $objType { + device + { + set nameList [sinfox list $objName $key $name] + writeList $objName $key $nameList + } + command + { + debug "sinfo.message = { %s is command objectType}" $objName + } + server + { + set cmd [format "sinfo::server %s %s %s %s" \ + $objName $key $argv(name) $argv(val)] + return [eval $cmd] + } + sequencer + { + debug "sinfo.message = { %s is sequencer objectType}" $objName + if {$argv(bKey)} { + set key $argv(key) + switch $key { + "command" + { + if $bName { + set target [format "::sequencer::%s" $name] + sinfo::writeNamespaceList $objName $name $target + } else { + sinfo::writeNamespaceChildren $objName \ + $key ::sequencer + } + } + default + { + } + } + } else { + sinfo::writeNamespaceList "sequencer" "list" "::sequencer" + } + } + object + { +# todo: test for interface name + switch $objName { + default { + writeError "sinfo" \ + [format "'%s' is invalid object" $objName] + } + } + } + unknown - + default { + writeError "sinfo" [format "'%s' has invalid object type" $objName] + } + } +} + +# ----------------------------------------------------------------------------- +# wrapper procs for sinfo class + +proc sinfo args { + set l [llength $args] + if {$l < 1} { + sinWrite [sinfo::helpMsgStr] "value" + return + } + set arglist [ split $args ] + set objName [lindex $arglist 0] + set cmd [format "sinfo::%s $args" $objName] + #sinWrite "DEBUG: $cmd" "value" +# set cmd $args + #set cmd "sinfo::list $args" + #FIXME the command should provide the output code for sinWrite + #sinWrite [eval $cmd] "value" + eval $cmd +} + +proc sin args { + set argc [llength $args] + if {$argc < 1} { + set msg \ + "sin.usage = \ + { sin \[server|sequencer|device|command\] \[parameter\] }" + sinWrite $msg "value" + } else { + sinWrite [sinfo::list $args] "value" + } +} diff --git a/sinfox.c b/sinfox.c new file mode 100644 index 00000000..6330b687 --- /dev/null +++ b/sinfox.c @@ -0,0 +1,1221 @@ +/*-------------------------------------------------------------------------- + ANSTO Server Info Command Object + Paul Hathaway, January, 2005 + Copyright: See copyright.txt +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include /* incl. SCWrite */ +#include +#include +#include +#include +#include "sinfox.h" + +/*----------------------------------------------------------------------- + * External Interface defined in sinfox.h includes + * struct pSinfox + * int InstallSinfox(SConnection *pCon, SicsInterp *pSics, void *pData, + * int argc, char *argv[]); + * void DeleteSinfox(void *pSelf); + * int SinfoxAction(SConnection *pCon, SicsInterp *pSics, void *pData, + * int argc, char *argv[]); + * and lists of option keys + *-----------------------------------------------------------------------*/ + +/* Core module functions */ +static pSinfox CreateSinfox(void); +static int SinfoxInit(SicsInterp *pSics, char *infofile); +static int SinfoxHelp(pSinfox pSin, SicsInterp* pSics); +static int SinfoxReset(pSinfox pSin, SicsInterp* pSics); +static int SinfoxSetDesc(pSinfox pSin, SicsInterp *pSics, + char *objName, char *pDesc); +static int SinfoxSetGrp(pSinfox pSin, SicsInterp *pSics, + char *objName, char *pGrp); +static int SinfoxSetKey(pSinfox pSin, SicsInterp *pSics, + char *objName, char *keyName, char *eltValue); +static int SinfoxReadKey(pSinfox pSin, SicsInterp *pSics, + char *objName, char *fileName); +static int SinfoxList(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, + char *pObjName, char *pKeyName, char *pEltName); +static int SinfoxEnumerate(pSinfox pSin, SicsInterp* pSics, + SConnection *pCon, char *keyName); +static int SinfoxShow(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, + char *keyName, char *eltName); +static int SinfoxDevice(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, + char *devName, char *keyName, char *eltName); +static int SinfoxGetGrp(pSinfox pSin, SicsInterp *pSics, + char *objName); + +/* Utility functions */ +static int EnumChoice(char *pList[], int iLength, char *pInput); +static int LinkVar(char *tcl_var_name, char *pAddress, int link_flags); +static void setOKE(char *obj, char *key, char *elt, + char *oVal, char *kVal, char *eVal); +static int isNameDevice(char *name); +static int isNameCommand(char *name); +static int isObjectDevice(CommandList *pObj); +static int isObjectCommand(CommandList *pObj); +static void addToList(Tcl_Interp *tTcl, Tcl_Obj *tList, char *prefix, char *sVal); +static void addPairsToList(Tcl_Interp *tTcl, Tcl_Obj *tList, IPair *pList); +static void RemoveWhiteSpace(char *pText); + +/*--------------------------------------------------------------------------*/ +pSinfox CreateSinfox(void) +{ + int i; + pSinfox pNew = NULL; + SicsInterp *pSics; + Tcl_Interp *tTcl; + + pNew = (pSinfox)malloc(sizeof(Sinfox)); + if(!pNew) + { + return NULL; + } + pNew->pDes = CreateDescriptor("sinfox"); + if(!pNew->pDes) + { + free(pNew); + return NULL; + } + pSics = GetInterpreter(); + tTcl = (Tcl_Interp *)(pSics->pTcl); + pNew->tTcl = tTcl; + /* LinkVar("server::configName",pNew->configName,TCL_LINK_STRING); */ + pNew->buildVersion = Tcl_GetVar(tTcl, + "::server::buildVersion",TCL_GLOBAL_ONLY); + pNew->configName = Tcl_GetVar(tTcl, + "::server::configName",TCL_GLOBAL_ONLY); + pNew->configVersion = Tcl_GetVar(tTcl, + "::server::configVersion",TCL_GLOBAL_ONLY); + pNew->description = Tcl_GetVar(tTcl, + "::server::description",TCL_GLOBAL_ONLY); + pNew->instrument = Tcl_GetVar(tTcl, + "::server::instrument",TCL_GLOBAL_ONLY); + pNew->schemaVersion = Tcl_GetVar(tTcl, + "::server::schemaVersion",TCL_GLOBAL_ONLY); + pNew->pDes->description = NULL; + pNew->pDes->group = NULL; + pNew->pDes->pKeys = NULL; + return pNew; +} + +/*-------------------------------------------------------------------------*/ +void DeleteSinfox(void *self) +{ + int i; + pSinfox pOld = (pSinfox)self; + + if(NULL==pOld) + { + return; + } + if(pOld->buildVersion) + { + free((void *)(pOld->buildVersion)); + } + if(pOld->configName) + { + free((void *)(pOld->configName)); + } + if(pOld->configVersion) + { + free((void *)(pOld->configVersion)); + } + if(pOld->description) + { + free((void *)(pOld->description)); + } + if(pOld->instrument) + { + free((void *)(pOld->instrument)); + } + if(pOld->schemaVersion) + { + free((void *)(pOld->schemaVersion)); + } + if(pOld->pDes) + { + DeleteDescriptor(pOld->pDes); + } + free(pOld); +} + +/*--------------------------------------------------------------------------*/ +int InstallSinfox(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) +{ + pSinfox pNew = NULL; + pNew = CreateSinfox(); + if(NULL==pNew) + { + SCWrite(pCon,"No memory to create Sinfox",eError); + return 0; + } + AddCommand(pSics,"sinfox",SinfoxAction,DeleteSinfox,pNew); + SCSendOK(pCon); + return 1; +} + +/*--------------------------------------------------------------------------*/ +static int SinfoxInit(SicsInterp *pSics, char *infofile) +{ + SConnection *pCon = NULL; + char pBuf[1024]; + int iRet; + + /* create a connection */ + pCon = SCCreateDummyConnection(pSics); + if(!pCon) + { + return 0; + } + pCon->iFiles = 1; + pCon->pFiles[0] = stdout; + + /* evaluate the file */ + sprintf(pBuf,"fileeval %s",infofile); + iRet = InterpExecute(pSics,pCon,pBuf); + pCon->iFiles = 0; + SCDeleteConnection(pCon); + + return iRet; +} + +/*------------------------------------------------------------------------*/ +static int SinfoxHelp(pSinfox pSin, SicsInterp* pSics) +{ + Tcl_SetResult((Tcl_Interp *)(pSics->pTcl),"Sinfox Help",TCL_VOLATILE); + return 1; +} + +/*------------------------------------------------------------------------*/ +static int SinfoxReset(pSinfox pSin, SicsInterp* pSics) +{ + int i; + + pSin->buildVersion = Tcl_GetVar(pSin->tTcl, + "::server::buildVersion",TCL_GLOBAL_ONLY); + pSin->configName = Tcl_GetVar(pSin->tTcl, + "::server::configName",TCL_GLOBAL_ONLY); + pSin->configVersion = Tcl_GetVar(pSin->tTcl, + "::server::configVersion",TCL_GLOBAL_ONLY); + pSin->description = Tcl_GetVar(pSin->tTcl, + "::server::description",TCL_GLOBAL_ONLY); + pSin->instrument = Tcl_GetVar(pSin->tTcl, + "::server::instrument",TCL_GLOBAL_ONLY); + pSin->schemaVersion = Tcl_GetVar(pSin->tTcl, + "::server::schemaVersion",TCL_GLOBAL_ONLY); + + Tcl_SetResult(pSin->tTcl,"{Sinfox Reset}",TCL_VOLATILE); + return 1; +} + +/*------------------------------------------------------------------------*/ +static int SinfoxSetDesc(pSinfox pSin, SicsInterp *pSics, + char *objName, char *pDesc) +{ + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + char pBuf[256]; + + memset(pBuf,0,256); + pCurrent = pSics->pCList; + + pCurrent = FindCommand(pSics,objName); + if(NULL != pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + SetDescriptorDescription(pDes,pDesc); + sprintf(pBuf,"description=%s",pDesc); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 1; + } + } + sprintf(pBuf,"error=unable to set %s.description to %s",objName,pDesc); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 0; +} + +/*------------------------------------------------------------------------*/ +static int SinfoxSetGrp(pSinfox pSin, SicsInterp *pSics, + char *objName, char *pGrp) +{ + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + char pBuf[256]; + + memset(pBuf,0,256); + pCurrent = pSics->pCList; + + pCurrent = FindCommand(pSics,objName); + if(NULL!=pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + SetDescriptorGroup(pDes,pGrp); + sprintf(pBuf,"group=%s",pGrp); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 1; + } + } + sprintf(pBuf,"error=unable to set %s.group to %s",objName,pGrp); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 0; +} + +static int SinfoxGetGrp(pSinfox pSin, SicsInterp *pSics, + char *objName) +{ + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + char pBuf[256]; + + pBuf[0]='\0'; + pCurrent = pSics->pCList; + + pCurrent = FindCommand(pSics,objName); + if(NULL==pCurrent) { + sprintf(pBuf,"%s.group=none",objName); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 1; + } else { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + sprintf(pBuf,"%s.group=%s",objName, GetDescriptorGroup(pDes)); + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return 1; + } + } +} +/*------------------------------------------------------------------------*/ +static int SinfoxSetKey(pSinfox pSin, SicsInterp *pSics, + char *objName, char *keyName, char *eltValue) +{ + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + int bOK = 0; + char *obj; + char pBuf[256]; + memset(pBuf,0,256); + + obj = strdup(objName); + strtolower(obj); + + if(0==strcmp(obj,"server")) + { /* sinfox object is surrogate for server object inside SICS */ + free(obj); + obj = strdup("sinfox"); + } + else + { + free(obj); + obj = strdup(objName); + } + + pCurrent = pSics->pCList; + pCurrent = FindCommand(pSics,obj); + + if(NULL != pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + strtolower(keyName); + strtolower(eltValue); + pDes->pKeys = IFSetOption(pDes->pKeys,keyName,eltValue); + if(NULL != pDes->pKeys) + { + bOK=1; + } + } + } + + if(bOK==1) + { + sprintf(pBuf,"%s.%s=%s", + pCurrent->pName,pDes->pKeys->name,pDes->pKeys->value); + } + else + { + sprintf(pBuf,"error=unable to set %s.%s to %s", + obj,keyName,eltValue); + } + + Tcl_SetObjResult(pSin->tTcl,Tcl_NewStringObj(pBuf,strlen(pBuf))); + return bOK; +} + +/*------------------------------------------------------------------------*/ +static int SinfoxReadKey(pSinfox pSin, SicsInterp *pSics, + char *objName, char *fileName) +{ + static FILE *fKeyFile = NULL; + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + char pBuf[256]; + char pName[132]; + char pValue[132]; + char *pPos; + int iLen; + + memset(pBuf,0,256); + + pCurrent = pSics->pCList; + pCurrent = FindCommand(pSics,objName); + + if(NULL != pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + fKeyFile = fopen(fileName,"r"); + if(NULL == fKeyFile) + { + return 0; + } + + while(!feof(fKeyFile)) + { + fgets(pBuf,255,fKeyFile); + if(feof(fKeyFile)) continue; + + if(pBuf[0] == '#') continue; + + pPos = strchr(pBuf,'='); + if(!pPos) continue; + + iLen = pPos - pBuf; + strncpy(pName,pBuf,iLen); + pName[iLen] = '\0'; + strcpy(pValue,(pPos+1)); + RemoveWhiteSpace(pName); + RemoveWhiteSpace(pValue); + strtolower(pName); + strtolower(pValue); + + pDes->pKeys = IFAddOption(pDes->pKeys,pName,pValue); + if(NULL==pDes->pKeys) return 0; + } + + fclose(fKeyFile); + return 1; + } + } +} + +/*------------------------------------------------------------------------*/ +static int SinfoxList(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, + char *pObjName, char *pKeyName, char *pEltName) +{ + int iRet; + char *objName; + char *keyName = NULL; + char *eltName = NULL; + CommandList *pObj = NULL; + + objName = strdup(pObjName); strtolower(objName); + if (NULL!=pKeyName) + { + keyName = strdup(pKeyName); strtolower(keyName); + } + if (NULL!=pEltName) + { + eltName = strdup(pEltName); strtolower(eltName); + } + + /* check if objName is an interfaceName */ + iRet = EnumChoice(pIFaces,iNumIFaces,objName); + if(-1 < iRet) + { + if((0==strcmp(keyName,"device")) || (0==strcmp(keyName,NULL))) + { /* format as sinfox list server interface interfaceName */ + setOKE(objName,keyName,eltName,"server","interface",objName); + } else if(0==strcmp(keyName,"command")) + { /* todo: not yet implemented */ + return SinfoxHelp(pSin,pSics); + } + } + + /* check if objName is commandName */ + /* check if objName is a deviceName */ + pObj = FindCommand(pSics,objName); + if(NULL != pObj) + { + if(1==isObjectDevice(pObj)) + { + return SinfoxDevice(pSin,pSics,pCon,objName,keyName,eltName); + } + else /* command */ + { return 0; + iRet = EnumChoice(pCommandKeys,iNumCommandKeys,keyName); + switch(iRet) + { + case 1: /* argument */ + /* todo: not yet implemented */ + case 2: /* device */ + /* todo: secondary: not yet implemented */ + case 3: /* interface */ + /* todo: secondary: not yet implemented */ + default: /* sinfox list server command commandName */ + setOKE(objName,keyName,eltName,"server","command",objName); + break; + } + } + } + + if(0 == strcmp(objName,"server")) + { + iRet = EnumChoice(pServerKeys,iNumServerKeys,keyName); + /* if invalid (iRet < 0) then default to "help" command */ + switch(iRet) + { + /* cases that have no eltName argument */ + case 1: /* list */ + case 3: /* connection */ + case 6: /* experiment */ + case 9: /* key */ + return SinfoxEnumerate(pSin,pSics,pCon,keyName); + break; + /* cases that are not fully implemented */ + case 2: /* command */ + case 4: /* device */ + case 5: /* deviceType */ + case 7: /* group */ + case 8: /* interface */ + return SinfoxShow(pSin,pSics,pCon,keyName,eltName); + break; + /* fully functional cases */ + case 0: /* help */ + default: + return SinfoxHelp(pSin,pSics); + break; + } + return 1; + } +} + +/*------------------------------------------------------------------------*/ +/* Retrieve a list of elements from CommandList matching criteria */ +static int SinfoxEnumerate(pSinfox pSin, SicsInterp* pSics, + SConnection *pCon, char *keyName) +{ + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + Tcl_Interp *tTcl; + Tcl_Obj *tList; + IPair *pOption = NULL; + IPair *pGroups = NULL; + pSicsVariable pSVar = NULL; + int iRet; + char pBuf[256]; + int checkDeviceTypes[iNumDeviceTypes]; + + pCurrent = pSics->pCList; + tTcl = (Tcl_Interp *)(pSics->pTcl); + tList = Tcl_NewListObj(0,NULL); + memset(pBuf,0,256); + + iRet = EnumChoice(pServerKeys,iNumServerKeys,keyName); + /* if invalid (iRet < 0) then default to "help" command */ + switch(iRet) + { + /* cases that have no eltName argument - not fully implemented */ + case 1: /* list */ + addToList(tTcl,tList,"buildVersion",(char *)(pSin->buildVersion)); + addToList(tTcl,tList,"configName",(char *)(pSin->configName)); + addToList(tTcl,tList,"configVersion",(char *)(pSin->configVersion)); + addToList(tTcl,tList,"description",(char *)(pSin->description)); + addToList(tTcl,tList,"instrument",(char *)(pSin->instrument)); + addToList(tTcl,tList,"schemaVersion",(char *)(pSin->schemaVersion)); + addPairsToList(tTcl,tList,pSin->pDes->pKeys); + addPairsToList(tTcl,tList,pSICSOptions); + break; + case 2: /* command */ + while(pCurrent) + { + if(1==isObjectCommand(pCurrent)) + { + strcpy(pBuf,pCurrent->pName); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + pCurrent = pCurrent->pNext; + } + break; + case 3: /* connection */ + sprintf(pBuf,"%d",SCGetRights(pCon)); + addToList(tTcl,tList,"userAccessLevel",pBuf); + addToList(tTcl,tList,"protocol",GetProtocolName(pCon)); + break; + case 6: /* experiment */ + while(pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + strcpy(pBuf,pDes->name); + strtolower(pBuf); + if(0==strcmp(pBuf,"sicsvariable")) + { + pSVar=FindVariable(pSics,pCurrent->pName); + addToList(tTcl,tList,pCurrent->pName,pSVar->text); + } + } + pCurrent = pCurrent->pNext; + } + break; + case 9: /* key */ + for(iRet=0;iRetpName); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + pCurrent = pCurrent->pNext; + } + break; + case 5: /* deviceType */ + for(iRet=0;iRetpData); + if(NULL != pDes) + { + strcpy(pBuf,pDes->name); + strtolower(pBuf); + iRet = EnumChoice(pDeviceTypes,iNumDeviceTypes,pBuf); + if(-1 < iRet) + { + if(1!=checkDeviceTypes[iRet]) + { + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + checkDeviceTypes[iRet] = 1; + } + } + } + pCurrent = pCurrent->pNext; + } + break; + case 7: /* group */ + pCurrent = pSics->pCList; + /* Always add default group "none" */ + pGroups = IFAddOption(pGroups,"none","OK"); + Tcl_ListObjAppendElement(tTcl,tList,Tcl_NewStringObj("none",4)); + while(pCurrent) + { + if(1==isObjectDevice(pCurrent)) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes->group) + { + strcpy(pBuf,pDes->group); + strtolower(pBuf); + if(NULL==IFindOption(pGroups,pBuf)) + { + pGroups = IFAddOption(pGroups,pBuf,"OK"); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + } + } + pCurrent = pCurrent->pNext; + } + if(NULL!=pGroups) + { + IFDeleteOptions(pGroups); + } + break; + case 8: /* interface */ + for(iRet=0;iRetpCList; + tTcl = (Tcl_Interp *)(pSics->pTcl); + tList = Tcl_NewListObj(0,NULL); + memset(pBuf,0,256); + + if (NULL==eltName) + { + return SinfoxEnumerate(pSin,pSics,pCon,keyName); + } + pElt = strdup(eltName); + strtolower(pElt); + + iRet = EnumChoice(pServerKeys,iNumServerKeys,keyName); + /* if invalid (iRet < 0) then default to "help" command */ + switch(iRet) + { + case 2: /* command */ + case 4: /* device - list deviceName {attribute|command|interface} */ + //addToList(tTcl,tList,pElt,"is being searched for"); + pCurrent = FindCommand(pSics,pElt); + if(NULL!=pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + //addToList(tTcl,tList,"debug2","descriptor found"); + if(1==isObjectDevice(pCurrent)) + { + if(NULL!=pDes->name) + { + strcpy(pBuf,pDes->name); + strtolower(pBuf); + addToList(tTcl,tList,"devicetype",pBuf); + } + if(NULL!=pDes->group) + { + strcpy(pBuf,pDes->group); + strtolower(pBuf); + addToList(tTcl,tList,"group",pBuf); + } + } + if(NULL!=pDes->description) + { + strcpy(pBuf,pDes->description); + strtolower(pBuf); + addToList(tTcl,tList,"description",pBuf); + } + //addToList(tTcl,tList,"debug3","default fields processed"); + if(NULL!=pDes->pKeys) + { + addPairsToList(tTcl,tList,pDes->pKeys); + } + } + } + //addToList(tTcl,tList,"debug4","device show finished"); + break; + case 5: /* devicetype */ + iRet = EnumChoice(pDeviceTypes,iNumDeviceTypes,pElt); + if (0 > iRet) + { + if((0==strcmp(pElt,"all"))||(0==strcmp(pElt,"*"))) + { + Tcl_SetVar(tTcl,"name",keyName,0); + return SinfoxEnumerate(pSin,pSics,pCon,keyName); + } + } + else + { + while(pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + strcpy(pBuf,pDes->name); + strtolower(pBuf); + if(0==strcmp(pElt,pBuf)) + { + strcpy(pBuf,pCurrent->pName); + strtolower(pBuf); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + } + pCurrent = pCurrent->pNext; + } + } + break; + case 7: /* group */ + if((0==strcmp(pElt,"all"))||(0==strcmp(pElt,"*"))) + { + Tcl_SetVar(tTcl,"name",keyName,0); + return SinfoxEnumerate(pSin,pSics,pCon,keyName); + } + while(NULL!=pCurrent) + { + if(1==isObjectDevice(pCurrent)) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + if(NULL == pDes->group) + { + strcpy(pBuf,"none"); + } + else + { + strcpy(pBuf,pDes->group); + strtolower(pBuf); + } + if(0==strcmp(pElt,pBuf)) + { + strcpy(pBuf,pCurrent->pName); + strtolower(pBuf); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + } + } + pCurrent = pCurrent->pNext; + } + break; + case 8: /* interface */ + iRet = EnumChoice(pIFaces,iNumIFaces,pElt); + if (0 > iRet) + { + if((0==strcmp(pElt,"all"))||(0==strcmp(pElt,"*"))) + { + Tcl_SetVar(tTcl,"name",keyName,0); + return SinfoxEnumerate(pSin,pSics,pCon,keyName); + } + } + else + { + switch(iRet) + { + case 0: /* callback */ + iType = CALLBACKINTERFACE; break; + case 1: /* countable */ + iType = COUNTID; break; + case 2: /* drivable */ + iType = DRIVEID; break; + case 3: /* environment */ + iType = ENVIRINTERFACE; break; + default: /* interface not recognised */ + Tcl_SetObjResult(tTcl,tList); + return 1; + break; + } + while(pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + if(NULL != pDes->GetInterface(pDes,iType)) + { + strcpy(pBuf,pCurrent->pName); + strtolower(pBuf); + Tcl_ListObjAppendElement(tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + } + pCurrent = pCurrent->pNext; + } + } + break; + default: + addToList(tTcl,tList,"error","unknown key"); + break; + } + Tcl_SetObjResult(tTcl,tList); + return 1; +} + +/*-------------------------------------------------------------------------*/ +static int SinfoxDevice(pSinfox pSin, SicsInterp* pSics, SConnection *pCon, + char *devName, char *keyName, char *eltName) +{ + int i,iRet,iType; + Tcl_Obj *tList; + char pBuf[256]; + char *pTmp; + CommandList *pCurrent; + pObjectDescriptor pDes = NULL; + + memset(pBuf,0,256); + pCurrent = pSics->pCList; + tList = Tcl_NewListObj(0,NULL); + pCurrent = FindCommand(pSics,devName); +/* debug */ +addToList(pSin->tTcl,tList,"dev",devName); +addToList(pSin->tTcl,tList,"key",keyName); +addToList(pSin->tTcl,tList,"elt",eltName); +/*-------*/ + iRet = EnumChoice(pDeviceKeys,iNumDeviceKeys,keyName); + switch(iRet) + { + case 2: /* interface */ + if(NULL!=pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + for(i=0;itTcl,tList); + return 0; + break; + } + if(NULL != pDes->GetInterface(pDes,iType)) + { + strcpy(pBuf,pIFaces[i]); + Tcl_ListObjAppendElement(pSin->tTcl,tList, + Tcl_NewStringObj(pBuf,strlen(pBuf))); + } + } + } + } + break; + case 0: /* attribute */ + if(NULL==eltName) + { + return SinfoxShow(pSin,pSics,pCon,"device",devName); + } + else + { + if(NULL!=pCurrent) + { + pDes = FindDescriptor(pCurrent->pData); + if(NULL != pDes) + { + pTmp = IFindOption(pDes->pKeys,eltName); + if(NULL!=pTmp) + { + strcpy(pBuf,pTmp); + addToList(pSin->tTcl,tList,eltName,pTmp); + } + } + } + } + break; + case 1: /* command */ + /* todo: secondary: not yet implemented */ + default: /* sinfox list server device deviceName */ + return SinfoxShow(pSin,pSics,pCon,"device",devName); + break; + } + Tcl_SetObjResult(pSin->tTcl,tList); + return 1; +} +/*-------------------------------------------------------------------------*/ +int SinfoxAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) +{ + int iRet; + char **argx; + FuPaResult PaRes; + pSinfox pSin = NULL; + + const int iNumCmds = 8; + FuncTemplate CommandTemplate[] = { + {"help",0,{0,0}}, + {"list",3,{FUPATEXT,FUPATEXT,FUPAOPT}}, + {"setdesc",2,{FUPATEXT,FUPATEXT}}, + {"setgrp",2,{FUPATEXT,FUPATEXT}}, + {"setkey",3,{FUPATEXT,FUPATEXT,FUPATEXT}}, + {"reset",0,{0,0}}, + {"readkey",2,{FUPATEXT,FUPATEXT}}, + {"getgrp",1,{FUPATEXT}}, + NULL + }; + + assert(pCon); + assert(pSics); + pSin = (pSinfox)pData; + assert(pSin); + + /* You need to have User level access rights to use this facility */ + if(!SCMatchRights(pCon,usUser)) + { + return 0; + } + + /* parse function args */ + argtolower(argc,argv); + argx = &argv[1]; + iRet = EvaluateFuPa((pFuncTemplate)&CommandTemplate,iNumCmds,argc-1,argx,&PaRes); + /* if invalid (iRet < 0) then default to "help" command */ + switch(iRet) + { + case 1: /* list */ + if(1==PaRes.Arg[2].iVal) + { + iRet = SinfoxList(pSin,pSics,pCon, + PaRes.Arg[0].text,PaRes.Arg[1].text,PaRes.Arg[2].text); + } + else + { + iRet = SinfoxList(pSin,pSics,pCon, + PaRes.Arg[0].text,PaRes.Arg[1].text,NULL); + } + return iRet; + break; + case 2: /* setdesc */ + return SinfoxSetDesc(pSin,pSics, + PaRes.Arg[0].text,PaRes.Arg[1].text); + break; + case 3: /* setgrp */ + return SinfoxSetGrp(pSin,pSics, + PaRes.Arg[0].text,PaRes.Arg[1].text); + break; + case 4: /* setkey */ + return SinfoxSetKey(pSin,pSics, + PaRes.Arg[0].text,PaRes.Arg[1].text,PaRes.Arg[2].text); + break; + case 5: /* reset */ + return SinfoxReset(pSin,pSics); + break; + case 6: /* readkey */ + return SinfoxReadKey(pSin,pSics, + PaRes.Arg[0].text,PaRes.Arg[1].text); + break; + case 7: /*getgrp */ + return SinfoxGetGrp(pSin, pSics, PaRes.Arg[0].text); + break; + case 0: /* help */ + default: + return SinfoxHelp(pSin,pSics); + break; + } + return 1; +} + +/*-------------------------------------------------------------------------*/ +static int EnumChoice(char *pList[], int iLength, char *pInput) +{ + int i; + int iRet = -1; + + for(i=0;ipTcl); + /* tcl_flags = f(link_flags)*/ + switch(link_flags) + { + case TCL_LINK_INT : + break; + case TCL_LINK_DOUBLE: + case TCL_LINK_BOOLEAN: + case TCL_LINK_STRING: + tcl_flags = link_flags; + break; + default : return 0; + } + Tcl_LinkVar(pTcl,tcl_var_name,pAddress,tcl_flags); + return 1; +} + +/*-------------------------------------------------------------------------*/ +static void setOKE(char *obj, char *key, char *elt, char *oVal, char *kVal, char *eVal) +{ + char *eBuf; + char *kBuf; + char *oBuf; + eBuf = strdup(eVal); + kBuf = strdup(kVal); + oBuf = strdup(oVal); + free(elt); elt = eBuf; + free(key); key = kBuf; + free(obj); obj = oBuf; +} + +/*-------------------------------------------------------------------------*/ +static int isNameDevice(char *name) +{ + SicsInterp *pSics; + CommandList *pObj = NULL; + Dummy *pDum = NULL; + + pSics = GetInterpreter(); + pObj = FindCommand(pSics,name); + if(NULL != pObj) + { + pDum = (Dummy *)pObj->pData; + if(NULL != pDum) + { + if(NULL != pDum->pDescriptor->GetInterface(pDum,DRIVEID)) return 1; + if(NULL != pDum->pDescriptor->GetInterface(pDum,COUNTID)) return 1; + if(NULL != pDum->pDescriptor->GetInterface(pDum,ENVIRINTERFACE)) return 1; + } + } + return 0; +} + +/*-------------------------------------------------------------------------*/ +static int isNameCommand(char *name) +{ + SicsInterp *pSics; + CommandList *pObj = NULL; + Dummy *pDum = NULL; + + pSics = GetInterpreter(); + pObj = FindCommand(pSics,name); + if(NULL != pObj) + { + pDum = (Dummy *)pObj->pData; + if(NULL != pDum) + { + if(NULL != pDum->pDescriptor->GetInterface(pDum,DRIVEID)) return 0; + if(NULL != pDum->pDescriptor->GetInterface(pDum,COUNTID)) return 0; + if(NULL != pDum->pDescriptor->GetInterface(pDum,ENVIRINTERFACE)) return 0; + } + return 1; + } + return 0; +} + +/*-------------------------------------------------------------------------*/ +static int isObjectDevice(CommandList *pObj) +{ + Dummy *pDum = NULL; + if(NULL != pObj) + { + pDum = (Dummy *)pObj->pData; + if(NULL != pDum) + { + if(NULL != pDum->pDescriptor->GetInterface(pDum,DRIVEID)) return 1; + if(NULL != pDum->pDescriptor->GetInterface(pDum,COUNTID)) return 1; + if(NULL != pDum->pDescriptor->GetInterface(pDum,ENVIRINTERFACE)) + return 1; + } + } + return 0; +} + +/*-------------------------------------------------------------------------*/ +static int isObjectCommand(CommandList *pObj) +{ + Dummy *pDum = NULL; + if(NULL != pObj) + { + pDum = (Dummy *)pObj->pData; + if(NULL != pDum) + { + if(NULL != pDum->pDescriptor->GetInterface(pDum,DRIVEID)) return 0; + if(NULL != pDum->pDescriptor->GetInterface(pDum,COUNTID)) return 0; + if(NULL != pDum->pDescriptor->GetInterface(pDum,ENVIRINTERFACE)) return 0; + } + return 1; + } + return 0; +} + +/*-------------------------------------------------------------------------*/ +static void addToList(Tcl_Interp *tTcl, Tcl_Obj *tList, char *prefix, char *sVal) +{ + char pBuf[256]; + if(NULL!=sVal) + { + memset(pBuf,0,256); + sprintf(pBuf,"%s=%s",prefix,sVal); + Tcl_ListObjAppendElement(tTcl,tList,Tcl_NewStringObj(pBuf,strlen(pBuf))); + } +} +/*-------------------------------------------------------------------------*/ +static void addPairsToList(Tcl_Interp *tTcl, Tcl_Obj *tList, IPair *pList) +{ + IPair *pCurrent; + if(NULL!=pList) + { + pCurrent = pList; + while(NULL!=pCurrent) + { + addToList(tTcl,tList,pCurrent->name,pCurrent->value); + pCurrent = pCurrent->pNext; + } + } +} +/*--------------------------------------------------------------------------*/ +static void RemoveWhiteSpace(char *pText) +{ + int i, ii, i3; + char *pPtr; + + if(NULL==pText) return; + + /* find start */ + i = 0; + while(isspace(pText[i])) + { + i++; + } + + /* find end */ + ii = strlen(pText); + ii--; + while( (isspace(pText[ii])) || (pText[ii] == '\n') ) + { + ii--; + } + + /* copy it */ + pPtr = pText; + for(i3 = i; i3 < (ii+1); i3++) + { + *pPtr = pText[i3]; + pPtr++; + } + *pPtr = '\0'; +} diff --git a/sinfox.h b/sinfox.h new file mode 100644 index 00000000..7e66b929 --- /dev/null +++ b/sinfox.h @@ -0,0 +1,115 @@ +/*--------------------------------------------------------------------------- +----------------------------------------------------------------------------*/ +#ifndef ANSTO_SINFOX +#define ANSTO_SINFOX +#include +#include + +typedef struct __Sinfox { + pObjectDescriptor pDes; /* required as first field */ + const char *buildVersion; + const char *configName; + const char *configVersion; + const char *description; + const char *instrument; + const char *schemaVersion; + Tcl_Interp *tTcl; +} Sinfox; + +typedef struct __Sinfox *pSinfox; + +#ifndef SICSSITE /* Avoid duplicate declaration in site_ansto.c */ + +const int iNumInfoKeys = 6; +char *pInfoKeys[7] = { + "buildVersion", + "configName", + "configVersion", + "description", + "instrument", + "schemaVersion", + NULL +}; + +const int iNumCommandKeys = 3; +char *pCommandKeys[4] = { + "argument", + "device", + "interface", + NULL +}; + +const int iNumDeviceKeys = 3; +char *pDeviceKeys[4] = { + "attribute", + "command", + "interface", + NULL +}; + +const int iNumDeviceTypes = 24; +char *pDeviceTypes[25] = { + "4-circle-calculus", + "anticollider", + "chopper", + "chopperadaptor", + "connection", + "crystalselector", + "environment monitor", + "environment controller", + "gpib", + "hklscan", + "hmcontrol", + "lin2ang", + "local maximum detector", + "maximizer", + "mesure", + "motor", + "mulmot", + "omega2theta", + "rs232 controller", + "scanobject", + "sicsvariable", + "singlecounter", + "velocityselector", + "xytable", + NULL +}; + +const int iNumIFaces = 4; +char *pIFaces[5] = { + "callback", + "countable", + "drivable", + "environment", + NULL +}; + +const int iNumServerKeys = 10; +char *pServerKeys[11] = { + "help", + "list", + "command", + "connection", + "device", + "devicetype", + "experiment", + "group", + "interface", + "key", + NULL +}; + +#endif /* SICSSITE */ + +/*--------------------- lifecycle -------------------------------------- */ +int InstallSinfox(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +void DeleteSinfox(void *pSelf); + +/*--------------------- operations --------------------------------------*/ +int SinfoxAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +/*-----------------------------------------------------------------------*/ +#endif /* ANSTO_SINFOX */ diff --git a/status.c b/status.c index 6ccbf653..2aaaca2e 100644 --- a/status.c +++ b/status.c @@ -181,7 +181,8 @@ return 1; } /*------------------- The CallBack function for interest ------------------*/ - static int StatusCallback(int iEvent, void *pEvent, void *pUser) + static int StatusCallback(int iEvent, void *pEvent, void *pUser, + commandContext cc) { SConnection *pCon; char pBueffel[80]; @@ -191,7 +192,9 @@ pCon = (SConnection *)pUser; sprintf(pBueffel,"status = %s", pText[(int)eCode]); + SCPushContext2(pCon,cc); SCWrite(pCon,pBueffel,eWarning); + SCPopContext(pCon); return 1; } @@ -217,7 +220,8 @@ strtolower(argv[1]); if(strcmp(argv[1],"interest") == 0) { - lID = RegisterCallback(pCall, VALUECHANGE, StatusCallback, + lID = RegisterCallback(pCall, SCGetContext(pCon), + VALUECHANGE, StatusCallback, pCon, NULL); SCRegister(pCon,pSics, pCall,lID); SCSendOK(pCon); diff --git a/stptok.h b/stptok.h new file mode 100644 index 00000000..f1935ea7 --- /dev/null +++ b/stptok.h @@ -0,0 +1,18 @@ +/* +** stptok() -- public domain by Ray Gardner, modified by Bob Stout +** +** You pass this function a string to parse, a buffer to receive the +** "token" that gets scanned, the length of the buffer, and a string of +** "break" characters that stop the scan. It will copy the string into +** the buffer up to any of the break characters, or until the buffer is +** full, and will always leave the buffer null-terminated. It will +** return a pointer to the first non-breaking character after the one +** that stopped the scan. +*/ + +#ifndef STPSTPTOK +#define STPSTPTOK + +char *stptok(const char *s, char *tok, size_t toklen, char *brk); + +#endif diff --git a/sycFormat.tcl b/sycFormat.tcl new file mode 100644 index 00000000..78c21694 --- /dev/null +++ b/sycFormat.tcl @@ -0,0 +1,91 @@ +#---------------------------------------------------------------------------- +# Implements sycFormat which is needed by the sycamore protocol. +# Deobjectified version of the ANSTO original +# +# Original Implementor: Paul Hathaway, Ferdi Francescini +# +# More bugs introduced by: Mark Koennecke +#------------------------------------------------------------------------- + +if { [info exists sycinit] == 0 } { + set sycinit 1 + Publish sycformat Spy +} + + array set statusMap [ list OKOK "ok" \ + HWIdle "idle" \ + HWBusy "running" \ + HWFault "fault" \ + HWPosFault "posfault" \ + HWCrash "crash" \ + NOMEMORY "nomemory" \ + HWNoBeam "nobeam" \ + HWPause "pause" \ + HWWarn "warn" \ + HWRedo "redo" ] + + + # 'tag' and 'msgString' parameters must be passed within braces + # eg sycFormat con0004 t000005 s1 event {s1} {type.position status.HWBusy} + proc sycformat {connID transID devID msgFlag tag msgString} { + global statusMap cache + + set fullmatch ""; set msg ""; set eventType ""; set status "" + set position "" + + proc _prefix {flag} { + upvar connID cID transID tID devID dID + return "\[$cID:$tID:$dID:$flag\]" + } + + regexp {<(.*)>} $msgString match msg + regexp {type\.(\w*)} $msgString match eventType + regexp {status\.(\w*)} $msgString match status + + # Skip useless messages + if {[string first "Parameter Listing for motor" $msgString] > -1} { + return "" + } + + switch $msgFlag { + "start" { + set output "[_prefix start] $msgString" + + } + "event" { + switch $eventType { + "POSITION" { + regexp {(\w+)\.position *= *(\d+(?:\.\d+)?)} $msgString match device position + set output "[_prefix event] $tag={type=$eventType,$devID.position=$position}" + } + default { + # Error + } + } + } + "out" { + # Concatenate multiple messages into a comma separated list + if [info exists cache($transID)] { + append msg ", " $msgString + eval "lappend cache($transID) $msg" + } else { + eval "lappend cache($transID) $msgString" + } + set output "" + } + "finish" { + if [info exists cache($transID)] { + set output "[_prefix out] $tag=\{$cache($transID)\}" + append output "\n[_prefix finish]" + unset cache($transID) + } else { + set output "[_prefix finish]" + } + } + default { + set output "[_prefix $msgFlag] $msgString" + } + } + return $output + } + diff --git a/sycamore.tcl b/sycamore.tcl new file mode 100644 index 00000000..8d5dcbc1 --- /dev/null +++ b/sycamore.tcl @@ -0,0 +1,219 @@ +#source $sychome/stooop/mkpkgidx.tcl +#source stooop.tcl +#set tcl_pkgPath $sychome +# ClientPut $tcl_pkgPath "value" +# package require stooop 4 ;# load stooop package +# namespace forget stooop::* ;# remove if previously loaded +# namespace import stooop::* + +# ----------------------------------------------------------------------------- +# source $sychome/ns_site.tcl +# source $sychome/ns_sequencer.tcl +# source $sychome/ns_server.tcl + + set STACKTRACE 0 + proc stackTrace args { + set level [ info level ] + ClientPut "====================" "value" + for {set i 1} {$i < $level} {incr i} { + ClientPut [info level $i] "value" + ClientPut " " "value" + } + ClientPut "====================" "value" + } + +# ----------------------------------------------------------------------------- +# testing stubs when SICS modules not available +# proc sinfox args +# proc ClientPut {msg oCode} +# proc SICSType {objName} +# source stubs.tcl + +# ----------------------------------------------------------------------------- +# Sycamore Utilities: tcl procedures required by sycamore implementation + + proc sinWrite {msg oCode} { + # simplest processing of format for now + global STACKTRACE + if {$STACKTRACE} { + stackTrace + } + ClientPut $msg $oCode + } + + proc varexist {nsp var} { + return [expr [string compare $nsp$var [namespace which -variable $nsp$var]]==0] + } + +#proc sycFormat {connID transID devID msgFlag args} { +# return "\[$connID:$transID:$devID:$msgFlag\] $args" +#} +#source $sychome/sycFormat.tcl +#publish sycFormat spy + + proc arga argStr { + set args [ split $argStr ] + set argc [llength $args] + # syc::debug "arga.argc = %s" $argc + set objName "" + set key "" + set name "" + set val "" + set bObj [expr $argc > 0] + set bKey [expr $argc > 1] + set bName [expr $argc > 2] + set bVal [expr $argc > 3] + if $bObj { + set objName [string tolower [lindex $args 0]] + #syc::debug "arga.objName = %s" $objName + } + if $bKey { + set key [string tolower [lindex $args 1]] + #syc::debug "arga.key = %s" $key + } + if $bName { + set name [string tolower [lindex $args 2]] + } + if $bVal { + set val [string tolower [lindex $args 3]] + } +# ? cannot get 'array set' to work in the form: +# array set argv { +# argc $argc +# objName $objName +# ... etcetera +# } + set argv(argc) $argc + set argv(bObj) $bObj + set argv(bKey) $bKey + set argv(bName) $bName + set argv(bVal) $bVal + set argv(objName) $objName + set argv(key) $key + set argv(name) $name + set argv(val) $val + # would like to return associative array + # for now, settle for list + # syc::debug "arga.argv = { %s }" [array get argv] + return [array get argv] + } + + # alternative solution for passing arguments around + #class argv { + # proc argv {this args} { + # set ($this,argc) [llength $args] + # set ($this,objName) "" + # set ($this,key) "" + # set ($this,name) "" + # set ($this,val) "" + # set ($this,bObj) [expr $l > 0] + # set ($this,bKey) [expr $l > 0] + # set ($this,bName) [expr $l > 1] + # set ($this,bVal) [expr $l > 2] + # if $($this,bObj) { + # set ($this,objName) [lindex $args 0] + # } + # if $($this,bKey) { + # set ($this,key) [lindex $args 0] + # } + # if $($this,bName) { + # set ($this,name) [lindex $args 1] + # } + # if $($this,bVal) { + # set ($this,val) [lindex $args 2] + # } + # } + # proc ~argv {this} {} + #} + # + ## ----------------------------------------------------------------------------- + # working idea for making diagnostic class global + class diagnostic { + proc diagnostic {this} { + set ($this,id) $this + set ($this,debug) 0 + } + proc ~diagnostic {this} {} + + proc diag {this flag} { + set msg [format "diag=%s" $flag] + switch $flag { + "on" { + set ($this,debug) 1 + } + "off" { + set ($this,debug) 0 + } + default {} + } + if {1 == ($this,debug)} { + set msg "diag=on" + } else { + set msg "diag=off" + } + return [format "%s.diag = \{ %s \}" $this $msg] + } + + proc debug {this dMsg dVal} { + if {1 > ($this,debug)} { + return + } + sinWrite [format "%s::debug: %s" $this [format $dMsg $dVal]] "value" + } + } + + ## ----------------------------------------------------------------------------- + # Class for module static variables and methods + class syc { + # class lifecycle methods + proc syc {this} {} + proc ~syc {this} {} + + # static data members + set debug 0 + + # static methods + proc debug args { + if {$syc::debug < 1} { + return + } + set l [llength $args] + set dMsg "Script code event" + set dVal " " + if {$l > 0} { + set dMsg [lindex $args 0] + if {$l > 1} { + set dVal [lindex $args 1] + } + } + sinWrite [format "syc::debug: %s" [format $dMsg $dVal]] "value" + } + + proc diag args { + set flag [lindex $args 0] + set msg [format "diag=%s" $flag] + switch $flag { + "on" { + set syc::debug 1 + } + "off" { + set syc::debug 0 + } + default { + if {1 == $syc::debug} { + set msg "diag=on" + } else { + set msg "diag=off" + } + } + } + return [format "syc.diag = \{ %s \}" $msg] + } + } + + ## ----------------------------------------------------------------------------- + sinWrite "Loading sinfo" "value" +#source $sychome/sinfo.tcl +#publish sinfo spy + # source $sychome/sequencer.tcl + diff --git a/task.c b/task.c index 1fc4ca9b..235917bc 100644 --- a/task.c +++ b/task.c @@ -293,7 +293,7 @@ ente: assert(self); assert(self->iID == TASKERID); - /* Cycle until back at our selves killed. */ + /* Cycle until back at ourselves */ pEnd = self->pCurrent; pEnd->iStatus = WAITING; IncrTaskPointer(self); diff --git a/task.h b/task.h index 80183be8..7be25cd6 100644 --- a/task.h +++ b/task.h @@ -106,7 +106,7 @@ int TaskYield(pTaskMan self); /* does one cycle of the task loop and returns to the caller.This call allows - other tasks to execute while a task executeds a lengthy calculation. + other tasks to execute while a task executes a lengthy calculation. */ /*--------------------------------------------------------------------------*/ int TaskSignal(pTaskMan self, int iSignal, void *pSigData); diff --git a/tclmotdriv.c b/tclmotdriv.c new file mode 100644 index 00000000..c438a257 --- /dev/null +++ b/tclmotdriv.c @@ -0,0 +1,395 @@ +/*--------------------------------------------------------------------------- + This is a motor driver which is implemented in Tcl. This means + this code is only a wrapper which calls Tcl functions to do the + actual work. + + The Tcl functions to implement the interface are called with the name + of the motor as first parameter followed by any additional parameters + such as the position to run to for run. Functions have to return the proper + SICS return codes for a motor driver as integer numbers. + + The Tcl function list is initialized from a Tcl-array which holds function + names for the entries: + - getpos + - run + - status + - geterror + - fixit + This Tcl-array is passed as parameter on creating the motor. In order to + facilitate error handling, a motor parameter errorcode is available to + store errors between invocations. + + copyright: see file COPYRIGHT + + Mark Koennecke, December 2005 + --------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "sics.h" +#include "modriv.h" +#include "tclmotdriv.h" + +#define FUNCNOTFOUND -11000 +#define TCLERROR -11001 +#define NOTCLRESULT -11002 +/*----------------------------------------------------------------------------*/ +static int buildStandardCommandPart(TCLDriv *pDriv, char *command, + char *tclCommand, int commandLen){ + char tclFunc[132]; + int status; + + status = StringDictGet(pDriv->mappings,command,tclFunc,131); + if(status != 1) { + return 0; + } + snprintf(tclCommand,commandLen,"%s %s ", tclFunc, pDriv->motName); + return 1; +} +/*----------------------------------------------------------------------------*/ + static int GetTclPos(void *self, float *fPos){ + TCLDriv *pDriv; + char tclCommand[1024]; + int status; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + pDriv->errorCode = 0; + if(!buildStandardCommandPart(pDriv,"getpos",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + return HWFault; + } + + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL){ + pDriv->errorCode = NOTCLRESULT; + return HWFault; + } + if(status != TCL_OK){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + return HWFault; + } + sscanf(result,"%f",fPos); + return OKOK; + } +/*----------------------------------------------------------------------------*/ + static int TclRun(void *self, float fVal) { + TCLDriv *pDriv; + char tclCommand[1024]; + char num[80]; + int status; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + pDriv->errorCode = 0; + if(!buildStandardCommandPart(pDriv,"run",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + return HWFault; + } + snprintf(num,79,"%f",fVal); + strncat(tclCommand,num,1023-strlen(tclCommand)); + + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL) { + pDriv->errorCode = NOTCLRESULT; + return HWFault; + } + if(status != TCL_OK){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + return HWFault; + } + sscanf(result,"%d%",&status); + return status; + } +/*-------------------------------------------------------------------------*/ +static int evaluateInternalErrors(TCLDriv *pDriv, int *iCode, + char *error, int iErrLen){ + switch(pDriv->errorCode){ + case FUNCNOTFOUND: + strncpy(error,"Config Error: Tcl function for driver not found",iErrLen); + *iCode = pDriv->errorCode; + return 1; + break; + case TCLERROR: + strncpy(error,pDriv->tclError,iErrLen); + *iCode = pDriv->errorCode; + return 1; + break; + case NOTCLRESULT: + strncpy(error,"Tcl function did not return result",iErrLen); + *iCode = pDriv->errorCode; + return 1; + break; + default: + return 0; + break; + } + return 0; +} +/*--------------------------------------------------------------------------*/ + static void TclError(void *self, int *iCode, char *error, int iErrLen){ + TCLDriv *pDriv; + char tclCommand[1024]; + int status = 1; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + if(evaluateInternalErrors(pDriv,iCode,error,iErrLen) == 1) { + return; + } + + if(!buildStandardCommandPart(pDriv,"geterror",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + status = 0; + } + + if(status != 0){ + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL) { + pDriv->errorCode = NOTCLRESULT; + } + if(status != TCL_OK && result != NULL){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + } + } + + if(evaluateInternalErrors(pDriv,iCode,error,iErrLen) == 1) { + return; + } + strncpy(error,result,iErrLen); + } +/*---------------------------------------------------------------------------*/ + static int TclFix(void *self, int iError, float fNew){ + TCLDriv *pDriv; + char tclCommand[1024]; + char num[80]; + int status; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + pDriv->errorCode = 0; + if(!buildStandardCommandPart(pDriv,"fixit",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + return HWFault; + } + snprintf(num,79,"%f",fNew); + strncat(tclCommand,num,1023-strlen(tclCommand)); + + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL) { + pDriv->errorCode = NOTCLRESULT; + return HWFault; + } + if(status != TCL_OK){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + return HWFault; + } + sscanf(result,"%d%",&status); + return status; + } +/*--------------------------------------------------------------------------*/ + static int TclHalt(void *self) + { + TCLDriv *pDriv; + char tclCommand[1024]; + int status; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + pDriv->errorCode = 0; + if(!buildStandardCommandPart(pDriv,"halt",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + return HWFault; + } + + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL){ + pDriv->errorCode = NOTCLRESULT; + return HWFault; + } + if(status != TCL_OK){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + return HWFault; + } + return OKOK; + } +/*--------------------------------------------------------------------------*/ + static int TclStat(void *self) + { + TCLDriv *pDriv; + char tclCommand[1024]; + int status; + const char *result = NULL; + + assert(self); + pDriv = (TCLDriv *)self; + + pDriv->errorCode = 0; + if(!buildStandardCommandPart(pDriv,"status",tclCommand,1023)){ + pDriv->errorCode = FUNCNOTFOUND; + return HWFault; + } + + status = Tcl_Eval(pServ->pSics->pTcl,tclCommand); + result = Tcl_GetStringResult(pServ->pSics->pTcl); + if(result == NULL){ + pDriv->errorCode = NOTCLRESULT; + return HWFault; + } + if(status != TCL_OK){ + pDriv->errorCode = TCLERROR; + strncpy(pDriv->tclError,result,1023); + return HWFault; + } + sscanf(result,"%d%",&status); + return status; + } +/*-----------------------------------------------------------------------*/ +static int TclSetPar(void *self, SConnection *pCon, char *name, float newValue){ + TCLDriv *pDriv = (TCLDriv *) self; + + assert(self); + assert(pCon); + + if(strcmp(name,"hardupperlim") == 0) + { + pDriv->fUpper = newValue; + return 1; + } + if(strcmp(name,"hardlowerlim") == 0) + { + pDriv->fLower = newValue; + return 1; + } + if(strcmp(name,"errorcode") == 0) + { + pDriv->errorCode = (int)newValue; + return 1; + } + return 0; +} +/*-----------------------------------------------------------------------*/ +static int TclGetPar(void *self, char *name, float *value){ + TCLDriv *pDriv = (TCLDriv *) self; + + assert(self); + + if(strcmp(name,"errorcode") == 0) + { + *value = (float)pDriv->errorCode; + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ + void KillTCL(void *pData) + { + TCLDriv *pDriv = (TCLDriv *) pData; + + if(pDriv != NULL){ + DeleteStringDict(pDriv->mappings); + } + + return; + } +/*-------------------------------------------------------------------------*/ +static int assignMappings(TCLDriv *pDriv, SConnection *pCon, char *arrayName){ + const char *funcName = NULL; + char *funcText[] = {"getpos", + "run", + "status", + "halt", + "geterror", + "fixit", + NULL}; + char error[256]; + int count = 0; + + while(funcText[count] != NULL) { + funcName = Tcl_GetVar2(pServ->pSics->pTcl,arrayName,funcText[count],TCL_GLOBAL_ONLY); + if(funcName == NULL) { + snprintf(error,255,"ERROR: entry for %s not found in tcl-array %s", + funcText[count], arrayName); + SCWrite(pCon,error,eError); + return 0; + } + StringDictAddPair(pDriv->mappings,funcText[count],(char *)funcName); + count++; + } + return 1; +} +/*--------------------------------------------------------------------------*/ + MotorDriver *CreateTclMotDriv(SConnection *pCon, int argc, char *argv[]) + { + TCLDriv *pDriv = NULL; + + assert(pCon); + + if(argc < 4) { + SCWrite(pCon,"ERROR: not enough arguments to initilaize Tcl-driver",eError); + return NULL; + } + + pDriv = (TCLDriv *)malloc(sizeof(TCLDriv)); + if(!pDriv){ + SCWrite(pCon,"Error allocating memory in TclMotor",eError); + return NULL; + } + memset(pDriv,0,sizeof(TCLDriv)); + pDriv->mappings = CreateStringDict(); + if(pDriv->mappings == NULL){ + SCWrite(pCon,"Error allocating memory in TclMotor",eError); + free(pDriv); + return NULL; + } + if(assignMappings(pDriv,pCon,argv[3]) != 1){ + DeleteStringDict(pDriv->mappings); + free(pDriv); + return NULL; + } + + pDriv->name = strdup("Tcl-Driver"); + strncpy(pDriv->motName, argv[1], 131); + pDriv->GetPosition = GetTclPos; + pDriv->RunTo = TclRun; + pDriv->GetStatus = TclStat; + pDriv->GetError = TclError; + pDriv->TryAndFixIt = TclFix; + pDriv->SetDriverPar = TclSetPar; + pDriv->GetDriverPar = TclGetPar; + pDriv->Halt = TclHalt; + pDriv->KillPrivate = KillTCL; + + return (MotorDriver *)pDriv; + } + + + + + + + + + + diff --git a/tclmotdriv.h b/tclmotdriv.h new file mode 100644 index 00000000..96520e9e --- /dev/null +++ b/tclmotdriv.h @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------- + This is a motor driver which is implemented in Tcl. This means + this code is only a wrapper which calls Tcl functions to do the + actual work. + + copyright: see file COPYRIGHT + + Mark Koennecke, December 2005 + --------------------------------------------------------------------------*/ +#ifndef TCLMOTDRIV +#define TCLMOTDRIV +#include "stringdict.h" + + typedef struct ___TclDriv { + /* general motor driver interface + fields. REQUIRED! + */ + float fUpper; /* upper limit */ + float fLower; /* lower limit */ + char *name; + int (*GetPosition)(void *self,float *fPos); + int (*RunTo)(void *self, float fNewVal); + int (*GetStatus)(void *self); + void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); + int (*TryAndFixIt)(void *self,int iError, float fNew); + int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); + void (*KillPrivate)(void *self); + + /* Tcl specific fields */ + pStringDict mappings; + int errorCode; + char tclError[1024]; + char motName[132]; + } TCLDriv; +#endif diff --git a/velo.c b/velo.c index b26f69ae..3f8c260c 100644 --- a/velo.c +++ b/velo.c @@ -1,4 +1,4 @@ -/*--------------------------------------------------------------------------- + /*--------------------------------------------------------------------------- V E L O C I T Y S E L E C T O R The velocity selector module for SICS. For documentation see velo.w @@ -116,6 +116,37 @@ /* Success ! */ return 1; } +/*-----------------------------------------------------------------------*/ +static void VSListForbidden(pVelSel self, SConnection *pCon){ + Tcl_DString message; + int status; + Verbot Alcatraz; + char pBueffel[256]; + + Tcl_DStringInit(&message); + /* + The first entry in the forbidden region thing is meant to + contain the overall range: skip it! + */ + status = LLDnodePtr2First(self->iForbidden); + LLDnodeDataTo(self->iForbidden,&Alcatraz); + if(status == 1){ + snprintf(pBueffel,255,"%s.forbidden = {%f -inf", self->pName, Alcatraz.fMax); + Tcl_DStringAppend(&message,pBueffel,strlen(pBueffel)); + } + + /* now search the forbidden regions */ + status = LLDnodePtr2Next(self->iForbidden); + while(status != 0){ + LLDnodeDataTo(self->iForbidden,&Alcatraz); + snprintf(pBueffel,255,", %f - %f", Alcatraz.fMin, Alcatraz.fMax); + Tcl_DStringAppend(&message,pBueffel,strlen(pBueffel)); + status = LLDnodePtr2Next(self->iForbidden); + } + Tcl_DStringAppend(&message,"}",1); + SCWrite(pCon,Tcl_DStringValue(&message),eValue); + Tcl_DStringFree(&message); +} /*-------------------------------------------------------------------------*/ static long VSSetValue(void *pData,SConnection *pCon, float fVal) { @@ -701,7 +732,7 @@ return 1; } /*-------------------------------------------------------------------------*/ - static pEVDriver MakeDummyVel(pVelSel pVel) + pEVDriver MakeDummyVel(pVelSel pVel) { pEVDriver pNew = NULL; pVelPrivate ich = NULL; @@ -869,51 +900,6 @@ EVRegisterController(FindEMON(pSics),pBueffel,pNew->pMonitor,pCon); return iRet; } -/*------------------------------------------------------------------------*/ - static int TTFindNumber(Tcl_Interp *pTcl,char *pPtr, float *fVal) - { - int iRet; - char *pEnd; - char *pMark; - double dVal; - - pEnd = pPtr + strlen(pPtr); - - /* advance to first non blank or non = character */ - while( (isspace(*pPtr)) || (*pPtr == '=') ) - { - pPtr++; - if(pPtr >= pEnd) - { - return 0; - } - } - - /* find end of string */ - pMark = pPtr; - while( (!isspace(*pMark))) - { - pMark++; - if(pMark >= pEnd) - { - return 0; - } - } - /* replace pMark temporarily by \0 */ - *pMark = '\0'; - - /* now read number from pPtr */ - iRet = Tcl_GetDouble(pTcl,pPtr,&dVal); - if(iRet != TCL_OK) - { - return 0; - } - - /* fix back and return */ - *pMark = ' '; - *fVal = (float)dVal; - return 1; - } /*------------------------------------------------------------------------*/ typedef struct { SConnection *pCon; @@ -935,7 +921,8 @@ } } /*------------------------------------------------------------------------*/ - static int RotationInterest(int iEvent, void *pData, void *pUser) + static int RotationInterest(int iEvent, void *pData, void *pUser, + commandContext cc) { CBData *pDat = NULL; float *fVal = NULL; @@ -949,12 +936,12 @@ if(iEvent == ROTSTART) { sprintf(pBueffel,"%s Starting",pDat->pName); - SCWrite(pDat->pCon,pBueffel,eWarning); + SCWriteInContext(pDat->pCon,pBueffel,eWarning,cc); } else if(iEvent == ROTMOVE) { sprintf(pBueffel,"%s.rpm = %f",pDat->pName, *fVal); - SCWrite(pDat->pCon,pBueffel,eWarning); + SCWriteInContext(pDat->pCon,pBueffel,eWarning,cc); } return 1; } @@ -980,10 +967,6 @@ assert(pCon); assert(pSics); - /* convert to text for parsing */ - Arg2Text(argc,argv,pCommand, 511); - strtolower(pCommand); - if(argc < 2) { sprintf(pBueffel,"ERROR: %s expects at least one parameter",argv[0]); @@ -1026,10 +1009,10 @@ } pCB->pCon = pCon; pCB->pName = strdup(argv[0]); - lID = RegisterCallback(self->pCall, ROTSTART, RotationInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), ROTSTART, RotationInterest, pCB, KillCB); SCRegister(pCon,pSics, self->pCall,lID); - lID = RegisterCallback(self->pCall, ROTMOVE, RotationInterest, + lID = RegisterCallback(self->pCall, SCGetContext(pCon), ROTMOVE, RotationInterest, pCB, NULL); SCRegister(pCon,pSics, self->pCall,lID); SCSendOK(pCon); @@ -1081,6 +1064,13 @@ SCSendOK(pCon); return 1; } + + /* list forbidden regions */ + if(strcmp(argv[1],"forbidden") == 0) + { + VSListForbidden(self,pCon); + return 1; + } /* status, prints a status message */ if(strcmp(argv[1],"status") == 0) @@ -1132,6 +1122,30 @@ return 0; } } + + if(strcmp(argv[1],"rottolerance") == 0){ + if(argc > 2){ + /* set case */ + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); + if(iRet != TCL_OK){ + sprintf(pBueffel,"ERROR: %s not recognized as numeric value for fMax", + argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + self->pDriv->fTolerance = dVal; + SCSendOK(pCon); + return 1; + } else { + sprintf(pBueffel,"%s.rottolerance = %f", + argv[0],self->pDriv->fTolerance); + SCWrite(pCon,pBueffel,eError); + return 1; + } + } /* initialise the tilt and rot to current values */ iRet = VSGetRotation(self,&fRot); @@ -1143,61 +1157,50 @@ iRet = MotorGetSoftPosition(self->pTilt,pCon,&fTilt); if(!iRet) { - SCWrite(pCon,"ERROR: velocity selector operation aborted",eError); + SCWrite(pCon,"ERROR: failed to read tilt angle",eError); return 0; } /* search for Tilt */ - pPtr = strstr(pCommand,"tilt"); - if(pPtr) /* analyse tilt */ - { - iDrive = 1; - iRet = TTFindNumber(pSics->pTcl,pPtr+strlen("tilt"),&fTilt); - if(!iRet) - { - /* no new value, just print the current one */ - MotorGetSoftPosition(self->pTilt,pCon,&fTilt); - sprintf(pBueffel,"%s tilt = %f",argv[0],fTilt); - SCWrite(pCon,pBueffel,eError); - return 0; - } + if(strcmp(argv[1],"tilt") == 0){ + if(argc > 2){ + /* set case */ + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); + if(iRet != TCL_OK){ + sprintf(pBueffel,"ERROR: %s not recognized as numeric value for fMax", + argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + fTilt = dVal; + iDrive = 1; + } else { + sprintf(pBueffel,"%s tilt = %f",argv[0],fTilt); + SCWrite(pCon,pBueffel,eError); + return 1; + } } - /* serch for rottolerance */ - pPtr = strstr(pCommand,"rottolerance"); - if(pPtr) /* analyse rottolerance */ - { - iDrive = 1; - iRet = TTFindNumber(pSics->pTcl,pPtr+strlen("rottolerance"),&fTol); - if(!iRet) - { - sprintf(pBueffel,"%s.rottolerance = %f", - argv[0],self->pDriv->fTolerance); - SCWrite(pCon,pBueffel,eError); - return 1; - } - else - { - self->pDriv->fTolerance = fTol; - SCSendOK(pCon); - return 1; - } - } /* same for rot */ - pPtr = strstr(pCommand,"rot"); - if(pPtr) /* analyse tilt */ - { - iDrive = 1; - iRet = TTFindNumber(pSics->pTcl,pPtr+strlen("rot"),&fVal); - if(!iRet) - { - sprintf(pBueffel,"%s rot = %f",argv[0],fRot); - SCWrite(pCon,pBueffel,eError); - return 0; - } - fRot = fVal; + if(strcmp(argv[1],"rot") == 0){ + if(argc > 2){ + /* set case */ + iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal); + if(iRet != TCL_OK){ + sprintf(pBueffel,"ERROR: %s not recognized as numeric value for fMax", + argv[2]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + fRot = dVal; + iDrive = 1; + } else { + sprintf(pBueffel,"%s rot = %f",argv[0],fRot); + SCWrite(pCon,pBueffel,eError); + return 1; + } } /* do drive if we really need to */ diff --git a/velo.h b/velo.h index de416862..136b7d7b 100644 --- a/velo.h +++ b/velo.h @@ -46,7 +46,6 @@ #line 264 "velo.w" - #line 164 "velo.w" int VSGetLossCurrent(pVelSel self, SConnection *pCon, float *fLoss); diff --git a/viscom.tcl b/viscom.tcl index 8c4c1637..ee4e652d 100755 --- a/viscom.tcl +++ b/viscom.tcl @@ -11,7 +11,7 @@ lappend auto_path /data/koenneck/bin/tcl set INI(DefUser) Spy set INI(DefPasswd) 007 -set INI(ServerPort) 3006 +set INI(ServerPort) 2911 set INI(InterruptPort) 2913 set INI(box) localhost set INI(usPasswd) Rosy