/** @file * 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 * * Added treeChange callback, Mark Koennecke, November 2006 * * Added support for properties, Mark Koennecke, January 2007 * * Refactored callback handling, Markus Zolliker, Mark Koennecke, March 2008 * * Added property chnage events. Mark Koennecke, February 2015 */ #ifndef HIPADABA #define HIPADABA #include /*------- datatypes */ #define HIPNONE -1 #define HIPINT 0 #define HIPFLOAT 1 #define HIPTEXT 2 #define HIPINTAR 3 #define HIPFLOATAR 4 #define HIPINTVARAR 5 #define HIPFLOATVARAR 6 #define HIPOBJ 7 #define HIPFUNC 8 /*--------- error codes */ #define HDBTYPEMISMATCH -7701 #define HDBLENGTHMISMATCH -7702 /*===================== structure definitions ===================================*/ typedef void voidFunc(void); typedef struct __hdbValue { int dataType; int arrayLength; int doNotFree; union __value { int intValue; double doubleValue; char *text; int *intArray; double *floatArray; voidFunc *func; void *obj; } v; } hdbValue; /*------------------------------------------------------------------------------*/ typedef struct __hipadaba { int magic; struct __hipadaba *mama; struct __hipadaba *child; struct __hipadaba *next; struct __hdbcallback *callBackChain; char *name; char *path; hdbValue value; int iprotected; pStringDict properties; } Hdb, *pHdb; /*-------------- return values for callback functions -------------------------*/ typedef enum { hdbContinue, hdbAbort, hdbKill } hdbCallbackReturn; /*======================== Messages ===========================================*/ typedef struct __hdbMessage { char *type; } hdbMessage, *pHdbMessage; /*-----------------------------------------------------------------------------*/ typedef struct { char *type; hdbValue *v; void *callData; } hdbDataMessage, *pHdbDataMessage; /*-------------------------------------------------------------------------------*/ typedef struct { char *type; void *callData; } hdbTreeChangeMessage, *pHdbTreeChangeMessage; /*-------------------------------------------------------------------------------*/ typedef struct { char *type; void *testPtr; void *result; } hdbDataSearch, *pHdbDataSearch; /*-------------------------------------------------------------------------------*/ typedef struct { char *type; char *key; char *value; } hdbPropertyChange, *pHdbPropertyChange; /*-------------------------------------------------------------------------------*/ typedef hdbCallbackReturn(*hdbCallbackFunction) (pHdb currentNode, void *userData, pHdbMessage message); typedef void (*killUserData) (void *data); /*-------------------------------------------------------------------------------*/ typedef struct __hdbcallback { void *userData; killUserData killFunc; hdbCallbackFunction userCallback; int killFlag; struct __hdbcallback *next; struct __hdbcallback *previous; } hdbCallback, *pHdbCallback; /*============= Message Test Functions ==========================================*/ /** * Test a message if it is a set message * @param toTest The message to test. * @return NULL if the message is no set message or a message pointer if it is. */ pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest); /** * Test a message if it is a set message * @param toTest The message to test. * @return NULL if the message is no set message or a message pointer if it is. */ pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest); /** * Test a message if it is a update message * @param toTest The message to test. * @return NULL if the message is no update message or a message pointer if * it is. */ pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest); /** * Test a message if it is a tree change message * @param toTest The message to test. * @return NULL if the message is no tree change message or a message * pointer if it is. */ pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest); /** * Test a message if it is a data search message * @param toTest The message to test. * @return NULL if the message is no data search message or a message * pointer if it is. */ pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest); /** * Test a message if it is a kill node message * @param toTest The message to test. * @return NULL if the message is no kill node message or a message * pointer if it is. */ pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest); /** * Test a message if it is a property change message * @param toTest The message to test. * @return NULL if the message is no property chnage message or a message * pointer if it is. */ pHdbPropertyChange GetPropertyChangeMessage(pHdbMessage toTest); /*======================== Function protoypes: hdbData ========================*/ /** * make a hdbValue with the given datatype and length * Do not initialise * @param datatype The datatype of the hdbValue * @param length The array length of the hdbValue * @return a suitably defined hdbValue */ 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, int *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); /** * wrap a function as an hdbValue * @param func the function * @return: A properly initialized hdbValue structure */ hdbValue MakeHdbFunc(voidFunc * func); /** * wrap an object as an hdbValue * @param obj the object * @return: A properly initialized hdbValue structure */ hdbValue MakeHdbObj(void *obj); /** * 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); /** * get the length of the hdbValue in bytes. * @param v The hdbValue to calculate the length for * @return the number of data bytes */ int getHdbValueLength(hdbValue v); /** * calculate a checksum of the data in val * @param val The hdbValue to calcululate the checksum for * @return The checksum */ unsigned short getHdbCheckSum(hdbValue *val); /*========================== function protoypes: Nodes =======================*/ /** * make a new hipadaba node * @param name The name of the new node * @param datatype The datatype of the new node * @param length the array length * @return a new node or NULL when out of memory */ pHdb MakeHipadabaNode(char *name, int datatype, int length); /** * add a child to a node at the end of the child list. * @param parent The node to which to add the child * @param child The node to add * @param callData User data for the tree chnage callback. Can be NULL. */ void AddHipadabaChild(pHdb parent, pHdb child, void *callData); /** * Delete only the node data, without invoking any callbacks * @param node The node to delete. */ void DeleteNodeData(pHdb node); /** * Send a treechange message for node. * @param node The node whose child list has changed * @param calldata The connection or calldata associated with this operation. */ void SendTreeChangeMessage(pHdb node, void *callData); /** * delete a hipadaba node and all its children. Then invoke the tree * change callback to notify listeners. * @param node The node to delete * @param callData User data for the tree change callback */ void DeleteHipadabaNode(pHdb node, void *callData); /* * 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. * @param node the node to remove * @param callData User data for the tree change callback */ void RemoveHdbNodeFromParent(pHdb node, void *callData); /** * count the numbers of children in thie Hdb node * @param node The node to count children for * @return The number of children */ int CountHdbChildren(pHdb node); /*===================== 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 * @return A new suitabaly initialised callback structure or NULL when required elements * are missing or there is nor memory. */ pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func, void *userData, killUserData killFunc); /** * add a callback at the end of the callback chain * @param node The node to which to append the callback * @param newCB The callback to append */ void AppendHipadabaCallback(pHdb node, pHdbCallback newCB); /** * add a callback at the head of the callback chain * @param node The node to which to append the callback * @param newCB The callback prepend */ void PrependHipadabaCallback(pHdb node, pHdbCallback newCB); /** * find the callback data * @param node the node from where callbacks have to be searched * @param userPtr A pointer to some user data which the callback * uses to determine if it is the right one. * @return the found callback user data or NULL on failure */ void *FindHdbCallbackData(pHdb node, void *userPtr); /** * invoke a callback chain. * @param node The node reponsible for this callback chain * @param message the message to send * @return 1 on success, 0 on failure */ int InvokeCallbackChain(pHdb node, pHdbMessage message); /** * Deletes the callback chain of a node. This is internal, normal users * should not use this function. Or you create a mess! * @param node The node */ void DeleteCallbackChain(pHdb node); /** * apply message to the node and all its children * @param node The node where to start recursing * @param message The message to send */ void RecurseCallbackChains(pHdb node, pHdbMessage message); /*============== 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); /** * notify any update listeners that this node has been internally modifed. * @param node The node modified * @param callData Addtional data for the callback * @return 1 on success, 0 on failure */ int NotifyHipadabaPar(pHdb node, 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); /*================================ Property Interface ==============================================*/ /** * Set or delete a property * @param node The node to set the property for * @param key The key for the property * @param value The value of the property. If this is NULL, the * property is deleted. */ void SetHdbProperty(pHdb node, char *key, char *value); /** * get the value of a property * @param node The node to get the property from * @param key The properties key * @param value The area to which to copy the property * @param len The length of value * @return 0 on failure, 1 on success */ /** * Check if a property exists * @param node The node to get the property from * @param key The properties key * @return 1 or 0 for true or false */ int HasHdbProperty(pHdb node, char *key); int GetHdbProperty(pHdb node, char *key, char *value, int len); /** * get the value of a property * @param node The node to get the property from * @param key The properties key * @return the property or NULL on failure. Warning: the string is * only valid as long as the property has not changed */ char *GetHdbProp(pHdb node, char *key); /** * initialize a property scan on this node * @param node The node for which to scan properties */ void InitHdbPropertySearch(pHdb node); /** * get the next property in a search * @param node The node for which to search properties * @param value An area where to copy the value of the property * @param len The length of value * @return The key of the property or NULL when the property list is exhausted */ const char *GetNextHdbProperty(pHdb node, char *value, int len); #endif