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

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:38 2016 by Doxygen 1.6.3