00001
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <errno.h>
00038 #include <ctype.h>
00039 #include "gridlabd.h"
00040 #include "object.h"
00041 #include "aggregate.h"
00042
00043 #include "tape.h"
00044 #include "file.h"
00045 #include "odbc.h"
00046
00047 CLASS *player_class = NULL;
00048 static OBJECT *last_player = NULL;
00049
00050 extern TIMESTAMP delta_mode_needed;
00051
00052 PROPERTY *player_link_properties(struct player *player, OBJECT *obj, char *property_list)
00053 {
00054 char *item;
00055 PROPERTY *first=NULL, *last=NULL;
00056 UNIT *unit = NULL;
00057 PROPERTY *prop;
00058 PROPERTY *target;
00059 char1024 list;
00060 complex oblig;
00061 double scale;
00062 char256 pstr, ustr;
00063 char *cpart = 0;
00064 int64 cid = -1;
00065
00066 strcpy(list,property_list);
00067 for (item=strtok(list,","); item!=NULL; item=strtok(NULL,","))
00068 {
00069 prop = NULL;
00070 target = NULL;
00071 scale = 1.0;
00072 unit = NULL;
00073 cpart = 0;
00074 cid = -1;
00075
00076
00077 while (isspace(*item)) item++;
00078 if(2 == sscanf(item,"%[A-Za-z0-9_.][%[^]\n,\0]", pstr, ustr)){
00079 unit = gl_find_unit(ustr);
00080 if(unit == NULL){
00081 gl_error("sync_player:%d: unable to find unit '%s' for property '%s'",obj->id, ustr,pstr);
00082 return NULL;
00083 }
00084 item = pstr;
00085 }
00086 prop = (PROPERTY*)malloc(sizeof(PROPERTY));
00087
00088
00089
00090 cpart = strchr(item, '.');
00091 if(cpart != NULL){
00092 if(strcmp("imag", cpart+1) == 0){
00093 cid = (int)((int64)&(oblig.i) - (int64)&oblig);
00094 *cpart = 0;
00095 } else if(strcmp("real", cpart+1) == 0){
00096 cid = (int)((int64)&(oblig.r) - (int64)&oblig);
00097 *cpart = 0;
00098 } else {
00099 ;
00100 }
00101 }
00102
00103 target = gl_get_property(obj,item,NULL);
00104
00105 if (prop!=NULL && target!=NULL)
00106 {
00107 if(unit != NULL && target->unit == NULL){
00108 gl_error("sync_player:%d: property '%s' is unitless, ignoring unit conversion", obj->id, item);
00109 }
00110 else if(unit != NULL && 0 == gl_convert_ex(target->unit, unit, &scale))
00111 {
00112 gl_error("sync_player:%d: unable to convert property '%s' units to '%s'", obj->id, item, ustr);
00113 return NULL;
00114 }
00115 if (first==NULL) first=prop; else last->next=prop;
00116 last=prop;
00117 memcpy(prop,target,sizeof(PROPERTY));
00118 prop->unit = unit;
00119
00120
00121
00122 prop->next = NULL;
00123 }
00124 else
00125 {
00126 gl_error("sync_player: property '%s' not found", item);
00127 return NULL;
00128 }
00129 if(cid >= 0){
00130 prop->ptype = PT_double;
00131 (prop->addr) = (PROPERTYADDR)((int64)(prop->addr) + cid);
00132 }
00133 }
00134 return first;
00135 }
00136
00137 int player_write_properties(struct player *my, OBJECT *obj, PROPERTY *prop, const char *buffer)
00138 {
00139 int count=0;
00140 const char delim[] = ",\n\r\t";
00141 char1024 bufcpy;
00142 memcpy(bufcpy, buffer, sizeof(char1024));
00143 char *next;
00144 char *token = strtok_s(bufcpy, delim, &next);
00145 PROPERTY *p=NULL;
00146 for (p=prop; p!=NULL; p=p->next)
00147 {
00148 if (token == NULL)
00149 {
00150 gl_error("sync_player:%d: not enough values on line: %s", obj->id, buffer);
00151 return count;
00152 }
00153 gl_set_value(obj,GETADDR(obj,p),token,p);
00154 count++;
00155 token = strtok_s(NULL, delim, &next);
00156 }
00157 return count;
00158 }
00159
00160 EXPORT int create_player(OBJECT **obj, OBJECT *parent)
00161 {
00162 *obj = gl_create_object(player_class);
00163 if (*obj!=NULL)
00164 {
00165 struct player *my = OBJECTDATA(*obj,struct player);
00166 last_player = *obj;
00167 gl_set_parent(*obj,parent);
00168 strcpy(my->file,"");
00169 strcpy(my->filetype,"txt");
00170 strcpy(my->mode, "file");
00171 strcpy(my->property,"(undefined)");
00172 my->next.ts = TS_ZERO;
00173 strcpy(my->next.value,"");
00174 my->loopnum = 0;
00175 my->loop = 0;
00176 my->status = TS_INIT;
00177 my->target = gl_get_property(*obj,my->property,NULL);
00178 my->delta_track.ns = 0;
00179 my->delta_track.ts = TS_NEVER;
00180 my->delta_track.value[0] = '\0';
00181 return 1;
00182 }
00183 return 0;
00184 }
00185
00186 static int player_open(OBJECT *obj)
00187 {
00188 char32 type="file";
00189 char1024 fname="";
00190 char32 flags="r";
00191 struct player *my = OBJECTDATA(obj,struct player);
00192 TAPEFUNCS *tf = 0;
00193 int retvalue;
00194
00195
00196
00197
00198
00199 strcpy(fname,my->file);
00200
00201
00202
00203
00204 if (strcmp(fname,"")==0)
00205
00206
00207 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, my->filetype);
00208
00209
00210 tf = get_ftable(my->mode);
00211 if(tf == NULL)
00212 return 0;
00213 my->ops = tf->player;
00214 if(my->ops == NULL)
00215 return 0;
00216
00217
00218 if ( (my->ops->open)(my, fname, flags)==1 )
00219 {
00220
00221 if ( (obj->flags)&OF_DELTAMODE )
00222 {
00223 extern int delta_add_tape_device(OBJECT *obj, DELTATAPEOBJ tape_type);
00224 retvalue = delta_add_tape_device(obj,PLAYER);
00225
00226
00227 if (retvalue == 0)
00228 {
00229
00230 return 0;
00231 }
00232 }
00233 return 1;
00234 }
00235 else
00236 return 0;
00237 }
00238
00239 static void rewind_player(struct player *my)
00240 {
00241 (*my->ops->rewind)(my);
00242 }
00243
00244 static void close_player(struct player *my)
00245 {
00246 (my->ops->close)(my);
00247 }
00248
00249 static void trim(char *str, char *to){
00250 int i = 0, j = 0;
00251 if(str == 0)
00252 return;
00253 while(str[i] != 0 && isspace(str[i])){
00254 ++i;
00255 }
00256 while(str[i] != 0){
00257 to[j] = str[i];
00258 ++j;
00259 ++i;
00260 }
00261 --j;
00262 while(j > 0 && isspace(to[j])){
00263 to[j] = 0;
00264 --j;
00265 }
00266 }
00267
00268 TIMESTAMP player_read(OBJECT *obj)
00269 {
00270 char buffer[1024];
00271 char timebuf[64], valbuf[1024], tbuf[64];
00272 char tz[6];
00273 int Y=0,m=0,d=0,H=0,M=0;
00274 double S=0;
00275 struct player *my = OBJECTDATA(obj,struct player);
00276 char unit[2];
00277 TIMESTAMP t1;
00278 char *result=NULL;
00279 char1024 value;
00280 int voff=0;
00281
00282
00283 static enum {UNKNOWN,ISO,US,EURO} dateformat = UNKNOWN;
00284 if ( dateformat==UNKNOWN )
00285 {
00286 static char global_dateformat[8]="";
00287 gl_global_getvar("dateformat",global_dateformat,sizeof(global_dateformat));
00288 if (strcmp(global_dateformat,"ISO")==0) dateformat = ISO;
00289 else if (strcmp(global_dateformat,"US")==0) dateformat = US;
00290 else if (strcmp(global_dateformat,"EURO")==0) dateformat = EURO;
00291 else dateformat = ISO;
00292 }
00293
00294 Retry:
00295 result = my->ops->read(my, buffer, sizeof(buffer));
00296
00297 memset(timebuf, 0, 64);
00298 memset(valbuf, 0, 1024);
00299 memset(tbuf, 0, 64);
00300 memset(value, 0, 1024);
00301 memset(tz, 0, 6);
00302 if (result==NULL)
00303 {
00304 if (my->loopnum>0)
00305 {
00306 rewind_player(my);
00307 my->loopnum--;
00308 goto Retry;
00309 }
00310 else {
00311 close_player(my);
00312 my->status=TS_DONE;
00313 my->next.ts = TS_NEVER;
00314 my->next.ns = 0;
00315 goto Done;
00316 }
00317 }
00318 if (result[0]=='#' || result[0]=='\n')
00319 goto Retry;
00320
00321 if(sscanf(result, "%32[^,],%1024[^\n\r;]", tbuf, valbuf) == 2){
00322 trim(tbuf, timebuf);
00323 trim(valbuf, value);
00324 if (sscanf(timebuf,"%d-%d-%d %d:%d:%lf %4s",&Y,&m,&d,&H,&M,&S, tz)==7){
00325
00326 DATETIME dt;
00327 switch ( dateformat ) {
00328 case ISO:
00329 dt.year = Y;
00330 dt.month = m;
00331 dt.day = d;
00332 break;
00333 case US:
00334 dt.year = d;
00335 dt.month = Y;
00336 dt.day = m;
00337 break;
00338 case EURO:
00339 dt.year = d;
00340 dt.month = m;
00341 dt.day = Y;
00342 break;
00343 }
00344 dt.hour = H;
00345 dt.minute = M;
00346 dt.second = (unsigned short)S;
00347 dt.nanosecond = (unsigned int)(1e9*(S-dt.second));
00348 strcpy(dt.tz, tz);
00349 t1 = (TIMESTAMP)gl_mktime(&dt);
00350 if ((obj->flags & OF_DELTAMODE)==OF_DELTAMODE)
00351 enable_deltamode(dt.nanosecond==0?TS_NEVER:t1);
00352 if (t1!=TS_INVALID && my->loop==my->loopnum){
00353 my->next.ts = t1;
00354 my->next.ns = dt.nanosecond;
00355 while(value[voff] == ' '){
00356 ++voff;
00357 }
00358 strcpy(my->next.value, value+voff);
00359 }
00360 }
00361 else if (sscanf(timebuf,"%d-%d-%d %d:%d:%lf",&Y,&m,&d,&H,&M,&S)>=4)
00362 {
00363
00364 DATETIME dt;
00365 switch ( dateformat ) {
00366 case ISO:
00367 dt.year = Y;
00368 dt.month = m;
00369 dt.day = d;
00370 break;
00371 case US:
00372 dt.year = d;
00373 dt.month = Y;
00374 dt.day = m;
00375 break;
00376 case EURO:
00377 dt.year = d;
00378 dt.month = m;
00379 dt.day = Y;
00380 break;
00381 }
00382 dt.hour = H;
00383 dt.minute = M;
00384 dt.second = (unsigned short)S;
00385 dt.tz[0] = 0;
00386 dt.nanosecond = (unsigned int)(1e9*(S-dt.second));
00387 t1 = (TIMESTAMP)gl_mktime(&dt);
00388 if ((obj->flags & OF_DELTAMODE)==OF_DELTAMODE)
00389 enable_deltamode(dt.nanosecond==0?TS_NEVER:t1);
00390 if (t1!=TS_INVALID && my->loop==my->loopnum){
00391 my->next.ts = t1;
00392 my->next.ns = dt.nanosecond;
00393 while(value[voff] == ' '){
00394 ++voff;
00395 }
00396 strcpy(my->next.value, value+voff);
00397 }
00398 }
00399 else if (sscanf(timebuf,"%" FMT_INT64 "d%1s", &t1, unit)==2)
00400 {
00401 {
00402 int64 scale=1;
00403 switch(unit[0]) {
00404 case 's': scale=TS_SECOND; break;
00405 case 'm': scale=60*TS_SECOND; break;
00406 case 'h': scale=3600*TS_SECOND; break;
00407 case 'd': scale=86400*TS_SECOND; break;
00408 default: break;
00409 }
00410 t1 *= scale;
00411 if (result[0]=='+'){
00412 my->next.ts += t1;
00413 while(value[voff] == ' '){
00414 ++voff;
00415 }
00416 strcpy(my->next.value, value+voff);
00417 } else if (my->loop==my->loopnum){
00418 my->next.ts = t1;
00419 while(value[voff] == ' '){
00420 ++voff;
00421 }
00422 strcpy(my->next.value, value+voff);
00423 }
00424 }
00425 }
00426 else if (sscanf(timebuf,"%lf", &S)==1)
00427 {
00428 if (my->loop==my->loopnum) {
00429 my->next.ts = (unsigned short)S;
00430 my->next.ns = (unsigned int)(1e9*(S-my->next.ts));
00431 if ((obj->flags & OF_DELTAMODE)==OF_DELTAMODE)
00432 enable_deltamode(my->next.ns==0?TS_NEVER:t1);
00433 while(value[voff] == ' '){
00434 ++voff;
00435 }
00436 strcpy(my->next.value, value+voff);
00437 }
00438 }
00439 else
00440 {
00441 gl_warning("player was unable to parse timestamp \'%s\'", result);
00442 }
00443 } else {
00444 gl_warning("player was unable to split input string \'%s\'", result);
00445 }
00446
00447 Done:
00448 return my->next.ns==0 ? my->next.ts : (my->next.ts+1);
00449 }
00450
00451 EXPORT TIMESTAMP sync_player(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00452 {
00453 struct player *my = OBJECTDATA(obj,struct player);
00454 TIMESTAMP t1 = (TS_OPEN == my->status) ? my->next.ts : TS_NEVER;
00455 TIMESTAMP temp_t;
00456
00457 if (my->status==TS_INIT){
00458
00459
00460 if (my->target==NULL && obj->parent == NULL)
00461 my->target = gl_get_property(obj,"value",NULL);
00462
00463 if(player_open(obj) == 0)
00464 {
00465 gl_error("sync_player: Unable to open player file '%s' for object '%s'", my->file, obj->name?obj->name:"(anon)");
00466 }
00467 else
00468 {
00469 t1 = player_read(obj);
00470 }
00471 }
00472 while (my->status==TS_OPEN && t1<=t0
00473 && my->next.ns==0 )
00474 {
00475 if (my->target==NULL)
00476 my->target = player_link_properties(my, obj->parent, my->property);
00477 if (my->target==NULL){
00478 gl_error("sync_player: Unable to find property \"%s\" in object %s", my->property, obj->name?obj->name:"(anon)");
00479 my->status = TS_ERROR;
00480 }
00481 if (my->target!=NULL)
00482 {
00483 OBJECT *target = obj->parent ? obj->parent : obj;
00484 player_write_properties(my, target, my->target, my->next.value);
00485 }
00486
00487
00488 my->delta_track.ns = my->next.ns;
00489 my->delta_track.ts = my->next.ts;
00490 memcpy(my->delta_track.value,my->next.value,sizeof(char1024));
00491
00492 t1 = player_read(obj);
00493 }
00494
00495
00496 if ((my->target!=NULL) && (my->delta_track.ts<t0) && (my->delta_track.ns!=0))
00497 {
00498 OBJECT *target = obj->parent ? obj->parent : obj;
00499 player_write_properties(my, target, my->target, my->delta_track.value);
00500 }
00501
00502
00503 if (((obj->flags & OF_DELTAMODE)!=OF_DELTAMODE) && (my->next.ns != 0) && (my->status==TS_OPEN))
00504 {
00505
00506 temp_t = t1;
00507
00508
00509 if (my->target==NULL)
00510 my->target = player_link_properties(my, obj->parent, my->property);
00511 if (my->target==NULL){
00512 gl_error("sync_player: Unable to find property \"%s\" in object %s", my->property, obj->name?obj->name:"(anon)");
00513 my->status = TS_ERROR;
00514 }
00515
00516
00517 while ((my->next.ns != 0) && (my->next.ts<=t0))
00518 {
00519
00520
00521 if ((my->target!=NULL) && (my->next.ts<t0))
00522 {
00523 OBJECT *target = obj->parent ? obj->parent : obj;
00524 player_write_properties(my, target, my->target, my->next.value);
00525 }
00526
00527
00528 my->delta_track.ns = my->next.ns;
00529 my->delta_track.ts = my->next.ts;
00530 memcpy(my->delta_track.value,my->next.value,sizeof(char1024));
00531
00532
00533 temp_t = player_read(obj);
00534 }
00535
00536
00537 t1 = temp_t;
00538 }
00539 else if (((obj->flags & OF_DELTAMODE)==OF_DELTAMODE) && (delta_mode_needed<t0))
00540 {
00541 if (my->next.ts<t0)
00542 {
00543
00544 while ((my->next.ns != 0) && (my->next.ts<=t0))
00545 {
00546
00547
00548 if ((my->target!=NULL) && (my->next.ts<t0))
00549 {
00550 OBJECT *target = obj->parent ? obj->parent : obj;
00551 player_write_properties(my, target, my->target, my->next.value);
00552 }
00553
00554
00555 my->delta_track.ns = my->next.ns;
00556 my->delta_track.ts = my->next.ts;
00557 memcpy(my->delta_track.value,my->next.value,sizeof(char1024));
00558
00559
00560 temp_t = player_read(obj);
00561 }
00562
00563
00564 if (t1 < t0)
00565 {
00566
00567 t1 = temp_t;
00568 }
00569 else
00570 {
00571 if ((temp_t<t1) && (temp_t>t0))
00572 t1 = temp_t;
00573 }
00574 }
00575 else if (my->next.ts == t0)
00576 {
00577
00578
00579 my->delta_track.ns = my->next.ns;
00580 my->delta_track.ts = my->next.ts;
00581 memcpy(my->delta_track.value,my->next.value,sizeof(char1024));
00582
00583
00584 temp_t = player_read(obj);
00585 }
00586 }
00587
00588
00589 if ((my->delta_track.ts!=TS_NEVER) && (my->delta_track.ns != 0))
00590 {
00591
00592 temp_t = my->delta_track.ts+1;
00593
00594
00595 if ((temp_t<t1) && (temp_t>t0))
00596 t1 = temp_t;
00597 }
00598
00599
00600 if ((obj->flags & OF_DELTAMODE) == OF_DELTAMODE)
00601 {
00602 if ((t1>t0) && (my->next.ts==t0) && (my->next.ns != 0))
00603 {
00604
00605 t1 = t0;
00606 }
00607
00608
00609 if ((my->next.ts == gl_globalstoptime) && (my->next.ns != 0) && (t1 == gl_globalstoptime))
00610 {
00611
00612 t1 = t1 + 1;
00613 }
00614 }
00615
00616 obj->clock = t0;
00617 return t1;
00618 }
00619