Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Simulator.cc

Go to the documentation of this file.
00001 #include "Simulator.h"
00002 #include "Main.h"
00003 #include "Motion.h"
00004 #include "SoundPlay.h"
00005 #include "sim.h"
00006 #include "Shared/string_util.h"
00007 #include "Shared/RobotInfo.h"
00008 #include "SimConfig.h"
00009 #include "Shared/debuget.h"
00010 #include "Shared/MarkScope.h"
00011 #include "IPC/MessageReceiver.h"
00012 #include "IPC/RegionRegistry.h"
00013 #include "IPC/FailsafeThread.h"
00014 #include "local/DataSources/FileSystemDataSource.h"
00015 #include "local/DataSources/FileSystemImageSource.h"
00016 #include "local/CommPort.h"
00017 #include "local/DeviceDriver.h"
00018 #include "Events/EventRouter.h"
00019 #include "Events/TextMsgEvent.h"
00020 #include "Motion/PostureEngine.h"
00021 #include "local/DataSources/SensorStateAccessor.h"
00022 
00023 #include <iostream>
00024 #include <iterator>
00025 #include <libxml/tree.h>
00026 
00027 #ifndef DISABLE_READLINE
00028 #  include <readline/readline.h>
00029 #  include <readline/history.h>
00030 #  include <dlfcn.h> // to test if we actually have BSD's libedit emulation
00031 #endif
00032 
00033 using namespace std;
00034 
00035 const float Simulator::avgSpeedupGamma=.99f;
00036 
00037 Simulator::MotionMonitorThread * Simulator::motionHookMonitor=NULL;
00038 Simulator* Simulator::theSim=NULL;
00039 std::set<MotionHook*> Simulator::motionHooks;
00040 
00041 Simulator::Simulator()
00042 : Process(getID(),getClassName()), plist::PrimitiveListener(), plist::CollectionListener(), MessageQueueStatusThread::StatusListener(),
00043 frameCounter(), cmdThread(),
00044 sensorThread(this,&Simulator::sendSensor), sendSensorSent(false), 
00045 cameraQueue(ipc_setup->registerRegion(Simulator::getCameraQueueID(),sizeof(sim::CameraQueue_t))),
00046 sensorQueue(ipc_setup->registerRegion(Simulator::getSensorQueueID(),sizeof(sim::SensorQueue_t))),
00047 timerWakeup(ipc_setup->registerRegion(Simulator::getTimerWakeupID(),sizeof(sim::TimerWakeup_t))),
00048 motionWakeup(ipc_setup->registerRegion(Simulator::getMotionWakeupID(),sizeof(sim::MotionWakeup_t))),
00049 statusRequest(ipc_setup->registerRegion(Simulator::getStatusRequestID(),sizeof(sim::StatusRequest_t))),
00050 soundmanager(ipc_setup->registerRegion(SoundPlay::getSoundManagerID(),sizeof(SoundManager))),
00051 sounds(ipc_setup->registerRegion(SoundPlay::getSoundPlayID(),sizeof(sim::SoundPlayQueue_t))),
00052 events(ipc_setup->registerRegion(Main::getEventsID(),sizeof(sim::EventQueue_t))),
00053 motionout(ipc_setup->registerRegion(Motion::getMotionOutputID(),sizeof(sim::MotionOutput_t))),
00054 motionoutpids(ipc_setup->registerRegion(Motion::getMotionOutputPIDsID(),sizeof(sim::MotionOutputPIDs_t))),
00055 commandQueue(ipc_setup->registerRegion(Simulator::getCommandQueueID(),sizeof(CommandQueue_t))),
00056 cameraStatus(*cameraQueue), sensorStatus(*sensorQueue), timerStatus(*timerWakeup), motionStatus(*motionWakeup), eventsStatus(), etrans(NULL), commandrecv(NULL), motionrecv(NULL), motionpidsrecv(NULL),
00057 frameTimes(), runSpeed(1), lastTimeScale(0), step(STEP_NONE), waitingSteps(0), curLevel(SharedGlobals::CONSTRUCTING),
00058 activeSensors(), activeSensorSrcs(), activeCameras(), activeCameraSrcs(),
00059 fullspeedWallStart(), fullspeedSimStart(), lastFrameWallStart(), avgWallTime(), avgSimTime(),
00060 simLock()
00061 {
00062   theSim=this;
00063   new (&(*cameraQueue)) sim::CameraQueue_t;
00064   new (&(*sensorQueue)) sim::SensorQueue_t;
00065   new (&(*timerWakeup)) sim::TimerWakeup_t;
00066   new (&(*motionWakeup)) sim::MotionWakeup_t;
00067   new (&(*statusRequest)) sim::StatusRequest_t;
00068   new (&(*commandQueue)) CommandQueue_t;
00069   statusRequest->setOverflowPolicy(MessageQueueBase::WAIT);
00070   commandQueue->setOverflowPolicy(MessageQueueBase::WAIT);
00071   sndman=&(*soundmanager);
00072   
00073   DataSource::setSensorFramerate(&globals->sensors.framerate);
00074   
00075   /* Since we do a two stage loading (some stuff in sim.cc launcher, then some command line
00076    *  stuff, then the rest of it now that we're loaded), this is a little tricker than it normally would be. */
00077   // don't remove entries from parse tree, we're going to be adding more and want their values...
00078   sim::config.setSavePolicy(plist::Collection::UNION);
00079   // write out the current values for entries we do have, which may have been modified since originally loaded
00080   sim::config.writeParseTree();
00081   // add communication ports (could just get away with addEntry()'s, but this function is a little more robust)
00082   replaceEntry("CommPorts",CommPort::getRegistry(),"Communication portals for use by device drivers");
00083   // reload from parse tree to get values for these new entries
00084   sim::config.readParseTree();
00085   // now add the rest of our entries - we wanted to make sure the CommPorts get set up first so drivers init more easily
00086   replaceEntry("Drivers",DeviceDriver::getRegistry(),"Settings for device drivers");
00087   // now we're done adding entries, so if there's anything extra in the file, make note of it
00088   sim::config.setUnusedWarning(true);
00089   // reload from parse tree to get values for these new entries
00090   sim::config.readParseTree();
00091   // any future saves should be strict and remove those unused values (...maybe?)
00092   sim::config.setSavePolicy(plist::Collection::SYNC);
00093   
00094   motionWakeup->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00095   timerWakeup->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00096   cameraQueue->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00097   sensorQueue->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00098   sensorQueue->addMessageFilter(frameCounter);
00099   
00100   //handle arguments passed from command line
00101   list<vector<string> > delayed; // will delay setting data queue sources until after other arguments
00102   for(unsigned int i=0; i<sim::cmdlineArgs.size(); i++) {
00103     // this special handling shouldn't really be necessary, but avoids extra resetting and open/closing during initialization
00104     if(sim::cmdlineArgs[i].find(".Source=")!=string::npos) {
00105       vector<string> setarg;
00106       setarg.push_back("set");
00107       setarg.push_back(sim::cmdlineArgs[i]);
00108       delayed.push_back(setarg); // delay setting of source until after options like Frozen or Speed have been set
00109     } else if(sim::cmdlineArgs[i].find(".CommPort=")!=string::npos) {
00110       vector<string> setarg;
00111       setarg.push_back("set");
00112       setarg.push_back(sim::cmdlineArgs[i]);
00113       delayed.push_front(setarg); // delay setting of commports, but before 'Source's
00114     } else {
00115       if(!processCommand(sim::cmdlineArgs[i],false))
00116         cerr << "Occurred while processing " << sim::cmdlineArgs[i] << endl;
00117     }
00118   }
00119   for(list<vector<string> >::const_iterator it=delayed.begin(); it!=delayed.end(); ++it) {
00120     //this avoids dropping initial frame(s)
00121     //if we had set the source before freezing or pausing, might've dropped something between them
00122     if(!cmdSet(*it))
00123       cerr << "Occurred while processing " << (*it)[1] << endl;
00124   }
00125   
00126   // if we were supposed to start up paused, reset clock now that we've set the speed
00127   if(globals->timeScale<=0)
00128     globals->resetBootTime();
00129   
00130   // load startup posture, see also Main and Motion pull defaults from globals->sensorState
00131   if(globals->motion.startPose.size()>0) {
00132     PostureEngine pose(globals->motion.startPose);
00133     for(unsigned int i=0; i<NumOutputs; ++i)
00134       state->outputs[i]=globals->sensorState.outputs[i]=pose(i).value;
00135   }
00136   
00137   globals->motion.verbose.addPrimitiveListener(this);
00138   globals->sensors.sources.addCollectionListener(this);
00139   globals->vision.sources.addCollectionListener(this);
00140   // we'll start listening to globals->timeScale once we hit run()
00141   
00142   cmdThread.start();
00143   
00144   if(sim::config.tgtRunlevel>SharedGlobals::RUNNING)
00145     globals->signalShutdown();
00146   processRunlevel(SharedGlobals::CONSTRUCTING);
00147 }
00148 
00149 Simulator::~Simulator() {
00150   curLevel=SharedGlobals::DESTRUCTING;
00151   globals->vision.sources.clear();
00152   globals->sensors.sources.clear();
00153   DeviceDriver::getRegistry().clear();
00154   CommPort::getRegistry().clear();
00155   DeviceDriver::getRegistry().removeCollectionListener(this);
00156   globals->motion.verbose.removePrimitiveListener(this);
00157   globals->vision.sources.removeCollectionListener(this);
00158   globals->sensors.sources.removeCollectionListener(this);
00159   globals->sensorState.resourceSync = NULL;
00160   DataSource::setSensorFramerate(NULL);
00161   processRunlevel(SharedGlobals::DESTRUCTING);
00162   //::close(STDIN_FILENO); // seems to prevent proper terminal reset on exit...
00163   theSim=NULL;
00164 }
00165 
00166 static void driversChangedFunctor(Simulator* s) { s->plistCollectionEntriesChanged(DeviceDriver::getRegistry()); }
00167 
00168 void Simulator::doStart() {
00169   curLevel=SharedGlobals::STARTING;
00170   Process::doStart();
00171   // this is needed mainly on Mac, as audio callbacks are processed in Simulator group (can't seem to control that)
00172   sndman->InitAccess(*sounds);
00173   
00174   motionHookMonitor = new MotionMonitorThread;
00175   
00176   eventsStatus.setMessageQueue(*events);
00177   if(!sim::config.multiprocess) {
00178     // don't use our own etrans here, because erouter will delete it for us, don't want a double-delete in our destructor...
00179     EventTranslator * forwardTrans = new IPCEventTranslator(*events);
00180     forwardTrans->setTrapEventValue(true);
00181     erouter->setForwardingAgent(getID(),forwardTrans);
00182   } else {
00183     etrans=new IPCEventTranslator(*events);
00184     MotionManager::setTranslator(etrans); //although Simulator shouldn't use any motions...
00185     
00186     // Set up Event Translator to trap and send events to main process
00187     //send everything over except erouter events
00188     for(unsigned int i=0; i<EventBase::numEGIDs; i++)
00189       if(i!=EventBase::erouterEGID)
00190         erouter->addTrapper(etrans,static_cast<EventBase::EventGeneratorID_t>(i));
00191   }
00192   commandrecv = new MessageReceiver(*commandQueue, gotCommand);
00193   
00194   // do this now that the settings have been processed, this is when data sources get their registerSource() called
00195   DeviceDriver::getRegistry().addCollectionListener(this);
00196   
00197   // abortable lets us abort and quit if a driver gets hung up
00198   abortable(&driversChangedFunctor,this);
00199 
00200   processRunlevel(SharedGlobals::STARTING);
00201 }
00202 
00203 void Simulator::run() {
00204   curLevel=SharedGlobals::RUNNING;
00205   if(sim::config.multiprocess) {
00206     for(unsigned int i=0; i<ProcessID::NumProcesses; ++i)
00207       cout << globals->processNames[i] << " pid=" << globals->pids[i] << ";  ";
00208     cout << endl;
00209   }
00210   
00211   motionrecv = new MessageReceiver(*motionout, gotMotion);
00212   motionpidsrecv = new MessageReceiver(*motionoutpids, gotMotionPIDs);
00213   
00214   if(globals->timeScale!=0)
00215     runSpeed=globals->timeScale;
00216   
00217   DataSource::setNeedsSensor(globals->waitForSensors);
00218   if(!globals->waitForSensors) {
00219     resetSpeedMode();
00220   } else {
00221     globals->waitForSensors.addPrimitiveListener(this);
00222     if(globals->sensors.sources.size()==0) {
00223       cout << "WARNING: Ignoring WaitForSensors configuration flag because Sensors has no sources" << endl;
00224       globals->signalHaveSensors();
00225       resetSpeedMode();
00226     } else if(0==std::count_if(motionHooks.begin(),motionHooks.end(),std::mem_fun(&MotionHook::isConnected))) {
00227       cout << "WARNING: Ignoring WaitForSensors configuration flag because there are no connected MotionHooks" << endl;
00228       globals->signalHaveSensors();
00229       resetSpeedMode();
00230     } else {
00231       if(activeSensorSrcs.size()==0) {
00232         std::cout << "WARNING: WaitForSensors is true, but all Sensors.Sources are invalid (";
00233         for(plist::ArrayOf<plist::Primitive<std::string> >::const_iterator it=globals->sensors.sources.begin(); it!=globals->sensors.sources.end(); ++it) {
00234           if(it!=globals->sensors.sources.begin())
00235             std::cout << ", ";
00236           std::cout << **it;
00237         }
00238         std::cout << ")\n         Instantiate the missing drivers, or set WaitForSensors=false to continue." << std::endl;
00239       }
00240       if(globals->timeScale>0) {
00241         resetSpeedMode();
00242         abortable(&SharedGlobals::waitSensors,*globals);
00243       } else {
00244         for(std::set<DataSource*>::const_iterator it=activeSensorSrcs.begin(); it!=activeSensorSrcs.end(); ++it)
00245           abortable(&DataSource::advance,**it);
00246         sendSensorSent=false; // clear the flag to make sure we send since we're not making non-sync calls to sendSensor
00247         sendSensor(true);
00248         while(!globals->haveSensors() && !globals->isShutdown()) {
00249           CallbackThread w4s(&SharedGlobals::waitSensors,*globals,true);
00250           FailsafeThread fs(w4s,0.5,true);
00251           if(w4s.join()==Thread::CANCELLED && 0==std::count_if(motionHooks.begin(),motionHooks.end(),std::mem_fun(&MotionHook::isConnected))) {
00252             cout << "WARNING: Ignoring WaitForSensors configuration flag because there are no longer any connected MotionHooks" << endl;
00253             globals->signalHaveSensors();
00254           }
00255         }
00256         resetSpeedMode();
00257        }
00258     }
00259     globals->waitForSensors.removePrimitiveListener(this);
00260   }
00261   DataSource::setNeedsSensor(false);
00262 
00263   if(globals->timeScale<0)
00264     incrementTime();
00265   globals->timeScale.addPrimitiveListener(this);
00266   
00267   if(sim::config.tgtRunlevel==SharedGlobals::RUNNING)
00268     Process::run();
00269   
00270   globals->timeScale.removePrimitiveListener(this);
00271   if(globals->timeScale<0) {
00272     motionStatus.removeStatusListener(this);
00273     timerStatus.removeStatusListener(this);
00274     sensorStatus.removeStatusListener(this);
00275     cameraStatus.removeStatusListener(this);
00276   }
00277   if(sensorThread.isStarted())
00278     sensorThread.stop().join();
00279   if(globals->timeScale!=0)
00280     setMotionLeavingRealtime(false);
00281   globals->signalShutdown();
00282 }
00283 
00284 void Simulator::plistValueChanged(const plist::PrimitiveBase& pl) {
00285   MarkScope l(simLock);
00286   if(&pl==&globals->timeScale) {
00287     get_time(); // force SharedGlobals to notice the change and update its state
00288     resetSpeedMode();
00289     if(globals->timeScale<0)
00290       incrementTime();
00291     timerWakeup->sendMessage(NULL);
00292     motionWakeup->sendMessage(NULL);
00293   } else if(&pl==&globals->motion.verbose) {
00294     for(std::set<MotionHook*>::iterator it=motionHooks.begin(); it!=motionHooks.end(); ++it)
00295       (*it)->setMotionHookVerbose(globals->motion.verbose);
00296   } else if(&pl==&globals->waitForSensors) {
00297     cout << "Aborting block on WaitForSensors flag" << endl;
00298     DataSource::setNeedsSensor(false);
00299     globals->signalHaveSensors(); // unblock everything waiting on the signal
00300   } else if(std::count(globals->sensors.sources.begin(),globals->sensors.sources.end(),&pl)) {
00301     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00302   } else if(std::count(globals->vision.sources.begin(),globals->vision.sources.end(),&pl)) {
00303     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00304   } else {
00305     cerr << "WARNING: Simulator got a plistValueChanged for an unknown plist primitive";
00306   }
00307 }
00308 void Simulator::plistCollectionEntryAdded(plist::Collection& col, plist::ObjectBase& primitive) {
00309   MarkScope l(simLock);
00310   if(&col==&DeviceDriver::getRegistry()) {
00311     if(DeviceDriver * d=dynamic_cast<DeviceDriver*>(&primitive)) {
00312       if(MotionHook * mh = d->getMotionSink()) {
00313         motionHookMonitor->motionCheckTime.Set();
00314         ASSERT(motionHooks.find(mh)==motionHooks.end(),"new DeviceDriver already has active MotionHook?");
00315         mh->setMotionHookVerbose(globals->motion.verbose);
00316         if(curLevel==SharedGlobals::RUNNING || curLevel==SharedGlobals::STARTING) {
00317           motionHookMonitor->curFuncName="motionStarting()"; motionHookMonitor->curHook=mh;
00318           mh->motionStarting();
00319           motionHookMonitor->curHook=NULL;
00320         }
00321         if(curLevel==SharedGlobals::RUNNING) {
00322           if(globals->timeScale>0) {
00323             motionHookMonitor->curFuncName="enteringRealtime()"; motionHookMonitor->curHook=mh;
00324             mh->enteringRealtime(globals->timeScale);
00325           } else {
00326             motionHookMonitor->curFuncName="leavingRealtime()"; motionHookMonitor->curHook=mh;
00327             mh->leavingRealtime(globals->timeScale<0);
00328           }
00329           motionHookMonitor->curHook=NULL;
00330         }
00331         motionHooks.insert(mh);
00332       }
00333     } else {
00334       cerr << "WARNING: Simulator got a plistCollectionEntryAdded for an unknown primitive type";
00335     }
00336     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00337     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00338   } else if(&col==&globals->sensors.sources) {
00339     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00340   } else if(&col==&globals->vision.sources) {
00341     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00342   } else {
00343     cerr << "WARNING: Simulator got a plistCollectionEntryAdded for an unknown plist collection";
00344   }
00345 }
00346 void Simulator::plistCollectionEntryRemoved(plist::Collection& col, plist::ObjectBase& primitive) {
00347   MarkScope l(simLock);
00348   if(&col==&DeviceDriver::getRegistry()) {
00349     if(DeviceDriver * d=dynamic_cast<DeviceDriver*>(&primitive)) {
00350       if(MotionHook * mh = d->getMotionSink()) {
00351         motionHooks.erase(mh);
00352         motionHookMonitor->motionCheckTime.Set();
00353         if(curLevel==SharedGlobals::RUNNING && globals->timeScale!=0) {
00354           motionHookMonitor->curFuncName="leavingRealtime()"; motionHookMonitor->curHook=mh;
00355           mh->leavingRealtime(false);
00356           motionHookMonitor->curHook=NULL;
00357         }
00358         if(curLevel==SharedGlobals::STARTING || curLevel==SharedGlobals::RUNNING) {
00359           motionHookMonitor->curFuncName="motionStopping()"; motionHookMonitor->curHook=mh;
00360           mh->motionStopping();
00361           motionHookMonitor->curHook=NULL;
00362         }
00363       }
00364     } else {
00365       cerr << "WARNING: Simulator got a plistCollectionEntryRemoved for an unknown primitive type";
00366     }
00367     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00368     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00369   } else if(&col==&globals->sensors.sources) {
00370     dynamic_cast<plist::PrimitiveBase&>(primitive).removePrimitiveListener(this);
00371     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00372   } else if(&col==&globals->vision.sources) {
00373     dynamic_cast<plist::PrimitiveBase&>(primitive).removePrimitiveListener(this);
00374     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00375   } else {
00376     cerr << "WARNING: Simulator got a plistCollectionEntryRemoved for an unknown plist collection";
00377   }
00378 }
00379 void Simulator::plistCollectionEntriesChanged(plist::Collection& col) {
00380   MarkScope l(simLock);
00381   if(&col==&DeviceDriver::getRegistry()) {
00382     for(DeviceDriver::registry_t::const_iterator it=DeviceDriver::getRegistry().begin(); it!=DeviceDriver::getRegistry().end(); ++it) {
00383       if(DeviceDriver * d=DeviceDriver::getRegistry().getInstance(it->first)) {
00384         if(MotionHook * mh = d->getMotionSink()) {
00385           if(motionHooks.find(mh)!=motionHooks.end())
00386             continue; // already activated
00387           motionHookMonitor->motionCheckTime.Set();
00388           mh->setMotionHookVerbose(globals->motion.verbose);
00389           if(curLevel==SharedGlobals::RUNNING || curLevel==SharedGlobals::STARTING) {
00390             motionHookMonitor->curFuncName="motionStarting()"; motionHookMonitor->curHook=mh;
00391             mh->motionStarting();
00392             motionHookMonitor->curHook=NULL;
00393           }
00394           if(curLevel==SharedGlobals::RUNNING) {
00395             if(globals->timeScale>0) {
00396               motionHookMonitor->curFuncName="enteringRealtime()"; motionHookMonitor->curHook=mh;
00397               mh->enteringRealtime(globals->timeScale);
00398             } else {
00399               motionHookMonitor->curFuncName="leavingRealtime()"; motionHookMonitor->curHook=mh;
00400               mh->leavingRealtime(globals->timeScale<0);
00401             }
00402             motionHookMonitor->curHook=NULL;
00403           }
00404           motionHooks.insert(mh);
00405         }
00406       } else {
00407         cerr << "WARNING: In Simulator::plistCollectionEntriesChanged, driver " << it->first << " does not correspond to a known instance" << endl;
00408       }
00409     }
00410     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00411     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00412   } else if(&col==&globals->sensors.sources) {
00413     updateDataSources(activeSensors, activeSensorSrcs, globals->sensors.sources, &DeviceDriver::getSensorSources);
00414   } else if(&col==&globals->vision.sources) {
00415     updateDataSources(activeCameras, activeCameraSrcs, globals->vision.sources, &DeviceDriver::getImageSources);
00416   } else {
00417     cerr << "WARNING: Simulator got a plistCollectionEntriesChanged for an unknown plist collection";
00418   }
00419 }
00420 
00421 void Simulator::messagesRead(MessageQueueBase& mq, unsigned int /*n*/) {
00422   MarkScope l(simLock);
00423   if(globals->timeScale<0) {
00424     //clear corresponding bit in waitingSteps
00425      if(&mq==&(*cameraQueue)) {
00426       //cout << "Camera read, ";
00427       waitingSteps&=~(1<<STEP_CAMERA);
00428     } else if(&mq==&(*sensorQueue)) {
00429       //cout << "Sensor read, ";
00430       waitingSteps&=~(1<<STEP_SENSOR);
00431     } else if(&mq==&(*timerWakeup)) {
00432       //cout << "Timer read, ";
00433       waitingSteps&=~(1<<STEP_TIMER);
00434     } else if(&mq==&(*motionWakeup)) {
00435       //cout << "Motion read, ";
00436       waitingSteps&=~(1<<STEP_MOTION);
00437     } else if(&mq==&(*events)) {
00438       //cout << "Main read event queue (" << events->getMessagesUnread() << "remain), ";
00439       // nothing to do, just waiting for main to catch up before incrementing
00440     } else {
00441       cout << "Unknown message base read (either you meant to add some code to Simulator::messagesRead, or why did you bother to register a listener?)" << endl;
00442     }
00443     //cout << " waiting " << waitingSteps << " events " << events->getMessagesUnread() << endl;
00444     
00445     if(waitingSteps==0 && events->getMessagesUnread()==0) //if that was the last one we were waiting for -- go for the next!
00446       incrementTime();
00447   }
00448 }
00449 
00450 void Simulator::sendCommand(const std::string& cmd) {
00451   static unsigned int cmdSN=0;
00452   char msgname[30];
00453   snprintf(msgname,30,"SimCommand.%d.%d",ProcessID::getID(),cmdSN++);
00454   RCRegion * msg = new RCRegion(msgname,cmd.size());
00455   strcpy(msg->Base(),cmd.c_str());
00456   SharedObject<CommandQueue_t> commandQ(ipc_setup->registerRegion(Simulator::getCommandQueueID(),sizeof(CommandQueue_t)));
00457   commandQ->sendMessage(msg,true);
00458 }
00459 
00460 void Simulator::setMotionStarting() {
00461   // don't need lock, this is only called during single-threaded operation (doStart())
00462   //MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00463   Simulator::motionHookMonitor->motionCheckTime.Set();
00464   Simulator::motionHookMonitor->curFuncName="motionStarting()"; 
00465   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00466     Simulator::motionHookMonitor->curHook=*it;
00467     (*it)->motionStarting();
00468   }
00469   Simulator::motionHookMonitor->curHook=NULL;
00470 }
00471 void Simulator::setMotionStopping() {
00472   // don't need lock, this is only called during single-threaded operation (doStop())
00473   //MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00474   Simulator::motionHookMonitor->motionCheckTime.Set();
00475   Simulator::motionHookMonitor->curFuncName="motionStopping()"; 
00476   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00477     Simulator::motionHookMonitor->curHook=*it;
00478     (*it)->motionStopping();
00479   }
00480   Simulator::motionHookMonitor->curHook=NULL;
00481 }
00482 void Simulator::updateMotion(const float outputs[][NumOutputs]) {
00483   MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00484   Simulator::motionHookMonitor->motionCheckTime.Set();
00485   Simulator::motionHookMonitor->curFuncName="motionCheck(const float[][])"; 
00486   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00487     Simulator::motionHookMonitor->curHook=*it;
00488     (*it)->motionCheck(outputs);
00489   }
00490   Simulator::motionHookMonitor->curHook=NULL;
00491 }
00492 void Simulator::updatePIDs(const std::vector<MotionHook::PIDUpdate>& pids) {
00493   MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00494   Simulator::motionHookMonitor->motionCheckTime.Set();
00495   Simulator::motionHookMonitor->curFuncName="updatePIDs(PIDUpdate)"; 
00496   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00497     Simulator::motionHookMonitor->curHook=*it;
00498     (*it)->updatePIDs(pids);
00499   }
00500   Simulator::motionHookMonitor->curHook=NULL;
00501 }
00502 void Simulator::setMotionLeavingRealtime(bool isFullSpeed) {
00503   MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00504   Simulator::motionHookMonitor->motionCheckTime.Set();
00505   Simulator::motionHookMonitor->curFuncName="leavingRealtime()"; 
00506   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00507     Simulator::motionHookMonitor->curHook=*it;
00508     (*it)->leavingRealtime(isFullSpeed);
00509   }
00510   Simulator::motionHookMonitor->curHook=NULL;
00511   if(theSim!=NULL) { // if actually running in simulator (may be Motion in multiprocess...)
00512     globals->sensorState.resourceSync = NULL;
00513     for(std::set<DataSource*>::const_iterator it=theSim->activeCameraSrcs.begin(); it!=theSim->activeCameraSrcs.end(); ++it)
00514       (*it)->leavingRealtime(isFullSpeed);
00515     for(std::set<DataSource*>::const_iterator it=theSim->activeSensorSrcs.begin(); it!=theSim->activeSensorSrcs.end(); ++it)
00516       (*it)->leavingRealtime(isFullSpeed);
00517   }
00518 }
00519 void Simulator::setMotionEnteringRealtime() {
00520   MarkScope l(theSim ? dynamic_cast<Resource&>(theSim->simLock) : ::emptyResource);
00521   Simulator::motionHookMonitor->motionCheckTime.Set();
00522   Simulator::motionHookMonitor->curFuncName="enteringRealtime()"; 
00523   for(std::set<MotionHook*>::iterator it=theSim->motionHooks.begin(); it!=theSim->motionHooks.end(); ++it) {
00524     Simulator::motionHookMonitor->curHook=*it;
00525     (*it)->enteringRealtime(globals->timeScale);
00526   }
00527   Simulator::motionHookMonitor->curHook=NULL;
00528   if(theSim!=NULL) { // if actually running in simulator (may be Motion in multiprocess...)
00529     globals->sensorState.resourceSync = syncSensors;
00530     for(std::set<DataSource*>::const_iterator it=theSim->activeCameraSrcs.begin(); it!=theSim->activeCameraSrcs.end(); ++it)
00531       (*it)->enteringRealtime(globals->timeScale);
00532     for(std::set<DataSource*>::const_iterator it=theSim->activeSensorSrcs.begin(); it!=theSim->activeSensorSrcs.end(); ++it)
00533       (*it)->enteringRealtime(globals->timeScale);
00534   }
00535 }
00536 
00537 const TimeET Simulator::MotionMonitorThread::timeout(1000L);
00538 unsigned int Simulator::MotionMonitorThread::runloop() {
00539   if(timeout < motionCheckTime.Age()) {
00540     float blockTime = static_cast<unsigned int>(motionCheckTime.Age().Value()*10+.5)/10.0f;
00541     if(curHook==NULL) {
00542       std::cerr << "Looks like " << ProcessID::getIDStr() << " has been stuck for " << blockTime << " seconds, but I can't tell where, try attaching debugger?" << std::endl;
00543       return 2000000;
00544     }
00545     const DeviceDriver * guilty=NULL;
00546     for(DeviceDriver::registry_t::const_iterator it=DeviceDriver::getRegistry().begin(); it!=DeviceDriver::getRegistry().end(); ++it) {
00547       if(DeviceDriver * d=DeviceDriver::getRegistry().getInstance(it->first)) {
00548         if(curHook == d->getMotionSink()) {
00549           guilty = d;
00550         }
00551       }
00552     }
00553     if(guilty==NULL) {
00554       std::cerr << ProcessID::getIDStr() << " has blocked within " << curFuncName << " on an unknown " << " MotionHook with typeid '" << typeid(*curHook).name() << "' @" << curHook << " for " << motionCheckTime.Age() << std::endl;
00555     } else {
00556       std::cerr << ProcessID::getIDStr() << " has blocked within " << curFuncName << " on MotionHook with typeid '" << typeid(*curHook).name() << "'";
00557       if(guilty->getName()==guilty->getClassName())
00558         std::cerr << " from driver " << guilty->getName();
00559       else
00560         std::cerr << " from driver instance " << guilty->getName() << " (type " << guilty->getClassName() << ")";
00561       std::cerr << " for " << blockTime << " seconds" << std::endl;
00562     }
00563   }
00564   return 2000000;
00565 }
00566 
00567 
00568 void Simulator::doStop() {
00569   curLevel=SharedGlobals::STOPPING;
00570   commandrecv->finish();
00571   delete commandrecv;
00572   commandrecv=NULL;
00573   motionrecv->finish();
00574   delete motionrecv;
00575   motionrecv=NULL;
00576   motionpidsrecv->finish();
00577   delete motionpidsrecv;
00578   motionpidsrecv=NULL;
00579   setMotionStopping();
00580   delete motionHookMonitor;
00581   motionHookMonitor=NULL;
00582   
00583   if(!sim::config.multiprocess) {
00584     erouter->setForwardingAgent(getID(),NULL);
00585     MotionManager::setTranslator(NULL);
00586   } else {
00587     erouter->removeTrapper(etrans);
00588     delete etrans;
00589     etrans=NULL;
00590     MotionManager::setTranslator(NULL);
00591   }
00592   
00593   processRunlevel(SharedGlobals::STOPPING);
00594   Process::doStop();
00595 }
00596 
00597 
00598 Simulator::CommandThread::~CommandThread() {
00599   if(isStarted()) {
00600     interrupt();
00601     join();
00602   }
00603 }
00604 
00605 #ifndef DISABLE_READLINE
00606 extern int rl_catch_signals; // libedit doesn't export this, but does provide the symbol
00607 #endif
00608 
00609 void* Simulator::CommandThread::run() {
00610   Simulator * simp=dynamic_cast<Simulator*>(Process::getCurrent());
00611   ASSERTRETVAL(simp!=NULL,"CommandThread not in Simulator!",NULL);
00612   string prompt; // initially prompt is empty because it will be buried in startup text anyway
00613   // we'll display another prompt at the end of launch (or if user hits enter)
00614   while(true) {
00615     testCancel();
00616     string line;
00617 #ifndef DISABLE_READLINE
00618     // Mac OS X ships with BSD libedit emulation, which apparently crashes (as of 10.6.3) if you override rl_getc_function (WTF)
00619     // Detect this condition:
00620     {
00621       // rl_gnu_readline_p is not defined in libedit, and if it were, should be zero
00622       static bool tested=false, haveGNU;
00623       if(!tested) {
00624         void* gnuFlag = dlsym(RTLD_DEFAULT,"rl_gnu_readline_p");
00625         haveGNU = (gnuFlag!=NULL && *reinterpret_cast<int*>(gnuFlag));
00626         tested=true; // don't repeat test for every prompt
00627       }
00628       if(haveGNU)
00629         rl_getc_function = ::getc; // the default rl_getc screws up thread cancellation, just use regular getc instead
00630       // if not using GNU readline, don't need to override rl_getc (the libedit version doesn't eat signals), so can just ignore this
00631     }
00632     rl_catch_signals = 0;
00633     char* readin=readline(prompt.c_str());
00634     if(readin==NULL) {
00635       cout << endl;
00636       simp->cmdQuit(vector<string>());
00637       break;
00638     }
00639     line=readin;
00640     free(readin);
00641 #else
00642     cout << prompt << flush;
00643     getline(cin,line);
00644     if(!cin) {
00645       cout << endl;
00646       simp->cmdQuit(vector<string>());
00647       break;
00648     }
00649 #endif
00650     simp->processCommand(line,true);
00651     prompt = sim::config.cmdPrompt;
00652   }
00653   return NULL;
00654 }
00655 
00656 void Simulator::CommandThread::runInitThread(Thread& th) {
00657   Thread::NoCancelScope nc;
00658   {
00659     MarkScope l(initThreadsLock);
00660     th.start();
00661     initThreads.insert(&th);
00662   }
00663   th.join();
00664   {
00665     MarkScope l(initThreadsLock);
00666     initThreads.erase(&th);
00667   }
00668 }
00669 void Simulator::CommandThread::abortInitThreads() {
00670   MarkScope l(initThreadsLock);
00671   std::for_each(initThreads.begin(),initThreads.end(),std::mem_fun(&Thread::stop));
00672 }
00673 
00674 
00675 
00676 void Simulator::resetSpeedMode() {
00677   if(globals->timeScale<=0) {
00678     if(sensorThread.isStarted()) {
00679       sensorThread.stop();
00680       //sensorThread.join(); // can't join because runfor/runto pause might be triggered within LoadFileThread's get_time() call
00681     }
00682     if(motionHookMonitor->isStarted() && curLevel==SharedGlobals::RUNNING)
00683       motionHookMonitor->stop();
00684   }
00685   if( (lastTimeScale>0 && globals->timeScale<=0) // was realtime, now non-realtime...
00686      || (lastTimeScale==0 && globals->timeScale<0) // or was paused, now full-speed...
00687      || (lastTimeScale<0 && globals->timeScale==0) ) { // or was full-speed now paused...
00688     setMotionLeavingRealtime(globals->timeScale<0); // 
00689   } else if(lastTimeScale<=0 && globals->timeScale>0) {
00690     setMotionEnteringRealtime();
00691   }
00692   if(curLevel==SharedGlobals::RUNNING) {
00693     if(globals->timeScale>0) {
00694       if(!sensorThread.isStarted())
00695         sensorThread.start();
00696       if(!motionHookMonitor->isStarted())
00697         motionHookMonitor->start();
00698     }
00699   } else {
00700     if(!motionHookMonitor->isStarted())
00701       motionHookMonitor->start();
00702   }
00703   
00704   if(globals->timeScale<0) {
00705     cameraQueue->setOverflowPolicy(MessageQueueBase::WAIT);
00706     sensorQueue->setOverflowPolicy(MessageQueueBase::WAIT);
00707     // these status listener calls check to prevent duplicate listeners
00708     cameraStatus.addStatusListener(this);
00709     sensorStatus.addStatusListener(this);
00710     timerStatus.addStatusListener(this);
00711     motionStatus.addStatusListener(this);
00712     eventsStatus.addStatusListener(this);
00713     fullspeedWallStart.Set();
00714     fullspeedSimStart=globals->simulatorTime;
00715     lastFrameWallStart.Set();
00716     avgWallTime=avgSimTime=0;
00717   } else {
00718     cameraQueue->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00719     sensorQueue->setOverflowPolicy(MessageQueueBase::DROP_OLDEST);
00720     eventsStatus.removeStatusListener(this);
00721     motionStatus.removeStatusListener(this);
00722     timerStatus.removeStatusListener(this);
00723     sensorStatus.removeStatusListener(this);
00724     cameraStatus.removeStatusListener(this);
00725   }
00726   if(globals->timeScale==0)
00727     globals->setAutoPauseTime(-1U);
00728   lastTimeScale=globals->timeScale;
00729 }
00730 
00731 void Simulator::replaceEntry(const std::string& name, plist::Dictionary& d, const std::string& comment) {
00732   plist::Dictionary::const_iterator it = sim::config.findEntry(name);
00733   if(it==sim::config.end()) {
00734     sim::config.addEntry(name,d,comment);
00735   } else {
00736     d.set(*it->second);
00737     sim::config.setEntry(name,d);
00738     sim::config.setComment(name,comment);
00739   }
00740 }
00741 
00742 bool Simulator::sendSensor(bool syncCall) {
00743   bool sent=false;
00744   Thread::NoCancelScope nc;
00745   if(!syncCall)
00746     sendSensorSent=false;
00747   if(globals->sensorState.dirty) {
00748     if(!syncCall)
00749       return false; // this is counter-intuitive, but we'll reduce latency by waiting for the next update
00750     if(sendSensorSent)
00751       return false; // already sent an update for this period, don't exceed requested frame rate
00752     if(globals->sensors.verbose>=2)
00753       std::cout << "Sending sensor update at " << get_time() << std::endl;
00754     ++globals->sensorState.frameNumber;
00755     globals->sensorState.dirty=false;
00756     sensorQueue->sendMessage(NULL);
00757     sendSensorSent=sent=true;
00758   } else if(globals->sensors.heartbeat) {
00759     unsigned int curTime = get_time();
00760     unsigned int tgtTime = globals->sensorState.timestamp + static_cast<unsigned int>(1000.f / globals->sensors.framerate + 0.5f);
00761     //std::cout << "Candidate heartbeat " << tgtTime << " at " << curTime << std::endl;
00762     if(tgtTime<=curTime) {
00763       if(globals->sensors.verbose>=3)
00764         std::cout << "Sending sensor heartbeat at " << curTime << std::endl;
00765       ++globals->sensorState.frameNumber;
00766       globals->sensorState.timestamp=curTime;
00767       sensorQueue->sendMessage(NULL);
00768       sent=true;
00769     }
00770   }
00771   return sent;
00772 }
00773 
00774 unsigned int Simulator::nextVisionTime() {
00775   unsigned int vis=-1U;
00776   for(std::set<DataSource*>::const_iterator it=activeCameraSrcs.begin(); it!=activeCameraSrcs.end(); ++it) {
00777     if(!(*it)->getFrozen())
00778       vis = std::min(vis,(*it)->nextTimestamp());
00779   }
00780   return vis;
00781 }
00782 
00783 unsigned int Simulator::nextSensorTime() {
00784   unsigned int tpf = static_cast<unsigned int>(1000/globals->sensors.framerate + .5f);
00785   return (get_time()/tpf + 1)*tpf;
00786 }
00787 
00788 void Simulator::incrementTime() {
00789   MarkScope l(simLock);
00790   waitingSteps=getNextFrame();
00791   if(waitingSteps==0)
00792     return;
00793   unsigned int next=*frameTimes.begin();
00794   if(next>globals->simulatorTime) {
00795     unsigned int adv=next-globals->simulatorTime;
00796     avgWallTime=avgWallTime*avgSpeedupGamma + (float)lastFrameWallStart.Age().Value()*(1-avgSpeedupGamma);
00797     avgSimTime=avgSimTime*avgSpeedupGamma + adv*(1-avgSpeedupGamma);
00798     lastFrameWallStart.Set();
00799     //cout << "inc " << (avgSimTime/avgWallTime/1000) << " " << waitingSteps << endl;
00800     globals->simulatorTime=next;
00801   }
00802   if(waitingSteps & (1<<STEP_CAMERA)) {
00803     bool sent=false;
00804     for(std::set<DataSource*>::const_iterator it=activeCameraSrcs.begin(); it!=activeCameraSrcs.end(); ++it)
00805       if((*it)->advance())
00806         sent=true;
00807     if(!sent)
00808       waitingSteps &= ~(1<<STEP_CAMERA); // nothing sent, clear waiting flag
00809   }
00810   if(waitingSteps & (1<<STEP_SENSOR)) {
00811     for(std::set<DataSource*>::const_iterator it=activeSensorSrcs.begin(); it!=activeSensorSrcs.end(); ++it)
00812       (*it)->advance();
00813     sendSensorSent=false; // clear the flag to make sure we send since we're not making non-sync calls to sendSensor
00814     if(!sendSensor(true))
00815       waitingSteps &= ~(1<<STEP_SENSOR); // nothing sent, clear waiting flag
00816   }
00817   if(waitingSteps & (1<<STEP_TIMER))
00818     timerWakeup->sendMessage(NULL);
00819   if(waitingSteps & (1<<STEP_MOTION))
00820     motionWakeup->sendMessage(NULL);
00821   if(globals->getAutoPauseTime()<=globals->simulatorTime || (1<<step) & waitingSteps) {
00822     //that was the step we were waiting for, pause sim
00823     globals->timeScale=0;
00824     step=STEP_NONE;
00825     globals->setAutoPauseTime(-1U);
00826   }
00827 }
00828 
00829 unsigned int Simulator::getNextFrame() {
00830   frameTimes.clear();
00831   unsigned int vis = nextVisionTime();
00832   frameTimes.insert(vis);
00833   unsigned int sen = nextSensorTime();
00834   frameTimes.insert(sen);
00835   unsigned int tim=globals->getNextTimer();
00836   frameTimes.insert(tim);
00837   unsigned int mot=globals->getNextMotion();
00838   frameTimes.insert(mot);
00839   unsigned int next=*frameTimes.begin();
00840   //cout << "Testing: " << globals->simulatorTime << " => next camera: "<< vis << " next sensor: " << sen << " next timer: " << tim << " next motion: " << mot << " => " << next << endl;
00841   unsigned int steps=0;
00842   if(next!=-1U) {
00843     if(next==vis) {
00844       steps |= 1<<STEP_CAMERA;
00845     }
00846     if(next==sen) {
00847       steps |= 1<<STEP_SENSOR;
00848     }
00849     if(next==tim) {
00850       steps |= 1<<STEP_TIMER;
00851     }
00852     if(next==mot) {
00853       steps |= 1<<STEP_MOTION;
00854     }
00855   }
00856   return steps;
00857 }
00858 
00859 void Simulator::processRunlevel(SharedGlobals::runlevel_t curRunLevel) {
00860   curLevel=curRunLevel;
00861   if(sim::config.tgtRunlevel==curLevel && (!globals->isShutdown() || curLevel>SharedGlobals::RUNNING))
00862     cout << sim::config.cmdPrompt << flush;
00863   while(sim::config.tgtRunlevel==curLevel && (!globals->isShutdown() || curLevel>SharedGlobals::RUNNING)) {
00864     usleep(500000); // recheck status every half second
00865   }
00866 }
00867 
00868 bool Simulator::processCommand(const std::string& line, bool addToHistory) {
00869   vector<string> args;
00870   vector<unsigned int> offs;
00871   if(!string_util::parseArgs(line,args,offs)) {
00872     cerr << "Mismatched quotes" << endl;
00873     return false;
00874   }
00875   if(args.size()==0)
00876     return true;
00877 #ifndef DISABLE_READLINE
00878   /*    if(current_history()==NULL)
00879     cout << "current_history()==NULL" << endl;
00880   else if(current_history()->line==NULL)
00881     cout << "line == NULL" << endl;
00882   else if(line!=current_history()->line)
00883     cout << "line is different" << endl;
00884   else {
00885     cout << "not added" << endl;
00886     cout << "new line: " << line << endl;
00887     cout << "old line: " << current_history()->line << endl;
00888   }
00889   if(history_get(-1)==NULL)
00890     cout << "history_get(0)==NULL" << endl;
00891   else if(history_get(-1)->line==NULL)
00892     cout << "line 0 == NULL" << endl;
00893   else {
00894     cout << "line 0: " << history_get(-1)->line << endl;
00895     if(line!=history_get(-1)->line)
00896       cout << "line 0 is different" << endl;
00897     else
00898       cout << "0 not added" << endl;
00899   }
00900   */  
00901   if(addToHistory && (current_history()==NULL || current_history()->line==NULL || line!=current_history()->line))
00902     add_history(line.c_str());
00903 #endif
00904   if(args[0]=="shutdown" || args[0]=="quit" || args[0]=="exit") {
00905     cmdQuit(args);
00906   } else if(args[0]=="load") {
00907     cmdLoad(args);
00908   } else if(args[0]=="save") {
00909     cmdSave(args);
00910   } else if(args[0]=="runlevel") {
00911     cmdRunlevel(args);
00912   } else if(args[0]=="get_time") {
00913     cout << "Current time is " << get_time() << endl;
00914   } else if(args[0]=="print") {
00915     cmdPrint(args);
00916   } else if(args[0]=="set") {
00917     cmdSet(args);
00918   } else if(args[0]=="runto") {
00919     cmdRun(args,false);
00920   } else if(args[0]=="runfor") {
00921     cmdRun(args,true);
00922   } else if(args[0]=="run" || args[0]=="r") {
00923     cmdRun(args);
00924   } else if(args[0]=="pause" || args[0]=="p") {
00925     cmdPause(args);
00926   } else if(args[0]=="help") {
00927     cmdHelp(args);
00928   } else if(args[0]=="step") {
00929     cmdStep(args);
00930   } else if(args[0]=="status") {
00931     cmdStatus(args);
00932   } else if(args[0]=="advance") {
00933     cmdAdvance(args);
00934   } else if(args[0]=="freeze") {
00935     cmdFreeze(true,args);
00936   } else if(args[0]=="unfreeze") {
00937     cmdFreeze(false,args);
00938   } else if(args[0]=="reset") {
00939     cmdReset(args);
00940   } else if(args[0]=="new") {
00941     cmdNew(args);
00942   } else if(args[0]=="delete") {
00943     cmdDelete(args);
00944   } else if(args[0]=="post") {
00945     cmdPost(args);
00946   } else if(args[0]=="msg") {
00947     cmdMsg(args);
00948   } else {
00949     unsigned int i;
00950     for(i=0; i<args.size(); ++i) {
00951       if(args[i].find("=")!=string::npos) {
00952         cmdSet(args);
00953         break;
00954       }
00955     }
00956     if(i==args.size()) {
00957       cout << "Unknown command '" << args[0] << "'" << endl;
00958       return false;
00959     }
00960   }
00961   return true;
00962 }
00963 
00964 bool Simulator::gotCommand(RCRegion* msg) {
00965   Simulator * simp=dynamic_cast<Simulator*>(Process::getCurrent());
00966   ASSERTRETVAL(simp!=NULL,"gotCommand, but not within Simulator process!",true);
00967   simp->processCommand(msg->Base(),false);
00968   return true;
00969 } 
00970 
00971 bool Simulator::gotMotion(RCRegion* msg) {
00972 #ifdef DEBUG
00973   Simulator * simp=dynamic_cast<Simulator*>(Process::getCurrent());
00974   ASSERTRETVAL(simp!=NULL,"gotMotion, but not within Simulator process!",true);
00975 #endif
00976   updateMotion(reinterpret_cast<float(*)[NumOutputs]>(msg->Base()));
00977   return true;
00978 }
00979 
00980 bool Simulator::gotMotionPIDs(RCRegion* msg) {
00981 #ifdef DEBUG
00982   Simulator * simp=dynamic_cast<Simulator*>(Process::getCurrent());
00983   ASSERTRETVAL(simp!=NULL,"gotMotion, but not within Simulator process!",true);
00984 #endif
00985   std::vector<MotionHook::PIDUpdate> updates;
00986   unsigned int num = msg->Size()/sizeof(MotionHook::PIDUpdate);
00987   MotionHook::PIDUpdate * incoming = reinterpret_cast<MotionHook::PIDUpdate*>(msg->Base());
00988   updates.reserve(num);
00989   std::copy(incoming,incoming+num,std::back_inserter(updates));
00990   updatePIDs(updates);
00991   return true;
00992 }
00993 
00994 void Simulator::updateDataSources(std::set<std::string>& active, std::set<DataSource*>& activeSrcs, const plist::ArrayOf<plist::Primitive<std::string> >& requested, getDataSources_t getDataSources) {
00995   std::set<std::string> reqNames;
00996   for(plist::ArrayOf<plist::Primitive<std::string> >::const_iterator it=requested.begin(); it!=requested.end(); ++it) {
00997     (*it)->addPrimitiveListener(this);
00998     reqNames.insert(**it);
00999   }
01000   std::set<std::string> newNames;
01001   std::set_difference(reqNames.begin(),reqNames.end(),active.begin(),active.end(),std::inserter(newNames,newNames.end()));
01002   
01003   // look up the DataSources from the names
01004   std::set<DataSource*> reqSrcs;
01005   for(std::set<std::string>::const_iterator it=reqNames.begin(); it!=reqNames.end(); ++it) {
01006     std::string errStr;
01007     lookupDataSource(*it, getDataSources, reqSrcs, errStr);
01008     if(errStr.size()>0) {
01009       if(newNames.count(*it))
01010         std::cerr << errStr << std::endl;
01011     }
01012   }
01013   
01014   // figure out which data sources have been added and which have been removed
01015   std::set<DataSource*> newSrcs, delSrcs;
01016   std::set_difference(reqSrcs.begin(),reqSrcs.end(),activeSrcs.begin(),activeSrcs.end(),std::inserter(newSrcs,newSrcs.end()));
01017   std::set_difference(activeSrcs.begin(),activeSrcs.end(),reqSrcs.begin(),reqSrcs.end(),std::inserter(delSrcs,delSrcs.end()));
01018   
01019   if(curLevel==SharedGlobals::RUNNING) {
01020     if(globals->timeScale!=0) {
01021       // those which have been removed should be stopped
01022       for(std::set<DataSource*>::const_iterator it=delSrcs.begin(); it!=delSrcs.end(); ++it)
01023         (*it)->leavingRealtime(false);
01024     }
01025   }
01026   
01027   if(curLevel>=SharedGlobals::STARTING) {
01028     for(std::set<DataSource*>::const_iterator it=delSrcs.begin(); it!=delSrcs.end(); ++it)
01029       (*it)->deregisterSource();
01030   }
01031   if(getDataSources == &DeviceDriver::getImageSources) {
01032     for(std::set<DataSource*>::const_iterator it=delSrcs.begin(); it!=delSrcs.end(); ++it)
01033       (*it)->setImageQueue(NULL);
01034     for(std::set<DataSource*>::const_iterator it=newSrcs.begin(); it!=newSrcs.end(); ++it)
01035       (*it)->setImageQueue(&*cameraQueue);
01036   }
01037   if(curLevel>=SharedGlobals::STARTING) {
01038     for(std::set<DataSource*>::const_iterator it=newSrcs.begin(); it!=newSrcs.end(); ++it)
01039       (*it)->registerSource();
01040   }
01041   
01042   if(curLevel==SharedGlobals::RUNNING) {
01043     // those which are newly added should be started/updated
01044     if(globals->timeScale<=0) {
01045       for(std::set<DataSource*>::const_iterator it=newSrcs.begin(); it!=newSrcs.end(); ++it)
01046         (*it)->leavingRealtime(globals->timeScale<0);
01047     } else if(globals->timeScale>0) {
01048       for(std::set<DataSource*>::const_iterator it=newSrcs.begin(); it!=newSrcs.end(); ++it)
01049         (*it)->enteringRealtime(globals->timeScale);
01050     }
01051   }
01052   
01053   activeSrcs = reqSrcs;
01054 }
01055 
01056 void Simulator::lookupDataSource(const std::string& name, getDataSources_t getDataSources, std::set<DataSource*>& dataSrcs, std::string& errStr) {
01057   errStr.clear();
01058   std::string::size_type dot=name.find('.');
01059   DeviceDriver* dd=DeviceDriver::getRegistry().getInstance(name.substr(0,dot));
01060   if(dd==NULL) {
01061     errStr = "Could not find driver named '" + name + "' for data source";
01062   } else {
01063     std::map<std::string,DataSource*> dsmap;
01064     (dd->*getDataSources)(dsmap);
01065     if(dsmap.size()==0) {
01066       errStr = "Driver '" + name.substr(0,dot) + "' does not have any data sources";
01067     } else if(dot==std::string::npos) {
01068       // add all the data sources
01069       for(std::map<std::string,DataSource*>::const_iterator ds = dsmap.begin(); ds!=dsmap.end(); ++ds)
01070         dataSrcs.insert(ds->second);
01071     } else {
01072       std::map<std::string,DataSource*>::const_iterator ds=dsmap.find(name.substr(dot+1));
01073       if(ds!=dsmap.end()) {
01074         dataSrcs.insert(ds->second);
01075       } else {
01076         errStr = "Could not find stream named '" + name.substr(dot+1) + "' in driver '" + name.substr(0,dot) + "'";
01077       }
01078     }
01079   }
01080 }
01081 
01082 std::string Simulator::lookupDataSourceName(const DataSource* src) const {
01083   for(DeviceDriver::registry_t::const_iterator it = DeviceDriver::getRegistry().begin(); it!=DeviceDriver::getRegistry().end(); ++it) {
01084     DeviceDriver* dd = DeviceDriver::getRegistry().getInstance(it->first);
01085     std::map<std::string,DataSource*> sources, sensorSources, imageSources;
01086     dd->getSensorSources(sensorSources);
01087     dd->getImageSources(imageSources);
01088     std::merge(sensorSources.begin(),sensorSources.end(), imageSources.begin(),imageSources.end(), std::inserter(sources,sources.end()));
01089     bool foundNonMatch=false;
01090     std::string ans;
01091     for(std::map<std::string,DataSource*>::const_iterator sit=sources.begin(); sit!=sources.end(); ++sit) {
01092       if(sit->second == src) {
01093         if(ans.size()==0)
01094           ans = it->first + "." + sit->first;
01095         else
01096           ans += "/" + sit->first;
01097       } else {
01098         foundNonMatch=true;
01099       }
01100     }
01101     if(ans.size()>0) {
01102       // if all source(s) match, then just return the driver name, otherwise return the full name
01103       return !foundNonMatch ? it->first : ans;
01104     }
01105   }
01106   return std::string();
01107 }
01108 
01109 
01110 void Simulator::cmdQuit(const std::vector<std::string>& /*args*/) {
01111   sim::config.tgtRunlevel=SharedGlobals::DESTRUCTED;
01112   cmdThread.abortInitThreads();
01113   globals->signalShutdown();
01114 }
01115 void Simulator::cmdLoad(const std::vector<std::string>& args) {
01116   if(args.size()>1)
01117     for(unsigned int i=1; i<args.size(); i++) {
01118       cout << "Loading from " << args[i] << "... " << flush;
01119       size_t res=sim::config.loadFile(args[i].c_str());
01120       cout << (res>0 ? "done." : "load failed.") << endl;
01121     }
01122   else {
01123     cout << "Loading from " << sim::config.getLastFile() << "... " << flush;
01124     size_t res=sim::config.loadFile(sim::config.getLastFile().c_str());
01125     cout << (res>0 ? "done." : "load failed.") << endl;
01126   }
01127 }
01128 void Simulator::cmdSave(const std::vector<std::string>& args) {
01129   if(args.size()>1)
01130     for(unsigned int i=1; i<args.size(); i++)
01131       sim::config.saveFile(args[i].c_str());
01132   else {
01133     cout << "Saving to " << sim::config.getLastFile() << "... " << flush;
01134     size_t res=sim::config.saveFile(sim::config.getLastFile().c_str());
01135     cout << (res>0 ? "done." : "save failed.") << endl;
01136   }
01137 }
01138 void Simulator::cmdRunlevel(const std::vector<std::string>& args) {
01139   if(args.size()<=1) {
01140     sim::config.tgtRunlevel=static_cast<SharedGlobals::runlevel_t>(sim::config.tgtRunlevel+1);
01141     cout << "Moving to next runlevel: " << SharedGlobals::runlevel_names[sim::config.tgtRunlevel] << endl;
01142   } else {
01143     try {
01144       sim::config.tgtRunlevel=string_util::makeUpper(args[1]);
01145     } catch(...) {
01146       cout << "Invalid runlevel specification.  Try one of:\n\t";
01147       for(unsigned int i=0; i<SharedGlobals::NUM_RUNLEVELS; i++)
01148         cout << i << ' ' << SharedGlobals::runlevel_names[i] << ", ";
01149       cout << "\nCurrently at " << SharedGlobals::runlevel_names[curLevel] << endl;
01150       return;
01151     }
01152     if(sim::config.tgtRunlevel<curLevel) {
01153       sim::config.tgtRunlevel=curLevel;
01154       cout << "Cannot reduce runlevel, currently at " << curLevel << ' ' << SharedGlobals::runlevel_names[curLevel] << "\n\t";
01155       for(unsigned int i=0; i<SharedGlobals::NUM_RUNLEVELS; i++)
01156         cout << i << ' ' << SharedGlobals::runlevel_names[i] << ", ";
01157       cout << endl;
01158       return;
01159     } else if(sim::config.tgtRunlevel==curLevel) {
01160       cout << "Already at " << curLevel << ' ' << SharedGlobals::runlevel_names[curLevel] << "\n\t";
01161       for(unsigned int i=0; i<SharedGlobals::NUM_RUNLEVELS; i++)
01162         cout << i << ' ' << SharedGlobals::runlevel_names[i] << ", ";
01163       cout << endl;
01164       return;
01165     }
01166   }
01167   if(sim::config.tgtRunlevel>SharedGlobals::RUNNING && curLevel<=SharedGlobals::RUNNING)
01168     globals->signalShutdown();
01169 }
01170 bool Simulator::cmdPrint(const std::vector<std::string>& args) {
01171   if(args.size()==0 || (args[0]=="print" && args.size()==1)) {
01172     plist::filteredDisplay(cout,sim::config,"^[^.].*",REG_EXTENDED,3);
01173     return false;
01174   }
01175   string arg;
01176   for(unsigned int i=(args[0]=="print"?1:0); i<args.size(); i++) {
01177     arg+=args[i];
01178     if(i!=args.size()-1)
01179       arg+=" ";
01180   }
01181   const string WS_PREFIX="WorldState";
01182   if(arg.substr(0,WS_PREFIX.size())==WS_PREFIX) {
01183     return SensorStateAccessor().print(arg);
01184   }
01185   plist::ObjectBase* ob=sim::config.resolveEntry(arg);
01186   if(ob==NULL) {
01187     cout << "'" << arg << "' is unknown" << endl;
01188     return false;
01189   }
01190   plist::filteredDisplay(cout,*ob,"^[^.].*",REG_EXTENDED,3);
01191   return true;
01192 }
01193 bool Simulator::cmdSet(const std::vector<std::string>& args) {
01194   if(args.size()==0 || (args[0]=="set" && args.size()==1)) {
01195     plist::filteredDisplay(cout,sim::config,"^[^.].*",REG_EXTENDED,3);
01196     return false;
01197   }
01198   string arg;
01199   for(unsigned int i=(args[0]=="set"?1:0); i<args.size(); i++) {
01200     arg+=args[i];
01201     if(i!=args.size()-1)
01202       arg+=" ";
01203   }
01204   const string WS_PREFIX="WorldState";
01205   if(arg.rfind("=")==string::npos) {
01206     if(arg.substr(0,WS_PREFIX.size())==WS_PREFIX) {
01207       return SensorStateAccessor().print(arg);
01208     }
01209     plist::ObjectBase* ob=sim::config.resolveEntry(arg);
01210     if(ob==NULL) {
01211       cout << "'" << arg << "' is unknown" << endl;
01212       return false;
01213     }
01214     plist::filteredDisplay(cout,*ob,"^[^.].*",REG_EXTENDED,3);
01215   } else {
01216     return sim::config.resolveAssignment(arg,std::cerr);
01217   }
01218   return false;
01219 }
01220 void Simulator::cmdRun(const std::vector<std::string>& args, bool isRelative) {
01221   if(args.size()<=1) {
01222     cout << "runfor/runto requires an argument" << endl;
01223     return;
01224   }
01225   if(isRelative)
01226     globals->setAutoPauseTime(get_time()+atoi(args[1].c_str()));
01227   else
01228     globals->setAutoPauseTime(atoi(args[1].c_str()));
01229   if(globals->timeScale==0)
01230     globals->timeScale=runSpeed;
01231 }
01232 void Simulator::cmdRun(const std::vector<std::string>& args) {
01233   if(args.size()<=1) {
01234     if(globals->timeScale!=0) {
01235       cout << "Already running" << endl;
01236       return;
01237     }
01238     globals->timeScale=runSpeed;
01239   } else {
01240     float speed=(float)atof(args[1].c_str());
01241     if(speed!=0)
01242       runSpeed=speed;
01243     globals->timeScale=speed;
01244   }
01245 }
01246 void Simulator::cmdPause(const std::vector<std::string>& args) {
01247   if(globals->timeScale==0) {
01248     if(find(args.begin(),args.end(),"quiet")==args.end())
01249       cout << "Already paused" << endl;
01250     return;
01251   }
01252   runSpeed=globals->timeScale;
01253   globals->timeScale=0;
01254 }
01255 void Simulator::cmdHelp(const std::vector<std::string>& args) {
01256   map<string,string> syntax;
01257   syntax["load"]="[file]";
01258   syntax["save"]="[file]";
01259   syntax["runlevel"]="[";
01260   for(unsigned int i=0; i<SharedGlobals::NUM_RUNLEVELS; i++) {
01261     stringstream ss;
01262     ss << i << "|" << SharedGlobals::runlevel_names[i];
01263     if(i!=SharedGlobals::NUM_RUNLEVELS-1)
01264       ss << " | ";
01265     syntax["runlevel"]+=ss.str();
01266   }
01267   syntax["runlevel"]+="]";
01268   syntax["get_time"]="";
01269   syntax["print"]="[var]";
01270   syntax["set"]="[var=value]";
01271   syntax["runto"]="time";
01272   syntax["runfor"]="time";
01273   syntax["run"]="[speed]";
01274   syntax["pause"]="";
01275   syntax["step"]="[camera|sensor|timer|motion]";
01276   syntax["status"]="[Main|Motion|SoundPlay|Simulator|all]*";
01277   syntax["advance"]=syntax["freeze"]=syntax["unfreeze"]="[camera|sensors|all]*";
01278   syntax["reset"]="[camera|sensors|all]";
01279   syntax["new"]="<type> [name]";
01280   syntax["delete"]="name";
01281   syntax["post"]="<generator> <source> <type> [duration]";
01282   syntax["msg"]="<string>";
01283   
01284   map<string,string> help;
01285   
01286   help["load"]="Load HAL configuration from file; if file unspecified, uses last specified file ('hal-$MODEL.plist' by default).\n"
01287     "Note that these files are human-readable XML (with comments!), and you can remove values to specify only a subset of settings.";
01288   
01289   help["save"]="Save HAL configuration to file; if file unspecified, uses last specified file ('hal-$MODEL.plist' by default).\n"
01290     "Note that these files are human-readable XML (with comments!), and you can remove values to specify only a subset of settings.";
01291   
01292   help["runlevel"]="You can specify a runlevel to move to, or if unspecified, the next one.\n"
01293     "You can only move forward runlevels, not backward.  Usually you'll only need RUNNING, "
01294     "unless you are debugging startup/shutdown code or the Tekkotsu itself.";
01295   
01296   help["get_time"]="Displays the simulator time.";
01297   
01298   help["print"]="Displays a configuration entry.  Can also call 'set' without an assignment.";
01299   
01300   help["set"]="Sets HAL configuration variables.  Without any arguments, displays all available variables and their current values.\n"
01301     "Type 'help set <variable>' to get more information about a particular variable.\n"
01302     "You can also use the set command to assign values for buttons and sensors when not connected to physical hardware.  Type 'print WorldState' to see available keys.";
01303   
01304   help["runto"]="Triggers 'run' until the simulator time reaches the specified value and then pauses.";
01305   
01306   help["runfor"]="Triggers 'run' until the simulator time has moved by the specified number of milliseconds, then pauses.";
01307   
01308   help["run"]="Resets speed to last non-zero value (i.e. value prior to last 'pause'), can override by passing a new value as argument.  Can be abbreviated 'r'.";
01309   
01310   help["pause"]="Equivalent to 'set Speed=0'.  Can be abbreviated 'p'.  Stops the flow of time within the simulator.";
01311   
01312   help["step"]="Runs at \"full\" speed until the next indicated time frame, or the next available frame if no type is specified.\n"
01313     "See 'status' for available frames.";
01314   
01315   help["status"]="Displays a status report regarding current time, upcoming keyframes, and semaphore usage.  Specify one or more processes to get more in-depth, per-process status reports.";
01316   
01317   help["advance"]="Sends the next frame for the specified queue(s) in their listed order (can be listed more than once).\n"
01318     "Disregards timestamp information, and doesn't advance time, unlike 'step' command.  No arguments and \"all\" is the same as \"sensors camera\".";
01319   
01320   help["freeze"]="Equivalent to 'set queue.Frozen=true'.\n"
01321     "Stops sending frames from the specified queue(s), but still allows time to move (unlike 'pause').  No arguments is the same as \"all\".  See 'advance' and 'unfreeze'.";
01322   
01323   help["unfreeze"]="Equivalent to 'set queue.Frozen=false'.\n"
01324     "Begin sending frames from the specified queue(s) again.  Timestamps for the file listing are offset by the time spent frozen minus frames advanced so the queue(s) will continue from their current position.  No arguments is the same as \"all\".";
01325   
01326   help["reset"]="Moves the specified data queue(s) back to the first entry in their list.";
01327   
01328   help["new"]="Creates a new driver or communication port instance.\n  Driver types are:";
01329   set<string> driverNames;
01330   DeviceDriver::getRegistry().getTypeNames(driverNames);
01331   for(set<string>::iterator it=driverNames.begin(); it!=driverNames.end(); ++it)
01332     help["new"]+=" "+*it;
01333   set<string> commNames;
01334   CommPort::getRegistry().getTypeNames(commNames);
01335   help["new"]+="\n  Communication ports types are:";
01336   for(set<string>::iterator it=commNames.begin(); it!=commNames.end(); ++it)
01337     help["new"]+=" "+*it;
01338   
01339   help["delete"]="Remove an entry from the CommPort or Drivers list";
01340   
01341   help["post"]="Posts an event to the Main process, same as Controller's !post command";
01342   
01343   help["msg"]="Posts a TextMsgEvent to the Main process, same as Controller's !msg command";
01344     
01345   if(args.size()==1) {
01346     cout << "Available commands: " << endl;
01347     for(map<string,string>::const_iterator it=help.begin(); it!=help.end(); ++it) {
01348       cout << '\t' << it->first << " " << syntax[it->first] << endl;
01349     }
01350     cout << "type 'help <command>' for more information" << endl;
01351   } else {
01352     if(help.find(args[1])==help.end()) {
01353       cout << "The command '"<< args[1] << "' was not found" << endl;
01354       return;
01355     }
01356     if(args.size()==2) {
01357       cout << args[1] << " " << syntax[args[1]] << endl;
01358       cout << help[args[1]] << endl;
01359     } else {
01360       if(args[1]=="set") {
01361         plist::ObjectBase* ob=sim::config.resolveEntry(args[2]);
01362         if(ob==NULL) {
01363           cout << "'" << args[2] << "' is unknown" << endl;
01364           return;
01365         }
01366         size_t n=args[2].rfind('.');
01367         if(n==string::npos)
01368           cout << sim::config.getComment(args[2]) << endl;
01369         else {
01370           ob=sim::config.resolveEntry(args[2].substr(0,n));
01371           if(const plist::Dictionary * dict=dynamic_cast<const plist::Dictionary*>(ob))
01372             cout << dict->getComment(args[2].substr(n+1)) << endl;
01373           else
01374             cout << "'" << args[2].substr(0,n) << "' is not a dictionary" << endl;
01375         }
01376       } else {
01377         cout << args[1] << " " << syntax[args[1]] << endl;
01378         cout << help[args[1]] << endl;
01379       }
01380     }
01381   }
01382 }
01383 void Simulator::cmdStep(const std::vector<std::string>& args) {
01384   if(args.size()<=1) {
01385     if(globals->timeScale!=0)
01386       globals->timeScale=0;
01387     step=STEP_NONE;
01388     incrementTime();
01389     return;
01390   }
01391   if(args.size()>2) {
01392     cout << args[0] << " takes 0 or 1 arguments; " << args.size()-1 << " supplied" << endl;
01393     return;
01394   }
01395   if(args[1]=="camera")
01396     step=STEP_CAMERA;
01397   else if(args[1]=="sensor" || args[1]=="sensors")
01398     step=STEP_SENSOR;
01399   else if(args[1]=="timer")
01400     step=STEP_TIMER;
01401   else if(args[1]=="motion")
01402     step=STEP_MOTION;
01403   else {
01404     cout << args[1] << " is not a valid argument for 'step'.  Type 'help step'." << endl;
01405     return;
01406   }
01407   // TODO
01408   /*
01409   if(step==STEP_CAMERA && vision.frozen && !vision.heartbeat) {
01410     cout << "Camera queue is frozen and has no heartbeat, cannot step (use 'advance' instead)" << endl;
01411     step=STEP_NONE;
01412   } else if(step==STEP_SENSOR && sensors.frozen && !sensors.heartbeat) {
01413     cout << "Sensor queue is frozen and has no heartbeat, cannot step (use 'advance' instead)" << endl;
01414     step=STEP_NONE;
01415   } else*/ {
01416     unsigned int steps=getNextFrame();
01417     if((1<<step) & steps) { // the desired step is the next step -- just increment
01418       if(globals->timeScale!=0)
01419         globals->timeScale=0;
01420       step=STEP_NONE;
01421       incrementTime();
01422     } else if(globals->timeScale!=-1)
01423       globals->timeScale=-1;
01424   }
01425 }
01426 void Simulator::cmdStatus(const std::vector<std::string>& args) {
01427   cout << "Speed is " << static_cast<float>(globals->timeScale);
01428   if(globals->timeScale<0)
01429     cout << " (full speed mode: avg speed=" << ((globals->simulatorTime-fullspeedSimStart)/fullspeedWallStart.Age().Value()/1000) << "x, "
01430       << " current speed=" << (avgSimTime/avgWallTime/1000) << "x)";
01431   cout << endl;
01432   cout << "Current time is " << get_time() << endl;
01433   unsigned int sen=nextSensorTime();
01434   unsigned int tim=globals->getNextTimer();
01435   unsigned int mot=globals->getNextMotion();
01436   cout << "Next camera: ";
01437   if(activeCameraSrcs.size()==0) cout << "(none)"; else {
01438     cout << nextVisionTime() << " (";
01439     for(std::set<DataSource*>::const_iterator it=activeCameraSrcs.begin(); it!=activeCameraSrcs.end(); ++it) {
01440       if(it!=activeCameraSrcs.begin())
01441         cout << ' ';
01442       cout << lookupDataSourceName(*it) << ':' << (*it)->nextName() << '@' << (*it)->nextTimestamp();
01443       if((*it)->getFrozen())
01444         cout << "(frozen)";
01445     }
01446     cout << ")";
01447   }
01448   cout << endl;
01449   // TODO
01450   cout << "Next sensor: ";
01451   if(sen==-1U) cout << "(none)"; else cout << sen;
01452   /*{
01453     if(sensors.frozen)
01454       cout << "Frozen@";
01455     cout << sensors.getDataSource()->nextName();
01456     if(!sensors.frozen || sensors.heartbeat) {
01457       if(sensors.frozen && sensors.heartbeat && sensors.getDataSource()->nextName()!="heartbeat")
01458         cout << " heartbeat";
01459       cout << " scheduled at " << sen;
01460     }
01461   }*/
01462   cout << endl;
01463   cout << "Next timer: ";
01464   if(tim==-1U) cout << "(none)"; else cout << tim;
01465   cout << endl;
01466   cout << "Next motion: ";
01467   if(mot==-1U) cout << "(none)"; else cout << mot;
01468   cout << endl;
01469   unsigned int semUsed=MessageQueueBase::getSemaphoreManager()->used();
01470   unsigned int semMax=semUsed+MessageQueueBase::getSemaphoreManager()->available();
01471   cout << "Semaphores used: " << semUsed << "/" << semMax << " (" << ((semUsed*10000+5)/semMax/10)/10.f << "%)" << endl;
01472   cout << endl;
01473   if(args.size()>1) {
01474     if(args[1].substr(0,6)=="region") {
01475       SemaphoreManager::semid_t sem=statusRequest->addReadStatusListener();
01476       std::set<std::string> tgts;
01477       std::copy(args.begin()+2,args.end(),std::inserter(tgts,tgts.end()));
01478       if(tgts.size()==0)
01479         tgts.insert("all");
01480       for(std::set<std::string>::const_iterator it=tgts.begin(); it!=tgts.end(); ++it) {
01481         RCRegion * region=new RCRegion(it->size()+1);
01482         strncpy(region->Base(),it->c_str(),region->Size());
01483         statusRequest->sendMessage(region);
01484         region->RemoveReference();
01485       }
01486       //wait until they're done to put the prompt back up
01487       if(sem!=statusRequest->getSemaphoreManager()->invalid()) {
01488         statusRequest->getSemaphoreManager()->lower(sem,tgts.size());
01489         statusRequest->removeReadStatusListener(sem);
01490       }
01491       //check to see if we're included:
01492       for(std::set<std::string>::const_iterator it=tgts.begin(); it!=tgts.end(); ++it) {
01493         if(strcasecmp(it->c_str(),getName())==0 || strcasecmp(it->c_str(),"all")==0) {
01494           statusReport(cout);
01495           cout << endl;
01496         }
01497       }
01498     } else if(args[1]=="feedback") {
01499       cout << "Sensor feedback for outputs:\n";
01500       unsigned int len=10;
01501       for(unsigned int i=0; i<NumOutputs; ++i)
01502         if(strlen(outputNames[i])>len)
01503           len=strlen(outputNames[i]);
01504       cout << "    " << setw(len+2) << left << "--OUTPUT--" << "--FEEDBACK-SOURCE--\n";
01505       for(unsigned int i=0; i<NumOutputs; ++i) {
01506         cout << "    " << setw(len+2) << left << outputNames[i];
01507         if(globals->sensorState.providedOutputs[i]==0) {
01508           cout << (globals->motion.feedbackDelay<0 ? "none (Motion.FeedbackDelay is negative)\n" : "motion process (open loop)\n");
01509         } else if(globals->sensorState.providedOutputs[i]==1) {
01510           cout << (globals->motion.feedbackDelay>=0 && globals->motion.override ? "motion process override (open loop)\n" : "sensed by device driver\n");
01511         } else {
01512           if(globals->motion.feedbackDelay>=0 && globals->motion.override)
01513             cout << "motion process override (open loop)\n";
01514           else
01515             cout << "provided by " << globals->sensorState.providedOutputs[i] << " device drivers (may be conflict)\n";
01516         }
01517       }
01518     }
01519   }
01520 }
01521 void Simulator::cmdAdvance(const std::vector<std::string>& args) {
01522   if(curLevel!=SharedGlobals::RUNNING) {
01523     cout << args[0] << " can only be used in the RUNNING runlevel" << endl;
01524     return;
01525   }
01526   
01527   // this defines a local functor so we don't need to repeat the hairy STL algo call a bunch of places
01528   struct { void operator()(const std::set<DataSource*>& src, std::set<DataSource*>& dst) {
01529       std::remove_copy_if(src.begin(), src.end(), std::inserter(dst,dst.end()), std::not1(std::mem_fun(&DataSource::getFrozen)));
01530   } } copyUnfrozen;
01531   
01532   std::set<DataSource*> camSrcs, senSrcs;
01533   
01534   bool isAll=false;
01535   if(args.size()<=1) {
01536     // no arguments supplied, advance all frozen queues
01537     copyUnfrozen(activeCameraSrcs,camSrcs);
01538     copyUnfrozen(activeSensorSrcs,senSrcs);
01539     isAll=true;
01540     
01541   } else for(unsigned int i=1; i<args.size(); ++i) {
01542     // process explicitly named data sources
01543     if(args[i]=="camera" || args[i]=="vision" || args[i]=="image") {
01544       copyUnfrozen(activeCameraSrcs,camSrcs);
01545     } else if(args[i]=="sensors") {
01546       copyUnfrozen(activeSensorSrcs,senSrcs);
01547     } else {
01548       std::string errStrC,errStrS;
01549       
01550       std::set<DataSource*> tmp;
01551       lookupDataSource(args[i], &DeviceDriver::getImageSources, tmp, errStrC);
01552       copyUnfrozen(tmp,camSrcs);
01553       
01554       tmp.clear();
01555       lookupDataSource(args[i], &DeviceDriver::getSensorSources, tmp, errStrS);
01556       copyUnfrozen(tmp,senSrcs);
01557       
01558       if(errStrC.size()>0 && errStrS.size()>0) {
01559         std::cerr << errStrS << std::endl;
01560         return;
01561       }
01562     }
01563   }
01564   
01565   // do all cameras before all sensors
01566   // (this is a heuristic that users want the camera before the sensor values, and at least want a reliable ordering)
01567   for(std::set<DataSource*>::const_iterator it=camSrcs.begin(); it!=camSrcs.end(); ++it) {
01568     SemaphoreManager::semid_t sem=cameraQueue->addReadStatusListener(); //register read status listener before sending!
01569     bool sent = (*it)->advance();
01570     if(!sent && !isAll) // no data in queue and only report empty queue if the queue was explicitly specified
01571       cout << "No data in " << lookupDataSourceName(*it) << " queue" << endl;
01572     if(sent)
01573       cameraQueue->getSemaphoreManager()->lower(sem,true); //block until we know message was read
01574     cameraQueue->removeReadStatusListener(sem);
01575   }
01576   
01577   // cameras have been processed, now do sensors
01578   for(std::set<DataSource*>::const_iterator it=senSrcs.begin(); it!=senSrcs.end(); ++it) {
01579     SemaphoreManager::semid_t sem=sensorQueue->addReadStatusListener(); //register read status listener before sending!
01580     bool sent = (*it)->advance();
01581     if(!sent && !isAll) // no data in queue and only report empty queue if the queue was explicitly specified
01582       cout << "No data in " << lookupDataSourceName(*it) << " queue" << endl;
01583     if(sent && globals->timeScale==0) {
01584       ASSERT(!sensorThread.isStarted(), "advance while paused, yet timeScale is non-zero?");
01585       sendSensorSent=false;
01586       sent = sendSensor(true); // have to manually pump it out since sensorThread (shouldn't) be running
01587     }
01588     if(sent)
01589       sensorQueue->getSemaphoreManager()->lower(sem,true); //block until we know message was read
01590     sensorQueue->removeReadStatusListener(sem);
01591   }
01592 }
01593 void Simulator::cmdFreeze(bool v, const std::vector<std::string>& args) {
01594   std::set<DataSource*> srcs;
01595   
01596   if(args.size()<=1) {
01597     // no arguments supplied, freeze/unfreeze all frozen queues
01598     std::merge(activeSensorSrcs.begin(),activeSensorSrcs.end(), activeCameraSrcs.begin(),activeCameraSrcs.end(), std::inserter(srcs,srcs.end()));
01599     
01600   } else for(unsigned int i=1; i<args.size(); ++i) {
01601     if(args[i]=="camera" || args[i]=="vision" || args[i]=="image") {
01602       srcs.insert(activeCameraSrcs.begin(),activeCameraSrcs.end());
01603     } else if(args[i]=="sensors") {
01604       srcs.insert(activeSensorSrcs.begin(),activeSensorSrcs.end());
01605     } else {
01606       std::string errStrC,errStrS;
01607       lookupDataSource(args[i], &DeviceDriver::getImageSources, srcs, errStrC);
01608       lookupDataSource(args[i], &DeviceDriver::getSensorSources, srcs, errStrS);
01609       if(errStrC.size()>0 && errStrS.size()>0) {
01610         std::cerr << errStrS << std::endl;
01611         return;
01612       }
01613     }
01614   }
01615   
01616   for(std::set<DataSource*>::const_iterator it=srcs.begin(); it!=srcs.end(); ++it)
01617     (*it)->setFrozen(v);
01618 }
01619 void Simulator::cmdReset(const std::vector<std::string>& args) {
01620   std::set<DataSource*> srcs;
01621   for(unsigned int i=1; i<args.size(); ++i) {
01622     if(args[i]=="camera" || args[i]=="vision" || args[i]=="image") {
01623       srcs.insert(activeCameraSrcs.begin(),activeCameraSrcs.end());
01624     } else if(args[i]=="sensors") {
01625       srcs.insert(activeSensorSrcs.begin(),activeSensorSrcs.end());
01626     } else {
01627       std::string errStr;
01628       lookupDataSource(args[i], &DeviceDriver::getSensorSources, srcs, errStr);
01629       if(errStr.size()>0) {
01630         lookupDataSource(args[i], &DeviceDriver::getImageSources, srcs, errStr);
01631         if(errStr.size()>0) {
01632           std::cerr << errStr << std::endl;
01633           return;
01634         }
01635       }
01636     }
01637   }
01638   
01639   for(std::set<DataSource*>::const_iterator it=srcs.begin(); it!=srcs.end(); ++it)
01640     (*it)->reset();
01641 }
01642 void Simulator::cmdNew(const std::vector<std::string>& args) {
01643   set<string> driverNames;
01644   DeviceDriver::getRegistry().getTypeNames(driverNames);
01645   set<string> commNames;
01646   CommPort::getRegistry().getTypeNames(commNames);
01647   if(args.size()<2) {
01648     cerr << "Must specify type to instantiate:\n";
01649     cerr << "  Communication Ports:";
01650     for(set<string>::iterator it=commNames.begin(); it!=commNames.end(); ++it)
01651       cerr << ' ' << *it;
01652     cerr << endl;
01653     cerr << "  Device Drivers:";
01654     for(set<string>::iterator it=driverNames.begin(); it!=driverNames.end(); ++it)
01655       cerr << ' ' << *it;
01656     cerr << endl;
01657     return;
01658   }
01659   std::string type = args[1];
01660   std::string name = (args.size()>2) ? args[2] : args[1];
01661   try {
01662     if(driverNames.find(type)!=driverNames.end()) {
01663       DeviceDriver * d = DeviceDriver::getRegistry().create(type,name);
01664       if(d==NULL) {
01665         cerr << "Error instantiating " << type << " (instance with same name already exists?)" << endl;
01666         return;
01667       }
01668     } else if(commNames.find(type)!=commNames.end()) {
01669       CommPort * c = CommPort::getRegistry().create(type,name);
01670       if(c==NULL) {
01671         cerr << "Error instantiating " << type << " (instance with same name already exists?)" << endl;
01672         return;
01673       }
01674     } else {
01675       cerr << "'" << type << "' is not a valid type for instantiation.  Please choose one of:\n";
01676       cerr << "  Communication Ports:";
01677       for(set<string>::iterator it=commNames.begin(); it!=commNames.end(); ++it)
01678         cerr << ' ' << *it;
01679       cerr << endl;
01680       cerr << "  Device Drivers:";
01681       for(set<string>::iterator it=driverNames.begin(); it!=driverNames.end(); ++it)
01682         cerr << ' ' << *it;
01683       cerr << endl;
01684     }
01685   } catch(const std::exception& e) {
01686     cout << "An exception occured during construction of "<<type<<": " << e.what() << endl;
01687   } catch(...) {
01688     cout << "An exception occured during construction of "<<type << endl;
01689   }
01690 }
01691 
01692 void Simulator::cmdDelete(const std::vector<std::string>& args) {
01693   if(args.size()<2) {
01694     cerr << "Must specify instance to delete:\n";
01695     cerr << "  Communication Ports:";
01696     for(CommPort::registry_t::const_iterator it=CommPort::getRegistry().begin(); it!=CommPort::getRegistry().end(); ++it)
01697       cerr << ' ' << it->first;
01698     cerr << endl;
01699     cerr << "  Device Drivers:";
01700     for(DeviceDriver::registry_t::const_iterator it=DeviceDriver::getRegistry().begin(); it!=DeviceDriver::getRegistry().end(); ++it)
01701       cerr << ' ' << it->first;
01702     cerr << endl;
01703     return;
01704   }
01705   if(DeviceDriver::getRegistry().getInstance(args[1])!=NULL) {
01706     if(!DeviceDriver::getRegistry().destroy(args[1]))
01707       cerr << "Could not delete driver named '" << args[1] << "'" << endl;
01708   } else if(CommPort::getRegistry().getInstance(args[1])!=NULL) {
01709     if(!CommPort::getRegistry().destroy(args[1]))
01710       cerr << "Could not delete comm port named '" << args[1] << "'" << endl;
01711   } else {
01712     // look for a collection entry to remove
01713     string key=string_util::trim(args[1]);
01714     plist::ObjectBase* ob=sim::config.resolveEntry(key);
01715     if(ob==NULL) {
01716       cerr << "'" << key << "' is unknown" << endl;
01717     } else {
01718       string::size_type dotpos = key.rfind(".");
01719       string parent = key.substr(0,dotpos);
01720       string entry = key.substr(dotpos+1);
01721       ob=sim::config.resolveEntry(parent);
01722       if(ob==NULL) {
01723         cerr << "Internal error, could not access parent '" << parent << "' of key '" << key << "' for removal" << endl;
01724       } else if(plist::Collection* col=dynamic_cast<plist::Collection*>(ob)) {
01725         if((col->getLoadPolicy() & plist::Collection::REMOVALS) != plist::Collection::REMOVALS) {
01726           cerr << "Collection '" << parent << "' is not dynamically resizeable, cannot remove entry '" << entry << "'" << endl;
01727         } else if(plist::ArrayBase* arr=dynamic_cast<plist::ArrayBase*>(ob)) {
01728           size_t i = atoi(entry.c_str());
01729           arr->removeEntry(i);
01730         } else if(plist::DictionaryBase* dict=dynamic_cast<plist::DictionaryBase*>(ob)) {
01731           dict->removeEntry(entry);
01732         } else {
01733           cerr << "Internal error, unknown collection type for removing entry '" << entry <<"' from '" << parent << "'" << endl;
01734         }
01735       } else {
01736         cerr << '\'' << parent <<'\'' << " is not a collection, cannot remove entry '" << entry << '\'' << endl;
01737       }
01738     }
01739   }
01740 }
01741 
01742 void Simulator::cmdPost(const std::vector<std::string>& args) {
01743   if(args.size()<4) {
01744     cerr << "Bad post command, need at least 3 arguments: generator source type [duration]" << endl;
01745     return;
01746   }
01747   //parse generator id -- could be a generator name or a numeric value
01748   int egid=0;
01749   for(;egid<EventBase::numEGIDs && args[1]!=EventBase::EventGeneratorNames[egid];egid++) {}
01750   if(egid==EventBase::numEGIDs) {
01751     egid=atoi(args[1].c_str());
01752     if(egid==0 && args[1]!="0") {
01753       cerr << "Bad event generator '" << args[1] << "'" << endl;
01754       return;
01755     }
01756   }
01757   //parse source id -- numeric value, unless egid is buttonEGID, in which case we can look up a button name
01758   //(if you want to add support for other symbolic source types, this is where to do it)
01759   unsigned int name;
01760   if(egid==EventBase::buttonEGID) {
01761     name=capabilities.findButtonOffset(args[2].c_str());
01762     if(name==-1U) {
01763       name=atoi(args[2].c_str());
01764       if(name==0 && args[2]!="0") {
01765         cerr << "Invalid button name or index '" << args[2] << "'" << endl;
01766         return;
01767       }
01768     }
01769   } else {
01770     name=atoi(args[2].c_str());
01771   }
01772   //parse type id -- numeric, name, or abbreviated name
01773   int etid=0;
01774   for(;etid<EventBase::numETIDs && args[3]!=EventBase::EventTypeNames[etid];etid++) {}
01775   if(etid==EventBase::numETIDs) {
01776     etid=0;
01777     for(;etid<EventBase::numETIDs && args[3]!=EventBase::EventTypeAbbr[etid];etid++) {}
01778     if(etid==EventBase::numETIDs) {
01779       etid=atoi(args[3].c_str());
01780       if(etid==0 && args[3]!="0") {
01781         cerr << "Bad event type '" << args[3] << "'" << endl;
01782         return;
01783       }
01784     }
01785   }
01786   //duration field (optional, have to check args.size())
01787   int dur=0;
01788   if(args.size()>4)
01789     dur=atoi(args[4].c_str());
01790   //send event!
01791   SemaphoreManager::semid_t sem=events->addReadStatusListener(); //register read status listener before sending!
01792   erouter->postEvent((EventBase::EventGeneratorID_t)egid,name,(EventBase::EventTypeID_t)etid,dur);
01793   events->getSemaphoreManager()->lower(sem,true); //block until we know message was read
01794   events->removeReadStatusListener(sem);
01795 }
01796 
01797 void Simulator::cmdMsg(const std::vector<std::string>& args) {
01798   SemaphoreManager::semid_t sem=events->addReadStatusListener(); //register read status listener before sending!
01799   string s;
01800   if(args.size()>1)
01801     s=args[1];
01802   for(size_t i=2; i<args.size(); ++i)
01803     s.append(" ").append(args[i]);
01804   erouter->postEvent(TextMsgEvent(s,0));
01805   events->getSemaphoreManager()->lower(sem,true); //block until we know message was read
01806   events->removeReadStatusListener(sem);
01807 }
01808 
01809 
01810 /*! @file
01811  * @brief 
01812  * @author ejt (Creator)
01813  */
01814 

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Mon May 9 05:01:39 2016 by Doxygen 1.6.3