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

libFAUDES 2.22s --- 2013.10.07 --- c++ source docu by doxygen