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