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