plc/machine.cpp

Go to the documentation of this file.
00001 
00073 
00074 
00075 #include <stdlib.h>
00076 #include <stdarg.h>
00077 #ifdef WIN32
00078 #include <direct.h>
00079 #define getcwd _getcwd
00080 #define putenv _putenv
00081 #else
00082 #include <unistd.h>
00083 #include <dlfcn.h>
00084 #endif
00085 #include "machine.h"
00086 #include "plc.h"
00087 #include "comm.h"
00088 
00089 #ifdef WIN32
00090 char path[1024] = "c:/mingw/bin";
00091 char tmpdir[1024] = "c:/temp";
00092 #else
00093 char path[1024] = "/usr/bin";
00094 char tmpdir[1024] = "/tmp";
00095 #endif
00096 
00097 int exec(char *format,...)
00098 {
00099     char cmd[1024];
00100     va_list ptr;
00101     va_start(ptr,format);
00102     vsprintf(cmd,format,ptr);
00103     va_end(ptr);
00104     gl_debug("Running '%s'", cmd);
00105     return system(cmd);
00106 }
00107 
00108 void sendx(machine *src, char *to, void *str, unsigned int len)
00109 {
00110     if (len==0)
00111         len=(unsigned int)strlen((char*)str);
00112     OBJECT *obj = gl_get_object(to);
00113     if (obj)
00114     {
00115         machine *dst = OBJECTDATA(obj,plc)->get_machine();
00116         src->send(new Message(str,len,src,dst));
00117     }
00118     else
00119         gl_error("sendx(machine=%x, to='%s', str='%-.8s%s', len=%d): message recipient '%s' not found", src, to, (char*)str, len>8?"...":"", len, to);
00120 }
00121 
00122 int recvx(machine *dst, char *from, void *str, unsigned int len)
00123 {
00124     Message *msg = dst->receive();
00125     if (msg!=NULL)
00126     {
00127         unsigned int sz = (unsigned int)msg->get_size()+1;
00128         if (sz>len) sz=len;
00129         memcpy(str,msg->get_data(),sz);
00130         strcpy(from,"(unknown)");
00131         return sz;
00132     }
00133     else 
00134         return 0;
00135 }
00136 
00137 machine::machine(void)
00138 : _link()
00139 {
00140     _code=NULL;
00141     _init=NULL;
00142     _data=NULL;
00143     wait=-1;
00144 }
00145 
00146 machine::~machine(void)
00147 {
00148 }
00149 
00150 // COMPILE
00151 // This function load a source file and generates
00152 // a machine that can be executed
00153 // RETURN
00154 //   -1 - failed
00155 //   0 - succeeded
00156 int machine::compile(char *source)
00157 {
00158     extern char libpath[1024], incpath[1024];
00159     char cfile[1024];
00160     char ofile[1024];
00161     char lfile[1024];
00162     char name[64], *basename;
00163     char *pSlash, *pDot;
00164     char oldpath[1024]="", newpath[1024];
00165     char buffer[1024];
00166     FILE *fp;
00167 
00168     /* path */
00169     if (getenv("PATH")) strcpy(oldpath, getenv("PATH"));
00170     if (strcmp(oldpath,"")==0)
00171         sprintf(newpath,"PATH=%s",path);
00172     else
00173         sprintf(newpath,"PATH=%s;%s",path,oldpath);
00174     putenv(newpath);
00175 
00176     /* build the basename */
00177     strcpy(name,source);
00178     pSlash = strrchr(name,'/');
00179     pDot = strrchr(name,'.');
00180     if (pDot!=NULL && pDot>pSlash)
00181         *pDot='\0';
00182     basename = (pSlash==NULL ? name : pSlash+1);
00183     sprintf(cfile,"%s/%s.c", tmpdir,basename);
00184     sprintf(ofile,"%s/%s.o", tmpdir,basename);
00185 
00186 #ifdef WIN32
00187     sprintf(lfile,"%s/%s.dll", tmpdir,basename);
00188 #else
00189     sprintf(lfile,"%s/lib%s.so", tmpdir,basename);
00190 #endif
00191 
00192     /* build source code */
00193     gl_verbose("converting %s to %s...", source, cfile);
00194     fp=fopen(cfile,"w");
00195     if (fp==NULL)
00196     {
00197         gl_error("%s: %s", cfile, strerror(errno));
00198         return -1;
00199     }
00200     fprintf(fp,"/* this code automatically generated by gridlab-d " __FILE__ "*/\n");
00201     fprintf(fp,"/* wd=%s */\n", getcwd(buffer,sizeof(buffer)));
00202     fprintf(fp,"#include <plc.h>\n");
00203     fprintf(fp,"#include \"%s/%s\"\n", buffer,source);
00204     fprintf(fp,"/* END */\n");
00205     fclose(fp);
00206 
00207     /* compile source */
00208     gl_verbose("compiling %s from %s using incpath '%s'...", ofile, cfile,incpath);
00209     if (exec("gcc -I%s -c %s -o %s",incpath,cfile,ofile)!=0)
00210         return -1;
00211 
00212     /* link */
00213     gl_verbose("converting %s to dynamic link library...", ofile);
00214     if (exec("gcc -export-all-symbols -shared -o %s -Wl,%s", lfile,ofile)!=0)
00215         return -1;
00216 
00217     /* load the code (loader is in main.cpp) */
00218     gl_verbose("loading dynamic link library %s...", ofile);
00219     wait = load_library(lfile,&_code,&_init,&_data);
00220     if (wait<0)
00221     {
00222 #ifdef WIN32
00223         gl_error("%s: %s", lfile, strerror(errno));
00224 #else
00225         gl_error("%s: %s", lfile, dlerror());
00226 #endif
00227         return -1;
00228     }
00229     if (_code==NULL)
00230     {
00231         gl_error("%s: CODE block not found", source);
00232         return -1;
00233     }
00234     if (_init==NULL)
00235     {
00236         gl_error("%s: INIT block not found", source);
00237         return -1;
00238     }
00239     if (_data==NULL)
00240     {
00241         gl_error("%s: DATA block not found", source);
00242         return -1;
00243     }
00244     return 0;
00245 }
00246 
00247 // INIT
00248 // Initializes the machine
00249 // RETURN
00250 //   -1 - failed
00251 //    0 - succeeded
00252 //    n - succeeded, wait n seconds before calling run
00253 int machine::init(OBJECT *parent)
00254 {
00255     gl_debug("Connecting PLC to %s:%d...", parent->oclass->name, parent->id);
00256     PLCDATA item;
00257     for (item=_data; item->name!=NULL; item++)
00258     {
00259         PROPERTY *p = gl_get_property(parent,item->name);
00260         if (p==NULL)
00261         {
00262             gl_error("PCL data item %s is not found in object %s:%d", item->name, parent->oclass->name, parent->id);
00263             return -1;
00264         }
00265         else if (item->type!=p->ptype)
00266         {
00267             gl_error("PLC data item %s does not match parent's type", item->name);
00268             return -1;
00269         }
00270         else
00271             item->addr = (void*)((char*)(parent+1)+(unsigned int64)p->addr);
00272     }
00273     gl_debug("Initializing %s:%d PLC...", parent->oclass->name, parent->id);
00274     return (*_init)();
00275 }
00276 
00277 // RUN
00278 // Runs the machine once through
00279 // RETURN
00280 //   -1 - failed
00281 //    0 - succeeded, call again asap
00282 //    n - succeeded, call again after n seconds
00283 int machine::run(double dt)
00284 {
00285     extern TIMESTAMP *pGlobalClock;
00286     static PLCDEV dev = {(unsigned int)((*pGlobalClock)/TS_SECOND),{&sendx,&recvx}};
00287     return (*_code)(this,dt,&dev);
00288 }
00289 
00290 void machine::connect(comm *ptr)
00291 {
00292     net = ptr;
00293 }
00294 
00295 void machine::deliver(Message *msg)
00296 {
00297     _link.add(msg);
00298 }
00299 
00300 Message *machine::receive(void)
00301 {
00302     return _link.take();
00303 }
00304 
00305 void machine::send(Message *msg)
00306 {
00307     net->route(msg);
00308 }
00309 
00310 void machine::send(char *to, void *str, size_t len)
00311 {
00312     if (len==0)
00313         len=strlen((char*)str);
00314     OBJECT *obj = gl_get_object(to);
00315     machine *dst = OBJECTDATA(obj,plc)->get_machine();
00316     send(new Message(str,len,this,dst));
00317 }
00318 

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