iop_vdevice.cppGo 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 |