core/cmex.c

Go to the documentation of this file.
00001 
00018 #include <stdlib.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <math.h>
00022 #include <signal.h>
00023 #include <conio.h>
00024 #include <stdarg.h>
00025 #include <ctype.h>
00026 #include "mex.h"
00027 
00028 #define _MAIN_C
00029 
00030 #include "globals.h"
00031 #include "module.h"
00032 #include "load.h"
00033 #include "exec.h"
00034 #include "legal.h"
00035 #include "output.h"
00036 #include "object.h"
00037 #include "convert.h"
00038 #include "find.h"
00039 
00040 #define MAXNAME 256
00041 #define MATLABDATETIME(X) ((double)(X)/TS_SECOND/86400 + 719529)
00042 
00043 typedef enum {MH_GLOBAL=0x19c3, MH_OBJECT=0x82a3, MH_CLASS=0x5d37, MH_MODULE=0xb40f} MEXHANDLETYPE; /* number carefully chosen to mean nothing */
00044 
00045 static mxArray *make_handle(MEXHANDLETYPE type, void *ptr)
00046 {
00047     mxArray *handle = mxCreateNumericMatrix(1,2,mxINT64_CLASS,mxREAL);
00048     unsigned int64 *data = (unsigned int64*)mxGetPr(handle);
00049     data[0] = type;
00050     data[1] = (unsigned int64)ptr;
00051     return handle;
00052 }
00053 
00054 static char *make_fieldname(char *str)
00055 {
00056     char *p;
00057     for (p=str; *p!='\0'; p++)
00058         if (!isalnum(*p))
00059             *p = '_';
00060     return str;
00061 }
00062 
00063 static OBJECT *find_object(mxArray *handle)
00064 {
00065     unsigned int64 *data = (unsigned int64*)mxGetPr(handle);
00066     return data[0]==MH_OBJECT ? (OBJECT*)data[1] : NULL;
00067 }
00068 
00069 static GLOBALVAR *find_global(mxArray *handle)
00070 {
00071     unsigned int64 *data = (unsigned int64*)mxGetPr(handle);
00072     return data[0]==MH_GLOBAL ? (GLOBALVAR*)data[1] : NULL;
00073 }
00074 
00075 static CLASS *find_class(mxArray *handle)
00076 {
00077     unsigned int64 *data = (unsigned int64*)mxGetPr(handle);
00078     return data[0]==MH_CLASS ? (CLASS*)data[1] : NULL;
00079 }
00080 
00081 static MODULE *find_module(mxArray *handle)
00082 {
00083     unsigned int64 *data = (unsigned int64*)mxGetPr(handle);
00084     return data[0]==MH_MODULE ? (MODULE*)data[1] : NULL;
00085 }
00086 
00087 static mxArray *get_object_data(OBJECT *obj)
00088 {
00089     mxArray *plhs[1];
00090 
00091     /* set the standard info */
00092 #define ERROR "(error)"
00093 #define NONE "(none)"
00094     char *fnames[1024] = {"id","class","parent","rank","clock","latitude","longitude","in_svc","out_svc","flags",NULL}; // };
00095     int nFields = 0;
00096     int nData = 0;
00097     char value[1024];
00098     PROPERTY *prop;
00099     mxArray *pId = mxCreateString(convert_from_object(value,sizeof(value),&obj,NULL)?value:ERROR);
00100     mxArray *pClass = mxCreateString(obj->oclass->name);
00101     mxArray *pParent = mxCreateString(obj->parent!=NULL&&convert_from_object(value,sizeof(value),&(obj->parent),NULL)?value:NONE);
00102     mxArray *pRank = mxCreateNumericMatrix(1,1,mxUINT32_CLASS,mxREAL);
00103     mxArray *pClock = mxCreateString(convert_from_timestamp(obj->clock,value,sizeof(value))?value:ERROR);
00104     mxArray *pLatitude = mxCreateString(convert_from_latitude(obj->latitude,value,sizeof(value))?value:NONE);
00105     mxArray *pLongitude = mxCreateString(convert_from_longitude(obj->longitude,value,sizeof(value))?value:NONE);
00106     mxArray *pInSvc = mxCreateString(convert_from_timestamp(obj->in_svc,value,sizeof(value))?value:ERROR);
00107     mxArray *pOutSvc = mxCreateString(convert_from_timestamp(obj->out_svc,value,sizeof(value))?value:ERROR);
00108     mxArray *pFlags = mxCreateString(convert_from_set(value,sizeof(value),(void*)&obj->flags,object_flag_property())?value:ERROR);
00109 
00110     *(OBJECTRANK*)mxGetPr(pRank) = obj->rank;
00111 
00112     /* count the number of header items */
00113     while (fnames[nFields]!=NULL) nFields++;
00114 
00115     /* count the number of object properties and assign the field names */
00116     for (prop=class_get_first_property(obj->oclass);  prop!=NULL; prop=class_get_next_property(prop))
00118         fnames[nFields+nData++] = make_fieldname(prop->name);
00119 
00120     /* construct the return value */
00121     plhs[0] = mxCreateStructMatrix(1,1,nFields+nData,fnames);
00122 
00123     /* construct the header fields */
00124     mxSetFieldByNumber(plhs[0],0,0,pId);
00125     mxSetFieldByNumber(plhs[0],0,1,pClass);
00126     mxSetFieldByNumber(plhs[0],0,2,pParent);
00127     mxSetFieldByNumber(plhs[0],0,3,pRank);
00128     mxSetFieldByNumber(plhs[0],0,4,pClock);
00129     mxSetFieldByNumber(plhs[0],0,5,pLatitude);
00130     mxSetFieldByNumber(plhs[0],0,6,pLongitude);
00131     mxSetFieldByNumber(plhs[0],0,7,pInSvc);
00132     mxSetFieldByNumber(plhs[0],0,8,pOutSvc);
00133     mxSetFieldByNumber(plhs[0],0,9,pFlags);
00134 
00135     /* construct the data fields */
00136     for (prop=class_get_first_property(obj->oclass);  prop!=NULL; nFields++,prop=class_get_next_property(prop))
00137     {
00138         mxArray *pValue;
00139         if (prop->ptype==PT_double)
00140         {
00141             pValue = mxCreateDoubleMatrix(1,1,mxREAL);
00142             *(double*)mxGetPr(pValue) = *object_get_double(obj,prop);
00143         }
00144         else if (prop->ptype==PT_int32)
00145         {
00146             pValue = mxCreateDoubleMatrix(1,1,mxREAL);
00147             *(double*)mxGetPr(pValue) = (double)*object_get_int32(obj,prop);
00148         }
00149         else if (prop->ptype==PT_complex)
00150         {
00151             complex *pData = object_get_complex(obj,prop);
00152             pValue = mxCreateDoubleMatrix(1,1,mxCOMPLEX);
00153             *(double*)mxGetPr(pValue) = pData->r;
00154             *(double*)mxGetPi(pValue) = pData->i;
00155         }
00156         else 
00157         {
00158             pValue = mxCreateString(object_get_value_by_name(obj,prop->name,value,sizeof(value))?value:ERROR);
00159         }
00160         mxSetFieldByNumber(plhs[0],0,nFields,pValue);
00161     }
00162     return plhs[0];
00163 }
00164 
00165 static void set_object_data(const mxArray *data)
00166 {
00167     OBJECT *obj;
00168     mxArray *pId = mxGetField(data,0,"id");
00169     char id[256];
00170     if (pId==NULL)
00171         output_error("set_object_data(const mxArray *data={...}) did not find a required object id field");
00172     else if (mxGetString(pId,id,sizeof(id)))
00173         output_error("set_object_data(const mxArray *data={...}) couldn't read the object id field");
00174     else if ((obj=object_find_name(id))==NULL)
00175         output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't find object id", id);
00176     else
00177     {
00178         int i;
00179         for (i=0; i<mxGetNumberOfFields(data); i++)
00180         {   
00181             const char *name;
00182             const mxArray *pField = mxGetFieldByNumber(data,0,i);
00183             char value[4096];
00184             if ((name=mxGetFieldNameByNumber(data,i))==NULL)
00185                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the name of field %d", id, i);
00186             else if (strcmp(name,"id")==0 || strcmp(name,"class")==0)
00187             {   /* these may not be changed */ }
00188             else if (pField==NULL)
00189                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the object field '%s' for object '%s'", id, name);
00190             else if (mxIsChar(pField) && mxGetString(pField,value,sizeof(value)))
00191                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the string value '%s' from field '%s'", id, value, name);
00192             else if (mxIsDouble(pField) && sprintf(value,"%lg",*(double*)mxGetPr(pField))<1)
00193                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the double value '%lg' from field '%s'", id, *(double*)mxGetPr(pField), name);
00194             else if (mxIsComplex(pField) && sprintf(value,"%lg%+lgi",*(double*)mxGetPr(pField),*(double*)mxGetPi(pField))<1)
00195                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the complex value '%lg%+lgi' from field '%s'", id, *(double*)mxGetPr(pField), *(double*)mxGetPi(pField), name);
00196             else if (mxIsUint32(pField) && sprintf(value,"%lu",*(unsigned int*)mxGetPr(pField))<1)
00197                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the uint32 value '%lu' from field '%s'", id, *(unsigned int*)mxGetPr(pField), name);
00198             else if (strcmp(value,ERROR)==0)
00199                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't use error value '%s'", id, value);
00200             else if (strcmp(value,NONE)==0 && strcpy(value,"")==NULL)
00201                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't clear empty value '%s'", id, value);
00202             else if (!object_set_value_by_name(obj,name,value))
00203                 output_error("set_object_data(const mxArray *data={id='%s',...}) couldn't read the value '%s' into property '%s'", id, value, name);
00204         }
00205     }
00206 }
00207 
00208 static int cmex_printerr(char *format, ...)
00209 {
00210     int count=0;
00211     static char buffer[1024];
00212     va_list ptr;
00213     va_start(ptr,format);
00214     count += vsprintf(buffer,format,ptr);
00215     va_end(ptr);
00216     if (strncmp(buffer,"ERROR",5)==0 || strncmp(buffer,"FATAL",5)==0)
00217         mexErrMsgTxt(buffer);
00218     else if (strncmp(buffer,"WARN",4)==0)
00219         mexWarnMsgTxt(buffer);
00220     else
00221         mexPrintf("%s",buffer);
00222     return count;
00223 }
00224 
00225 void cmex_object_list(int nlhs, mxArray *plhs[], 
00226                       int nrhs, const mxArray *prhs[] ) 
00227 {
00228     OBJECT *obj;
00229     char criteria[1024]="(undefined)";
00230     FINDPGM *search = NULL;
00231     char *fields[] = {"name","class","parent","flags","location","service","rank","clock","handle"};
00232     FINDLIST *list = NULL;
00233     if (nrhs>0 && mxGetString(prhs[0],criteria,sizeof(criteria))!=0)
00234         output_error("gl('list',type='object'): unable to read search criteria (arg 2)");
00235     else if (nrhs>0 && (search=find_mkpgm(criteria))==NULL)
00236         output_error("gl('list',type='object'): unable to run search '%s'",criteria);
00237     else if (search==NULL && (list=find_objects(NULL,NULL))==NULL)
00238         output_error("gl('list',type='object'): unable to obtain default list");
00239     else if (list==NULL && (list=find_runpgm(NULL,search))==NULL)
00240         output_error("gl('list',type='object'): unable search failed");
00241     else if ((plhs[0] = mxCreateStructMatrix(list->hit_count,1,sizeof(fields)/sizeof(fields[0]),fields))==NULL)
00242         output_error("gl('list',type='object'): unable to allocate memory for result list");
00243     else
00244     {
00245         unsigned int n;
00246         for (n=0, obj=find_first(list); obj!=NULL; n++, obj=find_next(list,obj))
00247         {
00248             char tmp[1024];
00249             mxArray *data;
00250             double *pDouble;
00251             unsigned int *pInt;
00252             mxSetFieldByNumber(plhs[0], n, 0, mxCreateString(object_name(obj)));
00253             mxSetFieldByNumber(plhs[0], n, 1, mxCreateString(obj->oclass->name));
00254             mxSetFieldByNumber(plhs[0], n, 2, mxCreateString(obj->parent?object_name(obj->parent):NONE));
00255             mxSetFieldByNumber(plhs[0], n, 3, mxCreateString(convert_from_set(tmp,sizeof(tmp),&(obj->flags),object_flag_property())?tmp:ERROR));
00256             pDouble = mxGetPr(data=mxCreateDoubleMatrix(1,2,mxREAL)); pDouble[0] = obj->longitude; pDouble[1] = obj->latitude;
00257             mxSetFieldByNumber(plhs[0], n, 4, data);
00258             pDouble = mxGetPr(data=mxCreateDoubleMatrix(1,2,mxREAL)); pDouble[0] = (double)obj->in_svc/TS_SECOND; pDouble[1] = (double)obj->out_svc/TS_SECOND;
00259             mxSetFieldByNumber(plhs[0], n, 5, data);
00260             pInt = (unsigned int*)mxGetPr(data=mxCreateNumericMatrix(1,1,mxINT32_CLASS,mxREAL)); pInt[0] = obj->rank;
00261             mxSetFieldByNumber(plhs[0], n, 6, data);
00262             pDouble = mxGetPr(data=mxCreateDoubleMatrix(1,1,mxREAL)); pDouble[0] = (double)obj->clock/TS_SECOND; 
00263             mxSetFieldByNumber(plhs[0], n, 7, data);
00264             mxSetFieldByNumber(plhs[0], n, 8, make_handle(MH_OBJECT,obj));
00265         }
00266     }
00267 }
00268 
00272 void cmex_list(int nlhs, mxArray *plhs[], 
00273                int nrhs, const mxArray *prhs[] ) 
00274 {
00275     char type[32];
00276     if (nlhs>1)
00277         output_error("gl('list',type=...): returns only one value");
00278     else if (nlhs<1)
00279         return; /* nothing to do */
00280     else if (nrhs<1)
00281         output_error("gl('list',type=...): needs a type (arg 1)");
00282     else if (mxGetString(prhs[0],type,sizeof(type))==1)
00283         output_error("gl('list',type=...): type (arg 1) should be a string");
00284     else if (strcmp(type,"object")==0)
00285         cmex_object_list(nlhs,plhs,nrhs-1,prhs+1);
00286     else if (strcmp(type,"global")==0)
00287         output_error("gl('list',type='%s'): type (arg 1) not implemented",type);
00288     else if (strcmp(type,"class")==0)
00289         output_error("gl('list',type='%s'): type (arg 1) not implemented",type);
00290     else if (strcmp(type,"module")==0)
00291         output_error("gl('list',type='%s'): type (arg 1) not implemented",type);
00292     else
00293         output_error("gl('list',type='%s'): type (arg 1) not recognized",type);
00294 
00295     return;
00296 }
00297 
00301 void cmex_version(int nlhs, mxArray *plhs[], 
00302                   int nrhs, const mxArray *prhs[] ) 
00303 {
00304     /* setup result array */
00305     if (nlhs>0)
00306     {
00307         double *res = NULL;
00308         plhs[0] = mxCreateDoubleMatrix(1, 2, mxREAL);
00309         res = mxGetPr(plhs[0]);
00310         *res++ = global_version_major;
00311         *res++ = global_version_minor;
00312     }
00313     else
00314         legal_notice();
00315 
00316     return;
00317 }
00318 
00322 void cmex_global(int nlhs, mxArray *plhs[], 
00323                    int nrhs, const mxArray *prhs[] )  
00324 {
00325     char name[256];
00326     size_t nDims;
00327     const mwSize *dim;
00328     if (nlhs!=0)
00329         output_error("global does not return a value");
00330     else if (nrhs!=2)
00331         output_error("global requires a name (arg 1) and an array (arg 2)");
00332     else if (!mxIsChar(prhs[0]) || mxGetString(prhs[0],name,sizeof(name))==1)
00333         output_error("global name (arg 1) must be a string");
00334     else if ((nDims=(size_t)mxGetNumberOfDimensions(prhs[1]))<2)
00335         output_error("dimensions of array (arg 2) are not valid");
00336     else if ((dim=mxGetDimensions(prhs[1]))==NULL)
00337         output_error("dimensions of array (arg 2) are not available");
00338     else
00339     {
00340         size_t size=1;
00341         while (nDims-->0) 
00342             size*=dim[nDims];
00343         if (mxIsChar(prhs[1]))
00344         {
00345             char *buffer = malloc(1024);
00346             if(mxGetString(prhs[1],buffer,1024) && global_create(name,PT_char1024,buffer,PT_SIZE,1,NULL)==NULL)
00347                 output_error("unable to register string variable '%s' in globals", name);
00348         }
00349         else if (mxIsDouble(prhs[1]))
00350         {
00351             double *x = malloc(sizeof(double)*size);
00352             unsigned int i;
00353             memset(x,0,sizeof(double)*size);
00354             for (i=0; i<size; i++)
00355                 x[i] = ((double*)mxGetPr(prhs[1]))[i];
00356             if (global_create(name,PT_double,x,PT_SIZE,size,NULL)==NULL)
00357                 output_error("unable to register double array variable '%s' in globals", name);
00358         }
00359         else if (mxIsComplex(prhs[1]))
00360         {
00361             complex *x = (complex*)malloc(sizeof(complex)*size);
00362             unsigned int i;
00363             memset(x,0,sizeof(complex)*size);
00364             for (i=0; i<size; i++)
00365             {
00366                 x[i].r = ((double*)mxGetPr(prhs[1]))[i];
00367                 x[i].i = ((double*)mxGetPi(prhs[1]))[i];
00368                 x[i].f = I;
00369             }
00370             if (global_create(name,PT_complex,x,PT_SIZE,size,NULL)==NULL)
00371                 output_error("unable to register complex array variable '%s' in globals", name);
00372             free(x);
00373         }
00374         else if (mxIsStruct(prhs[1]))
00375         {
00376             output_error("unable to register struct variable '%s' in globals", name);
00377         }
00378         else 
00379             output_error("array (arg 2) type is not supported");
00380     }
00381 }
00382 
00386 void cmex_setenv(int nlhs, mxArray *plhs[], 
00387                    int nrhs, const mxArray *prhs[] ) 
00388 {
00389     if (nrhs>1)
00390     {
00391         char name[1024];
00392         char value[1024];
00393         if (!mxIsChar(prhs[0]))
00394             output_error("variable name is not a string");
00395         else if (!mxIsChar(prhs[1]))
00396             output_error("value is not a string");
00397         else if (nlhs>0)
00398             output_error("setenv does not return a value");
00399         else if (mxGetString(prhs[0],name,sizeof(name))!=0)
00400             output_error("variable name too long");
00401         else if (mxGetString(prhs[1],value,sizeof(value))!=0)
00402             output_error("value too long");
00403         else 
00404         {
00405             char env[2050];
00406             if (sprintf(env,"%s=%s", name, value)<0)
00407                 output_error("unable to make environment value");
00408             else if (putenv(env)<0)
00409                 output_error("unable to save environment value");
00410         }
00411     }
00412     else
00413         output_error("environment name and value not specified");
00414     return;
00415 }
00416 
00420 void cmex_getenv(int nlhs, mxArray *plhs[], 
00421                    int nrhs, const mxArray *prhs[] ) 
00422 {
00423     char name[1024];
00424     if (!mxIsChar(prhs[0]))
00425         output_error("variable name is not a string");
00426     else if (mxGetString(prhs[0],name,sizeof(name))!=0)
00427         output_error("variable name too long");
00428     else 
00429     {
00430         char *value = getenv(name);
00431         if (value==NULL)
00432             output_error("%s is not defined",name);
00433         else if (nlhs==0)
00434             output_message("%s='%s'",name,value);
00435         else if (nlhs==1)
00436             plhs[0] = mxCreateString(value);
00437         else
00438             output_error("getenv does not return more than one value");
00439     }
00440     return;
00441 }
00442 
00446 void cmex_create(int nlhs, mxArray *plhs[], 
00447                  int nrhs, const mxArray *prhs[]) 
00448 {
00449     CLASS *oclass;
00450     OBJECT *obj;
00451     CLASSNAME classname;
00452     unsigned int num_properties = (nrhs-1)/2;
00453 
00454     /* check return value */
00455     if (nlhs>1)
00456         output_error("create only returns one struct");
00457     /* check class name */
00458     else if (!mxIsChar(prhs[0]))
00459         output_error("class name (arg 1) must be a string");
00460 
00461     /* get class name */
00462     else if (mxGetString(prhs[0],classname,sizeof(classname)))
00463         output_error("unable to read class name (arg 1)");
00464 
00465     /* check the number of properties */
00466     else if (num_properties!=(nrhs/2))
00467         output_error("an object property value is missing");
00468 
00469     /* create object */
00470     else if ((oclass=class_get_class_from_classname(classname))==NULL)
00471         output_error("class '%s' is not registered", classname);
00472 
00473     /* create the object */
00474     else if (oclass->create(&obj,NULL)==FAILED)
00475         output_error("unable to create object of class %s", classname);
00476 
00477     /* copy properties */
00478     else
00479     {
00480         unsigned int i;
00481         for (i=0; i<num_properties; i++)
00482         {
00483             char name[256];
00484             char value[1024];
00485             unsigned int n=i*2+1;
00486             const mxArray *p[] = {prhs[n],prhs[n+1]};
00487             if (!mxIsChar(p[0]))
00488                 output_error("property name (arg %d) must be a string", n);
00489             else if (mxGetString(p[0],name,sizeof(name)))
00490                 output_error("property name (arg %d) couldn't be read", n);
00491             else if (mxIsChar(p[1]) && mxGetString(p[1],value,sizeof(value)))
00492                 output_error("property %s (arg %d) value couldn't be read", name, n);
00493             else if (mxIsDouble(p[1]) && sprintf(value,"%lg",*(double*)mxGetPr(p[1]))<1)
00494                 output_error("property %s (arg %d) value couldn't be converted from double", name, n);
00495             else if (mxIsComplex(p[1]) && sprintf(value,"%lg%+lgi",*(double*)mxGetPr(p[1]),*(double*)mxGetPi(p[1]))<1)
00496                 output_error("property %s (arg %d) value couldn't be converted from complex", name, n);
00497             else if (object_set_value_by_name(obj,name,value)==0)
00498                 output_error("property %s (arg %d) couldn't be set to '%s'", name, n, value);
00499             else if (nlhs>0 && (plhs[0]=get_object_data(obj))==NULL)
00500                 output_error("couldn't get object data for %s", name);
00501         }
00502     }
00503 }
00504 
00508 void cmex_load(int nlhs, mxArray *plhs[], 
00509                int nrhs, const mxArray *prhs[] ) 
00510 {
00511     if (nrhs>0)
00512     {
00513         char fname[1024];
00514         if (!mxIsChar(prhs[0]))
00515             output_error("Model name is not a string");
00516         else if (nlhs>0)
00517             output_error("load does not return a value");
00518         else if (mxGetString(prhs[0],fname,sizeof(fname))!=0)
00519             output_error("Model name too long");
00520         else if (loadall(fname)==FAILED)
00521             output_error("Model load failed");
00522         else 
00523             output_message("Model %s loaded ok", fname);
00524     }
00525     else
00526         output_error("Module not specified");
00527     return;
00528 }
00529 
00533 void cmex_start(int nlhs, mxArray *plhs[], 
00534                   int nrhs, const mxArray *prhs[] ) 
00535 {
00536     global_keep_progress = 1;
00537     if (exec_start()==FAILED)
00538         output_error("Simulation failed!");
00539     return;
00540 }
00545 void cmex_module(int nlhs, mxArray *plhs[], 
00546                    int nrhs, const mxArray *prhs[] ) 
00547 {
00548     if (nrhs>0)
00549     {
00550         char fname[1024];
00551         MODULE *mod;
00552         if (!mxIsChar(prhs[0]))
00553             output_error("Module name is not a string");
00554         else if (nlhs>1)
00555             output_error("Only one return value is possible");
00556         else if (mxGetString(prhs[0],fname,sizeof(fname))!=0)
00557             output_error("Module name too long");
00558         else if ((mod=module_find(fname))==NULL && (mod=module_load(fname,0,NULL))==NULL)
00559             output_error("Module load failed");
00560         else if (nlhs=0)
00561             output_message("Module '%s(%d.%d)' loaded ok", mod->name, mod->major, mod->minor);
00562         else
00563         {
00564             /* set the standard info */
00565             char *fnames[256] = {"handle","name","major","minor"};
00566             mxArray *name = mxCreateString(mod->name);
00567             mxArray *handle = mxCreateNumericMatrix(1,1,sizeof(int32)==sizeof(int)?mxUINT32_CLASS:mxUINT64_CLASS,mxREAL);
00568             mxArray *major = mxCreateNumericMatrix(1,1,mxUINT8_CLASS,mxREAL);
00569             mxArray *minor = mxCreateNumericMatrix(1,1,mxUINT8_CLASS,mxREAL);
00570             mxArray *value[256];
00571             unsigned int64 *pHandle = mxGetData(handle);
00572             unsigned char *pMajor = mxGetData(major);
00573             unsigned char *pMinor = mxGetData(minor);
00574             char32 varname="";
00575             int nFields=4;
00576             char vnames[256][32];
00577             *pHandle = (unsigned int64)mod->hLib;
00578             *pMajor = (unsigned char)mod->major;
00579             *pMinor = (unsigned char)mod->minor;
00580 
00581             /* get the module data */
00582             while (module_getvar(mod,varname,NULL,0))
00583             {
00584                 char32 buffer;
00585                 if (module_getvar(mod,varname,buffer,sizeof(buffer)) && nFields<sizeof(fname)/sizeof(fname[0]))
00586                 {
00587                     double *pVal;
00588                     output_verbose("module variable %s = '%s'", varname, buffer);
00589                     value[nFields] = mxCreateDoubleMatrix(1,1,mxREAL);
00590                     pVal = mxGetPr(value[nFields]);
00591                     *pVal = atof(buffer);
00592                     strcpy(vnames[nFields],varname);
00593                     fnames[nFields] = vnames[nFields];
00594                     nFields++;
00595                 }
00596             }
00597 
00598             /* construct the result */
00599             plhs[0] = mxCreateStructMatrix(1,1,nFields,fnames);
00600             mxSetFieldByNumber(plhs[0],0,0,handle);
00601             mxSetFieldByNumber(plhs[0],0,1,name);
00602             mxSetFieldByNumber(plhs[0],0,2,major);
00603             mxSetFieldByNumber(plhs[0],0,3,minor);
00604             while (nFields-->4)
00605                 mxSetFieldByNumber(plhs[0],0,nFields,value[nFields]);
00606 
00607         }
00608     }
00609     else
00610         output_error("Module not specified");
00611     return;
00612 }
00613 
00617 void cmex_set(int nlhs, mxArray *plhs[], 
00618                 int nrhs, const mxArray *prhs[]) 
00619 {
00620     if (nlhs>0)
00621         output_error("set does not return a value");
00622     else if (nrhs==1 && mxIsStruct(prhs[0]))
00623         set_object_data(prhs[0]);
00624     else if (nrhs!=3)
00625         output_error("set requires either a structure, or object id, property name and value");
00626     else if (!mxIsChar(prhs[0]))
00627         output_error("object id (arg 0) must be a string");
00628     else if (mxIsChar(prhs[1]))
00629     {
00630         char value[1024];
00631         PROPERTY* prop;
00632         OBJECT *obj=NULL;
00633         GLOBALVAR *var=NULL;
00634         if (mxGetString(prhs[0],value,sizeof(value))!=0)
00635             output_error("object name (arg 0) too long");
00636         else if (strcmp(value,"global")==0)
00637         {
00638             if (!mxIsChar(prhs[1]))
00639                 output_error("global variable name is not a string");
00640             else if (!mxIsChar(prhs[2]))
00641                 output_error("global value is not is not a string");
00642             else
00643             {
00644                 char name[32], value[1024];
00645                 mxGetString(prhs[1],name,sizeof(name));
00646                 mxGetString(prhs[2],value,sizeof(value));
00647                 if (global_setvar(name,value)!=SUCCESS)
00648                     output_error("unable to set global '%s' to '%s'", name,value);
00649             }
00650         }
00651         else if (convert_to_object(value,&obj,NULL)==0)
00652             output_error("object (arg 0) %s not found",value);
00653         else if (mxGetString(prhs[1],value,sizeof(value))!=0)
00654             output_error("property name (arg 1) too long");
00655         else if ((prop=object_get_property(obj,value))==NULL)
00656             output_error("property name (arg 1) %s not found in object %s:%d", value,obj->oclass->name, obj->id);
00657         else if (mxIsChar(prhs[2]))
00658         {
00659             if (mxGetString(prhs[2],value,sizeof(value))!=0)
00660                 output_error("value (arg 2) is too long");
00661             else if (object_set_value_by_name(obj,prop->name,value)==0)
00662                 output_error("unable to set %s:%d/%s to %s", obj->oclass->name, obj->id, prop->name, value);
00663             else
00664                 return; /* ok */
00665         }
00666         else if (mxIsDouble(prhs[2]) && prop->ptype==PT_double)
00667         {
00668             double v = *mxGetPr(prhs[2]);
00669             if (prop->ptype==PT_double && object_set_double_by_name(obj,prop->name,v)==0)
00670                 output_error("unable to set %s:%d/%s to %lg", obj->oclass->name, obj->id, prop->name, v);
00671         }
00672         else if (mxIsComplex(prhs[2]) || mxIsDouble(prhs[2]))
00673         {
00674             sprintf(value,"%lg%+lgi",*mxGetPr(prhs[2]),mxIsComplex(prhs[2])?*mxGetPi(prhs[2]):0);
00675             if (object_set_value_by_name(obj,prop->name,value)==0)
00676                 output_error("unable to set %s:%d/%s to %s", obj->oclass->name, obj->id, prop->name, value);
00677         }
00678         else 
00679             output_error("value (arg 2) has an unsupported data type");
00680     }
00681     else
00682         output_error("property or data (arg 1) type is not valid");
00683 }
00684 
00688 void cmex_get(int nlhs, mxArray *plhs[], 
00689                 int nrhs, const mxArray *prhs[] ) 
00690 {
00691     if (nrhs>0)
00692     {
00693         char name[1024];
00694         OBJECT *obj=NULL;
00695         if (!mxIsChar(prhs[0]))
00696             output_error("entity name (arg 1) is not a string");
00697         else if (nlhs>1)
00698             output_error("only one return value is possible");
00699         else if (mxGetString(prhs[0],name,sizeof(name))!=0)
00700             output_error("object name too long");
00701         else if (strcmp(name,"clock")==0)
00702         {
00703             char *fnames[] = {"timestamp","timestring","timezone"};
00704             char buffer[256];
00705             mxArray *pTimestamp = mxCreateDoubleMatrix(1,1,mxREAL);
00706             mxArray *pTimestring = mxCreateString(convert_from_timestamp(global_clock,buffer,sizeof(buffer))?buffer:"(error)");
00707             mxArray *pTimezone = mxCreateString(timestamp_current_timezone());
00708 
00709             *(double*)mxGetPr(pTimestamp) = ((double)global_clock)/TS_SECOND;
00710             plhs[0] = mxCreateStructMatrix(1,1,sizeof(fnames)/sizeof(fnames[0]),fnames);
00711             mxSetFieldByNumber(plhs[0],0,0,pTimestamp);
00712             mxSetFieldByNumber(plhs[0],0,1,pTimestring);
00713             mxSetFieldByNumber(plhs[0],0,2,pTimezone);
00714         }
00715         else if (strcmp(name,"property")==0 && nrhs>1)
00716         {
00717             if (mxGetString(prhs[1],name,sizeof(name))!=0)
00718                 output_error("missing property name");
00719             else
00720             {
00721                 char classname[256];
00722                 char propname[256];
00723                 if (sscanf(name,"%[^.].%s",classname,propname)==2)
00724                 {
00725                     CLASS *pClass = class_get_class_from_classname(classname);
00726                     if (pClass)
00727                     {
00728                         PROPERTY *pProp = class_find_property(pClass,propname);
00729                         if (pProp)
00730                         {
00731                             char *fields[] = {"class","name","type","size","access","unit","delegation","keywords"};
00732                             int fn = 0;
00733                             mxArray *oclass = mxCreateString(classname);
00734                             mxArray *prop = mxCreateString(pProp->name);
00735                             mxArray *type = mxCreateString(class_get_property_typename(pProp->ptype));
00736                             mxArray *size = mxCreateDoubleMatrix(1,1,mxREAL); 
00737                             mxArray *access = mxCreateString("(na)"); 
00738                             mxArray *unit = mxCreateString(pProp->unit->name);
00739                             mxArray *delegation = mxCreateString(pProp->delegation?pProp->delegation->oclass->name:"(none)");
00740                             mxArray *keywords = mxCreateString("(na)"); 
00741                             *(mxGetPr(size)) = pProp->size==0?1:pProp->size;
00742                             plhs[0] = mxCreateStructMatrix(1,1,sizeof(fields)/sizeof(fields[0]),fields);
00743                             mxSetFieldByNumber(plhs[0],0,fn++,oclass);
00744                             mxSetFieldByNumber(plhs[0],0,fn++,prop);
00745                             mxSetFieldByNumber(plhs[0],0,fn++,type);
00746                             mxSetFieldByNumber(plhs[0],0,fn++,size);
00747                             mxSetFieldByNumber(plhs[0],0,fn++,access);
00748                             mxSetFieldByNumber(plhs[0],0,fn++,unit);
00749                             mxSetFieldByNumber(plhs[0],0,fn++,delegation);
00750                             mxSetFieldByNumber(plhs[0],0,fn++,keywords);
00751                         }
00752                         else
00753                             output_error("property %s is not found in class %s", propname,classname);
00754                     }
00755                     else
00756                         output_error("class %s is not found");
00757                 }
00758                 else
00759                     output_error("property name not in class.name format");
00760             }
00761         }
00762         else if ((convert_to_object(name,&obj,NULL))==0)
00763         {
00764             GLOBALVAR *var = global_find(name);
00765             if (var==NULL)
00766                 output_error("entity '%s' not found", name);
00767             else if (var->prop->ptype==PT_double)
00768             {
00769                 size_t size = var->prop->size?var->prop->size:1;
00770                 plhs[0] = mxCreateDoubleMatrix(size,1,mxREAL);
00771                 memcpy(mxGetPr(plhs[0]),(void*)var->prop->addr,sizeof(double)*size);
00772             }
00773             else if (var->prop->ptype==PT_int32)
00774             {
00775                 size_t size = var->prop->size?var->prop->size:1;
00776                 plhs[0] = mxCreateDoubleMatrix(size,1,mxREAL);
00777 
00778                 memcpy(mxGetPr(plhs[0]),(void*)var->prop->addr,sizeof(double)*size);
00779             }
00780             else if (var->prop->ptype!=PT_double)
00781                 output_error("cannot retrieve globals that are of type %s",class_get_property_typename(var->prop->ptype));
00782         }
00783         else if ((plhs[0]=get_object_data(obj))==NULL)
00784             output_error("unable to extract %s data", name);
00785     }
00786     else
00787         output_error("object not specified");
00788     return;
00789 }
00790 
00791 /************************************************************
00792  *
00793  * MAIN MEX FUNCTION
00794  *
00795  ************************************************************/
00796 
00797 typedef struct
00798 {
00799     char *name;
00800     void (*call)(int, mxArray*[],int,const mxArray*[]);
00801     char *brief;
00802     char *detail;
00803 } CMDMAP;
00804 static CMDMAP cmdMap[] = 
00805 {
00806     {"setenv",cmex_setenv,"Set environment",
00807         "\tgl('setenv','name','value')\n"
00808         "  Set an environment variable\n"
00809     },
00810 
00811     {"getenv",cmex_getenv,"Get environment",
00812         "\tgl('getenv','name')\n"
00813         "  Get an environment variable\n"
00814     },
00815 
00816     {"start",cmex_start,"Start simulation",
00817         "\tgl('start')\n"
00818         "  Start the GridLAB simulation.\n"
00819     },
00820 
00821     {"load",cmex_load,"Import GridLAB model",
00822         "\tgl('load',filename)\n"
00823         "  Import the GridLAB model in <filename>.\n"
00824     },
00825 
00826     {"module",cmex_module,"Load GridLAB module",
00827         "\tgl('module',modulename)\n"
00828         "  Load the GridLAB module named <modulename>.\n"
00829     },
00830 
00831     {"version",cmex_version,"Get GridLAB version information",
00832         "\tgl('version')\n"
00833         "  Returns the major, minor, and build numbers of the installed version of GridLAB.\n"
00834     },
00835 
00836     {"get",cmex_get,"Get an object's data",
00837         "\tgl('get',name)\n"
00838         "  Returns the object structure\n"
00839     },
00840 
00841     {"set",cmex_set,"Set an object's data",
00842         "\tgl('set',id,property,value)\n"
00843         "  Returns the object structure\n"
00844     },
00845     {"create",cmex_create,"Create an object",
00846         "\tgl('create',class, property1,value1, property2,value2, ..., propertyN,valueN)\n"
00847         "  Returns the object structure\n"
00848     },
00849     {"global",cmex_global,"Create a global variable",
00850         "\tgl('global',name,array)\n"
00851         "  Returns nothing\n"
00852     },
00853 
00854     {"list",cmex_list,"Obtain a list of entities",
00855         "\tgl('list',type)\n"
00856         "  Returns a list of entities\n"
00857     },
00858 };
00859 
00860 void mexFunction( int nlhs, mxArray *plhs[],
00861           int nrhs, const mxArray *prhs[] )
00862 {
00863     static first = 1;
00864     char key[MAXNAME];
00865     int i;
00866     
00867     if (first==1)
00868     {
00869         first = 0;
00870 
00871         /* prevent Matlab from clearing GridLAB */
00872         mexLock(); 
00873 
00874         /* register Matlab output routines */
00875         output_set_stdout(mexPrintf);
00876         output_set_stderr(cmex_printerr);
00877 
00878         /* display legal stuff */
00879         legal_license();
00880 
00881         /* initialize GridLAB */
00882         exec_init();
00883     }
00884 
00885     /* check number of input arguments */
00886     if (nrhs<1)
00887     {
00888         output_error("Use gl('help') for a list of commands.");
00889         return;
00890     }
00891     
00892     /* check type of first argument */
00893     if (!mxIsChar(prhs[0]))
00894     {
00895         output_error("token must be a string");
00896         return;
00897     }
00898     
00899     /* read first argument */
00900     if (mxGetString(prhs[0],key,sizeof(key))!=0)
00901         output_warning("GridLAB key string too long");
00902         
00903     /* scan command map to find call function */
00904     for (i=0; i<sizeof(cmdMap)/sizeof(cmdMap[0]); i++)
00905     {
00906         if (strcmp(key,cmdMap[i].name)==0)
00907         {
00908             if (cmdMap[i].call == NULL) /* help request */
00909             {
00910                 int j;
00911                 if (nrhs==1)
00912                 {
00913                     output_raw("Available top-level commands\n");
00914                     for (j=0; j<sizeof(cmdMap)/sizeof(cmdMap[0]); j++)
00915                         output_raw("\t%s\t%s\n", cmdMap[j].name, cmdMap[j].brief);
00916                     output_raw("Use gl('help',command) for details\n");
00917                     return;
00918                 }
00919                 else if (mxIsChar(prhs[1]))
00920                 {
00921                     char cmd[MAXNAME];
00922                     if (mxGetString(prhs[1],cmd,sizeof(cmd))!=0)
00923                         output_warning("command string too long to read fully");
00924 
00925                     for (j=0; j<sizeof(cmdMap)/sizeof(cmdMap[0]); j++)
00926                     {
00927                         if (strcmp(cmd,cmdMap[j].name)==0)
00928                         {
00929                             output_raw("Help for command '%s'\n\n%s\n", cmd, cmdMap[j].detail ? cmdMap[j].detail : "\tNo details available\n");
00930                             return;
00931                         }
00932                     }
00933                     output_error("Command '%s' does not exist", cmd);
00934                     return;
00935                 }
00936                 else
00937                 {
00938                     output_error("command must be a string");
00939                     return;
00940                 }
00941             }
00942             else
00943             {
00944                 (cmdMap[i].call)(nlhs,plhs,nrhs-1,prhs+1);
00945                 return;
00946             }
00947         }
00948     }
00949 
00950     /* function not found */
00951     {   int nret = nlhs;
00952         output_error("unrecognized GridLAB operation--gl('help') for list");
00953         while (nret-->0)
00954             plhs[nret] = mxCreateDoubleMatrix(0,0,mxREAL);
00955     }
00956     return;
00957 }
00958 

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