00001
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033 #include <ctype.h>
00034 #include "gridlabd.h"
00035 #include "object.h"
00036 #include "aggregate.h"
00037
00038 #include "tape.h"
00039 #include "file.h"
00040 #include "odbc.h"
00041
00042 #ifndef WIN32
00043 #define strtok_s strtok_r
00044 #else
00045 #ifdef __MINGW32__
00046 char* strtok_t(char *str, const char *delim, char **nextp)
00047 {
00048 char *ret;
00049
00050 if (str == NULL)
00051 {
00052 str = *nextp;
00053 }
00054
00055 str += strspn(str, delim);
00056
00057 if (*str == '\0')
00058 {
00059 return NULL;
00060 }
00061
00062 ret = str;
00063
00064 str += strcspn(str, delim);
00065
00066 if (*str)
00067 {
00068 *str++ = '\0';
00069 }
00070
00071 *nextp = str;
00072
00073 return ret;
00074 }
00075
00076 #define strtok_s strtok_t
00077 #endif
00078
00079 #endif
00080
00081 CLASS *multi_recorder_class = NULL;
00082 static OBJECT *last_recorder = NULL;
00083
00084 EXPORT int create_multi_recorder(OBJECT **obj, OBJECT *parent)
00085 {
00086 *obj = gl_create_object(multi_recorder_class);
00087 if (*obj!=NULL)
00088 {
00089 struct recorder *my = OBJECTDATA(*obj,struct recorder);
00090 last_recorder = *obj;
00091 gl_set_parent(*obj,parent);
00092 strcpy(my->file,"");
00093 strcpy(my->multifile,"");
00094 strcpy(my->filetype,"txt");
00095 strcpy(my->delim,",");
00096 strcpy(my->mode, "file");
00097 strcpy(my->property,"(undefined)");
00098 my->interval = -1;
00099 my->dInterval = -1.0;
00100 my->last.ts = -1;
00101 strcpy(my->last.value,"");
00102 my->limit = 0;
00103 my->samples = 0;
00104 my->status = TS_INIT;
00105 my->trigger[0]='\0';
00106 my->format = 0;
00107 strcpy(my->plotcommands,"");
00108 my->target = gl_get_property(*obj,my->property,NULL);
00109 my->header_units = HU_DEFAULT;
00110 my->line_units = LU_DEFAULT;
00111 return 1;
00112 }
00113 return 0;
00114 }
00115
00116 static int multi_recorder_open(OBJECT *obj)
00117 {
00118 char32 type="file";
00119 char1024 fname="";
00120 char32 flags="w";
00121 struct recorder *my = OBJECTDATA(obj,struct recorder);
00122 TAPEFUNCS *tf = 0;
00123
00124 my->interval = (int64)(my->dInterval/TS_SECOND);
00125
00126 if (sscanf(my->file,"%32[^:]:%1024[^:]:%[^:]",type,fname,flags)==1)
00127 {
00128
00129 strcpy(fname,my->file);
00130 strcpy(type,"file");
00131 }
00132
00133
00134 if (strcmp(fname,"")==0)
00135
00136
00137 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00138
00139
00140 if(my->type == FT_FILE && my->multifile[0] != 0){
00141 if(my->interval < 1){
00142 gl_error("multirecorder: transient recorders cannot use multi-run output files");
00143 return 0;
00144 }
00145 sprintf(my->multitempfile, "temp_%s", my->file);
00146 my->multifp = fopen(my->multitempfile, "w");
00147 if(my->multifp == NULL){
00148 gl_error("multirecorder: unable to open \'%s\' for multi-run output", my->multitempfile);
00149 } else {
00150 time_t now=time(NULL);
00151
00152 my->inputfp = fopen(my->multifile, "r");
00153
00154
00155 fprintf(my->multifp,"# file...... %s\n", my->file);
00156 fprintf(my->multifp,"# date...... %s", asctime(localtime(&now)));
00157 #ifdef WIN32
00158 fprintf(my->multifp,"# user...... %s\n", getenv("USERNAME"));
00159 fprintf(my->multifp,"# host...... %s\n", getenv("MACHINENAME"));
00160 #else
00161 fprintf(my->multifp,"# user...... %s\n", getenv("USER"));
00162 fprintf(my->multifp,"# host...... %s\n", getenv("HOST"));
00163 #endif
00164 if(obj->parent){
00165 fprintf(my->multifp,"# target.... %s %d\n", obj->parent->oclass->name, obj->parent->id);
00166 } else {
00167 fprintf(my->multifp,"# target.... (none)\n");
00168 }
00169 fprintf(my->multifp,"# trigger... %s\n", my->trigger[0]=='\0'?"(none)":my->trigger);
00170 fprintf(my->multifp,"# interval.. %d\n", my->interval);
00171 fprintf(my->multifp,"# limit..... %d\n", my->limit);
00172 fprintf(my->multifp,"# property.. %s\n", my->property);
00173
00174 }
00175 if(my->inputfp != NULL){
00176 char1024 inbuffer;
00177 char *data;
00178 int get_col = 0;
00179 do{
00180 if(0 != fgets(inbuffer, 1024, my->inputfp)){
00181 char *end = strchr(inbuffer, '\n');
00182 data = inbuffer+strlen("# file...... ");
00183 if(end != 0){
00184 *end = 0;
00185 }
00186
00187 if(strncmp(inbuffer, "# file", strlen("# file")) == 0){
00188 ;
00189 } else if(strncmp(inbuffer, "# date", strlen("# date")) == 0){
00190 ;
00191 } else if(strncmp(inbuffer, "# user", strlen("# user")) == 0){
00192 ;
00193 } else if(strncmp(inbuffer, "# host", strlen("# host")) == 0){
00194 ;
00195 } else if(strncmp(inbuffer, "# target", strlen("# target")) == 0){
00196
00197 char256 target;
00198 if(obj->parent != 0){
00199 sprintf(target, "%s %d", obj->parent->oclass->name, obj->parent->id);
00200 if(0 != strncmp(target, data, strlen(data))){
00201 gl_error("multirecorder:%i: re-recording target mismatch: was %s, now %s", obj->id, data, target);
00202 }
00203 } else {
00204 if(strncmp("(none)", target, 6)){
00205 gl_error("multirecorder:%i: re-recording target mismatch: was %s, now blank", obj->id, data);
00206 }
00207 }
00208 } else if(strncmp(inbuffer, "# trigger", strlen("# trigger")) == 0){
00209
00210 ;
00211 } else if(strncmp(inbuffer, "# interval", strlen("# interval")) == 0){
00212
00213 int interval = atoi(data);
00214 if(interval != my->interval){
00215 gl_error("multirecorder:%i: re-recording interval mismatch: was %i, now %i", obj->id, interval, my->interval);
00216 }
00217 } else if(strncmp(inbuffer, "# limit", strlen("# limit")) == 0){
00218
00219 int limit = atoi(data);
00220 if(limit != my->limit){
00221 gl_error("multirecorder:%i: re-recording limit mismatch: was %i, now %i", obj->id, limit, my->limit);
00222 }
00223 } else if(strncmp(inbuffer, "# property", strlen("# property")) == 0){
00224
00225 if(0 != strncmp(my->property, data, strlen(my->property))){
00226 gl_error("multirecorder:%i: re-recording property mismatch: was %s, now %s", obj->id, data, my->property);
00227 }
00228
00229 get_col = 1;
00230 }
00231 } else {
00232 gl_error("multirecorder: error reading multi-read input file \'%s\'", my->multifile);
00233 break;
00234 }
00235 } while(inbuffer[0] == '#' && get_col == 0);
00236
00237 if(0 != fgets(inbuffer, 1024, my->inputfp)){
00238 int rep=0;
00239 int replen = (int)strlen("# repetition");
00240 int len, lenmax = 1024, i = 0;
00241 char1024 propstr, shortstr;
00242 PROPERTY *tprop = my->target;
00243 gl_verbose("read last buffer");
00244 if(strncmp(inbuffer, "# repetition", replen) == 0){
00245 char *trim;
00246 rep = atoi(inbuffer + replen + 1);
00247 ++rep;
00248 fprintf(my->multifp, "# repetition %i\n", rep);
00249 fgets(inbuffer, 1024, my->inputfp);
00250 trim = strchr(inbuffer, '\n');
00251 if(trim) *trim = 0;
00252 } else {
00253 rep = 0;
00254 fprintf(my->multifp, "# repetition %i\n", rep);
00255 }
00256
00257 while(tprop != NULL){
00258 sprintf(shortstr, ",%s(%i)", tprop->name, rep);
00259 len = (int)strlen(shortstr);
00260 if(len > lenmax){
00261 gl_error("multirecorder: multi-run recorder output full property list is larger than the buffer, please start a new file!");
00262 break;
00263 }
00264 strncpy(propstr+i, shortstr, len+1);
00265 i += len;
00266 tprop = tprop->next;
00267 }
00268 fprintf(my->multifp, "%s%s\n", inbuffer, propstr);
00269 }
00270 } else {
00271 char1024 propstr, shortstr;
00272
00273
00274
00275 int len, lenmax = 1024, i = 0;
00276 PROPERTY *tprop = my->target;
00277 fprintf(my->multifp, "# repetition 0\n");
00278
00279 sprintf(propstr, "# timestamp");
00280 len = (int)strlen(propstr);
00281 lenmax-=len;
00282 i = len;
00283
00284 while(tprop != NULL){
00285 sprintf(shortstr, ",%s(0)", tprop->name);
00286 len = (int)strlen(shortstr);
00287 if(len > lenmax){
00288 gl_error("multirecorder: multi-run recorder output full property list is larger than the buffer, please start a new file!");
00289 break;
00290 }
00291 strncpy(propstr+i, shortstr, len+1);
00292 i += len;
00293 tprop = tprop->next;
00294 }
00295 fprintf(my->multifp, "%s\n", propstr);
00296
00297
00298
00299 }
00300 }
00301
00302
00303 tf = get_ftable(type);
00304 if(tf == NULL)
00305 return 0;
00306 my->ops = tf->recorder;
00307 if(my->ops == NULL)
00308 return 0;
00309 set_csv_options();
00310
00311
00312 {size_t offset = 0;
00313 char unit_buffer[1024];
00314 char *token = 0, *prop_ptr = 0, *unit_ptr = 0, *obj_ptr = 0;
00315 char objstr[1024], bigpropstr[1024], propstr[1024], unitstr[64];
00316 PROPERTY *prop = 0;
00317 UNIT *unit = 0;
00318 int first = 1;
00319 OBJECT *myobj = 0;
00320 switch(my->header_units){
00321 case HU_DEFAULT:
00322 strcpy(my->out_property, my->property);
00323 break;
00324 case HU_ALL:
00325 strcpy(unit_buffer, my->property);
00326 for(token = strtok(unit_buffer, ","); token != NULL; token = strtok(NULL, ",")){
00327 unit = 0;
00328 prop = 0;
00329 unitstr[0] = 0;
00330 propstr[0] = 0;
00331 objstr[0] = 0;
00332 prop_ptr = strchr(token, ':');
00333 if(prop_ptr != 0){
00334 unit_ptr = strchr(prop_ptr, '[');
00335 } else {
00336 unit_ptr = strchr(token, '[');
00337 }
00338
00339 if(prop_ptr == 0){
00340 prop_ptr = token;
00341 myobj = obj->parent;
00342 strcpy(bigpropstr, token);
00343 } else {
00344 sscanf(token, "%[^:]:%[^\n\r\t;]", objstr, bigpropstr);
00345 myobj = gl_get_object(objstr);
00346 if(myobj == 0){
00347 gl_error("multi_recorder:%d: unable to find object '%s'", obj->id, objstr);
00348 return 0;
00349 }
00350 }
00351
00352 if(unit_ptr == 0){
00353
00354 prop = gl_get_property(myobj, bigpropstr,NULL);
00355 if(prop == 0){
00356 gl_error("multi_recorder:%d: unable to find property '%s' for object '%s'", obj->id, propstr, myobj->name);
00357 return 0;
00358 }
00359
00360 if(prop->ptype == PT_double){
00361 strcpy(unitstr, prop->unit->name);
00362 } else {
00363 ;
00364 }
00365 strcpy(propstr, bigpropstr);
00366 } else {
00367
00368 if(2 == sscanf(bigpropstr, "%[A-Za-z0-9_.][%[^]\n,\0]", propstr, unitstr)){
00369 unit = gl_find_unit(unitstr);
00370 if(unit == 0){
00371 gl_error("multi_recorder:%d: unable to find unit '%s' for property '%s'", obj->id, unitstr, propstr);
00372 return 0;
00373 }
00374 prop = gl_get_property(myobj, propstr,NULL);
00375 if(prop == 0){
00376 gl_error("multi_recorder:%d: unable to find property '%s' for object '%s'", obj->id, propstr, myobj->name);
00377 return 0;
00378 }
00379 } else {
00380 gl_error("oops");
00381 }
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 if(myobj != obj->parent){
00402
00403 if(unit != 0){
00404 sprintf(my->out_property+offset, "%s%s:%s[%s]", (first ? "" : ","), myobj->name, propstr, (unitstr[0] ? unitstr : unit->name));
00405 offset += strlen(propstr) + (first ? 0 : 1) + 2 + strlen(unitstr[0] ? unitstr : unit->name) + strlen(myobj->name) + 1;
00406 } else {
00407 sprintf(my->out_property+offset, "%s%s:%s", (first ? "" : ","), myobj->name, propstr);
00408 offset += strlen(propstr) + (first ? 0 : 1 + strlen(myobj->name) + 1);
00409 }
00410 } else {
00411
00412 if(unit != 0){
00413 sprintf(my->out_property+offset, "%s%s[%s]", (first ? "" : ","), propstr, (unitstr[0] ? unitstr : unit->name));
00414 offset += strlen(propstr) + (first ? 0 : 1) + 2 + strlen(unitstr[0] ? unitstr : unit->name);
00415 } else {
00416 sprintf(my->out_property+offset, "%s%s", (first ? "" : ","), propstr);
00417 offset += strlen(propstr) + (first ? 0 : 1);
00418 }
00419 }
00420 first = 0;
00421 }
00422 break;
00423 case HU_NONE:
00424 strcpy(unit_buffer, my->property);
00425 for(token = strtok(unit_buffer, ","); token != NULL; token = strtok(NULL, ",")){
00426 if(2 == sscanf(token, "%[A-Za-z0-9_:.][%[^]\n,\0]", propstr, unitstr)){
00427 ;
00428 }
00429
00430 sprintf(my->out_property+offset, "%s%s", (first ? "" : ","), propstr);
00431 offset += strlen(propstr) + (first ? 0 : 1);
00432 first = 0;
00433 }
00434 break;
00435 default:
00436
00437 break;
00438 }
00439 }
00440 return my->ops->open(my, fname, flags);
00441 }
00442
00443 static int write_multi_recorder(struct recorder *my, char *ts, char *value)
00444 {
00445 return my->ops->write(my, ts, value);
00446 }
00447
00448 static void close_multi_recorder(struct recorder *my)
00449 {
00450 if (my->ops){
00451 my->ops->close(my);
00452 }
00453 if(my->multifp){
00454 if(0 != fclose(my->multifp)){
00455 gl_error("multirecorder: unable to close multi-run temp file \'%s\'", my->multitempfile);
00456 perror("fclose(): ");
00457 }
00458
00459 my->multifp = 0;
00460
00461 if(my->inputfp != NULL){
00462 fclose(my->inputfp);
00463 if(0 != remove(my->multifile)){
00464 gl_error("multirecorder: unable to remove out-of-data multi-run file \'%s\'", my->multifile);
00465 perror("remove(): ");
00466 }
00467 }
00468 if(0 != rename(my->multitempfile, my->multifile)){
00469 gl_error("multirecorder: unable to rename multi-run file \'%s\' to \'%s\'", my->multitempfile, my->multifile);
00470 perror("rename(): ");
00471 }
00472
00473 }
00474 }
00475
00476 static TIMESTAMP multi_recorder_write(OBJECT *obj)
00477 {
00478 struct recorder *my = OBJECTDATA(obj,struct recorder);
00479 char ts[64]="0";
00480 if (my->format==0)
00481 {
00482 if (my->last.ts>TS_ZERO)
00483 {
00484 DATETIME dt;
00485 gl_localtime(my->last.ts,&dt);
00486 gl_strtime(&dt,ts,sizeof(ts));
00487 }
00488
00489 }
00490 else
00491 sprintf(ts,"%" FMT_INT64 "d", my->last.ts);
00492 if ((my->limit>0 && my->samples > my->limit)
00493 || write_multi_recorder(my, ts, my->last.value)==0)
00494 {
00495 close_multi_recorder(my);
00496 my->status = TS_DONE;
00497 }
00498 else
00499 my->samples++;
00500
00501
00502
00503
00504 if(my->multifp != NULL){
00505 char1024 inbuffer;
00506 char1024 outbuffer;
00507 char *lasts = 0;
00508 char *in_ts = 0;
00509 char *in_tok = 0;
00510
00511 memset(inbuffer, 0, sizeof(inbuffer));
00512
00513 if(my->inputfp != NULL){
00514
00515 do{
00516 if(0 == fgets(inbuffer, 1024, my->inputfp)){
00517 if(feof(my->inputfp)){
00518
00519
00520
00521 return TS_NEVER;
00522 } else {
00523 gl_error("multirecorder: error reading past recordings file");
00524 my->status = TS_ERROR;
00525 return TS_NEVER;
00526 }
00527 }
00528
00529 } while(inbuffer[0] == '#');
00530
00531
00532
00533 in_ts = strtok_s(inbuffer, ",\n", &lasts);
00534 in_tok = strtok_s(NULL, "\n", &lasts);
00535
00536 if(in_ts == NULL){
00537 gl_error("multirecorder: unable to indentify a timestamp within the line read from ");
00538 }
00539
00540
00541
00542 if(strcmp(in_ts, ts) != 0){
00543 gl_warning("multirecorder: timestamp mismatch between current input line and simulation time");
00544 }
00545 sprintf(outbuffer, "%s,%s", in_tok, my->last.value);
00546 } else {
00547 strcpy(outbuffer, my->last.value);
00548 }
00549
00550 fprintf(my->multifp, "%s,%s\n", ts, outbuffer);
00551 }
00552 return TS_NEVER;
00553 }
00554
00555 RECORDER_MAP *link_multi_properties(OBJECT *obj, char *property_list)
00556 {
00557 char *itemptr, *item;
00558 char objstr[128];
00559 char itemstr[128];
00560 RECORDER_MAP *first=NULL, *last=NULL, *rmap;
00561 OBJECT *target_obj = NULL;
00562 UNIT *unit = NULL;
00563 char1024 list;
00564 complex oblig;
00565 int partres = 0;
00566 char name[128];
00567 char256 pstr, ustr;
00568 char *cpart = 0;
00569 int64 cid = -1;
00570 PROPERTY *prop = NULL;
00571 PROPERTY *target = NULL;
00572 double scale = 1.0;
00573
00574 strcpy(list,property_list);
00575 for (itemptr = strtok(list,","); itemptr != NULL; itemptr = strtok(NULL,","))
00576 {
00577 cpart = 0;
00578 cid = -1;
00579 prop = NULL;
00580 target = NULL;
00581 scale = 1.0;
00582 ustr[0] = 0;
00583 pstr[0] = 0;
00584 unit = NULL;
00585
00586
00587 if(2 == sscanf(itemptr, " %[^:]:%s", objstr, itemstr)){
00588 item = itemstr;
00589 target_obj = gl_get_object(objstr);
00590 if(target_obj == 0){
00591 gl_error("multirecorder: unable to find object '%s'", objstr);
00592 return 0;
00593 }
00594 } else {
00595 if(obj == 0){
00596 gl_error("multirecorder: no parent object and no specified target object in '%s'", itemstr);
00597 return 0;
00598 }
00599 target_obj = obj;
00600 item = objstr;
00601 }
00602
00603
00604 while (isspace(*item)) item++;
00605 if(2 == sscanf(item,"%[A-Za-z0-9_.][%[^]\n,\0]", pstr, ustr)){
00606 unit = gl_find_unit(ustr);
00607 if(unit == NULL){
00608 gl_error("multirecorder: unable to find unit '%s' for property '%s' in object '%s %i'", ustr,pstr,target_obj->oclass->name, target_obj->id);
00609 return NULL;
00610 }
00611 item = pstr;
00612 }
00613 rmap = (RECORDER_MAP *)malloc(sizeof(RECORDER_MAP));
00614 memset(rmap, 0, sizeof(RECORDER_MAP));
00615
00616
00617
00618 cpart = strchr(item, '.');
00619 if(cpart != NULL){
00620 if(strcmp("imag", cpart+1) == 0){
00621 cid = (int)((int64)&(oblig.i) - (int64)&oblig);
00622 *cpart = 0;
00623 } else if(strcmp("real", cpart+1) == 0){
00624 cid = (int)((int64)&(oblig.r) - (int64)&oblig);
00625 *cpart = 0;
00626 } else {
00627 ;
00628 }
00629 }
00630
00631 target = gl_get_property(target_obj,item,NULL);
00632
00633 if (rmap != NULL && target != NULL)
00634 {
00635 if(unit != NULL && target->unit == NULL){
00636 gl_error("recorder:%d: property '%s' is unitless, ignoring unit conversion", obj->id, item);
00637 }
00638 else if(unit != NULL && 0 == gl_convert_ex(target->unit, unit, &scale))
00639 {
00640 gl_error("recorder:%d: unable to convert property '%s' units to '%s'", obj->id, item, ustr);
00641 return NULL;
00642 }
00643 if(first == NULL){
00644 first = rmap;
00645 } else {
00646 last->next=rmap;
00647 }
00648 last = rmap;
00649 rmap->obj = target_obj;
00650 memcpy(&(rmap->prop), target, sizeof(PROPERTY));
00651 rmap->prop.unit = unit;
00652 rmap->next = NULL;
00653 }
00654 else
00655 {
00656 gl_name_object(target_obj, name, 128);
00657 gl_error("multirecorder: property '%s' not found in object '%s'", item, name);
00658 return NULL;
00659 }
00660 if(cid >= 0){
00661 rmap->prop.ptype = PT_double;
00662 (rmap->prop.addr) = (PROPERTYADDR)((int64)(rmap->prop.addr) + cid);
00663 }
00664 }
00665 return first;
00666 }
00667
00668 int read_multi_properties(struct recorder *my, OBJECT *obj, RECORDER_MAP *rmap, char *buffer, int size)
00669 {
00670 RECORDER_MAP *r;
00671 int offset = 0;
00672 int count = 0;
00673 double value;
00674 PROPERTY *p2 = 0;
00675 PROPERTY fake;
00676 memset(&fake, 0, sizeof(PROPERTY));
00677 fake.ptype = PT_double;
00678 fake.unit = 0;
00679 for(r = rmap; r != NULL && offset < size - 33; r = r->next){
00680 if(offset > 0){
00681 strcpy(buffer+offset++,",");
00682 }
00683
00684 if(r->prop.ptype == PT_double){
00685 switch(my->line_units){
00686 case LU_ALL:
00687
00688 case LU_DEFAULT:
00689 offset+=gl_get_value(r->obj,GETADDR(r->obj,&(r->prop)),buffer+offset,size-offset-1,&(r->prop));
00690 break;
00691 case LU_NONE:
00692
00693 value = *gl_get_double(r->obj, &(r->prop));
00694 p2 = gl_get_property(r->obj, r->prop.name,NULL);
00695 if(p2 == 0){
00696 gl_error("unable to locate %s.%s for LU_NONE", r->obj, r->prop.name);
00697 return 0;
00698 }
00699 if(r->prop.unit != 0 && p2->unit != 0){
00700 if(0 == gl_convert_ex(p2->unit, r->prop.unit, &value)){
00701 gl_error("unable to convert %s to %s for LU_NONE", r->prop.unit, p2->unit);
00702 } else {
00703 offset+=gl_get_value(r->obj,&value,buffer+offset,size-offset-1,&fake); ;
00704 }
00705 } else {
00706 offset+=gl_get_value(r->obj,GETADDR(r->obj,&(r->prop)),buffer+offset,size-offset-1,&(r->prop)); ;
00707 }
00708 break;
00709 default:
00710 break;
00711 }
00712 } else {
00713
00714 offset += gl_get_value(r->obj, GETADDR(r->obj, &(r->prop)), buffer+offset, size-offset-1, &(r->prop));
00715 }
00716 buffer[offset] = '\0';
00717 count++;
00718 }
00719 return count;
00720 }
00721
00722 EXPORT TIMESTAMP sync_multi_recorder(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00723 {
00724 struct recorder *my = OBJECTDATA(obj,struct recorder);
00725 typedef enum {NONE='\0', LT='<', EQ='=', GT='>'} COMPAREOP;
00726 COMPAREOP comparison;
00727 char1024 buffer = "";
00728
00729 if (my->status==TS_DONE)
00730 {
00731 close_multi_recorder(my);
00732 return TS_NEVER;
00733 }
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 if(my->last.ts < 1 && my->interval != -1)
00746 my->last.ts = t0;
00747
00748
00749 if (my->rmap==NULL){
00750 my->rmap = link_multi_properties(obj->parent,my->property);
00751 }
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 if (my->rmap==NULL)
00762 {
00763 sprintf(buffer,"'%s' contains a property reference that was not found", my->property);
00764 close_multi_recorder(my);
00765 my->status = TS_ERROR;
00766 goto Error;
00767 }
00768
00769
00770 if ((my->status==TS_OPEN) && (t0 > obj->clock))
00771 {
00772 obj->clock = t0;
00773
00774 if((my->interval > 0) && (my->last.ts < t0) && (my->last.value[0] != 0)){
00775 multi_recorder_write(obj);
00776 my->last.value[0] = 0;
00777 }
00778 }
00779
00780
00781 if ((my->rmap != NULL) && (my->interval == 0 || my->interval == -1)){
00782 if(read_multi_properties(my, obj->parent,my->rmap,buffer,sizeof(buffer))==0)
00783 {
00784
00785 sprintf(buffer,"unable to read a property");
00786 close_multi_recorder(my);
00787 my->status = TS_ERROR;
00788 }
00789 }
00790 if ((my->rmap != NULL) && (my->interval > 0)){
00791 if((t0 >=my->last.ts + my->interval) || (t0 == my->last.ts)){
00792 if(read_multi_properties(my, obj->parent,my->rmap,buffer,sizeof(buffer))==0)
00793 {
00794
00795 sprintf(buffer,"unable to read a property");
00796 close_multi_recorder(my);
00797 my->status = TS_ERROR;
00798 }
00799 my->last.ts = t0;
00800 }
00801 }
00802
00803
00804 comparison = (COMPAREOP)my->trigger[0];
00805 if (comparison!=NONE)
00806 {
00807 int desired = comparison==LT ? -1 : (comparison==EQ ? 0 : (comparison==GT ? 1 : -2));
00808
00809
00810 int actual = strcmp(buffer,my->trigger+1);
00811 if (actual!=desired || (my->status==TS_INIT && !multi_recorder_open(obj)))
00812 {
00813
00814 return (my->interval==0 || my->interval==-1) ? TS_NEVER : t0+my->interval;
00815 }
00816 }
00817 else if (my->status==TS_INIT && !multi_recorder_open(obj))
00818 {
00819 close_multi_recorder(my);
00820 return TS_NEVER;
00821 }
00822
00823 if(my->last.ts < 1 && my->interval != -1)
00824 my->last.ts = t0;
00825
00826
00827 if (my->status==TS_OPEN)
00828 {
00829 if (my->interval==0
00830 || ((my->interval==-1) && my->last.ts!=t0 && strcmp(buffer,my->last.value)!=0)
00831 )
00832
00833 {
00834 strncpy(my->last.value,buffer,sizeof(my->last.value));
00835 my->last.ts = t0;
00836 multi_recorder_write(obj);
00837 } else if (my->interval > 0 && my->last.ts == t0){
00838 strncpy(my->last.value,buffer,sizeof(my->last.value));
00839 }
00840 }
00841 Error:
00842 if (my->status==TS_ERROR)
00843 {
00844 gl_error("recorder %d %s\n",obj->id, buffer);
00845 close_multi_recorder(my);
00846 my->status=TS_DONE;
00847 return TS_NEVER;
00848 }
00849
00850 if (my->interval==0 || my->interval==-1)
00851 {
00852 return TS_NEVER;
00853 }
00854 else
00855 {
00856 return my->last.ts+my->interval;
00857 }
00858 }
00859