About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
libFAUDES

Sections

Index

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

libFAUDES 2.20s --- 2011.10.12 --- c++ source docu by doxygen