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