FlightGear next
hla.cxx
Go to the documentation of this file.
1//
2// Copyright (C) 2009 - 2012 Mathias Fröhlich <Mathias.Froehlich@web.de>
3//
4// This program is free software; you can redistribute it and/or
5// modify it under the terms of the GNU General Public License as
6// published by the Free Software Foundation; either version 2 of the
7// License, or (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17//
18
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include "hla.hxx"
24
25#include <simgear/compiler.h>
26
27#include <algorithm>
28#include <list>
29#include <map>
30#include <string>
31#include <stack>
32
33#include <simgear/debug/logstream.hxx>
34#include <simgear/math/SGMath.hxx>
35#include <simgear/misc/sg_path.hxx>
36#include <simgear/props/props.hxx>
37#include <simgear/structure/exception.hxx>
38#include <simgear/xml/easyxml.hxx>
39
40#include <simgear/hla/HLAFederate.hxx>
41#include <simgear/hla/HLAArrayDataElement.hxx>
42#include <simgear/hla/HLADataElement.hxx>
43#include <simgear/hla/HLADataType.hxx>
44#include <simgear/hla/HLALocation.hxx>
45#include <simgear/hla/HLAObjectClass.hxx>
46#include <simgear/hla/HLAObjectInstance.hxx>
47#include <simgear/hla/HLAPropertyDataElement.hxx>
48#include <simgear/hla/HLAVariantRecordDataElement.hxx>
49
51#include <AIModel/AIManager.hxx>
52
54
55#include <Main/fg_props.hxx>
56#include <Main/globals.hxx>
57
58// FIXME rename HLAMP
59// FIXME make classes here private ...
60
61namespace sg = simgear;
62
68
69class FGHLA::XMLConfigReader : public XMLVisitor {
70public:
72 _rtiVersion(RTI13)
73 { }
74
75 const std::string& getFederateObjectModel() const
76 { return _federateObjectModel; }
77
79 { return _rtiVersion; }
80 const std::list<std::string>& getRTIArguments() const
81 { return _rtiArguments; }
82
83 struct DataElement {
84 std::string _type;
85 std::string _name;
86 std::string _inProperty;
87 std::string _outProperty;
88 };
89 typedef std::list<DataElement> DataElementList;
90 struct ModelConfig {
91 std::string _type;
93 std::list<std::pair<std::string, std::string> > _modelMap;
94 };
104 std::string _name;
105 };
115 typedef std::list<ObjectClassConfig> ObjectClassConfigList;
116
118 { return _objectClassConfigList; }
119
120protected:
121 virtual void startXML()
122 {
123 _modeStack.push(TopLevelMode);
124 }
125 virtual void endXML()
126 {
127 _modeStack.pop();
128 }
129 virtual void startElement(const char* name, const XMLAttributes& atts)
130 {
131 if (strcmp(name, "hlaConfiguration") == 0) {
132 if (!isModeStackTop(TopLevelMode))
133 throw sg_exception("hlaConfiguration tag not at top level");
134
135 _modeStack.push(HLAConfigurationMode);
136 }
137
138 else if (strcmp(name, "rti") == 0) {
139 if (!isModeStackTop(HLAConfigurationMode))
140 throw sg_exception("rti tag not at top level");
141
142 std::string rtiVersion = getAttribute("version", atts);
143 if (rtiVersion == "RTI13")
144 _rtiVersion = RTI13;
145 else if (rtiVersion == "RTI1516")
146 _rtiVersion = RTI1516;
147 else if (rtiVersion == "RTI1516E")
148 _rtiVersion = RTI1516E;
149 else
150 throw sg_exception("invalid version attribute in rti tag");
151
152 _modeStack.push(RTIMode);
153 }
154 else if (strcmp(name, "argument") == 0) {
155 if (!isModeStackTop(RTIMode))
156 throw sg_exception("argument tag not inside an rti tag");
157
158 _modeStack.push(RTIArgumentMode);
159 _rtiArguments.push_back(std::string());
160 }
161
162 else if (strcmp(name, "objects") == 0) {
163 if (!isModeStackTop(HLAConfigurationMode))
164 throw sg_exception("objects tag not at top level");
165
166 _modeStack.push(ObjectsMode);
167 }
168 else if (strcmp(name, "objectClass") == 0) {
169 // Currently this is flat and only allows one class to be configured
170 if (!isModeStackTop(ObjectsMode))
171 throw sg_exception("objects tag not inside an objects tag");
172 if (!_objectClassConfigList.empty())
173 throw sg_exception("currently only one objectClass is allowed");
174 // if (!isModeStackTop(ObjectsMode) && !isModeStackTop(ObjectClassMode))
175 // throw sg_exception("objects tag not inside an objects or objectClass tag");
176
177 ObjectClassConfig objectClassConfig;
178 objectClassConfig._type = getAttribute("type", atts);
179 objectClassConfig._name = getAttribute("name", atts);
180 _objectClassConfigList.push_back(objectClassConfig);
181
182 _modeStack.push(ObjectClassMode);
183 }
184 else if (strcmp(name, "model") == 0) {
185 if (!isModeStackTop(ObjectClassMode))
186 throw sg_exception("position tag not inside an objectClass tag");
187
188 _objectClassConfigList.back()._modelConfig._type = getAttribute("type", atts);
189
190 _modeStack.push(ModelMode);
191 }
192 else if (strcmp(name, "key") == 0) {
193 if (!isModeStackTop(ModelMode))
194 throw sg_exception("key tag not inside an model tag");
195
196 std::pair<std::string,std::string> p;
197 p.first = getAttribute("external", atts);
198 p.second = getAttribute("modelPath", atts);
199 _objectClassConfigList.back()._modelConfig._modelMap.push_back(p);
200
201 _modeStack.push(KeyMode);
202 }
203 else if (strcmp(name, "simTime") == 0) {
204 if (!isModeStackTop(ObjectClassMode))
205 throw sg_exception("simTime tag not inside an objectClass tag");
206
207 _objectClassConfigList.back()._simTimeConfig._type = getAttribute("type", atts);
208
209 _modeStack.push(SimTimeMode);
210 }
211 else if (strcmp(name, "position") == 0) {
212 if (!isModeStackTop(ObjectClassMode))
213 throw sg_exception("position tag not inside an objectClass tag");
214
215 _objectClassConfigList.back()._positionConfig._type = getAttribute("type", atts);
216
217 _modeStack.push(PositionMode);
218 }
219 else if (strcmp(name, "mpProperties") == 0) {
220 if (!isModeStackTop(ObjectClassMode))
221 throw sg_exception("mpProperties tag not inside an objectClass tag");
222
223 _objectClassConfigList.back()._mpPropertiesConfig._name = getAttribute("name", atts);
224
225 _modeStack.push(MPPropertiesMode);
226 }
227 else if (strcmp(name, "dataElement") == 0) {
228
229 DataElement dataElement;
230 dataElement._type = getAttribute("type", atts);
231 dataElement._name = getAttribute("name", atts);
232 if (isModeStackTop(ModelMode)) {
233 _objectClassConfigList.back()._modelConfig._dataElementList.push_back(dataElement);
234 } else if (isModeStackTop(SimTimeMode)) {
235 _objectClassConfigList.back()._simTimeConfig._dataElementList.push_back(dataElement);
236 } else if (isModeStackTop(PositionMode)) {
237 _objectClassConfigList.back()._positionConfig._dataElementList.push_back(dataElement);
238 } else if (isModeStackTop(ObjectClassMode)) {
239 std::string io = getAttribute("io", atts);
240 dataElement._inProperty = getAttribute("in", atts);
241 if (dataElement._inProperty.empty())
242 dataElement._inProperty = io;
243 dataElement._outProperty = getAttribute("out", atts);
244 if (dataElement._outProperty.empty())
245 dataElement._outProperty = io;
246 _objectClassConfigList.back()._dataElementList.push_back(dataElement);
247 } else {
248 throw sg_exception("dataElement tag not inside a position, model or objectClass tag");
249 }
250
251 _modeStack.push(DataElementMode);
252 }
253
254 else if (strcmp(name, "federateObjectModel") == 0) {
255 if (!isModeStackTop(HLAConfigurationMode))
256 throw sg_exception("federateObjectModel tag not at top level");
257
258 _federateObjectModel = getAttribute("name", atts);
259 _modeStack.push(FederateObjectModelMode);
260 }
261
262 else {
263 throw sg_exception(std::string("Unknown tag ") + name);
264 }
265 }
266
267 virtual void data(const char * s, int length)
268 {
269 if (isModeStackTop(RTIArgumentMode)) {
270 _rtiArguments.back().append(s, length);
271 }
272 }
273
274 virtual void endElement(const char* name)
275 {
276 _modeStack.pop();
277 }
278
279 std::string getAttribute(const char* name, const XMLAttributes& atts)
280 {
281 int index = atts.findAttribute(name);
282 if (index < 0 || atts.size() <= index)
283 return std::string();
284 return std::string(atts.getValue(index));
285 }
286 std::string getAttribute(const std::string& name, const XMLAttributes& atts)
287 {
288 int index = atts.findAttribute(name.c_str());
289 if (index < 0 || atts.size() <= index)
290 return std::string();
291 return std::string(atts.getValue(index));
292 }
293
294private:
295 // poor peoples xml validation ...
296 enum Mode {
297 TopLevelMode,
298 HLAConfigurationMode,
299 RTIMode,
300 RTIArgumentMode,
301 ObjectsMode,
302 ObjectClassMode,
303 ModelMode,
304 KeyMode,
305 SimTimeMode,
306 PositionMode,
307 MPPropertiesMode,
308 DataElementMode,
309 FederateObjectModelMode
310 };
311 bool isModeStackTop(Mode mode)
312 {
313 if (_modeStack.empty())
314 return false;
315 return _modeStack.top() == mode;
316 }
317 std::stack<Mode> _modeStack;
318
319 std::string _federateObjectModel;
320 HLAVersion _rtiVersion;
321 std::list<std::string> _rtiArguments;
322
323 ObjectClassConfigList _objectClassConfigList;
324};
325
326class PropertyReferenceSet : public SGReferenced {
327public:
328 void insert(const std::string& relativePath, const SGSharedPtr<sg::HLAPropertyDataElement>& dataElement)
329 {
330 if (_rootNode.valid())
331 dataElement->setPropertyNode(_rootNode->getNode(relativePath, true));
332 _pathDataElementPairList.push_back(PathDataElementPair(relativePath, dataElement));
333 }
334
335 void setRootNode(SGPropertyNode* rootNode)
336 {
337 _rootNode = rootNode;
338 for (PathDataElementPairList::iterator i = _pathDataElementPairList.begin();
339 i != _pathDataElementPairList.end(); ++i) {
340 i->second->setPropertyNode(_rootNode->getNode(i->first, true));
341 }
342 }
343 SGPropertyNode* getRootNode()
344 { return _rootNode.get(); }
345
346private:
347 SGSharedPtr<SGPropertyNode> _rootNode;
348
349 typedef std::pair<std::string, SGSharedPtr<sg::HLAPropertyDataElement> > PathDataElementPair;
350 typedef std::list<PathDataElementPair> PathDataElementPairList;
351 PathDataElementPairList _pathDataElementPairList;
352};
353
354class AbstractSimTime : public SGReferenced {
355public:
356 virtual ~AbstractSimTime() {}
357
358 virtual double getTimeStamp() const = 0;
359 virtual void setTimeStamp(double) = 0;
360};
361
362class AbstractModel : public SGReferenced {
363public:
364 virtual ~AbstractModel() {}
365
366 virtual std::string getModelPath() const = 0;
367 virtual void setModelPath(const std::string&) = 0;
368};
369
370// Factory class that is used to create an apternative data element for the multiplayer property attribute
372 public sg::HLAVariantArrayDataElement::AlternativeDataElementFactory {
373public:
375 _propertyReferenceSet(propertyReferenceSet)
376 { }
377
378 virtual sg::HLADataElement* createElement(const sg::HLAVariantRecordDataElement& variantRecordDataElement, unsigned index)
379 {
380 const sg::HLAVariantRecordDataType* dataType = variantRecordDataElement.getDataType();
381 if (!dataType)
382 return 0;
383 const sg::HLAEnumeratedDataType* enumDataType = dataType->getEnumeratedDataType();
384 if (!enumDataType)
385 return 0;
386 const sg::HLADataType* alternativeDataType = dataType->getAlternativeDataType(index);
387 if (!alternativeDataType)
388 return 0;
389
390 // The relative property path should be in the semantics field name
391 std::string relativePath = dataType->getAlternativeSemantics(index);
392 sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement(alternativeDataType, (SGPropertyNode*)0);
393 _propertyReferenceSet->insert(relativePath, dataElement);
394 return dataElement;
395 }
396
397private:
398 SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
399};
400
401class FGHLA::MultiplayerObjectInstance : public sg::HLAObjectInstance {
402public:
403 MultiplayerObjectInstance(sg::HLAObjectClass* objectClass) :
404 sg::HLAObjectInstance(objectClass),
406 _mpProperties(new sg::HLAVariantArrayDataElement)
407 {
408 _mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantRecordDataElementFactory(_propertyReferenceSet.get()));
409 }
411 { }
412
413 SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
414 SGSharedPtr<sg::HLAAbstractLocation> _location;
415 SGSharedPtr<AbstractSimTime> _simTime;
416 SGSharedPtr<AbstractModel> _model;
417 SGSharedPtr<sg::HLAVariantArrayDataElement> _mpProperties;
418};
419
420class FGHLA::MPUpdateCallback : public sg::HLAObjectInstance::UpdateCallback {
421public:
422 virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
423 {
424 updateAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
425 objectInstance.encodeAttributeValues();
426 objectInstance.sendAttributeValues(tag);
427 }
428
429 virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const SGTimeStamp& timeStamp, const sg::RTIData& tag)
430 {
431 updateAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
432 objectInstance.encodeAttributeValues();
433 objectInstance.sendAttributeValues(timeStamp, tag);
434 }
435
437 {
438 objectInstance._simTime->setTimeStamp(globals->get_sim_time_sec());
439
440 SGGeod position = _ifce.getPosition();
441 // The quaternion rotating from the earth centered frame to the
442 // horizontal local frame
443 SGQuatd qEc2Hl = SGQuatd::fromLonLat(position);
444 SGQuatd hlOr = SGQuatd::fromYawPitchRoll(_ifce.get_Psi(), _ifce.get_Theta(), _ifce.get_Phi());
445 objectInstance._location->setCartPosition(SGVec3d::fromGeod(position));
446 objectInstance._location->setCartOrientation(qEc2Hl*hlOr);
447 // The angular velocitied in the body frame
448 double p = _ifce.get_P_body();
449 double q = _ifce.get_Q_body();
450 double r = _ifce.get_R_body();
451 objectInstance._location->setAngularBodyVelocity(SGVec3d(p, q, r));
452 // The body uvw velocities in the interface are wrt the wind instead
453 // of wrt the ec frame
454 double n = _ifce.get_V_north()*SG_FEET_TO_METER;
455 double e = _ifce.get_V_east()*SG_FEET_TO_METER;
456 double d = _ifce.get_V_down()*SG_FEET_TO_METER;
457 objectInstance._location->setLinearBodyVelocity(hlOr.transform(SGVec3d(n, e, d)));
458
459 if (objectInstance._mpProperties.valid() && objectInstance._mpProperties->getNumElements() == 0) {
460 if (objectInstance._propertyReferenceSet.valid() && objectInstance._propertyReferenceSet->getRootNode()) {
461 const sg::HLADataType* elementDataType = objectInstance._mpProperties->getElementDataType();
462 const sg::HLAVariantRecordDataType* variantRecordDataType = elementDataType->toVariantRecordDataType();
463 for (unsigned i = 0, count = 0; i < variantRecordDataType->getNumAlternatives(); ++i) {
464 std::string name = variantRecordDataType->getAlternativeSemantics(i);
465 SGPropertyNode* node = objectInstance._propertyReferenceSet->getRootNode()->getNode(name);
466 if (!node)
467 continue;
468 objectInstance._mpProperties->getOrCreateElement(count++)->setAlternativeIndex(i);
469 }
470 }
471 }
472 }
473
475};
476
477class FGHLA::MPReflectCallback : public sg::HLAObjectInstance::ReflectCallback {
478public:
479 virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance,
480 const sg::HLAIndexList& indexList, const sg::RTIData& tag)
481 {
482 objectInstance.reflectAttributeValues(indexList, tag);
483 reflectAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
484 }
485 virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::HLAIndexList& indexList,
486 const SGTimeStamp& timeStamp, const sg::RTIData& tag)
487 {
488 objectInstance.reflectAttributeValues(indexList, timeStamp, tag);
489 reflectAttributeValues(static_cast<MultiplayerObjectInstance&>(objectInstance));
490 }
491
493 {
494 // Puh, damn ordering problems with properties startup and so on
495 if (_aiMultiplayer.valid()) {
496 FGExternalMotionData motionInfo;
497 motionInfo.time = objectInstance._simTime->getTimeStamp();
498 motionInfo.lag = 0;
499
500 motionInfo.position = objectInstance._location->getCartPosition();
501 motionInfo.orientation = toQuatf(objectInstance._location->getCartOrientation());
502 motionInfo.linearVel = toVec3f(objectInstance._location->getLinearBodyVelocity());
503 motionInfo.angularVel = toVec3f(objectInstance._location->getAngularBodyVelocity());
504 motionInfo.linearAccel = SGVec3f::zeros();
505 motionInfo.angularAccel = SGVec3f::zeros();
506
507 _aiMultiplayer->addMotionInfo(motionInfo, SGTimeStamp::now().getSeconds());
508
509 } else {
510 std::string modelPath = objectInstance._model->getModelPath();
511 if (modelPath.empty())
512 return;
513 auto aiMgr = globals->get_subsystem<FGAIManager>();
514 if (!aiMgr)
515 return;
516
518 _aiMultiplayer->setPath(modelPath.c_str());
519 aiMgr->attach(_aiMultiplayer.get());
520
521 objectInstance._propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
522 }
523 }
524
525 void setDie()
526 {
527 if (!_aiMultiplayer.valid())
528 return;
529 _aiMultiplayer->setDie(true);
530 _aiMultiplayer = 0;
531 }
532
533 SGSharedPtr<FGAIMultiplayer> _aiMultiplayer;
534};
535
536class SimTimeFactory : public SGReferenced {
537public:
538 virtual ~SimTimeFactory() {}
539 virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance&) const = 0;
540};
541
542// A SimTime implementation that works with the simulation
543// time in an attribute. Used when we cannot do real time management.
545public:
546 class SimTime : public AbstractSimTime {
547 public:
548 virtual double getTimeStamp() const
549 { return _simTime; }
550 virtual void setTimeStamp(double simTime)
551 { _simTime = simTime; }
552
553 sg::HLADataElement* getDataElement()
554 { return _simTime.getDataElement(); }
555
556 private:
557 sg::HLADoubleData _simTime;
558 };
559
560 virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance& objectInstance) const
561 {
562 SimTime* simTime = new SimTime;
563 objectInstance.setAttributeDataElement(_simTimeIndex, simTime->getDataElement());
564 return simTime;
565 }
566 void setSimTimeIndex(const sg::HLADataElementIndex& simTimeIndex)
567 { _simTimeIndex = simTimeIndex; }
568
569private:
570 sg::HLADataElementIndex _simTimeIndex;
571};
572
573// A SimTime implementation that works with the simulation
574// time in two attributes like the avation sim net fom works
576public:
577 class SimTime : public AbstractSimTime {
578 public:
579 virtual double getTimeStamp() const
580 {
581 return _secSimTime + 1e-3*_msecSimTime;
582 }
583 virtual void setTimeStamp(double simTime)
584 {
585 double sec = floor(simTime);
586 _secSimTime = sec;
587 _msecSimTime = 1e3*(simTime - sec);
588 }
589
590 sg::HLADataElement* getSecDataElement()
591 { return _secSimTime.getDataElement(); }
592 sg::HLADataElement* getMSecDataElement()
593 { return _msecSimTime.getDataElement(); }
594
595 private:
596 sg::HLADoubleData _secSimTime;
597 sg::HLADoubleData _msecSimTime;
598 };
599
600 virtual AbstractSimTime* createSimTime(sg::HLAObjectInstance& objectInstance) const
601 {
602 SimTime* simTime = new SimTime;
603 objectInstance.setAttributeDataElement(_secIndex, simTime->getSecDataElement());
604 objectInstance.setAttributeDataElement(_msecIndex, simTime->getMSecDataElement());
605 return simTime;
606 }
607 void setSecIndex(const sg::HLADataElementIndex& secIndex)
608 { _secIndex = secIndex; }
609 void setMSecIndex(const sg::HLADataElementIndex& msecIndex)
610 { _msecIndex = msecIndex; }
611
612private:
613 sg::HLADataElementIndex _secIndex;
614 sg::HLADataElementIndex _msecIndex;
615};
616
617class ModelFactory : public SGReferenced {
618public:
619 virtual ~ModelFactory() {}
620 virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const = 0;
621};
622
624public:
625 class Model : public AbstractModel {
626 public:
627 virtual std::string getModelPath() const
628 { return _modelPath; }
629 virtual void setModelPath(const std::string& modelPath)
630 { _modelPath = modelPath; }
631
632 sg::HLADataElement* getDataElement()
633 { return _modelPath.getDataElement(); }
634
635 private:
636 sg::HLAStringData _modelPath;
637 };
638
639 virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const
640 {
641 Model* model = new Model;
642 objectInstance.setAttributeDataElement(_modelIndex, model->getDataElement());
643 return model;
644 }
645 void setModelIndex(const sg::HLADataElementIndex& modelIndex)
646 { _modelIndex = modelIndex; }
647
648private:
649 sg::HLADataElementIndex _modelIndex;
650};
651
653public:
654 class Model : public AbstractModel {
655 public:
656 Model(const AttributeMapModelFactory* mapModelFactory) :
657 _mapModelFactory(mapModelFactory)
658 { }
659
660 virtual std::string getModelPath() const
661 {
662 if (_modelPath.getValue().empty())
663 return _modelPath.getValue();
664 return _mapModelFactory->mapToFlightgear(_modelPath);
665 }
666 virtual void setModelPath(const std::string& modelPath)
667 { _modelPath = _mapModelFactory->mapToExternal(modelPath); }
668
669 sg::HLADataElement* getDataElement()
670 { return _modelPath.getDataElement(); }
671
672 private:
673 sg::HLAStringData _modelPath;
674 SGSharedPtr<const AttributeMapModelFactory> _mapModelFactory;
675 };
676
677 virtual AbstractModel* createModel(sg::HLAObjectInstance& objectInstance) const
678 {
679 Model* model = new Model(this);
680 objectInstance.setAttributeDataElement(_modelIndex, model->getDataElement());
681 return model;
682 }
683 void setModelIndex(const sg::HLADataElementIndex& modelIndex)
684 { _modelIndex = modelIndex; }
685
686 std::string mapToFlightgear(const std::string& externalModel) const
687 {
688 std::map<std::string,std::string>::const_iterator i;
689 i = _externalToModelPathMap.find(externalModel);
690 if (i != _externalToModelPathMap.end())
691 return i->second;
692 return "default";
693 }
694 std::string mapToExternal(const std::string& modelPath) const
695 {
696 std::map<std::string,std::string>::const_iterator i;
697 i = _modelPathToExternalMap.find(modelPath);
698 if (i != _modelPathToExternalMap.end())
699 return i->second;
700 return _externalDefault;
701 }
702
703 void setExternalDefault(const std::string& externalDefault)
704 { _externalDefault = externalDefault; }
705 void addExternalModelPathPair(const std::string& external, const std::string& modelPath)
706 {
707 _externalToModelPathMap[external] = modelPath;
708 _modelPathToExternalMap[modelPath] = external;
709 }
710
711private:
712 sg::HLADataElementIndex _modelIndex;
713
714 std::map<std::string,std::string> _externalToModelPathMap;
715 std::map<std::string,std::string> _modelPathToExternalMap;
716 std::string _externalDefault;
717};
718
719class FGHLA::MultiplayerObjectClass : public sg::HLAObjectClass {
720public:
721 MultiplayerObjectClass(const std::string& name, sg::HLAFederate* federate) :
722 HLAObjectClass(name, federate)
723 { }
725 { }
726
728 { return new MultiplayerObjectInstance(this); }
729
730 virtual void discoverInstance(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
731 {
732 HLAObjectClass::discoverInstance(objectInstance, tag);
733 MPReflectCallback* reflectCallback = new MPReflectCallback;
734 objectInstance.setReflectCallback(reflectCallback);
735 attachDataElements(static_cast<MultiplayerObjectInstance&>(objectInstance), false);
736 }
737 virtual void removeInstance(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
738 {
739 HLAObjectClass::removeInstance(objectInstance, tag);
740 MPReflectCallback* reflectCallback;
741 reflectCallback = dynamic_cast<MPReflectCallback*>(objectInstance.getReflectCallback().get());
742 if (!reflectCallback) {
743 SG_LOG(SG_IO, SG_WARN, "HLA: expected to have a different attribute callback in remove instance.");
744 return;
745 }
746 reflectCallback->setDie();
747 }
748 virtual void registerInstance(sg::HLAObjectInstance& objectInstance)
749 {
750 HLAObjectClass::registerInstance(objectInstance);
751 MPUpdateCallback* updateCallback = new MPUpdateCallback;
752 objectInstance.setUpdateCallback(updateCallback);
753 MultiplayerObjectInstance& mpObjectInstance = static_cast<MultiplayerObjectInstance&>(objectInstance);
754 attachDataElements(mpObjectInstance, true);
755 mpObjectInstance._model->setModelPath(fgGetString("/sim/model/path", "default"));
756 mpObjectInstance._propertyReferenceSet->setRootNode(fgGetNode("/", true));
757 }
758 virtual void deleteInstance(sg::HLAObjectInstance& objectInstance)
759 {
760 HLAObjectClass::deleteInstance(objectInstance);
761 }
762
763 virtual void createAttributeDataElements(sg::HLAObjectInstance& objectInstance)
764 {
765 sg::HLAObjectClass::createAttributeDataElements(objectInstance);
766 }
767
768 void setLocationFactory(sg::HLALocationFactory* locationFactory)
769 { _locationFactory = locationFactory; }
770 sg::HLALocationFactory* getLocationFactory()
771 { return _locationFactory.get(); }
772
773 void setSimTimeFactory(SimTimeFactory* simTimeFactory)
774 { _simTimeFactory = simTimeFactory; }
776 { return _simTimeFactory.get(); }
777
778 void setModelFactory(ModelFactory* modelFactory)
779 { _modelFactory = modelFactory; }
781 { return _modelFactory.get(); }
782
783 void setMPPropertiesIndex(const sg::HLADataElementIndex& index)
784 { _mpPropertiesIndex = index; }
785 const sg::HLADataElementIndex& getMPPropertiesIndex() const
786 { return _mpPropertiesIndex; }
787
788 void setInputProperty(const sg::HLADataElementIndex& index, const std::string& property)
789 {
790 _inputProperties[index] = property;
791 }
792 void setOutputProperty(const sg::HLADataElementIndex& index, const std::string& property)
793 {
794 _outputProperties[index] = property;
795 }
796
797private:
798 void attachDataElements(MultiplayerObjectInstance& objectInstance, bool outgoing)
799 {
800 objectInstance.setAttributeDataElement(_mpPropertiesIndex, objectInstance._mpProperties.get());
801
802 if (_locationFactory.valid())
803 objectInstance._location = _locationFactory->createLocation(objectInstance);
804 if (_modelFactory.valid())
805 objectInstance._model = _modelFactory->createModel(objectInstance);
806 if (_simTimeFactory.valid())
807 objectInstance._simTime = _simTimeFactory->createSimTime(objectInstance);
808
809 if (outgoing)
810 attachPropertyDataElements(*objectInstance._propertyReferenceSet,
811 objectInstance, _outputProperties);
812 else
813 attachPropertyDataElements(*objectInstance._propertyReferenceSet,
814 objectInstance, _inputProperties);
815 }
816 typedef std::map<sg::HLADataElementIndex, std::string> IndexPropertyMap;
817
818 void attachPropertyDataElements(PropertyReferenceSet& propertyReferenceSet,
819 sg::HLAObjectInstance& objectInstance,
820 const IndexPropertyMap& attributePathPropertyMap)
821 {
822 for (IndexPropertyMap::const_iterator i = attributePathPropertyMap.begin();
823 i != attributePathPropertyMap.end(); ++i) {
824 sg::HLAPropertyDataElement* dataElement = new sg::HLAPropertyDataElement;
825 propertyReferenceSet.insert(i->second, dataElement);
826 objectInstance.setAttributeDataElement(i->first, dataElement);
827 }
828 }
829
830 IndexPropertyMap _inputProperties;
831 IndexPropertyMap _outputProperties;
832
833 SGSharedPtr<sg::HLALocationFactory> _locationFactory;
834 SGSharedPtr<SimTimeFactory> _simTimeFactory;
835 SGSharedPtr<ModelFactory> _modelFactory;
836
837 sg::HLADataElementIndex _mpPropertiesIndex;
838};
839
840class FGHLA::Federate : public sg::HLAFederate {
841public:
842 virtual ~Federate()
843 { }
844 virtual bool readObjectModel()
845 { return readRTI1516ObjectModelTemplate(getFederationObjectModel()); }
846
847 virtual sg::HLAObjectClass* createObjectClass(const std::string& name)
848 {
851 if (_localAircraftClass.valid()) {
852 return new MultiplayerObjectClass(name, this);
853 } else {
855 return _localAircraftClass.get();
856 }
857 } else {
858 return 0;
859 }
860 }
861
863 {
864 // First push our own data so that others can recieve ...
865 if (!_localAircraftClass.valid())
866 return;
867 if (!_localAircraftInstance.valid()) {
869 _localAircraftInstance->registerInstance();
870 }
871 _localAircraftInstance->updateAttributeValues(sg::RTIData("MPAircraft"));
872 }
873
874 virtual bool shutdown()
875 {
876 if (_localAircraftInstance.valid()) {
877 // Remove the local object from the rti
878 _localAircraftInstance->deleteInstance(simgear::RTIData("gone"));
880 }
881 return HLAFederate::shutdown();
882 }
883
884 std::list<std::string> _multiplayerObjectClassNames;
886 SGSharedPtr<MultiplayerObjectClass> _localAircraftClass;
888 SGSharedPtr<MultiplayerObjectInstance> _localAircraftInstance;
889};
890
891FGHLA::FGHLA(const std::vector<std::string>& tokens) :
892 _hlaFederate(new Federate)
893{
894 if (1 < tokens.size() && !tokens[1].empty())
895 set_direction(tokens[1]);
896 else
897 set_direction("bi");
898
899 int rate = 60;
900 if (2 < tokens.size() && !tokens[2].empty()) {
901 std::stringstream ss(tokens[2]);
902 ss >> rate;
903 }
904 set_hz(rate);
905
906 if (3 < tokens.size() && !tokens[3].empty())
907 _federate = tokens[3];
908 else
909 _federate = fgGetString("/sim/user/callsign");
910
911 if (4 < tokens.size() && !tokens[4].empty())
912 _federation = tokens[4];
913 else
914 _federation = "FlightGear";
915
916 if (5 < tokens.size() && !tokens[5].empty())
917 _objectModelConfig = tokens[5];
918 else
919 _objectModelConfig = "mp-aircraft.xml";
920}
921
923{
924}
925
926bool
928{
929 if (is_enabled()) {
930 SG_LOG(SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
931 "is already in use, ignoring");
932 return false;
933 }
934
935 if (_federation.empty()) {
936 SG_LOG(SG_IO, SG_ALERT, "No federation to join given to "
937 "the HLA module");
938 return false;
939 }
940
941 if (_federate.empty()) {
942 SG_LOG(SG_IO, SG_ALERT, "No federate name given to the HLA module");
943 return false;
944 }
945
946 if (!SGPath(_objectModelConfig).exists()) {
947 SGPath path(globals->get_fg_root());
948 path.append("HLA");
949 path.append(_objectModelConfig);
950 if (path.exists())
951 _objectModelConfig = path.str();
952 else {
953 SG_LOG(SG_IO, SG_ALERT, "Federate object model configuration \""
954 << _objectModelConfig << "\" does not exist.");
955 return false;
956 }
957 }
958
959 XMLConfigReader configReader;
960 try {
961 readXML(_objectModelConfig, configReader);
962 } catch (const sg_throwable& e) {
963 SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file: "
964 << e.getMessage());
965 return false;
966 } catch (...) {
967 SG_LOG(SG_IO, SG_ALERT, "Could not open HLA configuration file");
968 return false;
969 }
970
971 // Flightgears hla configuration
972 std::string objectModel = configReader.getFederateObjectModel();
973 if (objectModel.empty()) {
974 SG_LOG(SG_IO, SG_ALERT, "No federate object model given to "
975 "the HLA module");
976 return false;
977 }
978 if (!SGPath(objectModel).exists()) {
979 SGPath path(SGPath(_objectModelConfig).dir());
980 path.append(objectModel);
981 if (path.exists())
982 objectModel = path.str();
983 else {
984 SG_LOG(SG_IO, SG_ALERT, "Federate object model file \""
985 << objectModel << "\" does not exist.");
986 return false;
987 }
988 }
989
990 // We need that to communicate to the rti
991 switch (configReader.getRTIVersion()) {
992 case RTI13:
993 _hlaFederate->setVersion(simgear::HLAFederate::RTI13);
994 break;
995 case RTI1516:
996 _hlaFederate->setVersion(simgear::HLAFederate::RTI1516);
997 break;
998 case RTI1516E:
999 _hlaFederate->setVersion(simgear::HLAFederate::RTI1516E);
1000 break;
1001 }
1002 _hlaFederate->setConnectArguments(configReader.getRTIArguments());
1003 _hlaFederate->setFederationExecutionName(_federation);
1004 _hlaFederate->setFederationObjectModel(objectModel);
1005 _hlaFederate->setFederateType(_federate);
1006
1007 // Store the multiplayer class name in the federate
1008 XMLConfigReader::ObjectClassConfigList::const_iterator i;
1009 for (i = configReader.getObjectClassConfigList().begin();
1010 i != configReader.getObjectClassConfigList().end(); ++i) {
1011
1012 if (i->_type != "Multiplayer") {
1013 SG_LOG(SG_IO, SG_ALERT, "Ignoring unknown object class type \"" << i->_type << "\"!");
1014 continue;
1015 }
1016
1017 // Register the object class that we need for this simple hla implementation
1018 _hlaFederate->_multiplayerObjectClassNames.push_back(i->_name);
1019 }
1020
1021
1022 // Now that it is paramtrized, connect/join
1023 if (!_hlaFederate->init()) {
1024 SG_LOG(SG_IO, SG_ALERT, "Could not init the hla/rti connect.");
1025 return false;
1026 }
1027
1028 // bool publish = get_direction() & SG_IO_OUT;
1029 // bool subscribe = get_direction() & SG_IO_IN;
1030
1031 // Interpret the configuration file
1032 for (i = configReader.getObjectClassConfigList().begin();
1033 i != configReader.getObjectClassConfigList().end(); ++i) {
1034
1036 if (i->_type != "Multiplayer")
1037 continue;
1038
1040 SGSharedPtr<MultiplayerObjectClass> objectClass;
1041
1042 // Register the object class that we need for this simple hla implementation
1043 std::string aircraftClassName = i->_name;
1044 objectClass = dynamic_cast<MultiplayerObjectClass*>(_hlaFederate->getObjectClass(aircraftClassName));
1045 if (!objectClass.valid()) {
1046 SG_LOG(SG_IO, SG_ALERT, "Could not find " << aircraftClassName << " object class!");
1047 continue;
1048 }
1049
1050 SGSharedPtr<MultiplayerObjectClass> mpClassCallback = objectClass;
1051
1052 if (i->_positionConfig._type == "cartesian") {
1053 SGSharedPtr<sg::HLACartesianLocationFactory> locationFactory;
1054 locationFactory = new sg::HLACartesianLocationFactory;
1055 XMLConfigReader::DataElementList::const_iterator j;
1056 for (j = i->_positionConfig._dataElementList.begin();
1057 j != i->_positionConfig._dataElementList.end(); ++j) {
1058
1059 if (j->_type == "position-x")
1060 locationFactory->setPositionIndex(0, objectClass->getDataElementIndex(j->_name));
1061 else if (j->_type == "position-y")
1062 locationFactory->setPositionIndex(1, objectClass->getDataElementIndex(j->_name));
1063 else if (j->_type == "position-z")
1064 locationFactory->setPositionIndex(2, objectClass->getDataElementIndex(j->_name));
1065
1066 else if (j->_type == "orientation-sin-angle-axis-x")
1067 locationFactory->setOrientationIndex(0, objectClass->getDataElementIndex(j->_name));
1068 else if (j->_type == "orientation-sin-angle-axis-y")
1069 locationFactory->setOrientationIndex(1, objectClass->getDataElementIndex(j->_name));
1070 else if (j->_type == "orientation-sin-angle-axis-z")
1071 locationFactory->setOrientationIndex(2, objectClass->getDataElementIndex(j->_name));
1072
1073 else if (j->_type == "angular-velocity-x")
1074 locationFactory->setAngularVelocityIndex(0, objectClass->getDataElementIndex(j->_name));
1075 else if (j->_type == "angular-velocity-y")
1076 locationFactory->setAngularVelocityIndex(1, objectClass->getDataElementIndex(j->_name));
1077 else if (j->_type == "angular-velocity-z")
1078 locationFactory->setAngularVelocityIndex(2, objectClass->getDataElementIndex(j->_name));
1079
1080 else if (j->_type == "linear-velocity-x")
1081 locationFactory->setLinearVelocityIndex(0, objectClass->getDataElementIndex(j->_name));
1082 else if (j->_type == "linear-velocity-y")
1083 locationFactory->setLinearVelocityIndex(1, objectClass->getDataElementIndex(j->_name));
1084 else if (j->_type == "linear-velocity-z")
1085 locationFactory->setLinearVelocityIndex(2, objectClass->getDataElementIndex(j->_name));
1086
1087 else {
1088 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1089 << j->_type << "\"for object class \"" << aircraftClassName << "\". Ignoring!");
1090 }
1091 }
1092
1093 mpClassCallback->setLocationFactory(locationFactory.get());
1094 } else if (i->_positionConfig._type == "geodetic") {
1095 SGSharedPtr<sg::HLAGeodeticLocationFactory> locationFactory;
1096 locationFactory = new sg::HLAGeodeticLocationFactory;
1097
1098 XMLConfigReader::DataElementList::const_iterator j;
1099 for (j = i->_positionConfig._dataElementList.begin();
1100 j != i->_positionConfig._dataElementList.end(); ++j) {
1101
1102 if (j->_type == "latitude-deg")
1103 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LatitudeDeg,
1104 objectClass->getDataElementIndex(j->_name));
1105 else if (j->_type == "latitude-rad")
1106 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LatitudeRad,
1107 objectClass->getDataElementIndex(j->_name));
1108 else if (j->_type == "longitude-deg")
1109 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LongitudeDeg,
1110 objectClass->getDataElementIndex(j->_name));
1111 else if (j->_type == "longitude-rad")
1112 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::LongitudeRad,
1113 objectClass->getDataElementIndex(j->_name));
1114 else if (j->_type == "elevation-m")
1115 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::ElevationM,
1116 objectClass->getDataElementIndex(j->_name));
1117 else if (j->_type == "elevation-m")
1118 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::ElevationFt,
1119 objectClass->getDataElementIndex(j->_name));
1120 else if (j->_type == "heading-deg")
1121 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::HeadingDeg,
1122 objectClass->getDataElementIndex(j->_name));
1123 else if (j->_type == "heading-rad")
1124 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::HeadingRad,
1125 objectClass->getDataElementIndex(j->_name));
1126 else if (j->_type == "pitch-deg")
1127 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::PitchDeg,
1128 objectClass->getDataElementIndex(j->_name));
1129 else if (j->_type == "pitch-rad")
1130 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::PitchRad,
1131 objectClass->getDataElementIndex(j->_name));
1132 else if (j->_type == "roll-deg")
1133 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::RollDeg,
1134 objectClass->getDataElementIndex(j->_name));
1135 else if (j->_type == "roll-rad")
1136 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::RollRad,
1137 objectClass->getDataElementIndex(j->_name));
1138 else if (j->_type == "ground-track-deg")
1139 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundTrackDeg,
1140 objectClass->getDataElementIndex(j->_name));
1141 else if (j->_type == "ground-track-rad")
1142 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundTrackRad,
1143 objectClass->getDataElementIndex(j->_name));
1144 else if (j->_type == "ground-speed-kt")
1145 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedKnots,
1146 objectClass->getDataElementIndex(j->_name));
1147 else if (j->_type == "ground-speed-ft-per-sec")
1148 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedFtPerSec,
1149 objectClass->getDataElementIndex(j->_name));
1150 else if (j->_type == "ground-speed-m-per-sec")
1151 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::GroundSpeedMPerSec,
1152 objectClass->getDataElementIndex(j->_name));
1153 else if (j->_type == "vertical-speed-ft-per-sec")
1154 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerSec,
1155 objectClass->getDataElementIndex(j->_name));
1156 else if (j->_type == "vertical-speed-ft-per-min")
1157 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedFtPerMin,
1158 objectClass->getDataElementIndex(j->_name));
1159 else if (j->_type == "vertical-speed-m-per-sec")
1160 locationFactory->setIndex(sg::HLAGeodeticLocationFactory::VerticalSpeedMPerSec,
1161 objectClass->getDataElementIndex(j->_name));
1162 else {
1163 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown position configuration type \""
1164 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1165 }
1166 }
1167
1168 mpClassCallback->setLocationFactory(locationFactory.get());
1169 }
1170
1171 if (i->_modelConfig._type == "native") {
1172 SGSharedPtr<AttributeModelFactory> attributeModelFactory;
1173 attributeModelFactory = new AttributeModelFactory;
1174
1175 XMLConfigReader::DataElementList::const_iterator j;
1176 for (j = i->_modelConfig._dataElementList.begin();
1177 j != i->_modelConfig._dataElementList.end(); ++j) {
1178
1179 if (j->_type == "model-path")
1180 attributeModelFactory->setModelIndex(objectClass->getDataElementIndex(j->_name));
1181
1182 else {
1183 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1184 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1185 }
1186 }
1187
1188 mpClassCallback->setModelFactory(attributeModelFactory.get());
1189 } else if (i->_modelConfig._type == "map") {
1190
1191 SGSharedPtr<AttributeMapModelFactory> attributeModelFactory;
1192 attributeModelFactory = new AttributeMapModelFactory;
1193
1194 XMLConfigReader::DataElementList::const_iterator j;
1195 for (j = i->_modelConfig._dataElementList.begin();
1196 j != i->_modelConfig._dataElementList.end(); ++j) {
1197
1198 if (j->_type == "external")
1199 attributeModelFactory->setModelIndex(objectClass->getDataElementIndex(j->_name));
1200
1201 else {
1202 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1203 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1204 }
1205 }
1206
1207 std::list<std::pair<std::string, std::string> >::const_iterator k;
1208 for (k = i->_modelConfig._modelMap.begin();
1209 k != i->_modelConfig._modelMap.end(); ++k) {
1210
1211 if (k->second.empty())
1212 attributeModelFactory->setExternalDefault(k->first);
1213 else
1214 attributeModelFactory->addExternalModelPathPair(k->first, k->second);
1215 }
1216
1217 mpClassCallback->setModelFactory(attributeModelFactory.get());
1218
1219 } else {
1220 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown model configuration type \""
1221 << i->_modelConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1222 }
1223
1224 if (i->_simTimeConfig._type == "attribute") {
1225 SGSharedPtr<AttributeSimTimeFactory> attributeSimTimeFactory;
1226 attributeSimTimeFactory = new AttributeSimTimeFactory;
1227
1228 XMLConfigReader::DataElementList::const_iterator j;
1229 for (j = i->_simTimeConfig._dataElementList.begin();
1230 j != i->_simTimeConfig._dataElementList.end(); ++j) {
1231
1232 if (j->_type == "local-simtime")
1233 attributeSimTimeFactory->setSimTimeIndex(objectClass->getDataElementIndex(j->_name));
1234 else {
1235 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1236 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1237 }
1238 }
1239
1240 mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1241 } else if (i->_simTimeConfig._type == "attribute-sec-msec") {
1242 SGSharedPtr<MSecAttributeSimTimeFactory> attributeSimTimeFactory;
1243 attributeSimTimeFactory = new MSecAttributeSimTimeFactory;
1244
1245 XMLConfigReader::DataElementList::const_iterator j;
1246 for (j = i->_simTimeConfig._dataElementList.begin();
1247 j != i->_simTimeConfig._dataElementList.end(); ++j) {
1248
1249 if (j->_type == "local-simtime-sec")
1250 attributeSimTimeFactory->setSecIndex(objectClass->getDataElementIndex(j->_name));
1251 else if (j->_type == "local-simtime-msec")
1252 attributeSimTimeFactory->setMSecIndex(objectClass->getDataElementIndex(j->_name));
1253 else {
1254 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1255 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1256 }
1257 }
1258
1259 mpClassCallback->setSimTimeFactory(attributeSimTimeFactory.get());
1260 } else {
1261 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown simtime configuration type \""
1262 << i->_simTimeConfig._type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1263 }
1264
1265 if (!i->_mpPropertiesConfig._name.empty()) {
1266 mpClassCallback->setMPPropertiesIndex(objectClass->getDataElementIndex(i->_mpPropertiesConfig._name));
1267 }
1268
1269 // The free configurabel property - dataElement mapping
1270 XMLConfigReader::DataElementList::const_iterator j;
1271 for (j = i->_dataElementList.begin();
1272 j != i->_dataElementList.end(); ++j) {
1273
1274 if (j->_type == "property") {
1275 if (!j->_inProperty.empty())
1276 mpClassCallback->setInputProperty(objectClass->getDataElementIndex(j->_name), j->_inProperty);
1277 if (!j->_outProperty.empty())
1278 mpClassCallback->setOutputProperty(objectClass->getDataElementIndex(j->_name), j->_outProperty);
1279 } else {
1280 SG_LOG(SG_IO, SG_ALERT, "HLA: Unknown dataElement configuration type \""
1281 << j->_type << "\" for object class \"" << aircraftClassName << "\". Ignoring!");
1282 }
1283 }
1284 }
1285
1286 set_enabled(true);
1287 return is_enabled();
1288}
1289
1290bool
1292{
1293 if (!is_enabled())
1294 return false;
1295
1296 if (!_hlaFederate.valid())
1297 return false;
1298
1299 // First push our own data so that others can recieve ...
1300 if (get_direction() & SG_IO_OUT)
1301 _hlaFederate->updateLocalAircraftInstance();
1302
1303 // Then get news from others and process possible update requests
1304 _hlaFederate->update();
1305
1306 return true;
1307}
1308
1309bool
1311{
1312 if (!is_enabled())
1313 return false;
1314
1315 if (!_hlaFederate.valid())
1316 return false;
1317
1318 // Leave the federation and try to destroy the federation execution.
1319 _hlaFederate->shutdown();
1320 _hlaFederate = 0;
1321
1322 set_enabled(false);
1323
1324 return true;
1325}
1326
#define p(x)
#define i(x)
virtual void setModelPath(const std::string &)=0
virtual ~AbstractModel()
Definition hla.cxx:364
virtual std::string getModelPath() const =0
virtual double getTimeStamp() const =0
virtual ~AbstractSimTime()
Definition hla.cxx:356
virtual void setTimeStamp(double)=0
virtual std::string getModelPath() const
Definition hla.cxx:660
sg::HLADataElement * getDataElement()
Definition hla.cxx:669
Model(const AttributeMapModelFactory *mapModelFactory)
Definition hla.cxx:656
virtual void setModelPath(const std::string &modelPath)
Definition hla.cxx:666
void addExternalModelPathPair(const std::string &external, const std::string &modelPath)
Definition hla.cxx:705
std::string mapToFlightgear(const std::string &externalModel) const
Definition hla.cxx:686
virtual AbstractModel * createModel(sg::HLAObjectInstance &objectInstance) const
Definition hla.cxx:677
std::string mapToExternal(const std::string &modelPath) const
Definition hla.cxx:694
void setExternalDefault(const std::string &externalDefault)
Definition hla.cxx:703
void setModelIndex(const sg::HLADataElementIndex &modelIndex)
Definition hla.cxx:683
sg::HLADataElement * getDataElement()
Definition hla.cxx:632
virtual void setModelPath(const std::string &modelPath)
Definition hla.cxx:629
virtual std::string getModelPath() const
Definition hla.cxx:627
void setModelIndex(const sg::HLADataElementIndex &modelIndex)
Definition hla.cxx:645
virtual AbstractModel * createModel(sg::HLAObjectInstance &objectInstance) const
Definition hla.cxx:639
sg::HLADataElement * getDataElement()
Definition hla.cxx:553
virtual void setTimeStamp(double simTime)
Definition hla.cxx:550
virtual double getTimeStamp() const
Definition hla.cxx:548
virtual AbstractSimTime * createSimTime(sg::HLAObjectInstance &objectInstance) const
Definition hla.cxx:560
void setSimTimeIndex(const sg::HLADataElementIndex &simTimeIndex)
Definition hla.cxx:566
std::list< std::string > _multiplayerObjectClassNames
Definition hla.cxx:884
void updateLocalAircraftInstance()
Definition hla.cxx:862
virtual bool readObjectModel()
Definition hla.cxx:844
SGSharedPtr< MultiplayerObjectClass > _localAircraftClass
This class is used to register the local instance and to subscribe for others.
Definition hla.cxx:886
virtual sg::HLAObjectClass * createObjectClass(const std::string &name)
Definition hla.cxx:847
SGSharedPtr< MultiplayerObjectInstance > _localAircraftInstance
The local aircraft instance.
Definition hla.cxx:888
virtual bool shutdown()
Definition hla.cxx:874
virtual ~Federate()
Definition hla.cxx:842
SGSharedPtr< FGAIMultiplayer > _aiMultiplayer
Definition hla.cxx:533
void reflectAttributeValues(MultiplayerObjectInstance &objectInstance)
Definition hla.cxx:492
virtual void reflectAttributeValues(sg::HLAObjectInstance &objectInstance, const sg::HLAIndexList &indexList, const sg::RTIData &tag)
Definition hla.cxx:479
virtual void reflectAttributeValues(sg::HLAObjectInstance &objectInstance, const sg::HLAIndexList &indexList, const SGTimeStamp &timeStamp, const sg::RTIData &tag)
Definition hla.cxx:485
FlightProperties _ifce
Definition hla.cxx:474
virtual void updateAttributeValues(sg::HLAObjectInstance &objectInstance, const SGTimeStamp &timeStamp, const sg::RTIData &tag)
Definition hla.cxx:429
virtual void updateAttributeValues(sg::HLAObjectInstance &objectInstance, const sg::RTIData &tag)
Definition hla.cxx:422
void updateAttributeValues(MultiplayerObjectInstance &objectInstance)
Definition hla.cxx:436
MultiplayerObjectClass(const std::string &name, sg::HLAFederate *federate)
Definition hla.cxx:721
const sg::HLADataElementIndex & getMPPropertiesIndex() const
Definition hla.cxx:785
SimTimeFactory * getSimTimeFactory()
Definition hla.cxx:775
virtual void removeInstance(sg::HLAObjectInstance &objectInstance, const sg::RTIData &tag)
Definition hla.cxx:737
void setMPPropertiesIndex(const sg::HLADataElementIndex &index)
Definition hla.cxx:783
void setOutputProperty(const sg::HLADataElementIndex &index, const std::string &property)
Definition hla.cxx:792
sg::HLALocationFactory * getLocationFactory()
Definition hla.cxx:770
virtual void registerInstance(sg::HLAObjectInstance &objectInstance)
Definition hla.cxx:748
void setInputProperty(const sg::HLADataElementIndex &index, const std::string &property)
Definition hla.cxx:788
void setLocationFactory(sg::HLALocationFactory *locationFactory)
Definition hla.cxx:768
virtual ~MultiplayerObjectClass()
Definition hla.cxx:724
virtual void deleteInstance(sg::HLAObjectInstance &objectInstance)
Definition hla.cxx:758
virtual MultiplayerObjectInstance * createObjectInstance(const std::string &name)
Definition hla.cxx:727
virtual void discoverInstance(sg::HLAObjectInstance &objectInstance, const sg::RTIData &tag)
Definition hla.cxx:730
void setModelFactory(ModelFactory *modelFactory)
Definition hla.cxx:778
ModelFactory * getModelFactory()
Definition hla.cxx:780
void setSimTimeFactory(SimTimeFactory *simTimeFactory)
Definition hla.cxx:773
virtual void createAttributeDataElements(sg::HLAObjectInstance &objectInstance)
Definition hla.cxx:763
MultiplayerObjectInstance(sg::HLAObjectClass *objectClass)
Definition hla.cxx:403
SGSharedPtr< sg::HLAVariantArrayDataElement > _mpProperties
Definition hla.cxx:417
SGSharedPtr< PropertyReferenceSet > _propertyReferenceSet
Definition hla.cxx:413
SGSharedPtr< AbstractModel > _model
Definition hla.cxx:416
SGSharedPtr< sg::HLAAbstractLocation > _location
Definition hla.cxx:414
SGSharedPtr< AbstractSimTime > _simTime
Definition hla.cxx:415
std::list< DataElement > DataElementList
Definition hla.cxx:89
HLAVersion getRTIVersion() const
Definition hla.cxx:78
std::string getAttribute(const char *name, const XMLAttributes &atts)
Definition hla.cxx:279
const std::list< std::string > & getRTIArguments() const
Definition hla.cxx:80
virtual void endXML()
Definition hla.cxx:125
virtual void endElement(const char *name)
Definition hla.cxx:274
const ObjectClassConfigList & getObjectClassConfigList() const
Definition hla.cxx:117
std::string getAttribute(const std::string &name, const XMLAttributes &atts)
Definition hla.cxx:286
virtual void startXML()
Definition hla.cxx:121
virtual void data(const char *s, int length)
Definition hla.cxx:267
virtual void startElement(const char *name, const XMLAttributes &atts)
Definition hla.cxx:129
std::list< ObjectClassConfig > ObjectClassConfigList
Definition hla.cxx:115
const std::string & getFederateObjectModel() const
Definition hla.cxx:75
virtual bool close()
Definition hla.cxx:1310
FGHLA(const std::vector< std::string > &tokens)
Definition hla.cxx:891
virtual bool process()
Definition hla.cxx:1291
virtual ~FGHLA()
Definition hla.cxx:922
virtual bool open()
Definition hla.cxx:927
SGProtocolDir get_direction() const
Definition protocol.hxx:65
void set_hz(double t)
Definition protocol.hxx:69
void set_enabled(const bool b)
Definition protocol.hxx:88
void set_direction(const std::string &d)
Definition protocol.cxx:111
bool is_enabled() const
Definition protocol.hxx:87
Encapsulate the FDM properties in some getter/setter helpers.
virtual sg::HLADataElement * createElement(const sg::HLAVariantRecordDataElement &variantRecordDataElement, unsigned index)
Definition hla.cxx:378
MPPropertyVariantRecordDataElementFactory(PropertyReferenceSet *propertyReferenceSet)
Definition hla.cxx:374
virtual void setTimeStamp(double simTime)
Definition hla.cxx:583
virtual double getTimeStamp() const
Definition hla.cxx:579
sg::HLADataElement * getSecDataElement()
Definition hla.cxx:590
sg::HLADataElement * getMSecDataElement()
Definition hla.cxx:592
void setMSecIndex(const sg::HLADataElementIndex &msecIndex)
Definition hla.cxx:609
void setSecIndex(const sg::HLADataElementIndex &secIndex)
Definition hla.cxx:607
virtual AbstractSimTime * createSimTime(sg::HLAObjectInstance &objectInstance) const
Definition hla.cxx:600
virtual ~ModelFactory()
Definition hla.cxx:619
virtual AbstractModel * createModel(sg::HLAObjectInstance &objectInstance) const =0
void setRootNode(SGPropertyNode *rootNode)
Definition hla.cxx:335
void insert(const std::string &relativePath, const SGSharedPtr< sg::HLAPropertyDataElement > &dataElement)
Definition hla.cxx:328
SGPropertyNode * getRootNode()
Definition hla.cxx:343
virtual ~SimTimeFactory()
Definition hla.cxx:538
virtual AbstractSimTime * createSimTime(sg::HLAObjectInstance &) const =0
const char * name
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
Definition fg_props.cxx:556
FGGlobals * globals
Definition globals.cxx:142
HLAVersion
Definition hla.cxx:63
@ RTI13
Definition hla.cxx:64
@ RTI1516E
Definition hla.cxx:66
@ RTI1516
Definition hla.cxx:65
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27
std::list< std::pair< std::string, std::string > > _modelMap
Definition hla.cxx:93
DataElementList _dataElementList
Definition hla.cxx:92
MPPropertiesConfig _mpPropertiesConfig
Definition hla.cxx:112