#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(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();
});
}
ADTF_PLUGIN(
"Qt5 Substream Logic Generator Plugin", cQtSubstreamLogicGeneratorFilter)
cQtSubstreamLogicGeneratorFilter::cQtSubstreamLogicGeneratorFilter()
{
const auto fnDefineStructure
{
oStructure.
Add<decltype(oTypeDummy)>(strSignalName);
strSignalName + " Description",
{},
{},
};
setObjectName("Qt5 Substream Logic Generator");
SetDescription("Use this UI filter to generate sample data.");
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;
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)
{
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();
1.0 / m_oParameters.m_nTimerFrequency * 1'000'000.0,
0,
[this]
{
const auto tmSampleTimeStampNs = m_pClock->GetStreamTimeNs();
CreateSample(tmSampleTimeStampNs);
});
if (!m_oTimer.Stoppable())
{
}
}
void cQtSubstreamLogicGeneratorFilter::CreateSample(tNanoSeconds 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.
#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.
#define IS_OK(s)
Check if result is OK.
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.
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.