]> git.mxchange.org Git - simgear.git/blob - simgear/hla/HLAObjectInstance.cxx
56ccf78e556640f5d209108f5877e715ce2cd68d
[simgear.git] / simgear / hla / HLAObjectInstance.cxx
1 // Copyright (C) 2009 - 2012  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 "HLAObjectInstance.hxx"
19
20 #include <algorithm>
21 #include "simgear/debug/logstream.hxx"
22 #include "HLAArrayDataElement.hxx"
23 #include "HLABasicDataElement.hxx"
24 #include "HLADataElement.hxx"
25 #include "HLAEnumeratedDataElement.hxx"
26 #include "HLAFederate.hxx"
27 #include "HLAFixedRecordDataElement.hxx"
28 #include "HLAObjectClass.hxx"
29 #include "HLAVariantRecordDataElement.hxx"
30 #include "RTIObjectClass.hxx"
31 #include "RTIObjectInstance.hxx"
32
33 namespace simgear {
34
35 HLAObjectInstance::UpdateCallback::~UpdateCallback()
36 {
37 }
38
39 HLAObjectInstance::ReflectCallback::~ReflectCallback()
40 {
41 }
42
43 HLAObjectInstance::HLAObjectInstance(HLAObjectClass* objectClass) :
44     _federate(objectClass->_federate),
45     _objectClass(objectClass)
46 {
47 }
48
49 HLAObjectInstance::~HLAObjectInstance()
50 {
51     _clearRTIObjectInstance();
52 }
53
54 const std::string&
55 HLAObjectInstance::getName() const
56 {
57     return _name;
58 }
59
60 const SGWeakPtr<HLAFederate>&
61 HLAObjectInstance::getFederate() const
62 {
63     return _federate;
64 }
65
66 const SGSharedPtr<HLAObjectClass>&
67 HLAObjectInstance::getObjectClass() const
68 {
69     return _objectClass;
70 }
71
72 unsigned
73 HLAObjectInstance::getNumAttributes() const
74 {
75     return _objectClass->getNumAttributes();
76 }
77
78 unsigned
79 HLAObjectInstance::getAttributeIndex(const std::string& name) const
80 {
81     return _objectClass->getAttributeIndex(name);
82 }
83
84 std::string
85 HLAObjectInstance::getAttributeName(unsigned index) const
86 {
87     return _objectClass->getAttributeName(index);
88 }
89
90 bool
91 HLAObjectInstance::getAttributeOwned(unsigned index) const
92 {
93     if (!_rtiObjectInstance.valid())
94         return false;
95     return _rtiObjectInstance->getAttributeOwned(index);
96 }
97
98 const HLADataType*
99 HLAObjectInstance::getAttributeDataType(unsigned index) const
100 {
101     return _objectClass->getAttributeDataType(index);
102 }
103
104 HLADataElement*
105 HLAObjectInstance::getAttributeDataElement(unsigned index)
106 {
107     if (_attributeVector.size() <= index)
108         return 0;
109     return _attributeVector[index]._dataElement.get();
110 }
111
112 const HLADataElement*
113 HLAObjectInstance::getAttributeDataElement(unsigned index) const
114 {
115     if (_attributeVector.size() <= index)
116         return 0;
117     return _attributeVector[index]._dataElement.get();
118 }
119
120 bool
121 HLAObjectInstance::getAttributeData(unsigned index, RTIData& data) const
122 {
123     if (!_rtiObjectInstance.valid()) {
124         SG_LOG(SG_IO, SG_ALERT, "Trying to get raw attribute data without rti object instance for \"" << getName() << "\"!");
125         return false;
126     }
127     return _rtiObjectInstance->getAttributeData(index, data);
128 }
129
130 void
131 HLAObjectInstance::setAttributeDataElement(unsigned index, const SGSharedPtr<HLADataElement>& dataElement)
132 {
133     unsigned numAttributes = getNumAttributes();
134     if (numAttributes <= index)
135         return;
136     _attributeVector.resize(numAttributes);
137     if (_attributeVector[index]._dataElement.valid())
138         _attributeVector[index]._dataElement->clearStamp();
139     _attributeVector[index]._dataElement = dataElement;
140     if (_attributeVector[index]._dataElement.valid())
141         _attributeVector[index]._dataElement->createStamp();
142 }
143
144 class HLAObjectInstance::DataElementFactoryVisitor : public HLADataElementFactoryVisitor {
145 public:
146     DataElementFactoryVisitor(const HLAPathElementMap& pathElementMap) :
147         _pathElementMap(pathElementMap)
148     { }
149     DataElementFactoryVisitor(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
150         _pathElementMap(pathElementMap),
151         _path(path)
152     { }
153     virtual ~DataElementFactoryVisitor() {}
154
155     virtual void apply(const HLADataType& dataType)
156     {
157         _dataElement = createDataElement(_path, dataType);
158         if (_dataElement.valid())
159             return;
160
161         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Can not find a suitable data element for data type \""
162                << dataType.getName() << "\"");
163     }
164
165     virtual void apply(const HLAInt8DataType& dataType)
166     {
167         _dataElement = createDataElement(_path, dataType);
168         if (_dataElement.valid())
169             return;
170
171         HLADataElementFactoryVisitor::apply(dataType);
172     }
173     virtual void apply(const HLAUInt8DataType& dataType)
174     {
175         _dataElement = createDataElement(_path, dataType);
176         if (_dataElement.valid())
177             return;
178
179         HLADataElementFactoryVisitor::apply(dataType);
180     }
181     virtual void apply(const HLAInt16DataType& dataType)
182     {
183         _dataElement = createDataElement(_path, dataType);
184         if (_dataElement.valid())
185             return;
186
187         HLADataElementFactoryVisitor::apply(dataType);
188     }
189     virtual void apply(const HLAUInt16DataType& dataType)
190     {
191         _dataElement = createDataElement(_path, dataType);
192         if (_dataElement.valid())
193             return;
194
195         HLADataElementFactoryVisitor::apply(dataType);
196     }
197     virtual void apply(const HLAInt32DataType& dataType)
198     {
199         _dataElement = createDataElement(_path, dataType);
200         if (_dataElement.valid())
201             return;
202
203         HLADataElementFactoryVisitor::apply(dataType);
204     }
205     virtual void apply(const HLAUInt32DataType& dataType)
206     {
207         _dataElement = createDataElement(_path, dataType);
208         if (_dataElement.valid())
209             return;
210
211         HLADataElementFactoryVisitor::apply(dataType);
212     }
213     virtual void apply(const HLAInt64DataType& dataType)
214     {
215         _dataElement = createDataElement(_path, dataType);
216         if (_dataElement.valid())
217             return;
218
219         HLADataElementFactoryVisitor::apply(dataType);
220     }
221     virtual void apply(const HLAUInt64DataType& dataType)
222     {
223         _dataElement = createDataElement(_path, dataType);
224         if (_dataElement.valid())
225             return;
226
227         HLADataElementFactoryVisitor::apply(dataType);
228     }
229     virtual void apply(const HLAFloat32DataType& dataType)
230     {
231         _dataElement = createDataElement(_path, dataType);
232         if (_dataElement.valid())
233             return;
234
235         HLADataElementFactoryVisitor::apply(dataType);
236     }
237     virtual void apply(const HLAFloat64DataType& dataType)
238     {
239         _dataElement = createDataElement(_path, dataType);
240         if (_dataElement.valid())
241             return;
242
243         HLADataElementFactoryVisitor::apply(dataType);
244     }
245
246     class ArrayDataElementFactory : public HLAArrayDataElement::DataElementFactory {
247     public:
248         ArrayDataElementFactory(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
249             _path(path)
250         {
251             for (HLAPathElementMap::const_iterator i = pathElementMap.lower_bound(path);
252                  i != pathElementMap.end(); ++i) {
253                 if (i->first.begin() != std::search(i->first.begin(), i->first.end(),
254                                                     path.begin(), path.end()))
255                     break;
256                 _pathElementMap.insert(*i);
257             }
258         }
259         virtual HLADataElement* createElement(const HLAArrayDataElement& element, unsigned index)
260         {
261             const HLADataType* dataType = element.getElementDataType();
262             if (!dataType)
263                 return 0;
264             HLADataElement::Path path = _path;
265             path.push_back(HLADataElement::PathElement(index));
266             DataElementFactoryVisitor visitor(path, _pathElementMap);
267             dataType->accept(visitor);
268             return visitor._dataElement.release();
269         }
270     private:
271         HLADataElement::Path _path;
272         HLAPathElementMap _pathElementMap;
273     };
274
275     virtual void apply(const HLAFixedArrayDataType& dataType)
276     {
277         _dataElement = createDataElement(_path, dataType);
278         if (_dataElement.valid())
279             return;
280
281         SGSharedPtr<HLAArrayDataElement> arrayDataElement;
282         arrayDataElement = new HLAArrayDataElement(&dataType);
283         arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_path, _pathElementMap));
284         arrayDataElement->setNumElements(dataType.getNumElements());
285
286         _dataElement = arrayDataElement;
287     }
288
289     virtual void apply(const HLAVariableArrayDataType& dataType)
290     {
291         _dataElement = createDataElement(_path, dataType);
292         if (_dataElement.valid())
293             return;
294
295         SGSharedPtr<HLAArrayDataElement> arrayDataElement;
296         arrayDataElement = new HLAArrayDataElement(&dataType);
297         arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_path, _pathElementMap));
298
299         _dataElement = arrayDataElement;
300     }
301
302     virtual void apply(const HLAEnumeratedDataType& dataType)
303     {
304         _dataElement = createDataElement(_path, dataType);
305         if (_dataElement.valid())
306             return;
307
308         HLADataElementFactoryVisitor::apply(dataType);
309     }
310
311     virtual void apply(const HLAFixedRecordDataType& dataType)
312     {
313         _dataElement = createDataElement(_path, dataType);
314         if (_dataElement.valid())
315             return;
316
317         SGSharedPtr<HLAFixedRecordDataElement> recordDataElement;
318         recordDataElement = new HLAFixedRecordDataElement(&dataType);
319
320         unsigned numFields = dataType.getNumFields();
321         for (unsigned i = 0; i < numFields; ++i) {
322
323             _path.push_back(HLADataElement::PathElement(dataType.getFieldName(i)));
324
325             dataType.getFieldDataType(i)->accept(*this);
326             recordDataElement->setField(i, _dataElement.release());
327
328             _path.pop_back();
329         }
330         _dataElement = recordDataElement;
331     }
332
333     class VariantRecordDataElementFactory : public HLAVariantRecordDataElement::DataElementFactory {
334     public:
335         VariantRecordDataElementFactory(const HLADataElement::Path& path, const HLAPathElementMap& pathElementMap) :
336             _path(path)
337         {
338             for (HLAPathElementMap::const_iterator i = pathElementMap.lower_bound(path);
339                  i != pathElementMap.end(); ++i) {
340                 if (i->first.begin() != std::search(i->first.begin(), i->first.end(),
341                                                     path.begin(), path.end()))
342                     break;
343                 _pathElementMap.insert(*i);
344             }
345         }
346         virtual HLADataElement* createElement(const HLAVariantRecordDataElement& element, unsigned index)
347         {
348             const HLAVariantRecordDataType* dataType = element.getDataType();
349             if (!dataType)
350                 return 0;
351             const HLADataType* alternativeDataType = element.getAlternativeDataType();
352             if (!alternativeDataType)
353                 return 0;
354             HLADataElement::Path path = _path;
355             path.push_back(HLADataElement::PathElement(dataType->getAlternativeName(index)));
356             DataElementFactoryVisitor visitor(path, _pathElementMap);
357             alternativeDataType->accept(visitor);
358             return visitor._dataElement.release();
359         }
360     private:
361         HLADataElement::Path _path;
362         HLAPathElementMap _pathElementMap;
363     };
364
365     virtual void apply(const HLAVariantRecordDataType& dataType)
366     {
367         _dataElement = createDataElement(_path, dataType);
368         if (_dataElement.valid())
369             return;
370
371         SGSharedPtr<HLAVariantRecordDataElement> variantRecordDataElement;
372         variantRecordDataElement = new HLAVariantRecordDataElement(&dataType);
373         variantRecordDataElement->setDataElementFactory(new VariantRecordDataElementFactory(_path, _pathElementMap));
374
375         _dataElement = variantRecordDataElement;
376     }
377
378 private:
379     SGSharedPtr<HLADataElement> createDataElement(const HLADataElement::Path& path, const HLADataType& dataType)
380     {
381         HLAPathElementMap::const_iterator i = _pathElementMap.find(path);
382         if (i == _pathElementMap.end()) {
383             SG_LOG(SG_IO, SG_WARN, "No dataElement provided for \""
384                    << HLADataElement::toString(path) << "\".");
385
386             return 0;
387         }
388         SGSharedPtr<HLADataElement> dataElement = i->second.getDataElement(path);
389         if (!dataElement->setDataType(&dataType)) {
390             SG_LOG(SG_IO, SG_ALERT, "Cannot set data type for data element at \""
391                    << HLADataElement::toString(path) <<  "\"!");
392             return 0;
393         }
394         SG_LOG(SG_IO, SG_DEBUG, "Using provided dataElement for \""
395                << HLADataElement::toString(path) << "\".");
396         return dataElement;
397     }
398
399     const HLAPathElementMap& _pathElementMap;
400     HLADataElement::Path _path;
401 };
402
403 void
404 HLAObjectInstance::setAttribute(unsigned index, const HLAPathElementMap& pathElementMap)
405 {
406     const HLADataType* dataType = getAttributeDataType(index);
407     if (!dataType) {
408         SG_LOG(SG_IO, SG_ALERT, "Cannot get attribute data type for setting attribute \""
409                << getAttributeName(index) << "\" at index " << index << "!");
410         return;
411     }
412
413     SG_LOG(SG_IO, SG_DEBUG, "Setting DataElement for attribute \""
414            << getAttributeName(index) << "\".");
415
416     DataElementFactoryVisitor visitor(pathElementMap);
417     dataType->accept(visitor);
418     setAttributeDataElement(index, visitor.getDataElement());
419 }
420
421 void
422 HLAObjectInstance::setAttributes(const HLAAttributePathElementMap& attributePathElementMap)
423 {
424     for (HLAAttributePathElementMap::const_iterator i = attributePathElementMap.begin();
425          i != attributePathElementMap.end(); ++i) {
426         setAttribute(i->first, i->second);
427     }
428 }
429
430 void
431 HLAObjectInstance::registerInstance()
432 {
433     if (_rtiObjectInstance.valid()) {
434         SG_LOG(SG_IO, SG_ALERT, "Trying to register object " << getName() << " already known to the RTI!");
435         return;
436     }
437     if (!_objectClass.valid()) {
438         SG_LOG(SG_IO, SG_ALERT, "Could not register object with unknown object class!");
439         return;
440     }
441     // This error must have been flagged before
442     if (!_objectClass->_rtiObjectClass.valid())
443         return;
444     _setRTIObjectInstance(_objectClass->_rtiObjectClass->registerObjectInstance(this));
445     if (!_rtiObjectInstance.valid()) {
446         SG_LOG(SG_IO, SG_ALERT, "Could not register object at the RTI!");
447         return;
448     }
449     _objectClass->_registerInstance(this);
450 }
451
452 void
453 HLAObjectInstance::deleteInstance(const RTIData& tag)
454 {
455     if (!_rtiObjectInstance.valid()) {
456         SG_LOG(SG_IO, SG_ALERT, "Trying to delete inactive object!");
457         return;
458     }
459     if (!_objectClass.valid())
460         return;
461     _objectClass->_deleteInstance(*this);
462     _rtiObjectInstance->deleteObjectInstance(tag);
463 }
464
465 void
466 HLAObjectInstance::updateAttributeValues(const RTIData& tag)
467 {
468     if (_attributeCallback.valid())
469         _attributeCallback->updateAttributeValues(*this, tag);
470     if (_updateCallback.valid()) {
471         _updateCallback->updateAttributeValues(*this, tag);
472     } else {
473         encodeAttributeValues();
474         sendAttributeValues(tag);
475     }
476 }
477
478 void
479 HLAObjectInstance::updateAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag)
480 {
481     if (_attributeCallback.valid())
482         _attributeCallback->updateAttributeValues(*this, tag);
483     if (_updateCallback.valid()) {
484         _updateCallback->updateAttributeValues(*this, timeStamp, tag);
485     } else {
486         encodeAttributeValues();
487         sendAttributeValues(timeStamp, tag);
488     }
489 }
490
491 void
492 HLAObjectInstance::encodeAttributeValues()
493 {
494     unsigned numAttributes = _attributeVector.size();
495     for (unsigned i = 0; i < numAttributes;++i) {
496         if (_attributeVector[i]._unconditionalUpdate) {
497             encodeAttributeValue(i);
498         } else if (_attributeVector[i]._enabledUpdate) {
499             const HLADataElement* dataElement = getAttributeDataElement(i);
500             if (dataElement && dataElement->getDirty())
501                 encodeAttributeValue(i);
502         }
503     }
504 }
505
506 void
507 HLAObjectInstance::encodeAttributeValue(unsigned index)
508 {
509     if (!_rtiObjectInstance.valid()) {
510         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
511         return;
512     }
513     HLADataElement* dataElement = getAttributeDataElement(index);
514     if (!dataElement)
515         return;
516     _rtiObjectInstance->encodeAttributeData(index, *dataElement);
517     dataElement->setDirty(false);
518 }
519
520 void
521 HLAObjectInstance::sendAttributeValues(const RTIData& tag)
522 {
523     if (!_rtiObjectInstance.valid()) {
524         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
525         return;
526     }
527     _rtiObjectInstance->updateAttributeValues(tag);
528 }
529
530 void
531 HLAObjectInstance::sendAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag)
532 {
533     if (!_rtiObjectInstance.valid()) {
534         SG_LOG(SG_IO, SG_INFO, "Not updating inactive object!");
535         return;
536     }
537     _rtiObjectInstance->updateAttributeValues(timeStamp, tag);
538 }
539
540 void
541 HLAObjectInstance::reflectAttributeValues(const HLAIndexList& indexList, const RTIData& tag)
542 {
543     for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i)
544         reflectAttributeValue(*i, tag);
545 }
546
547 void
548 HLAObjectInstance::reflectAttributeValues(const HLAIndexList& indexList,
549                                           const SGTimeStamp& timeStamp, const RTIData& tag)
550 {
551     for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i)
552         reflectAttributeValue(*i, timeStamp, tag);
553 }
554
555 void
556 HLAObjectInstance::reflectAttributeValue(unsigned index, const RTIData& tag)
557 {
558     HLADataElement* dataElement = getAttributeDataElement(index);
559     if (!dataElement)
560         return;
561     dataElement->setTimeStampValid(false);
562     _rtiObjectInstance->decodeAttributeData(index, *dataElement);
563 }
564
565 void
566 HLAObjectInstance::reflectAttributeValue(unsigned index, const SGTimeStamp& timeStamp, const RTIData& tag)
567 {
568     HLADataElement* dataElement = getAttributeDataElement(index);
569     if (!dataElement)
570         return;
571     dataElement->setTimeStamp(timeStamp);
572     dataElement->setTimeStampValid(true);
573     _rtiObjectInstance->decodeAttributeData(index, *dataElement);
574 }
575
576 void
577 HLAObjectInstance::_setRTIObjectInstance(RTIObjectInstance* rtiObjectInstance)
578 {
579     _rtiObjectInstance = rtiObjectInstance;
580     _rtiObjectInstance->setObjectInstance(this);
581     _name = _rtiObjectInstance->getName();
582
583     unsigned numAttributes = getNumAttributes();
584     _attributeVector.resize(numAttributes);
585     for (unsigned i = 0; i < numAttributes; ++i) {
586         HLAUpdateType updateType = getObjectClass()->getAttributeUpdateType(i);
587         if (getAttributeOwned(i) && updateType != HLAUndefinedUpdate) {
588             _attributeVector[i]._enabledUpdate = true;
589             _attributeVector[i]._unconditionalUpdate = (updateType == HLAPeriodicUpdate);
590             // In case of an owned attribute, now encode its value
591             encodeAttributeValue(i);
592         } else {
593             _attributeVector[i]._enabledUpdate = false;
594             _attributeVector[i]._unconditionalUpdate = false;
595         }
596     }
597
598     // This makes sense with any new object. Even if we registered one, there might be unpublished attributes.
599     HLAIndexList indexList;
600     for (unsigned i = 0; i < numAttributes; ++i) {
601         HLAUpdateType updateType = getObjectClass()->getAttributeUpdateType(i);
602         if (getAttributeOwned(i))
603             continue;
604         if (updateType == HLAUndefinedUpdate)
605             continue;
606         if (updateType == HLAPeriodicUpdate)
607             continue;
608         indexList.push_back(i);
609     }
610     _rtiObjectInstance->requestObjectAttributeValueUpdate(indexList);
611 }
612
613 void
614 HLAObjectInstance::_clearRTIObjectInstance()
615 {
616     if (!_rtiObjectInstance.valid())
617         return;
618
619     for (unsigned i = 0; i < _attributeVector.size(); ++i) {
620         _attributeVector[i]._enabledUpdate = false;
621         _attributeVector[i]._unconditionalUpdate = false;
622     }
623
624     _rtiObjectInstance->setObjectInstance(0);
625     _rtiObjectInstance = 0;
626 }
627
628 void
629 HLAObjectInstance::_removeInstance(const RTIData& tag)
630 {
631     if (!_objectClass.valid())
632         return;
633     _objectClass->_removeInstance(*this, tag);
634 }
635
636 void
637 HLAObjectInstance::_reflectAttributeValues(const HLAIndexList& indexList, const RTIData& tag)
638 {
639     if (_reflectCallback.valid()) {
640         _reflectCallback->reflectAttributeValues(*this, indexList, tag);
641     } else if (_attributeCallback.valid()) {
642         reflectAttributeValues(indexList, tag);
643
644         RTIIndexDataPairList dataPairList;
645         for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i) {
646             dataPairList.push_back(RTIIndexDataPair());
647             dataPairList.back().first = *i;
648             getAttributeData(*i, dataPairList.back().second);
649         }
650         _attributeCallback->reflectAttributeValues(*this, dataPairList, tag);
651     } else {
652         reflectAttributeValues(indexList, tag);
653     }
654 }
655
656 void
657 HLAObjectInstance::_reflectAttributeValues(const HLAIndexList& indexList, const SGTimeStamp& timeStamp, const RTIData& tag)
658 {
659     if (_reflectCallback.valid()) {
660         _reflectCallback->reflectAttributeValues(*this, indexList, timeStamp, tag);
661     } else if (_attributeCallback.valid()) {
662         reflectAttributeValues(indexList, timeStamp, tag);
663
664         RTIIndexDataPairList dataPairList;
665         for (HLAIndexList::const_iterator i = indexList.begin(); i != indexList.end(); ++i) {
666             dataPairList.push_back(RTIIndexDataPair());
667             dataPairList.back().first = *i;
668             getAttributeData(*i, dataPairList.back().second);
669         }
670         _attributeCallback->reflectAttributeValues(*this, dataPairList, timeStamp, tag);
671     } else {
672         reflectAttributeValues(indexList, timeStamp, tag);
673     }
674 }
675
676 } // namespace simgear