ADTF  3.18.3
Source Code for Qt5 Substream Logic Generator Plugin
Location
./src/examples/src/adtf/filters/qt/substream_logic_generator_filter/
Namespace for entire ADTF SDK.
Build Environment
To see how to set up the build environment have a look at ADTF CMake Environment
This implementation shows:
  • how to extend the sec_substream_display
Header
/*
* This file depends on Qt which is licensed under LGPLv3.
* See ADTF_DIR/3rdparty/qt5 and doc/license for detailed information.
*/
#pragma once
#include <adtfqtsubstreamdisplaysdk/substream_display.h>
#include <adtf_ui.h>
#include <QWidget>
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::filter;
using namespace adtf::substreamdisplay;
struct cLogicGeneratorParameters
{
enum class eSignalType { Rectangle, Triangle, Sine };
uint64_t m_nTimerFrequency = 100;
uint64_t m_nFrequency = 2;
double m_fAmplitude = 1.0;
double m_fOffset = 0.0;
eSignalType m_tSignalType = eSignalType::Rectangle;
};
Q_DECLARE_METATYPE(cLogicGeneratorParameters::eSignalType)
// cLogicGeneratorWidget
class cLogicGeneratorWidget : public QWidget
{
Q_OBJECT
public:
cLogicGeneratorWidget(cLogicGeneratorParameters& oParameters);
signals:
void changed();
private:
cLogicGeneratorParameters& m_oParameters;
};
// cQtSubstreamLogicGeneratorFilter
class cQtSubstreamLogicGeneratorFilter : public QObject, public adtf::ui::cQtUIFilter
{
Q_OBJECT
public:
ADTF_CLASS_ID_NAME(cQtSubstreamLogicGeneratorFilter,
"qt_substream_logic_generator.ui_filter.adtf.cid",
"Qt5 Substream Logic Generator");
public:
cQtSubstreamLogicGeneratorFilter();
tResult Init(tInitStage eStage) override;
QWidget* CreateView() override;
void ReleaseView() override;
private:
tResult InitTimer();
void CreateSample(tNanoSeconds tmSampleTimeStampNs);
private:
static constexpr auto DISPLAY_TYPE = "Logic Generator Display";
static constexpr auto DISPLAY_BASE_NAME = "Logic Generator Display";
std::recursive_mutex m_oMutex;
ISampleWriter* m_pSimpleWriter = nullptr;
ISampleWriter* m_pDDLWriter = nullptr;
cLogicGeneratorWidget* m_pLogicGeneratorWidget = nullptr;
cLogicGeneratorParameters m_oParameters;
std::chrono::time_point<std::chrono::system_clock> m_tmStart = std::chrono::system_clock::now();
};
Copyright © Audi Electronics Venture GmbH.
#define REQUIRE_INTERFACE(_interface)
Macro usable with ADTF_CLASS_DEPENDENCIES() to require mandatory interfaces.
#define ADTF_CLASS_DEPENDENCIES(...)
Add interface ids (string literals,.
#define ADTF_CLASS_ID_NAME(_class, _strcid, _strclabel)
Common macro to enable correct treatment of class identifier AND Class Name by IClassInfo.
Definition: class_id.h:33
Class that wraps a kernel timer to call a method at specified intervals.
Definition: kernel_timer.h:20
Object pointer implementation used for reference counting on objects of type IObject.
Definition: object_ptr.h:163
Interface definition for the ADTF XSystem based on Qt.
Copyright © Audi Electronics Venture GmbH.
Copyright © Audi Electronics Venture GmbH.
Namespace for the ADTF Base SDK.
Namespace for the ADTF Filter SDK.
Namespace for the ADTF Streaming SDK.
qt_ui_filter< adtf::filter::ant::cFilter > cQtUIFilter
UI Filter basic implementation which has static pins only and supports the IDataBinding.
Definition: qt_ui_filter.h:98
Copyright © Audi Electronics Venture GmbH.
Implementation
/*
* This file depends on Qt which is licensed under LGPLv3.
* See ADTF_DIR/3rdparty/qt5 and doc/license for detailed information.
*/
#include "substream_logic_generator_filter.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include <QButtonGroup>
#include <QGroupBox>
#include <QRadioButton>
#include <QTimer>
#ifdef GetObject
#undef GetObject
#endif
namespace
{
constexpr auto strSignalTypeProperty = "signalType";
}
// cLogicGeneratorWidget
cLogicGeneratorWidget::cLogicGeneratorWidget(cLogicGeneratorParameters& oParameters) :
m_oParameters(oParameters)
{
const auto pLayout = new QVBoxLayout;
setLayout(pLayout);
const auto pTimerFrequencyLayout = new QHBoxLayout;
pLayout->addLayout(pTimerFrequencyLayout);
pTimerFrequencyLayout->addWidget(new QLabel(tr("Timer Frequency")));
const auto pTimerFrequencyLineEdit = new QLineEdit;
pTimerFrequencyLayout->addWidget(pTimerFrequencyLineEdit);
pTimerFrequencyLineEdit->setValidator(new QIntValidator);
pTimerFrequencyLineEdit->setText(QString::number(oParameters.m_nTimerFrequency));
pTimerFrequencyLayout->addWidget(new QLabel(tr("Hz")));
const auto pSignalTypeGroupBox = new QGroupBox(tr("Signal type"));
pLayout->addWidget(pSignalTypeGroupBox);
const auto pSignalTypeLayout = new QHBoxLayout;
pSignalTypeGroupBox->setLayout(pSignalTypeLayout);
const auto pRectangleSignalRadioButton = new QRadioButton(tr("Rectangle"));
pSignalTypeLayout->addWidget(pRectangleSignalRadioButton);
pRectangleSignalRadioButton->setProperty(strSignalTypeProperty, QVariant::fromValue(cLogicGeneratorParameters::eSignalType::Rectangle));
const auto pTriangleSignalRadioButton = new QRadioButton(tr("Triangle"));
pSignalTypeLayout->addWidget(pTriangleSignalRadioButton);
pTriangleSignalRadioButton->setProperty(strSignalTypeProperty, QVariant::fromValue(cLogicGeneratorParameters::eSignalType::Triangle));
const auto pSineSignalRadioButton = new QRadioButton(tr("Sine"));
pSignalTypeLayout->addWidget(pSineSignalRadioButton);
pSineSignalRadioButton->setProperty(strSignalTypeProperty, QVariant::fromValue(cLogicGeneratorParameters::eSignalType::Sine));
pSignalTypeLayout->addStretch(1);
const auto pSignalTypeButtonGroup = new QButtonGroup;
pSignalTypeButtonGroup->addButton(pRectangleSignalRadioButton);
pSignalTypeButtonGroup->addButton(pTriangleSignalRadioButton);
pSignalTypeButtonGroup->addButton(pSineSignalRadioButton);
const auto pParameterLayout = new QHBoxLayout;
pLayout->addLayout(pParameterLayout);
const auto pFrequencyLayout = new QHBoxLayout;
pParameterLayout->addLayout(pFrequencyLayout);
pFrequencyLayout->addWidget(new QLabel(tr("Frequency")));
const auto pFrequencyLineEdit = new QLineEdit;
pFrequencyLayout->addWidget(pFrequencyLineEdit);
pFrequencyLineEdit->setValidator(new QIntValidator);
pFrequencyLineEdit->setText(QString::number(oParameters.m_nFrequency));
pFrequencyLayout->addWidget(new QLabel(tr("Hz")));
const auto pAmplitudeLayout = new QHBoxLayout;
pParameterLayout->addLayout(pAmplitudeLayout);
pAmplitudeLayout->addWidget(new QLabel(tr("Amplitude")));
const auto pAmplitudeLineEdit = new QLineEdit;
pAmplitudeLayout->addWidget(pAmplitudeLineEdit);
pAmplitudeLineEdit->setValidator(new QIntValidator);
pAmplitudeLineEdit->setText(QString::number(oParameters.m_fAmplitude));
const auto pOffsetLayout = new QHBoxLayout;
pParameterLayout->addLayout(pOffsetLayout);
pOffsetLayout->addWidget(new QLabel(tr("Offset")));
const auto pOffsetLineEdit = new QLineEdit;
pOffsetLayout->addWidget(pOffsetLineEdit);
pOffsetLineEdit->setValidator(new QIntValidator);
pOffsetLineEdit->setText(QString::number(oParameters.m_fOffset));
pParameterLayout->addStretch(1);
pLayout->addStretch(1);
for (auto pButton : pSignalTypeButtonGroup->buttons())
{
if (pButton->property("signalType").value<cLogicGeneratorParameters::eSignalType>() == m_oParameters.m_tSignalType)
{
pButton->setChecked(true);
break;
}
}
connect(pTimerFrequencyLineEdit, &QLineEdit::textChanged,
[this, pTimerFrequencyLineEdit]
{
m_oParameters.m_nTimerFrequency = pTimerFrequencyLineEdit->text().toULongLong();
emit changed();
});
connect(pSignalTypeButtonGroup, qOverload<QAbstractButton*>( &QButtonGroup::buttonClicked),
[this](QAbstractButton* pButton)
{
const auto tSignalType = pButton->property("signalType").value<cLogicGeneratorParameters::eSignalType>();
m_oParameters.m_tSignalType = tSignalType;
emit changed();
});
connect(pFrequencyLineEdit, &QLineEdit::textChanged,
[this, pFrequencyLineEdit]
{
m_oParameters.m_nFrequency = pFrequencyLineEdit->text().toULongLong();
emit changed();
});
connect(pAmplitudeLineEdit, &QLineEdit::textChanged,
[this, pAmplitudeLineEdit]
{
m_oParameters.m_fAmplitude = pAmplitudeLineEdit->text().toDouble();
emit changed();
});
connect(pOffsetLineEdit, &QLineEdit::textChanged,
[this, pOffsetLineEdit]
{
m_oParameters.m_fOffset = pOffsetLineEdit->text().toDouble();
emit changed();
});
}
// cQtSubstreamLogicGeneratorFilter
ADTF_PLUGIN("Qt5 Substream Logic Generator Plugin", cQtSubstreamLogicGeneratorFilter)
cQtSubstreamLogicGeneratorFilter::cQtSubstreamLogicGeneratorFilter()
{
const auto fnDefineStructure
= [](adtf::mediadescription::structure<void>& oStructure, const std::string& strSignalName, auto oMinimumValue, auto oMaximumValue, auto oTypeDummy)
{
oStructure.Add<decltype(oTypeDummy)>(strSignalName);
oStructure.setElementInfo(strSignalName,
strSignalName + " Description",
{},
{},
std::to_string(oMinimumValue),
std::to_string(oMaximumValue));
};
//
setObjectName("Qt5 Substream Logic Generator");
// sets a short description for the component
SetDescription("Use this UI filter to generate sample data.");
// set help link to jump to documentation from ADTF Configuration Editor
set_help_link(*this, "$(ADTF_DIR)/doc/adtf_html/page_substream_logic_generator.html#sec_substream_logic_generator");
cSubStreamTypes oSimpleSubStreamTypes;
oSimpleSubStreamTypes.SetSubStream("logic_value", 0, stream_type_plain<float>());
m_pSimpleWriter = CreateOutputPin("simple_outpin", oSimpleSubStreamTypes);
set_description(*this, "simple_outpin", "output pin for generated simple sample data");
cSubStreamTypes oDDLSubStreamTypes;
adtf::mediadescription::structure<void> oStructure("structure");
fnDefineStructure(oStructure, "signal", 0.0f, 2.0f, float{});
oDDLSubStreamTypes.SetSubStream("logic_value_min_max", 1, oStructure);
m_pDDLWriter = CreateOutputPin("ddl_outpin", oDDLSubStreamTypes);
set_description(*this, "ddl_outpin", "output pin for generated DDL sample data (with min/max values)");
}
tResult cQtSubstreamLogicGeneratorFilter::Init(tInitStage eStage)
{
RETURN_IF_FAILED(adtf::ui::cQtUIFilter::Init(eStage))
if (eStage == StagePostConnect)
{
InitTimer();
}
}
QWidget* cQtSubstreamLogicGeneratorFilter::CreateView()
{
m_pLogicGeneratorWidget = new cLogicGeneratorWidget(m_oParameters);
m_pLogicGeneratorWidget->setObjectName("qt_substream_logic_generator_widget");
connect(m_pLogicGeneratorWidget, &cLogicGeneratorWidget::changed, [this]
{
InitTimer();
});
return m_pLogicGeneratorWidget;
}
void cQtSubstreamLogicGeneratorFilter::ReleaseView()
{
delete m_pLogicGeneratorWidget;
m_pLogicGeneratorWidget = nullptr;
}
tResult cQtSubstreamLogicGeneratorFilter::InitTimer()
{
m_oTimer.Stop();
m_oTimer = adtf::system::kernel_timer(get_named_graph_object_full_name(*this) + "::frame_timer",
1.0 / m_oParameters.m_nTimerFrequency * 1'000'000.0,
0,
[this]
{
const auto tmSampleTimeStampNs = m_pClock->GetStreamTimeNs();
CreateSample(tmSampleTimeStampNs);
});
if (!m_oTimer.Stoppable())
{
RETURN_ERROR_DESC(ERR_UNEXPECTED, "Unable to create kernel timer");
}
}
void cQtSubstreamLogicGeneratorFilter::CreateSample(tNanoSeconds tmSampleTimeStampNs)
{
if (IS_OK(alloc_sample(pSample, tmSampleTimeStampNs)))
{
float fValue{};
const std::chrono::time_point<std::chrono::system_clock> tmTimeStamp = std::chrono::system_clock::now();
const auto tmRelativeTimeStampMicroseconds = std::chrono::duration_cast<std::chrono::microseconds>(tmTimeStamp - m_tmStart).count();
const float nPeriodDurationMicroseconds = 1.0f / m_oParameters.m_nFrequency * 1'000'000.0f;
switch (m_oParameters.m_tSignalType)
{
case cLogicGeneratorParameters::eSignalType::Rectangle:
{
const float nHalfPeriodDurationMicroseconds = nPeriodDurationMicroseconds / 2.0f;
fValue = std::fmod(m_oParameters.m_fOffset + tmRelativeTimeStampMicroseconds, nPeriodDurationMicroseconds)
<= nHalfPeriodDurationMicroseconds ?
m_oParameters.m_fAmplitude :
0.0f;
break;
}
case cLogicGeneratorParameters::eSignalType::Triangle:
{
fValue = m_oParameters.m_fAmplitude
* std::fmod(m_oParameters.m_fOffset + tmRelativeTimeStampMicroseconds, nPeriodDurationMicroseconds)
/ nPeriodDurationMicroseconds;
break;
}
case cLogicGeneratorParameters::eSignalType::Sine:
{
fValue = m_oParameters.m_fAmplitude * std::sin(2.0 * M_PI / nPeriodDurationMicroseconds * (m_oParameters.m_fOffset + tmRelativeTimeStampMicroseconds));
break;
}
}
{
output_sample_data<float> oSample(tmSampleTimeStampNs, fValue, 0);
m_pSimpleWriter->Write(oSample.Release());
m_pSimpleWriter->ManualTrigger(tmSampleTimeStampNs);
}
{
output_sample_data<float> oSample(tmSampleTimeStampNs, fValue, 1);
m_pDDLWriter->Write(oSample.Release());
m_pDDLWriter->ManualTrigger(tmSampleTimeStampNs);
}
}
if (!pSample)
{
m_pSimpleWriter->SetStreamError(ERR_BAD_DEVICE);
}
}
#define ADTF_PLUGIN(__plugin_identifier,...)
The ADTF Plugin Macro will add the code of a adtf::ucom::ant::IPlugin implementation.
Definition: adtf_plugin.h:22
#define RETURN_ERROR_DESC(_code,...)
Same as RETURN_ERROR(_error) using a printf like parameter list for detailed error description.
#define RETURN_IF_FAILED(s)
Return if expression is failed, which requires the calling function's return type to be tResult.
#define RETURN_NOERROR
Return status ERR_NOERROR, which requires the calling function's return type to be tResult.
This is used to create a structure type from an existing c++ struct definition.
structure & Add(const std::string &strName, MemberType T::*pMemberOffset)
Adds a new member of arithmetic type (POD).
virtual tResult GetObject(iobject_ptr< IObject > &pObject, const char *strNameOID) const =0
Get registered object from object registry.
void setElementInfo(const std::string &element_name, const std::string &description={}, const std::string &comment={}, const std::string &value={}, const std::string &minimum_value={}, const std::string &maximum_value={}, const std::string &default_value={}, const std::string &scale={}, const std::string &offset={})
Set additional element information to the given element_name.
Definition: ddstructure.h:824
cString to_string(const tResult &i_oResult, eResultFormatFlags i_eFormatFlags=eResultFormatFlags::RFF_DisableNone, const tChar *i_strFormat=nullptr)
Copy all information of an assigned result object to a (formatted) string.
bool toDouble(const std::string &from, double &to)
Safely convert a string to a numeric value.
adtf_util::cString get_named_graph_object_full_name(const INamedGraphObject &oGraphObject)
Helper function to retrieve a full qualified unique name of an object registered in IFilterGraph.
tResult alloc_sample(ucom::ant::iobject_ptr< ucom::ant::IObject > &pSampleObject, const char *strSampleCID)
Helper Function to get a Sample Instance through the adtf::ucom::ant::IRuntime.
void set_description(base::ant::IConfiguration &oConfig, const char *strDescription)
Sets description information.
void set_help_link(base::ant::IConfiguration &oConfig, const char *strUrl)
Set the link to the corresponding help/documentation.
adtf::ucom::IRuntime * _runtime
Global Runtime Pointer to reference to the current runtime.