00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "interpreter_defs.h"
00034
00035 #include "config.h"
00036 #include "simlpy.h"
00037
00038 #include "Entity.h"
00039 #include "Registry.h"
00040 #include "Terminator.h"
00041 #include "InterpreterEvent.h"
00042 #include "InterpreterEntity.h"
00043 #include "SimulationException.h"
00044
00045 #include "boost/random/ranlux.hpp"
00046
00047 #include <iostream>
00048 #include <vector>
00049 #include <queue>
00050 #include <string>
00051 #include <unistd.h>
00052 #include <stdio.h>
00053
00056
00057 #ifndef PyMODINIT_FUNC
00060 #define PyMODINIT_FUNC extern "C" void
00061 #endif
00062
00063
00066
00071 typedef struct
00072 {
00073 PyObject_HEAD
00074 PyObject* type;
00075 Entity* e;
00076 int id;
00077 } PySimEntity;
00078
00083 static char PySimEntity_doc[] = "Simulation entity.\n\
00084 \n\
00085 An Entity is created by calling\n\
00086 \n\
00087 sim.Entity(<type>)\n\
00088 \n\
00089 where <type> is a string corresponding to the unique identifier\n\
00090 registered for a particular subclass.\n\
00091 \n\
00092 The string representation of an Entity is an integer. While the\n\
00093 Entity cannot be constructed using this value, it does provide a\n\
00094 usable handle within the simulator for retrieving the object\n\
00095 from within the C++ framework.\n";
00096
00108 static PyObject*
00109 PySimEntity_id( PyObject* self )
00110 {
00111 return PyString_FromFormat("%d",((PySimEntity*)self)->id);
00112 }
00113
00122 static void
00123 PySimEntity_dealloc( PySimEntity* self )
00124 {
00125 Py_XDECREF( self->type );
00126
00127 self->ob_type->tp_free((PyObject*)self);
00128 }
00129
00130 void
00131 clean_arglist( Entity::ArgList& alist )
00132 {
00133 Entity::ArgList::iterator itr = alist.begin();
00134 Entity::ArgList::iterator end = alist.end();
00135 for ( ; itr != end ; ++itr )
00136 {
00137 Py_DECREF(*itr);
00138 }
00139 }
00140
00141 void
00142 build_arglist( Entity::ArgList& alist, PyObject* args )
00143 {
00144 if ( 0 == args ) return;
00145 if ( ! PyTuple_Check( args ) )
00146 {
00147 PyErr_SetString(PyExc_TypeError,"config expects a list of arguments");
00148 throw SimulationException( __FILE__ , __LINE__ );
00149 }
00150 int n = PyTuple_Size( args );
00151 for ( int i = 0 ; i < n ; ++i )
00152 {
00153 PyObject* p = PyTuple_GetItem( args, i );
00154 if ( 0 == p )
00155 {
00156 PyErr_SetString(PyExc_TypeError,"missing argument in list");
00157 throw SimulationException( __FILE__ , __LINE__ );
00158 }
00159 Py_INCREF(p);
00160 alist.push_back(p);
00161 }
00162 }
00163
00167 static char PySimEntity_config_doc[] = "Configure the Entity.\n\
00168 \n\
00169 Calling syntax for a sim.Entity e:\n\
00170 e.config(<arg1>,<arg2>,...)\n\
00171 \n\
00172 We perform no type checking on the arguments, other than that\n\
00173 they are in fact a list. All Python objects passed to this\n\
00174 method are converted first to Python strings and then to C++\n\
00175 strings. The latter are passed to Entity::configure() through\n\
00176 an Entity::ArgList.\n\
00177 \n\
00178 It is up to specific subclasses to interpret the argument list.\n\
00179 Modules that implement concrete subclasses will document valid\n\
00180 calls to e.config() for those classes.\n";
00181
00191 static PyObject*
00192 PySimEntity_config( PySimEntity* self, PyObject* args )
00193 {
00194 Entity::ArgList entityArgs;
00195 try
00196 {
00197 build_arglist( entityArgs, args );
00198 self->e->configure( entityArgs );
00199 clean_arglist(entityArgs);
00200 }
00201 catch ( ... )
00202 {
00203 PyErr_SetString(PyExc_ValueError,
00204 "Bad argument list passed to sim.config");
00205 clean_arglist(entityArgs);
00206 return 0;
00207 }
00208 Py_INCREF(self);
00209 return (PyObject*)self;
00210 }
00211
00215 static char PySimEntity_emit_doc[] = "Have the Entity emit an Event.\n\
00216 \n\
00217 Calling syntax for a sim.Entity e:\n\
00218 e.emit(<arg1>,<arg2>,...)\n\
00219 \n\
00220 We perform no type checking on the arguments, other than that\n\
00221 they are in fact a list. All Python objects passed to this\n\
00222 method are converted first to Python strings and then to C++\n\
00223 strings. The latter are passed to Entity::emit() through an\n\
00224 Entity::ArgList.\n\
00225 \n\
00226 It is up to specific subclasses to interpret the argument list.\n\
00227 Modules that implement concrete subclasses will document valid\n\
00228 calls to e.config() for those classes.\n";
00229
00239 static PyObject*
00240 PySimEntity_emit( PySimEntity* self, PyObject* args )
00241 {
00242 Entity::ArgList entityArgs;
00243 try
00244 {
00245 build_arglist( entityArgs, args );
00246 self->e->emit( entityArgs );
00247 clean_arglist(entityArgs);
00248 }
00249 catch ( ... )
00250 {
00251 PyErr_SetString(PyExc_ValueError,
00252 "Bad argument list passed to sim.emit");
00253 clean_arglist(entityArgs);
00254 return 0;
00255 }
00256 Py_INCREF(self);
00257 return (PyObject*)self;
00258 }
00259
00263 static char PySimEntity_get_doc[] = "Get Entity attributes.\n\
00264 \n\
00265 Calling syntax for a sim.Entity e:\n\
00266 e.get(<arg1>,<arg2>,...)\n\
00267 \n\
00268 The arguments are generally strings, specifying Entity\n\
00269 attributes to query. The specific Entity subclass determines\n\
00270 how to interpret the arguments, so fairly complex behavior can\n\
00271 be implemented through this mechanism.\n\
00272 \n\
00273 This method returns something appropriate for the arguments\n\
00274 provided. The type of this return value is completely\n\
00275 subclass-dependent.\n\
00276 \n\
00277 Modules that implement concrete subclasses will document\n\
00278 valid calls to e.get() for those classes.\n";
00279
00289 static PyObject*
00290 PySimEntity_get( PySimEntity* self, PyObject* args )
00291 {
00292 Entity::ArgList entityArgs;
00293 PyObject* retval = 0;
00294 try
00295 {
00296 build_arglist( entityArgs, args );
00297 retval = self->e->get( entityArgs );
00298 clean_arglist(entityArgs);
00299 }
00300 catch ( ... )
00301 {
00302 PyErr_SetString(PyExc_ValueError,
00303 "Bad argument list passed to sim.config");
00304 clean_arglist(entityArgs);
00305 return 0;
00306 }
00307 return retval;
00308 }
00309
00312 static PyMethodDef PySimEntity_methods[] =
00313 {
00314 { "config",
00315 (PyCFunction)PySimEntity_config,
00316 METH_VARARGS,
00317 PySimEntity_config_doc },
00318 { "emit",
00319 (PyCFunction)PySimEntity_emit,
00320 METH_VARARGS,
00321 PySimEntity_emit_doc },
00322 { "get",
00323 (PyCFunction)PySimEntity_get,
00324 METH_VARARGS,
00325 PySimEntity_get_doc },
00326 {0}
00327 };
00328
00331 static PyMemberDef PySimEntity_members[] =
00332 {
00333 {"type", T_OBJECT_EX, offsetof(PySimEntity, type), 0, "Entity type"},
00334 {0}
00335 };
00336
00339 static PyTypeObject sim_PySimEntity = {
00340 PyObject_HEAD_INIT(0)
00341 0,
00342 "sim.Entity",
00343 sizeof(PySimEntity),
00344 0,
00345 (destructor)PySimEntity_dealloc,
00346 0,
00347 0,
00348 0,
00349 0,
00350 PySimEntity_id,
00351 0,
00352 0,
00353 0,
00354 0,
00355 0,
00356 0,
00357 0,
00358 0,
00359 0,
00360 Py_TPFLAGS_DEFAULT,
00361 PySimEntity_doc,
00362 0,
00363 0,
00364 0,
00365 0,
00366 0,
00367 0,
00368 PySimEntity_methods,
00369 PySimEntity_members,
00370 0,
00371 0,
00372 0,
00373 0,
00374 0,
00375 0,
00376 0,
00377 0,
00378 0,
00379 };
00380
00382
00383
00386
00388 typedef std::vector< PySimEntity* > SimEntityVec;
00389
00395 static SimEntityVec entityList;
00396
00399 static Terminator kronos;
00400
00403 static InterpreterEntity iEntity;
00404
00405 static PyObject* sim_args;
00406
00408
00409
00426 static PyObject*
00427 sim_entity( PyTypeObject* type, PyObject* args, PyObject* kwds )
00428 {
00429 const char* eType;
00430 if ( ! PyArg_ParseTuple(args, "s", &eType) )
00431 {
00432 std::cerr << "Incorrect argument list" << std::endl;
00433 return 0;
00434 }
00435 const Entity* e = 0;
00436 try
00437 {
00438 e = Registry::lookup( eType );
00439 }
00440 catch ( ... )
00441 {
00442 std::string errString = "No entity type \"";
00443 errString += eType;
00444 errString += "\" registered";
00445 PyErr_SetString(PyExc_KeyError,errString.c_str());
00446 return 0;
00447 }
00448 Entity* newE = e->create();
00449 if ( 0 == newE )
00450 {
00451 std::cerr << "Could not allocate a new " << eType << std::endl;
00452 return PyErr_NoMemory();
00453 }
00454
00455 return export_entity(newE);
00456 }
00457
00458
00461
00465 static char sim_time_doc[] = "Get the current simulator time.\n\
00466 \n\
00467 This function, which takes no arguments, returns a list of\n\
00468 the form:\n\
00469 \n\
00470 [ seconds , microseconds ]\n\
00471 \n\
00472 corresponding to the current time in the simulator.\n\
00473 \n\
00474 If no events have been processed since starting simlpy, this\n\
00475 will have the value\n\
00476 \n\
00477 [0L, 0L]\n\
00478 \n\
00479 Otherwise, it will typically return the time of the last-\n\
00480 scheduled sim.stopAt() call.\n";
00481
00492 static PyObject*
00493 sim_time( PyObject* self, PyObject* args )
00494 {
00495 return construct_time( Clock::time() );
00496 }
00497
00501 static char sim_timeAsDouble_doc[] = "Get the current simulator time.\n\
00502 \n\
00503 This function, which takes no arguments, returns the current\n\
00504 time in seconds.\n\
00505 \n\
00506 If no events have been processed since starting simlpy, this\n\
00507 will have the value\n\
00508 \n\
00509 [0L, 0L]\n\
00510 \n\
00511 Otherwise, it will typically return the time of the last-\n\
00512 scheduled sim.stopAt() call.\n";
00513
00524 static PyObject*
00525 sim_timeAsDouble( PyObject* self, PyObject* args )
00526 {
00527 const Time& t = Clock::time();
00528 double dt = t.tv.tv_sec + 1.0*t.tv.tv_usec/Time::MILLION;
00529 return construct_double(dt);
00530 }
00531
00535 static char sim_run_doc[] = "Start a simulation run.\n\
00536 \n\
00537 This is, in effect, the main loop of the simulator. As long\n\
00538 as the simulator is still in its running state, this routine\n\
00539 will continue to consume simulation events. The loop will exit\n\
00540 when there are no more events to process or when it processes\n\
00541 an event scheduled by calling sim.stopAt().\n";
00542
00551 static PyObject*
00552 sim_run( PyObject* self, PyObject* args )
00553 {
00554 Clock::setRunning( true );
00555 while ( Clock::running() )
00556 {
00557 Clock::tick();
00558 }
00559 Py_INCREF(Py_None);
00560 return Py_None;
00561 }
00562
00566 static char sim_stopAt_doc[] = "Set an end time for the simulation.\n\
00567 \n\
00568 Calling syntax:\n\
00569 sim.stopAt( [<s>,<us>] )\n\
00570 \n\
00571 The list provided is a simulation time expressed in\n\
00572 seconds and microseconds. Calling this function schedules\n\
00573 an event for this time that will cause the simulation to stop.\n\
00574 \n\
00575 Stopping the simulation does not cause simlpy to exit. Rather,\n\
00576 it continues processing input. A subsequent call to sim.run()\n\
00577 will resume the simulation from the point at which it stopped.\n\
00578 If there is no more input, and a sys.exit() or similar has not\n\
00579 been processed, control is returned to the user at an interactive\n\
00580 prompt.\n";
00581
00591 static PyObject*
00592 sim_stopAt( PyObject* self, PyObject* args )
00593 {
00594 try
00595 {
00596 kronos.stopAt(parse_time(PyTuple_GetItem(args,0)));
00597 }
00598 catch( ... )
00599 {
00600 return 0;
00601 }
00602 Py_INCREF(Py_None);
00603 return Py_None;
00604 }
00605
00609 static char sim_collect_doc[] = "Collect information from Entitys.\n\
00610 \n\
00611 When called, this will loop over all Entitys created by the\n\
00612 sim module, and will run that object's collect() method\n\
00613 in C++. The default behavior for an Entity is to do nothing.\n\
00614 \n\
00615 See the documentation for a specific module for the behavior\n\
00616 of its Entity subclasses when this is called.\n";
00617
00628 static PyObject*
00629 sim_collect( PyObject* self, PyObject* args )
00630 {
00631 SimEntityVec::iterator itr = entityList.begin();
00632 SimEntityVec::iterator end = entityList.end();
00633 for ( ; itr != end ; ++itr )
00634 {
00635 if ( 0 != (*itr)->e )
00636 {
00637 (*itr)->e->collect();
00638 }
00639 }
00640 Py_INCREF(Py_None);
00641 return Py_None;
00642 }
00643
00644 static boost::ranlux3_01 sim_prng;
00645
00646 void
00647 seed_prng( unsigned long int s )
00648 {
00649 sim_prng.seed(s);
00650 }
00651
00652 float
00653 prng()
00654 {
00655 return sim_prng();
00656 }
00657
00661 static char sim_seed_doc[] = "Seed the random number generator.\n\
00662 \n\
00663 Calling syntax:\n\
00664 sim.seed( i )\n\
00665 sim.seed()\n\
00666 \n\
00667 When called, this will seed the random number generator\n\
00668 with the supplied integer i. If no seed value is given,\n\
00669 one will be selected and reported on the console.\n";
00670
00680 static PyObject*
00681 sim_seed( PyObject* self, PyObject* args )
00682 {
00683 unsigned int s;
00684 Entity::ArgList alist;
00685 build_arglist( alist, args );
00686 if ( alist.empty() )
00687 {
00688
00689
00690 union time_int
00691 {
00692 int i;
00693 char c[4];
00694 };
00695 struct timeval tv;
00696 gettimeofday(&tv,0);
00697 time_int seconds;
00698 seconds.i = tv.tv_sec;
00699 time_int useconds;
00700 useconds.i = tv.tv_usec;
00701 time_int seed;
00702 seed.i = 0;
00703
00704
00705
00706 seed.c[0] = seconds.c[0] ^ seconds.c[3] ^ useconds.c[0];
00707 seed.c[1] = seconds.c[1] ^ seconds.c[2] ^ useconds.c[1];
00708 seed.c[2] = seconds.c[2] ^ seconds.c[1] ^ useconds.c[2];
00709 seed.c[3] = seconds.c[3] ^ seconds.c[0] ^ useconds.c[3];
00710 s = seed.i;
00711 seed_prng( s );
00712 std::cout << "Random number seed = " << s
00713 << " (" << std::hex << s << ")" << std::dec
00714 << std::endl;
00715 }
00716 else
00717 {
00718 try
00719 {
00720 s = parse_long(alist[0]);
00721 seed_prng( s );
00722 }
00723 catch ( ... )
00724 {
00725 std::cerr << "usage: sim.seed( i )" << std::endl;
00726 return 0;
00727 }
00728 }
00729 return construct_ulong(s);
00730 }
00731
00735 static char sim_random_doc[] = "Call the random number generator.\n\
00736 \n\
00737 Calling syntax:\n\
00738 r = sim.random()\n\
00739 \n\
00740 When called, this will return the next pseudo-random number\n\
00741 in the sequence, as a float in the range [0,1).\n";
00742
00753 static PyObject*
00754 sim_random( PyObject* self, PyObject* args )
00755 {
00756 return construct_double( prng() );
00757 }
00758
00762 static char sim_get_args_doc[] = "Get command-line arguments.\n\
00763 \n\
00764 Calling syntax:\n\
00765 l = sim.args()\n\
00766 \n\
00767 When called, this returns a list of the arguments supplied to\n\
00768 simlpy on the command line with the \"-a\" flag. All arguments\n\
00769 are returned as strings, and must be converted to other types\n\
00770 as appropriate.\n";
00771
00781 static PyObject*
00782 sim_get_args( PyObject* self, PyObject* args )
00783 {
00784 Py_INCREF(sim_args);
00785 return sim_args;
00786 }
00787
00791 static char sim_schedule_doc[] = "Schedule a python function.\n\
00792 \n\
00793 Calling syntax:\n\
00794 sim.schedule(t,f)\n\
00795 \n\
00796 This schedules the function f to be run at simulation time t.\n\
00797 For example:\n\
00798 \n\
00799 def f():\n\
00800 print sim.time()\n\
00801 sim.schedule(10,f)\n\
00802 sim.run()\n\
00803 \n\
00804 would produce the output:\n\
00805 \n\
00806 [10L, 0L]\n\
00807 \n\
00808 f may also be any callable python object.\n";
00809
00819 static PyObject*
00820 sim_schedule( PyObject* self, PyObject* args )
00821 {
00822 Entity::ArgList alist;
00823 try
00824 {
00825 build_arglist( alist, args );
00826 if ( 2 != alist.size() )
00827 {
00828 std::cerr << "sim.schedule() expected 2 arguments, "
00829 << alist.size() << " provided"
00830 << std::endl;
00831 throw SimulationException( __FILE__ , __LINE__ );
00832 }
00833 Time t = parse_time( alist[0] );
00834 InterpreterItem f = alist[1];
00835 if ( ! PyCallable_Check(f) )
00836 {
00837 throw SimulationException( __FILE__ , __LINE__ );
00838 }
00839 Clock::schedule( new InterpreterEvent( &iEntity, &iEntity, t, f ) );
00840 clean_arglist( alist );
00841 }
00842 catch ( ... )
00843 {
00844 PyErr_SetString(PyExc_ValueError,
00845 "Bad argument list passed to sim.schedule");
00846 clean_arglist(alist);
00847 return 0;
00848 }
00849 Py_INCREF(Py_None);
00850 return Py_None;
00851 }
00852
00855 static PyMethodDef SimMethods[] =
00856 {
00857 {"time",sim_time,METH_NOARGS,sim_time_doc},
00858 {"timeAsDouble",sim_timeAsDouble,METH_NOARGS,sim_timeAsDouble_doc},
00859 {"run",sim_run,METH_NOARGS,sim_run_doc},
00860 {"stopAt",sim_stopAt,METH_VARARGS,sim_stopAt_doc},
00861 {"collect",sim_collect,METH_NOARGS,sim_collect_doc},
00862 {"seed",sim_seed,METH_VARARGS,sim_seed_doc},
00863 {"random",sim_random,METH_NOARGS,sim_random_doc},
00864 {"args",sim_get_args,METH_VARARGS,sim_get_args_doc},
00865 {"schedule",sim_schedule,METH_VARARGS,sim_schedule_doc},
00866 {0,0,0,0}
00867 };
00868
00871 static char SimDoc[] = "Simulator namespace.\n\
00872 \n\
00873 The sim module, which is imported into simlpy by default,\n\
00874 contains the classes and methods needed for basic simulation\n\
00875 control. Specific functional simulator elements are added\n\
00876 by importing additional modules, such as pydtn, into simlpy.\n";
00877
00879
00880
00881
00884
00888 PyMODINIT_FUNC
00889 initsim()
00890 {
00891 sim_PySimEntity.tp_new = sim_entity;
00892 if ( PyType_Ready(&sim_PySimEntity) < 0 )
00893 {
00894 return;
00895 }
00896
00897 PyObject* m = Py_InitModule3("sim",SimMethods,SimDoc);
00898 Py_INCREF(&sim_PySimEntity);
00899 PyModule_AddObject(m, "Entity", (PyObject*)&sim_PySimEntity);
00900 if ( PyRun_SimpleString("import sim") < 0 )
00901 {
00902 std::cerr << "Error importing sim\n"
00903 << "exiting" << std::endl;
00904 ::exit(1);
00905 }
00906 }
00907
00909
00910
00911
00914
00915
00916 void
00917 add_entity( Entity* e )
00918 {
00919 try
00920 {
00921 Registry::insert( e );
00922 }
00923 catch ( ... )
00924 {
00925 std::cerr << "failed to register an Entity" << std::endl;
00926 }
00927 }
00928
00929 unsigned int
00930 num_entities()
00931 {
00932 return entityList.size();
00933 }
00934
00935 InterpreterItem
00936 get_entity(unsigned int i)
00937 {
00938 if ( i >= entityList.size() )
00939 {
00940 throw SimulationException( __FILE__ , __LINE__ );
00941 }
00942 return (PyObject*)(entityList[i]);
00943 }
00944
00945
00946 ItemWrapper
00947 resolve_symbol( InterpreterItem e )
00948 {
00949 ItemWrapper retval;
00950 if ( ! PyObject_TypeCheck(e,&sim_PySimEntity) )
00951 {
00952 PyErr_SetString(PyExc_TypeError,"expected a sim.Entity");
00953 throw SimulationException( __FILE__ , __LINE__ );
00954 }
00955 unsigned int id = ((PySimEntity*)e)->id;
00956 if ( id >= entityList.size() )
00957 {
00958 PyErr_SetString(PyExc_IndexError,"unknown sim.Entity");
00959 throw SimulationException( __FILE__ , __LINE__ );
00960 }
00961 PySimEntity* pse = entityList[id];
00962 if ( 0 == pse )
00963 {
00964 PyErr_SetString(PyExc_KeyError,"unknown sim.Entity");
00965 throw SimulationException( __FILE__ , __LINE__ );
00966 }
00967 retval.type = PyString_AsString(pse->type);
00968 retval.id = e;
00969 retval.item = pse->e;
00970 return retval;
00971 }
00972
00973 long int
00974 parse_long( const InterpreterItem l )
00975 {
00976 long int retval = 0;
00977 if ( PyLong_Check( l ) )
00978 {
00979 retval = PyLong_AsLong(l);
00980 }
00981 else if ( PyInt_Check( l ) )
00982 {
00983 retval = PyInt_AsLong(l);
00984 }
00985 else
00986 {
00987 PyErr_SetString(PyExc_TypeError,"an integer was expected");
00988 throw SimulationException( __FILE__ , __LINE__ );
00989 }
00990 return retval;
00991 }
00992
00993 double
00994 parse_double( const InterpreterItem d )
00995 {
00996 double retval = 0;
00997 if ( PyFloat_Check(d) )
00998 {
00999 retval = PyFloat_AsDouble(d);
01000 }
01001 else if ( PyLong_Check(d) )
01002 {
01003 retval = PyLong_AsDouble(d);
01004 }
01005 else if ( PyInt_Check(d) )
01006 {
01007 retval = PyInt_AsLong(d);
01008 }
01009 else
01010 {
01011 PyErr_SetString(PyExc_TypeError,"a real number was expected");
01012 throw SimulationException( __FILE__ , __LINE__ );
01013 }
01014 return retval;
01015 }
01016
01017 std::string
01018 parse_string( const InterpreterItem s )
01019 {
01020 if ( ! PyString_Check( s ) )
01021 {
01022 PyErr_SetString(PyExc_TypeError,"a string was expected");
01023 throw SimulationException( __FILE__ , __LINE__ );
01024 }
01025
01026
01027
01028 const char* sbuf = PyString_AsString(s);
01029 std::string retval;
01030 for ( int i = 0 ; i < PyString_Size(s) ; ++i )
01031 {
01032 retval += sbuf[i];
01033 }
01034 return retval;
01035 }
01036
01037
01038 Time
01039 parse_time( const InterpreterItem t )
01040 {
01041 long sec=0;
01042 long usec=0;
01043
01044
01045 if ( PyList_Check( t ) )
01046 {
01047 int n = PyList_Size( t );
01048 if ( n < 2 )
01049 {
01050 PyErr_SetString(PyExc_TypeError,"a list [s,us] was expected");
01051 throw SimulationException( __FILE__ , __LINE__ );
01052 }
01053
01054 sec = parse_long( PyList_GetItem( t, 0 ) );
01055 usec = parse_long( PyList_GetItem( t, 1 ) );
01056 }
01057 else
01058 {
01059
01060 try
01061 {
01062 sec = parse_long(t);
01063 }
01064 catch(...)
01065 {
01066
01067 PyErr_Clear();
01068 try
01069 {
01070 double d = parse_double(t);
01071 sec = (long int) ::floor(d);
01072 usec = (long int) ::floor( Time::MILLION * (d-sec) );
01073 }
01074 catch(...)
01075 {
01076 PyErr_SetString(PyExc_TypeError,
01077 "could not interpret value as a time");
01078 throw SimulationException( __FILE__ , __LINE__ );
01079 }
01080 }
01081 }
01082 return Time(sec,usec);
01083 }
01084
01085 InterpreterItem
01086 construct_string( const std::string& s )
01087 {
01088 return PyString_FromStringAndSize( s.data(), s.length() );
01089 }
01090
01091 InterpreterItem
01092 construct_double( double d )
01093 {
01094 return PyFloat_FromDouble(d);
01095 }
01096
01097 InterpreterItem
01098 construct_long( long int l )
01099 {
01100 return PyLong_FromLong(l);
01101 }
01102
01103 InterpreterItem
01104 construct_ulong( unsigned long int l )
01105 {
01106 return PyLong_FromUnsignedLong(l);
01107 }
01108
01109 InterpreterItem construct_list( Entity::ArgList& alist )
01110 {
01111 PyObject* p = PyList_New(0);
01112 if ( 0 == p )
01113 {
01114 return 0;
01115 }
01116 Entity::ArgList::iterator itr = alist.begin();
01117 Entity::ArgList::iterator end = alist.end();
01118 for ( ; itr != end ; ++itr )
01119 {
01120
01121 PyList_Append( p, *itr );
01122 }
01123 return p;
01124 }
01125
01126 InterpreterItem construct_boolean( bool b )
01127 {
01128 return PyBool_FromLong(b);
01129 }
01130
01131 InterpreterItem construct_time( const Time& t )
01132 {
01133 PyObject* p = PyList_New(0);
01134 if ( 0 == p )
01135 {
01136 return 0;
01137 }
01138 PyList_Append( p, PyLong_FromLong(t.tv.tv_sec) );
01139 PyList_Append( p, PyLong_FromLong(t.tv.tv_usec) );
01140 return p;
01141 }
01142
01144 static unsigned char vlevel = 0;
01145
01146 unsigned char
01147 verbosity()
01148 {
01149 return vlevel;
01150 }
01151
01152 PyObject*
01153 export_entity( Entity* e )
01154 {
01155 if ( 0 == e ) return 0;
01156
01157
01158 PySimEntity* self =
01159 (PySimEntity*)sim_PySimEntity.tp_alloc(&sim_PySimEntity,0);
01160 if ( 0 == self )
01161 {
01162 std::cerr << "Could not allocate a new sim.Entity" << std::endl;
01163 return 0;
01164 }
01165 self->type = PyString_FromString( e->identifier().c_str() );
01166 if ( 0 == self->type )
01167 {
01168 Py_DECREF(self);
01169 return 0;
01170 }
01171 self->e = e;
01172 self->id = entityList.size();
01173 entityList.push_back(self);
01174
01175
01176 Py_INCREF(self);
01177 Py_INCREF(self);
01178
01179 return (PyObject*)self;
01180 }
01181
01183
01184
01185
01186
01188 void
01189 cleanup()
01190 {
01191 SimEntityVec::iterator itr = entityList.begin();
01192 SimEntityVec::iterator end = entityList.end();
01193 for ( ; itr != end ; ++itr )
01194 {
01195 if ( 0 != (*itr)->e )
01196 {
01197 (*itr)->e->finalize();
01198 delete (*itr)->e;
01199 }
01200 PySimEntity_dealloc( *itr );
01201 }
01202 Registry::clean();
01203 }
01204
01208 int main(int argc, char** argv)
01209 {
01210 typedef std::queue< std::string > StringQ;
01211
01212
01213 std::string python_path;
01214 StringQ module_path;
01215 StringQ import_files;
01216 Entity::ArgList alist;
01217 int arg = 0;
01218 while ( -1 != arg )
01219 {
01220 arg = getopt(argc,argv,"p:i:L:va:");
01221 switch(arg)
01222 {
01223 case 'p' :
01224 python_path = optarg;
01225 break;
01226 case 'i' :
01227 import_files.push( optarg );
01228 break;
01229 case 'L' :
01230 module_path.push( optarg );
01231 break;
01232 case 'v' :
01233 ++vlevel;
01234 break;
01235 case 'a' :
01236 alist.push_back( construct_string(optarg) );
01237 break;
01238 case ':' :
01239 case '?' :
01240 std::cerr << "Add usage string!!" << std::endl;
01241 ::exit(1);
01242 }
01243 }
01244
01245 sim_args = construct_list(alist);
01246
01247
01248 StringQ script_files;
01249 for ( int i = optind ; i < argc ; ++i )
01250 {
01251 script_files.push( argv[i] );
01252 }
01253
01254
01255 if ( python_path.length() > 0 )
01256 {
01257 Py_SetProgramName((char*)python_path.c_str());
01258 }
01259 else
01260 {
01261
01262
01263
01264
01265
01266 Py_SetProgramName((char*)PYEXE);
01267 }
01268 Py_AtExit( cleanup );
01269 Py_Initialize();
01270 PySys_SetArgv(argc,argv);
01271
01272
01273 initsim();
01274
01275
01276 PyRun_SimpleString("import sys");
01277 PyRun_SimpleString("sys.path.append('"SHLIB_DIR"')");
01278 PyRun_SimpleString("sys.path.append('.')");
01279 while ( ! module_path.empty() )
01280 {
01281 std::string dir = module_path.front();
01282 module_path.pop();
01283 std::string cmd = "sys.path.append('";
01284 cmd += dir;
01285 cmd += "')";
01286 if ( PyRun_SimpleString((char*)cmd.c_str()) < 0 )
01287 {
01288 std::cerr << "Error adding " << dir << " to the path\n"
01289 << "exiting" << std::endl;
01290 ::exit(1);
01291 }
01292 }
01293
01294
01295 while ( ! import_files.empty() )
01296 {
01297 std::string mod = import_files.front();
01298 import_files.pop();
01299 std::string cmd = "import ";
01300 cmd += mod;
01301 if ( PyRun_SimpleString((char*)cmd.c_str()) < 0 )
01302 {
01303 std::cerr << "Error importing " << mod << "\n"
01304 << "exiting" << std::endl;
01305 ::exit(1);
01306 }
01307 }
01308
01309
01310 while ( ! script_files.empty() )
01311 {
01312 std::string scr = script_files.front();
01313 script_files.pop();
01314 FILE* fp = fopen(scr.c_str(),"r");
01315 if ( 0 == fp )
01316 {
01317 std::cerr << "Could not open script file " << scr << "\n"
01318 << "exiting" << std::endl;
01319 ::exit(1);
01320 }
01321 if ( PyRun_SimpleFile(fp,(char*)(scr.c_str())) < 0 )
01322 {
01323 std::cerr << "Error running file " << scr << "\n"
01324 << "exiting" << std::endl;
01325 ::exit(1);
01326 }
01327 fclose(fp);
01328 }
01329
01330
01331 int retval = 0;
01332
01333
01334
01335 if ( Py_IsInitialized() )
01336 {
01337 PyRun_SimpleString("import readline");
01338 retval = PyRun_InteractiveLoop(stdin,"<stdin>");
01339 }
01340
01341
01342 Py_Exit( retval );
01343
01344 return retval;
01345 }
01346