/*--------------------------------------------------------------------------- pardef.h my way to define and handle objects and its parameters Markus Zolliker, March 2005 ---------------------------------------------------------------------------- */ #ifndef PARDEF_H #define PARDEF_H #include "sics.h" #include "logger.h" #include "hipadaba.h" int ParPrintf(void *object, int iOut, const char *fmt, ...); typedef enum { PAR_ALWAYS_READY, PAR_NOT_READY, PAR_NOW_READY } ReadyState; typedef struct ParInfo { struct ParInfo *next; char *name; Logger *log; int saveIt; /* bool */ int saveLog; /* bool */ ReadyState state; /* enum ReadyState */ int sugarStatus; /* =1: sugar object made */ pHdb node; /* node for update */ } ParInfo; #define PAR_LEVELS 8 #define PAR_NAN -999999. #define PAR_LNAN -999999 typedef void (*ParDef) (void *); typedef struct ParClass { char *name; size_t size; int level; struct ParClass *base[PAR_LEVELS]; } ParClass; typedef struct ParData { pObjectDescriptor desc; /* SICS object descriptor */ ParClass *class; /* class descriptor */ ParDef pardef; char *creationCmd; /* the command to create this object */ char *name; /* object name */ time_t logTime; /* last logging time */ int logPending; int period; /* logging interval */ ParInfo *infoList; /* list for additional info on parameters */ pICallBack pCall; /* sics callback function */ SConnection *conn; /* last connection with user or manager priv. */ int verbose; /* verbosity, mainly for tests */ pHdb node; /* node for update */ char *secop_module; /* secop module name, if enabled */ } ParData; /* Implementation of an object: object data: The first member of the objects data struct must be a plain ParData (not a pointer) The ParData member may also be the first member of an nested struct, the only condition is, that it is at offset 0, i.e. a cast to ParData is always valid. typedef struct { ParData p; // object members: float value; char *text; FooSpecialObject *obj; } FooData; a static class object of type ParClass has to be declared and initialized with its name and the object data size: static ParClass fooClass {"Foo", sizeof(FooData) } at initialisation, or at least before it is used first, it has to be initialized with ParMakeClass(&fooClass, NULL); (NULL as the second argument makes ParData to be the base class, if more levels of inheritance are used, use the base class as argument) parameter definition: The parameters definition is within the pardef function, for example void FooPardef(void *object) { FooData *data = ParCast(&fooClass, object); ParName("value"); ParFmt("%.3f"); ParFloat(&data->value, 0.0); ParName("text"); ParList(NULL); ParStr(&data->text, ""); if (ParAction() == PAR_KILL) { if (data->obj) { FreeSpecialObject(data->obj); data->obj = NULL; } } } The first line in FooPardef is a cast converting the anonymous object to your data type. ParCast does some validity checks, which are strongly recommended. The next two lines are parameters definitions. A parameter definition starts always with ParName, followed by some options, and ends with the parameter type definition. FooPardef is called for all operations on data, so do not insert long calculations inside it. For special actions, code may be inserted for something like killing members. All char arguments in the following functions might be referred even after the function returned. If they are not a constant, it is the callers responsibility to make its contents valid whenever they are used. */ void ParName(char *name); /* name must not change during lifetime of the object, normally it is a constant */ /* Options (to be called before parameter type definitions): */ void ParFmt(char *fmt); /* format (float only) */ void ParAccess(int access); /* access rights (default usInternal = read only) */ void ParSave(int save); /* save on status file (0: do not svae, 1: save, 2: saved by driver (default: 0 for ParAccess(usInternal), 1 for others) */ void ParEnum(char *list[]); /* automatic keyword to number conversion */ void ParList(char *group); /* ParList may be repeated with several group arguments, to appear on a list subcommand. Give NULL for std list, "" for no list */ void ParTail(char *tail); /* comment to appear after list entry (e.g. units). If ParList is not called, ParTail will force to appear in standard list. */ void ParLogAs(char *name); /* switch log on and give sugar name (NULL for no logging) */ /* Parameter type definitions: select one out of these per parameter, with a pointer to the corresponding object member as argument */ void ParFloat(float *value, float defValue); void ParInt(int *value, int defValue); void ParFixedStr(char *value, int maxsize, char *defValue); /* fixed size string */ void ParStr(char **value, char *defValue); /* dynamic string */ typedef int (*ParCommand) (void *object, void *userarg, int argc, char *argv[]); /* command function to be executed */ int ParCmd(ParCommand cmd, void *userarg); /* command, returns 0 when not executed else return value from cmd, default access is usUser */ /* If code has to be executed for a specific to a parameter and and action, ParActionIs (see below) may be used. Typical usage: if (ParActionIs(PAR_SET) > 0) { things to do when parameter has changed } A parameter definition finishes after these calls. There are predefined actions which are all handled by this module: */ typedef enum { PAR_NOOP, /* no operation */ PAR_INIT, /* initialize object (called during initialisation) */ PAR_SHOW, /* show single parameter (1) */ PAR_SET, /* set a single parameter (1) */ PAR_GET, /* get a single float parameter (1) */ PAR_LIST, /* list all or a group of parameters (2) */ PAR_LOG, /* log all parameters activated for logging (2) */ PAR_LOGSWITCH, /* (de)activate single parameter for logging (1) */ PAR_SAVE, /* save all parameters activated for saving (2) */ PAR_SAVESWITCH, /* (de)activate single parameter for saving (1) */ PAR_KILL, /* kill content (called before remove) */ PAR_UPDATE, /* update hipadaba node */ PAR_HDBSET /* set from hipadaba node */ } ParAct; int ParActionIs(ParAct action); /* to be called inside the pardef function. returns 0, when the action is not active. returns 1 or -1 when the action is active. the return value -1 is used under following conditions: - for actions marked with (1), when the name does not match (for this case ParActionIs may be called between the call to ParName for the parameter referred and before the next call to ParName) - for actions marked with (2), when the parameter was not used (for this case ParActionIs must be called after the parameter definition for the parameter referred and before the next call to ParName) */ void ParStdDef(void); /* handle the standard parameters "verbose" and "driver" */ void *ParObject(void); /* get the current object (to be called by functions called inside pardef, when the object is not in the argument list */ void ParLogReady(ReadyState state); /* set ready state for log */ FILE *ParSaveFile(void); /* get the save-file name when action is PAR_SAVE */ char *ParGetValueArg(); /* get the set argument for floats and ints. If this function is called, the caller is reponsible for assigning the value to the object parameter */ /* functions to be used outside pardef: */ void ParUpdateAll(void *object); /* update all hdb nodes */ int ParLog(void *object); /* log all parameters of this object, but only if not already logged in the interval, returns >= 0 when done, or < 0, when not done (execute PAR_LOG action) */ void ParKill(void *object); /* free the object (execute PAR_KILL action) */ void ParGetFloat(SConnection * con, void *object, char *name, float *value); /* get a float parameter (execute PAR_GET action) */ void *ParCast(ParClass * class, void *object); /* returns object, if the object has type "class" or inherits type "class", returns NULL otherwise */ void *ParCheck(ParClass * class, void *object); /* dumps core when object has not or does not inherit "class" */ void *ParMakeClass(ParClass * class, ParClass * base); /* initialize "class". base defines its base class or NULL when ParData is its direct base class */ void *ParMake(SConnection * con, char *name, ParClass * class, ParDef pardef, char *creationCmd); /* make an object of class "class", and declare its pardef function. Add it as command "name" to SICS, and execute pardef with PAR_INIT action. When creationCmd is not NULL, it is saved in order to recreate the object. The SICS system will execute: - PAR_SHOW, PAR_SET, PAR_LIST, PAR_LOGSWITCH from the corresponding command - PAR_LOG after a PAR_SET action - PAR_SAVE after a parameter change on any SICS command - PAR_KILL on RemoveCommand */ char *ParArg2Str(int argc, char *argv[], char *res, int maxsize); /* convert args to text. if res==NULL, the result is allocated and maxsize is ignored */ void ParSaveConn(void *object, SConnection * con); /* save connection for further use */ void ParInitPar(void *object, char *name, int logged); /* inititalize dynamic parameter */ void ParKillPar(void *object, char *name); /* delete dynamic parameter */ #endif