Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

EventLogger.cc

Go to the documentation of this file.
00001 #include "EventLogger.h"
00002 #include "Events/EventRouter.h"
00003 #include "Motion/MMAccessor.h"
00004 #include "Motion/LedMC.h"
00005 #include "ValueEditControl.h"
00006 #include "StringInputControl.h"
00007 #include "NullControl.h"
00008 #include <sstream>
00009 #include "Sound/SoundManager.h"
00010 #include "Vision/FilterBankGenerator.h"
00011 #include "Vision/JPEGGenerator.h"
00012 #include "Shared/Base64.h"
00013 #include "Behaviors/StateNode.h"
00014 
00015 #include <libxml/xmlmemory.h>
00016 #include <libxml/parser.h>
00017 
00018 Socket* EventLogger::logSocket=NULL;
00019 unsigned int EventLogger::logSocketRefCount=0;
00020 int EventLogger::port=10080;
00021 EventLogger * EventLogger::theOne=NULL;
00022 EventLogger::queuedEvents_t EventLogger::queuedEvents;
00023 EventLogger::transStack_t EventLogger::transStack;
00024 
00025 EventLogger::StateMachineListener EventLogger::smProcess;
00026 
00027 EventLogger::EventLogger()
00028   : ControlBase("Event Logger","Allows you to see/log all of the un-trapped events as they are generated"),
00029     logfilePath(), logfile(), verbosity(0), listen() {
00030   for(unsigned int i=0; i<EventBase::numEGIDs; i++) {
00031     std::string tmp=EventBase::EventGeneratorNames[i];
00032     pushSlot(new NullControl(("[ ] "+tmp).c_str(),"Show/hide events from "+tmp));
00033   }
00034   pushSlot(NULL);
00035   pushSlot(new ValueEditControl<unsigned int>("Verbosity","Controls verbosity level: 0=(gen,source,type); 1=0+gen_id,source_id,type_id; 2=1+duration,timestamp; 3=2+magnitude; additional columns may be added for subclass info","Please enter a new verbosity level: 0=(gen,source,type); 1=0+gen_id,source_id,type_id; 2=1+duration,timestamp; 3=2+magnitude; additional columns may be added for subclass info",&verbosity));
00036   pushSlot(new ControlBase("[X] Console Output","If selected, outputs events to the console"));
00037   pushSlot(new StringInputControl("[ ] File Output","Please enter the filename to log to (in /ms/...)"));
00038   if(logSocket==NULL) {
00039     theOne=this;
00040     ASSERT(logSocketRefCount==0,"logSocket is NULL, ref count is non-zero");
00041     logSocket=wireless->socket(Socket::SOCK_STREAM,1024,1<<15);
00042     wireless->setDaemon(logSocket);
00043     wireless->setReceiver(logSocket, callback);
00044     wireless->listen(logSocket,port);
00045   }
00046   logSocketRefCount++;
00047 }
00048 
00049 EventLogger::~EventLogger() {
00050   while(!queuedEvents.empty())
00051     queuedEvents.pop();
00052   clearSlots();
00053   if(--logSocketRefCount==0) {
00054     wireless->setDaemon(logSocket,false);
00055     wireless->close(logSocket);
00056     logSocket=NULL;
00057   }
00058   if(theOne==this)
00059     theOne=NULL;
00060 }
00061 
00062 ControlBase* EventLogger::doSelect() {
00063   ControlBase* ans=this;
00064   for(unsigned int i=0; i<hilights.size(); i++) {
00065     unsigned int cur=hilights[i];
00066     if(cur<EventBase::numEGIDs) {
00067       if(options[cur]->getName()[1]!=' ') {
00068         erouter->removeListener(this,(EventBase::EventGeneratorID_t)(cur));
00069         setStatus(cur,' ');
00070       } else {
00071         erouter->addListener(this,(EventBase::EventGeneratorID_t)(cur));
00072         setStatus(cur,'X');
00073       }
00074     } else if(cur==EventBase::numEGIDs+1) {
00075       ans=options[cur];
00076     } else if(cur==EventBase::numEGIDs+2) {
00077       if(options[cur]->getName()[1]!=' ') {
00078         setStatus(cur,' ');
00079       } else {
00080         setStatus(cur,'X');
00081       }
00082     } else if(cur==EventBase::numEGIDs+3) {
00083       if(options[cur]->getName()[1]!=' ') {
00084         logfile.close();
00085         options[cur]->setName("[ ] File Output");
00086       } else {
00087         ans=options[cur];
00088       }
00089     }
00090     sndman->playFile(config->controller.select_snd);
00091   }
00092   if(ans==this)
00093     refresh();
00094   return ans;
00095 }
00096 
00097 void EventLogger::refresh() {
00098   checkLogFile();
00099   ControlBase::refresh();
00100 }
00101 
00102 //!sends all events received to stdout and/or logfile
00103 void EventLogger::processEvent(const EventBase& event) {
00104   std::string logdata = event.getDescription(true,verbosity);
00105   if(options[EventBase::numEGIDs+2]->getName()[1]=='X')
00106     sout->printf("EVENT: %s\n",logdata.c_str());
00107   if(logSocket!=NULL && wireless->isConnected(logSocket->sock)) {
00108     xmlNode * cur = xmlNewNode(NULL,(const xmlChar*)"");
00109     xmlSetProp(cur,(const xmlChar*)"type",(const xmlChar*)"log");
00110     xmlNode * desc = xmlNewNode(NULL,(const xmlChar*)"param");
00111     event.saveXML(cur);
00112     xmlAddChild(cur,desc);
00113     xmlSetProp(desc,(const xmlChar*)"name",(const xmlChar*)"description");
00114     xmlSetProp(desc,(const xmlChar*)"value",(const xmlChar*)event.getDescription(true,3).c_str());
00115     xmlBuffer* buf=xmlBufferCreate();
00116     xmlDoc * doc = xmlNewDoc((const xmlChar*)"1.0");
00117     int n=xmlNodeDump(buf,doc,cur,0,1);
00118     xmlFreeNode(cur);
00119     xmlFreeDoc(doc);
00120     byte * nbuf = logSocket->getWriteBuffer(n+1);
00121     if(nbuf!=NULL) {
00122       memcpy(nbuf,xmlBufferContent(buf),n);
00123       nbuf[n]='\n';
00124       logSocket->write(n+1);
00125     }
00126     xmlBufferFree(buf);
00127   }
00128   checkLogFile();
00129   if(logfile)
00130     logfile << logdata << std::endl;
00131 }
00132 
00133 void EventLogger::logImage(FilterBankGenerator& fbg, unsigned int layer, unsigned int channel, const BehaviorBase* source/*=NULL*/) {
00134   if(logSocket==NULL || !wireless->isConnected(logSocket->sock))
00135     return;
00136 
00137   char * binbuf;
00138   unsigned int len;
00139   if(JPEGGenerator* jpeg=dynamic_cast<JPEGGenerator*>(&fbg)) {
00140     binbuf=(char*)jpeg->getImage(layer,channel);
00141     len=jpeg->getImageSize(layer,channel);
00142   } else {
00143     fbg.selectSaveImage(layer,channel);
00144     len=fbg.getBinSize();
00145     binbuf=new char[len];
00146     fbg.saveBuffer(binbuf,len);
00147   }
00148   std::string b64buf=base64::encode(binbuf,len);
00149   if(binbuf!=(char*)fbg.getImage(layer,channel)) //cached, should be a simple return
00150     delete [] binbuf;
00151   
00152   xmlNode * cur = xmlNewNode(NULL,(const xmlChar*)"event");
00153   xmlSetProp(cur,(const xmlChar*)"type",(const xmlChar*)"image");
00154   if(source!=NULL)
00155     xmlSetProp(cur,(const xmlChar*)"sid",(const xmlChar*)source->getName().c_str());
00156   char timebuf[20];
00157   snprintf(timebuf,20,"%d",get_time());
00158   xmlSetProp(cur,(const xmlChar*)"time",(const xmlChar*)timebuf);
00159   xmlNewChild(cur,NULL,(const xmlChar*)"image",(const xmlChar*)b64buf.c_str());
00160   queuedEvents.push(cur);
00161   if(transStack.empty())
00162     dumpQueuedEvents();
00163 }
00164 
00165 void EventLogger::logMessage(std::string msg, const BehaviorBase* source/*=NULL*/, const char* icon/*=NULL*/, unsigned int placement/*=0*/) {
00166   if(logSocket==NULL || !wireless->isConnected(logSocket->sock))
00167     return;
00168 
00169   xmlNode * cur = xmlNewNode(NULL,(const xmlChar*)"event");
00170   xmlSetProp(cur,(const xmlChar*)"type",(const xmlChar*)"userlog");
00171   if(source!=NULL)
00172     xmlSetProp(cur,(const xmlChar*)"sid",(const xmlChar*)source->getName().c_str());
00173   if(icon!=NULL)
00174     xmlSetProp(cur,(const xmlChar*)"icon",(const xmlChar*)icon);
00175   const unsigned int len=20;
00176   char sbuf[len];
00177   snprintf(sbuf,len,"%d",placement);
00178   xmlSetProp(cur,(const xmlChar*)"voff",(const xmlChar*)sbuf);
00179   snprintf(sbuf,len,"%d",get_time());
00180   xmlSetProp(cur,(const xmlChar*)"time",(const xmlChar*)sbuf);
00181   xmlNodeSetContent(cur,(const xmlChar*)msg.c_str());
00182   queuedEvents.push(cur);
00183   if(transStack.empty())
00184     dumpQueuedEvents();
00185 }
00186 
00187 void EventLogger::logWebcam(const BehaviorBase* source/*=NULL*/) {
00188   if(logSocket==NULL || !wireless->isConnected(logSocket->sock))
00189     return;
00190 
00191   xmlNode * cur = xmlNewNode(NULL,(const xmlChar*)"event");
00192   xmlSetProp(cur,(const xmlChar*)"type",(const xmlChar*)"webcam");
00193   if(source!=NULL)
00194     xmlSetProp(cur,(const xmlChar*)"sid",(const xmlChar*)source->getName().c_str());
00195   const unsigned int len=20;
00196   char sbuf[len];
00197   snprintf(sbuf,len,"%d",get_time());
00198   xmlSetProp(cur,(const xmlChar*)"time",(const xmlChar*)sbuf);
00199   xmlNodeSetContent(cur,(const xmlChar*)" ");
00200   queuedEvents.push(cur);
00201   if(transStack.empty())
00202     dumpQueuedEvents();
00203 }
00204 
00205 void EventLogger::clearSlots() {
00206   erouter->removeListener(this);
00207   ControlBase::clearSlots();
00208 }
00209 
00210 void EventLogger::setStatus(unsigned int i, char c) {
00211   std::string tmp=options[i]->getName();
00212   tmp[1]=c;
00213   options[i]->setName(tmp);
00214 }
00215 
00216 void EventLogger::checkLogFile() {
00217   unsigned int cur=EventBase::numEGIDs+3;
00218   StringInputControl * strin=dynamic_cast<StringInputControl*>(options[cur]);
00219   ASSERTRET(strin!=NULL,"The StringInputControl is misplaced");
00220   if(strin->getLastInput()!=logfilePath) {
00221     logfile.close();
00222     logfilePath=strin->getLastInput();
00223     logfile.clear();
00224     if(logfilePath.size()!=0) {
00225       sout->printf("Opening `%s'\n",(config->portPath(logfilePath)).c_str());
00226       logfile.open((config->portPath(logfilePath)).c_str());
00227       if(!logfile.fail()) {
00228         setStatus(cur,'X');
00229         strin->setName(strin->getName()+": "+logfilePath);
00230       } else {
00231         serr->printf("Opening `%s' failed\n",(config->portPath(logfilePath)).c_str());
00232       }
00233     }
00234   }
00235 }
00236 
00237 
00238 void EventLogger::spider(const StateNode* n, xmlNode* parent/*=NULL*/) {
00239   if(n==NULL)
00240     return;
00241 
00242   xmlNode * cur = xmlNewNode(NULL,(const xmlChar*)"state");
00243   ASSERTRET(cur!=NULL,"EventLogger::spider() could not allocate new xml state node");
00244   xmlSetProp(cur,(const xmlChar*)"class",(const xmlChar*)n->getClassName().c_str());
00245   xmlSetProp(cur,(const xmlChar*)"id",(const xmlChar*)n->getName().c_str());
00246   
00247   const std::vector<StateNode*>& subnodes=n->getNodes();
00248   if(subnodes.size()>0) {
00249     // it's not a leaf node, has subnodes and transitions between them
00250 
00251     std::set<const Transition*> transitions;
00252     // now recurse on sub-nodes, extracting all of the subnodes transitions
00253     for(unsigned int i=0; i<subnodes.size(); i++) {
00254       spider(subnodes[i],cur);
00255       const std::vector<Transition*>& curt=subnodes[i]->getTransitions();
00256       transitions.insert(curt.begin(),curt.end());
00257     }
00258 
00259     // now output transitions between subnodes we collected in previous step
00260     for(std::set<const Transition*>::const_iterator it=transitions.begin(); it!=transitions.end(); it++) {
00261       xmlNode * t = xmlAddChild(cur,xmlNewNode(NULL,(const xmlChar*)"transition"));
00262       ASSERTRET(t!=NULL,"EventLogger::spider() could not allocate new xml transition node");
00263       xmlSetProp(t,(const xmlChar*)"class",(const xmlChar*)(*it)->getClassName().c_str());
00264       xmlSetProp(t,(const xmlChar*)"id",(const xmlChar*)(*it)->getName().c_str());
00265       
00266       typedef std::vector<StateNode*> statevec_t;
00267       const statevec_t& incoming=(*it)->getSources();
00268       for(statevec_t::const_iterator nit=incoming.begin(); nit!=incoming.end(); ++nit) {
00269         xmlNode * sn = xmlAddChild(t,xmlNewNode(NULL,(const xmlChar*)"source"));
00270         ASSERTRET(sn!=NULL,"EventLogger::spider() could not allocate new xml transition source node");
00271         xmlNodeSetContent(sn,(const xmlChar*)(*nit)->getName().c_str());
00272       }
00273       const statevec_t& outgoing=(*it)->getDestinations();
00274       for(statevec_t::const_iterator nit=outgoing.begin(); nit!=outgoing.end(); ++nit) {
00275         xmlNode * sn = xmlAddChild(t,xmlNewNode(NULL,(const xmlChar*)"destination"));
00276         ASSERTRET(sn!=NULL,"EventLogger::spider() could not allocate new xml transition source node");
00277         xmlNodeSetContent(sn,(const xmlChar*)(*nit)->getName().c_str());
00278       }
00279     }
00280   }
00281   if(parent==NULL)
00282     dumpNode(cur);
00283   else
00284     xmlAddChild(parent,cur);
00285 }
00286   
00287 bool EventLogger::isListening(const StateNode* n) {
00288   while(n!=NULL) {
00289     if(listen.find(n->getName())!=listen.end())
00290       return true;
00291     n=n->getParent();
00292   }
00293   return false;
00294 }
00295 
00296 void EventLogger::indent(unsigned int level) {
00297   for(unsigned int i=0; i<level; i++)
00298     logSocket->printf("  ");
00299 }
00300 
00301 const StateNode * EventLogger::find(const std::string& sname) {
00302   const registry_t& registry=BehaviorBase::getRegistry();
00303   for(registry_t::const_iterator it=registry.begin(); it!=registry.end(); it++) {
00304     const StateNode * cur=dynamic_cast<const StateNode*>(*it);
00305     if(cur!=NULL && cur->getName()==sname)
00306       return cur;
00307   }
00308   //serr->printf("WARNING: EventLogger Could not find StateNode named `%s'\n",sname.c_str());
00309   return NULL;
00310 }
00311 
00312 void EventLogger::runCommand(const std::string& s) {
00313   if(s==std::string("list")) {
00314     const registry_t& registry=BehaviorBase::getRegistry();
00315     unsigned int numstate=0;
00316     for(registry_t::const_iterator it=registry.begin(); it!=registry.end(); it++) {
00317       const StateNode * cur=dynamic_cast<const StateNode*>(*it);
00318       if(cur!=NULL)
00319         numstate++;
00320     }
00321     logSocket->printf("%d\n",numstate);
00322     for(registry_t::const_iterator it=registry.begin(); it!=registry.end(); it++) {
00323       const StateNode * cur=dynamic_cast<const StateNode*>(*it);
00324       if(cur!=NULL)
00325         logSocket->printf("%s\n",cur->getName().c_str());
00326     }
00327 
00328   } else if(s.find("spider ")==0) {
00329     const StateNode * n=find(s.substr(7));
00330     if(n==NULL) {
00331       serr->printf("WARNING: EventLogger could not find \"%s\" for spidering\n",s.substr(7).c_str());
00332       logSocket->printf("<model></model>\n");
00333     } else {
00334       logSocket->printf("<model>\n");
00335       spider(n);
00336       logSocket->printf("</model>\n");
00337     }
00338 
00339   } else if(s.find("listen ")==0) {
00340     if(listen.size()==0) {
00341       erouter->addListener(&smProcess,EventBase::stateMachineEGID);
00342       erouter->addListener(&smProcess,EventBase::stateTransitionEGID);
00343     }
00344     listen.insert(s.substr(7));
00345 
00346   } else if(s.find("ignore ")==0) {
00347     listen.erase(s.substr(7));
00348     if(listen.size()==0)
00349       erouter->removeListener(&smProcess);
00350 
00351   } else if(s=="clear") {
00352     listen.clear();
00353     erouter->removeListener(&smProcess);
00354 
00355   } else {
00356     serr->printf("EventLogger::runCommand() - bad message: '%s'\n",s.c_str());
00357   }
00358 }
00359 
00360 // The command packet reassembly mechanism
00361 int EventLogger::callback(char *buf, int bytes) {
00362   if(EventLogger::theOne==NULL)
00363     return 0;
00364   static std::string cmd;
00365   for(int i=0; i<bytes; i++) {
00366     if(buf[i]=='\n') {
00367       EventLogger::theOne->runCommand(cmd);
00368       cmd.clear();
00369     } else if(buf[i]!='\r')
00370       cmd+=buf[i];
00371   }
00372   return 0;
00373 }
00374 
00375 void EventLogger::processStateMachineEvent(const EventBase& e) {
00376   if(!wireless->isConnected(logSocket->sock) || listen.size()==0)
00377     return;
00378   
00379   if(e.getGeneratorID()==EventBase::stateTransitionEGID) {
00380     bool care=false;
00381     const Transition * trans = reinterpret_cast<Transition*>(e.getSourceID());
00382     const std::vector<StateNode*>& incoming=trans->getSources();
00383     const std::vector<StateNode*>& outgoing=trans->getDestinations();
00384     for(std::vector<StateNode*>::const_iterator it=incoming.begin(); it!=incoming.end() && !care; it++)
00385       care=isListening(*it);
00386     for(std::vector<StateNode*>::const_iterator it=outgoing.begin(); it!=outgoing.end() && !care; it++)
00387       care=isListening(*it);
00388     if(!care)
00389       return;
00390     
00391     if(e.getTypeID()==EventBase::activateETID) {
00392       xmlNode * root = xmlNewNode(NULL,(const xmlChar*)"event");
00393       xmlNode * fire = xmlAddChild(root,xmlNewNode(NULL,(const xmlChar*)"fire"));
00394       xmlSetProp(fire,(const xmlChar*)"id",(const xmlChar*)trans->getName().c_str());
00395       const unsigned int len=20;
00396       char sbuf[len];
00397       snprintf(sbuf,len,"%d",e.getTimeStamp());
00398       xmlSetProp(fire,(const xmlChar*)"time",(const xmlChar*)sbuf);
00399       transStack.push(root);
00400       queuedEvents.push(root);
00401     } else {
00402       ASSERTRET(!transStack.empty(),"got a transition deactivate that I should care about, but I didn't see the activate");
00403       transStack.pop();
00404       if(transStack.empty())
00405         dumpQueuedEvents();
00406     }
00407     
00408   } else if(e.getGeneratorID()==EventBase::stateMachineEGID) {
00409     if(e.getTypeID()==EventBase::statusETID)
00410       return;
00411     const StateNode * beh=reinterpret_cast<StateNode*>(e.getSourceID());
00412     if(!isListening(beh))
00413       return;
00414     if(e.getTypeID()!=EventBase::activateETID && e.getTypeID()!=EventBase::deactivateETID) {
00415       serr->printf("WARNING: Unrecognized TypeID %d\n",e.getTypeID());
00416       return;
00417     }
00418     
00419     xmlNode * root = transStack.empty() ? xmlNewNode(NULL,(const xmlChar*)"event") : transStack.top();
00420     const char* sttypestr = (e.getTypeID()==EventBase::activateETID) ? "statestart" : "statestop";
00421     xmlNode * st = xmlAddChild(root,xmlNewNode(NULL,(const xmlChar*)sttypestr));
00422     xmlSetProp(st,(const xmlChar*)"id",(const xmlChar*)beh->getName().c_str());
00423     const unsigned int len=20;
00424     char sbuf[len];
00425     snprintf(sbuf,len,"%d",e.getTimeStamp());
00426     xmlSetProp(st,(const xmlChar*)"time",(const xmlChar*)sbuf);
00427     
00428     if(transStack.empty()) {
00429       queuedEvents.push(root);
00430       dumpQueuedEvents();
00431     }
00432     
00433   } else {
00434     serr->printf("WARNING: Unknown event %s (%s)\n",e.getName().c_str(),e.getDescription().c_str());
00435   }
00436 }
00437 
00438 void EventLogger::dumpQueuedEvents() {
00439   xmlDoc * doc = xmlNewDoc((const xmlChar*)"1.0");
00440   while(!queuedEvents.empty()) {
00441     dumpNode(queuedEvents.front(),doc);
00442     queuedEvents.pop();
00443   }
00444   xmlFreeDoc(doc);
00445 }
00446 
00447 void EventLogger::dumpNode(xmlNode* node, xmlDoc* doc/*=NULL*/) {
00448   xmlBuffer* buf=xmlBufferCreate();
00449   int n=xmlNodeDump(buf,doc,node,0,1);
00450   byte * nbuf = logSocket->getWriteBuffer(n+1);
00451   if(nbuf!=NULL) {
00452     memcpy(nbuf,xmlBufferContent(buf),n);
00453     nbuf[n]='\n';
00454     logSocket->write(n+1);
00455   }
00456   xmlBufferFree(buf);
00457   xmlFreeNode(node);
00458 }
00459 
00460 
00461 
00462 
00463 /*! @file
00464  * @brief Describes EventLogger, which allows logging of events to the console or a file
00465  * @author ejt (Creator)
00466  *
00467  * $Author: ejt $
00468  * $Name: tekkotsu-4_0 $
00469  * $Revision: 1.25 $
00470  * $State: Exp $
00471  * $Date: 2007/11/11 23:57:18 $
00472  */

Tekkotsu v4.0
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4