libFAUDES

Sections

Index

iop_vdevice.cpp

Go to the documentation of this file.
00001 /** @file iop_vdevice.cpp Virtual device for interface definition  */
00002 
00003 /*
00004    FAU Discrete Event Systems Library (libfaudes)
00005 
00006    Copyright (C) 2008, Thomas Moor
00007    Exclusive copyright is granted to Klaus Schmidt
00008 
00009 */
00010 
00011 
00012 
00013 #include "iop_vdevice.h"
00014 
00015 #include "iop_simplenet.h"
00016 #include "iop_comedi.h"
00017 #include "iop_wago.h"
00018 #include "iop_xdevice.h"
00019 #include "sp_densityfnct.h"
00020 #include "sys/time.h"
00021 
00022 
00023 namespace faudes {
00024 
00025 
00026 
00027 /*
00028  **********************************************
00029  **********************************************
00030  **********************************************
00031 
00032  implementation: AttributeDeviceEvent
00033 
00034  **********************************************
00035  **********************************************
00036  **********************************************
00037  */
00038 
00039 
00040 // faudes type std
00041 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeDeviceEvent,AttributeVoid)
00042 
00043 // Default constructor (no attributes, aka undefined) */
00044 AttributeDeviceEvent::AttributeDeviceEvent(void) :
00045   AttributeVoid(), 
00046   mpOutputAttribute(0), 
00047   mpInputAttribute(0),
00048   pOutputPrototype(0), 
00049   pInputPrototype(0)
00050 {
00051   FD_DHV("AttributeDeviceEvent::AttributeDeviceEvent(" << this << ")");
00052   pOutputPrototype= FallbackAttributep(); 
00053   pInputPrototype= FallbackAttributep();
00054 }
00055 
00056 // Copy constructor (never called)
00057 AttributeDeviceEvent::AttributeDeviceEvent(const AttributeDeviceEvent& rOtherAttr) :
00058   AttributeVoid(), 
00059   mpOutputAttribute(0), 
00060   mpInputAttribute(0), 
00061   pOutputPrototype(0), 
00062   pInputPrototype(0)
00063 {
00064   FD_DHV("AttributeDeviceEvent(" << this << "): form other attr " <<  &rOtherAttr);
00065   pOutputPrototype= FallbackAttributep(); 
00066   pInputPrototype= FallbackAttributep();
00067   DoAssign(rOtherAttr);
00068 }
00069 
00070 // Destructor    
00071 AttributeDeviceEvent::~AttributeDeviceEvent(void) {
00072   if(mpOutputAttribute) delete mpOutputAttribute;
00073   if(mpInputAttribute)   delete mpInputAttribute;
00074 }
00075 
00076 // pseudo statics
00077 const AttributeVoid* AttributeDeviceEvent::FallbackAttributep(void) {
00078   static AttributeVoid* avoid=new AttributeVoid();
00079   return avoid;
00080 }
00081 
00082 // Clear
00083 void AttributeDeviceEvent::Clear(void) {
00084   if(mpOutputAttribute) delete mpOutputAttribute;
00085   if(mpInputAttribute)   delete mpInputAttribute;
00086   mpOutputAttribute=0;
00087   mpInputAttribute=0;
00088 }
00089 
00090 // Assignement
00091 void AttributeDeviceEvent::DoAssign(const AttributeDeviceEvent& rSrcAttr) {
00092   FD_DHV("AttributeDeviceEvent(" << this << "):DoAssign(): " 
00093     << typeid(*this).name() << " from " << typeid(rSrcAttr).name());
00094   Clear();
00095   if(rSrcAttr.IsInput())   Input(*rSrcAttr.Inputp());
00096   if(rSrcAttr.IsOutput()) Output(*rSrcAttr.Outputp());
00097 }
00098 
00099 
00100 
00101 // DoWrite(rTw,rLabel,pContext)
00102 void AttributeDeviceEvent::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
00103   FD_DHV("AttributeDeviceEvent(" << this << ")::DoWrite(tw): " << IsOutput() << " " << IsInput()  );
00104   if(IsOutput()) mpOutputAttribute->Write(rTw,rLabel,pContext);
00105   if(IsInput())   mpInputAttribute->Write(rTw,rLabel,pContext);
00106 }
00107 
00108 //DoRead(rTr,rLabel,pContext)
00109 void AttributeDeviceEvent::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
00110   FD_DHV("AttributeDeviceEvent(" << this << ")::DoRead(tr)");
00111   // clear
00112   if(mpInputAttribute) delete mpInputAttribute;
00113   if(mpOutputAttribute) delete mpOutputAttribute;
00114   mpInputAttribute=0;
00115   mpOutputAttribute=0;
00116   // test for output/input section
00117   Token token;
00118   rTr.Peek(token);
00119   if(token.Type()!=Token::Begin) return;
00120   // read output/input
00121   if(token.StringValue()=="Output" || token.StringValue()=="Actuator") {
00122     DefaultOutput();
00123     mpOutputAttribute->Read(rTr,rLabel,pContext);
00124     FD_DHV("Found Output : " << mpOutputAttribute->ToString());
00125   }
00126   // read output/input
00127   if(token.StringValue()=="Input" || token.StringValue()=="Sensor") {
00128     DefaultInput();
00129     mpInputAttribute->Read(rTr,rLabel,pContext);
00130     FD_DHV("Found Input: " << mpInputAttribute->ToString() << " " << rLabel);
00131   }
00132   // ignore others
00133 }
00134 
00135 
00136 /*
00137  **********************************************
00138  **********************************************
00139  **********************************************
00140 
00141  implementation: vDevice
00142 
00143  **********************************************
00144  **********************************************
00145  **********************************************
00146  */
00147 
00148 
00149 //vDevice()
00150 vDevice::vDevice(void) {
00151   // constructor
00152 
00153   FD_DHV("vDevice(" << mName << ")::vDevice()");
00154   //set defaults
00155   mName = "IoDevice";       //device-name
00156   mpConfiguration = NULL;     //derived class to set: pointer to config-set
00157   mState = Down;        //initial state
00158   mDefaultLabel ="Device";      //label used with token-io
00159   mTimeScale = 1000;        //faudes-time scaling-factor 1[ftu] =^ 1[sec]
00160   mMaxSyncGap = tpTime::Step;     //max time-delay used with simulator
00161   pWaitMutex=&mWaitMutex;     //use object - mutex
00162   pWaitCondition=&mWaitCondition;     //use object - condition
00163   pBufferMutex=&mBufferMutex;     //use object - buffer-mutex
00164   pInputBuffer=&mInputBuffer;     //use object - input-buffer
00165 
00166   //initial mutex- and condition variables
00167   pthread_mutex_init(&mWaitMutex,NULL);
00168   pthread_cond_init(&mWaitCondition,NULL);
00169   pthread_mutex_init(&mBufferMutex,NULL);
00170 
00171 #ifdef FAUDES_DEBUG_IOPERF
00172   // initialize arrays to store time stamps
00173   mpPerformanceWaitEnter = new timeval[FAUDES_DEBUG_IOPERF_SAMPLES];
00174   mpPerformanceWaitExit = new timeval[FAUDES_DEBUG_IOPERF_SAMPLES];
00175   mPerformanceEndIterator = 0;
00176   mPerformanceBeginIterator = 0;
00177 #endif
00178 
00179   // track devices
00180   AllDevices().insert(this);
00181 
00182 }
00183 
00184 // pseudo static members
00185 std::set<vDevice*>& vDevice::AllDevices(void) {
00186   static std::set<vDevice*> *dlist = new std::set< vDevice* >();
00187   return *dlist;
00188 }
00189 
00190 
00191 //~vDevice()
00192 vDevice::~vDevice(void) {
00193   // destructor
00194   FD_DHV("vDevice(" << mName << ")::~vDevice()");
00195   //delete configuration
00196   if(mpConfiguration) delete mpConfiguration;
00197   //destroy mutex
00198   pthread_mutex_destroy(&mWaitMutex);
00199   pthread_cond_destroy(&mWaitCondition);
00200   pthread_mutex_destroy(&mBufferMutex);
00201 
00202 #ifdef FAUDES_DEBUG_IOPERF
00203   // delete time stamps
00204   delete mpPerformanceWaitEnter;
00205   delete mpPerformanceWaitExit;
00206 #endif
00207 
00208   // track devices
00209   AllDevices().erase(this);
00210 }
00211 
00212 //FromTokenReader
00213 vDevice* vDevice::FromTokenReader(TokenReader& rTr) {
00214   // construct from token reader
00215   FD_DHV("vDevice::FromTokenReader()");
00216   // peek first token // s&e tr->rTr
00217   Token token;
00218   rTr.Peek(token);
00219   if(!token.Type()==Token::Begin) {
00220     std::stringstream errstr;
00221     errstr << "Expected Begin Section in  \"" << rTr.FileName() << "\"";
00222     throw Exception("vDevice::FromFile", errstr.str(), 52);
00223   }
00224   // instantiate typed faudes object
00225   std::string ftype=token.StringValue();
00226   FD_DHV("vDevice::FromFile(" << rTr.FileName() <<"): device type " << ftype);
00227   Type* fobject= NewFaudesObject(ftype);
00228   if(!fobject) {
00229     std::stringstream errstr;
00230     errstr << "Unknown type \"" << ftype << "\" at  \"" << rTr.FileLine()  << "\"";
00231     throw Exception("vDevice()::FromFile", errstr.str(), 52);
00232     return 0;
00233   }
00234   // cast to vdevice
00235   vDevice* fdevice= dynamic_cast<vDevice*>(fobject);
00236   if(!fdevice) {
00237     std::stringstream errstr;
00238     errstr << "Could not cast to device object from type \"" << ftype << "\" at  \"" << rTr.FileLine()  << "\")";
00239     throw Exception("vDevice()::FromFile", errstr.str(), 52);
00240     return 0;
00241   }
00242   // do read stream
00243   fdevice->Read(rTr);
00244   return fdevice;
00245 }
00246 
00247 
00248 //FromFile(rFileName)
00249 vDevice* vDevice::FromFile(const std::string& rFileName) {
00250   FD_DHV("vDevice::FromFile(" << rFileName <<")");
00251   // peek first token
00252   TokenReader tr(rFileName);
00253   return FromTokenReader(tr);
00254 }
00255 
00256 
00257 // static member function
00258 void vDevice::StopAll(void) {
00259   // cosmetic bail out
00260   if(AllDevices().size()==0) return;
00261   // report
00262   FD_DH("vDevice::StopAll()");
00263   // reset
00264   std::set<vDevice*>::const_iterator dit;
00265   for(dit=AllDevices().begin(); dit != AllDevices().end(); dit++) {
00266     if( dynamic_cast<xDevice*>(*dit) ) continue;
00267     FD_DH("vDevice::StopAll(): Reset " << *dit);
00268     (*dit)->Reset();
00269   }
00270   // stop
00271   for(dit=AllDevices().begin(); dit != AllDevices().end(); dit++) {
00272     if( dynamic_cast<xDevice*>(*dit) ) continue;
00273     FD_DH("vDevice::StopAll(): Stop " << *dit);
00274     (*dit)->Stop();
00275   }
00276 }
00277 
00278 
00279 // Start(void)
00280 void vDevice::Start(void) {
00281   // only start if currently down
00282   if(mState!=Down) return;
00283 
00284   FD_DHV("vDevice(" << mName << ")::Start()");
00285   if(!mpConfiguration) {
00286     std::stringstream errstr;
00287     errstr << "cannot start device when not configured";
00288     throw Exception("vDevice()::Start()", errstr.str(), 550);
00289   }
00290   // optimistic default in base class
00291   mState=Up;
00292   // Start implies Reset
00293   Reset();
00294 }
00295 
00296 
00297 // Stop()
00298 void vDevice::Stop(void) {
00299   // only stop if up or starting up
00300   if(mState!=Up && mState!=StartUp) return;
00301   FD_DHV("vDevice(" << mName << ")::Stop()");
00302   // Stop() implies Reset
00303   Reset();
00304   // optimistic default in base class
00305   mState=Down;
00306 }
00307 
00308 
00309 // Reset()
00310 void vDevice::Reset(void){
00311   //delete dynamic data
00312   FD_DHV("vDevice(" << mName <<")::Reset()");
00313   //reset time and delete dynamic data
00314   CurrentTime(0);
00315   // reset input buffer
00316   pthread_mutex_lock(pBufferMutex);
00317   pInputBuffer->clear();
00318   mResetRequest=false;
00319   pthread_mutex_unlock(pBufferMutex);
00320 }
00321 
00322 
00323 // Clear()
00324 void vDevice::Clear(void) {
00325   //delete static data
00326   FD_DHV("vDevice("<< mName <<")::Clear()");
00327   //implies stop
00328   Stop();
00329   //clear exisiting data
00330   if(mpConfiguration) mpConfiguration->Clear();
00331   mOutputs.Clear();
00332   mInputs.Clear();
00333   // sensible defaults
00334   mTimeScale=1000;
00335 }
00336 
00337 
00338 // Name(rName)
00339 void vDevice::Name(const std::string& rName) {
00340   FD_DHV("vDevice(" << mName << ")::Name(\"" << rName << "\")");
00341   mName = rName;
00342 }
00343 
00344 // Name()
00345 const std::string& vDevice::Name(void) const {
00346   FD_DHV("vDevice(" << mName << ")::Name()");
00347   return mName;
00348 }
00349 
00350 
00351 //StatusString()
00352 std::string vDevice::StatusString(void) {
00353   //status string, informal (should prepare mutex)
00354 
00355   FD_DHV("vDevice(" << mName << ")::Name()");
00356   //prepare result
00357   std::string res;
00358   //get curretn device state
00359   DeviceState currentState=Status();
00360   switch(currentState) {
00361   case Down: res="down"; break;
00362   case StartUp: res="starting up"; break;
00363   case Up: res="up and running"; break;
00364   case ShutDown: res="shutting down"; break;
00365   }
00366 
00367   return res;
00368 }
00369 
00370 
00371 //DoWrite(rTr,rLabel,pContext)
00372 void vDevice::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
00373   (void) pContext; (void) rTw;
00374   FD_DHV("vDevice("<<mName<<")::DoWrite()");
00375   // Set up defaults
00376   std::string label=rLabel;
00377   std::string ftype=TypeName();
00378   // Write begin
00379   if(label=="") label=TypeName(); 
00380   if(label=="") label = mDefaultLabel;
00381   Token btag;
00382   btag.SetBegin(label);
00383   if(Name()!=label) btag.InsAttributeString("name",Name());
00384   if(ftype!=label && ftype!="") btag.InsAttributeString("ftype",ftype);
00385   rTw << btag;
00386   // dispatch
00387   DoWritePreface(rTw,"",pContext);
00388   DoWriteConfiguration(rTw,"",pContext);
00389   // end of my section
00390   rTw.WriteEnd(label);
00391 }
00392 
00393 //DoWritePreface(rTw,rLabel,pContext)
00394 void vDevice::DoWritePreface(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
00395   (void) pContext; (void) rTw;
00396   // virtual interface for token-output: device specific parameters
00397   FD_DHV("vDevice("<<mName<<")::DoWritePreface()");
00398   // write faudes-time scaling-factor
00399   Token atoken;
00400   atoken.SetEmpty("TimeScale");
00401   atoken.InsAttributeInteger("value",mTimeScale);
00402   rTw<<atoken;
00403 }
00404 
00405 
00406 //DoWriteConfiguration(rTw,rLabel,pContext)
00407 void vDevice::DoWriteConfiguration(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
00408   (void) pContext; (void) rTw;
00409   // virtual interface for for token-output: event configuration
00410   FD_DHV("vDevice("<<mName<<")::DoWriteConfiguration()");
00411   // figure section, write begin
00412   std::string label=rLabel;
00413   if(label == "") label = "EventConfiguration";
00414   rTw.WriteBegin(label);
00415   // loop events
00416   for (EventSet::Iterator it = mpConfiguration->Begin(); it != mpConfiguration->End(); ++it) {
00417     Token etoken;
00418     const AttributeVoid& attr=mpConfiguration->Attribute(*it);
00419     const AttributeDeviceEvent* attrp = dynamic_cast<const AttributeDeviceEvent*>(&attr);
00420 #ifdef FAUDES_DEBUG_CODE
00421     if(!attrp) {
00422       std::stringstream errstr;
00423       errstr << "Invalid attribute configuration" << rTr.FileLine();
00424       throw Exception("vDevice::DoWriteConfiguration", errstr.str(), 550);
00425     }
00426 #endif
00427     if(!attrp) continue; 
00428     // figure whether we have an effetively default attribute 
00429     // note: we should have a smart token writer to figure empty sections automatically
00430     bool def=false;
00431     if(attrp->IsInput())
00432       if(attrp->Inputp()->IsDefault()) def=true;
00433     if(attrp->IsOutput())
00434       if(attrp->Outputp()->IsDefault()) def=true;
00435     // case a: no attribute value
00436     if(def) {
00437       etoken.SetEmpty("Event");
00438       etoken.InsAttributeString("name",mpConfiguration->SymbolicName(*it));
00439       if(attrp->IsInput())  etoken.InsAttributeString("iotype","input");
00440       if(attrp->IsOutput()) etoken.InsAttributeString("iotype","output");
00441       rTw << etoken;
00442     } 
00443     // case b: incl attribute value
00444     if(!def) {
00445       etoken.SetBegin("Event");
00446       etoken.InsAttributeString("name",mpConfiguration->SymbolicName(*it));
00447       if(attrp->IsInput()) etoken.InsAttributeString("iotype",std::string("input"));
00448       if(attrp->IsOutput()) etoken.InsAttributeString("iotype","output");
00449       rTw << etoken;
00450       attrp->Write(rTw,"",pContext);
00451       etoken.SetEnd("Event");
00452       rTw << etoken;
00453     }
00454   }
00455   // loop done
00456   rTw.WriteEnd(label);
00457 
00458 
00459   // write event-configuration
00460   //if(mpConfiguration) mpConfiguration->XWrite(rTw,label);
00461 }
00462 
00463 //DoRead(rTr,rLabel,pContext)
00464 void vDevice::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
00465   (void) pContext; (void) rLabel; (void) rTr;
00466   // virtual interface for token-input: dispatcher
00467   FD_DHV("vDevice("<<mName<<")::DoRead()");
00468   Clear();
00469   // set default label if no label specified (configure in type constructor)
00470   std::string label = rLabel;
00471   if(label=="") label = mDefaultLabel;
00472   // read my section
00473   Token btag;
00474   rTr.ReadBegin(label,btag);
00475   // extract name
00476   Name(label);
00477   if(btag.ExistsAttributeString("name"))
00478     Name(btag.AttributeStringValue("name"));
00479   // call DoReadConfiguration and DoReadPreface
00480   DoReadPreface(rTr,"",pContext);
00481   DoReadConfiguration(rTr,"",pContext);
00482   // end of my section
00483   rTr.ReadEnd(label);
00484   // organize internal data structures
00485   Compile();
00486 }
00487 
00488 //DoReadConfiguration(rTr,rLabel,pContext)
00489 void vDevice::DoReadConfiguration(TokenReader& rTr,const std::string& rLabel, const Type* pContext){
00490   // bail out on bad configuration
00491   if(!mpConfiguration) return;
00492   // set default label if no label specified
00493   std::string label=rLabel;
00494   if(label=="") label="EventConfiguration";
00495   // set name
00496   mpConfiguration->Name(label);
00497   // test for  begin
00498   /*
00499   Token token;
00500   rTr.Peek(token);
00501   if(!token.IsBegin()) return;
00502   if(token.StringValue()!=label) return;
00503   */
00504   // read begin
00505   rTr.ReadBegin(label); 
00506   FD_DHV("vDevice("<<mName<<")::DoReadConfiguration()");
00507   // prepare attribute
00508   AttributeVoid* vattrp = mpConfiguration->Attribute().New();
00509   AttributeDeviceEvent* attrp = dynamic_cast<AttributeDeviceEvent*>(vattrp);
00510 #ifdef FAUDES_DEBUG_CODE
00511   if(!attrp) {
00512     std::stringstream errstr;
00513     errstr << "Invalid attribute configuration" << rTr.FileLine();
00514     throw Exception("vDevice::DoReadConfiguration", errstr.str(), 550);
00515   }
00516 #endif
00517   if(!attrp) return; 
00518   FD_DHV("vDevice::DoReadConfiguration(" << this << "): attribute type " << typeid(*attrp).name());
00519   // loop tokens
00520   std::string name;
00521   std::string iotype;
00522   while(!rTr.Eos(label)) {
00523     Token token;
00524     rTr.Peek(token);
00525 
00526     // snse and digest pre 2.16 format
00527     if(token.IsString()) {
00528       rTr.Get(token);
00529       name=token.StringValue();
00530       // read faudes attribute
00531       attrp->Read(rTr,"",pContext);
00532       // skip unknown faudes attributes
00533       AttributeVoid::Skip(rTr);
00534       // insert element with attribute
00535       Idx index=mpConfiguration->Insert(name); 
00536       mpConfiguration->Attribute(index,*attrp);
00537       continue;
00538     }
00539 
00540     // read element section 
00541     if(token.IsBegin()) 
00542     if(token.StringValue()=="Event") {
00543       FD_DHV("vDevice(" << this << ")::DoReadConfiguration(..): " << token.Str() << "\"");
00544       rTr.ReadBegin("Event",token);
00545       name=token.AttributeStringValue("name");
00546       iotype=token.AttributeStringValue("iotype");
00547       // input event
00548       if(iotype=="input") 
00549         attrp->ReadInput(rTr);
00550       // output event
00551       if(iotype=="output") 
00552         attrp->ReadOutput(rTr);
00553       // valid
00554       if((iotype=="input") || (iotype=="output")) {
00555         // insert element with attribute
00556         Idx index=mpConfiguration->Insert(name); 
00557         mpConfiguration->Attribute(index,*attrp);
00558         rTr.ReadEnd("Event");
00559         continue;
00560       }
00561     }
00562     // cannot process token
00563     delete attrp;
00564     std::stringstream errstr;
00565     errstr << "Invalid token of type " << token.Type() << " at " << rTr.FileLine();
00566     throw Exception("vDevice::DoReadConfiguration", errstr.str(), 50);
00567   }
00568   rTr.ReadEnd(label);
00569   delete attrp;
00570 }
00571 
00572 //DoReadPreface(rTr,rLabel,pContext)
00573 void vDevice::DoReadPreface(TokenReader& rTr, const std::string& rLabel, const Type* pContext){
00574   (void) pContext; (void) rLabel; (void) rTr;
00575   // virtual interface for token-input: device specific parameters
00576   FD_DHV("vDevice("<<mName<<")::DoReadPreface()");
00577 
00578   // sense and digest pre 2.16 format
00579   Token token;
00580   rTr.Peek(token);
00581   if(token.IsString()) {
00582     mName = rTr.ReadString();
00583     mTimeScale = rTr.ReadInteger();
00584     return;
00585   }
00586 
00587   // loop my members
00588   while(true) {
00589     Token token;
00590     rTr.Peek(token);
00591     // time scale
00592     if(token.IsBegin()) 
00593     if(token.StringValue()=="TimeScale") {
00594       rTr.ReadBegin("TimeScale", token);
00595       mTimeScale=token.AttributeIntegerValue("value");
00596       rTr.ReadEnd("TimeScale");
00597       continue;
00598     }
00599     // break on unknown
00600     break;
00601   }
00602 }
00603 
00604 // Configure(Idx,AttributeDeviceEvent&)
00605 void vDevice::Configure(Idx event, const AttributeDeviceEvent& attr){
00606   //inserts an attributed event and compiles internal data structure  
00607   FD_DHV("vDevice(" << mName << ")::Configure(event)");
00608   Stop();
00609   // test type
00610   if(typeid(attr)!=typeid(mpConfiguration->Attribute())) {
00611     std::stringstream errstr;
00612     errstr << "Cannot cast attribute to device event attribute";
00613     throw Exception("vDevice::Configure", errstr.str(), 550);
00614   }
00615   // record
00616   mpConfiguration->Insert(event);
00617   mpConfiguration->Attribute(event,attr);
00618   // setup internal data structure
00619   Compile();
00620 }
00621 
00622 // Configure(EventSet)
00623 void vDevice::Configure(const EventSet& rPhysicalEvents){
00624   FD_DHV("vDevice(" << mName << ")::Configure(alphabet)");
00625   Stop();
00626   // test type
00627   if(typeid(rPhysicalEvents.Attribute())!=typeid(mpConfiguration->Attribute())) {
00628     std::stringstream errstr;
00629     errstr << "Cannot cast attribute to device event attribute";
00630     throw Exception("vDevice::Configure", errstr.str(), 550);
00631   }
00632   // record events
00633   for(EventSet::Iterator eit=rPhysicalEvents.Begin(); eit!=rPhysicalEvents.End(); eit++) {
00634     const AttributeVoid attr = rPhysicalEvents.Attribute(*eit);
00635     mpConfiguration->Insert(*eit);
00636     mpConfiguration->Attribute(*eit,attr); // why does this do the job???
00637   }
00638   // setup internal data structure
00639   Compile();
00640 }
00641 
00642 //Compile()
00643 void vDevice::Compile(void){
00644   FD_DHV("vDevice(" << mName << ")::Compile()");
00645   // Compile() implies Stop()
00646   Stop();
00647   // clear input- and output-set
00648   mInputs.Clear();
00649   mOutputs.Clear();
00650   // loop over events and set outputs and inputs
00651   mInputs.Clear();
00652   mOutputs.Clear();
00653   for(EventSet::Iterator eit=mpConfiguration->Begin(); eit!=mpConfiguration->End(); eit++) {
00654     AttributeVoid* attr = mpConfiguration->Attributep(*eit);
00655     AttributeDeviceEvent* dattr = dynamic_cast< AttributeDeviceEvent* >(attr);
00656     if(!dattr) {
00657       std::stringstream errstr;
00658       errstr << "Cannot cast attribute to device event attribute";
00659       throw Exception("vDevice()::Configure", errstr.str(), 550);
00660     }
00661     if(dattr->IsInput()) mInputs.Insert(*eit);
00662     if(dattr->IsOutput()) mOutputs.Insert(*eit);
00663   }
00664 }
00665 
00666 //UseCondition(pthread_mutex_t*)
00667 void vDevice::UseCondition(pthread_mutex_t* wmutex, pthread_cond_t* wcond) {
00668   // tell device which condition variable to use
00669   FD_DHV("vDevice(" << mName << ")::UseCondition()");
00670   // set cond/mutex for wait inputs
00671   if(wmutex) pWaitMutex=wmutex;
00672   if(wcond) pWaitCondition=wcond;
00673 }
00674 
00675 //UseBuffer(mutex, buffer)
00676 void vDevice::UseBuffer(pthread_mutex_t* bmutex, std::deque<Idx>* bbuffer) {
00677   // Tell the device which buffer to use
00678   FD_DHV("vDevice(" << mName << ")::UseBuffer()");
00679   //set input buffer and buffer-mutex and
00680   if(bmutex) pBufferMutex=bmutex;
00681   if(bbuffer) pInputBuffer=bbuffer;
00682 }
00683 
00684 // Outputs()
00685 const EventSet& vDevice::Outputs(void) const {
00686   return mOutputs;
00687 }
00688 
00689 // Inputs()
00690 const EventSet& vDevice::Inputs(void) const {
00691   return mInputs;
00692 }
00693 
00694 //DiffTime(timeval,timeval)
00695 timeval vDevice::DiffTime(timeval end, timeval start){
00696   // computes differenz between two timval-structs
00697   FD_DHV("vDevice::DiffTime()");
00698   // declare a new timval construct to store the result in
00699   timeval res;
00700   // perform subtraction
00701   res.tv_sec = end.tv_sec-start.tv_sec;
00702   res.tv_usec = end.tv_usec-start.tv_usec;
00703   // and treat the carryover
00704   if(res.tv_usec <= 0){
00705     res.tv_sec--;
00706     res.tv_usec += 1000000;
00707   }
00708   return res;
00709 }
00710 
00711 //SumTime(timeval,timeval)
00712 timeval vDevice::SumTime(timeval start, timeval duration){
00713   // computes sum of two timeval-structs
00714   FD_DHV("vDevice::SumTime()");
00715   // hypothesis: usec component is (to be kept) below 1000000
00716   timeval res;
00717   // perform addition
00718   res.tv_sec = start.tv_sec + duration.tv_sec;
00719   res.tv_usec = start.tv_usec + duration.tv_usec;
00720   // and treat the carryover
00721   if(res.tv_usec >= 1000000) {
00722     res.tv_sec++;
00723     res.tv_usec-=1000000;
00724   }
00725   return res;
00726 }
00727 
00728 //FtuToNsec(int)
00729 timespec vDevice::FtuToTimeSpec(tpTime::Type duration){
00730   // convert faudes-time to nsec(timespec)
00731   FD_DHV("vDevice("<<mName<<")::FtuToTimeSpec(" << duration << "): using scale " << mTimeScale);
00732   //prepare result
00733   timespec res;
00734   //convert duration to real time
00735   long int durationMsec = mTimeScale*duration;
00736   //get current system-time
00737   timeval now;
00738   gettimeofday(&now,0);
00739   // convert duration from mssec (long int) to usec (timeval)
00740   timeval delta;
00741   delta.tv_sec = durationMsec/1000;
00742   delta.tv_usec = ( durationMsec - ((durationMsec/1000)*1000)  ) *1000;
00743   //specify the absolut point of time
00744   timeval tmp_res = vDevice::SumTime(now,delta);
00745   // convert to timespec
00746   res.tv_sec = tmp_res.tv_sec;
00747   res.tv_nsec = tmp_res.tv_usec*1000;
00748   // done
00749   return res;
00750 }
00751 
00752 //FtuMsecToNsec(long int)
00753 timespec vDevice::MsToTimeSpec(long int duration){
00754   //convert msec to nsec(timespec)
00755   FD_DHV("vDevice::MsToTimeSpec()");
00756   //prepare result
00757   timespec res;
00758   //get current system-time
00759   timeval now;
00760   gettimeofday(&now,0);
00761   // convert duration from msec (long int) to usec (timeval)
00762   timeval durationMsec;
00763   durationMsec.tv_sec = duration/1000;
00764   durationMsec.tv_usec = ( duration - ((duration/1000)*1000)  ) *1000;
00765   // has to wait before false is returned
00766   timeval tmp_res = vDevice::SumTime(now,durationMsec);
00767   // convertto timespec
00768   res.tv_sec = tmp_res.tv_sec;
00769   res.tv_nsec = tmp_res.tv_usec*1000;
00770   
00771   return res;
00772 }
00773 
00774 // FtuToMs(tpTime::Type)
00775 long int vDevice::FtuToMs(tpTime::Type faudes_time){
00776   //convert faudes-time to realtime in ms
00777   FD_DHV("vDevice("<<mName<<")::FtuToMs() ");
00778   // avoid buffer-overflow while trying to convert an
00779   // "infinite" periode of time
00780   if(faudes_time>= tpTime::Max/ (mTimeScale+1)) return tpTime::Max;
00781     // return real time in ms
00782   return mTimeScale*faudes_time;
00783 }
00784 
00785 // MsToFtu(long int)
00786 tpTime::Type vDevice::MsToFtu(long int real_time){
00787   //Convert real time in ms to faudes-time
00788 
00789   FD_DHV("vDevice(" << mName << ")::MsToFtu()");
00790   return (long int)((1.0/mTimeScale)*real_time/1000*1000);
00791 }
00792 
00793 //CurrentTime(void)
00794 tpTime::Type vDevice::CurrentTime(void) {
00795   //return current faudes-time
00796   FD_DHV("vDevice("<<mName<<")::CurrentTime() ");
00797   // declarate a local timestructure
00798   struct timeval now;
00799   // and store the current system in it
00800   gettimeofday(&now,0);
00801   // compute the time elapsed since backgroundthread-startup
00802   timeval diffTime = vDevice::DiffTime(now,mTimeZero);
00803   // convert current physical time to current faudes-time
00804   return (long int) ((1000.0/mTimeScale) * (diffTime.tv_sec + diffTime.tv_usec*1e-6));
00805 }
00806 
00807 //CurrentTime(now)
00808 void vDevice::CurrentTime(tpTime::Type now){
00809   // set current faudes-time
00810 
00811   FD_DHV("vDevice(" << mName <<")::CurrentTime("<<tpTime::Str(now) <<")");
00812   CurrentTimeMs(mTimeScale*now);
00813 }
00814 
00815 //CurrentTimeMs()
00816 long int vDevice::CurrentTimeMs(void) {
00817   //return current real-time in ms
00818 
00819   FD_DHV("vDevice("<<mName<<")::CurrentTimeMs() ");
00820   // declare a local timestructure
00821   struct timeval now;
00822   // and store the current system in it
00823   gettimeofday(&now,0);
00824   // compute the time elapsed since backgroundthread-startup
00825   timeval diffTime = vDevice::DiffTime(now,mTimeZero);
00826   // convert current physical time to msecs
00827   return 1000*diffTime.tv_sec + diffTime.tv_usec/1000;
00828 }
00829 
00830 
00831 //CurrentTimeMs(long int)
00832 void vDevice::CurrentTimeMs(long int nowms){
00833   // set current real-time in ms
00834   FD_DHV("vDevice("<<mName<<")::CurrentTimeMs(nowms) ");
00835   // set for now =0
00836   gettimeofday(&mTimeZero,0);
00837   // adjust to now
00838   timeval delta;
00839   delta.tv_sec = nowms/1000;
00840   delta.tv_usec = 1000*(nowms%1000);
00841   // carry
00842   if(delta.tv_usec >= 1000*1000){
00843     delta.tv_sec++;
00844     delta.tv_usec -= 1000000;
00845   }
00846   // do adjust
00847   mTimeZero=DiffTime(mTimeZero,delta);
00848   // report
00849   time_t systime;
00850   time(&systime);
00851   struct tm* timeinfo;
00852   timeinfo= localtime(&systime);
00853   char strbuf[80];
00854   strftime(strbuf,80,"%X",timeinfo);
00855 }
00856 
00857 
00858 // WaitInputs(tpTime::Type)
00859 bool vDevice::WaitInputs(tpTime::Type duration) {
00860   //wait a specified time for input events to occur
00861 
00862   FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << ")");
00863 
00864   // adjust arguments TODO
00865   if(duration> 3600*24) { duration= 3600*24;};
00866 
00867   // wait mutex gets released while waiting
00868   pthread_mutex_lock(pWaitMutex);
00869 
00870   // get preliminary result
00871   bool sr=InputReady();
00872   // actually wait only if there are no input yet
00873   if(!sr && duration>0) {
00874 
00875 #ifdef FAUDES_DEBUG_IOPERF
00876     // performance time stamp
00877     gettimeofday(mpPerformanceWaitEnter + mPerformanceEndIterator,0);
00878 #endif
00879 
00880     //convert duration in nsec spec
00881     timespec condtime = vDevice::FtuToTimeSpec(duration);
00882     //wait for report from mThreadSynchro about occured input events
00883     FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << "): waiting for condition");
00884     pthread_cond_timedwait(pWaitCondition, pWaitMutex, &condtime);
00885     FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << "): release at "<< CurrentTime());
00886     // update result
00887     sr=InputReady();
00888 
00889 #ifdef FAUDES_DEBUG_IOPERF
00890     // performance time stamp
00891     gettimeofday(mpPerformanceWaitExit + mPerformanceEndIterator,0);
00892     mPerformanceEndIterator++;
00893     if(mPerformanceEndIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00894       mPerformanceEndIterator=0;
00895     if(mPerformanceEndIterator == mPerformanceBeginIterator)
00896       mPerformanceBeginIterator++;
00897     if(mPerformanceBeginIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00898       mPerformanceBeginIterator=0;
00899 #endif
00900 
00901   }
00902 
00903   // release wait mutex
00904   pthread_mutex_unlock(pWaitMutex);
00905 
00906 
00907   return sr;
00908 }
00909 
00910 
00911 // WaitInputsMs(long int)
00912 bool vDevice::WaitInputsMs(long int duration) {
00913   //wait a specified time for input events to occur
00914 
00915   FD_DHV("vDevice("<<mName<<")::WaitInputsMs("<< duration << ")");
00916 
00917   // adjust arguments TODO
00918   if(duration> 30*3600*24) { duration= 30*3600*24;};
00919 
00920   // wait mutex gets released while waiting
00921   pthread_mutex_lock(pWaitMutex);
00922 
00923   // get preliminary result
00924   bool sr=InputReady();
00925   // actually wait onnly if there are no input yet
00926   if(!sr && duration>0) {
00927 
00928 #ifdef FAUDES_DEBUG_IOPERF
00929     // performance time stamp
00930     gettimeofday(mpPerformanceWaitEnter + mPerformanceEndIterator,0);
00931 #endif
00932 
00933     //convert duration in nsec spec
00934     timespec condtime = vDevice::MsToTimeSpec( duration );
00935     //wait for report from mThreadSynchro about occured input events
00936     pthread_mutex_lock(pWaitMutex);
00937     pthread_cond_timedwait(pWaitCondition, pWaitMutex, &condtime);
00938     pthread_mutex_unlock(pWaitMutex);
00939     // update result
00940     sr=InputReady();
00941 
00942 #ifdef FAUDES_DEBUG_IOPERF
00943     // performance time stamp
00944     gettimeofday(mpPerformanceWaitExit + mPerformanceEndIterator,0);
00945     mPerformanceEndIterator++;
00946     if(mPerformanceEndIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00947       mPerformanceEndIterator=0;
00948     if(mPerformanceEndIterator == mPerformanceBeginIterator)
00949       mPerformanceBeginIterator++;
00950     if(mPerformanceBeginIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00951       mPerformanceBeginIterator=0;
00952 #endif
00953 
00954   }
00955 
00956   // released wait mutex
00957   pthread_mutex_unlock(pWaitMutex);
00958 
00959   return sr;
00960 }
00961 
00962 // ResetRequest()
00963 bool vDevice::ResetRequest(void) {
00964   bool res=false;
00965   pthread_mutex_lock(pBufferMutex);
00966   res=mResetRequest;
00967   mResetRequest=false;
00968   pthread_mutex_unlock(pBufferMutex);
00969   return res;
00970 }
00971 
00972 //ReadInputs()
00973 Idx vDevice::ReadInput(void) {
00974   //reads input-buffer and returns first occured events by index
00975 
00976   FD_DHV("vDevice("<<mName<<")::ReadInput()");
00977   // prepare result, invalid
00978   Idx res=0;
00979 
00980   // take oldest entry
00981   pthread_mutex_lock(pBufferMutex);
00982   if(!pInputBuffer->empty())  {
00983     res=pInputBuffer->front();
00984     pInputBuffer->pop_front();
00985   }
00986   pthread_mutex_unlock(pBufferMutex);
00987   FD_DHV("vDevice("<<mName<<")::ReadInput(): found: " << res);
00988   return res;
00989 }
00990 
00991 
00992 //PeekInputs()
00993 Idx vDevice::PeekInput(void) {
00994   //reads input-buffer and returns first occured events by index
00995   // does not remove the event from the buffer
00996 
00997   FD_DHV("vDevice("<<mName<<")::PeekInput()");
00998   // prepare result, invalid
00999   Idx res=0;
01000 
01001   // take oldest entry
01002   pthread_mutex_lock(pBufferMutex);
01003   if(!pInputBuffer->empty())  {
01004     res=pInputBuffer->front();
01005   }
01006   pthread_mutex_unlock(pBufferMutex);
01007 
01008   FD_DHV("vDevice("<<mName<<")::PeekInput(): found: " << res);
01009   return res;
01010 }
01011 
01012 
01013 //InputReady()
01014 bool vDevice::InputReady(void) {
01015   // returns true if a input-event occured
01016 
01017   FD_DHV("vDevice("<<mName<<")::ReadInput()");
01018   //prepare result
01019   bool res;
01020   //read buffer
01021   pthread_mutex_lock(pBufferMutex);
01022   res= !mInputBuffer.empty();
01023   pthread_mutex_unlock(pBufferMutex);
01024 
01025   return res;
01026 }
01027 
01028 
01029 // timing analysis
01030 SampledDensityFunction vDevice::Performance(void) {
01031 #ifdef FAUDES_DEBUG_IOPERF
01032 
01033   FD_DHV("vDevice::Performance(" << Name() << "): " << mPerformanceBeginIterator << " " << mPerformanceEndIterator);
01034 
01035   // have samples
01036   SampledDensityFunction busyduration;
01037   busyduration.Dim(50);
01038   busyduration.Clear();
01039   busyduration.Name("performance " + Name() + " (busy duration in usecs)");
01040 
01041   // inspect time stamps
01042   for(int i = mPerformanceBeginIterator; ;i++){
01043     if(i>= FAUDES_DEBUG_IOPERF_SAMPLES) i=0;
01044     int ip = i+1;
01045     if(ip>= FAUDES_DEBUG_IOPERF_SAMPLES) ip =0;
01046     if(ip==mPerformanceEndIterator) break;
01047     timeval busy=vDevice::DiffTime(mpPerformanceWaitEnter[ip],mpPerformanceWaitExit[i]);
01048     busyduration.Sample(busy.tv_sec*1000000 + busy.tv_usec);
01049   }   
01050 
01051   // compile
01052   busyduration.Compile();
01053 
01054   // done
01055   return busyduration;
01056 
01057 #else
01058 
01059   FD_DHV("vDevice::Performance(" << Name() << "): not enabled");
01060   SampledDensityFunction busyduration;
01061   return busyduration;
01062 
01063 #endif
01064 }
01065 
01066 // WritePerformance
01067 void vDevice::WritePerformance(void) {
01068 
01069   SampledDensityFunction busyduration=Performance();
01070 
01071   // token output
01072   busyduration.Write();
01073 
01074   // pretty print
01075   std::cout << busyduration.Str() << std::endl;
01076 }
01077 
01078 // ClearPerformance
01079 void vDevice::ResetPerformance(void) {
01080 
01081 #ifdef FAUDES_DEBUG_IOPERF
01082   mPerformanceEndIterator = 0;
01083   mPerformanceBeginIterator = 0;
01084 #endif
01085 
01086 }
01087 
01088 } // name space
01089 

libFAUDES 2.18b --- 2010-12-17 --- c++ source docu by doxygen 1.6.3