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); 00714 } 00715 //return if device is running 00716 if(mState!=Up && mState!=StartUp) { 00717 std::stringstream errstr; 00718 errstr << "Signal access not possible while background thread is not running "; 00719 throw Exception("sDevice::ReadSignal: ", errstr.str(), 552); 00720 } 00721 // lock global image, prevent background thread from reading/writing 00722 LOCK_E; 00723 // run with hooks 00724 bool res=false; 00725 if(DoReadSignalsPre()) { 00726 res=DoReadSignal(bit); 00727 DoReadSignalsPost(); 00728 } 00729 // free global image 00730 UNLOCK_E; 00731 return res; 00732 } 00733 00734 //WriteSignal(int,int) 00735 void sDevice::WriteSignal(int bit, bool value){ 00736 // write one actor value, adressed by bit number (0 to 63); 00737 FD_DHV("sDevice(" << mName << ")::WriteSignal(int)"); 00738 // make sure device supports outputs 00739 if(Outputs().Empty()){ 00740 std::stringstream errstr; 00741 errstr << "(" << mName << ") is not configured for outputs"; 00742 throw Exception("sDevice::WriteSignal():", errstr.str(), 552); 00743 } 00744 // bail out if device is running 00745 if(mState!=Up && mState!=StartUp) { 00746 std::stringstream errstr; 00747 errstr << "Signal access not possible while background thread is not running "; 00748 throw Exception("sDevice::ReadSignal: ", errstr.str(), 552); 00749 } 00750 // lock global image, prevent background thread from reading/writing 00751 LOCK_E; 00752 // case a) asynchronous write 00753 if(!mSyncWrite) { 00754 if(DoWriteSignalsPre()) { 00755 DoWriteSignal(bit,value); 00756 DoWriteSignalsPost(); 00757 } 00758 } 00759 // case b) synchronous write 00760 if(mSyncWrite) { 00761 // record next value 00762 Levels* level= &mpOutputLevels[bit]; 00763 level->next=value; 00764 if(level->edge) level->lost=true; 00765 level->edge=true; 00766 } 00767 // free global image 00768 UNLOCK_E; 00769 } 00770 00771 00772 //SDeviceSynchro(void*) 00773 void* SDeviceSynchro(void* arg){ 00774 00775 //background-thread main-routine 00776 00777 // cast this object 00778 sDevice* sdevice = static_cast<sDevice*>(arg); 00779 00780 FD_DH("sDevice(" << sdevice->mName << ")::Synchro(" << sdevice << "): with ct " << sdevice->mCycleTime); 00781 00782 #ifdef FAUDES_DEBUG_IOTIMING_X 00783 ///////////////////////////////////////////////////// 00784 // cyletime analysis 00785 // timeA: time consumed for an entire cycle 00786 // timeB: time consumed for edge detection and i/o 00787 // timeC: time left for usleep 00788 // 00789 // provide arrays for samples 00790 faudes_systime_t* timeA = new faudes_systime_t[MAX_SAMPLES]; 00791 faudes_systime_t* timeB = new faudes_systime_t[MAX_SAMPLES]; 00792 faudes_systime_t* timeC = new faudes_systime_t[MAX_SAMPLES]; 00793 // provide pointer to current sample 00794 int itime=0; 00795 // take a sample 00796 faudes_gettimeofday(timeA+itime); 00797 #endif 00798 00799 bool running=true; 00800 00801 while(running){ 00802 00803 // loop timer 00804 faudes_systime_t timeL1; 00805 faudes_gettimeofday(&timeL1); 00806 00807 // lock global variables 00808 TLOCK_E; 00809 00810 // call hook 00811 sdevice->DoLoopCallback(); 00812 00813 // start up: initialize dynamic state 00814 if(sdevice->mState==sDevice::StartUp) { 00815 // reset outputs (clear image) 00816 bool aready= sdevice->DoWriteSignalsPre(); 00817 if(aready) { 00818 // output image: set to zero 00819 FD_DHV("sDevice("<<sdevice->Name()<<")::synchro: reset: clear lines"); 00820 for(int bit=0; bit<=sdevice->mMaxBitAddress; bit++) { 00821 sDevice::Levels* level= &sdevice->mpOutputLevels[bit]; 00822 level->current=false; 00823 level->next=false; 00824 level->edge=false; 00825 level->lost=false; 00826 level->rel = (!sdevice->mOutputLevelIndexMap[bit].Empty()); 00827 if(level->rel) sdevice->DoWriteSignal(bit,false); 00828 } 00829 sdevice->DoWriteSignalsPost(); 00830 } 00831 // reset inputs (edge detecteion) 00832 bool sready= sdevice->DoReadSignalsPre(); 00833 if(sready) { 00834 // edge detection: use actual signal levels 00835 FD_DHV("sDevice("<<sdevice->Name()<<")::synchro: reset: edge detection"); 00836 for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) { 00837 sDevice::Edges* edge= &sdevice->mpInputEdges[bit]; 00838 edge->current=sdevice->DoReadSignal(bit); 00839 edge->past = edge->current; 00840 edge->pos = false; 00841 edge->neg = false; 00842 edge->posrel = (!sdevice->mInputPosEdgeIndexMap[bit].Empty()); 00843 edge->negrel = (!sdevice->mInputNegEdgeIndexMap[bit].Empty()); 00844 edge->lost = false; 00845 } 00846 sdevice->DoReadSignalsPost(); 00847 for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) { 00848 sDevice::Edges* redge= &sdevice->mpRecentInputEdges[bit]; 00849 redge->pos = false; 00850 redge->neg = false; 00851 redge->posrel = false; 00852 redge->negrel = false; 00853 redge->lost = false; 00854 } 00855 } 00856 // new state 00857 if(sready && aready) 00858 sdevice->mState=sDevice::Up; 00859 } 00860 00861 // normal operation, inputs 00862 if(sdevice->mState==sDevice::Up) { 00863 bool ready=sdevice->DoReadSignalsPre(); 00864 if(!ready) 00865 sdevice->mState=sDevice::StartUp; 00866 if(ready) { 00867 // edge detection, accumulative 00868 for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) { 00869 // define pointer to Inputedges 00870 sDevice::Edges* edge= &sdevice->mpInputEdges[bit]; 00871 // pass edge-info about edge in last cycle 00872 edge->past = edge->current; 00873 // and get corresponding input-value 00874 edge->current = sdevice->DoReadSignal(bit); 00875 if(edge->posrel) 00876 if(edge->current && (!edge->past) ) { 00877 FD_DHV("sDevice::synchro: sensed positive edge at bit address " << bit); 00878 edge->pos = true; 00879 // queue events to buffer 00880 faudes_mutex_lock(sdevice->pBufferMutex); 00881 EventSet::Iterator eit=sdevice->mInputPosEdgeIndexMap[bit].Begin(); 00882 EventSet::Iterator eit_end=sdevice->mInputPosEdgeIndexMap[bit].End(); 00883 for(; eit!=eit_end; eit++) { 00884 sdevice->pInputBuffer->push_back(*eit); 00885 } 00886 faudes_mutex_unlock(sdevice->pBufferMutex); 00887 //send signal to function "WaitSenosrs()" 00888 FD_DHV("sDevice::synchro: send signal " ); 00889 faudes_cond_broadcast(sdevice->pWaitCondition); 00890 } 00891 if(edge->negrel) 00892 if( (!edge->current) && edge->past ) { 00893 FD_DHV("sDevice::synchro: sensed negative edge at bit address " << bit); 00894 edge->neg = true; 00895 sdevice->mInputReady = true; 00896 // queue events to buffer 00897 faudes_mutex_lock(sdevice->pBufferMutex); 00898 EventSet::Iterator eit=sdevice->mInputNegEdgeIndexMap[bit].Begin(); 00899 EventSet::Iterator eit_end=sdevice->mInputNegEdgeIndexMap[bit].End(); 00900 for(; eit!=eit_end; eit++) { 00901 sdevice->pInputBuffer->push_back(*eit); 00902 } 00903 faudes_mutex_unlock(sdevice->pBufferMutex); 00904 //send signal to function "WaitSenosrs" 00905 FD_DHV("sDevice::synchro: send signal " ); 00906 faudes_cond_broadcast(sdevice->pWaitCondition); 00907 } 00908 } // loop bits 00909 sdevice->DoReadSignalsPost(); 00910 } // end-if device ok 00911 } // end-if inputs 00912 00913 00914 // normal operation, outputs 00915 if(sdevice->mState==sDevice::Up && sdevice->mSyncWrite) { 00916 bool ready=sdevice->DoWriteSignalsPre(); 00917 if(!ready) 00918 sdevice->mState=sDevice::StartUp; 00919 if(ready) { 00920 // write values from image 00921 for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) { 00922 // define pointer to levels 00923 sDevice::Levels* level= &sdevice->mpOutputLevels[bit]; 00924 // not written by libfaudes 00925 if(!level->edge) continue; 00926 // write and record 00927 sdevice->DoWriteSignal(bit,level->next); 00928 level->current = level->next; 00929 level->edge = false; 00930 level->lost = false; 00931 } 00932 sdevice->DoWriteSignalsPost(); 00933 } 00934 } 00935 00936 // check for cancel request 00937 if(sdevice->mCancelRequest) { 00938 running=false; 00939 sdevice->mState=vDevice::ShutDown; 00940 } 00941 // unlock global variables 00942 TUNLOCK_E; 00943 00944 #ifdef FAUDES_DEBUG_IOTIMING_X 00945 ////////////////////////////////////// 00946 //cycletime analysis: take a sample 00947 if(itime < MAX_SAMPLES) faudes_gettimeofday(timeB+itime); 00948 #endif 00949 00950 // let time pass 00951 faudes_systime_t timeL2; 00952 faudes_gettimeofday(&timeL2); 00953 long int delta = (timeL2.tv_nsec - timeL1.tv_nsec)/1000; 00954 delta+= 1000000 * (timeL2.tv_sec - timeL1.tv_sec); 00955 if(delta < sdevice->mCycleTime) faudes_usleep(sdevice->mCycleTime-delta); 00956 else { 00957 if(sdevice->mState==sDevice::Up) FD_DH("sDevice::synchro: missed cycle time by " << delta - sdevice->mCycleTime << " usec"); 00958 } 00959 00960 00961 #ifdef FAUDES_DEBUG_IOTIMING_X 00962 ////////////////////////////////////// 00963 // cycletime analysis 00964 00965 // take a sample 00966 if(itime < MAX_SAMPLES) faudes_gettimeofday(timeC+itime); 00967 // increment pointer 00968 itime++; 00969 if(itime < MAX_SAMPLES) faudes_gettimeofday(timeA+itime); 00970 00971 #endif 00972 // count cycles 00973 sdevice->mCycleCount++; 00974 } // loop while running 00975 00976 00977 #ifdef FAUDES_DEBUG_IOTIMING_X 00978 00979 ///////////////////////////////////////////// 00980 // cycletime analysis 00981 // set up statsitics 00982 FD_DHT("sDevice::synchro: performance analysis"); 00983 00984 SampledDensityFunction SamplesA; 00985 SamplesA.Clear(); 00986 SamplesA.Dim(100); 00987 SamplesA.Name("time stamp AA: overall period"); 00988 00989 SampledDensityFunction SamplesB; 00990 SamplesB.Clear(); 00991 SamplesB.Dim(100); 00992 SamplesB.Name("time stamp AB: process time"); 00993 00994 SampledDensityFunction SamplesC; 00995 SamplesC.Clear(); 00996 SamplesC.Dim(100); 00997 SamplesC.Name("time stamp CB: sleep time"); 00998 00999 SampledDensityFunction SamplesWS; 01000 SamplesWS.Clear(); 01001 SamplesWS.Dim(100); 01002 SamplesWS.Name("time passed till the next call of WaitInputs"); 01003 01004 // timeval-structures needed for further computations 01005 faudes_systime_t dAA,dBA,dCB,dER; 01006 01007 // perform analysis 01008 // time for a hole cycle 01009 for(int ind = 0; ind < itime-2; ind++){ 01010 // compute time needed 01011 // for a hole cycle 01012 faudes_diffsystime(timeA[ind+1],timeA[ind],&dAA); 01013 // for computing input-state 01014 faudes_diffsystime(timeB[ind],timeA[ind],&dBA); 01015 // by usleep(mCyleTime) 01016 faudes_diffsystime(timeC[ind],timeB[ind],&dCB); 01017 // time passed by until the next call of WaitInputs 01018 faudes_diffsystime(sdevice->mptimeBegin[ind+1],sdevice->mptimeEnd[ind],&dER); 01019 // insert samples to density functions 01020 SamplesA.Sample(dAA.tv_sec*1000000 + dAA.tv_nsec/1000); 01021 SamplesB.Sample(dBA.tv_sec*1000000 + dBA.tv_nsec/1000); 01022 SamplesC.Sample(dCB.tv_sec*1000000 + dCB.tv_nsec/1000); 01023 SamplesWS.Sample(1000000*dER.tv_sec + dER.tv_nsec/1000); 01024 } 01025 01026 // perform statistic computation 01027 SamplesA.Compile(); 01028 SamplesB.Compile(); 01029 SamplesC.Compile(); 01030 SamplesWS.Compile(); 01031 01032 // token output 01033 // SamplesA.Write(); 01034 // SamplesB.Write(); 01035 // SamplesC.Write(); 01036 // SamplesWS.Write(); 01037 01038 // pretty print output 01039 std::cout << SamplesA.Str() << std::endl; 01040 std::cout << SamplesB.Str() << std::endl; 01041 std::cout << SamplesC.Str() << std::endl; 01042 std::cout << SamplesWS.Str() << std::endl; 01043 #endif 01044 01045 FD_DH("sDevice(" << sdevice->mName << ")::synchro: terminate background thread"); 01046 faudes_thread_exit(NULL); 01047 // never happens, prevent gcc warning 01048 return NULL; 01049 } 01050 01051 // Write Output(Idx) 01052 void sDevice::WriteOutput(Idx output) { 01053 01054 FD_DHV("sDevice("<<mName<<")::WriteOutput(" << output <<")"); 01055 //return if device is running 01056 if(mState!=Up && mState!=StartUp) return; 01057 //make sure event is part of devices eventset 01058 if(!mOutputs.Exists(output)) { 01059 std::stringstream errstr; 01060 errstr << "Unknown output event " << output; 01061 throw Exception("sDevice::WriteOutput", errstr.str(), 65); 01062 } 01063 // find properties 01064 const AttributeSignalOutput* aattr = pConfiguration->Attribute(output).Outputp(); 01065 if(!aattr) { 01066 std::stringstream errstr; 01067 errstr << "Invalid output attribute " << output; 01068 throw Exception("sDevice::WriteOutput", errstr.str(), 65); 01069 } 01070 //debug-flag 01071 FD_DHV("sDevice("<<mName<<")::WriteOutput: properties found"); 01072 // execute command ... 01073 std::vector<AttributeSignalOutput::Action>::const_iterator eit; 01074 // ... case a) asynchronous write (does not supper invert) 01075 if(!mSyncWrite) { 01076 // prepare 01077 if(DoWriteSignalsPre()) { 01078 // loop actions 01079 for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){ 01080 FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue); 01081 DoWriteSignal(eit->mBit,eit->mValue == AttributeSignalOutput::Set); 01082 } 01083 DoWriteSignalsPost(); 01084 } 01085 } 01086 // ... case b) synchronous write (does support invert) 01087 if(mSyncWrite) { 01088 // lock global image 01089 LOCK_E; 01090 // loop actions and record 01091 for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){ 01092 FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue); 01093 Levels* level= &mpOutputLevels[eit->mBit]; 01094 switch(eit->mValue) { 01095 case AttributeSignalOutput::Set: 01096 level->next=1; break; 01097 case AttributeSignalOutput::Clr: 01098 level->next=0; break; 01099 case AttributeSignalOutput::Inv: 01100 level->next= ~level->next; break; 01101 } 01102 if(level->edge) level->lost=true; 01103 level->edge=true; 01104 } 01105 // free global image 01106 UNLOCK_E; 01107 } 01108 // done 01109 FD_DHV("sDevice("<<mName<<")::WriteOutput: done"); 01110 } 01111 01112 //ClrInputSignals() 01113 void sDevice::ClrInputSignals(void) { 01114 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): MaxBitAddress: " << mMaxBitAddress); 01115 //return if device is not running or device is not able to read inputs 01116 if( mState!=Up || Inputs().Empty()) return; 01117 // lock global variables 01118 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): lock mutex "); 01119 LOCK_E; 01120 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detection "); 01121 // initialise edge detection: assume low signals 01122 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01123 Edges* edge= &mpInputEdges[bit]; 01124 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit); 01125 edge->current=0; 01126 edge->past = 0; 01127 edge->pos = false; 01128 edge->neg = false; 01129 edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty()); 01130 edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty()); 01131 edge->lost = false; 01132 } 01133 // initialise edge detection: actual signal levels 01134 if(DoReadSignalsPre()) { 01135 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01136 Edges* edge= &mpInputEdges[bit]; 01137 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit); 01138 edge->current=DoReadSignal(bit); 01139 edge->past = edge->current; 01140 edge->pos = false; 01141 edge->neg = false; 01142 edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty()); 01143 edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty()); 01144 edge->lost = false; 01145 } 01146 DoReadSignalsPost(); 01147 } 01148 // initialize edge detection: recent edges 01149 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): initialize recent edges "); 01150 for(int bit = 0;bit<=mMaxBitAddress;bit++) { 01151 Edges* redge= &mpRecentInputEdges[bit]; 01152 redge->pos = false; 01153 redge->neg = false; 01154 redge->posrel = false; 01155 redge->negrel = false; 01156 redge->lost = false; 01157 } 01158 // reset cyclecount 01159 mCycleCount=0; 01160 mRecentCycleCount=0; 01161 mInputReady=false; 01162 // unlock global variables 01163 UNLOCK_E; 01164 FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): done"); 01165 } 01166 01167 //ClrOutputSignals() 01168 void sDevice::ClrOutputSignals(void) { 01169 //clear all output line levels 01170 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals"); 01171 // return if device is not running or not abel to set output signals 01172 if(mState!=Up || Outputs().Empty()) return; 01173 // lock variables, prevent background from writing 01174 LOCK_E; 01175 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: passed lock"); 01176 // clear all (allways asynchronous) 01177 if(DoWriteSignalsPre()) { 01178 for(int bit=0; bit<=mMaxBitAddress; bit++) 01179 if(mpOutputLevels[bit].rel) DoWriteSignal(bit, false); 01180 DoWriteSignalsPost(); 01181 } 01182 // clear image 01183 for(int bit=0; bit<=mMaxBitAddress; bit++) { 01184 Levels* level= &mpOutputLevels[bit]; 01185 level->current=false; 01186 level->next=false; 01187 level->edge=false; 01188 level->lost=false; 01189 } 01190 // done 01191 UNLOCK_E; 01192 FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: done"); 01193 } 01194 01195 }//end namespace faudes 01196 01197 libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |