libFAUDES
Sections
Index
|
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 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