]> git.mxchange.org Git - simgear.git/blob - simgear/hla/HLAFederate.cxx
hla: lift the event loop logic from RTI to HLAFederate.
[simgear.git] / simgear / hla / HLAFederate.cxx
1 // Copyright (C) 2009 - 2011  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #include "HLAFederate.hxx"
19
20 #include "RTI13Federate.hxx"
21 #include "RTIFederate.hxx"
22 #include "RTIInteractionClass.hxx"
23 #include "RTIObjectClass.hxx"
24 #include "HLADataElement.hxx"
25 #include "HLADataType.hxx"
26 #include "HLAOMTXmlVisitor.hxx"
27
28 namespace simgear {
29
30 HLAFederate::HLAFederate() :
31     _version(RTI13)
32 {
33 }
34
35 HLAFederate::~HLAFederate()
36 {
37 }
38
39 HLAFederate::Version
40 HLAFederate::getVersion() const
41 {
42     return _version;
43 }
44
45 bool
46 HLAFederate::setVersion(HLAFederate::Version version)
47 {
48     if (_rtiFederate.valid()) {
49         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
50         return false;
51     }
52     _version = version;
53     return true;
54 }
55
56 const std::list<std::string>&
57 HLAFederate::getConnectArguments() const
58 {
59     return _connectArguments;
60 }
61
62 bool
63 HLAFederate::setConnectArguments(const std::list<std::string>& connectArguments)
64 {
65     if (_rtiFederate.valid()) {
66         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
67         return false;
68     }
69     _connectArguments = connectArguments;
70     return true;
71 }
72
73 const std::string&
74 HLAFederate::getFederationExecutionName() const
75 {
76     return _federationExecutionName;
77 }
78
79 bool
80 HLAFederate::setFederationExecutionName(const std::string& federationExecutionName)
81 {
82     if (_rtiFederate.valid()) {
83         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
84         return false;
85     }
86     _federationExecutionName = federationExecutionName;
87     return true;
88 }
89
90 const std::string&
91 HLAFederate::getFederationObjectModel() const
92 {
93     return _federationObjectModel;
94 }
95
96 bool
97 HLAFederate::setFederationObjectModel(const std::string& federationObjectModel)
98 {
99     if (_rtiFederate.valid()) {
100         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
101         return false;
102     }
103     _federationObjectModel = federationObjectModel;
104     return true;
105 }
106
107 const std::string&
108 HLAFederate::getFederateType() const
109 {
110     return _federateType;
111 }
112
113 bool
114 HLAFederate::setFederateType(const std::string& federateType)
115 {
116     if (_rtiFederate.valid()) {
117         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
118         return false;
119     }
120     _federateType = federateType;
121     return true;
122 }
123
124 const std::string&
125 HLAFederate::getFederateName() const
126 {
127     return _federateName;
128 }
129
130 bool
131 HLAFederate::setFederateName(const std::string& federateName)
132 {
133     if (_rtiFederate.valid()) {
134         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
135         return false;
136     }
137     _federateName = federateName;
138     return true;
139 }
140
141 bool
142 HLAFederate::connect(Version version, const std::list<std::string>& stringList)
143 {
144     if (_rtiFederate.valid()) {
145         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
146         return false;
147     }
148     switch (version) {
149     case RTI13:
150         _rtiFederate = new RTI13Federate(stringList);
151         _version = version;
152         _connectArguments = stringList;
153         break;
154     case RTI1516:
155         SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516 not yet(!?) supported.");
156         // _rtiFederate = new RTI1516Federate(stringList);
157         break;
158     case RTI1516E:
159         SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
160         // _rtiFederate = new RTI1516eFederate(stringList);
161         break;
162     default:
163         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
164     }
165     return _rtiFederate.valid();
166 }
167
168 bool
169 HLAFederate::connect()
170 {
171     if (_rtiFederate.valid()) {
172         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
173         return false;
174     }
175     switch (_version) {
176     case RTI13:
177         _rtiFederate = new RTI13Federate(_connectArguments);
178         break;
179     case RTI1516:
180         SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516 not yet(!?) supported.");
181         // _rtiFederate = new RTI1516Federate(_connectArguments);
182         break;
183     case RTI1516E:
184         SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
185         // _rtiFederate = new RTI1516eFederate(_connectArguments);
186         break;
187     default:
188         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
189     }
190     return _rtiFederate.valid();
191 }
192
193 bool
194 HLAFederate::disconnect()
195 {
196     if (!_rtiFederate.valid()) {
197         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
198         return false;
199     }
200     _rtiFederate = 0;
201     return true;
202 }
203
204 bool
205 HLAFederate::createFederationExecution(const std::string& federation, const std::string& objectModel)
206 {
207     if (!_rtiFederate.valid()) {
208         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
209         return false;
210     }
211
212     RTIFederate::FederationManagementResult createResult;
213     createResult = _rtiFederate->createFederationExecution(federation, objectModel);
214     if (createResult == RTIFederate::FederationManagementFatal)
215         return false;
216
217     _federationExecutionName = federation;
218     _federationObjectModel = objectModel;
219     return true;
220 }
221
222 bool
223 HLAFederate::destroyFederationExecution(const std::string& federation)
224 {
225     if (!_rtiFederate.valid()) {
226         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
227         return false;
228     }
229
230     RTIFederate::FederationManagementResult destroyResult;
231     destroyResult = _rtiFederate->destroyFederationExecution(federation);
232     if (destroyResult == RTIFederate::FederationManagementFatal)
233         return false;
234
235     return true;
236 }
237
238 bool
239 HLAFederate::createFederationExecution()
240 {
241     if (!_rtiFederate.valid()) {
242         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
243         return false;
244     }
245
246     RTIFederate::FederationManagementResult createResult;
247     createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
248     if (createResult != RTIFederate::FederationManagementSuccess)
249         return false;
250
251     return true;
252 }
253
254 bool
255 HLAFederate::destroyFederationExecution()
256 {
257     if (!_rtiFederate.valid()) {
258         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
259         return false;
260     }
261
262     RTIFederate::FederationManagementResult destroyResult;
263     destroyResult = _rtiFederate->destroyFederationExecution(_federationExecutionName);
264     if (destroyResult != RTIFederate::FederationManagementSuccess)
265         return false;
266
267     return true;
268 }
269
270 bool
271 HLAFederate::join(const std::string& federateType, const std::string& federation)
272 {
273     if (!_rtiFederate.valid()) {
274         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
275         return false;
276     }
277
278     RTIFederate::FederationManagementResult joinResult;
279     joinResult = _rtiFederate->join(federateType, federation);
280     if (joinResult == RTIFederate::FederationManagementFatal)
281         return false;
282
283     return true;
284 }
285
286 bool
287 HLAFederate::join()
288 {
289     if (!_rtiFederate.valid()) {
290         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
291         return false;
292     }
293
294     RTIFederate::FederationManagementResult joinResult;
295     joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
296     if (joinResult != RTIFederate::FederationManagementSuccess)
297         return false;
298
299     return true;
300 }
301
302 bool
303 HLAFederate::resign()
304 {
305     if (!_rtiFederate.valid()) {
306         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
307         return false;
308     }
309     return _rtiFederate->resign();
310 }
311
312 bool
313 HLAFederate::createJoinFederationExecution()
314 {
315     if (!_rtiFederate.valid()) {
316         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
317         return false;
318     }
319
320     for (;;) {
321         // Try to join.
322         RTIFederate::FederationManagementResult joinResult;
323         joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
324         switch (joinResult) {
325         case RTIFederate::FederationManagementSuccess:
326             // Fast return on success
327             return true;
328         case RTIFederate::FederationManagementFatal:
329             // Abort on fatal errors
330             return false;
331         default:
332             break;
333         };
334
335         // If not already joinable, try to create the requested federation
336         RTIFederate::FederationManagementResult createResult;
337         createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
338         switch (createResult) {
339         case RTIFederate::FederationManagementFatal:
340             // Abort on fatal errors
341             return false;
342         default:
343             // Try again to join
344             break;
345         }
346     }
347 }
348
349 bool
350 HLAFederate::resignDestroyFederationExecution()
351 {
352     if (!_rtiFederate.valid()) {
353         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
354         return false;
355     }
356     
357     // Resign ourselves
358     bool success = _rtiFederate->resign();
359
360     // and try to destroy, non fatal if still some federates joined
361     if (_rtiFederate->destroyFederationExecution(_federationExecutionName) == RTIFederate::FederationManagementFatal)
362         success = false;
363
364     return success;
365 }
366
367 bool
368 HLAFederate::enableTimeConstrained()
369 {
370     if (!_rtiFederate.valid()) {
371         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
372         return false;
373     }
374
375     if (!_rtiFederate->enableTimeConstrained()) {
376         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time constrained!");
377         return false;
378     }
379
380     while (!_rtiFederate->getTimeConstrainedEnabled()) {
381         _rtiFederate->processMessage();
382     }
383
384     return true;
385 }
386
387 bool
388 HLAFederate::disableTimeConstrained()
389 {
390     if (!_rtiFederate.valid()) {
391         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
392         return false;
393     }
394     return _rtiFederate->disableTimeConstrained();
395 }
396
397 bool
398 HLAFederate::enableTimeRegulation(const SGTimeStamp& lookahead)
399 {
400     if (!_rtiFederate.valid()) {
401         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
402         return false;
403     }
404
405     if (!_rtiFederate->enableTimeRegulation(lookahead)) {
406         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time regulation!");
407         return false;
408     }
409
410     while (!_rtiFederate->getTimeRegulationEnabled()) {
411         _rtiFederate->processMessage();
412     }
413
414     return true;
415 }
416
417 bool
418 HLAFederate::disableTimeRegulation()
419 {
420     if (!_rtiFederate.valid()) {
421         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
422         return false;
423     }
424     return _rtiFederate->disableTimeRegulation();
425 }
426
427 bool
428 HLAFederate::modifyLookahead(const SGTimeStamp& timeStamp)
429 {
430     if (!_rtiFederate.valid()) {
431         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
432         return false;
433     }
434     return _rtiFederate->modifyLookahead(timeStamp);
435 }
436
437 bool
438 HLAFederate::timeAdvanceBy(const SGTimeStamp& timeIncrement)
439 {
440     if (!_rtiFederate.valid()) {
441         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
442         return false;
443     }
444
445     SGTimeStamp timeStamp;
446     if (!_rtiFederate->queryFederateTime(timeStamp)) {
447         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query federate time!");
448         return false;
449     }
450
451     if (!_rtiFederate->timeAdvanceRequest(timeStamp + timeIncrement)) {
452         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
453         return false;
454     }
455
456     return processMessages();
457 }
458
459 bool
460 HLAFederate::timeAdvance(const SGTimeStamp& timeStamp)
461 {
462     if (!_rtiFederate.valid()) {
463         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
464         return false;
465     }
466
467     if (!_rtiFederate->timeAdvanceRequest(timeStamp)) {
468         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
469         return false;
470     }
471
472     return processMessages();
473 }
474
475 bool
476 HLAFederate::timeAdvanceAvailable()
477 {
478     if (!_rtiFederate.valid()) {
479         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
480         return false;
481     }
482
483     SGTimeStamp timeStamp;
484     if (!_rtiFederate->queryGALT(timeStamp)) {
485         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query GALT!");
486         return false;
487     }
488
489     if (!_rtiFederate->timeAdvanceRequestAvailable(timeStamp)) {
490         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
491         return false;
492     }
493
494     return processMessages();
495 }
496
497 bool
498 HLAFederate::queryFederateTime(SGTimeStamp& timeStamp)
499 {
500     if (!_rtiFederate.valid()) {
501         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
502         return false;
503     }
504     return _rtiFederate->queryFederateTime(timeStamp);
505 }
506
507 bool
508 HLAFederate::queryLookahead(SGTimeStamp& timeStamp)
509 {
510     if (!_rtiFederate.valid()) {
511         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
512         return false;
513     }
514     return _rtiFederate->queryLookahead(timeStamp);
515 }
516
517 bool
518 HLAFederate::processMessage()
519 {
520     if (!_rtiFederate.valid()) {
521         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
522         return false;
523     }
524     return _rtiFederate->processMessage();
525 }
526
527 bool
528 HLAFederate::processMessage(const SGTimeStamp& timeout)
529 {
530     if (!_rtiFederate.valid()) {
531         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
532         return false;
533     }
534     return _rtiFederate->processMessages(timeout.toSecs(), 0);
535 }
536
537 bool
538 HLAFederate::processMessages()
539 {
540     if (!_rtiFederate.valid()) {
541         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
542         return false;
543     }
544
545     while (_rtiFederate->getTimeAdvancePending()) {
546         _rtiFederate->processMessage();
547     }
548
549     // Now flush just what is left
550     while (!_rtiFederate->processMessages(0, 0));
551
552     return true;
553 }
554
555 bool
556 HLAFederate::tick(const double& minimum, const double& maximum)
557 {
558     if (!_rtiFederate.valid()) {
559         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
560         return false;
561     }
562     return _rtiFederate->processMessages(minimum, maximum);
563 }
564
565 bool
566 HLAFederate::readObjectModelTemplate(const std::string& objectModel,
567                                      HLAFederate::ObjectModelFactory& objectModelFactory)
568 {
569     if (!_rtiFederate.valid()) {
570         SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
571         return false;
572     }
573
574     // The XML version of the federate object model.
575     // This one covers the generic attributes, parameters and data types.
576     HLAOMTXmlVisitor omtXmlVisitor;
577     try {
578         readXML(objectModel, omtXmlVisitor);
579     } catch (const sg_throwable& e) {
580         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
581                << e.getMessage());
582         return false;
583     } catch (...) {
584         SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
585         return false;
586     }
587
588     unsigned numObjectClasses = omtXmlVisitor.getNumObjectClasses();
589     for (unsigned i = 0; i < numObjectClasses; ++i) {
590         const HLAOMTXmlVisitor::ObjectClass* objectClass = omtXmlVisitor.getObjectClass(i);
591         std::string objectClassName = objectClass->getName();
592
593         SGSharedPtr<HLAObjectClass> hlaObjectClass = objectModelFactory.createObjectClass(objectClassName, *this);
594         if (!hlaObjectClass.valid()) {
595             SG_LOG(SG_IO, SG_INFO, "Ignoring object class \"" << objectClassName << "\".");
596             continue;
597         }
598
599         bool publish = objectModelFactory.publishObjectClass(objectClassName, objectClass->getSharing());
600         bool subscribe = objectModelFactory.subscribeObjectClass(objectClassName, objectClass->getSharing());
601
602         std::set<unsigned> subscriptions;
603         std::set<unsigned> publications;
604
605         // process the attributes
606         for (unsigned j = 0; j < objectClass->getNumAttributes(); ++j) {
607             const simgear::HLAOMTXmlVisitor::Attribute* attribute;
608             attribute = objectClass->getAttribute(j);
609
610             std::string attributeName = attribute->getName();
611             unsigned index = hlaObjectClass->getAttributeIndex(attributeName);
612
613             if (index == ~0u) {
614                 SG_LOG(SG_IO, SG_WARN, "RTI does not know the \"" << attributeName << "\" attribute!");
615                 continue;
616             }
617
618             SGSharedPtr<HLADataType> dataType;
619             dataType = omtXmlVisitor.getAttributeDataType(objectClassName, attributeName);
620             if (!dataType.valid()) {
621                 SG_LOG(SG_IO, SG_WARN, "Could not find data type for attribute \""
622                        << attributeName << "\" in object class \"" << objectClassName << "\"!");
623             }
624             hlaObjectClass->setAttributeDataType(index, dataType);
625
626             HLAUpdateType updateType = HLAUndefinedUpdate;
627             if (attribute->_updateType == "Periodic")
628                 updateType = HLAPeriodicUpdate;
629             else if (attribute->_updateType == "Static")
630                 updateType = HLAStaticUpdate;
631             else if (attribute->_updateType == "Conditional")
632                 updateType = HLAConditionalUpdate;
633             hlaObjectClass->setAttributeUpdateType(index, updateType);
634
635             if (subscribe && objectModelFactory.subscribeAttribute(objectClassName, attributeName, attribute->_sharing))
636                 subscriptions.insert(index);
637             if (publish && objectModelFactory.publishAttribute(objectClassName, attributeName, attribute->_sharing))
638                 publications.insert(index);
639         }
640
641         if (publish)
642             hlaObjectClass->publish(publications);
643         if (subscribe)
644             hlaObjectClass->subscribe(subscriptions, true);
645
646         _objectClassMap[objectClassName] = hlaObjectClass;
647     }
648
649     return true;
650 }
651
652 HLAObjectClass*
653 HLAFederate::getObjectClass(const std::string& name)
654 {
655     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
656     if (i == _objectClassMap.end())
657         return 0;
658     return i->second.get();
659 }
660
661 const HLAObjectClass*
662 HLAFederate::getObjectClass(const std::string& name) const
663 {
664     ObjectClassMap::const_iterator i = _objectClassMap.find(name);
665     if (i == _objectClassMap.end())
666         return 0;
667     return i->second.get();
668 }
669
670 HLAInteractionClass*
671 HLAFederate::getInteractionClass(const std::string& name)
672 {
673     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
674     if (i == _interactionClassMap.end())
675         return 0;
676     return i->second.get();
677 }
678
679 const HLAInteractionClass*
680 HLAFederate::getInteractionClass(const std::string& name) const
681 {
682     InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
683     if (i == _interactionClassMap.end())
684         return 0;
685     return i->second.get();
686 }
687
688 } // namespace simgear