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