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