iop_sdevice.cpp

Go 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