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

libFAUDES 2.20s --- 2011.10.12 --- c++ source docu by doxygen