/** * {{ namespace_abbr_upper }} Data Topic Client Interface * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2016-04-07 */ {% autoescape off %} // filename: {{ namespace_abbr }}_dtc_impl.cpp #include "{{ namespace_abbr }}_dtc_impl.h" {% if custom_dtc_procs %} #include <{{ include_prefix }}/{{ namespace_abbr }}_dtc_impl_custom.h> {% endif %} #include #include #include #include #include #include namespace {{ namespace }} { namespace Interface { // initializer function std::shared_ptr Dtc::create(const std::shared_ptr &ddsConnector) { // share only for main thread if (qApp->thread() != QThread::currentThread()) {% if custom_dtc_procs %} return std::make_shared(ddsConnector); {% else %} return std::make_shared(ddsConnector); {% endif %} static std::unordered_map> s_availableConnectors; auto it = s_availableConnectors.find(ddsConnector.get()); if (it != s_availableConnectors.end()) { auto ret = it->second.lock(); if (ret) return ret; s_availableConnectors.erase(it); } {% if custom_dtc_procs %} auto ret = std::make_shared(ddsConnector); {% else %} auto ret = std::make_shared(ddsConnector); {% endif %} s_availableConnectors.insert(std::make_pair(ddsConnector.get(), ret)); return std::move(ret); // c++11 defect } // DtcImpl DtcImpl::DtcImpl(const std::shared_ptr &ddsConnector) : Dtc() , m_ddsConnector(ddsConnector) , m_logger(getLogger("Dtc")) {} DtcImpl::~DtcImpl() { enableAll(false); } bool DtcImpl::enableAll(bool enable) { {% for dt in dataTopics.member %} {% if dt.dtcImpl %} {% if dt.autosubscribe %} if (!enable{{ dt.name }}(enable)) { ERROR_LOG(m_logger) << "Error initializing data topic {{ dt.name }}"; return false; } {% endif %} {% endif %} {% endfor %} return true; } {% for dt in dataTopics.member %} {% if dt.dtcImpl %} {% if dt.key.name %} template <> struct TopicConstraints<{{ dt.type }}> { using KEY = {{ dt.key.cppType }}; }; {% endif %} {% endif %} {% endfor %} template bool DtcImpl::checkEnabled(const DTC &dtc) const { if (!dtc) { using TOPIC = typename DtcConstraints::TOPIC ; WARNING_LOG(m_logger) << "Error retrieving data topic " << DDS::topic_type_name::value() << " - not enabled"; Q_ASSERT(false); return false; } return true; } template bool DtcImpl::waitForHistoricalData(DTC &dtc, int timeoutMSec) { if (!checkEnabled(dtc)) return false; return dtc->waitForHistoricalData(timeoutMSec); } template ::KEY> K getKey(const T &val); template QMap DtcImpl::getAll(const DTC &dtc) const { if (!checkEnabled(dtc)) return {}; QMap retMap; for (const auto &sample : dtc->readAlive()) retMap.insert(getKey(sample.data()), sample); return retMap; } template T DtcImpl::getOne(const DTC &dtc, const C &cont, const K &key) const { if (!checkEnabled(dtc)) return {}; const auto it = cont.find(key); return it == cont.end() ? T() : it.value(); } template bool DtcImpl::iterateAll(const DTC &dtc, const C &cont, const std::function &cb) const { if (!checkEnabled(dtc)) return false; for (const auto &sample : cont) cb(sample); return true; } template bool DtcImpl::iterateUntil(const DTC &dtc, const C &cont, const std::function &cb) const { if (!checkEnabled(dtc)) return false; for (const auto &sample : cont) { if (cb(sample)) return true; } return false; } {% for dt in dataTopics.member %} {% if dt.dtcImpl %} // // Data Topic '{{ dt.name }}' // bool DtcImpl::enable{{ dt.name }}(bool enable) { if (enable) { if (m_dtc{{ dt.name }}) { INFO_LOG(m_logger) << "{{ dt.name }} already enabled!"; return true; } m_dtc{{ dt.name }}.reset(m_ddsConnector->createDTC()); assert(m_dtc{{ dt.name }}.get()); m_dtc{{ dt.name }}->setSubscriberCallback([this](const {{ namespace }}::{{ dt.name }} &data, DataModification modType) { {{ dt.nameFlc }}ChangedInternal(data, modType); }); } else { m_dtc{{ dt.name }} = nullptr; } return true; } bool DtcImpl::waitForHistoricalData{{ dt.name }}(int timeoutMSec) { if (!is{{ dt.name }}Enabled()) { enable{{ dt.name }}(); DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ; } if (!waitForHistoricalData(m_dtc{{ dt.name }}, timeoutMSec)) return false; {% if dt.key.name %} m_{{ dt.nameFlc }}Cont = getAll(m_dtc{{ dt.name }}); {% else %} auto samples = m_dtc{{ dt.name }}->readAlive(); if (samples.length() == 0) return false; m_{{ dt.nameFlc }} = samples[samples.length() - 1].data(); {% endif %} return true; } {% if dt.key.name %} template <> {{ dt.key.cppType }} getKey(const {{ dt.type }} &val) { return val.{{ dt.key.name }}(); } QMap<{{ dt.key.cppType }},{{ namespace }}::{{ dt.type }}> DtcImpl::{{ dt.nameFlc }}s() { if (!is{{ dt.name }}Enabled()) { enable{{ dt.name }}(); DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ; waitForHistoricalData{{ dt.name }}(10); } return m_{{ dt.nameFlc }}Cont; } bool DtcImpl::{{ dt.nameFlc }}s(const std::function &cb) { if (!is{{ dt.name }}Enabled()) { enable{{ dt.name }}(); DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ; waitForHistoricalData{{ dt.name }}(10); } return iterateAll(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, cb); } bool DtcImpl::{{ dt.nameFlc }}s(const std::function &cb) { if (!is{{ dt.name }}Enabled()) { enable{{ dt.name }}(); DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ; waitForHistoricalData{{ dt.name }}(10); } return iterateUntil(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, cb); } {{ namespace }}::{{ dt.type }} DtcImpl::{{ dt.nameFlc }}({{ dt.key.cppTypeCr }} {{ dt.key.nameFlc }}) { if (!is{{ dt.name }}Enabled()) { enable{{ dt.name }}(); DEBUG_LOG(m_logger) << "NEED TO ENABLE ! {{ dt.name }}" ; waitForHistoricalData{{ dt.name }}(10); } return getOne(m_dtc{{ dt.name }}, m_{{ dt.nameFlc }}Cont, {{ dt.key.nameFlc }}); } void DtcImpl::{{ dt.nameFlc }}ChangedInternal(const {{ namespace }}::{{ dt.type }} &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_{{ dt.nameFlc }}Cont[getKey(data)] = data; break; case DataModification::eRemoved: m_{{ dt.nameFlc }}Cont.remove(getKey(data)); break; } emit {{ dt.nameFlc }}Changed(data, modType); } {% else %} {{ namespace }}::{{ dt.type }} DtcImpl::{{ dt.nameFlc }}() { return m_{{ dt.nameFlc }}; } void DtcImpl::{{ dt.nameFlc }}ChangedInternal(const {{ namespace }}::{{ dt.type }} &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_{{ dt.nameFlc }} = data; break; case DataModification::eRemoved: m_{{ dt.nameFlc }} = {{ namespace }}::{{ dt.type }}(); break; } emit {{ dt.nameFlc }}Changed(data, modType); } {% endif %} {% endif %} {% endfor %} } // namespace Interface } // namespace {{ namespace }} {% endautoescape %}