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   faudes_mutex_init(&mWaitMutex);
00167   faudes_cond_init(&mWaitCondition);
00168   faudes_mutex_init(&mBufferMutex);
00169 
00170 #ifdef FAUDES_DEBUG_IOPERF
00171   // initialize arrays to store time stamps
00172   mpPerformanceWaitEnter = new faudes_systime_t[FAUDES_DEBUG_IOPERF_SAMPLES];
00173   mpPerformanceWaitExit = new faudes_systime_t[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   faudes_mutex_destroy(&mWaitMutex);
00198   faudes_cond_destroy(&mWaitCondition);
00199   faudes_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   faudes_mutex_lock(pBufferMutex);
00316   pInputBuffer->clear();
00317   mResetRequest=false;
00318   faudes_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(faudes_mutex_t*)
00666 void vDevice::UseCondition(faudes_mutex_t* wmutex, faudes_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(faudes_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 //FtuToSystemTime(int)
00694 faudes_systime_t vDevice::FtuToSystemTime(tpTime::Type duration){
00695   // convert faudes-time to sys.time)
00696   FD_DHV("vDevice("<<mName<<")::FtuToSystemTime(" << duration << "): using scale " << mTimeScale);
00697   //prepare result
00698   faudes_systime_t res;
00699   //get current system-time
00700   faudes_systime_t now;
00701   faudes_gettimeofday(&now);
00702   //convert duration to real time msec
00703   long int durationMsec = mTimeScale*duration;
00704   //convert duration from msec (long int) to nsec (sys.time)
00705   faudes_systime_t delta;
00706   delta.tv_sec = durationMsec/1000;
00707   delta.tv_nsec = ( durationMsec - (delta.tv_sec*1000)  ) *1000000;
00708   //specify the absolut point of time
00709   faudes_sumsystime(now,delta,&res);
00710   // done
00711   return res;
00712 }
00713 
00714 // FtuToMs(tpTime::Type)
00715 long int vDevice::FtuToMs(tpTime::Type faudes_time){
00716   //convert faudes-time to realtime in ms
00717   FD_DHV("vDevice("<<mName<<")::FtuToMs() ");
00718   // avoid buffer-overflow while trying to convert an
00719   // "infinite" periode of time
00720   if(faudes_time>= tpTime::Max/ (mTimeScale+1)) return tpTime::Max;
00721     // return real time in ms
00722   return mTimeScale*faudes_time;
00723 }
00724 
00725 // MsToFtu(long int)
00726 tpTime::Type vDevice::MsToFtu(long int real_time){
00727   //Convert real time in ms to faudes-time
00728 
00729   FD_DHV("vDevice(" << mName << ")::MsToFtu()");
00730   return (long int)((1.0/mTimeScale)*real_time/1000*1000);
00731 }
00732 
00733 //CurrentTime(void)
00734 tpTime::Type vDevice::CurrentTime(void) {
00735   //return current faudes-time
00736   FD_DHV("vDevice("<<mName<<")::CurrentTime() ");
00737   //get current system-time
00738   faudes_systime_t now;
00739   faudes_gettimeofday(&now);
00740   // compute the time elapsed since backgroundthread-startup
00741   faudes_systime_t diff;
00742   faudes_diffsystime(now,mTimeZero,&diff);
00743   // convert physical time to faudes-time
00744   return (long int) ((1000.0/mTimeScale) * (diff.tv_sec + diff.tv_nsec*1e-9));
00745 }
00746 
00747 //CurrentTime(now)
00748 void vDevice::CurrentTime(tpTime::Type now){
00749   // set current faudes-time
00750   FD_DHV("vDevice(" << mName <<")::CurrentTime("<<tpTime::Str(now) <<")");
00751   CurrentTimeMs(mTimeScale*now);
00752 }
00753 
00754 //CurrentTimeMs()
00755 long int vDevice::CurrentTimeMs(void) {
00756   //return current real-time in ms
00757   FD_DHV("vDevice("<<mName<<")::CurrentTimeMs() ");
00758   //get current system-time
00759   faudes_systime_t now;
00760   faudes_gettimeofday(&now);
00761   // compute the time elapsed since backgroundthread-startup
00762   faudes_systime_t diffTime;
00763   faudes_diffsystime(now,mTimeZero,&diffTime);
00764   // convert current physical time to msecs
00765   return 1000*diffTime.tv_sec + diffTime.tv_nsec/1000000;
00766 }
00767 
00768 
00769 //CurrentTimeMs(long int)
00770 void vDevice::CurrentTimeMs(long int nowms){
00771   // set current real-time in ms
00772   FD_DHV("vDevice("<<mName<<")::CurrentTimeMs(nowms) ");
00773   // set for now =0
00774   faudes_systime_t now;
00775   faudes_gettimeofday(&now);
00776   // adjust to now
00777   faudes_systime_t delta;
00778   delta.tv_sec = nowms/1000;
00779   delta.tv_nsec = 1000000*(nowms%1000);
00780   // do adjust
00781   faudes_diffsystime(now,delta,&mTimeZero);
00782   // report
00783   /*
00784   time_t systime;
00785   time(&systime);
00786   struct tm* timeinfo;
00787   timeinfo= localtime(&systime);
00788   char strbuf[80];
00789   strftime(strbuf,80,"%X",timeinfo);
00790   */
00791 }
00792 
00793 
00794 // WaitInputs(tpTime::Type)
00795 bool vDevice::WaitInputs(tpTime::Type duration) {
00796   //wait a specified time for input events to occur
00797 
00798   FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << ")");
00799 
00800   // adjust arguments TODO
00801   if(duration> 3600*24) { duration= 3600*24;};
00802 
00803   // if this is a nontrivial wait, flush outputs
00804   if(duration>0) FlushOutputs();
00805 
00806   // wait mutex gets released while waiting
00807   faudes_mutex_lock(pWaitMutex);
00808 
00809   // get preliminary result
00810   bool sr=InputReady();
00811 
00812   // actually wait only if there are no input yet
00813   if(!sr && duration>0) {
00814 
00815 #ifdef FAUDES_DEBUG_IOPERF
00816     // performance time stamp
00817     faudes_systime_t now;
00818     faudes_gettimeofday(&now);
00819     mpPerformanceWaitEnter[mPerformanceEndIterator]=now;
00820 #endif
00821 
00822     //convert duration in systemtime
00823     faudes_systime_t condtime = vDevice::FtuToSystemTime(duration);
00824     //wait for report from background thread about on available events
00825     FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << "): waiting for condition");
00826     faudes_cond_timedwait(pWaitCondition, pWaitMutex, &condtime);
00827     FD_DHV("vDevice("<<mName<<")::WaitInputs("<< duration << "): release at "<< CurrentTime());
00828     // update result
00829     sr=InputReady();
00830 
00831 #ifdef FAUDES_DEBUG_IOPERF
00832     // performance time stamp
00833     faudes_gettimeofday(&now);
00834     mpPerformanceWaitExit[mPerformanceEndIterator]=now;
00835     mPerformanceEndIterator++;
00836     if(mPerformanceEndIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00837       mPerformanceEndIterator=0;
00838     if(mPerformanceEndIterator == mPerformanceBeginIterator)
00839       mPerformanceBeginIterator++;
00840     if(mPerformanceBeginIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00841       mPerformanceBeginIterator=0;
00842 #endif
00843 
00844   }
00845 
00846   // release wait mutex
00847   faudes_mutex_unlock(pWaitMutex);
00848 
00849 
00850   return sr;
00851 }
00852 
00853 
00854 // WaitInputsMs(long int)
00855 bool vDevice::WaitInputsMs(long int duration) {
00856   //wait a specified time for input events to occur
00857 
00858   FD_DHV("vDevice("<<mName<<")::WaitInputsMs("<< duration << ")");
00859 
00860   // adjust arguments TODO
00861   if(duration> 30*3600*24) { duration= 30*3600*24;};
00862 
00863   // if this is a nontrivial wait, flush outputs
00864   if(duration>0) FlushOutputs();
00865 
00866   // wait mutex gets released while waiting
00867   faudes_mutex_lock(pWaitMutex);
00868 
00869   // get preliminary result
00870   bool sr=InputReady();
00871   // actually wait onnly if there are no input yet
00872   if(!sr && duration>0) {
00873 
00874 #ifdef FAUDES_DEBUG_IOPERF
00875     // performance time stamp
00876     faudes_systime_t now;
00877     faudes_gettimeofday(&now);
00878     mpPerformanceWaitEnter[mPerformanceEndIterator]=now;
00879 #endif
00880 
00881     //convert duration in nsec spec
00882     faudes_systime_t condtime;
00883     faudes_msdelay(duration,&condtime);
00884     //wait for report from background thread on available events
00885     faudes_cond_timedwait(pWaitCondition, pWaitMutex, &condtime);
00886     // update result
00887     sr=InputReady();
00888 
00889 #ifdef FAUDES_DEBUG_IOPERF
00890     // performance time stamp
00891     faudes_gettimeofday(&now);
00892     mpPerformanceWaitExit[mPerformanceEndIterator]=now;
00893     mPerformanceEndIterator++;
00894     if(mPerformanceEndIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00895       mPerformanceEndIterator=0;
00896     if(mPerformanceEndIterator == mPerformanceBeginIterator)
00897       mPerformanceBeginIterator++;
00898     if(mPerformanceBeginIterator >= FAUDES_DEBUG_IOPERF_SAMPLES) 
00899       mPerformanceBeginIterator=0;
00900 #endif
00901 
00902   }
00903 
00904   // released wait mutex
00905   faudes_mutex_unlock(pWaitMutex);
00906 
00907   return sr;
00908 }
00909 
00910 // FlushOutputs(void)
00911 void vDevice::FlushOutputs(void) {
00912 }
00913 
00914 // ResetRequest()
00915 bool vDevice::ResetRequest(void) {
00916   bool res=false;
00917   faudes_mutex_lock(pBufferMutex);
00918   res=mResetRequest;
00919   mResetRequest=false;
00920   faudes_mutex_unlock(pBufferMutex);
00921   return res;
00922 }
00923 
00924 //ReadInputs()
00925 Idx vDevice::ReadInput(void) {
00926   //reads input-buffer and returns first occured events by index
00927 
00928   FD_DHV("vDevice("<<mName<<")::ReadInput()");
00929   // prepare result, invalid
00930   Idx res=0;
00931 
00932   // take oldest entry
00933   faudes_mutex_lock(pBufferMutex);
00934   if(!pInputBuffer->empty())  {
00935     res=pInputBuffer->front();
00936     pInputBuffer->pop_front();
00937   }
00938   faudes_mutex_unlock(pBufferMutex);
00939   FD_DHV("vDevice("<<mName<<")::ReadInput(): found: " << res);
00940   return res;
00941 }
00942 
00943 
00944 //PeekInputs()
00945 Idx vDevice::PeekInput(void) {
00946   //reads input-buffer and returns first occured events by index
00947   // does not remove the event from the buffer
00948 
00949   FD_DHV("vDevice("<<mName<<")::PeekInput()");
00950   // prepare result, invalid
00951   Idx res=0;
00952 
00953   // take oldest entry
00954   faudes_mutex_lock(pBufferMutex);
00955   if(!pInputBuffer->empty())  {
00956     res=pInputBuffer->front();
00957   }
00958   faudes_mutex_unlock(pBufferMutex);
00959 
00960   FD_DHV("vDevice("<<mName<<")::PeekInput(): found: " << res);
00961   return res;
00962 }
00963 
00964 
00965 //InputReady()
00966 bool vDevice::InputReady(void) {
00967   // returns true if a input-event occured
00968 
00969   FD_DHV("vDevice("<<mName<<")::ReadInput()");
00970   //prepare result
00971   bool res;
00972   //read buffer
00973   faudes_mutex_lock(pBufferMutex);
00974   res= !mInputBuffer.empty();
00975   faudes_mutex_unlock(pBufferMutex);
00976 
00977   return res;
00978 }
00979 
00980 
00981 // timing analysis
00982 SampledDensityFunction vDevice::Performance(void) {
00983 #ifdef FAUDES_DEBUG_IOPERF
00984 
00985   FD_DHV("vDevice::Performance(" << Name() << "): " << mPerformanceBeginIterator << " " << mPerformanceEndIterator);
00986 
00987   // have samples
00988   SampledDensityFunction busyduration;
00989   busyduration.Dim(50);
00990   busyduration.Clear();
00991   busyduration.Name("performance " + Name() + " (busy duration in usecs)");
00992 
00993   // inspect time stamps
00994   for(int i = mPerformanceBeginIterator; ;i++){
00995     if(i>= FAUDES_DEBUG_IOPERF_SAMPLES) i=0;
00996     int ip = i+1;
00997     if(ip>= FAUDES_DEBUG_IOPERF_SAMPLES) ip =0;
00998     if(ip==mPerformanceEndIterator) break;
00999     faudes_systime_t busy;
01000     faudes_diffsystime(mpPerformanceWaitEnter[ip],mpPerformanceWaitExit[i],&busy);
01001     busyduration.Sample(busy.tv_sec*1000000 + busy.tv_nsec/1000);
01002   }   
01003 
01004   // compile
01005   busyduration.Compile();
01006 
01007   // done
01008   return busyduration;
01009 
01010 #else
01011 
01012   FD_DHV("vDevice::Performance(" << Name() << "): not enabled");
01013   SampledDensityFunction busyduration;
01014   busyduration.Name("performance monitoring not enabled");
01015   return busyduration;
01016 
01017 #endif
01018 }
01019 
01020 // WritePerformance
01021 void vDevice::WritePerformance(void) {
01022 #ifdef FAUDES_DEBUG_IOPERF
01023   SampledDensityFunction busyduration=Performance();
01024   // token output
01025   busyduration.Write();
01026   // pretty print
01027   std::cout << busyduration.Str() << std::endl;
01028 #endif
01029 }
01030 
01031 // ClearPerformance
01032 void vDevice::ResetPerformance(void) {
01033 
01034 #ifdef FAUDES_DEBUG_IOPERF
01035   mPerformanceEndIterator = 0;
01036   mPerformanceBeginIterator = 0;
01037 #endif
01038 
01039 }
01040 
01041 } // name space
01042 

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen