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