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

Tekkotsu v3.0
Generated Wed Oct 4 00:03:43 2006 by Doxygen 1.4.7