diff --git a/access.c b/access.c index 860c962a..110947e9 100644 --- a/access.c +++ b/access.c @@ -3,8 +3,9 @@ Mark Koennecke, November 1996 ----------------------------------------------------------------------------*/ -#ifndef PCODE -#define PCODE +#include +#include +#include static char *aCode[] = { "internal", @@ -13,4 +14,19 @@ "spy", NULL }; static int iCodes = 4; -#endif +/*--------------------------------------------------------------------------*/ +int decodeSICSPriv(char *privText){ + int code = 0; + + strtolower(privText); + while(aCode[code] != NULL){ + if(strcmp(aCode[code], privText) == 0){ + return code; + } + code++; + } + if(code >= iCodes){ + return -1; + } + return -1; +} diff --git a/conman.c b/conman.c index 26d92edd..c341ec79 100644 --- a/conman.c +++ b/conman.c @@ -65,6 +65,7 @@ #include "uubuffer.h" #include "commandlog.h" #include "stptok.h" +#include "sicshipadaba.h" /* #define UUDEB 1 @@ -361,6 +362,7 @@ extern pServer pServ; char pBueffel[132]; SConnection *pVictim = NULL; Item sItem; + pHdb root = NULL; pVictim = (SConnection *)pData; if(!VerifyConnection(pVictim)) @@ -388,6 +390,15 @@ extern pServer pServ; */ KillCapture(pVictim); + /* + * remove any callbacks which might still be active in the Hipadaba + */ + root = GetHipadabaRoot(); + if(root != NULL) + { + InternalRemoveHipadabaCallback(root,pVictim->ident); + } + /* If we have a grab, release it ! */ diff --git a/doc/manager/nxupdate.htm b/doc/manager/nxupdate.htm index 6b0e1373..0c20845d 100644 --- a/doc/manager/nxupdate.htm +++ b/doc/manager/nxupdate.htm @@ -65,6 +65,9 @@ file.
updateintervall
The time intervall in seconds between updates. The defualt is 1200, eg. 20 minutes. +
onoff +
can be 1 or 0. Switches automatic updates on or off. It might be usefule for + scans to switch this off.

diff --git a/fomerge.c b/fomerge.c index 8b971dbb..99629336 100644 --- a/fomerge.c +++ b/fomerge.c @@ -553,8 +553,6 @@ static int putSum(SicsInterp *pSics, SConnection *pCon, HistInt *sum = NULL; int iDet, iTime, i, j, iIndex, status; - return 1; - iTime = getFMdim(TIMEBIN); if(strcmp(name,"upper") == 0) { @@ -607,8 +605,6 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, pHistMem pMem = NULL; float fCenter, fFWHM, fStdDev, fVal; - return 1; - pMem = (pHistMem)FindCommandData(pSics,"hm2","HistMem"); if(pMem == NULL) { diff --git a/hipadaba.c b/hipadaba.c new file mode 100644 index 00000000..3c2d4bff --- /dev/null +++ b/hipadaba.c @@ -0,0 +1,788 @@ +/*------------------------------------------------------------------------- + The hierarchical parameter database code. For more information, see + hipadaba.h + + copyright: GPL + + Mark Koennecke, June 2006 +---------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "hipadaba.h" + +#define ABS(x) (x < 0 ? -(x) : (x)) +#define HDBMAGICK 77119900 +/*================== internal functions ===================================*/ +void DeleteCallbackChain(pHdbCallback root){ + pHdbCallback current = NULL, thisEntry; + + current = root; + while(current != NULL){ + if(current->killFunc != NULL){ + current->killFunc(current->userData); + } + thisEntry = current; + current = (pHdbCallback)current->next; + free(thisEntry); + } +} +/*-----------------------------------------------------------------------*/ +static void DeleteNodeData(pHdb node){ + pHdb tmp = NULL; + + if(node == NULL){ + return; + } + DeleteCallbackChain(node->writeCallbacks); + DeleteCallbackChain(node->updateCallbacks); + DeleteCallbackChain(node->readCallbacks); + + if(node->name != NULL){ + free(node->name); + } + ReleaseHdbValue(&node->value); + node->magic = 000000; + + while(node->child != NULL){ + tmp = node->child; + node->child = node->child->next; + DeleteNodeData(tmp); + } + free(node); +} +/*------------------------------------------------------------------------*/ +void RemoveHdbNodeFromParent(pHdb node){ + pHdb parent = NULL; + pHdb current = NULL; + + parent = node->mama; + if(parent != NULL){ + if(parent->child == node){ + parent->child = node->next; + return; + } + current = parent->child; + while(current->next != node){ + current = current->next; + } + current->next = current->next->next; + } +} +/*-----------------------------------------------------------------------*/ +static void RemoveCallbackNode(pHdbCallback victim){ + if(victim->previous != NULL) { + victim->previous->next = victim->next; + } + if(victim->next != NULL){ + victim->next->previous = victim->previous; + } + if(victim->killFunc != NULL){ + victim->killFunc(victim->userData); + } + free(victim); +} +/*----------------------------------------------------------------------- + * This code is ugly: the problem is fixing up the start of the chain. + * Think about it and improve + * ----------------------------------------------------------------------*/ +static pHdbCallback DeleteForID(pHdbCallback root, int id){ + pHdbCallback current = root; + pHdbCallback tmp = NULL; + pHdbCallback result = NULL; + + if(root == NULL){ + return NULL; + } + + /* + * delete at the start of the chain + */ + result = root; + while(result->id == id){ + tmp = result; + result = result->next; + RemoveCallbackNode(tmp); + if(result == NULL){ + return NULL; + } + } + + /* + * delete nodes in the middle of the chain + */ + current = result; + while(current != NULL){ + if(current->id == id){ + tmp = current; + current = (pHdbCallback)current->next; + RemoveCallbackNode(tmp); + } else { + current = (pHdbCallback)current->next; + } + } + return result; +} +/*-----------------------------------------------------------------------*/ +static pHdbCallback DeleteForInternalID(pHdbCallback root, int id){ + pHdbCallback current = root; + pHdbCallback tmp = NULL; + pHdbCallback result = NULL; + + if(root == NULL){ + return NULL; + } + + /* + * delete at the start of the chain + */ + result = root; + while(result->internalID == id){ + tmp = result; + result = result->next; + if(tmp->killFunc != NULL){ + tmp->killFunc(tmp->userData); + } + free(tmp); + if(result == NULL){ + return NULL; + } + } + + /* + * delete nodes in the middle of the chain + */ + current = result; + while(current != NULL){ + if(current->internalID == id){ + if(current->next != NULL){ + current->next->previous = current->previous; + } + if(current->previous != NULL){ + current->previous->next = current->next; + } + tmp = current; + current = (pHdbCallback)current->next; + if(tmp->killFunc != NULL){ + tmp->killFunc(tmp->userData); + } + free(tmp); + } else { + current = (pHdbCallback)current->next; + } + } + return result; +} +/*-------------------------------------------------------------------------*/ +static int InvokeCallbackChain(pHdbCallback root, pHdb node, + void *callData, hdbValue v){ + pHdbCallback current = root; + int status; + + while(current != NULL){ + status = current->userCallback(current->userData,callData, + node,v); + if(status != 1){ + return status; + } + current = current->next; + } + return 1; +} +/*----------------------------------------------------------------------*/ +char *hdbTrim(char *str) +{ + char *ibuf = str, *obuf = str; + int i = 0, cnt = 0; + + /* + ** Trap NULL + */ + + if (str) + { + /* + ** Remove leading spaces (from RMLEAD.C) + */ + + for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf) + ; + if (str != ibuf) + memmove(str, ibuf, ibuf - str); + + /* + ** Collapse embedded spaces (from LV1WS.C) + */ + + while (*ibuf) + { + if (isspace(*ibuf) && cnt) + ibuf++; + else + { + if (!isspace(*ibuf)) + cnt = 0; + else + { + *ibuf = ' '; + cnt = 1; + } + obuf[i++] = *ibuf++; + } + } + obuf[i] = '\0'; + + /* + ** Remove trailing spaces (from RMTRAIL.C) + */ + + while (--i >= 0) + { + if (!isspace(obuf[i])) + break; + } + obuf[++i] = '\0'; + } + return str; +} +/*------------------------------------------------------------------------*/ +static pHdb locateChild(pHdb root, char *name){ + pHdb current = NULL; + + current = root->child; + while(current != NULL){ + if(strcmp(current->name,name) == 0){ + return current; + } + current = current->next; + } + return NULL; +} +/*================= data functions ========================================*/ +hdbValue makeHdbValue(int datatype, int length){ + hdbValue val; + + memset(&val,0,sizeof(hdbValue)); + val.dataType = datatype; + + switch(datatype){ + case HIPINTAR: + val.arrayLength = length; + val.v.intArray = malloc(length*sizeof(long)); + if(val.v.intArray != NULL){ + memset(val.v.intArray,0,length*sizeof(long)); + } + break; + case HIPFLOATAR: + val.arrayLength = length; + val.v.floatArray = malloc(length*sizeof(double)); + if(val.v.floatArray != NULL){ + memset(val.v.floatArray,0,length*sizeof(double)); + } + break; + case HIPTEXT: + val.v.text = strdup("UNKNOWN"); + break; + } + return val; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbInt(int initValue){ + hdbValue result; + + result.dataType = HIPINT; + result.v.intValue = initValue; + return result; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbFloat(double initValue){ + hdbValue result; + + result.dataType = HIPFLOAT; + result.v.doubleValue = initValue; + return result; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbText(char *initText){ + hdbValue result; + + result.dataType = HIPTEXT; + result.v.text = initText; + return result; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbIntArrray(int length, long *data){ + hdbValue result; + + result.dataType = HIPINTAR; + result.arrayLength = length; + result.v.intArray = data; + return result; +} +/*-------------------------------------------------------------------------*/ +hdbValue MakeHdbFloatArrray(int length, double *data){ + hdbValue result; + + result.dataType = HIPFLOATAR; + result.arrayLength = length; + result.v.floatArray = data; + return result; +} +/*-------------------------------------------------------------------------*/ +void ReleaseHdbValue(hdbValue *v){ + switch(v->dataType){ + case HIPTEXT: + if(v->v.text != NULL){ + free(v->v.text); + } + break; + case HIPINTAR: + if(v->v.intArray != NULL){ + free(v->v.intArray); + } + break; + case HIPFLOATAR: + if(v->v.floatArray != NULL){ + free(v->v.floatArray); + } + break; + } +} +/*------------------------------------------------------------------------*/ +int compareHdbValue(hdbValue v1, hdbValue v2){ + int i; + + if(v1.dataType != v2.dataType){ + return 0; + } + switch(v1.dataType){ + case HIPNONE: + return 0; + break; + case HIPINT: + if(v1.v.intValue == v2.v.intValue){ + return 1; + } else { + return 0; + } + break; + case HIPFLOAT: + if(ABS(v1.v.doubleValue - v2.v.doubleValue) < .01){ + return 1; + } else { + return 0; + } + break; + case HIPTEXT: + if(strcmp(v1.v.text,v2.v.text) == 0){ + return 1; + } else { + return 0; + } + break; + case HIPINTAR: + if(v1.arrayLength != v2.arrayLength){ + return 0; + } + for(i = 0; i < v1.arrayLength; i++){ + if(v1.v.intArray[i] != v2.v.intArray[i]){ + return 0; + } + } + return 1; + break; + case HIPFLOATAR: + if(v1.arrayLength != v2.arrayLength){ + return 0; + } + for(i = 0; i < v1.arrayLength; i++){ + if(ABS(v1.v.floatArray[i] - v2.v.floatArray[i]) > .01){ + return 0; + } + } + return 1; + break; + default: + assert(0); + break; + } + return 0; +} +/*-------------------------------------------------------------------------*/ +int cloneHdbValue(hdbValue *source, hdbValue *clone){ + + memset(clone,0,sizeof(hdbValue)); + clone->dataType = source->dataType; + return copyHdbValue(source, clone); +} +/*================= node functions ========================================*/ +pHdb MakeHipadabaNode(char *name, int datatype, int length){ + pHdb pNew = NULL; + + pNew = malloc(sizeof(Hdb)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(Hdb)); + pNew->magic = HDBMAGICK; + pNew->name = strdup(name); + pNew->value.dataType = datatype; + switch(datatype){ + case HIPINTAR: + pNew->value.arrayLength = length; + pNew->value.v.intArray = malloc(length*sizeof(long)); + if(pNew->value.v.intArray == NULL){ + return NULL; + } + memset(pNew->value.v.intArray,0,length*sizeof(long)); + break; + case HIPFLOATAR: + pNew->value.arrayLength = length; + pNew->value.v.floatArray = malloc(length*sizeof(double)); + if(pNew->value.v.floatArray == NULL){ + return NULL; + } + memset(pNew->value.v.floatArray,0,length*sizeof(double)); + break; + case HIPTEXT: + pNew->value.v.text = strdup("UNKNOWN"); + break; + } + return pNew; +} +/*-------------------------------------------------------------------------*/ +void AddHipadabaChild(pHdb parent, pHdb child){ + pHdb current = NULL, prev = NULL; + + assert(parent != NULL && child != NULL); + + current = parent->child; + child->mama = parent; + if(current == NULL){ + parent->child = child; + child->next = NULL; + } else { + /* + * step to end of child chain + */ + while(current != NULL){ + prev = current; + current = current->next; + } + child->next = NULL; + prev->next = child; + } +} +/*--------------------------------------------------------------------------*/ +void DeleteHipadabaNode(pHdb node){ + pHdb current = NULL, tmp = NULL; + + if(node == NULL){ + return; + } + + RemoveHdbNodeFromParent(node); + + DeleteNodeData(node); +} +/*--------------------------------------------------------------------------*/ +int isHdbNodeValid(pHdb node){ + if(node == NULL){ + return 0; + } + if(node->magic == HDBMAGICK){ + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------------*/ +pHdb GetHipadabaNode(pHdb root, char *path){ + pHdb resultNode = NULL; + char *separator = NULL; + + path = hdbTrim(path); + + if(strcmp(path,"/") == 0 || strlen(path) == 0){ + return root; + } + + if(path[0] == '/'){ + path++; + } + + separator = strchr(path,'/'); + if(separator == NULL){ + return locateChild(root,path); + } else { + *separator = '\0'; + resultNode = locateChild(root, path); + if(resultNode == NULL){ + return NULL; + } else { + separator++; + return GetHipadabaNode(resultNode,separator); + } + } +} +/*--------------------------------------------------------------------------*/ +char *GetHipadabaPath(pHdb node){ + pHdb nodeStack[64]; + int depth = 0, length = 0, i; + pHdb current = NULL; + char *pPtr = NULL; + + /** + * build a nodestack and find out required string length for path + */ + current = node; + while(current != NULL){ + length += strlen(current->name) + 1; + nodeStack[depth] = current; + depth++; + assert(depth < 64); + current = current->mama; + } + + pPtr = malloc(length*sizeof(char)); + if(pPtr == NULL){ + return NULL; + } + memset(pPtr,0,length*sizeof(char)); + + /* + * we wish to decremement by one because above loop + * increments one to many and we wish to ignore the + * root node + */ + for(i = depth - 2; i >= 0; i--){ + strcat(pPtr,"/"); + strcat(pPtr,nodeStack[i]->name); + } + return pPtr; +} +/*==================== Callback Functions ==================================*/ +pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, + void *userData, killUserData killFunc, + int id, int internalID){ + pHdbCallback pNew = NULL; + + assert(func != NULL); + + pNew = malloc(sizeof(hdbCallback)); + if(pNew == NULL){ + return NULL; + } + memset(pNew,0,sizeof(hdbCallback)); + + pNew->userCallback = func; + pNew->userData = userData; + pNew->killFunc = killFunc; + pNew->id = id; + pNew->internalID = internalID; + return pNew; +} +/*-------------------------------------------------------------------*/ +void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){ + pHdbCallback current = NULL; + + switch(type){ + case HCBSET: + if(node->writeCallbacks == NULL){ + node->writeCallbacks = newCB; + return; + } else { + current = node->writeCallbacks; + } + break; + case HCBUPDATE: + if(node->updateCallbacks == NULL){ + node->updateCallbacks = newCB; + return; + } else { + current = node->updateCallbacks; + } + break; + case HCBREAD: + if(node->readCallbacks == NULL){ + node->readCallbacks = newCB; + return; + } else { + current = node->readCallbacks; + } + break; + default: + assert(0); + break; + } + if(current != NULL){ + while(current->next != NULL){ + current = (pHdbCallback)current->next; + } + current->next= newCB; + newCB->previous = current; + } +} +/*-------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){ + switch(type){ + case HCBSET: + if(node->writeCallbacks == NULL){ + node->writeCallbacks = newCB; + return; + } else { + newCB->next = node->writeCallbacks; + node->writeCallbacks->previous = newCB; + node->writeCallbacks = newCB; + } + break; + case HCBUPDATE: + if(node->updateCallbacks == NULL){ + node->updateCallbacks = newCB; + return; + } else { + newCB->next = node->updateCallbacks; + node->updateCallbacks->previous = newCB; + node->updateCallbacks = newCB; + } + break; + case HCBREAD: + if(node->readCallbacks == NULL){ + node->readCallbacks = newCB; + return; + } else { + newCB->next = node->readCallbacks; + node->readCallbacks->previous = newCB; + node->readCallbacks = newCB; + } + break; + default: + assert(0); + break; + } +} +/*----------------------------------------------------------------------------*/ +void RemoveHipadabaCallback(pHdb root, int id){ + pHdb current = NULL; + + root->writeCallbacks = DeleteForID(root->writeCallbacks,id); + root->updateCallbacks = DeleteForID(root->updateCallbacks,id); + root->readCallbacks = DeleteForID(root->readCallbacks,id); + + current = root->child; + while(current != NULL){ + RemoveHipadabaCallback(current,id); + current = current->next; + } +} +/*----------------------------------------------------------------------------*/ +void InternalRemoveHipadabaCallback(pHdb root, int internalID){ + pHdb current = NULL; + + root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID); + root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID); + root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID); + + current = root->child; + while(current != NULL){ + InternalRemoveHipadabaCallback(current,internalID); + current = current->next; + } +} +/*=================== parameter interface ====================================*/ +int copyHdbValue(hdbValue *source, hdbValue *target){ + int i; + + if(source->dataType != target->dataType){ + return 0; + } + + switch(source->dataType){ + case HIPNONE: + break; + case HIPINT: + target->v.intValue = source->v.intValue; + break; + case HIPFLOAT: + target->v.doubleValue = source->v.doubleValue; + break; + case HIPTEXT: + if(target->v.text != NULL){ + free(target->v.text); + } + target->v.text = strdup(source->v.text); + break; + case HIPINTAR: + if(target->arrayLength != source->arrayLength){ + if(target->v.intArray != NULL){ + free(target->v.intArray); + } + target->v.intArray = malloc(source->arrayLength * sizeof(long)); + if(target->v.intArray == NULL){ + return 0; + } + memset(target->v.intArray,0,source->arrayLength * sizeof(long)); + target->arrayLength = source->arrayLength; + } + for(i = 0; i < source->arrayLength; i++){ + target->v.intArray[i] = source->v.intArray[i]; + } + break; + case HIPFLOATAR: + if(target->arrayLength != source->arrayLength){ + if(target->v.floatArray != NULL){ + free(target->v.floatArray); + } + target->v.floatArray = malloc(source->arrayLength * sizeof(double)); + if(target->v.floatArray == NULL){ + return 0; + } + memset(target->v.floatArray,0,source->arrayLength * sizeof(double)); + target->arrayLength = source->arrayLength; + } + for(i = 0; i < source->arrayLength; i++){ + target->v.floatArray[i] = source->v.floatArray[i]; + } + break; + default: + /* + * unknown data type + */ + assert(0); + break; + } + return 1; +} +/*----------------------------------------------------------------------------*/ +int SetHipadabaPar(pHdb node, hdbValue v, void *callData){ + int status; + + status = InvokeCallbackChain(node->writeCallbacks, node, callData, v); + return status; +} +/*-----------------------------------------------------------------------------*/ +int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData){ + int status; + + status = InvokeCallbackChain(node->updateCallbacks, node, callData, v); + if(status != 1 ){ + return status; + } + copyHdbValue(&v,&node->value); + return 1; +} +/*-----------------------------------------------------------------------------*/ +int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){ + int status; + + status = InvokeCallbackChain(node->readCallbacks, node, callData, *v); + if(status != 1 ){ + return status; + } + v->dataType = node->value.dataType; + copyHdbValue(&node->value,v); + return 1; +} + diff --git a/hipadaba.h b/hipadaba.h new file mode 100644 index 00000000..8b27f4cc --- /dev/null +++ b/hipadaba.h @@ -0,0 +1,266 @@ +/** + * Hipadaba is a hierarchical database of parameters. Parameters can be of various types. + * What happens when a parameter is being set, updated or read is largely determined + * through callbacks which can be registered on parameters. This can implement permission + * checking, range checking, automatic notifications and whatever comes up. + * + * There is some subtlety here between updating and setting a parameter. The issue is + * that in instrument control there are two types of parameters: Instant program parameters + * and external parameters like motors which are dependent on some possibly slow and + * inaccurate hardware. Let us consider the latter: Setting the parameter should do all + * necessary checks on the parameter and tell the hardware where to go. Some internal code + * may be watching the hardware; that code should use Update which justs sets a new value + * and invokes callbacks which notify interested parties about the new parameter value. + * For program parameters, a callback shall be installed which calls update directly + * after setting the parameter. Thus notification callbacks shall always be connected to the + * update chain. + * + * copyright: GPL + * + * Mark Koennecke, June 2006 + */ +#ifndef HIPADABA +#define HIPADABA + +/*------- datatypes */ +#define HIPNONE -1 +#define HIPINT 0 +#define HIPFLOAT 1 +#define HIPTEXT 2 +#define HIPINTAR 3 +#define HIPFLOATAR 4 +/* -------- callback types */ +#define HCBSET 0 +#define HCBUPDATE 1 +#define HCBREAD 2 +/*===================== structure definitions ===================================*/ +typedef struct __hdbValue { + int dataType; + int arrayLength; + union __value { + long intValue; + double doubleValue; + char *text; + long *intArray; + double *floatArray; + }v; +}hdbValue; +/*------------------------------------------------------------------------------*/ +typedef struct __hipadaba { + int magic; + struct __hipadaba *mama; + struct __hipadaba *child; + struct __hipadaba *next; + struct __hdbcallback *writeCallbacks; + struct __hdbcallback *updateCallbacks; + struct __hdbcallback *readCallbacks; + char *name; + hdbValue value; + }Hdb, *pHdb; +/*-------------------------------------------------------------------------------*/ +typedef int (*hdbCallbackFunction)(void *userData, void *callData, + pHdb currentNode, hdbValue v ); +typedef void (*killUserData)(void *data); +/*-------------------------------------------------------------------------------*/ +typedef struct __hdbcallback { + void *userData; + killUserData killFunc; + hdbCallbackFunction userCallback; + int id; + int internalID; + struct __hdbcallback *next; + struct __hdbcallback *previous; + }hdbCallback, *pHdbCallback; +/*======================== Function protoypes: hdbData ========================*/ +hdbValue makeHdbValue(int datatype, int length); +/** + * wrap an integer as an hdbValue + * @param initValue the initial value of the int + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbInt(int initValue); +/** + * wrap a float as an hdbValue + * @param initValue the initial value of the float + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbFloat(double initValue); +/** + * wrap a text string as an hdbValue + * @param initText the initial value of the text. WARNING: MakeHdbText does + * not copy the data. The Hdb code only copies data on updates. Normally this + * no problem; however in complicated cenarios it is better if initText points + * to dynamically allocated memory. + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbText(char *initText); +/** + * wrap a int array as an hdbValue + * @param length The length of the int array + * @param data the initial content of the int array. WARNING: MakeHdbIntArray + * does not copy the data. The Hdb code only copies data on updates. Normally + * this no problem; however in complicated scenarios it is better if + * data points to dynamically allocated memory. + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbIntArray(int length, long *data); +/** + * wrap a float array as an hdbValue + * @param length The length of the int array + * @param data the initial content of the float array. WARNING: MakeHdbFloatArray + * does not copy the data. The Hdb code only copies data on updates. Normally + * this no problem; however in complicated scenarios it is better if + * data points to dynamically allocated memory. + * @return: A properly initialized hdbValue structure + */ +hdbValue MakeHdbFloatArray(int length, double *data); +/** + * release any dynamic memory associated with v + * @param v The hdbValue to check for dynamic memory allocation to be + * released. + */ +void ReleaseHdbValue(hdbValue *v); +/** + * copy a hipadaba value field. Takes care of memory allocation + * @param source The hdbValue to copy from + * @param target The hdbValue to copy to. + * @return 1 on success, 0 when out of memory or when type mismatch + */ +int copyHdbValue(hdbValue *source, hdbValue *target); +/** + * compares two hdbValues for identity + * @param v1 The first hdbValue + * @param v2 The second hdbValue + * @return 1 when identical, 0 else + */ +int compareHdbValue(hdbValue v1, hdbValue v2); +/** + * create a hdbValue structure with the identical properties + * as the one given as parameter. Datatypes are copied, memory is + * allocated etc. Data is copied, too + * @param source The hdbValue type to clone + * @param clone the target hdbValue structure + * @return 1 on success, 0 on when out of memory + */ +int cloneHdbValue(hdbValue *source, hdbValue *clone); +/*========================== function protoypes: Nodes =======================*/ +/** + * make a new hipadaba node + * @param name The name of the new node + * @param datatype The datatype of the new node + * @return a new node or NULL when out of memory + */ +pHdb MakeHipadabaNode(char *name, int datatype, int length); +/** + * add a child to a node + * @param parent The node to which to add the child + * @param child The node to add + */ +void AddHipadabaChild(pHdb parent, pHdb child); +/** + * delete a hipadaba node and all its children + * @parma node The node to delete + */ +void DeleteHipadabaNode(pHdb node); +/* + * checks if a Hdb node is valid + * @param node The node to check + * @return 1 when valid, 0 else + */ +int isHdbNodeValid(pHdb node); +/** + * retrieve a node + * @param root The node where to start the search for the node + * @param path The unix path string for the node relative to parent + * @return The desired node or NULL when no such node exists + */ +pHdb GetHipadabaNode(pHdb root, char *path); +/** + * given a node, return the full path name to the node + * @param node The node to get the path for + * @return The full path to the node. This is dynamically allocated memory; + * the caller is reponsible for deleting it. Can be NULL when out of memory. + */ +char *GetHipadabaPath(pHdb node); +/** + * removes a node from the parents child list. + * @node the node to remove + */ +void RemoveHdbNodeFromParent(pHdb node); +/** + * delete a callback chain + * @param root The callback chain to delete + */ +void DeleteCallbackChain(pHdbCallback root); +/*===================== function protoypes: Callbacks ========================*/ +/** + * make a new hipdaba callback + * @param func The function to invoke for this callback + * @param userData userData to be associated with this callback. Can be NULL. + * @param killFunc A function for freeing the userData. Can be NULL, then it will + * not be invoked + * @param id An ID associated with this callback + * @param internalID Another ID to be associated with this callback. ID's come in + * useful when callbacks have to be deleted in a later stage. + * @return A new suitabvly initialised callback structure or NULL when required elements + * are missing or there is nor memory. + */ +pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, + void *userData, killUserData killFunc, + int id, int internalID); +/** + * add a callback at the end of the callback chain + * @param node The node to which to append the callback + * @param type the type of the callback to append + * @param newCB The callback to append + */ +void AppendHipadabaCallback(pHdb node,int type, pHdbCallback newCB); +/** + * add a callback at the head of the callback chain + * @param node The node to which to append the callback + * @param type the type of the callback to append + * @param newCB The callback prepend + */ +void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB); +/** + * remove recursively all callbacks witch match the id + * @param root The starting node from where to start removing callbacks + * @param id The ID callbacks have to match in order to be removed. + */ +void RemoveHipadabaCallback(pHdb root, int id); +/** + * remove recursively all callbacks witch match the internal id + * @param root The starting node from where to start removing callbacks + * @param internalID The internal ID callbacks have to match in order to be removed. + */ +void InternalRemoveHipadabaCallback(pHdb root, int internalID); + +/*============== Parameter Handling ===============================*/ +/** + * Set a hipadaba parameter. This is an external set for a parameter. It may cause + * motors to start driving etc. + * @param node The node for which to set the parameter + * @param v The new value for the node + * @param callData Additonal context data to be passed to the callback functions + * @return 0 on failure, 1 on success + */ +int SetHipadabaPar(pHdb node, hdbValue v, void *callData); +/** + * Update a hipadaba parameter. This is an internal update of a parameter, during + * driving etc. + * @param node The node for which to update the parameter + * @param v The new value for the node + * @param callData Additonal context data to be passed to the callback functions + * @return 0 on failure, 1 on success + */ +int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData); +/** + * Read a hipadaba parameter + * @param node The node for which to read the parameter + * @param v The read value for the node + * @param callData Additonal context data to be passed to the callback functions + * @return 0 on failure, 1 on success + */ +int GetHipadabaPar(pHdb node, hdbValue *v, void *callData); + +#endif diff --git a/macro.c b/macro.c index c2d5134d..e98b50f1 100644 --- a/macro.c +++ b/macro.c @@ -61,11 +61,9 @@ #include #include #include -#include "SCinter.h" -#include "conman.h" -#include "macro.h" +#include #include "status.h" -#include "obdes.h" +#include "macro.h" #include "splitter.h" #include "ifile.h" #include "Dbg.h" @@ -914,8 +912,6 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, } return 1; /* not reached */ } - -#include "access.c" /*--------------------------------------------------------------------------*/ int TclPublish(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -943,17 +939,8 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp, } /* try convert last parameter to user code */ - iUser = 0; - strtolower(argv[2]); - while(aCode[iUser] != NULL) - { - if(strcmp(aCode[iUser],argv[2]) == 0) - { - break; - } - iUser++; - } - if(iUser > iCodes) + iUser = decodeSICSPriv(argv[2]); + if(iUser < 0) { sprintf(pBueffel,"ERROR: cannot identify %s as a valid user code", argv[2]); diff --git a/make_gen b/make_gen index f31d9607..5bcbf35a 100644 --- a/make_gen +++ b/make_gen @@ -8,7 +8,7 @@ COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ) SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ servlog.o sicvar.o nserver.o SICSmain.o motorlist.o\ - sicsexit.o costa.o task.o $(FORTIFYOBJ)\ + sicsexit.o costa.o task.o $(FORTIFYOBJ) access.o\ macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \ devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \ lld_blob.o strrepl.o lin2ang.o fomerge.o napi4.o napi5.o \ @@ -30,7 +30,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.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 tclmotdriv.o protocol.o \ - sinfox.o sicslist.o cone.o statistics.o + sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/motor.c b/motor.c index 08c2d105..5446556d 100644 --- a/motor.c +++ b/motor.c @@ -492,6 +492,8 @@ extern void KillPiPiezo(void *pData); pM = (pMotor)self; + MotorHalt(pM); + if(pM->name) free(pM->name); diff --git a/motorlist.c b/motorlist.c index 8dc4db9f..60c3ff77 100644 --- a/motorlist.c +++ b/motorlist.c @@ -83,7 +83,7 @@ static long MOLISetValue(void *data, SConnection *pCon, float val){ return test; } else { tuktuk.running = 1; - LLDnodeDataFrom(self,&tuktuk); + LLDnodeDataFrom(self,&tuktuk); } iRet = LLDnodePtr2Next(self); } diff --git a/ofac.c b/ofac.c index b09ae2f4..1fdbc601 100644 --- a/ofac.c +++ b/ofac.c @@ -118,6 +118,7 @@ #include "sinfox.h" #include "sicslist.h" #include "cone.h" +#include "sicshipadaba.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -245,6 +246,7 @@ AddCommand(pInter,"scriptcallback",CallbackScript,NULL,NULL); AddCommand(pInter,"help",SicsHelp,KillHelp,NULL); AddCommand(pInter,"list",SicsList,NULL,NULL); + AddCommand(pInter,"InstallHdb",InstallSICSHipadaba,NULL,NULL); /* commands to do with the executor. Only StopExe carries the DeleteFunction in order to avoid double deletion. All the diff --git a/oscillate.c b/oscillate.c index ecd844d5..09be9e24 100644 --- a/oscillate.c +++ b/oscillate.c @@ -170,7 +170,6 @@ static int StartOscillation(pOscillator self, SConnection *pCon){ static void KillOscillator(void *data){ pOscillator self = (pOscillator)data; if(self != NULL){ - StopOscillation(self); if(self->pDes != NULL){ DeleteDescriptor(self->pDes); } diff --git a/sics.h b/sics.h index b7044e5b..a2dc465f 100644 --- a/sics.h +++ b/sics.h @@ -36,6 +36,12 @@ extern pServer pServ; +/** + * Decode privilege text. Implemented in access.c + * @param the text to decode + * @return -1 if code invalid, else the privilege code + */ +int decodeSICSPriv(char *privText); #endif diff --git a/sicshipadaba.c b/sicshipadaba.c new file mode 100644 index 00000000..bae97049 --- /dev/null +++ b/sicshipadaba.c @@ -0,0 +1,1210 @@ +/** + * This is a set of helper functions for SICS to work with the hierarchical parameter + * database hipadaba. In SICS, the calldata associated with any callback will always + * be the connection object. + * + * copyright: GPL + * + * Mark Koennecke, June 2006 + */ +#include +#include +#include +#include +#include +#include + +/*== there can be only hipadaba in SICS, some globals to care for that == */ +static pHdb root = NULL; +static int scriptUpdate = -1; +static hdbUpdateTask taskData; +/*=============== common callback functions used for SICS ===========================*/ +static int SICSCheckPermissionCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + int *testPriv = NULL; + SConnection *pCon = NULL; + + pCon = (SConnection *)callData; + testPriv = (int *)userData; + + assert(pCon != NULL && testPriv != NULL); + + if(SCMatchRights(pCon,*testPriv) == 1){ + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------------------------*/ +pHdbCallback MakeCheckPermissionCallback(int priv){ + int *testPriv = NULL; + + testPriv = malloc(sizeof(int)); + if(testPriv == NULL){ + return NULL; + } + return MakeHipadabaCallback(SICSCheckPermissionCallback, testPriv,free,-1,-1); +} +/*-------------------------------------------------------------------------------------*/ +static int SICSSetUpdateCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + return UpdateHipadabaPar(node,v,callData); +} +/*-------------------------------------------------------------------------------------*/ +pHdbCallback MakeSetUpdateCallback(){ + return MakeHipadabaCallback(SICSSetUpdateCallback, NULL,NULL,-1,-1); +} +/*---------------------------------------------------------------------------------------*/ +static int SICSReadOnlyCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + SConnection *pCon = NULL; + + pCon = (SConnection *)callData; + assert(pCon != NULL); + + SCWrite(pCon,"ERROR: parameter is READ-ONLY", eError); + return 0; +} +/*-------------------------------------------------------------------------------------*/ +static pHdbCallback MakeReadOnlyCallback(){ + return MakeHipadabaCallback(SICSReadOnlyCallback, NULL,NULL,-1,-1); +} +/*-------------------------------------------------------------------------------------*/ +static int SICSDriveCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + SConnection *pCon = NULL; + pDummy dum = NULL; + + pCon = (SConnection *)callData; + dum = (pDummy)userData; + assert(pCon != NULL && dum != NULL); + return StartDevice(pServ->pExecutor,node->name,dum->pDescriptor, + userData, pCon, (float)v.v.doubleValue); +} +/*---------------------------------------------------------------------------------------*/ +pHdbCallback MakeSICSDriveCallback(void *sicsObject){ + return MakeHipadabaCallback(SICSDriveCallback, sicsObject,NULL,-1,-1); +} +/*---------------------------------------------------------------------------------------*/ +typedef struct { + SConnection *pCon; + commandContext context; +}HdbCBInfo; +/*----------------------------------------------------------------------------------------*/ +static int SICSNotifyCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + HdbCBInfo *cbInfo = NULL; + pDynString printedData = NULL; + pDynString result = NULL; + char *pPath = NULL; + + cbInfo = (HdbCBInfo *)userData; + pPath = GetHipadabaPath(node); + printedData = formatValue(v); + result = CreateDynString(128,128); + if(pPath == NULL || printedData == NULL || result == NULL){ + SCWriteInContext(cbInfo->pCon,"ERROR: out of memory formatting data" , + eEvent,cbInfo->context); + /* + * no need to interrupt something because writing data to a client does + * not work + */ + return 1; + } + DynStringCopy(result,pPath); + DynStringConcat(result," = "); + DynStringConcat(result,GetCharArray(printedData)); + SCWriteInContext(cbInfo->pCon,GetCharArray(result), + eEvent,cbInfo->context); + free(pPath); + DeleteDynString(result); + DeleteDynString(printedData); + + return 1; +} +/*-----------------------------------------------------------------------------------------*/ +pHdbCallback MakeNotifyCallback(SConnection *pCon, int id){ + HdbCBInfo *cbInfo = NULL; + + cbInfo = malloc(sizeof(HdbCBInfo)); + if(cbInfo == NULL){ + return NULL; + } + cbInfo->pCon = pCon; + cbInfo->context = SCGetContext(pCon); + return MakeHipadabaCallback(SICSNotifyCallback, cbInfo,free,id,pCon->ident); +} +/*----------------------------------------------------------------------------------------*/ +static int SICSScriptWriteCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + char *command = NULL; + SConnection *pCon = NULL; + pDynString newVal = NULL; + char error[1024]; + int status; + + command = (char *)userData; + pCon = (SConnection *)callData; + + assert(command != NULL && pCon != NULL); + + newVal = formatValue(v); + if(newVal == NULL){ + SCWrite(pCon,"ERROR: out of memory setting parameter",eError); + return 0; + } + + /** + * prepend command + */ + DynStringInsert(newVal," ", 0); + DynStringInsert(newVal,command,0); + + /* + * evaluate + */ + status = Tcl_Eval(InterpGetTcl(pServ->pSics),GetCharArray(newVal)); + if(status != TCL_OK){ + snprintf(error,1023,"ERROR: tcl returned error: %s", + Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); + SCWrite(pCon,error,eError); + status = 0; + } else { + status = 1; + } + DeleteDynString(newVal); + return status; +} +/*---------------------------------------------------------------------------------------*/ +static pHdbCallback MakeSICSWriteScriptCallback(char *script){ + return MakeHipadabaCallback(SICSScriptWriteCallback, strdup(script),free,-1,-1); +} +/*----------------------------------------------------------------------------------------*/ +static int SICSScriptReadCallback(void *userData, void *callData, pHdb node, + hdbValue v){ + char *command = NULL, *data = NULL, *equal = NULL; + SConnection *pCon = NULL; + pDynString newVal = NULL; + char error[1024]; + int status; + + command = (char *)userData; + pCon = (SConnection *)callData; + + assert(command != NULL && pCon != NULL); + + /* + * evaluate + */ + status = Tcl_Eval(InterpGetTcl(pServ->pSics),command); + if(status != TCL_OK){ + snprintf(error,1023,"ERROR: Tcl returned error: %s", + Tcl_GetStringResult(InterpGetTcl(pServ->pSics))); + SCWrite(pCon,error,eError); + status = 0; + } else { + status = 1; + } + + /* + * decode result. This handles both the case of the standard SICS answer + * something = anything + * as well as a plain value alone + */ + data = Tcl_GetStringResult(InterpGetTcl(pServ->pSics)); + if(data == NULL){ + SCWrite(pCon,"ERROR: no result returned from script",eError); + return 0; + } + equal = strchr(data,'='); + if(equal != NULL){ + data = equal + 1; + } + strcpy(error,"ERROR: "); + status = readHdbValue(&node->value,data, error+7, 1024-7); + if(status != 1){ + SCWrite(pCon,error,eError); + return 0; + } + return status; +} +/*----------------------------------------------------------------------------------------*/ +static pHdbCallback MakeSICSReadScriptCallback(char *script){ + return MakeHipadabaCallback(SICSScriptReadCallback, strdup(script),free,-1,-1); +} +/*============= Parameter Creation =======================================================*/ +pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v){ + pHdb result = NULL; + pHdbCallback pHcb = NULL; + + result = MakeHipadabaNode(name,v.dataType,v.arrayLength); + if(result == NULL){ + return NULL; + } + copyHdbValue(&v,&result->value); + + pHcb = MakeCheckPermissionCallback(priv); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + pHcb = MakeSetUpdateCallback(); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + return result; +} +/*----------------------------------------------------------------------------*/ +pHdb MakeSICSHdbDriv(char *name, int priv, void *sicsObject, int dataType){ + pHdb result = NULL; + pHdbCallback pHcb = NULL; + + result = MakeHipadabaNode(name,dataType,0); + if(result == NULL){ + return NULL; + } + + pHcb = MakeCheckPermissionCallback(priv); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + pHcb = MakeSICSDriveCallback(sicsObject); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + return result; +} +/*----------------------------------------------------------------------------*/ +pHdb MakeSICSHdbROPar(char *name, int priv, hdbValue v){ + pHdb result = NULL; + pHdbCallback pHcb = NULL; + + result = MakeHipadabaNode(name,v.dataType,v.arrayLength); + if(result == NULL){ + return NULL; + } + copyHdbValue(&v,&result->value); + + pHcb = MakeReadOnlyCallback(priv); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + return result; +} +/*---------------------------------------------------------------------------*/ +pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript, + hdbValue v){ + pHdb result = NULL; + pHdbCallback pHcb = NULL; + + result = MakeHipadabaNode(name,v.dataType,v.arrayLength); + if(result == NULL){ + return NULL; + } + copyHdbValue(&v,&result->value); + + pHcb = MakeSICSWriteScriptCallback(setScript); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBSET,pHcb); + + pHcb = MakeSICSReadScriptCallback(readScript); + if(pHcb == NULL){ + DeleteHipadabaNode(result); + return NULL; + } + AppendHipadabaCallback(result,HCBREAD,pHcb); + /** + * put into the list of nodes to check with the update task + */ + LLDnodeAppend(scriptUpdate,&result); + + return result; +} +/*--------------------------------------------------------------------------*/ +static void removeNodeFromUpdateList(pHdb node){ + pHdb current = NULL; + int status; + + status = LLDnodePtr2First(scriptUpdate); + while(status != 0){ + current = LLDnodePtr(scriptUpdate); + if(current == node){ + LLDnodeDelete(scriptUpdate); + return; + } + status = LLDnodePtr2Next(scriptUpdate); + } +} +/*-----------------------------------------------------------------------*/ +static void SICSDeleteNodeData(pHdb node){ + pHdb tmp = NULL; + + if(node == NULL){ + return; + } + DeleteCallbackChain(node->writeCallbacks); + DeleteCallbackChain(node->updateCallbacks); + DeleteCallbackChain(node->readCallbacks); + + if(node->name != NULL){ + free(node->name); + } + ReleaseHdbValue(&node->value); + node->magic = 000000; + + while(node->child != NULL){ + tmp = node->child; + node->child = node->child->next; + SICSDeleteNodeData(tmp); + } + removeNodeFromUpdateList(node); + free(node); +} +/*--------------------------------------------------------------------------*/ +void RemoveSICSPar(pHdb node){ + pHdb current = NULL, tmp = NULL; + + if(node == NULL){ + return; + } + + RemoveHdbNodeFromParent(node); + + SICSDeleteNodeData(node); +} + +/*---------------------------------------------------------------------------*/ +int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse){ + pHdb currentChild = NULL; + pHdbCallback noty = NULL; + + noty = MakeNotifyCallback(pCon,id); + if(noty == NULL){ + SCWrite(pCon,"ERROR: out of memory installing callback", eError); + return 0; + } + AppendHipadabaCallback(node, HCBUPDATE, noty); + + if(recurse == 1){ + currentChild = node->child; + while(currentChild != NULL){ + InstallSICSNotify(currentChild,pCon,id,recurse); + currentChild = currentChild->next; + } + } + return 1; +} +/*---------------------------------------------------------------------------*/ +int ProcessSICSHdbPar(pHdb root, SConnection *pCon, + char *printPrefix, int argc, char *argv[]){ + hdbValue input; + pHdb parNode = NULL; + pDynString parData = NULL; + char error[512]; + int i, status; + + assert(root != NULL && pCon != NULL); + + if(argc < 1){ + SCWrite(pCon,"ERROR: nor parameter to treat specified",eError); + return -1; + } + + parNode = GetHipadabaNode(root,argv[0]); + if(parNode == NULL){ + /* no error reporting here, upper level code might wish to continue + * processing commands after having tested for parameters. + */ + return -1; + } + + if(argc > 1) { + /* + * setting the value is attempted. + */ + memset(&input,0,sizeof(hdbValue)); + input.dataType = parNode->value.dataType; + copyHdbValue(&parNode->value,&input); + parData = CreateDynString(64,64); + if(parData == NULL){ + SCWrite(pCon,"ERROR: out of memory processing parameter",eError); + return 0; + } + for(i = 1; i < argc; i++){ + DynStringConcat(parData," "); + DynStringConcat(parData, argv[i]); + } + strcpy(error,"ERROR: "); + if(!readHdbValue(&input, GetCharArray(parData), + error+7,512-7)){ + SCWrite(pCon,error, eError); + return 0; + } + DeleteDynString(parData); + status = SetHipadabaPar(parNode,input,pCon); + ReleaseHdbValue(&input); + return status; + } else { + /* + * reading is in demand + */ + status = GetHipadabaPar(parNode,&input, pCon); + if(status != 1){ + return 0; + } + parData = formatValue(input); + if(parData == NULL){ + SCWrite(pCon,"ERROR: out of memory reading parameter data",eError); + return 0; + } + DynStringInsert(parData," =", 0); + DynStringInsert(parData,argv[0],0); + if(printPrefix != NULL){ + DynStringInsert(parData,printPrefix,0); + } + SCWrite(pCon,GetCharArray(parData),eValue); + DeleteDynString(parData); + ReleaseHdbValue(&input); + return 1; + } +} +/*---------------------------------------------------------------------------*/ +int SICSHipadabaTask(void *pData){ + pHdbUpdateTask self = NULL; + hdbValue old, newValue; + pHdb currentNode = NULL; + int status; + + self = (pHdbUpdateTask)pData; + assert(self != NULL); + + if(self->iEnd == 1){ + return 0; + } + memset(&old,0,sizeof(hdbValue)); + memset(&newValue,0,sizeof(hdbValue)); + + currentNode = (pHdb)LLDnodePtr(self->updateList); + + if(currentNode != NULL){ + old.dataType = currentNode->value.dataType; + copyHdbValue(¤tNode->value,&old); + if(GetHipadabaPar(currentNode,&newValue, self->pCon) == 1){ + if(!compareHdbValue(old,newValue)){ + UpdateHipadabaPar(currentNode,newValue,self->pCon); + } + } + ReleaseHdbValue(&old); + ReleaseHdbValue(&newValue); + + } + status = LLDnodePtr2Next(self->updateList); + if(status == 0){ + LLDnodePtr2First(self->updateList); + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +void SICSHipadabaSignal(void *pData, int iSignal, void *pSigData){ + pHdbUpdateTask self = NULL; + int *iInt; + + self = (pHdbUpdateTask)pData; + + if(iSignal == SICSINT){ + iInt = (int *)pSigData; + if(*iInt == eEndServer){ + self->iEnd = 1; + } + } +} +/*================ value helpers ============================================*/ +pDynString formatValue(hdbValue v){ + pDynString result = NULL; + int i; + char number[30]; + + result = CreateDynString(64,64); + if(result == NULL){ + return NULL; + } + switch(v.dataType){ + case HIPNONE: + break; + case HIPINT: + snprintf(number,30,"%ld", v.v.intValue); + DynStringCopy(result,number); + break; + case HIPFLOAT: + snprintf(number,30,"%12.4f", v.v.doubleValue); + DynStringCopy(result,number); + break; + case HIPTEXT: + DynStringCopy(result,v.v.text); + break; + case HIPINTAR: + for(i = 0; i < v.arrayLength; i++){ + snprintf(number,30," %ld", v.v.intArray[i]); + DynStringConcat(result,number); + } + break; + case HIPFLOATAR: + for(i = 0; i < v.arrayLength; i++){ + snprintf(number,30," %12.4f", v.v.floatArray[i]); + DynStringConcat(result,number); + } + break; + } + return result; +} +/*-------------------------------------------------------------------*/ +static char *getNextHdbNumber(char *pStart, char pNumber[80]){ + int charCount = 0; + pNumber[0] = '\0'; + + /* advance to first digit */ + while(isspace(*pStart) && *pStart != '\0'){ + pStart++; + } + if(*pStart == '\0'){ + return NULL; + } + + /* copy */ + while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){ + pNumber[charCount] = *pStart; + pStart++; + charCount++; + } + pNumber[charCount] = '\0'; + return pStart; +} + +/*---------------------------------------------------------------------------------*/ +int readHdbValue(hdbValue *v, char *data, char *error, int errlen){ + int i, status; + long lValue; + double dValue; + char number[80]; + char *pPtr = NULL; + + switch(v->dataType){ + case HIPNONE: + break; + case HIPINT: + getNextHdbNumber(data,number); + status = sscanf(number,"%ld", &v->v.intValue); + if(status != 1){ + snprintf(error,errlen,"Failed to convert %s to integer", + data); + return 0; + } + break; + case HIPFLOAT: + getNextHdbNumber(data,number); + status = sscanf(number,"%lf", &v->v.doubleValue); + if(status != 1){ + snprintf(error,errlen,"Failed to convert %s to double", + data); + return 0; + } + break; + case HIPTEXT: + if(v->v.text != NULL){ + free(v->v.text); + } + v->v.text = strdup(data); + break; + case HIPINTAR: + for(i = 0; i < v->arrayLength; i++){ + data = getNextHdbNumber(data,number); + if(data == NULL){ + snprintf(error,errlen,"Not enough values to parse, current index %d", + i); + return 0; + } + status = sscanf(number,"%ld", &lValue); + if(status != 1){ + snprintf(error,errlen,"Failed to convert %s to integer", + data); + return 0; + } + v->v.intArray[i] = lValue; + } + break; + case HIPFLOATAR: + for(i = 0; i < v->arrayLength; i++){ + data = getNextHdbNumber(data,number); + if(data == NULL){ + snprintf(error,errlen,"Not enough values to parse, current index %d", + i); + return 0; + } + status = sscanf(number,"%lf", &dValue); + if(status != 1){ + snprintf(error,errlen,"Failed to convert %s to double", + data); + return 0; + } + v->v.floatArray[i] = dValue; + } + break; + default: + assert(0); + break; + } + return 1; +} +/*================ interpreter interface ==================================*/ +pHdb GetHipadabaRoot(){ + return root; +} +/*-------------------------------------------------------------------------*/ +static char *hdbTypes[] = {"none", + "int", + "float", + "text", + "intar", + "floatar", + NULL}; +/*-------------------------------------------------------------------------*/ +static int convertHdbType(char *text){ + int type; + + type = 0; + while(hdbTypes[type] != NULL){ + if(strcmp(hdbTypes[type], text) == 0){ + break; + } + type++; + } + type--; /* we start counting at -1 */ + return type; +} +/*-------------------------------------------------------------------------*/ +static char *hdbTypeToText(int type){ + return hdbTypes[type+1]; +} +/*--------------------------------------------------------------------------*/ +static int MakeHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int type = 0, i, length = 0, priv = -1; + char *pPtr = NULL; + pHdb parent = NULL; + pHdb child = NULL; + + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc < 4) { + SCWrite(pCon,"ERROR: not enough arguments to MakeHdbNode",eError); + return 0; + } + + /* + * convert privilege + */ + priv = decodeSICSPriv(argv[2]); + /* + * convert datatype + */ + strtolower(argv[3]); + type = convertHdbType(argv[3]); + if(type >= 5){ + SCWrite(pCon, + "ERROR: invalid type requested: none, int, float, text, intar, floatar supported", + eError); + return 0; + } + if(type > 2){ + if( argc < 5){ + SCWrite(pCon,"ERROR: array length missing for array data type", + eError); + return 0; + } else { + length = atoi(argv[3]); + } + } + + /* split off last path element */ + pPtr = strrchr(argv[1],'/'); + if(pPtr == NULL){ + SCWrite(pCon,"ERROR: invalid path specification", + eError); + return 0; + } + *pPtr = '\0'; + pPtr++; + if(strlen(pPtr) < 1) { + parent = root; + } else { + parent = GetHipadabaNode(root,argv[1]); + } + if(parent == NULL){ + SCWrite(pCon,"ERROR: parent for new node does not exist",eError); + return 0; + } + if(type != HIPNONE){ + child = MakeSICSHdbPar(pPtr, priv, makeHdbValue(type,length)); + } else { + child = MakeHipadabaNode(pPtr,type,length); + } + if(child == NULL){ + SCWrite(pCon,"ERROR: out of memory creating node",eError); + return 0; + } + + AddHipadabaChild(parent,child); + SCSendOK(pCon); + return 1; +} +/*--------------------------------------------------------------------------*/ +static int MakeHdbScriptNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int type = 0, i, length = 0; + char *pPtr = NULL; + pHdb parent = NULL; + pHdb child = NULL; + pHdb current = NULL; + + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc < 5) { + SCWrite(pCon,"ERROR: not enough arguments to MakeHdbNode",eError); + return 0; + } + + /* + * convert datatype + */ + strtolower(argv[4]); + type = convertHdbType(argv[4]); + if(type >= 5){ + SCWrite(pCon, + "ERROR: invalid type requested: none, int, float, text, intar, floatar supported", + eError); + return 0; + } + if(type > 2){ + if( argc < 6){ + SCWrite(pCon,"ERROR: array length missing for array data type", + eError); + return 0; + } else { + length = atoi(argv[5]); + } + } + + /* split off last path element */ + pPtr = strrchr(argv[1],'/'); + if(pPtr == NULL){ + SCWrite(pCon,"ERROR: invalid path specification", + eError); + return 0; + } + *pPtr = '\0'; + pPtr++; + if(strlen(pPtr) < 1) { + parent = root; + } else { + parent = GetHipadabaNode(root,argv[1]); + } + if(parent == NULL){ + SCWrite(pCon,"ERROR: parent for new node does not exist",eError); + return 0; + } + child = MakeSICSScriptPar(pPtr, argv[3], argv[2], + makeHdbValue(type,length)); + if(child == NULL){ + SCWrite(pCon,"ERROR: out of memory creating node",eError); + return 0; + } + + AddHipadabaChild(parent,child); + SCSendOK(pCon); + return 1; +} + +/*-----------------------------------------------------------------------------------------*/ +static int DeleteHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb killNode = NULL; + + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc < 2){ + SCWrite(pCon,"ERROR: need path to node to delete",eError); + return 0; + } + killNode = GetHipadabaNode(root,argv[1]); + if(killNode == NULL){ + SCWrite(pCon,"ERROR: node to delete not found",eError); + return 0; + } + RemoveSICSPar(killNode); + SCSendOK(pCon); + return 1; +} +/*------------------------------------------------------------------------------------------*/ +static int SetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb targetNode = NULL; + hdbValue newValue; + pDynString parData = NULL; + char error[512]; + int i, status; + + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + + if(argc < 3) { + SCWrite(pCon,"ERROR: insufficient number of arguments to SetHdbNode", + eError); + return 0; + } + + targetNode = GetHipadabaNode(root,argv[1]); + if(targetNode == NULL){ + SCWrite(pCon,"ERROR: node to set not found!", + eError); + return 0; + } + if(!cloneHdbValue(&targetNode->value,&newValue)){ + SCWrite(pCon,"ERROR: out of mmeory cloning node", + eError); + return 0; + } + parData = CreateDynString(64,64); + if(parData == NULL){ + SCWrite(pCon,"ERROR: out of memory reading parameter",eError); + return 0; + } + for(i = 2; i < argc; i++){ + DynStringConcat(parData," "); + DynStringConcat(parData, argv[i]); + } + strcpy(error,"ERROR: "); + if(!readHdbValue(&newValue, GetCharArray(parData), + error+7,512-7)){ + SCWrite(pCon,error, eError); + return 0; + } + DeleteDynString(parData); + status = SetHipadabaPar(targetNode,newValue,pCon); + ReleaseHdbValue(&newValue); + if(status == 1){ + SCSendOK(pCon); + } + return status; +} +/*-----------------------------------------------------------------------------*/ +static int GetHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb targetNode = NULL; + hdbValue newValue; + pDynString parData = NULL; + char error[512], oriPath[512];; + int i, status; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need path to node to print",eError); + return 0; + } + + strncpy(oriPath,argv[1], 511); + targetNode = GetHipadabaNode(root,argv[1]); + if(targetNode == NULL){ + SCWrite(pCon,"ERROR: node to read not found!", + eError); + return 0; + } + memset(&newValue,0,sizeof(hdbValue)); + GetHipadabaPar(targetNode, &newValue, pCon); + parData = formatValue(newValue); + if(parData == NULL){ + SCWrite(pCon,"ERROR: out of memory formatting data",eError); + return 0; + } + DynStringInsert(parData," =",0); + DynStringInsert(parData,oriPath,0); + SCWrite(pCon,GetCharArray(parData),eValue); + DeleteDynString(parData); + ReleaseHdbValue(&newValue); + + return 1; +} +/*---------------------------------------------------------------------------*/ +static pDynString formatPlainList(pHdb node){ + pHdb current; + pDynString result = NULL; + + result = CreateDynString(128,128); + if(result == NULL){ + return NULL; + } + + current = node->child; + while(current != NULL){ + DynStringConcat(result,current->name); + DynStringConcat(result,"\n"); + current = current->next; + } + return result; +} +/*---------------------------------------------------------------------------*/ +static pDynString formatListWithVal(pHdb node){ + pHdb current; + pDynString result = NULL; + pDynString data = NULL; + + result = CreateDynString(128,128); + if(result == NULL){ + return NULL; + } + + current = node->child; + while(current != NULL){ + DynStringConcat(result,current->name); + data = formatValue(current->value); + if(data != NULL){ + DynStringConcat(result," = "); + DynStringConcat(result,GetCharArray(data)); + DeleteDynString(data); + } + DynStringConcat(result,"\n"); + current = current->next; + } + return result; +} +/*--------------------------------------------------------------------------*/ +static int countChildren(pHdb node){ + pHdb current = NULL; + int count = 0; + + current = node->child; + while(current != NULL){ + count++; + current = current->next; + } + return count; +} +/*---------------------------------------------------------------------------*/ +static pDynString formatClientList(pHdb node){ + pHdb current; + pDynString result = NULL; + int length; + int i; + char number[50]; + + result = CreateDynString(128,128); + if(result == NULL){ + return NULL; + } + + current = node->child; + while(current != NULL){ + DynStringConcat(result,current->name); + DynStringConcat(result,","); + DynStringConcat(result,hdbTypeToText(current->value.dataType)); + DynStringConcat(result,","); + snprintf(number,50,"%d",countChildren(current)); + DynStringConcat(result,number); + DynStringConcat(result,","); + if(current->value.dataType >= 3){ + length = current->value.arrayLength; + } else { + length = 1; + } + snprintf(number,50,"%d",length); + DynStringConcat(result,number); + DynStringConcat(result,","); + switch(current->value.dataType){ + case HIPNONE: + break; + case HIPINT: + snprintf(number,50,"%ld",current->value.v.intValue); + DynStringConcat(result,number); + break; + case HIPFLOAT: + snprintf(number,50,"%lf",current->value.v.doubleValue); + DynStringConcat(result,number); + break; + case HIPTEXT: + DynStringConcat(result,current->value.v.text); + break; + case HIPINTAR: + for(i = 0; i < length; i++){ + snprintf(number,50,"%ld",current->value.v.intArray[i]); + DynStringConcat(result,number); + if(i > length -1){ + DynStringConcat(result,","); + } + } + break; + case HIPFLOATAR: + for(i = 0; i < length; i++){ + snprintf(number,50,"%lf",current->value.v.floatArray[i]); + DynStringConcat(result,number); + if(i > length -1){ + DynStringConcat(result,","); + } + } + break; + } + DynStringConcat(result,"\n"); + current = current->next; + } + return result; +} +/*---------------------------------------------------------------------------*/ +static int ListHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb node = NULL; + int pathArg = 1; + pDynString listData = NULL; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need path to node to print",eError); + return 0; + } + + if(strchr(argv[1],'-') != NULL){ + pathArg = 2; + if(argc < 3){ + SCWrite(pCon,"ERROR: need path to node to print",eError); + return 0; + } + } + + node = GetHipadabaNode(root,argv[pathArg]); + if(node == NULL){ + SCWrite(pCon,"ERROR: node to list not found!", + eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"-val") == 0){ + listData = formatListWithVal(node); + } else if(strcmp(argv[1],"-cli") == 0){ + listData = formatClientList(node); + } else { + listData = formatPlainList(node); + } + if(listData == NULL){ + SCWrite(pCon,"ERROR: failed to format list", + eError); + return 0; + } + SCWrite(pCon,GetCharArray(listData),eValue); + DeleteDynString(listData); + return 1; +} +/*---------------------------------------------------------------------------*/ +static int AutoNotifyHdbNode(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHdb node = NULL; + int id, status; + + if(argc < 3) { + SCWrite(pCon,"ERROR: need path and id in order to add notify", + eError); + return 0; + } + + node = GetHipadabaNode(root,argv[1]); + if(node == NULL){ + SCWrite(pCon,"ERROR: node to add notify found!", + eError); + return 0; + } + + id = atoi(argv[2]); + + status = InstallSICSNotify(node, pCon, id, 1); + if(status == 1){ + SCSendOK(pCon); + } + + return status; +} +/*---------------------------------------------------------------------------*/ +static int RemoveHdbCallback(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int id; + + if(argc < 2) { + SCWrite(pCon,"ERROR: need callback id to remove", + eError); + return 0; + } + id = atoi(argv[1]); + RemoveHipadabaCallback(root,id); + SCSendOK(pCon); + return 1; +} +/*---------------------------------------------------------------------------*/ +void killSICSHipadaba(void *pData){ + DeleteHipadabaNode(root); + root = NULL; + /** + * children have already been removed when killing the + * main tree + */ + LLDdelete(scriptUpdate); + SCDeleteConnection(taskData.pCon); +} +/*---------------------------------------------------------------------------*/ +int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + + root = MakeHipadabaNode("/",HIPNONE,0); + scriptUpdate = LLDcreate(sizeof(void *)); + taskData.updateList = scriptUpdate; + taskData.iEnd = 0; + taskData.pCon = SCCreateDummyConnection(pSics); + if(taskData.pCon == NULL){ + SCWrite(pCon,"ERROR: out of memory creating Hipadaba",eError); + return 0; + } + TaskRegister(pServ->pTasker, + SICSHipadabaTask, + SICSHipadabaSignal, + killSICSHipadaba, + &taskData,1); + + AddCommand(pSics,"hmake", MakeHdbNode, killSICSHipadaba, NULL); + AddCommand(pSics,"hmakescript", MakeHdbScriptNode, NULL, NULL); + AddCommand(pSics,"hdel", DeleteHdbNode, NULL, NULL); + AddCommand(pSics,"hset", SetHdbNode, NULL, NULL); + AddCommand(pSics,"hget", GetHdbNode, NULL, NULL); + AddCommand(pSics,"hlist", ListHdbNode, NULL, NULL); + AddCommand(pSics,"hnotify", AutoNotifyHdbNode, NULL, NULL); + AddCommand(pSics,"hdelcb", RemoveHdbCallback, NULL, NULL); + + return 1; +} diff --git a/sicshipadaba.h b/sicshipadaba.h new file mode 100644 index 00000000..2014af40 --- /dev/null +++ b/sicshipadaba.h @@ -0,0 +1,175 @@ +/** + * This is a set of helper functions for SICS to work with the hierarchical parameter + * database hipadaba. In SICS, the calldata associated with any callback will always + * be the connection object. + * + * copyright: GPL + * + * Mark Koennecke, June 2006 + */ +#ifndef SICSHIPADABA_H_ +#define SICSHIPADABA_H_ +#include +#include +#include +/*======================== data structure for automatic parameter update =======*/ +typedef struct { + SConnection *pCon; + int updateList; + int iEnd; +}hdbUpdateTask, *pHdbUpdateTask; +/*======================== common callbacks =====================================*/ +/** + * make a callback which checks permissions. To be used on write + * @param priv The privilege to check against + * @return a suitably initialized callback structure for + * checking permissions. + */ +pHdbCallback MakeCheckPermissionCallback(int priv); +/** + * make a callback which directly updates a + * paramter after setting. Usefule for program parameters. + * @return a suitably initialized callback structure setting + * program parameters + */ +pHdbCallback MakeSetUpdateCallback(); +/** + * make a callback which starts a parameter driving. + * @param sicsObject The SICS object to drive. + * @return a suitably initialized callback structure for + * starting a parameter driving. + */ +pHdbCallback MakeSICSDriveCallback(void *sicsObject); +/** + * make a callback which enables automatically + * notification of pCon on parameter updates. + * @param pCon The connection to notify. The notification + * is issued in the context of this connection. + * @param id An integer id which can later on be used to remove the + * callback. + * @return a suitably initialized callback structure for + * automatic notification. + */ +pHdbCallback MakeNotifyCallback(SConnection *pCon, int id); +/*======================== parameter creation ===================================*/ +/** + * make a simple SICS hdb parameter. Setting it will call update immediately. Use + * this for program parameters. + * @param name The name of the parameter + * @param priv The privilege required to change that parameter + * @param v The initial value and datatype of this parameter + * @return A new suitably configured Hdb parameter or NULL when out of memory. + */ +pHdb MakeSICSHdbPar(char *name, int priv, hdbValue v); +/** + * make a SICS hdb drivable parameter. Setting it will start the motor, + * virtual motor or environment parameter. This will call StartDevice + * eventually + * @param name The name of the parameter + * @param priv The privilege required to change that parameter + * @param sicsObject The object corresponding to this parameter. + * @param dataType The datatype of this variable + * @return A new suitably configured Hdb parameter or NULL when out of memory. + */ + +pHdb MakeSICSHdbDriv(char *name, int priv,void *sicsObject, int datatype); +/** + * makes a SICS Hdb read only parameter. Setting such a parameter causes an error. + * @param name The name of the parameter + * @param v The initial value and datatype of this parameter + * @return A new suitably configured Hdb parameter or NULL when out of memory. + */ +pHdb MakeSICSROPar(char *name, hdbValue v); +/** + * make a SICS scriptable parameter. I.e. when this parameter is set or read, + * appropriate scripts are invoked. + * @param name The name of the parameter + * @param setScript The script to call when this parameter is being set + * @param readScript The script to call when this parameter is being read. + * @param v The initial value and datatype of this parameter + * @return A new suitably configured Hdb parameter or NULL when out of memory. + */ +pHdb MakeSICSScriptPar(char *name, char *setScript, char *readScript, hdbValue v); +/** + * remove a SICS paramameter node and its children. In contrast to the + * normal DeletHipadabaNode, this function also takes care of + * clearing scipted nodes out of the update tasks watch list. + * @param node The node to delete + */ +void RemoveSICSPar(pHdb node); +/*============= common SICS Interactions ===================================*/ +/** + * Install a SICS automatic notification callback on the node. This is + * a default callback using the current connection with its current + * context for notification. + * @param node The parameter on which to install the callback + * @param pCon The connection to which this callback is linked. + * @param id An int associated with this notification callback. A + * precaution for later removal. + * @param recurse a flag 0 or 1 which determines if callbacks are + * installed to all nodes recursively. + * @return 1 on success, 0 when out of memory. + */ +int InstallSICSNotify(pHdb node, SConnection *pCon, int id, int recurse); +/** + * handles the common task of checking for, and processing a SICS parameter. + * @param root The node at which to search for parameters + * @param pCon The connection in whichs context the parameter is processed. + * @param printPrefix A prefix to prepend before printing this parameter. + * Will be ignored if NULL. + * @param argc number of arguments to process. + * @param argv The arguments to process. argv[0] should be the parameter + * name. + * @return -1 when argv[0] is no parameter, 0 on failure, 1 on success. + */ +int ProcessSICSHdbPar(pHdb root, SConnection *pCon, char *printPrefix, + int argc, char *argv[]); +/** + * A SICS task which scans a Hipadaba and reads and updates all parameters, + * one per invocation. TODO: how to distinguish between automatic pars which + * do not need this and pars which need this? Idea 1: make a root point at an + * artificial tree of parameters which need to be checked like this. + * @param pData The root to start scanning at. + * @return 0 when ends, 1 else + */ +int SICSHipadabaTask(void *pData); +void SICSHipadabaSignal(void *pData, int iSignal, void *pSigData); +/*================== value helpers ========================================*/ +/** + * format a Hdb Value into a string using SICS defaults. + * @param v The Hdb value to format + * @return a dynamic string holding the formatted data. NULL when + * out of memory + */ +pDynString formatValue(hdbValue v); +/** + * read values for a Hdb value from a string. + * @param v The hdbValue to read data into. Datatype and arraylength must + * already have been initialised before this call in order to allow for + * checks. Arrays should also have been allocated in the right size. + * @param data The string to parse and convert. + * @param error A string to copy failure reasons too + * @param errlen The length of the error string + * @return 0 on failure, 1 on success + */ +int readHdbValue(hdbValue *v, char *data, char *error, int errlen); +/*================= SICS Interpreter Interface ===========================*/ +/** + * InstallHipadaba installs the Hipadaba commands into the SICS interpreter. + * The actual command implementation is in sicshipadaba.c. + * @param pCon The connection object + * @param pSics The SICS interpreter + * @param pData The object data structure + * @param argc The number of arguments + * @param argv[] The text arguments + * @return 0 on filaure, 1 on success + */ +int InstallSICSHipadaba(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +/** + * get the root of the SICS Hipadaba tree + * @return The root node of the hipdaba + */ +pHdb GetHipadabaRoot(); + +#endif /*SICSHIPADABA_H_*/ diff --git a/sicvar.c b/sicvar.c index 4d351a38..5b8af4c9 100644 --- a/sicvar.c +++ b/sicvar.c @@ -136,14 +136,7 @@ "float", NULL }; - static char *cAccess[] = { - "internal", - "mugger", - "user", - "spy", - NULL - }; - + int VarFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { @@ -196,30 +189,8 @@ } /* argv[3] must be the access code, check that now */ - i = 0; - while(cAccess[i] != NULL) - { - if(strcmp(argv[3],cAccess[i]) == 0) - { - break; - } - i++; - } - switch(i) - { - case 0: - iCode = usInternal; - break; - case 1: - iCode = usMugger; - break; - case 2: - iCode = usUser; - break; - case 3: - iCode = usSpy; - break; - default: + i = decodeSICSPriv(argv[3]); + if(i < 0){ sprintf(pBueffel," %s access code %s not recognized", argv[1], argv[3]); SCWrite(pCon,pBueffel,eError); @@ -227,7 +198,7 @@ } /* now we can actually install the variable */ - pRes = VarCreate(iCode,eType,argv[1]); + pRes = VarCreate(i,eType,argv[1]); if(!pRes) { sprintf(pBueffel,"Memory Error creating variable %s", argv[1]); diff --git a/tasdrive.c b/tasdrive.c index 9fd4e8bf..b0211af6 100644 --- a/tasdrive.c +++ b/tasdrive.c @@ -192,22 +192,24 @@ static int TASHalt(void *pData){ } /*--------------------------------------------------------------------------*/ -static void writeMotPos(SConnection *pCon, char *name, +static void writeMotPos(SConnection *pCon, int silent, char *name, float val, float target){ char pBueffel[132]; - snprintf(pBueffel,131,"Driving %5s from %8.3f to %8.3f", - name, val, target); - SCWrite(pCon,pBueffel,eWarning); - + if(silent != 1) { + snprintf(pBueffel,131,"Driving %5s from %8.3f to %8.3f", + name, val, target); + SCWrite(pCon,pBueffel,eWarning); + } } /*---------------------------------------------------------------------------*/ static int startMotors(ptasMot self, tasAngles angles, SConnection *pCon, int driveQ, int driveTilt){ float val; double curve; - int status; + int status, silent; + silent = self->math->silent; /* monochromator */ @@ -220,7 +222,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"a1",val, angles.monochromator_two_theta/2.); + writeMotPos(pCon,silent,"a1",val, angles.monochromator_two_theta/2.); val = self->math->motors[A2]->pDrivInt->GetValue(self->math->motors[A2],pCon); if(ABS(val - angles.monochromator_two_theta) > MOTPREC){ @@ -231,7 +233,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"a2",val, angles.monochromator_two_theta); + writeMotPos(pCon,silent,"a2",val, angles.monochromator_two_theta); if(self->math->motors[MCV] != NULL){ curve = maCalcVerticalCurvature(self->math->machine.monochromator, @@ -245,7 +247,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"mcv",val, curve); + writeMotPos(pCon,silent,"mcv",val, curve); } if(self->math->motors[MCH] != NULL){ @@ -260,7 +262,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"mch",val, curve); + writeMotPos(pCon,silent,"mch",val, curve); } /* @@ -277,7 +279,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,self->math->motors[A5]->name, + writeMotPos(pCon,silent,self->math->motors[A5]->name, val, angles.analyzer_two_theta/2.); val = self->math->motors[A6]->pDrivInt->GetValue(self->math->motors[A6],pCon); @@ -289,7 +291,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"a6",val, angles.analyzer_two_theta); + writeMotPos(pCon,silent,"a6",val, angles.analyzer_two_theta); if(self->math->motors[ACV] != NULL){ curve = maCalcVerticalCurvature(self->math->machine.analyzer, @@ -303,7 +305,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"acv",val, curve); + writeMotPos(pCon,silent,"acv",val, curve); } if(self->math->motors[ACH] != NULL){ curve = maCalcHorizontalCurvature(self->math->machine.analyzer, @@ -319,7 +321,7 @@ static int startMotors(ptasMot self, tasAngles angles, } } } - writeMotPos(pCon,"ach",val, curve); + writeMotPos(pCon,silent,"ach",val, curve); } if(driveQ == 0){ @@ -338,7 +340,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"a3",val, angles.a3); + writeMotPos(pCon,silent,"a3",val, angles.a3); val = self->math->motors[A4]->pDrivInt->GetValue(self->math->motors[A4],pCon); if(ABS(val - angles.sample_two_theta) > MOTPREC){ @@ -349,7 +351,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"a4",val, angles.sample_two_theta); + writeMotPos(pCon,silent,"a4",val, angles.sample_two_theta); if(driveTilt == 1){ val = self->math->motors[SGL]->pDrivInt->GetValue(self->math->motors[SGL],pCon); @@ -361,7 +363,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"sgl",val, angles.sgl); + writeMotPos(pCon,silent,"sgl",val, angles.sgl); val = self->math->motors[SGU]->pDrivInt->GetValue(self->math->motors[SGU],pCon); if(ABS(val - angles.sgu) > MOTPREC){ @@ -372,7 +374,7 @@ static int startMotors(ptasMot self, tasAngles angles, return status; } } - writeMotPos(pCon,"sgu",val, angles.sgu); + writeMotPos(pCon,silent,"sgu",val, angles.sgu); } self->math->mustDrive = 0; return OKOK; diff --git a/tasscanub.c b/tasscanub.c index aefdf783..8b291b19 100644 --- a/tasscanub.c +++ b/tasscanub.c @@ -692,6 +692,7 @@ static int TASUBScanDrive(pScanData self, int iPoint) int iTAS = 0; pMotor pMot; + pTAS->ub->silent = 1; /* loop through all the scan variables */ @@ -721,6 +722,7 @@ static int TASUBScanDrive(pScanData self, int iPoint) else { status = Wait4Success(GetExecutor()); + pTAS->ub->silent = 0; } return 1; } @@ -829,6 +831,8 @@ static int TASUBScanCount(pScanData self, int iPoint) /* loop over all scan variables */ status = 1; + + pTAS->ub->silent = 0; for(i = 0; i < self->iScanVar; i++) { DynarGet(self->pScanVar,i,&pDings); diff --git a/tasub.c b/tasub.c index a1eb6daf..0db04c9f 100644 --- a/tasub.c +++ b/tasub.c @@ -1514,6 +1514,25 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData, SCWrite(pCon,pBueffel,eValue); return 1; } + } else if(strcmp(argv[1],"silent") == 0){ + if(argc > 2){ + strtolower(argv[2]); + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&newSS); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to number",eError); + return 0; + } + self->silent = newSS; + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,131,"%s.silent = %d",argv[0],self->silent); + SCWrite(pCon,pBueffel,eValue); + return 1; + } } else { snprintf(pBueffel,131,"ERROR: subcommand %s to %s not defined",argv[1], argv[0]); diff --git a/tasub.h b/tasub.h index ac97a2de..1d22c3ab 100644 --- a/tasub.h +++ b/tasub.h @@ -30,6 +30,7 @@ pMotor motors[12]; tasReflection r1, r2; int ubValid; + int silent; }tasUB, *ptasUB; diff --git a/tasub.w b/tasub.w index afd15d07..a74ba7f1 100644 --- a/tasub.w +++ b/tasub.w @@ -32,6 +32,7 @@ A data structure: pMotor motors[12]; tasReflection r1, r2; int ubValid; + int silent; }tasUB, *ptasUB; @} \begin{description} @@ -55,6 +56,9 @@ A data structure: runtime. \item[r1,r2] The indexs of the reflections used for calculating the orientation matrix. +\item[ubValid] a flag denoting if the UB is valid. +\item[silent] A flga which when 1 suppresses the printing of motor positions + when driving. Usefule for scans. \end{description} For the virtual motors, there must be a data structure, too: