iop_sdevice.cpp
Go to the documentation of this file.
1 /** @file iop_sdevice.cpp Virtual device for interface definition */
2 
3 /*
4  FAU Discrete Event Systems Library (libfaudes)
5 
6  Copyright (C) 2008, Thomas Moor
7  Exclusive copyright is granted to Klaus Schmidt
8 
9 */
10 
11 
12 
13 #include "iop_sdevice.h"
14 #include "sys/time.h"
15 #include "sp_densityfnct.h"
16 
17 namespace faudes {
18 
19 
20 /*
21  **********************************************
22  **********************************************
23  **********************************************
24 
25  implementation: AttributeSignalOutput
26 
27  **********************************************
28  **********************************************
29  **********************************************
30  */
31 
32 // faudes type std
33 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSignalOutput,AttributeVoid)
34 
35 //DoAssign(Src)
36 void AttributeSignalOutput::DoAssign(const AttributeSignalOutput& rSrcAttr) {
37  FD_DHV("AttributeSignalOutput(" << this << "):DoAssign(): assignment from " << &rSrcAttr);
38  mActions=rSrcAttr.mActions;
39 }
40 
41 //DoWrite(rTw);
42 void AttributeSignalOutput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
43  (void) rLabel; (void) pContext;
44 
45  FD_DHV("AttributeSignalOutput::DoWrite(): #" << mActions.size() );
46  rTw.WriteBegin("Actions");
47  std::vector<Action>::const_iterator ait;
48  for(ait=mActions.begin(); ait!=mActions.end(); ait++) {
49  Token atoken;
50  if(ait->mValue==Set)
51  atoken.SetEmpty("Set");
52  if(ait->mValue==Clr)
53  atoken.SetEmpty("Clr");
54  if(ait->mValue==Inv)
55  atoken.SetEmpty("Inv");
56  atoken.InsAttributeInteger("address",ait->mBit);
57  rTw << atoken;
58  }
59  rTw.WriteEnd("Actions");
60 }
61 
62 
63 //DoRead(rTr)
64 void AttributeSignalOutput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
65  (void) rLabel; (void) pContext;
66  Token token;
67  FD_DHV("AttributeSignalOutput::DoRead()");
68 
69  // sense and digest pre 2.16 format
70  rTr.Peek(token);
71  if(token.IsBegin())
72  if((token.StringValue()=="Output") || (token.StringValue()=="Actuator")) {
73  rTr.ReadBegin("Actuator");
74  bool err=false;
75  rTr.ReadBegin("Actions");
76  while(!rTr.Eos("Actions")) {
77  Action action;
78  action.mBit=rTr.ReadInteger();
79  std::string value=rTr.ReadOption();
80  if(value== "Set") {
81  action.mValue=Set;
82  } else if(value == "Clr") {
83  action.mValue=Clr;
84  } else if(value == "Inv") {
85  action.mValue=Inv;
86  } else {
87  err=true;
88  break;
89  }
90  mActions.push_back(action);
91  }
92  rTr.ReadEnd("Actions");
93  rTr.ReadEnd("Actuator");
94  if(err) {
95  std::stringstream errstr;
96  errstr << "Invalid output event property" << rTr.FileLine();
97  throw Exception("AttributeSignalOutput::Read", errstr.str(), 52); //52 oder 352
98  }
99  } // end pre 2.16
100 
101 
102  // test for actions section
103  rTr.Peek(token);
104  if(!token.IsBegin()) return;
105  if(token.StringValue()!="Actions") return;
106  // read begin
107  bool err=false;
108  rTr.ReadBegin("Actions");
109  while(!rTr.Eos("Actions")) {
110  // prepare
111  Token atag;
112  Action action;
113  rTr.Peek(atag);
114  // set
115  if(atag.IsBegin())
116  if(atag.StringValue()=="Set") {
117  rTr.ReadBegin("Set");
118  action.mValue=Set;
119  action.mBit=atag.AttributeIntegerValue("address");
120  mActions.push_back(action);
121  rTr.ReadEnd("Set");
122  continue;
123  }
124  // clr
125  if(atag.IsBegin())
126  if(atag.StringValue()=="Clr") {
127  rTr.ReadBegin("Clr");
128  action.mValue=Clr;
129  action.mBit=atag.AttributeIntegerValue("address");
130  mActions.push_back(action);
131  rTr.ReadEnd("Clr");
132  continue;
133  }
134  // inv
135  if(atag.StringValue()=="Inv") {
136  rTr.ReadBegin("Inv");
137  action.mValue=Inv;
138  action.mBit=atag.AttributeIntegerValue("address");
139  mActions.push_back(action);
140  rTr.ReadEnd("Inv");
141  continue;
142  }
143  // error on unknown tokens
144  err=true;
145  break;
146  }
147  // done
148  rTr.ReadEnd("Actions");
149  // report error
150  if(err) {
151  std::stringstream errstr;
152  errstr << "Invalid output event property" << rTr.FileLine();
153  throw Exception("AttributeSignalOutput::Read", errstr.str(), 52); //52 oder 352
154  }
155 
156 }//DoRead
157 
158 
159 /*
160  **********************************************
161  **********************************************
162  **********************************************
163 
164  implementation: AttributeSignalInput
165 
166  **********************************************
167  **********************************************
168  **********************************************
169  */
170 
171 
172 // faudes type std
174 
175 
176 //DoAssign(Src)
177 void AttributeSignalInput::DoAssign(const AttributeSignalInput& rSrcAttr) {
178  FD_DHV("AttributeSignalInput(" << this << "):DoAssign(): assignment from " << &rSrcAttr);
179  mTriggers=rSrcAttr.mTriggers;
180 }
181 
182 
183 //DoWrite(rTw,rLabel,pContext)
184 void AttributeSignalInput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
185  (void) rLabel; (void) pContext;
186  FD_DHV("AttributeSignalInput()::DoWrite()");
187  rTw.WriteBegin("Triggers");
188  std::vector<Trigger>::const_iterator ait;
189  for(ait=mTriggers.begin(); ait!=mTriggers.end(); ait++) {
190  Token atoken;
191  if(ait->mPos && (!ait->mNeg)) {
192  atoken.SetEmpty("PositiveEdge");
193  }
194  if((!ait->mPos) && ait->mNeg) {
195  atoken.SetEmpty("NegativeEdge");
196  }
197  if((ait->mPos) && ait->mNeg) {
198  atoken.SetEmpty("AnyyEdge");
199  atoken.InsAttributeString("edge","any");
200  }
201  atoken.InsAttributeInteger("address",ait->mBit);
202  rTw << atoken;
203 
204  }
205  rTw.WriteEnd("Triggers");
206 }//DoWrite(rTw,rLabel,pContext)
207 
208 
209 //DoRead(rTr,rLabel,pContext)
210 void AttributeSignalInput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
211  (void) rLabel; (void) pContext;
212  Token token;
213  FD_DHV("AttributeSignalInput()::DoRead(tr)");
214 
215 
216  // sense and digest pre 2.16 format
217  rTr.Peek(token);
218  if(token.IsBegin())
219  if((token.StringValue()=="Input") || (token.StringValue()=="Sensor")) {
220  rTr.ReadBegin("Sensor");
221  bool err=false;
222  rTr.ReadBegin("Triggers");
223  while(!rTr.Eos("Triggers")) {
224  Trigger trigger;
225  trigger.mBit=rTr.ReadInteger();
226  std::string value=rTr.ReadOption();
227  if (value == "PosEdge") {
228  trigger.mPos=true;
229  trigger.mNeg=false;
230  } else if (value == "NegEdge") {
231  trigger.mPos=false;
232  trigger.mNeg=true;
233  } else if (value == "AnyEdge") {
234  trigger.mPos=true;
235  trigger.mNeg=true;
236  } else {
237  err=true;
238  break;
239  }
240  mTriggers.push_back(trigger);
241  }
242  rTr.ReadEnd("Triggers");
243  rTr.ReadEnd("Sensor");
244  if(err) {
245  std::stringstream errstr;
246  errstr << "invalid input event property" << rTr.FileLine();
247  throw Exception("AttributeSignalInput::Read", errstr.str(), 52);
248  }
249  } // end pre2.16
250 
251  // test for triggers section
252  rTr.Peek(token);
253  if(!token.IsBegin()) return;
254  if(token.StringValue()!="Triggers") return;
255  // read begin
256  bool err=false;
257  rTr.ReadBegin("Triggers");
258  while(!rTr.Eos("Triggers")) {
259  // prepare
260  Token atag;
261  Trigger trigger;
262  rTr.Peek(atag);
263  // positive edge
264  if(atag.IsBegin())
265  if(atag.StringValue()=="PositiveEdge") {
266  rTr.ReadBegin("PositiveEdge");
267  trigger.mPos=true;
268  trigger.mNeg=false;
269  trigger.mBit=atag.AttributeIntegerValue("address");
270  mTriggers.push_back(trigger);
271  rTr.ReadEnd("PositiveEdge");
272  continue;
273  }
274  // negative edge
275  if(atag.IsBegin())
276  if(atag.StringValue()=="NegativeEdge") {
277  rTr.ReadBegin("NegativeEdge");
278  trigger.mPos=false;
279  trigger.mNeg=true;
280  trigger.mBit=atag.AttributeIntegerValue("address");
281  mTriggers.push_back(trigger);
282  rTr.ReadEnd("NegativeEdge");
283  continue;
284  }
285  // any edge
286  if(atag.IsBegin())
287  if(atag.StringValue()=="AnyEdge") {
288  rTr.ReadBegin("AnyEdge");
289  trigger.mPos=true;
290  trigger.mNeg=true;
291  trigger.mBit=atag.AttributeIntegerValue("address");
292  mTriggers.push_back(trigger);
293  rTr.ReadEnd("AnyEdge");
294  continue;
295  }
296  // error on unknown tokens
297  err=true;
298  break;
299  }
300  // done
301  rTr.ReadEnd("Triggers");
302  // report error
303  if(err) {
304  std::stringstream errstr;
305  errstr << "Invalid input event property" << rTr.FileLine();
306  throw Exception("AttributeSignalInput::Read", errstr.str(), 52); //52 oder 352
307  }
308 }
309 
310 
311 
312 /*
313  **********************************************
314  **********************************************
315  **********************************************
316 
317  implementation: AttributeSignalEvent
318 
319  **********************************************
320  **********************************************
321  **********************************************
322  */
323 
324 
325 
326 // std faudes type
328 
329 // Default constructor, set my prototypes
331  FD_DHV("AttributeSignalEvent::AttributeSignalEvent(" << this << ")");
332  pOutputPrototype=OutputPrototypep();
333  pInputPrototype=InputPrototypep();
334 }
335 
336 // Copy constructor
339 {
340  FD_DHV("AttributeSimplenetEvent(" << this << "): form other attr " << &rOtherAttr);
343  DoAssign(rOtherAttr);
344 }
345 
346 
347 
348 // autoregister event confiration (required for XML token format)
350  gRti1RegisterSignalDeviceEventSet("SignalDeviceEventSet");
352  gRti1XElementTagSignalDeviceEventSet("SignalDeviceEventSet", "Event");
353 
354 // pseudo statics
357  return attrp;
358 }
359 
360 // pseudo statics
363  return attrp;
364 }
365 
366 /*
367  **********************************************
368  **********************************************
369  **********************************************
370 
371  implementation: sDevice
372 
373  **********************************************
374  **********************************************
375  **********************************************
376  */
377 
378 
379 ////////////////////////////////////////////////
380 // construction and destruction
381 
382 //sDevice()
384  // constructor
385 
386  FD_DHV("sDevice(" << mName << ")::sDevice()");
387  // have event set with appropriate attributes
390  // have appropriate default label for token io
391  mDefaultLabel ="SignalDevice";
392  // my signal data
393  mMaxBitAddress=-1;
394  mpInputEdges=0;
396  mpOutputLevels=0;
397  // background thread:
398  // install mutex
399  faudes_mutex_init(&mMutex);
400  // configuration defaults
401  mName="SignalDevice";
402  mCycleTime=1000; // 1ms
403  mTimeScale=500; // 500ms is one faudes time unit
404  mSyncWrite=false;
405 }
406 
407 
408 //~sDevice()
410  // destructor
411  FD_DHV("sDevice(" << mName << ")::~sDevice()");
412  // cancel background thread: stop
413  Stop();
414  // free mem
415  faudes_mutex_destroy(&mMutex);
416  // free mem
417  if(mpInputEdges) delete mpInputEdges;
419  if(mpOutputLevels) delete mpOutputLevels;
420 }
421 
422 
423 //DoWritePreface(rTw,rLabel,pContext)
424 void sDevice::DoWritePreface(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
425 
426  FD_DHV("sDevice("<<mName<<")::DoWritePreface()");
427  //call base
428  vDevice::DoWritePreface(rTw,rLabel,pContext);
429  //write cycle-time of background task
430  Token ttag;
431  ttag.SetEmpty("SampleInterval");
432  ttag.InsAttributeInteger("value",mCycleTime);
433  rTw<<ttag;
434  // write sync option
435  if(mSyncWrite) {
436  Token stag;
437  stag.SetEmpty("SynchronousWrite");
438  stag.InsAttributeString("value","true");
439  rTw<<stag;
440  }
441 }
442 
443 //DoReadPreface(rTr,rLabel,pContext)
444 void sDevice::DoReadPreface(TokenReader& rTr,const std::string& rLabel, const Type* pContext){
445 
446  FD_DHV("sDevice("<<mName<<")::DoReadPreface()");
447  // call base
448  vDevice::DoReadPreface(rTr,rLabel,pContext);
449 
450  // sense and digest pre 2.16 format
451  Token token;
452  rTr.Peek(token);
453  if(token.IsInteger()) {
454  mMaxBitAddress = rTr.ReadInteger();
455  mCycleTime = rTr.ReadInteger();
456  Token token;
457  rTr.Peek(token);
458  if(token.IsOption())
459  if(token.OptionValue()=="SyncWrite") {
460  rTr.Get(token);
461  mSyncWrite=true;
462  }
463  return;
464  }
465 
466  // loop my members
467  while(true) {
468  Token token;
469  rTr.Peek(token);
470  // cycle time
471  if(token.IsBegin())
472  if(token.StringValue()=="SampleInterval") {
473  rTr.ReadBegin("SampleInterval", token);
474  mCycleTime=token.AttributeIntegerValue("value");
475  rTr.ReadEnd("SampleInterval");
476  continue;
477  }
478  // sync write
479  if(token.IsBegin())
480  if(token.StringValue()=="SynchronousWrite") {
481  rTr.ReadBegin("SynchronousWrite");
482  rTr.ReadEnd("SynchronousWrite");
483  mSyncWrite=true;
484  if(token.ExistsAttributeString("value"))
485  if(token.AttributeStringValue("value")!="true")
486  mSyncWrite=false;
487  continue;
488  }
489  // break on unknown
490  break;
491  }
492 
493  // done
494 }
495 
496 
497 // lock - unlock shortcuts;
498 #define LOCK_E {int rc = faudes_mutex_lock(&mMutex); \
499  if(rc) {FD_ERR("sDevice("<<mName<<")::LOCK_E: lock mutex error\n"); exit(1); }}
500 #define UNLOCK_E {int rc = faudes_mutex_unlock(&mMutex); \
501  if(rc) {FD_ERR("sDevice("<<mName<<")::LOCK_E: unlock mutex error\n"); exit(1); }}
502 
503 
504 #define TLOCK_E {int rc = faudes_mutex_lock(&sdevice->mMutex); \
505  if(rc) {FD_ERR("sDevice::TLOCK_E: lock mutex error\n"); exit(1); }}
506 
507 #define TUNLOCK_E {int rc = faudes_mutex_unlock(&sdevice->mMutex); \
508  if(rc) {FD_ERR("sDevice::TLOCK_E: unlock mutex error\n"); exit(1); }}
509 
510 
511 
512 
513 
514 // Start(void)
515 void sDevice::Start(void) {
516  // bail out if device was allready started
517  if( (mState == Up) || (mState == StartUp) ) return;
518  FD_DHV("sDevice("<<mName<<")::Start()");
519  // call base incl virtual reset, state=up
520  vDevice::Start();
521  // create background for edge detection and sync write
522  if(!Inputs().Empty() || mSyncWrite){
523  mState=StartUp;
524  mCancelRequest = false;
525  // create and run thread
526  int rc = faudes_thread_create(&mThreadSynchro, SDeviceSynchro, this);
527  if(rc) {
528  FD_ERR("sDevice("<<mName<<")::Start(): cannot creat thread\n");
529  exit(1);
530  }
531  }
532 }
533 
534 // Stop()
535 void sDevice::Stop(void) {
536  // stop implies reset
537  Reset();
538  // bail out if device allready got the command to shut down
539  if(mState != Up && mState !=StartUp) return;
540  FD_DH("sDevice("<<mName<<")::Stop()");
541  // dont kill thread if no thread was created
542  if(!Inputs().Empty() || mSyncWrite) {
543  // cancle thread
544  LOCK_E;
545  FD_DHV("sDevice("<<mName<<")::Stop(): Lock passed, waiting to join thread");
546  mCancelRequest=true;
547  UNLOCK_E;
548  int pc = faudes_thread_join(mThreadSynchro,NULL);
549  if(pc) {
550  FD_ERR("sDevice("<<mName<<")::Stop(): cannot join thread??\n");
551  }
552  }
553  // indicate success
554  FD_DHV("sDevice("<<mName<<")::Stop(): done");
555  mState=Down;
556 }
557 
558 
559 //Reset()
561  // delete dynamic data
562  FD_DHV("sDevice("<<mName<<")::Reset()");
563  // call base (resets time)
564  vDevice::Reset();
565  //delete dynamic data
566  FD_DHV("sDevice("<<mName<<")::Reset(): reset signals");
567  ClrInputSignals();
569  // done
570  FD_DHV("sDevice("<<mName<<")::Reset(): done");
571 }
572 
573 // Clear()
574 void sDevice::Clear(void) {
575  //delete static data
576  FD_DHV("sDevice(" << mName << ")::Clear()");
577  // call base; note: clear implies stop
578  vDevice::Clear();
579  // clear compiled data
580  mInputPosEdgeIndexMap.clear();
581  mInputNegEdgeIndexMap.clear();
582  mMaxBitAddress=-1;
583  mSyncWrite=false;
584  mCycleTime=1000; // usec
585 }
586 
587 //Compile(void)
588 void sDevice::Compile(void){
589  //setup up internal data structure
590  FD_DHV("sDevice(" << mName << ")::Compile()");
591  // call base
593  // clear my internal data
594  mInputPosEdgeIndexMap.clear();
595  mInputNegEdgeIndexMap.clear();
596  mOutputLevelIndexMap.clear();
597  mMaxBitAddress=-1;
598  // setup my internal data
599  for(EventSet::Iterator eit=pConfiguration->Begin(); eit!=pConfiguration->End(); eit++) {
601  if(attr.IsInput()) {
602  // fill in reverse maps
603  std::vector<AttributeSignalInput::Trigger>::const_iterator ait;
604  const AttributeSignalInput* sattr = attr.Inputp();
605  for(ait=sattr->mTriggers.begin(); ait!=sattr->mTriggers.end(); ait++) {
606  if(ait->mPos) mInputPosEdgeIndexMap[ait->mBit].Insert(*eit);
607  if(ait->mNeg) mInputNegEdgeIndexMap[ait->mBit].Insert(*eit);
608  if(ait->mBit > mMaxBitAddress) mMaxBitAddress=ait->mBit;
609  }
610  }
611  // check max address, set inverse map
612  if(attr.IsOutput()) {
613  std::vector<AttributeSignalOutput::Action>::const_iterator ait;
614  const AttributeSignalOutput* aattr = attr.Outputp();
615  for(ait=aattr->mActions.begin(); ait!=aattr->mActions.end(); ait++) {
616  if(ait->mBit > mMaxBitAddress) mMaxBitAddress=ait->mBit;
617  mOutputLevelIndexMap[ait->mBit].Insert(*eit);
618  if(ait->mValue == AttributeSignalOutput::Inv && !mSyncWrite) {
619  throw Exception("sDevice::Compile(): ",
620  "Inv-Action is only supported with SyncWrite", 52);
621  }
622  }
623  }
624  }
625  // prep state data
626  if(mpInputEdges) delete mpInputEdges;
628  if(mpOutputLevels) delete mpOutputLevels;
632  // report
633 #ifdef FAUDES_DEBUG_IODEVICE
634  for(int i=0; i<=mMaxBitAddress; i++) {
635  if(mOutputLevelIndexMap[i].Empty()) continue;
636  FD_DH("sDevice(" << mName << ")::Compile(): output signal at address " << i);
637  }
638 #endif
639 }
640 
641 
642 // programmatic config: insert input event
643 void sDevice::InsInputEvent(const std::string& event) {
644  if(mState!=Down) return;
646  inp.DefaultInput();
647  Idx ev=pConfiguration->Insert(event);
648  pConfiguration->Attribute(ev, inp);
649 }
650 
651 
652 // programmatic config: add trigger
653 void sDevice::AppendTrigger(const std::string& event, const Trigger& trigger) {
654  if(mState!=Down) return;
655  if(!pConfiguration->Exists(event)) return;
656  Idx ev=pConfiguration->Index(event);
658  if(!attr->IsInput()) return;
659  AttributeSignalInput* iattr = attr->Inputp();
660  iattr->mTriggers.push_back(trigger);
661 }
662 
663 // programmatic config: insert output event
664 void sDevice::InsOutputEvent(const std::string& event) {
665  if(mState!=Down) return;
667  outp.DefaultOutput();
668  Idx ev=pConfiguration->Insert(event);
669  pConfiguration->Attribute(ev, outp);
670 }
671 
672 
673 // programmatic config: add action
674 void sDevice::AppendAction(const std::string& event, const Action& action) {
675  if(mState!=Down) return;
676  if(!pConfiguration->Exists(event)) return;
677  if(!pConfiguration->Exists(event)) return;
678  Idx ev=pConfiguration->Index(event);
680  if(!attr->IsOutput()) return;
681  AttributeSignalOutput* oattr = attr->Outputp();
682  oattr->mActions.push_back(action);
683 }
684 
685 
686 //CycleTime(void)
687 int sDevice::CycleTime(void) const {
688  //Report current cycle time
689  FD_DHV("sDevice(" << mName << ")::CycleTime()");
690  return mCycleTime;
691 }
692 
693 //CycleTime(int)
694 void sDevice::CycleTime(int cycleTime) {
695  //Set cycle time
696  FD_DHV("sDevice(" << mName << ")::CycleTime(int)");
697  if( mState==Up || mState==StartUp){
698  std::stringstream errstr;
699  errstr << "Changing cycle-time not possible while background thread is still running ";
700  throw Exception("sDevice::CycleTime: ", errstr.str(), 100);
701  }
702  mCycleTime = cycleTime;
703 }
704 
705 
706 //ReadSignal(int)
707 bool sDevice::ReadSignal(int bit){
708  FD_DHV("sDevice(" << mName << ")::ReadSignal(int)");
709  // make sure device is able to read signals
710  if(Inputs().Empty()){
711  std::stringstream errstr;
712  errstr << "(" << mName << ") is not able to read signals";
713  throw Exception("sDevice::ReadSignal():", errstr.str(), 552);
714  }
715  //return if device is running
716  if(mState!=Up && mState!=StartUp) {
717  std::stringstream errstr;
718  errstr << "Signal access not possible while background thread is not running ";
719  throw Exception("sDevice::ReadSignal: ", errstr.str(), 552);
720  }
721  // lock global image, prevent background thread from reading/writing
722  LOCK_E;
723  // run with hooks
724  bool res=false;
725  if(DoReadSignalsPre()) {
726  res=DoReadSignal(bit);
728  }
729  // free global image
730  UNLOCK_E;
731  return res;
732 }
733 
734 //WriteSignal(int,int)
735 void sDevice::WriteSignal(int bit, bool value){
736  // write one actor value, adressed by bit number (0 to 63);
737  FD_DHV("sDevice(" << mName << ")::WriteSignal(int)");
738  // make sure device supports outputs
739  if(Outputs().Empty()){
740  std::stringstream errstr;
741  errstr << "(" << mName << ") is not configured for outputs";
742  throw Exception("sDevice::WriteSignal():", errstr.str(), 552);
743  }
744  // bail out if device is running
745  if(mState!=Up && mState!=StartUp) {
746  std::stringstream errstr;
747  errstr << "Signal access not possible while background thread is not running ";
748  throw Exception("sDevice::ReadSignal: ", errstr.str(), 552);
749  }
750  // lock global image, prevent background thread from reading/writing
751  LOCK_E;
752  // case a) asynchronous write
753  if(!mSyncWrite) {
754  if(DoWriteSignalsPre()) {
755  DoWriteSignal(bit,value);
757  }
758  }
759  // case b) synchronous write
760  if(mSyncWrite) {
761  // record next value
762  Levels* level= &mpOutputLevels[bit];
763  level->next=value;
764  if(level->edge) level->lost=true;
765  level->edge=true;
766  }
767  // free global image
768  UNLOCK_E;
769 }
770 
771 
772 //SDeviceSynchro(void*)
773 void* SDeviceSynchro(void* arg){
774 
775  //background-thread main-routine
776 
777  // cast this object
778  sDevice* sdevice = static_cast<sDevice*>(arg);
779 
780  FD_DH("sDevice(" << sdevice->mName << ")::Synchro(" << sdevice << "): with ct " << sdevice->mCycleTime);
781 
782 #ifdef FAUDES_DEBUG_IOTIMING_X
783  /////////////////////////////////////////////////////
784  // cyletime analysis
785  // timeA: time consumed for an entire cycle
786  // timeB: time consumed for edge detection and i/o
787  // timeC: time left for usleep
788  //
789  // provide arrays for samples
790  faudes_systime_t* timeA = new faudes_systime_t[MAX_SAMPLES];
791  faudes_systime_t* timeB = new faudes_systime_t[MAX_SAMPLES];
792  faudes_systime_t* timeC = new faudes_systime_t[MAX_SAMPLES];
793  // provide pointer to current sample
794  int itime=0;
795  // take a sample
796  faudes_gettimeofday(timeA+itime);
797 #endif
798 
799  bool running=true;
800 
801  while(running){
802 
803  // loop timer
804  faudes_systime_t timeL1;
805  faudes_gettimeofday(&timeL1);
806 
807  // lock global variables
808  TLOCK_E;
809 
810  // call hook
811  sdevice->DoLoopCallback();
812 
813  // start up: initialize dynamic state
814  if(sdevice->mState==sDevice::StartUp) {
815  // reset outputs (clear image)
816  bool aready= sdevice->DoWriteSignalsPre();
817  if(aready) {
818  // output image: set to zero
819  FD_DHV("sDevice("<<sdevice->Name()<<")::synchro: reset: clear lines");
820  for(int bit=0; bit<=sdevice->mMaxBitAddress; bit++) {
821  sDevice::Levels* level= &sdevice->mpOutputLevels[bit];
822  level->current=false;
823  level->next=false;
824  level->edge=false;
825  level->lost=false;
826  level->rel = (!sdevice->mOutputLevelIndexMap[bit].Empty());
827  if(level->rel) sdevice->DoWriteSignal(bit,false);
828  }
829  sdevice->DoWriteSignalsPost();
830  }
831  // reset inputs (edge detecteion)
832  bool sready= sdevice->DoReadSignalsPre();
833  if(sready) {
834  // edge detection: use actual signal levels
835  FD_DHV("sDevice("<<sdevice->Name()<<")::synchro: reset: edge detection");
836  for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) {
837  sDevice::Edges* edge= &sdevice->mpInputEdges[bit];
838  edge->current=sdevice->DoReadSignal(bit);
839  edge->past = edge->current;
840  edge->pos = false;
841  edge->neg = false;
842  edge->posrel = (!sdevice->mInputPosEdgeIndexMap[bit].Empty());
843  edge->negrel = (!sdevice->mInputNegEdgeIndexMap[bit].Empty());
844  edge->lost = false;
845  }
846  sdevice->DoReadSignalsPost();
847  for(int bit = 0;bit<=sdevice->mMaxBitAddress;bit++) {
848  sDevice::Edges* redge= &sdevice->mpRecentInputEdges[bit];
849  redge->pos = false;
850  redge->neg = false;
851  redge->posrel = false;
852  redge->negrel = false;
853  redge->lost = false;
854  }
855  }
856  // new state
857  if(sready && aready)
858  sdevice->mState=sDevice::Up;
859  }
860 
861  // normal operation, inputs
862  if(sdevice->mState==sDevice::Up) {
863  bool ready=sdevice->DoReadSignalsPre();
864  if(!ready)
865  sdevice->mState=sDevice::StartUp;
866  if(ready) {
867  // edge detection, accumulative
868  for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) {
869  // define pointer to Inputedges
870  sDevice::Edges* edge= &sdevice->mpInputEdges[bit];
871  // pass edge-info about edge in last cycle
872  edge->past = edge->current;
873  // and get corresponding input-value
874  edge->current = sdevice->DoReadSignal(bit);
875  if(edge->posrel)
876  if(edge->current && (!edge->past) ) {
877  FD_DHV("sDevice::synchro: sensed positive edge at bit address " << bit);
878  edge->pos = true;
879  // queue events to buffer
880  faudes_mutex_lock(sdevice->pBufferMutex);
881  EventSet::Iterator eit=sdevice->mInputPosEdgeIndexMap[bit].Begin();
882  EventSet::Iterator eit_end=sdevice->mInputPosEdgeIndexMap[bit].End();
883  for(; eit!=eit_end; eit++) {
884  sdevice->pInputBuffer->push_back(*eit);
885  }
886  faudes_mutex_unlock(sdevice->pBufferMutex);
887  //send signal to function "WaitSenosrs()"
888  FD_DHV("sDevice::synchro: send signal " );
889  faudes_cond_broadcast(sdevice->pWaitCondition);
890  }
891  if(edge->negrel)
892  if( (!edge->current) && edge->past ) {
893  FD_DHV("sDevice::synchro: sensed negative edge at bit address " << bit);
894  edge->neg = true;
895  sdevice->mInputReady = true;
896  // queue events to buffer
897  faudes_mutex_lock(sdevice->pBufferMutex);
898  EventSet::Iterator eit=sdevice->mInputNegEdgeIndexMap[bit].Begin();
899  EventSet::Iterator eit_end=sdevice->mInputNegEdgeIndexMap[bit].End();
900  for(; eit!=eit_end; eit++) {
901  sdevice->pInputBuffer->push_back(*eit);
902  }
903  faudes_mutex_unlock(sdevice->pBufferMutex);
904  //send signal to function "WaitSenosrs"
905  FD_DHV("sDevice::synchro: send signal " );
906  faudes_cond_broadcast(sdevice->pWaitCondition);
907  }
908  } // loop bits
909  sdevice->DoReadSignalsPost();
910  } // end-if device ok
911  } // end-if inputs
912 
913 
914  // normal operation, outputs
915  if(sdevice->mState==sDevice::Up && sdevice->mSyncWrite) {
916  bool ready=sdevice->DoWriteSignalsPre();
917  if(!ready)
918  sdevice->mState=sDevice::StartUp;
919  if(ready) {
920  // write values from image
921  for(int bit = 0; bit<=sdevice->mMaxBitAddress; bit++) {
922  // define pointer to levels
923  sDevice::Levels* level= &sdevice->mpOutputLevels[bit];
924  // not written by libfaudes
925  if(!level->edge) continue;
926  // write and record
927  sdevice->DoWriteSignal(bit,level->next);
928  level->current = level->next;
929  level->edge = false;
930  level->lost = false;
931  }
932  sdevice->DoWriteSignalsPost();
933  }
934  }
935 
936  // check for cancel request
937  if(sdevice->mCancelRequest) {
938  running=false;
939  sdevice->mState=vDevice::ShutDown;
940  }
941  // unlock global variables
942  TUNLOCK_E;
943 
944 #ifdef FAUDES_DEBUG_IOTIMING_X
945  //////////////////////////////////////
946  //cycletime analysis: take a sample
947  if(itime < MAX_SAMPLES) faudes_gettimeofday(timeB+itime);
948 #endif
949 
950  // let time pass
951  faudes_systime_t timeL2;
952  faudes_gettimeofday(&timeL2);
953  long int delta = (timeL2.tv_nsec - timeL1.tv_nsec)/1000;
954  delta+= 1000000 * (timeL2.tv_sec - timeL1.tv_sec);
955  if(delta < sdevice->mCycleTime) faudes_usleep(sdevice->mCycleTime-delta);
956  else {
957  if(sdevice->mState==sDevice::Up) FD_DH("sDevice::synchro: missed cycle time by " << delta - sdevice->mCycleTime << " usec");
958  }
959 
960 
961 #ifdef FAUDES_DEBUG_IOTIMING_X
962  //////////////////////////////////////
963  // cycletime analysis
964 
965  // take a sample
966  if(itime < MAX_SAMPLES) faudes_gettimeofday(timeC+itime);
967  // increment pointer
968  itime++;
969  if(itime < MAX_SAMPLES) faudes_gettimeofday(timeA+itime);
970 
971 #endif
972  // count cycles
973  sdevice->mCycleCount++;
974  } // loop while running
975 
976 
977 #ifdef FAUDES_DEBUG_IOTIMING_X
978 
979  /////////////////////////////////////////////
980  // cycletime analysis
981  // set up statsitics
982  FD_DHT("sDevice::synchro: performance analysis");
983 
984  SampledDensityFunction SamplesA;
985  SamplesA.Clear();
986  SamplesA.Dim(100);
987  SamplesA.Name("time stamp AA: overall period");
988 
989  SampledDensityFunction SamplesB;
990  SamplesB.Clear();
991  SamplesB.Dim(100);
992  SamplesB.Name("time stamp AB: process time");
993 
994  SampledDensityFunction SamplesC;
995  SamplesC.Clear();
996  SamplesC.Dim(100);
997  SamplesC.Name("time stamp CB: sleep time");
998 
999  SampledDensityFunction SamplesWS;
1000  SamplesWS.Clear();
1001  SamplesWS.Dim(100);
1002  SamplesWS.Name("time passed till the next call of WaitInputs");
1003 
1004  // timeval-structures needed for further computations
1005  faudes_systime_t dAA,dBA,dCB,dER;
1006 
1007  // perform analysis
1008  // time for a hole cycle
1009  for(int ind = 0; ind < itime-2; ind++){
1010  // compute time needed
1011  // for a hole cycle
1012  faudes_diffsystime(timeA[ind+1],timeA[ind],&dAA);
1013  // for computing input-state
1014  faudes_diffsystime(timeB[ind],timeA[ind],&dBA);
1015  // by usleep(mCyleTime)
1016  faudes_diffsystime(timeC[ind],timeB[ind],&dCB);
1017  // time passed by until the next call of WaitInputs
1018  faudes_diffsystime(sdevice->mptimeBegin[ind+1],sdevice->mptimeEnd[ind],&dER);
1019  // insert samples to density functions
1020  SamplesA.Sample(dAA.tv_sec*1000000 + dAA.tv_nsec/1000);
1021  SamplesB.Sample(dBA.tv_sec*1000000 + dBA.tv_nsec/1000);
1022  SamplesC.Sample(dCB.tv_sec*1000000 + dCB.tv_nsec/1000);
1023  SamplesWS.Sample(1000000*dER.tv_sec + dER.tv_nsec/1000);
1024  }
1025 
1026  // perform statistic computation
1027  SamplesA.Compile();
1028  SamplesB.Compile();
1029  SamplesC.Compile();
1030  SamplesWS.Compile();
1031 
1032  // token output
1033  // SamplesA.Write();
1034  // SamplesB.Write();
1035  // SamplesC.Write();
1036  // SamplesWS.Write();
1037 
1038  // pretty print output
1039  std::cout << SamplesA.Str() << std::endl;
1040  std::cout << SamplesB.Str() << std::endl;
1041  std::cout << SamplesC.Str() << std::endl;
1042  std::cout << SamplesWS.Str() << std::endl;
1043 #endif
1044 
1045  FD_DH("sDevice(" << sdevice->mName << ")::synchro: terminate background thread");
1046  faudes_thread_exit(NULL);
1047  // never happens, prevent gcc warning
1048  return NULL;
1049 }
1050 
1051 // Write Output(Idx)
1053 
1054  FD_DHV("sDevice("<<mName<<")::WriteOutput(" << output <<")");
1055  //return if device is running
1056  if(mState!=Up && mState!=StartUp) return;
1057  //make sure event is part of devices eventset
1058  if(!mOutputs.Exists(output)) {
1059  std::stringstream errstr;
1060  errstr << "Unknown output event " << output;
1061  throw Exception("sDevice::WriteOutput", errstr.str(), 65);
1062  }
1063  // find properties
1064  const AttributeSignalOutput* aattr = pConfiguration->Attribute(output).Outputp();
1065  if(!aattr) {
1066  std::stringstream errstr;
1067  errstr << "Invalid output attribute " << output;
1068  throw Exception("sDevice::WriteOutput", errstr.str(), 65);
1069  }
1070  //debug-flag
1071  FD_DHV("sDevice("<<mName<<")::WriteOutput: properties found");
1072  // execute command ...
1073  std::vector<AttributeSignalOutput::Action>::const_iterator eit;
1074  // ... case a) asynchronous write (does not supper invert)
1075  if(!mSyncWrite) {
1076  // prepare
1077  if(DoWriteSignalsPre()) {
1078  // loop actions
1079  for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){
1080  FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue);
1081  DoWriteSignal(eit->mBit,eit->mValue == AttributeSignalOutput::Set);
1082  }
1084  }
1085  }
1086  // ... case b) synchronous write (does support invert)
1087  if(mSyncWrite) {
1088  // lock global image
1089  LOCK_E;
1090  // loop actions and record
1091  for(eit=aattr->mActions.begin(); eit!=aattr->mActions.end(); eit++){
1092  FD_DHV("sDevice("<<mName<<")::WriteOutput: mBit "<<eit->mBit<< " mValue "<<eit->mValue);
1093  Levels* level= &mpOutputLevels[eit->mBit];
1094  switch(eit->mValue) {
1096  level->next=1; break;
1098  level->next=0; break;
1100  level->next= ~level->next; break;
1101  }
1102  if(level->edge) level->lost=true;
1103  level->edge=true;
1104  }
1105  // free global image
1106  UNLOCK_E;
1107  }
1108  // done
1109  FD_DHV("sDevice("<<mName<<")::WriteOutput: done");
1110 }
1111 
1112 //ClrInputSignals()
1114  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): MaxBitAddress: " << mMaxBitAddress);
1115  //return if device is not running or device is not able to read inputs
1116  if( mState!=Up || Inputs().Empty()) return;
1117  // lock global variables
1118  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): lock mutex ");
1119  LOCK_E;
1120  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detection ");
1121  // initialise edge detection: assume low signals
1122  for(int bit = 0;bit<=mMaxBitAddress;bit++) {
1123  Edges* edge= &mpInputEdges[bit];
1124  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit);
1125  edge->current=0;
1126  edge->past = 0;
1127  edge->pos = false;
1128  edge->neg = false;
1129  edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty());
1130  edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty());
1131  edge->lost = false;
1132  }
1133  // initialise edge detection: actual signal levels
1134  if(DoReadSignalsPre()) {
1135  for(int bit = 0;bit<=mMaxBitAddress;bit++) {
1136  Edges* edge= &mpInputEdges[bit];
1137  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): edge detetion ReadSignal bit " << bit);
1138  edge->current=DoReadSignal(bit);
1139  edge->past = edge->current;
1140  edge->pos = false;
1141  edge->neg = false;
1142  edge->posrel = (!mInputPosEdgeIndexMap[bit].Empty());
1143  edge->negrel = (!mInputNegEdgeIndexMap[bit].Empty());
1144  edge->lost = false;
1145  }
1147  }
1148  // initialize edge detection: recent edges
1149  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): initialize recent edges ");
1150  for(int bit = 0;bit<=mMaxBitAddress;bit++) {
1151  Edges* redge= &mpRecentInputEdges[bit];
1152  redge->pos = false;
1153  redge->neg = false;
1154  redge->posrel = false;
1155  redge->negrel = false;
1156  redge->lost = false;
1157  }
1158  // reset cyclecount
1159  mCycleCount=0;
1161  mInputReady=false;
1162  // unlock global variables
1163  UNLOCK_E;
1164  FD_DHV("sDevice("<<mName<<")::ClrInputSignals(): done");
1165 }
1166 
1167 //ClrOutputSignals()
1169  //clear all output line levels
1170  FD_DHV("sDevice("<<mName<<")::ClrOutputSignals");
1171  // return if device is not running or not abel to set output signals
1172  if(mState!=Up || Outputs().Empty()) return;
1173  // lock variables, prevent background from writing
1174  LOCK_E;
1175  FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: passed lock");
1176  // clear all (allways asynchronous)
1177  if(DoWriteSignalsPre()) {
1178  for(int bit=0; bit<=mMaxBitAddress; bit++)
1179  if(mpOutputLevels[bit].rel) DoWriteSignal(bit, false);
1181  }
1182  // clear image
1183  for(int bit=0; bit<=mMaxBitAddress; bit++) {
1184  Levels* level= &mpOutputLevels[bit];
1185  level->current=false;
1186  level->next=false;
1187  level->edge=false;
1188  level->lost=false;
1189  }
1190  // done
1191  UNLOCK_E;
1192  FD_DHV("sDevice("<<mName<<")::ClrOutputSignals: done");
1193 }
1194 
1195 }//end namespace faudes
1196 
1197 

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen