plc/comm.cpp

Go to the documentation of this file.
00001 
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <errno.h>
00028 #include <math.h>
00029 #include "gridlabd.h"
00030 #include "comm.h"
00031 
00032 unsigned int64 Message::next_id = 0;
00033 
00035 // Queue implementation
00036 Queue::Queue(void)
00037 {
00038     gl_verbose("creating queue %x", this);
00039     first = last = NULL;
00040 }
00041 Queue::~Queue(void)
00042 {
00043     gl_verbose("destroying queue %x", this);
00044     while (first!=NULL)
00045     {
00046         Message *next = first->get_next();
00047         delete first;
00048         first = next;
00049     }
00050 }
00051 void Queue::add(Message *msg)
00052 {
00053     // @todo message need to be sorted by delivery time
00054     if (first==NULL)
00055         first = last = msg;
00056     else
00057     {
00058         msg->set_prev(last);
00059         last->set_next(msg);
00060     }
00061     msg->set_next(NULL);
00062     gl_verbose("message %"FMT_INT64"d '%-8.8s%s' added to queue %x", msg->get_id(), msg->get_data(), msg->get_size()>8?"...":"", this);
00063 }
00064 Message *Queue::peek(void)
00065 {
00066     return first;
00067 }
00068 Message *Queue::take(Message *msg)
00069 {
00070     if (msg==NULL)
00071         msg = first;
00072     if (msg==NULL)
00073         return NULL;
00074     Message *prev = msg->get_prev();
00075     Message *next = msg->get_next();
00076     if (prev!=NULL)
00077         prev->set_next(next);
00078     else
00079         first = next;
00080     if (next!=NULL)
00081         next->set_prev(prev);
00082     else
00083         last = prev;
00084     return msg;
00085 }
00086 Message *Queue::next(Message *msg)
00087 {
00088     return msg?msg->get_next():first;
00089 }
00090 
00091 Message *Queue::drop(Message *msg, bool reverse)
00092 {
00093     Message *prev = msg->get_prev();
00094     Message *next = msg->get_next();
00095     if (msg!=NULL)
00096         delete take(msg);
00097     return reverse?prev:next;
00098 }
00099 
00100 TIMESTAMP Queue::next_delivery_time(void)
00101 {
00102     return first ? first->get_deliverytime() : TS_NEVER;
00103 }
00104 
00106 // comm implementation
00107 CLASS *comm::oclass = NULL; 
00108 comm *comm::defaults = NULL; 
00109 
00110 void comm::route(Message *msg)
00111 {
00112     msg->set_deliverytime((TIMESTAMP)(gl_randomvalue(rtype,a,b)/TS_SECOND)+OBJECTHDR(this)->clock);
00113     DATETIME dt;
00114     char ts[64]="unknown time";
00115     gl_localtime(msg->get_deliverytime(),&dt);
00116     gl_strtime(&dt,ts,sizeof(ts));
00117     gl_verbose("message %"FMT_INT64"d from %x to %x will be delivered at %s", msg->get_id(), msg->get_src(), msg->get_dst(), ts);
00118     queue.add(msg);
00119 }
00120 
00121 void comm::route(comm *net, Message *msg)
00122 {
00123     net->queue.add(msg);
00124 }
00125 
00127 comm::comm(MODULE *mod)
00128 : queue()
00129 {
00130     // first time init
00131     if (oclass==NULL)
00132     {
00133         // register the class definition
00134         oclass = gl_register_class(mod,"comm",PC_PRETOPDOWN);
00135 
00136         // publish the class properties
00137         if (gl_publish_variable(oclass,
00138             PT_char256,"latency", PADDR(latency),
00139             PT_double,"reliability[pu]", PADDR(reliability),
00140             PT_double,"bitrate[b/s]",PADDR(bitrate),
00141             PT_double,"timeout[s]",PADDR(timeout),
00142             NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00143 
00144         // set defaults
00145         strcpy(latency,"random.degenerate(0)"); // instant delivery always
00146         reliability=1.0; // 100% reliable delivery
00147         bitrate=0.0; // not rate limit
00148         timeout=60; // 1 minute timeout on message delivery
00149         defaults = this;
00150     }
00151 }
00152 
00154 int comm::create()
00155 {
00156     // copy the defaults
00157     memcpy(this,defaults,sizeof(comm));
00158 
00159     // set object specific defaults
00160     return 1;
00161 }
00162 
00164 int comm::init(OBJECT *parent)
00165 {
00166     char32 rt;
00167     if (sscanf(latency,"%31[^(](%lf,%lf)",rt,&a,&b)==3)
00168         rtype = gl_randomtype(rt);
00169     else if (sscanf(latency,"%31[^(](%f)",rt,&a)==2)
00170     {
00171         b=0;
00172         rtype = gl_randomtype(rt);
00173     }
00174     else
00175     {
00176         gl_error("latency distribution '%s' is not valid", latency);
00177         return 0;
00178     }
00179     
00180     return 1; // return 0 on failure
00181 }
00182 
00184 TIMESTAMP comm::sync(TIMESTAMP t0)
00185 {
00186     if (queue.is_empty())
00187         return TS_NEVER;
00188     Message *msg=NULL;
00189     while ((msg=queue.next(msg))!=NULL)
00190     {
00191         if (msg->get_deliverytime()<=t0)
00192         {
00193             DATETIME dt;
00194             char ts[64]="unknown time";
00195             gl_localtime(t0,&dt);
00196             gl_strtime(&dt,ts,sizeof(ts));
00197             gl_verbose("message %"FMT_INT64"d delivered at %s", msg->get_id(), ts);
00198             queue.take(msg)->get_dst()->deliver(msg);
00199         }
00200         else if (msg->get_deliverytime()<=t0+timeout*TS_SECOND)
00201         {
00202             DATETIME dt;
00203             char ts[64];
00204             gl_localtime(t0,&dt);
00205             gl_strtime(&dt,ts,sizeof(ts));
00206             gl_warning("message %"FMT_INT64"d delivery timeout at %s", msg->get_id(), ts);
00207             msg = queue.drop(msg,true);
00208         }
00209     }
00210     return queue.next_delivery_time(); // return TS_ZERO on failure, or TIMESTAMP for pending event
00211 }
00212 
00214 // IMPLEMENTATION OF CORE LINKAGE
00216 EXPORT int create_comm(OBJECT **obj, OBJECT *parent)
00217 {
00218     *obj = gl_create_object(comm::oclass,sizeof(comm));
00219     if (*obj!=NULL)
00220         return OBJECTDATA(*obj,comm)->create();
00221     return 0;
00222 }
00223 
00224 EXPORT int init_comm(OBJECT *obj)
00225 {
00226     if (obj!=NULL)
00227         return OBJECTDATA(obj,comm)->init(obj->parent);
00228     return 0;
00229 }
00230 
00231 EXPORT TIMESTAMP sync_comm(OBJECT *obj, TIMESTAMP t0)
00232 {
00233     TIMESTAMP t1 = OBJECTDATA(obj,comm)->sync(t0);
00234     obj->clock = t0;
00235     return t1;
00236 }
00237 
00239 // IMPLEMENTATION OF COMM LINKAGE
00241 

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