libFAUDES
Sections
Index
|
iop_sdevice.cppGo to the documentation of this file.00001 /** @file iop_sdevice.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_sdevice.h" 00014 #include "sys/time.h" 00015 #include "sp_densityfnct.h" 00016 00017 // fix windows/mingw definition 00018 #ifdef FAUDES_WINEXTRA 00019 #define sleep(sec) Sleep((sec) * 1000) 00020 #define usleep(usec) Sleep((usec) / 1000) 00021 #endif 00022 00023 namespace faudes { 00024 00025 00026 /* 00027 ********************************************** 00028 ********************************************** 00029 ********************************************** 00030 00031 implementation: AttributeSignalOutput 00032 00033 ********************************************** 00034 ********************************************** 00035 ********************************************** 00036 */ 00037 00038 // faudes type std 00039 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSignalOutput,AttributeVoid) 00040 00041 //DoAssign(Src) 00042 void AttributeSignalOutput::DoAssign(const AttributeSignalOutput& rSrcAttr) { 00043 FD_DHV("AttributeSignalOutput(" << this << "):DoAssign(): assignment from " << &rSrcAttr); 00044 mActions=rSrcAttr.mActions; 00045 } 00046 00047 //DoWrite(rTw); 00048 void AttributeSignalOutput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00049 (void) rLabel; (void) pContext; 00050 00051 FD_DHV("AttributeSignalOutput::DoWrite(): #" << mActions.size() ); 00052 rTw.WriteBegin("Actions"); 00053 std::vector<Action>::const_iterator ait; 00054 for(ait=mActions.begin(); ait!=mActions.end(); ait++) { 00055 Token atoken; 00056 if(ait->mValue==Set) 00057 atoken.SetEmpty("Set"); 00058 if(ait->mValue==Clr) 00059 atoken.SetEmpty("Clr"); 00060 if(ait->mValue==Inv) 00061 atoken.SetEmpty("Inv"); 00062 atoken.InsAttributeInteger("address",ait->mBit); 00063 rTw << atoken; 00064 } 00065 rTw.WriteEnd("Actions"); 00066 } 00067 00068 00069 //DoRead(rTr) 00070 void AttributeSignalOutput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) { 00071 (void) rLabel; (void) pContext; 00072 Token token; 00073 FD_DHV("AttributeSignalOutput::DoRead()"); 00074 00075 // sense and digest pre 2.16 format 00076 rTr.Peek(token); 00077 if(token.IsBegin()) 00078 if((token.StringValue()=="Output") || (token.StringValue()=="Actuator")) { 00079 rTr.ReadBegin("Actuator"); 00080 bool err=false; 00081 rTr.ReadBegin("Actions"); 00082 while(!rTr.Eos("Actions")) { 00083 Action action; 00084 action.mBit=rTr.ReadInteger(); 00085 std::string value=rTr.ReadOption(); 00086 if(value== "Set") { 00087 action.mValue=Set; 00088 } else if(value == "Clr") { 00089 action.mValue=Clr; 00090 } else if(value == "Inv") { 00091 action.mValue=Inv; 00092 } else { 00093 err=true; 00094 break; 00095 } 00096 mActions.push_back(action); 00097 } 00098 rTr.ReadEnd("Actions"); 00099 rTr.ReadEnd("Actuator"); 00100 if(err) { 00101 std::stringstream errstr; 00102 errstr << "Invalid output event property" << rTr.FileLine(); 00103 throw Exception("AttributeSignalOutput::Read", errstr.str(), 52); //52 oder 352 00104 } 00105 } // end pre 2.16 00106 00107 00108 // test for actions section 00109 rTr.Peek(token); 00110 if(!token.IsBegin()) return; 00111 if(token.StringValue()!="Actions") return; 00112 // read begin 00113 bool err=false; 00114 rTr.ReadBegin("Actions"); 00115 while(!rTr.Eos("Actions")) { 00116 // prepare 00117 Token atag; 00118 Action action; 00119 rTr.Peek(atag); 00120 // set 00121 if(atag.IsBegin()) 00122 if(atag.StringValue()=="Set") { 00123 rTr.ReadBegin("Set"); 00124 action.mValue=Set; 00125 action.mBit=atag.AttributeIntegerValue("address"); 00126 mActions.push_back(action); 00127 rTr.ReadEnd("Set"); 00128 continue; 00129 } 00130 // clr 00131 if(atag.IsBegin()) 00132 if(atag.StringValue()=="Clr") { 00133 rTr.ReadBegin("Clr"); 00134 action.mValue=Clr; 00135 action.mBit=atag.AttributeIntegerValue("address"); 00136 mActions.push_back(action); 00137 rTr.ReadEnd("Clr"); 00138 continue; 00139 } 00140 // inv 00141 if(atag.StringValue()=="Inv") { 00142 rTr.ReadBegin("Inv"); 00143 action.mValue=Inv; 00144 action.mBit=atag.AttributeIntegerValue("address"); 00145 mActions.push_back(action); 00146 rTr.ReadEnd("Inv"); 00147 continue; 00148 } 00149 // error on unknown tokens 00150 err=true; 00151 break; 00152 } 00153 // done 00154 rTr.ReadEnd("Actions"); 00155 // report error 00156 if(err) { 00157 std::stringstream errstr; 00158 errstr << "Invalid output event property" << rTr.FileLine(); 00159 throw Exception("AttributeSignalOutput::Read", errstr.str(), 52); //52 oder 352 00160 } 00161 00162 }//DoRead 00163 00164 00165 /* 00166 ********************************************** 00167 ********************************************** 00168 ********************************************** 00169 00170 implementation: AttributeSignalInput 00171 00172 ********************************************** 00173 ********************************************** 00174 ********************************************** 00175 */ 00176 00177 00178 // faudes type std 00179 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSignalInput,AttributeVoid) 00180 00181 00182 //DoAssign(Src) 00183 void AttributeSignalInput::DoAssign(const AttributeSignalInput& rSrcAttr) { 00184 FD_DHV("AttributeSignalInput(" << this << "):DoAssign(): assignment from " << &rSrcAttr); 00185 mTriggers=rSrcAttr.mTriggers; 00186 } 00187 00188 00189 //DoWrite(rTw,rLabel,pContext) 00190 void AttributeSignalInput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00191 (void) rLabel; (void) pContext; 00192 FD_DHV("AttributeSignalInput()::DoWrite()"); 00193 rTw.WriteBegin("Triggers"); 00194 std::vector<Trigger>::const_iterator ait; 00195 for(ait=mTriggers.begin(); ait!=mTriggers.end(); ait++) { 00196 Token atoken; 00197 if(ait->mPos && (!ait->mNeg)) { 00198 atoken.SetEmpty("PositiveEdge"); 00199 } 00200 if((!ait->mPos) && ait->mNeg) { 00201 atoken.SetEmpty("NegativeEdge"); 00202 } 00203 if((ait->mPos) && ait->mNeg) { 00204 atoken.SetEmpty("AnyyEdge"); 00205 atoken.InsAttributeString("edge","any"); 00206 } 00207 atoken.InsAttributeInteger("address",ait->mBit); 00208 rTw << atoken; 00209 00210 } 00211 rTw.WriteEnd("Triggers"); 00212 }//DoWrite(rTw,rLabel,pContext) 00213 00214 00215 //DoRead(rTr,rLabel,pContext) 00216 void AttributeSignalInput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) { 00217 (void) rLabel; (void) pContext; 00218 Token token; 00219 FD_DHV("AttributeSignalInput()::DoRead(tr)"); 00220 00221 00222 // sense and digest pre 2.16 format 00223 rTr.Peek(token); 00224 if(token.IsBegin()) 00225 if((token.StringValue()=="Input") || (token.StringValue()=="Sensor")) { 00226 rTr.ReadBegin("Sensor"); 00227 bool err=false; 00228 rTr.ReadBegin("Triggers"); 00229 while(!rTr.Eos("Triggers")) { 00230 Trigger trigger; 00231 trigger.mBit=rTr.ReadInteger(); 00232 std::string value=rTr.ReadOption(); 00233 if (value == "PosEdge") { 00234 trigger.mPos=true; 00235 trigger.mNeg=false; 00236 } else if (value == "NegEdge") { 00237 trigger.mPos=false; 00238 trigger.mNeg=true; 00239 } else if (value == "AnyEdge") { 00240 trigger.mPos=true; 00241 trigger.mNeg=true; 00242 } else { 00243 err=true; 00244 break; 00245 } 00246 mTriggers.push_back(trigger); 00247 } 00248 rTr.ReadEnd("Triggers"); 00249 rTr.ReadEnd("Sensor"); 00250 if(err) { 00251 std::stringstream errstr; 00252 errstr << "invalid input event property" << rTr.FileLine(); 00253 throw Exception("AttributeSignalInput::Read", errstr.str(), 52); 00254 } 00255 } // end pre2.16 00256 00257 // test for triggers section 00258 rTr.Peek(token); 00259 if(!token.IsBegin()) return; 00260 if(token.StringValue()!="Triggers") return; 00261 // read begin 00262 bool err=false; 00263 rTr.ReadBegin("Triggers"); 00264 while(!rTr.Eos("Triggers")) { 00265 // prepare 00266 Token atag; 00267 Trigger trigger; 00268 rTr.Peek(atag); 00269 // positive edge 00270 if(atag.IsBegin()) 00271 if(atag.StringValue()=="PositiveEdge") { 00272 rTr.ReadBegin("PositiveEdge"); 00273 trigger.mPos=true; 00274 trigger.mNeg=false; 00275 trigger.mBit=atag.AttributeIntegerValue("address"); 00276 mTriggers.push_back(trigger); 00277 rTr.ReadEnd("PositiveEdge"); 00278 continue; 00279 } 00280 // negative edge 00281 if(atag.IsBegin()) 00282 if(atag.StringValue()=="NegativeEdge") { 00283 rTr.ReadBegin("NegativeEdge"); 00284 trigger.mPos=false; 00285 trigger.mNeg=true; 00286 trigger.mBit=atag.AttributeIntegerValue("address"); 00287 mTriggers.push_back(trigger); 00288 rTr.ReadEnd("NegativeEdge"); 00289 continue; 00290 } 00291 // any edge 00292 if(atag.IsBegin()) 00293 if(atag.StringValue()=="AnyEdge") { 00294 rTr.ReadBegin("AnyEdge"); 00295 trigger.mPos=true; 00296 trigger.mNeg=true; 00297 trigger.mBit=atag.AttributeIntegerValue("address"); 00298 mTriggers.push_back(trigger); 00299 rTr.ReadEnd("AnyEdge"); 00300 continue; 00301 } 00302 // error on unknown tokens 00303 err=true; 00304 break; 00305 } 00306 // done 00307 rTr.ReadEnd("Triggers"); 00308 // report error 00309 if(err) { 00310 std::stringstream errstr; 00311 errstr << "Invalid input event property" << rTr.FileLine(); 00312 throw Exception("AttributeSignalInput::Read", errstr.str(), 52); //52 oder 352 00313 } 00314 } 00315 00316 00317 00318 /* 00319 ********************************************** 00320 ********************************************** 00321 ********************************************** 00322 00323 implementation: AttributeSignalEvent 00324 00325 ********************************************** 00326 ********************************************** 00327 ********************************************** 00328 */ 00329 00330 00331 00332 // std faudes type 00333 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSignalEvent,AttributeDeviceEvent) 00334 00335 // Default constructor, set my prototypes 00336 AttributeSignalEvent::AttributeSignalEvent(void) : AttributeDeviceEvent() { 00337 FD_DHV("AttributeSignalEvent::AttributeSignalEvent(" << this << ")"); 00338 pOutputPrototype=OutputPrototypep(); 00339 pInputPrototype=InputPrototypep(); 00340 } 00341 00342 // Copy constructor 00343 AttributeSignalEvent::AttributeSignalEvent(const AttributeSignalEvent& rOtherAttr) : 00344 AttributeDeviceEvent() 00345 { 00346 FD_DHV("AttributeSimplenetEvent(" << this << "): form other attr " << &rOtherAttr); 00347 pOutputPrototype=OutputPrototypep(); 00348 pInputPrototype=InputPrototypep(); 00349 DoAssign(rOtherAttr); 00350 } 00351 00352 00353 00354 // autoregister event confiration (required for XML token format) 00355 AutoRegisterType< TaNameSet<AttributeSignalEvent> > 00356 gRti1RegisterSignalDeviceEventSet("SignalDeviceEventSet"); 00357 AutoRegisterXElementTag< TaNameSet<AttributeSignalEvent> > 00358 gRti1XElementTagSignalDeviceEventSet("SignalDeviceEventSet", "Event"); 00359 00360 // pseudo statics 00361 const AttributeSignalOutput* AttributeSignalEvent::OutputPrototypep(void){ 00362 AttributeSignalOutput* attrp= new AttributeSignalOutput(); 00363 return attrp; 00364 } 00365 00366 // pseudo statics 00367 const AttributeSignalInput* AttributeSignalEvent::InputPrototypep(void) { 00368 AttributeSignalInput* attrp= new AttributeSignalInput(); 00369 return attrp; 00370 } 00371 00372 /* 00373 ********************************************** 00374 ********************************************** 00375 ********************************************** 00376 00377 implementation: sDevice 00378 00379 ********************************************** 00380 ********************************************** 00381 ********************************************** 00382 */ 00383 00384 00385 //////////////////////////////////////////////// 00386 // construction and destruction 00387 00388 //sDevice() 00389 sDevice::sDevice(void) : vDevice() { 00390 // constructor 00391 00392 FD_DHV("sDevice(" << mName << ")::sDevice()"); 00393 // have event set with appropriate attributes 00394 mpConfiguration = new TaNameSet<AttributeSignalEvent>; 00395 pConfiguration = dynamic_cast< TaNameSet<AttributeSignalEvent>* >(mpConfiguration); 00396 // have appropriate default label for token io 00397 mDefaultLabel ="SignalDevice"; 00398 // my signal data 00399 mMaxBitAddress=-1; 00400 mpInputEdges=0; 00401 mpRecentInputEdges=0; 00402 mpOutputLevels=0; 00403 // background thread: 00404 // install mutex 00405 pthread_mutex_init(&mMutex, NULL); 00406 // configuration defaults 00407 mName="SignalDevice"; 00408 mCycleTime=1000; // 1ms 00409 mTimeScale=500; // 500ms is one faudes time unit 00410 mSyncWrite=false; 00411 } 00412 00413 00414 //~sDevice() 00415 sDevice::~sDevice(void) { 00416 // destructor 00417 00418 FD_DHV("sDevice(" << mName << ")::~sDevice()"); 00419 //cancel background thread: destroy mutex 00420 pthread_mutex_destroy(&mMutex); 00421 // invalidate data 00422 if(mpInputEdges) delete mpInputEdges; 00423 if(mpRecentInputEdges) delete mpRecentInputEdges; 00424 if(mpOutputLevels) delete mpOutputLevels; 00425 } 00426 00427 00428 //DoWritePreface(rTw,rLabel,pContext) 00429 void sDevice::DoWritePreface(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00430 00431 FD_DHV("sDevice("<<mName<<")::DoWritePreface()"); 00432 //call base 00433 vDevice::DoWritePreface(rTw,rLabel,pContext); 00434 //write cycle-time of background task 00435 Token ttag; 00436 ttag.SetEmpty("SampleInterval"); 00437 ttag.InsAttributeInteger("value",mCycleTime); 00438 rTw<<ttag; 00439 // write sync option 00440 if(mSyncWrite) rTw.WriteOption("SyncWrite"); 00441 } 00442 00443 //DoReadPreface(rTr,rLabel,pContext) 00444 void sDevice::DoReadPreface(TokenReader& rTr,const std::string& rLabel, const Type* pContext){ 00445 00446 FD_DHV("sDevice("<<mName<<")::DoReadPreface()"); 00447 // call base 00448 vDevice::DoReadPreface(rTr,rLabel,pContext); 00449 00450 // sense and digest pre 2.16 format 00451 Token token; 00452 rTr.Peek(token); 00453 if(token.IsInteger()) { 00454 mMaxBitAddress = rTr.ReadInteger(); 00455 mCycleTime = rTr.ReadInteger(); 00456 Token token; 00457 rTr.Peek(token); 00458 if(token.IsOption()) 00459 if(token.OptionValue()=="SyncWrite") { 00460 rTr.Get(token); 00461 mSyncWrite=true; 00462 } 00463 return; 00464 } 00465 00466 // loop my members 00467 while(true) { 00468 Token token; 00469 rTr.Peek(token); 00470 // cycle time 00471 if(token.IsBegin()) 00472 if(token.StringValue()=="SampleInterval") { 00473 rTr.ReadBegin("SampleInterval", token); 00474 mCycleTime=token.AttributeIntegerValue("value"); 00475 rTr.ReadEnd("SampleInterval"); 00476 continue; 00477 } 00478 // sync write 00479 if(token.IsBegin()) 00480 if(token.StringValue()=="SynchronousWrite") { 00481 rTr.ReadBegin("SynchronousWrite"); 00482 rTr.ReadEnd("SynchronousWrite"); 00483 mSyncWrite=true; 00484 continue; 00485 } 00486 // break on unknown 00487 break; 00488 } 00489 00490 // done 00491 } 00492 00493 00494 // lock - unlock shortcuts; 00495 #define LOCK_E {int rc = pthread_mutex_lock(&mMutex); \ 00496 if(rc) {FD_ERR("sDevice("<<mName<<")::LOCK_E: lock mutex error\n"); exit(1); }} 00497 #define UNLOCK_E {int rc = pthread_mutex_unlock(&mMutex); \ 00498 if(rc) {FD_ERR("sDevice("<<mName<<")::LOCK_E: unlock mutex error\n"); exit(1); }} 00499 00500 00501 #define TLOCK_E {int rc = pthread_mutex_lock(&sdevice->mMutex); \ 00502 if(rc) {FD_ERR("sDevice::TLOCK_E: lock mutex error\n"); exit(1); }} 00503 00504 #define TUNLOCK_E {int rc = pthread_mutex_unlock(&sdevice->mMutex); \ 00505 if(rc) {FD_ERR("sDevice::TLOCK_E: unlock mutex error\n"); exit(1); }} 00506 00507 00508 00509 00510 00511 // Start(void) 00512 void sDevice::Start(void) { 00513 //set device state and create thread 00514 00515 //return if device was allready started 00516 if( (mState == Up)||(mState == StartUp) ) return; 00517 FD_DHV("sDevice("<<mName<<")::Start()"); 00518 //call base incl virtual reset 00519 vDevice::Start(); 00520 mState=StartUp; 00521 //create background for edge detection and sync write 00522 if(!Inputs().Empty() || mSyncWrite){ 00523 mCancelRequest = false; 00524 //setup thread attribute 00525 pthread_attr_t attr; 00526 pthread_attr_init(&attr); 00527 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 00528 //create thread 00529 int rc = pthread_create(&mThreadSynchro, &attr, SDeviceSynchro, this); 00530 if (rc) { 00531 FD_ERR("sDevice("<<mName<<")::Start(): cannot creat thread\n"); 00532 exit(1); 00533 } 00534 //destroy thread-attribute 00535 pthread_attr_destroy(&attr); 00536 } 00537 } 00538 00539 // Stop() 00540 void sDevice::Stop(void) { 00541 // stop implies reset 00542 Reset(); 00543 // bail out if device allready got the command to shut down 00544 if(mState != Up && mState !=StartUp) return; 00545 FD_DH("sDevice("<<mName<<")::Stop()"); 00546 //dont kill thread if no thread was created 00547 if(!Inputs().Empty() || mSyncWrite) { 00548 //cancle thread 00549 LOCK_E; 00550 FD_DHV("sDevice("<<mName<<")::Stop(): Lock passed, waiting to join thread"); 00551 mCancelRequest=true; 00552 UNLOCK_E; 00553 int pc = pthread_join(mThreadSynchro,NULL); 00554 if(pc) { 00555 FD_ERR("sDevice("<<mName<<")::Stop(): cannot join thread??\n"); 00556 } 00557 } 00558 // indicate success 00559 mState=Down; 00560 } 00561 00562 00563 //Reset() 00564 void sDevice::Reset(){ 00565 //delete dynamic data 00566 FD_DH("sDevice("<<mName<<")::Reset()"); 00567 // call base (resets time) 00568 vDevice::Reset(); 00569 //delete dynamic data 00570 FD_DHV("sDevice("<<mName<<")::Reset(): B"); 00571 ClrInputSignals(); 00572 ClrOutputSignals(); 00573 // done 00574 FD_DHV("sDevice("<<mName<<")::Reset(): done"); 00575 } 00576 00577 // Clear() 00578 void sDevice::Clear(void) { 00579 //delete static data 00580 00581 FD_DHV("sDevice(" << mName << ")::Clear()"); 00582 // call base; note: clear implies stop 00583 vDevice::Clear(); 00584 // clear compiled data 00585 mInputPosEdgeIndexMap.clear(); 00586 mInputNegEdgeIndexMap.clear(); 00587 mMaxBitAddress=-1; 00588 mSyncWrite=false; 00589 mCycleTime=1000; // nsec 00590 } 00591 00592 //Compile(void) 00593 void sDevice::Compile(void){ 00594 //setup up internal data structure 00595 00596 FD_DHV("sDevice(" << mName << ")::Compile()"); 00597 // call base 00598 vDevice::Compile(); 00599 // clear my internal data 00600 mInputPosEdgeIndexMap.clear(); 00601 mInputNegEdgeIndexMap.clear(); 00602 mOutputLevelIndexMap.clear(); 00603 mMaxBitAddress=-1; 00604 // setup my internal data 00605 for(EventSet::Iterator eit=pConfiguration->Begin(); eit!=pConfiguration->End(); eit++) { 00606 AttributeSignalEvent attr = pConfiguration->Attribute(*eit); 00607 if(attr.IsInput()) { 00608 // fill in reverse maps 00609 std::vector<AttributeSignalInput::Trigger>::const_iterator ait; 00610 const AttributeSignalInput* sattr = attr.Inputp(); 00611 for(ait=sattr->mTriggers.begin(); ait!=sattr->mTriggers.end(); ait++) { 00612 if(ait->mPos) mInputPosEdgeIndexMap[ait->mBit].Insert(*eit); 00613 if(ait->mNeg) mInputNegEdgeIndexMap[ait->mBit].Insert(*eit); 00614 if(ait->mBit > mMaxBitAddress) mMaxBitAddress=ait->mBit; 00615 } 00616 } 00617 // check max address, set inverse map 00618 if(attr.IsOutput()) { 00619 std::vector<AttributeSignalOutput::Action>::const_iterator ait; 00620 const AttributeSignalOutput* aattr = attr.Outputp(); 00621 for(ait=aattr->mActions.begin(); ait!=aattr->mActions.end(); ait++) { 00622 if(ait->mBit > mMaxBitAddress) mMaxBitAddress=ait->mBit; 00623 mOutputLevelIndexMap[ait->mBit].Insert(*eit); 00624 if(ait->mValue == AttributeSignalOutput::Inv && !mSyncWrite) { 00625 throw Exception("sDevice::Compile(): ", 00626 "Inv-Action is currently only supported with SyncWrite", 52); 00627 } 00628 } 00629 } 00630 } 00631 // prep state data 00632 if(mpInputEdges) delete mpInputEdges; 00633 if(mpRecentInputEdges) delete mpRecentInputEdges; 00634 if(mpOutputLevels) delete mpOutputLevels; 00635 mpInputEdges = new Edges[mMaxBitAddress+1]; 00636 mpRecentInputEdges = new Edges[mMaxBitAddress+1]; 00637 mpOutputLevels = new Levels[mMaxBitAddress+1]; 00638 // report 00639 #ifdef FAUDES_DEBUG_IODEVICE 00640 for(int i=0; i<=mMaxBitAddress; i++) { 00641 if(mOutputLevelIndexMap[i].Empty()) continue; 00642 FD_DH("sDevice(" << mName << ")::Compile(): output signal at address " << i); 00643 } 00644 #endif 00645 } 00646 00647 //CycleTime(void) 00648 int sDevice::CycleTime(void) const { 00649 //Report current cycle time 00650 00651 FD_DHV("sDevice(" << mName << ")::CycleTime()"); 00652 return mCycleTime; 00653 } 00654 00655 //CycleTime(int) 00656 void sDevice::CycleTime(int cycleTime) { 00657 //Set cycle time 00658 FD_DHV("sDevice(" << mName << ")::CycleTime(int)"); 00659 if( mState==Up || mState==StartUp){ 00660 std::stringstream errstr; 00661 errstr << "Changing cycle-time not possible while background thread is still running "; 00662 throw Exception("sDevice::CycleTime: ", errstr.str(), 100); 00663 } 00664 mCycleTime = cycleTime; 00665 } 00666 00667 00668 //ReadSignal(int) 00669 bool sDevice::ReadSignal(int bit){ 00670 FD_DHV("sDevice(" << mName << ")::ReadSignal(int)"); 00671 00672 // make sure device is able to read signals 00673 if(Inputs().Empty()){ 00674 std::stringstream errstr; 00675 errstr << "(" << mName << ") is not able to read signals"; 00676 throw Exception("sDevice::ReadSignal():", errstr.str(), 552); //TODO: number! 00677 } 00678 00679 // lock global image, prevent background thread from reading/writing 00680 LOCK_E; 00681 // run with hooks 00682 bool res=false; 00683 if(DoReadSignalsPre()) 00684 res=DoReadSignal(bit); 00685 DoReadSignalsPost(); 00686 // free global image 00687 UNLOCK_E; 00688 00689 return res; 00690 } 00691 00692 //WriteSignal(int,int) 00693 void sDevice::WriteSignal(int bit, bool value){ 00694 // write one actor value, adressed by bit number (0 to 63); 00695 FD_DHV("sDevice(" << mName << ")::WriteSignal(int)"); 00696 // make sure device supports outputs 00697 if(Outputs().Empty()){ 00698 std::stringstream errstr; 00699 errstr << "(" << mName << ") is not configured for outputs"; 00700 throw Exception("sDevice::WriteSignal():", errstr.str(), 552); 00701 } 00702 // lock global image, prevent background thread from reading/writing 00703 LOCK_E; 00704 // case a) asynchronous write 00705 if(!mSyncWrite) { 00706 if(DoWriteSignalsPre()) { 00707 DoWriteSignal(bit,value); 00708 DoWriteSignalsPost(); 00709 } 00710 } 00711 // case b) synchronous write 00712 if(mSyncWrite) { 00713 // record next value 00714 Levels* level= &mpOutputLevels[bit]; 00715 level->next=value; 00716 if(level->edge) level->lost=true; 00717 level->edge=true; 00718 } 00719 // free global image 00720 UNLOCK_E; 00721 } 00722 00723 00724 //SDeviceSynchro(void*) 00725 void* SDeviceSynchro(void* arg){ 00726 00727 //background-thread main-routine 00728 00729 // cast this object 00730 sDevice* sdevice = static_cast<sDevice*>(arg); 00731 00732 FD_DH("sDevice(" << sdevice->mName << ")::Synchro(" << sdevice << "): with ct " << sdevice->mCycleTime); 00733 00734 ///////////////////////////////////////////////////// 00735 // cyletime-measurement 00736 // timeA: time consumed for a entire cycle 00737 // timeB: time consumed by computation 00738 // timeC: real time consumed by usleep 00739 //////////////////////////////////////////////////// 00740 #ifdef FAUDES_DEBUG_IOTIMING_X 00741 //arrays to store measured time in 00742 timeval* timeA = new timeval[MAX_SAMPLES]; 00743 timeval* timeB = new timeval[MAX_SAMPLES]; 00744 timeval* timeC = new timeval[MAX_SAMPLES]; 00745 // define local itterator 00746 int itime=0; 00747 // take time 00748 gettimeofday(timeA+itime,0); 00749 #endif 00750 00751 bool running=true; 00752 00753 while(running){ 00754 00755 // loop timer 00756 timeval timeL1; 00757 gettimeofday(&timeL1,0); 00758 00759 // lock global variables 00760 TLOCK_E; 00761 00762 // call hook 00763 sdevice->DoLoopCallback(); 00764 00765 // start up: initialize dynamic state 00766 if(sdevice->mState==sDevice::StartUp) { 00767 // reset inputs (edge detecteion) 00768 bool sready= sdevice->DoReadSignalsPre(); 00769 if(sready) { 00770 // edge detection: use actual signal levels 00771 FD_DH("sDevice("<<sdevice->Name()<<")::synchro: reset: edge detection"); 00772 for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) { 00773 sDevice::Edges* edge= &sdevice->mpInputEdges[bit]; 00774 edge->current=sdevice->DoReadSignal(bit); 00775 edge->past = edge->current; 00776 edge->pos = false; 00777 edge->neg = false; 00778 edge->posrel = (!sdevice->mInputPosEdgeIndexMap[bit].Empty()); 00779 edge->negrel = (!sdevice->mInputNegEdgeIndexMap[bit].Empty()); 00780 edge->lost = false; 00781 } 00782 sdevice->DoReadSignalsPost(); 00783 for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) { 00784 sDevice::Edges* redge= &sdevice->mpRecentInputEdges[bit]; 00785 redge->pos = false; 00786 redge->neg = false; 00787 redge->posrel = false; 00788 redge->negrel = false; 00789 redge->lost = false; 00790 } 00791 } 00792 // reset outputs (clear image) 00793 bool aready= sdevice->DoWriteSignalsPre(); 00794 if(aready) { 00795 // output image: set to zero 00796 FD_DH("sDevice("<<sdevice->Name()<<")::synchro: reset: clear lines"); 00797 for(int bit=0; bit<=sdevice->mMaxBitAddress; bit++) { 00798 sdevice->DoWriteSignal(bit,false); 00799 sDevice::Levels* level= &sdevice->mpOutputLevels[bit]; 00800 level->current=false; 00801 level->next=false; 00802 level->edge=false; 00803 level->lost=false; 00804 level->rel = (!sdevice->mOutputLevelIndexMap[bit].Empty()); 00805 } 00806 sdevice->DoWriteSignalsPost(); 00807 } 00808 // new state 00809 if(sready && aready) 00810 sdevice->mState=sDevice::Up; 00811 } 00812 00813 // normal operation, inputs 00814 if(sdevice->mState==sDevice::Up) { 00815 bool ready=sdevice->DoReadSignalsPre(); 00816 if(!ready) 00817 sdevice->mState=sDevice::StartUp; 00818 if(ready) { 00819 // edge detection, accumulative 00820 for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) { 00821 // define pointer to Inputedges 00822 sDevice::Edges* edge= &sdevice->mpInputEdges[bit]; 00823 // pass edge-info about edge in last cycle 00824 edge->past = edge->current; 00825 // and get corresponding input-value 00826 edge->current = sdevice->DoReadSignal(bit); 00827 if(edge->posrel) 00828 if(edge->current && (!edge->past) ) { 00829 /* 00830 if(edge->pos && (!edge->lost)) { 00831 FD_DH("sDevice::synchro: lost positive edge at bit address " << bit); 00832 edge->lost=true; 00833 } 00834 */ 00835 FD_DH("sDevice::synchro: sensed positive edge at bit address " << bit); 00836 edge->pos = true; 00837 // queue events to buffer 00838 pthread_mutex_lock(sdevice->pBufferMutex); 00839 EventSet::Iterator eit=sdevice->mInputPosEdgeIndexMap[bit].Begin(); 00840 EventSet::Iterator eit_end=sdevice->mInputPosEdgeIndexMap[bit].End(); 00841 for(; eit!=eit_end; eit++) { 00842 sdevice->pInputBuffer->push_back(*eit); 00843 } 00844 pthread_mutex_unlock(sdevice->pBufferMutex); 00845 //send signal to function "WaitSenosrs()" 00846 FD_DHV("sDevice::synchro: send signal " ); 00847 pthread_cond_broadcast(sdevice->pWaitCondition); 00848 } 00849 if(edge->negrel) 00850 if( (!edge->current) && edge->past ) { 00851 FD_DH("sDevice::synchro: sensed negative edge at bit address " << bit); 00852 edge->neg = true; 00853 sdevice->mInputReady = true; 00854 // queue events to buffer 00855 pthread_mutex_lock(sdevice->pBufferMutex); 00856 EventSet::Iterator eit=sdevice->mInputNegEdgeIndexMap[bit].Begin(); 00857 EventSet::Iterator eit_end=sdevice->mInputNegEdgeIndexMap[bit].End(); 00858 for(; eit!=eit_end; eit++) { 00859 sdevice->pInputBuffer->push_back(*eit); 00860 } 00861 pthread_mutex_unlock(sdevice->pBufferMutex); 00862 //send signal to function "WaitSenosrs" 00863 FD_DHV("sDevice::synchro: send signal " ); 00864 pthread_cond_broadcast(sdevice->pWaitCondition); 00865 } 00866 } // loop bits 00867 sdevice->DoReadSignalsPost(); 00868 } // end-if device ok 00869 } // end-if inputs 00870 00871 00872 // normal operation, outputs 00873 if(sdevice->mState==sDevice::Up && sdevice->mSyncWrite) { 00874 bool ready=sdevice->DoWriteSignalsPre(); 00875 if(!ready) 00876 sdevice->mState=sDevice::StartUp; 00877 if(ready) { 00878 // write values from image 00879 for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) { 00880 // define pointer to levels 00881 sDevice::Levels* level= &sdevice->mpOutputLevels[bit]; 00882 // not written by libfaudes 00883 if(!level->edge) continue; 00884 // write and record 00885 sdevice->DoWriteSignal(bit,level->next); 00886 level->current = level->next; 00887 level->edge = false; 00888 level->lost = false; 00889 } 00890 sdevice->DoWriteSignalsPost(); 00891 } 00892 } 00893 00894 // check for cancel request 00895 if(sdevice->mCancelRequest) running=false; 00896 // unlock global variables 00897 TUNLOCK_E; 00898 00899 ////////////////////////////////////// 00900 //cycletime measurement 00901 //measure time to perform computation 00902 #ifdef FAUDES_DEBUG_IOTIMING_X 00903 if(itime < MAX_SAMPLES) gettimeofday(timeB+itime,0); 00904 #endif 00905 00906 // let time pass (todo: reconsider overflow) 00907 timeval timeL2; 00908 gettimeofday(&timeL2,0); 00909 int delta = timeL2.tv_usec - timeL1.tv_usec; 00910 delta+= 1000000 * (timeL2.tv_sec - timeL1.tv_sec); 00911 if(delta < sdevice->mCycleTime) usleep(sdevice->mCycleTime-delta); 00912 else FD_DH("sDevice::synchro: missed cycle time by " << delta - sdevice->mCycleTime << " usec"); 00913 00914 00915 #ifdef FAUDES_DEBUG_IOTIMING_X 00916 ////////////////////////////////////// 00917 // cycletime measurement 00918 00919 // measure time consumed by wait 00920 if(itime < MAX_SAMPLES) gettimeofday(timeC+itime,0); 00921 // measure time needed for a hole cyle 00922 // increase iterator 00923 itime++; 00924 if(itime < MAX_SAMPLES) gettimeofday(timeA+itime,0); 00925 00926 #endif 00927 // count cycles 00928 sdevice->mCycleCount++; 00929 } // loop while running 00930 00931 00932 #ifdef FAUDES_DEBUG_IOTIMING_X 00933 00934 ///////////////////////////////////////////// 00935 // cycletime measurement 00936 // analysis using SampleDensityFunction 00937 FD_DHT("sDevice::synchro: performance analysis"); 00938 00939 SampledDensityFunction SamplesA; 00940 SamplesA.Clear(); 00941 SamplesA.Dim(100); 00942 SamplesA.Name("time stamp AA: overall period"); 00943 00944 SampledDensityFunction SamplesB; 00945 SamplesB.Clear(); 00946 SamplesB.Dim(100); 00947 SamplesB.Name("time stamp AB: process time"); 00948 00949 SampledDensityFunction SamplesC; 00950 SamplesC.Clear(); 00951 SamplesC.Dim(100); 00952 SamplesC.Name("time stamp CB: waited time"); 00953 00954 SampledDensityFunction SamplesWS; 00955 SamplesWS.Clear(); 00956 SamplesWS.Dim(100); 00957 SamplesWS.Name("time passed till the next call of WaitInputs"); 00958 00959 // timeval-structures needed for further computations 00960 timeval dAA,dBA,dCB,dER; 00961 00962 // perform analysis 00963 // time for a hole cycle 00964 for(int ind = 0; ind < itime-2; ind++){ 00965 // compute time needed 00966 // for a hole cycle 00967 dAA = vDevice::DiffTime(timeA[ind+1],timeA[ind]); 00968 // for computing input-state 00969 dBA = vDevice::DiffTime(timeB[ind],timeA[ind]); 00970 // by usleep(mCyleTime) 00971 dCB = vDevice::DiffTime(timeC[ind],timeB[ind]); 00972 // time passed by until the next call of WaitInputs 00973 dER = vDevice::DiffTime(sdevice->mptimeBegin[ind+1],sdevice->mptimeEnd[ind]); 00974 // add computed samples to corresponding 00975 // SampleDensityFunction classes 00976 SamplesA.Sample(dAA.tv_sec*1000000 + dAA.tv_usec); 00977 SamplesB.Sample(dBA.tv_sec*1000000 + dBA.tv_usec); 00978 SamplesC.Sample(dCB.tv_sec*1000000 + dCB.tv_usec); 00979 SamplesWS.Sample(1000000*dER.tv_sec + dER.tv_usec); 00980 } 00981 00982 // perform statistic computation 00983 SamplesA.Compile(); 00984 SamplesB.Compile(); 00985 SamplesC.Compile(); 00986 SamplesWS.Compile(); 00987 00988 // token output 00989 // SamplesA.Write(); 00990 // SamplesB.Write(); 00991 // SamplesC.Write(); 00992 // SamplesWS.Write(); 00993 00994 // pretty output 00995 std::cout << SamplesA.Str() << std::endl; 00996 std::cout << SamplesB.Str() << std::endl; 00997 std::cout << SamplesC.Str() << std::endl; 00998 std::cout << SamplesWS.Str() << std::endl; 00999 #endif 01000 FD_DH("sDevice(" << sdevice->mName << ")::synchro: terminate background thread"); 01001 pthread_exit(NULL); 01002 // never happens, prevent gcc warning 01003 return NULL; 01004 } 01005 01006 // Write Output(Idx) 01007 void sDevice::WriteOutput(Idx output) { 01008 01009 FD_DHV("sDevice("<<mName<<")::WriteOutput(" << output <<")"); 01010 //return if device is running 01011 if(mState!=Up && mState!=StartUp) return; 01012 //make sure event is part of devices eventset 01013 if(!mOutputs.Exists(output)) { 01014 std::stringstream errstr; 01015 errstr << "Unknown output event " << output; 01016 throw Exception("sDevice::WriteOutput", errstr.str(), 65); 01017 } 01018 // find properties 01019 const AttributeSignalOutput* aattr = pConfiguration->Attribute(output).Outputp(); 01020 if(!aattr) { 01021 std::stringstream errstr; 01022 errstr << "Invalid output attribute " << output; 01023 throw Exception("sDevice::WriteOutput", errstr.str(), 65); 01024 } 01025 //debug-flag 01026 FD_DHV("sDevice("<<mName<<")::WriteOutput: properties found"); 01027 // execute command ... 01028 std::vector<AttributeSignalOutput::Action>::const_iterator eit; 01029 // ... case a) asynchronous write (does not supper invert) 01030 if(!mSyncWrite) { 01031 if(DoWriteSignalsPre()) { 01032 // loop actions 01033 for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){ 01034 FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue); 01035 DoWriteSignal(eit->mBit,eit->mValue == AttributeSignalOutput::Set); 01036 } 01037 DoWriteSignalsPost(); 01038 } 01039 } 01040 // ... case b) synchronous write (does support invert) 01041 if(mSyncWrite) { 01042 // lock global image 01043 LOCK_E; 01044 // loop actions and record 01045 for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){ 01046 FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue); 01047 Levels* level= &mpOutputLevels[eit->mBit]; 01048 switch(eit->mValue) { 01049 case AttributeSignalOutput::Set: 01050 level->next=1; break; 01051 case AttributeSignalOutput::Clr: 01052 level->next=0; break; 01053 case AttributeSignalOutput::Inv: 01054 level->next= ~level->next; break; 01055 } 01056 if(level->edge) level->lost=true; 01057 level->edge=true; 01058 } 01059 // free global image 01060 UNLOCK_E; 01061 } 01062 // done 01063 FD_DHV("sDevice("<<mName<<")::WriteOutput: done"); 01064 } 01065 01066 //ClrInputSignals() 01067 void sDevice::ClrInputSignals(void) { 01068 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): MaxBitAddress: " << mMaxBitAddress); 01069 //return if device is not running or device is not able to read inputs 01070 if( mState!=Up || Inputs().Empty()) return; 01071 // lock global variables 01072 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): lock mutex "); 01073 LOCK_E; 01074 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detection "); 01075 // initialise edge detection: assume low signals 01076 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01077 Edges* edge= &mpInputEdges[bit]; 01078 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit); 01079 edge->current=0; 01080 edge->past = 0; 01081 edge->pos = false; 01082 edge->neg = false; 01083 edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty()); 01084 edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty()); 01085 edge->lost = false; 01086 } 01087 // initialise edge detection: actual signal levels 01088 if(DoReadSignalsPre()) { 01089 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01090 Edges* edge= &mpInputEdges[bit]; 01091 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit); 01092 edge->current=DoReadSignal(bit); 01093 edge->past = edge->current; 01094 edge->pos = false; 01095 edge->neg = false; 01096 edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty()); 01097 edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty()); 01098 edge->lost = false; 01099 } 01100 DoReadSignalsPost(); 01101 } 01102 // initialize edge detection: recent edges 01103 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): initialize recent edges "); 01104 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01105 Edges* redge= &mpRecentInputEdges[bit]; 01106 redge->pos = false; 01107 redge->neg = false; 01108 redge->posrel = false; 01109 redge->negrel = false; 01110 redge->lost = false; 01111 } 01112 // reset cyclecount 01113 mCycleCount=0; 01114 mRecentCycleCount=0; 01115 mInputReady=false; 01116 // unlock global variables 01117 UNLOCK_E; 01118 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): done"); 01119 } 01120 01121 //ClrOutputSignals() 01122 void sDevice::ClrOutputSignals(void) { 01123 //clear all output line levels 01124 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals"); 01125 // return if device is not running or not abel to set output signals 01126 if(mState!=Up || Outputs().Empty()) return; 01127 // lock variables, prevent background from writing 01128 LOCK_E; 01129 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: passed lock"); 01130 // clear all (allways asynchronous) 01131 if(DoWriteSignalsPre()) { 01132 for(int bit=0; bit<=mMaxBitAddress; bit++) DoWriteSignal(bit, false); 01133 DoWriteSignalsPost(); 01134 } 01135 // clear image 01136 for(int bit=0; bit<=mMaxBitAddress; bit++) { 01137 Levels* level= &mpOutputLevels[bit]; 01138 level->current=false; 01139 level->next=false; 01140 level->edge=false; 01141 level->lost=false; 01142 } 01143 // done 01144 UNLOCK_E; 01145 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: done"); 01146 } 01147 01148 }//end namespace faudes 01149 01150 |
libFAUDES 2.20s --- 2011.10.12 --- c++ source docu by doxygen