1 // Copyright (C) 2009 - 2011 Mathias Froehlich - Mathias.Froehlich@web.de
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.
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.
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.
18 #include "HLAFederate.hxx"
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"
30 HLAFederate::HLAFederate() :
32 _createFederationExecution(true),
33 _timeConstrained(false),
34 _timeRegulating(false),
35 _timeConstrainedByLocalClock(false),
40 HLAFederate::~HLAFederate()
45 HLAFederate::getVersion() const
51 HLAFederate::setVersion(HLAFederate::Version version)
53 if (_rtiFederate.valid()) {
54 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
61 const std::list<std::string>&
62 HLAFederate::getConnectArguments() const
64 return _connectArguments;
68 HLAFederate::setConnectArguments(const std::list<std::string>& connectArguments)
70 if (_rtiFederate.valid()) {
71 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
74 _connectArguments = connectArguments;
79 HLAFederate::getCreateFederationExecution() const
81 return _createFederationExecution;
85 HLAFederate::setCreateFederationExecution(bool createFederationExecution)
87 _createFederationExecution = createFederationExecution;
92 HLAFederate::getFederationExecutionName() const
94 return _federationExecutionName;
98 HLAFederate::setFederationExecutionName(const std::string& federationExecutionName)
100 if (_rtiFederate.valid()) {
101 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
104 _federationExecutionName = federationExecutionName;
109 HLAFederate::getFederationObjectModel() const
111 return _federationObjectModel;
115 HLAFederate::setFederationObjectModel(const std::string& federationObjectModel)
117 if (_rtiFederate.valid()) {
118 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
121 _federationObjectModel = federationObjectModel;
126 HLAFederate::getFederateType() const
128 return _federateType;
132 HLAFederate::setFederateType(const std::string& federateType)
134 if (_rtiFederate.valid()) {
135 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
138 _federateType = federateType;
143 HLAFederate::getFederateName() const
145 return _federateName;
149 HLAFederate::setFederateName(const std::string& federateName)
151 if (_rtiFederate.valid()) {
152 SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Ignoring HLAFederate parameter setting on already connected federate!");
155 _federateName = federateName;
160 HLAFederate::connect(Version version, const std::list<std::string>& stringList)
162 if (_rtiFederate.valid()) {
163 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
168 _rtiFederate = new RTI13Federate(stringList);
170 _connectArguments = stringList;
173 SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516 not yet(!?) supported.");
174 // _rtiFederate = new RTI1516Federate(stringList);
177 SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
178 // _rtiFederate = new RTI1516eFederate(stringList);
181 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
183 return _rtiFederate.valid();
187 HLAFederate::connect()
189 if (_rtiFederate.valid()) {
190 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Trying to connect to already connected federate!");
195 _rtiFederate = new RTI13Federate(_connectArguments);
198 SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516 not yet(!?) supported.");
199 // _rtiFederate = new RTI1516Federate(_connectArguments);
202 SG_LOG(SG_IO, SG_ALERT, "HLA version RTI1516E not yet(!?) supported.");
203 // _rtiFederate = new RTI1516eFederate(_connectArguments);
206 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Unknown rti version in connect!");
208 return _rtiFederate.valid();
212 HLAFederate::disconnect()
214 if (!_rtiFederate.valid()) {
215 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
223 HLAFederate::createFederationExecution(const std::string& federation, const std::string& objectModel)
225 if (!_rtiFederate.valid()) {
226 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
230 RTIFederate::FederationManagementResult createResult;
231 createResult = _rtiFederate->createFederationExecution(federation, objectModel);
232 if (createResult == RTIFederate::FederationManagementFatal)
235 _federationExecutionName = federation;
236 _federationObjectModel = objectModel;
241 HLAFederate::destroyFederationExecution(const std::string& federation)
243 if (!_rtiFederate.valid()) {
244 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
248 RTIFederate::FederationManagementResult destroyResult;
249 destroyResult = _rtiFederate->destroyFederationExecution(federation);
250 if (destroyResult == RTIFederate::FederationManagementFatal)
257 HLAFederate::createFederationExecution()
259 if (!_rtiFederate.valid()) {
260 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
264 RTIFederate::FederationManagementResult createResult;
265 createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
266 if (createResult != RTIFederate::FederationManagementSuccess)
273 HLAFederate::destroyFederationExecution()
275 if (!_rtiFederate.valid()) {
276 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
280 RTIFederate::FederationManagementResult destroyResult;
281 destroyResult = _rtiFederate->destroyFederationExecution(_federationExecutionName);
282 if (destroyResult != RTIFederate::FederationManagementSuccess)
289 HLAFederate::join(const std::string& federateType, const std::string& federation)
291 if (!_rtiFederate.valid()) {
292 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
296 RTIFederate::FederationManagementResult joinResult;
297 joinResult = _rtiFederate->join(federateType, federation);
298 if (joinResult == RTIFederate::FederationManagementFatal)
307 if (!_rtiFederate.valid()) {
308 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
312 RTIFederate::FederationManagementResult joinResult;
313 joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
314 if (joinResult != RTIFederate::FederationManagementSuccess)
321 HLAFederate::resign()
323 if (!_rtiFederate.valid()) {
324 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
327 return _rtiFederate->resign();
331 HLAFederate::createJoinFederationExecution()
333 if (!_rtiFederate.valid()) {
334 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
340 RTIFederate::FederationManagementResult joinResult;
341 joinResult = _rtiFederate->join(_federateType, _federationExecutionName);
342 switch (joinResult) {
343 case RTIFederate::FederationManagementSuccess:
344 // Fast return on success
346 case RTIFederate::FederationManagementFatal:
347 // Abort on fatal errors
353 // If not already joinable, try to create the requested federation
354 RTIFederate::FederationManagementResult createResult;
355 createResult = _rtiFederate->createFederationExecution(_federationExecutionName, _federationObjectModel);
356 switch (createResult) {
357 case RTIFederate::FederationManagementFatal:
358 // Abort on fatal errors
368 HLAFederate::resignDestroyFederationExecution()
370 if (!_rtiFederate.valid()) {
371 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
376 bool success = _rtiFederate->resign();
378 // and try to destroy, non fatal if still some federates joined
379 if (_rtiFederate->destroyFederationExecution(_federationExecutionName) == RTIFederate::FederationManagementFatal)
386 HLAFederate::getTimeConstrained() const
388 return _timeConstrained;
392 HLAFederate::setTimeConstrained(bool timeConstrained)
394 _timeConstrained = timeConstrained;
396 if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
397 if (_timeConstrained && !_rtiFederate->getTimeConstrainedEnabled()) {
398 if (!enableTimeConstrained())
400 } else if (!_timeConstrained && _rtiFederate->getTimeConstrainedEnabled()) {
401 if (!disableTimeConstrained())
411 HLAFederate::getTimeConstrainedByLocalClock() const
413 return _timeConstrainedByLocalClock;
417 HLAFederate::setTimeConstrainedByLocalClock(bool timeConstrainedByLocalClock)
419 _timeConstrainedByLocalClock = timeConstrainedByLocalClock;
421 if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
422 if (_timeConstrainedByLocalClock) {
423 if (!enableTimeConstrainedByLocalClock())
432 HLAFederate::getTimeRegulating() const
434 return _timeRegulating;
438 HLAFederate::setTimeRegulating(bool timeRegulating)
440 _timeRegulating = timeRegulating;
442 if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
443 if (_timeRegulating && !_rtiFederate->getTimeRegulationEnabled()) {
444 if (!enableTimeRegulation())
446 } else if (!_timeRegulating && _rtiFederate->getTimeRegulationEnabled()) {
447 if (!disableTimeRegulation())
456 HLAFederate::setLeadTime(const SGTimeStamp& leadTime)
458 if (leadTime < SGTimeStamp::fromSec(0)) {
459 SG_LOG(SG_NETWORK, SG_WARN, "Ignoring negative lead time!");
463 _leadTime = leadTime;
465 if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
466 if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
467 SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
476 HLAFederate::getLeadTime() const
482 HLAFederate::setTimeIncrement(const SGTimeStamp& timeIncrement)
484 if (timeIncrement < SGTimeStamp::fromSec(0)) {
485 SG_LOG(SG_NETWORK, SG_WARN, "Ignoring negative time increment!");
489 _timeIncrement = timeIncrement;
491 if (_rtiFederate.valid() && _rtiFederate->getJoined()) {
492 if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
493 SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
502 HLAFederate::getTimeIncrement() const
504 return _timeIncrement;
508 HLAFederate::enableTimeConstrained()
510 if (!_rtiFederate.valid()) {
511 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
515 if (!_rtiFederate->enableTimeConstrained()) {
516 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time constrained!");
520 while (!_rtiFederate->getTimeConstrainedEnabled()) {
521 _rtiFederate->processMessage();
528 HLAFederate::disableTimeConstrained()
530 if (!_rtiFederate.valid()) {
531 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
534 return _rtiFederate->disableTimeConstrained();
538 HLAFederate::enableTimeConstrainedByLocalClock()
540 // Compute the time offset from the system time to the simulation time
541 SGTimeStamp federateTime;
542 if (!queryFederateTime(federateTime)) {
543 SG_LOG(SG_NETWORK, SG_WARN, "Cannot get federate time!");
546 _localClockOffset = SGTimeStamp::now() - federateTime;
551 HLAFederate::enableTimeRegulation(const SGTimeStamp& lookahead)
553 if (!_rtiFederate.valid()) {
554 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
558 if (!_rtiFederate->enableTimeRegulation(lookahead)) {
559 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not enable time regulation!");
563 while (!_rtiFederate->getTimeRegulationEnabled()) {
564 _rtiFederate->processMessage();
571 HLAFederate::enableTimeRegulation()
573 if (!enableTimeRegulation(SGTimeStamp::fromSec(0))) {
574 SG_LOG(SG_NETWORK, SG_WARN, "Cannot enable time regulation!");
577 if (!modifyLookahead(_leadTime + SGTimeStamp::fromSec(_timeIncrement.toSecs()*0.9))) {
578 SG_LOG(SG_NETWORK, SG_WARN, "Cannot modify lookahead!");
585 HLAFederate::disableTimeRegulation()
587 if (!_rtiFederate.valid()) {
588 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
591 return _rtiFederate->disableTimeRegulation();
595 HLAFederate::modifyLookahead(const SGTimeStamp& timeStamp)
597 if (!_rtiFederate.valid()) {
598 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
601 return _rtiFederate->modifyLookahead(timeStamp);
605 HLAFederate::timeAdvanceBy(const SGTimeStamp& timeIncrement)
607 if (!_rtiFederate.valid()) {
608 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
612 SGTimeStamp timeStamp;
613 if (!_rtiFederate->queryFederateTime(timeStamp)) {
614 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query federate time!");
618 if (!_rtiFederate->timeAdvanceRequest(timeStamp + timeIncrement)) {
619 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
623 return processMessages();
627 HLAFederate::timeAdvance(const SGTimeStamp& timeStamp)
629 if (!_rtiFederate.valid()) {
630 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
634 if (!_rtiFederate->timeAdvanceRequest(timeStamp)) {
635 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
639 return processMessages();
643 HLAFederate::timeAdvanceAvailable()
645 if (!_rtiFederate.valid()) {
646 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
650 SGTimeStamp timeStamp;
651 if (!_rtiFederate->queryGALT(timeStamp)) {
652 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Could not query GALT!");
656 if (!_rtiFederate->timeAdvanceRequestAvailable(timeStamp)) {
657 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Time advance request failed!");
661 return processMessages();
665 HLAFederate::queryFederateTime(SGTimeStamp& timeStamp)
667 if (!_rtiFederate.valid()) {
668 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
671 return _rtiFederate->queryFederateTime(timeStamp);
675 HLAFederate::queryLookahead(SGTimeStamp& timeStamp)
677 if (!_rtiFederate.valid()) {
678 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
681 return _rtiFederate->queryLookahead(timeStamp);
685 HLAFederate::processMessage()
687 if (!_rtiFederate.valid()) {
688 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
691 return _rtiFederate->processMessage();
695 HLAFederate::processMessage(const SGTimeStamp& timeout)
697 if (!_rtiFederate.valid()) {
698 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
701 return _rtiFederate->processMessages(timeout.toSecs(), 0);
705 HLAFederate::processMessages()
707 if (!_rtiFederate.valid()) {
708 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
712 while (_rtiFederate->getTimeAdvancePending()) {
713 _rtiFederate->processMessage();
716 if (_timeConstrainedByLocalClock) {
717 SGTimeStamp federateTime;
718 if (!_rtiFederate->queryFederateTime(federateTime)) {
719 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Error querying federate time!");
722 SGTimeStamp systemTime = federateTime + _localClockOffset;
724 double rest = (systemTime - SGTimeStamp::now()).toSecs();
727 _rtiFederate->processMessages(rest, rest);
731 // Now flush just what is left
732 while (!_rtiFederate->processMessages(0, 0));
738 HLAFederate::tick(const double& minimum, const double& maximum)
740 if (!_rtiFederate.valid()) {
741 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
744 return _rtiFederate->processMessages(minimum, maximum);
748 HLAFederate::readObjectModelTemplate(const std::string& objectModel,
749 HLAFederate::ObjectModelFactory& objectModelFactory)
751 if (!_rtiFederate.valid()) {
752 SG_LOG(SG_NETWORK, SG_WARN, "HLA: Accessing unconnected federate!");
756 // The XML version of the federate object model.
757 // This one covers the generic attributes, parameters and data types.
758 HLAOMTXmlVisitor omtXmlVisitor;
760 readXML(objectModel, omtXmlVisitor);
761 } catch (const sg_throwable& e) {
762 SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file: "
766 SG_LOG(SG_IO, SG_ALERT, "Could not open HLA XML object model file");
770 unsigned numObjectClasses = omtXmlVisitor.getNumObjectClasses();
771 for (unsigned i = 0; i < numObjectClasses; ++i) {
772 const HLAOMTXmlVisitor::ObjectClass* objectClass = omtXmlVisitor.getObjectClass(i);
773 std::string objectClassName = objectClass->getName();
775 SGSharedPtr<HLAObjectClass> hlaObjectClass = objectModelFactory.createObjectClass(objectClassName, *this);
776 if (!hlaObjectClass.valid()) {
777 SG_LOG(SG_IO, SG_INFO, "Ignoring object class \"" << objectClassName << "\".");
781 bool publish = objectModelFactory.publishObjectClass(objectClassName, objectClass->getSharing());
782 bool subscribe = objectModelFactory.subscribeObjectClass(objectClassName, objectClass->getSharing());
784 std::set<unsigned> subscriptions;
785 std::set<unsigned> publications;
787 // process the attributes
788 for (unsigned j = 0; j < objectClass->getNumAttributes(); ++j) {
789 const simgear::HLAOMTXmlVisitor::Attribute* attribute;
790 attribute = objectClass->getAttribute(j);
792 std::string attributeName = attribute->getName();
793 unsigned index = hlaObjectClass->getAttributeIndex(attributeName);
796 SG_LOG(SG_IO, SG_WARN, "RTI does not know the \"" << attributeName << "\" attribute!");
800 SGSharedPtr<HLADataType> dataType;
801 dataType = omtXmlVisitor.getAttributeDataType(objectClassName, attributeName);
802 if (!dataType.valid()) {
803 SG_LOG(SG_IO, SG_WARN, "Could not find data type for attribute \""
804 << attributeName << "\" in object class \"" << objectClassName << "\"!");
806 hlaObjectClass->setAttributeDataType(index, dataType);
808 HLAUpdateType updateType = HLAUndefinedUpdate;
809 if (attribute->_updateType == "Periodic")
810 updateType = HLAPeriodicUpdate;
811 else if (attribute->_updateType == "Static")
812 updateType = HLAStaticUpdate;
813 else if (attribute->_updateType == "Conditional")
814 updateType = HLAConditionalUpdate;
815 hlaObjectClass->setAttributeUpdateType(index, updateType);
817 if (subscribe && objectModelFactory.subscribeAttribute(objectClassName, attributeName, attribute->_sharing))
818 subscriptions.insert(index);
819 if (publish && objectModelFactory.publishAttribute(objectClassName, attributeName, attribute->_sharing))
820 publications.insert(index);
824 hlaObjectClass->publish(publications);
826 hlaObjectClass->subscribe(subscriptions, true);
828 _objectClassMap[objectClassName] = hlaObjectClass;
835 HLAFederate::getObjectClass(const std::string& name)
837 ObjectClassMap::const_iterator i = _objectClassMap.find(name);
838 if (i == _objectClassMap.end())
840 return i->second.get();
843 const HLAObjectClass*
844 HLAFederate::getObjectClass(const std::string& name) const
846 ObjectClassMap::const_iterator i = _objectClassMap.find(name);
847 if (i == _objectClassMap.end())
849 return i->second.get();
853 HLAFederate::getInteractionClass(const std::string& name)
855 InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
856 if (i == _interactionClassMap.end())
858 return i->second.get();
861 const HLAInteractionClass*
862 HLAFederate::getInteractionClass(const std::string& name) const
864 InteractionClassMap::const_iterator i = _interactionClassMap.find(name);
865 if (i == _interactionClassMap.end())
867 return i->second.get();
871 HLAFederate::setDone(bool done)
877 HLAFederate::getDone() const
883 HLAFederate::readObjectModel()
885 /// Currently empty, but is called at the right time so that
886 /// the object model is present when it is needed
891 HLAFederate::subscribe()
893 /// Currently empty, but is called at the right time
898 HLAFederate::publish()
900 /// Currently empty, but is called at the right time
907 // We need to talk to the rti
911 if (_createFederationExecution) {
912 if (!createJoinFederationExecution())
918 // Read the xml file containing the object model
919 if (!readObjectModel()) {
923 // start being time constrained if required
924 if (_timeConstrained) {
925 if (!enableTimeConstrained()) {
930 // Now that we are potentially time constrained, we can subscribe.
931 // This is to make sure we do not get any time stamped message
932 // converted to a non time stamped message by the rti.
937 // Before we publish anything start getting regulating if required
938 if (_timeRegulating) {
939 if (!enableTimeRegulation()) {
944 // Note that starting from here, we need to be careful with things
945 // requireing unbounded time. The rest of the federation might wait
948 // Compute the time offset from the system time to the simulation time
949 if (_timeConstrainedByLocalClock) {
950 if (!enableTimeConstrainedByLocalClock()) {
951 SG_LOG(SG_NETWORK, SG_WARN, "Cannot enable time constrained by local clock!");
957 // Publish what we want to write
967 HLAFederate::update()
969 return timeAdvanceBy(_timeIncrement);
973 HLAFederate::shutdown()
975 // On shutdown, just try all in order.
976 // If something goes wrong, continue and try to get out here as good as possible.
979 if (_createFederationExecution) {
980 if (!resignDestroyFederationExecution())
1012 } // namespace simgear