tape/recorder.c

00001 
00018 #include <stdlib.h>
00019 #include <stdio.h>
00020 #include <errno.h>
00021 #include <ctype.h>
00022 #include "gridlabd.h"
00023 #include "object.h"
00024 #include "aggregate.h"
00025 
00026 #include "tape.h"
00027 #include "file.h"
00028 #include "odbc.h"
00029 
00030 CLASS *recorder_class = NULL;
00031 static OBJECT *last_recorder = NULL;
00032 
00033 EXPORT int create_recorder(OBJECT **obj, OBJECT *parent)
00034 {
00035     *obj = gl_create_object(recorder_class,sizeof(struct recorder));
00036     if (*obj!=NULL)
00037     {
00038         struct recorder *my = OBJECTDATA(*obj,struct recorder);
00039         last_recorder = *obj;
00040         gl_set_parent(*obj,parent);
00041         strcpy(my->file,"");
00042         strcpy(my->filetype,"txt");
00043         strcpy(my->delim,",");
00044         strcpy(my->property,"(undefined)");
00045         my->interval = -1; /* transients only */
00046         my->last.ts = -1;
00047         strcpy(my->last.value,"");
00048         my->limit = 0;
00049         my->samples = 0;
00050         my->status = TS_INIT;
00051         my->trigger[0]='\0';
00052         my->format = 0;
00053         my->target = gl_get_property(*obj,my->property);
00054         return 1;
00055     }
00056     return 0;
00057 }
00058 
00059 static int recorder_open(OBJECT *obj)
00060 {
00061     char32 type="file";
00062     char1024 fname="";
00063     char32 flags="w";
00064     struct recorder *my = OBJECTDATA(obj,struct recorder);
00065     
00066     /* if prefix is omitted (no colons found) */
00067     if (sscanf(my->file,"%32[^:]:%1024[^:]:%[^:]",type,fname,flags)==1)
00068     {
00069         /* filename is file by default */
00070         strcpy(fname,my->file);
00071         strcpy(type,"file");
00072     }
00073 
00074     /* if no filename given */
00075     if (strcmp(fname,"")==0)
00076 
00077         /* use object name-id as default file name */
00078         sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00079 
00080     /* if type is file or file is stdin */
00081     my->ops = get_ftable(type)->recorder;
00082     if(my->ops == NULL)
00083         return 0;
00084     return my->ops->open(my, fname, flags);
00085 }
00086 
00087 static int write_recorder(struct recorder *my, char *ts, char *value)
00088 {
00089     return my->ops->write(my, ts, value);
00090 }
00091 
00092 static void close_recorder(struct recorder *my)
00093 {
00094     my->ops->close(my);
00095 }
00096 
00097 static TIMESTAMP recorder_write(OBJECT *obj)
00098 {
00099     struct recorder *my = OBJECTDATA(obj,struct recorder);
00100     char ts[64];
00101     if (my->format==0)
00102     {
00103         time_t t = (time_t)(my->last.ts*TS_SECOND);
00104         strftime(ts,sizeof(ts),timestamp_format, gmtime(&t));
00105     }
00106     else
00107         sprintf(ts,"%" FMT_INT64 "d", my->last.ts);
00108     if ((my->limit>0 && my->samples > my->limit) /* limit reached */
00109         || write_recorder(my, ts, my->last.value)==0) /* write failed */
00110     {
00111         close_recorder(my);
00112         my->status = TS_DONE;
00113     }
00114     else
00115         my->samples++;
00116     return TS_NEVER;
00117 }
00118 
00119 PROPERTY *link_properties(OBJECT *obj, char *property_list)
00120 {
00121     char *item;
00122     PROPERTY *first=NULL, *last=NULL;
00123     char1024 list;
00124     strcpy(list,property_list); /* avoid destroying orginal list */
00125     for (item=strtok(list,","); item!=NULL; item=strtok(NULL,","))
00126     {
00127         PROPERTY *prop = (PROPERTY*)malloc(sizeof(PROPERTY));
00128         PROPERTY *target = gl_get_property(obj,item);
00129         if (prop!=NULL && target!=NULL)
00130         {
00131             if (first==NULL) first=prop; else last->next=prop;
00132             last=prop;
00133             memcpy(prop,target,sizeof(PROPERTY));
00134             prop->next = NULL;
00135         }
00136         else
00137         {
00138             gl_error("recorder:%d: property '%s' not found", obj->id,item);
00139             return NULL;
00140         }
00141     }
00142     return first;
00143 }
00144 
00145 int read_properties(OBJECT *obj, PROPERTY *prop, char *buffer, int size)
00146 {
00147     PROPERTY *p;
00148     int offset=0;
00149     int count=0;
00150     for (p=prop; p!=NULL && offset<size-33; p=p->next)
00151     {
00152         if (offset>0) strcpy(buffer+offset++,",");
00153         offset+=gl_get_value(obj,GETADDR(obj,p),buffer+offset,size-offset-1,p); /* pointer => int64 */
00154         buffer[offset]='\0';
00155         count++;
00156     }
00157     return count;
00158 }
00159 
00160 EXPORT TIMESTAMP sync_recorder(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00161 {
00162     struct recorder *my = OBJECTDATA(obj,struct recorder);
00163     typedef enum {NONE='\0', LT='<', EQ='=', GT='>'} COMPAREOP;
00164     COMPAREOP comparison;
00165     char1024 buffer = "";
00166     
00167     if (my->status==TS_DONE)
00168         return TS_NEVER;
00169 
00170     /* connect to property */
00171     if (my->target==NULL)
00172         my->target = link_properties(obj->parent,my->property);
00173 
00174     /* read property */
00175     if (my->target==NULL)
00176     {
00177         sprintf(buffer,"'%s' contains a property of %s %d that is not found", my->property, obj->parent->oclass->name, obj->parent->id);
00178         my->status = TS_ERROR;
00179     }
00180     else if (read_properties(obj->parent,my->target,buffer,sizeof(buffer))==0)
00181     {
00182         sprintf(buffer,"unable to read property '%s' of %s %d", my->property, obj->parent->oclass->name, obj->parent->id);
00183         my->status = TS_ERROR;
00184     }
00185 
00186     /* check trigger, if any */
00187     comparison = (COMPAREOP)my->trigger[0];
00188     if (comparison!=NONE)
00189     {
00190         int desired = comparison==LT ? -1 : (comparison==EQ ? 0 : (comparison==GT ? 1 : -2));
00191 
00192         /* if not trigger or can't get access */
00193         int actual = strcmp(buffer,my->trigger+1);
00194         if (actual!=desired || (my->status==TS_INIT && !recorder_open(obj)))
00195 
00196             /* better luck next time */
00197             return TS_NEVER;
00198     }
00199     else if (my->status==TS_INIT && !recorder_open(obj))
00200         return TS_NEVER;
00201 
00202     /* write tape */
00203     if (my->status==TS_OPEN)
00204     {   
00205         if (my->interval==0 /* sample on every pass */
00206             || ((my->interval==-1) && my->last.ts!=t0 && strcmp(buffer,my->last.value)!=0) /* sample only when value changes */
00207             || my->last.ts+my->interval <= t0) /* sample regularly */
00208         {
00209             my->last.ts = t0;
00210             strncpy(my->last.value,buffer,sizeof(my->last.value));
00211             recorder_write(obj);
00212         }
00213     }
00214     else if (my->status==TS_ERROR)
00215     {
00216         gl_error("recorder %d %s\n",obj->id, buffer);
00217         my->status=TS_DONE;
00218     }
00219 
00220 
00221     return (my->interval==0 || my->interval==-1) ? TS_NEVER : t0+my->interval;
00222 }
00223 

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy