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;
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
00067 if (sscanf(my->file,"%32[^:]:%1024[^:]:%[^:]",type,fname,flags)==1)
00068 {
00069
00070 strcpy(fname,my->file);
00071 strcpy(type,"file");
00072 }
00073
00074
00075 if (strcmp(fname,"")==0)
00076
00077
00078 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00079
00080
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)
00109 || write_recorder(my, ts, my->last.value)==0)
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);
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);
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
00171 if (my->target==NULL)
00172 my->target = link_properties(obj->parent,my->property);
00173
00174
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
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
00193 int actual = strcmp(buffer,my->trigger+1);
00194 if (actual!=desired || (my->status==TS_INIT && !recorder_open(obj)))
00195
00196
00197 return TS_NEVER;
00198 }
00199 else if (my->status==TS_INIT && !recorder_open(obj))
00200 return TS_NEVER;
00201
00202
00203 if (my->status==TS_OPEN)
00204 {
00205 if (my->interval==0
00206 || ((my->interval==-1) && my->last.ts!=t0 && strcmp(buffer,my->last.value)!=0)
00207 || my->last.ts+my->interval <= t0)
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