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

libFAUDES 2.33k --- 2025.09.16 --- c++ api documentaion by doxygen