diff --git a/src/logicanalyzer/logic_analyzer.cpp b/src/logicanalyzer/logic_analyzer.cpp index ea9137e84b..e247ba3f17 100644 --- a/src/logicanalyzer/logic_analyzer.cpp +++ b/src/logicanalyzer/logic_analyzer.cpp @@ -57,8 +57,11 @@ using namespace adiscope; using namespace adiscope::logic; -constexpr int MAX_BUFFER_SIZE_ONESHOT = 4 * 1024 * 1024; // 4M -constexpr int MAX_BUFFER_SIZE_STREAM = 64 * 4 * 1024 * 1024; // 64 x 4M +constexpr int MAX_BUFFER_SIZE_ONESHOT = 64 * 4 * 1024 * 1024; // 64 x 4M +constexpr int MAX_BUFFER_SIZE_STREAM = 1024 * 1024 * 1024; // 1Gb +constexpr int MAX_SR_ONESHOT = 10e7; // 100M +constexpr int MAX_SR_STREAM = 10e6; // 10M +constexpr int MAX_KERNEL_BUFFERS = 64; constexpr int DIGITAL_NR_CHANNELS = 16; /* helper method to sort srd_decoder objects based on ids(name) */ @@ -218,8 +221,8 @@ LogicAnalyzer::LogicAnalyzer(struct iio_context *ctx, adiscope::Filter *filt, m_timePositionButton->setStep(1); - // default: stream - ui->btnStreamOneShot->setChecked(false); + // default: oneshot + ui->btnStreamOneShot->setChecked(true); // default m_sampleRateButton->setValue(m_sampleRate); @@ -314,6 +317,12 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in QTabWidget *tabWidget = new QTabWidget(); tabWidget->setMovable(true); + QScrollArea *generalScrollArea = new QScrollArea(); + generalScrollArea->setWidgetResizable(true); + generalScrollArea->setMinimumSize(220, 300); + generalScrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + generalScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + QWidget *channelEnumerator = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(); QGridLayout *chEnumeratorLayout = new QGridLayout(); @@ -342,6 +351,7 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in }); QCheckBox *channelBox = new QCheckBox("DIO " + QString::number(i)); + curve->setName("DIO " + QString::number(i)); QHBoxLayout *hBoxLayout = new QHBoxLayout(this); @@ -633,7 +643,24 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in nameLineEdit->setAlignment(Qt::AlignCenter); nameLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QLineEdit *traceHeightLineEdit = new QLineEdit(); + traceHeightLineEdit->setText(""); + traceHeightLineEdit->setVisible(true); + traceHeightLineEdit->setDisabled(true); + traceHeightLineEdit->setAlignment(Qt::AlignCenter); + traceHeightLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + QComboBox *currentChannelTriggerComboBox = new QComboBox(); + currentChannelTriggerComboBox->addItem("-"); + for (int i = 1; i < ui->triggerComboBox->count(); ++i) { + currentChannelTriggerComboBox->addItem(ui->triggerComboBox->itemIcon(i), + ui->triggerComboBox->itemText(i)); + } + currentChannelMenuLayout->addWidget(nameLineEdit); + currentChannelMenuLayout->addWidget(traceHeightLineEdit); + currentChannelMenuLayout->addWidget(currentChannelTriggerComboBox); + currentChannelMenuLayout->addLayout(decoderSettingsLayout); currentChannelMenu->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -645,17 +672,101 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in stackDecoderLayout->insertSpacerItem(0, new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)); stackDecoderLayout->insertWidget(1, stackDecoderComboBox); - currentChannelMenuLayout->insertItem(-1, new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + /* Setup external trigger menu */ + QWidget *externalTrigger = new QWidget(currentChannelMenu); + QVBoxLayout *externalTriggerLayout = new QVBoxLayout(externalTrigger); + externalTriggerLayout->setContentsMargins(0, 0, 0, 0); + externalTrigger->setLayout(externalTriggerLayout); + + QHBoxLayout *externalSubTitle = new QHBoxLayout(); + auto label = new QLabel("EXTERNAL TRIGGER "); + label->setStyleSheet("QLabel {" + "font-size: 12px;" + "color: rgba(255, 255, 255, 70);" + "font-weight: normal;" + "}"); + externalSubTitle->addWidget(label); + externalSubTitle->setContentsMargins(0, 0, 0, 0); + externalSubTitle->setSpacing(0); + + QFrame *line = new QFrame(externalTrigger); + line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + line->setMaximumSize(QSize(16777215, 1)); + line->setStyleSheet(QString::fromUtf8("border: 1px solid rgba(255, 255, 255, 70);")); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + externalSubTitle->addWidget(line); + + externalTriggerLayout->addLayout(externalSubTitle); + + QGridLayout *externalGridLayout = new QGridLayout(); + auto externalOnOff = new adiscope::CustomSwitch(); + externalGridLayout->addWidget(externalOnOff, 0, 0); + auto labelCondition = new QLabel("Condition"); + externalGridLayout->addWidget(labelCondition, 1, 0); + + QFile file(":stylesheets/stylesheets/customSwitch.qss"); + file.open(QFile::ReadOnly); + QString styleSheet = QString::fromLatin1(file.readAll()); + externalOnOff->setStyleSheet(styleSheet); + + auto comboBoxCondition = new QComboBox(); + externalGridLayout->addWidget(comboBoxCondition, 1, 1); + + comboBoxCondition->setDisabled(true); + + connect(externalOnOff, &CustomSwitch::toggled, [=](bool on){ + if (on) { + comboBoxCondition->setEnabled(true); + m_m2kDigital->getTrigger()->setDigitalSource(SRC_TRIGGER_IN); + const int condition = comboBoxCondition->currentIndex(); + m_m2kDigital->getTrigger()->setDigitalExternalCondition( + static_cast((condition + 5) % 6)); + } else { + comboBoxCondition->setCurrentIndex(0); + comboBoxCondition->setDisabled(true); + m_m2kDigital->getTrigger()->setDigitalSource(SRC_NONE); + } + }); + comboBoxCondition->addItem("-"); + for (int i = 1; i < ui->triggerComboBox->count(); ++i) { + comboBoxCondition->addItem(ui->triggerComboBox->itemIcon(i), + ui->triggerComboBox->itemText(i)); + } + + connect(comboBoxCondition, QOverload::of(&QComboBox::currentIndexChanged), [=](int index){ + m_m2kDigital->getTrigger()->setDigitalExternalCondition( + static_cast((index + 5) % 6)); + }); + + externalTriggerLayout->addLayout(externalGridLayout); + layout->addWidget(externalTrigger); + + currentChannelMenuLayout->insertItem(-1, new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); tabWidget->addTab(channelEnumerator, "General"); const int channelMenuTabId = tabWidget->addTab(currentChannelMenuScrollArea, "Channel"); - connect(m_oscPlot, &CapturePlot::channelSelected, [=](int chIdx, bool selected){ + m_oscChannelSelectedConnection = connect(m_oscPlot, &CapturePlot::channelSelected, [=](int chIdx, bool selected){ chIdx -= m_oscAnalogChannels; if (m_oscChannelSelected != chIdx && selected) { m_oscChannelSelected = chIdx; nameLineEdit->setEnabled(true); nameLineEdit->setText(m_oscPlotCurves[chIdx]->getName()); + traceHeightLineEdit->setEnabled(true); + traceHeightLineEdit->setText(QString::number(m_oscPlotCurves[chIdx]->getTraceHeight())); + + if (m_oscChannelSelected < m_nbChannels) { + currentChannelTriggerComboBox->setEnabled(true); + QComboBox *triggerBox = qobject_cast(chEnumeratorLayout->itemAtPosition(m_oscChannelSelected % 8, + m_oscChannelSelected / 8)->layout()->itemAt(1)->widget()); + currentChannelTriggerComboBox->setCurrentIndex(triggerBox->currentIndex()); + } else { + currentChannelTriggerComboBox->setDisabled(true); + QSignalBlocker sb(currentChannelTriggerComboBox); + currentChannelTriggerComboBox->setCurrentIndex(0); + } tabWidget->setCurrentIndex(channelMenuTabId); @@ -680,6 +791,10 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in m_oscChannelSelected = -1; nameLineEdit->setDisabled(true); nameLineEdit->setText("No channel selected!"); + traceHeightLineEdit->setDisabled(true); + traceHeightLineEdit->setText(""); + currentChannelTriggerComboBox->setDisabled(true); + currentChannelTriggerComboBox->setCurrentIndex(0); if (m_oscDecoderMenu) { decoderSettingsLayout->removeWidget(m_oscDecoderMenu); @@ -691,6 +806,32 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in updateButtonStackedDecoder(); }); + connect(traceHeightLineEdit, &QLineEdit::editingFinished, [=](){ + int value = traceHeightLineEdit->text().toInt(); + m_oscPlotCurves[m_oscChannelSelected]->setTraceHeight(value); + m_oscPlot->replot(); + m_oscPlot->positionInGroupChanged(m_oscChannelSelected, 0, 0); + }); + + connect(currentChannelTriggerComboBox, QOverload::of(&QComboBox::currentIndexChanged), [=](int index) { + if (m_oscChannelSelected != -1 && m_oscChannelSelected < m_nbChannels) { + QComboBox *triggerBox = qobject_cast(chEnumeratorLayout->itemAtPosition(m_oscChannelSelected % 8, + m_oscChannelSelected / 8)->layout()->itemAt(1)->widget()); + triggerBox->setCurrentIndex(index); + } + }); + + connect(tabWidget, &QTabWidget::currentChanged, [=](int index){ + if (index == tabWidget->indexOf(currentChannelMenuScrollArea)) { + if (m_oscChannelSelected != -1 && m_oscChannelSelected < m_nbChannels) { + currentChannelTriggerComboBox->setEnabled(true); + QComboBox *triggerBox = qobject_cast(chEnumeratorLayout->itemAtPosition(m_oscChannelSelected % 8, + m_oscChannelSelected / 8)->layout()->itemAt(1)->widget()); + currentChannelTriggerComboBox->setCurrentIndex(triggerBox->currentIndex()); + } + } + }); + connect(stackDecoderComboBox, &QComboBox::currentTextChanged, [=](const QString &text) { if (m_oscChannelSelected < m_nbChannels) { return; @@ -735,11 +876,12 @@ std::vector LogicAnalyzer::enableMixedSignalView(CapturePlot *osc, in }); currentChannelMenuScrollArea->setWidget(currentChannelMenu); + generalScrollArea->setWidget(channelEnumerator); - tabWidget->addTab(channelEnumerator, "General"); + tabWidget->addTab(generalScrollArea, "General"); tabWidget->addTab(currentChannelMenuScrollArea, "Channel"); - return {tabWidget}; + return {tabWidget, generalScrollArea}; } void LogicAnalyzer::disableMixedSignalView() @@ -758,6 +900,10 @@ void LogicAnalyzer::disableMixedSignalView() curve = m_oscPlot->getDigitalPlotCurve(0); } + m_oscPlotCurves.clear(); + m_oscChannelSelected = -1; + + disconnect(m_oscChannelSelectedConnection); m_oscPlot = nullptr; } @@ -944,8 +1090,8 @@ void LogicAnalyzer::on_btnStreamOneShot_toggled(bool toggled) { qDebug() << "Btn stream one shot toggled !!!!!: " << toggled; - m_plot.enableTimeTrigger(toggled); - m_timePositionButton->setVisible(toggled); +// m_plot.enableTimeTrigger(toggled); +// m_timePositionButton->setVisible(toggled); m_m2kDigital->getTrigger()->setDigitalStreamingFlag(toggled); @@ -967,6 +1113,9 @@ void LogicAnalyzer::on_btnStreamOneShot_toggled(bool toggled) m_bufferSizeButton->setMaxValue(toggled ? MAX_BUFFER_SIZE_ONESHOT : MAX_BUFFER_SIZE_STREAM); + m_sampleRateButton->setMaxValue(toggled ? MAX_SR_ONESHOT + : MAX_SR_STREAM); + m_sampleRateButton->setIntegerDivider(m_sampleRateButton->maxValue()); m_bufferPreviewer->setCursorVisible(toggled); } @@ -998,6 +1147,13 @@ void LogicAnalyzer::channelSelectedChanged(int chIdx, bool selected) qDebug() << "Selected channel: " << chIdx; m_selectedChannel = chIdx; + + if (m_selectedChannel < m_nbChannels) { + ui->hardwareName->setText("DIO " + QString::number(m_selectedChannel)); + } else { + ui->hardwareName->setText(""); + } + ui->nameLineEdit->setEnabled(true); ui->nameLineEdit->setText(m_plotCurves[m_selectedChannel]->getName()); ui->traceHeightLineEdit->setEnabled(true); @@ -1040,6 +1196,7 @@ void LogicAnalyzer::channelSelectedChanged(int chIdx, bool selected) } } else if (m_selectedChannel == chIdx && !selected) { m_selectedChannel = -1; + ui->hardwareName->setText(""); ui->nameLineEdit->setDisabled(true); ui->nameLineEdit->setText(""); ui->traceHeightLineEdit->setDisabled(true); @@ -1065,7 +1222,7 @@ void LogicAnalyzer::setupUi() ui->setupUi(this); // Hide the run button - ui->runSingleWidget->enableRunButton(false); +// ui->runSingleWidget->enableRunButton(false); int gsettings_panel = ui->stackedWidget->indexOf(ui->generalSettings); ui->btnGeneralSettings->setProperty("id", QVariant(-gsettings_panel)); @@ -1272,18 +1429,6 @@ void LogicAnalyzer::connectSignalsAndSlots() connect(ui->nameLineEdit, &QLineEdit::textChanged, [=](const QString &text){ m_plot.setChannelName(text, m_selectedChannel); m_plotCurves[m_selectedChannel]->setName(text); - if (m_selectedChannel < m_nbChannels) { - QLayout *widgetInLayout = ui->channelEnumeratorLayout->itemAtPosition(m_selectedChannel % 8, - m_selectedChannel / 8)->layout(); - auto channelBox = dynamic_cast(widgetInLayout->itemAt(0)->widget()); - channelBox->setText(text); - } else { - const int selectedDecoder = m_selectedChannel - m_nbChannels; - QLayout *widgetInLayout = ui->decoderEnumeratorLayout->itemAtPosition(selectedDecoder / 2, - selectedDecoder % 2)->widget()->layout(); - auto decoderBox = dynamic_cast(widgetInLayout->itemAt(0)->widget()); - decoderBox->setText(text); - } }); connect(ui->traceHeightLineEdit, &QLineEdit::textChanged, [=](const QString &text){ @@ -1511,6 +1656,10 @@ void LogicAnalyzer::startStop(bool start) m_captureThread = nullptr; } + m_plot.setSampleRatelabelValue(m_sampleRate); + m_plot.setBufferSizeLabelValue(m_bufferSize); + m_plot.setTimeBaseLabelValue(m_bufferSize / m_sampleRate / m_plot.xAxisNumDiv()); + m_stopRequested = false; m_m2kDigital->stopAcquisition(); @@ -1580,66 +1729,61 @@ void LogicAnalyzer::startStop(bool start) m_plot.setTriggerState(CapturePlot::Waiting); }, Qt::QueuedConnection); - if (ui->btnStreamOneShot->isChecked()) { + uint64_t chunks = 4; + while ((bufferSizeAdjusted >> chunks) > (1 << 19)) { + chunks++; // select a small size for the chunks + // example: 2^19 samples in each chunk + } + const uint64_t chunk_size = (bufferSizeAdjusted >> chunks) > 0 ? (bufferSizeAdjusted >> chunks) : 4 ; + uint64_t totalSamples = bufferSizeAdjusted; + + do { try { - const uint16_t * const temp = m_m2kDigital->getSamplesP(bufferSize); - memcpy(m_buffer, temp, bufferSizeAdjusted * sizeof(uint16_t)); + m_m2kDigital->setKernelBuffersCountIn(64); + break; + } catch (libm2k::m2k_exception &e) { + qDebug() << e.what(); + } + } while (true); + + uint64_t absIndex = 0; + + do { + const uint64_t captureSize = std::min(chunk_size, totalSamples); + try { + const uint16_t * const temp = m_m2kDigital->getSamplesP(captureSize); + memcpy(m_buffer + absIndex, temp, sizeof(uint16_t) * captureSize); + absIndex += captureSize; + totalSamples -= captureSize; QMetaObject::invokeMethod(this, [=](){ m_plot.setTriggerState(CapturePlot::Triggered); }, Qt::QueuedConnection); - m_lastCapturedSample = bufferSize; - Q_EMIT dataAvailable(0, bufferSize); - updateBufferPreviewer(0, m_lastCapturedSample); - } catch (libm2k::m2k_exception &e) { - HANDLE_EXCEPTION(e) - qDebug() << e.what(); +// HANDLE_EXCEPTION(e) + qDebug() << e.what() << " code: " << e.iioCode(); + break; } - } else { - uint64_t chunks = 4; - while ((bufferSizeAdjusted >> chunks) > (1 << 19)) { - chunks++; // select a small size for the chunks - // example: 2^19 samples in each chunk + + if (m_stopRequested) { + break; } - const uint64_t chunk_size = (bufferSizeAdjusted >> chunks) > 0 ? (bufferSizeAdjusted >> chunks) : 4 ; - uint64_t totalSamples = bufferSizeAdjusted; - m_m2kDigital->setKernelBuffersCountIn(64); - uint64_t absIndex = 0; - - do { - const uint64_t captureSize = std::min(chunk_size, totalSamples); - try { - const uint16_t * const temp = m_m2kDigital->getSamplesP(captureSize); - memcpy(m_buffer + absIndex, temp, sizeof(uint16_t) * captureSize); - absIndex += captureSize; - totalSamples -= captureSize; - - QMetaObject::invokeMethod(this, [=](){ - m_plot.setTriggerState(CapturePlot::Triggered); - }, Qt::QueuedConnection); - - } catch (libm2k::m2k_exception &e) { - HANDLE_EXCEPTION(e) - qDebug() << e.what(); - break; - } - - if (m_stopRequested) { - break; - } - - Q_EMIT dataAvailable(absIndex - captureSize, absIndex); - - QMetaObject::invokeMethod(&m_plot, // trigger replot on Main Thread - "replot", - Qt::QueuedConnection); - m_lastCapturedSample = absIndex; - updateBufferPreviewer(0, m_lastCapturedSample); - - } while (totalSamples); - } + + Q_EMIT dataAvailable(absIndex - captureSize, absIndex); + + QMetaObject::invokeMethod(&m_plot, // trigger replot on Main Thread + "replot", + Qt::QueuedConnection); + m_lastCapturedSample = absIndex; + updateBufferPreviewer(0, m_lastCapturedSample); + + if (!totalSamples && ui->runSingleWidget->runButtonChecked()) { + totalSamples = bufferSizeAdjusted; + absIndex = 0; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } while (totalSamples); m_started = false; diff --git a/src/logicanalyzer/logic_analyzer.h b/src/logicanalyzer/logic_analyzer.h index bf3ebd1524..cff8de4633 100644 --- a/src/logicanalyzer/logic_analyzer.h +++ b/src/logicanalyzer/logic_analyzer.h @@ -206,6 +206,7 @@ private Q_SLOTS: int m_oscChannelSelected; QVector m_oscPlotCurves; QWidget *m_oscDecoderMenu; + QMetaObject::Connection m_oscChannelSelectedConnection; }; diff --git a/src/logicanalyzer/logicanalyzer_api.h b/src/logicanalyzer/logicanalyzer_api.h index 036835cd2a..fcef82e67c 100644 --- a/src/logicanalyzer/logicanalyzer_api.h +++ b/src/logicanalyzer/logicanalyzer_api.h @@ -32,9 +32,9 @@ class LogicAnalyzer_API : public ApiObject Q_OBJECT /* sweep settings */ + Q_PROPERTY(bool streamOneShot READ getStreamOrOneShot WRITE setStreamOrOneShot) Q_PROPERTY(double sampleRate READ getSampleRate WRITE setSampleRate) Q_PROPERTY(int bufferSize READ getBufferSize WRITE setBufferSize) - Q_PROPERTY(bool streamOneShot READ getStreamOrOneShot WRITE setStreamOrOneShot) Q_PROPERTY(int delay READ getDelay WRITE setDelay) /* channel settings */ diff --git a/src/logicanalyzer/logicdatacurve.cpp b/src/logicanalyzer/logicdatacurve.cpp index 4450a34bb9..65cbf79d98 100644 --- a/src/logicanalyzer/logicdatacurve.cpp +++ b/src/logicanalyzer/logicdatacurve.cpp @@ -38,7 +38,7 @@ static const QColor LowColor(0xC0, 0x00, 0x00); static const QColor SamplingPointColor(0x77, 0x77, 0x77); LogicDataCurve::LogicDataCurve(uint16_t *data, uint8_t bit, adiscope::logic::LogicTool *logic) : - GenericLogicPlotCurve(QString("Dio " + QString::number(bit)), QString("Dio " + QString::number(bit))), + GenericLogicPlotCurve(QString(QString::number(bit)), QString(QString::number(bit))), m_logic(logic), m_startSample(0), m_endSample(0), @@ -170,7 +170,9 @@ void LogicDataCurve::drawLines(QPainter *painter, const QwtScaleMap &xMap, displayedData += QPointF(fromSampleToTime(m_endSample - 1), (!edges.back().second) * heightInPoints + m_pixelOffset); } - displayedData += QPointF(plot()->axisInterval(QwtAxis::xBottom).maxValue(), displayedData.back().y()); + if (edges.back().first + 1 == m_endSample - 1) { + displayedData += QPointF(plot()->axisInterval(QwtAxis::xBottom).maxValue(), displayedData.back().y()); + } painter->save(); painter->setPen(QColor(74, 100, 255)); //4a64ff @@ -230,26 +232,14 @@ void LogicDataCurve::getSubsampledEdges(std::vector> & double dist = xMap.transform(fromSampleToTime(1)) - xMap.transform(fromSampleToTime(0)); QwtInterval interval = plot()->axisInterval(QwtAxis::xBottom); -// qDebug() << "from plot, left: " << interval.minValue() << " right: " << interval.maxValue(); uint64_t firstEdge = edgeAtX(fromTimeToSample(interval.minValue()), m_edges); uint64_t lastEdge = edgeAtX(fromTimeToSample(interval.maxValue()), m_edges); -// qDebug() << "First edge is: " << firstEdge; -// qDebug() << "Last edge is: " << lastEdge; - -// qDebug() << "first edge: " << firstEdge; -// qDebug() << "last edge: " << lastEdge; - - if (m_edges.size() == 0) { -// qDebug() << "first edge: " << firstEdge << " last edge: " << lastEdge; - } - if (firstEdge > 0) { firstEdge--; } if (lastEdge < m_edges.size() - 1) { -// qDebug() << "lastEdge: " << lastEdge << " < " << "m_edges.size() - 1: " << m_edges.size() - 1; lastEdge++; } @@ -304,12 +294,10 @@ void LogicDataCurve::getSubsampledEdges(std::vector> & // between the blocks and we want to make sure we display the correct logic level if (std::abs(a1 - a2) > pointsPerPixel) { edges.emplace_back(m_edges[std::distance(m_edges.begin(), previous)]); -// qDebug() << "gap emplace!!!!!!!"; } else { const int64_t currentSample = (*next).first; if ((*next).second == lastTransition) { edges.emplace_back((lastSample + currentSample) / 2, !lastTransition); -// qDebug() << "HACK!!!!!!"; } } diff --git a/src/oscilloscope.cpp b/src/oscilloscope.cpp index 27c39d457e..754a527134 100644 --- a/src/oscilloscope.cpp +++ b/src/oscilloscope.cpp @@ -1285,7 +1285,7 @@ void Oscilloscope::setFilteringEnabled(bool set) setSampleRate(active_sample_rate); } -void Oscilloscope::enableMixedSignalView() +void Oscilloscope::enableMixedSignalView(ChannelWidget *cw) { const bool iioStarted = isIioManagerStarted(); if (iioStarted) { @@ -1299,6 +1299,13 @@ void Oscilloscope::enableMixedSignalView() ui->logicSettingsLayout->addWidget(m_mixedSignalViewMenu[0]); + QTabWidget *tb = qobject_cast(m_mixedSignalViewMenu[0]); + showLogicAnalyzerTriggerConnection = connect(&trigger_settings, &TriggerSettings::showLogicAnalyzerTriggerSettings, + this, [=](){ + cw->menuButton()->setChecked(true); + tb->setCurrentIndex(tb->indexOf(m_mixedSignalViewMenu[1])); + }); + mixed_sink = mixed_signal_sink::make(m_logicAnalyzer, &this->plot, active_sample_count); mixed_source = gr::m2k::mixed_signal_source::make_from(m_m2k_context, active_sample_count); @@ -1339,6 +1346,8 @@ void Oscilloscope::disableMixedSignalView() m_mixedSignalViewEnabled = false; + disconnect(showLogicAnalyzerTriggerConnection); + // disable mixed signal from logic ui->logicSettingsLayout->removeWidget(m_mixedSignalViewMenu[0]); m_logicAnalyzer->disableMixedSignalView(); @@ -2076,6 +2085,22 @@ void Oscilloscope::create_add_channel_panel() tabWidget->addTab(logic, tr("Logic")); + connect(ui->mixedSignalBtn, &QPushButton::clicked, [=](){ + if (!m_mixedSignalViewEnabled) { + ui->btnAddMath->click(); + tabWidget->setCurrentIndex(tabWidget->indexOf(logic)); + } else { + for (int i = 0; i < ui->channelsList->count(); ++i) { + ChannelWidget *cw = qobject_cast( + ui->channelsList->itemAt(i)->widget()); + if (cw && cw->fullName() == "Logic Analyzer") { + cw->deleteButton()->click(); + break; + } + } + } + }); + connect(btnOpenFile, &QPushButton::clicked, this, &Oscilloscope::import); connect(tabWidget, &QTabWidget::currentChanged, [=](int index) { @@ -2105,6 +2130,7 @@ void Oscilloscope::create_add_channel_panel() if (tabWidget->currentIndex() == 2) { qDebug() << "Enable mixed signal view!"; + ui->mixedSignalBtn->setText("Disable Mixed\nSignal View"); ChannelWidget *logicAnalyzerChannelWidget = new ChannelWidget(-1, true, false, QColor(Qt::yellow), this); @@ -2144,13 +2170,14 @@ void Oscilloscope::create_add_channel_panel() logicAnalyzerChannelWidget->deleteLater(); tabWidget->setTabEnabled(logicTab, true); + ui->mixedSignalBtn->setText("Enable Mixed\nSignal View"); disableMixedSignalView(); }); logicAnalyzerChannelWidget->menuButton()->setChecked(true); - enableMixedSignalView(); + enableMixedSignalView(logicAnalyzerChannelWidget); return; } diff --git a/src/oscilloscope.hpp b/src/oscilloscope.hpp index c933120bbd..a12c9ea2fa 100644 --- a/src/oscilloscope.hpp +++ b/src/oscilloscope.hpp @@ -243,7 +243,7 @@ namespace adiscope { void toolDetached(bool); void setFilteringEnabled(bool set); - void enableMixedSignalView(); + void enableMixedSignalView(ChannelWidget *cw); void disableMixedSignalView(); void setDigitalPlotCurvesParams(); @@ -490,6 +490,7 @@ namespace adiscope { gr::m2k::mixed_signal_source::sptr mixed_source; mixed_signal_sink::sptr mixed_sink; + QMetaObject::Connection showLogicAnalyzerTriggerConnection; }; } #endif /* M2K_OSCILLOSCOPE_H */ diff --git a/src/oscilloscope_plot.cpp b/src/oscilloscope_plot.cpp index 557c35f2ba..09251e3ded 100644 --- a/src/oscilloscope_plot.cpp +++ b/src/oscilloscope_plot.cpp @@ -83,7 +83,8 @@ CapturePlot::CapturePlot(QWidget *parent, d_startedGrouping(false), d_bottomHandlesArea(nullptr), d_xAxisInterval{0.0, 0.0}, - d_currentHandleInitPx(1) + d_currentHandleInitPx(1), + d_maxBufferError(nullptr) { setMinimumHeight(250); setMinimumWidth(500); @@ -160,6 +161,11 @@ CapturePlot::CapturePlot(QWidget *parent, "color: #ffffff;" "}"); + d_maxBufferError = new QLabel(this); + d_maxBufferError->setStyleSheet("QLabel {" + "color: #ff0000;" + "}"); + // Top area layout QHBoxLayout *topWidgetLayout = new QHBoxLayout(d_topWidget); topWidgetLayout->setContentsMargins(d_leftHandlesArea->minimumWidth(), @@ -171,7 +177,9 @@ CapturePlot::CapturePlot(QWidget *parent, Qt::AlignBottom); topWidgetLayout->insertWidget(1, d_sampleRateLabel, 0, Qt::AlignLeft | Qt::AlignBottom); - topWidgetLayout->insertWidget(2, d_triggerStateLabel, 0, Qt::AlignRight | + topWidgetLayout->insertWidget(2, d_maxBufferError, 0, Qt::AlignRight | + Qt::AlignBottom); + topWidgetLayout->insertWidget(3, d_triggerStateLabel, 0, Qt::AlignRight | Qt::AlignBottom); QSpacerItem *spacerItem = new QSpacerItem(0, 0, QSizePolicy::Expanding, @@ -1501,7 +1509,6 @@ void CapturePlot::addToGroup(int currentGroup, int toAdd) void CapturePlot::onDigitalChannelAdded(int chnIdx) { - qDebug() << "Digital Channel Added!"; setLeftVertAxesCount(d_ydata.size() + d_ref_ydata.size() + chnIdx + 1); setAxisScale( QwtAxisId(QwtPlot::yLeft, d_ydata.size() + d_ref_ydata.size() + chnIdx), -5, 5); replot(); @@ -2374,6 +2381,11 @@ void CapturePlot::setTriggerState(int triggerState) d_triggerStateLabel->show(); } +void CapturePlot::setMaxBufferSizeErrorLabel(bool reached) +{ + d_maxBufferError->setText(reached ? "Maximum buffer size reached" : ""); +} + void CapturePlot::setCursorReadoutsTransparency(int value) { d_cursorReadouts->setTransparency(value); @@ -2387,8 +2399,8 @@ void CapturePlot::moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition void CapturePlot::updateBufferSizeSampleRateLabel(int nsamples, double sr) { QString txtSampleRate = d_cursorMetricFormatter.format(sr, "sps", 0); - QString txtSamplingPeriod = d_cursorTimeFormatter.format(1 / sr, "", 0); - QString text = QString("%1 Samples at ").arg(nsamples) + txtSampleRate; + QString txtSamples = d_cursorMetricFormatter.format(nsamples, "", 0); + QString text = QString("%1 Samples at ").arg(txtSamples) + txtSampleRate; d_sampleRateLabel->setText(text); } diff --git a/src/oscilloscope_plot.hpp b/src/oscilloscope_plot.hpp index 5e84c6e179..780dd6a50d 100644 --- a/src/oscilloscope_plot.hpp +++ b/src/oscilloscope_plot.hpp @@ -168,6 +168,7 @@ namespace adiscope { void setBufferSizeLabelValue(int numSamples); void setSampleRatelabelValue(double sampleRate); void setTriggerState(int triggerState); + void setMaxBufferSizeErrorLabel(bool reached); void setCursorReadoutsTransparency(int value); void moveCursorReadouts(CustomPlotPositionButton::ReadoutsPosition position); void setHorizCursorsLocked(bool value); @@ -249,6 +250,7 @@ namespace adiscope { QLabel *d_timeBaseLabel; QLabel *d_sampleRateLabel; QLabel *d_triggerStateLabel; + QLabel *d_maxBufferError; int d_bufferSizeLabelVal; double d_sampleRateLabelVal; diff --git a/src/patterngenerator/pattern_generator.cpp b/src/patterngenerator/pattern_generator.cpp index e14b711676..7d254188fd 100644 --- a/src/patterngenerator/pattern_generator.cpp +++ b/src/patterngenerator/pattern_generator.cpp @@ -751,10 +751,17 @@ void PatternGenerator::generateBuffer() m_sampleRate = sr; const uint64_t bufferSize = computeBufferSize(sr); + m_plot.setMaxBufferSizeErrorLabel(bufferSize == MAX_BUFFER_SIZE); qDebug() << "Buffer size is: " << bufferSize; m_bufferSize = bufferSize; + m_plot.setSampleRatelabelValue(m_sampleRate); + m_plot.setBufferSizeLabelValue(m_bufferSize); + m_plot.setTimeBaseLabelValue(static_cast(m_bufferSize) / + static_cast(m_sampleRate) / + m_plot.xAxisNumDiv()); + if (m_buffer) { delete[] m_buffer; } diff --git a/src/plot_line_handle.cpp b/src/plot_line_handle.cpp index a0bf5fd1ec..ce84120641 100644 --- a/src/plot_line_handle.cpp +++ b/src/plot_line_handle.cpp @@ -662,14 +662,14 @@ void FreePlotLineHandleV::paintEvent(QPaintEvent *) setToolTip(""); } - const double textHeight = QFontMetrics(QFont(fontFamily, fontSize)).height(); - - QPointF textPos(0.0, m_height / 2.0 + textHeight / 4.0); + const QSizeF size = QFontMetricsF(QFont(fontFamily, fontSize)).size(Qt::TextSingleLine, m_name); + QRectF textRect(QPointF(0.0, 0.0), size); + textRect.moveCenter(QPointF(m_image.width() / 2.0, m_height / 2.0)); p.save(); p.setPen(QPen(QBrush(Qt::white), 20)); p.setFont(QFont(fontFamily, fontSize)); - p.drawText(textPos, m_name); + p.drawText(textRect, m_name); p.restore(); } else { p.drawPixmap(imageTopLeft, m_image); diff --git a/src/scopyExceptionHandler.h b/src/scopyExceptionHandler.h index c334a0f01b..67a4f404d1 100644 --- a/src/scopyExceptionHandler.h +++ b/src/scopyExceptionHandler.h @@ -6,25 +6,33 @@ #include #include #include +#include using namespace adiscope; #define HANDLE_EXCEPTION(e) \ - if(GetScopyApplicationInstance()->getDebugMode()) { \ +if (GetScopyApplicationInstance()->getDebugMode()) { \ + auto me = dynamic_cast(&e); \ + auto handleLambda = [me, e](){ \ QMessageBox msg; \ QString str; \ - auto me = dynamic_cast(&e);\ - if(me) { \ + if (me) { \ str = QString("Exception %1\ne.type() - %2\ne.what() - %3\ne.iioCode() - %4\nthrown from %5:%6\ncaught in %7:%8\nScopy git tag %9\n") \ .arg("m2k_exception").arg(me->type()).arg(me->what()).arg(me->iioCode()).arg(QString::fromStdString(me->file())).arg(QString::number(me->line())).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ } else { \ str = QString("Exception %1\ncaught in %2:%3\nScopy git tag %4\n").arg(e.what()).arg(__FILE__).arg(__LINE__).arg(SCOPY_VERSION_GIT); \ } \ - if(WriteScopyMinidump()) { \ + if (WriteScopyMinidump()) { \ str = str + "Created minidump."; \ - }\ - msg.setText(str);\ - msg.exec();\ + } \ + msg.setText(str); \ + msg.exec(); \ + }; \ + if (GetScopyApplicationInstance()->thread() != QThread::currentThread()) { \ + QMetaObject::invokeMethod(GetScopyApplicationInstance(), handleLambda, Qt::BlockingQueuedConnection); \ + } else { \ + handleLambda(); \ } \ +} \ #endif // SCOPYEXCEPTIONHANDLER_H diff --git a/src/trigger_settings.cpp b/src/trigger_settings.cpp index da63fd0fcc..ff4f152c3c 100644 --- a/src/trigger_settings.cpp +++ b/src/trigger_settings.cpp @@ -74,7 +74,8 @@ TriggerSettings::TriggerSettings(M2kAnalogIn* libm2k_adc, trigger_raw_delay(0), daisyChainCompensation(0), m_trigger_in(false), - m_has_external_trigger_out(false) + m_has_external_trigger_out(false), + digital_trigger_was_on(false) { initInstrumentStrings(); ui->setupUi(this); @@ -169,6 +170,10 @@ TriggerSettings::TriggerSettings(M2kAnalogIn* libm2k_adc, wheelEventGuard->installEventRecursively(this); ui->mixedSignalLbl->setVisible(false); + ui->btnLogicAnalyzerTriggers->setVisible(false); + + connect(ui->btnLogicAnalyzerTriggers, &QPushButton::clicked, + this, &TriggerSettings::showLogicAnalyzerTriggerSettings); } TriggerSettings::~TriggerSettings() @@ -253,6 +258,12 @@ void TriggerSettings::enableMixedSignalView() ui->extern_en->setDisabled(true); ui->extern_to_en->setDisabled(true); ui->mixedSignalLbl->setVisible(true); + ui->btnLogicAnalyzerTriggers->setVisible(true); + ui->btnLogicAnalyzerTriggers->setEnabled(true); + digital_trigger_was_on = ui->digital_controls->isEnabled(); + if (digital_trigger_was_on) { + ui->digital_controls->setDisabled(true); + } } void TriggerSettings::disableMixedSignalView() @@ -260,6 +271,11 @@ void TriggerSettings::disableMixedSignalView() ui->extern_en->setEnabled(true); ui->extern_to_en->setEnabled(true); ui->mixedSignalLbl->setVisible(false); + ui->btnLogicAnalyzerTriggers->setVisible(false); + ui->btnLogicAnalyzerTriggers->setDisabled(true); + if (digital_trigger_was_on) { + ui->digital_controls->setEnabled(true); + } } void TriggerSettings::setDcLevelCoupled(double value) diff --git a/src/trigger_settings.hpp b/src/trigger_settings.hpp index cfb395e410..5e98953b16 100644 --- a/src/trigger_settings.hpp +++ b/src/trigger_settings.hpp @@ -84,6 +84,7 @@ namespace adiscope { void levelChanged(double); void analogTriggerEnabled(bool); void triggerModeChanged(int); + void showLogicAnalyzerTriggerSettings(); public Q_SLOTS: void setTriggerDelay(long long); @@ -145,6 +146,8 @@ namespace adiscope { libm2k::M2kHardwareTrigger* m_trigger; bool m_trigger_in; + bool digital_trigger_was_on; + std::vector> externalTriggerOutMapping; QList trigg_configs; diff --git a/ui/logic_analyzer.ui b/ui/logic_analyzer.ui index 24c62653bb..5ce6f7ce55 100644 --- a/ui/logic_analyzer.ui +++ b/ui/logic_analyzer.ui @@ -535,7 +535,7 @@ image: url(:/icons/setup3_checked_hover.svg); - 3 + 2 @@ -582,8 +582,8 @@ image: url(:/icons/setup3_checked_hover.svg); 0 0 - 200 - 272 + 310 + 469 @@ -639,6 +639,13 @@ font-weight: normal; + + + + + + + @@ -1470,8 +1477,8 @@ font-weight: normal; 0 0 - 315 - 469 + 300 + 258 @@ -2116,6 +2123,11 @@ color: rgba(255, 255, 255, 153); + + adiscope::CustomSwitch + QPushButton +
customSwitch.hpp
+
adiscope::DetachDragZone QWidget @@ -2139,11 +2151,6 @@ color: rgba(255, 255, 255, 153);
runsinglewidget.h
1
- - adiscope::CustomSwitch - QPushButton -
customSwitch.hpp
-
adiscope::InstrumentNotes QWidget diff --git a/ui/oscilloscope.ui b/ui/oscilloscope.ui index 0368cf98db..3b5c716ba1 100644 --- a/ui/oscilloscope.ui +++ b/ui/oscilloscope.ui @@ -139,6 +139,38 @@ QPushButton:hover {
+ + + + +QPushButton { + height: 40px; + + text-align: left; + font-weight: bold; + padding-left: 15px; + padding-right: 15px; + border-radius: 4px; + + background-color: #4a64ff; + color: #ffffff; + +} + +QPushButton:pressed { + background-color: #2a44df; +} + +QPushButton:hover { + background-color: #4a34ff; +} + + + Enable Mixed +Signal View + + + @@ -804,23 +836,7 @@ width: 14px; } QCheckBox::indicator:unchecked { background-color: transparent; } QCheckBox::indicator:checked { background-color: rgb(74,100,255); } - -QPushButton { -width: 40px; - height: 20px; - background-color: transparent; -} -QPushButton:pressed { border-image: url(:/icons/setup_btn_checked.svg); } -QPushButton:!pressed { border-image: url(:/icons/setup_btn_unchecked.svg); } -QPushButton:hover:!pressed:!checked { border-image: url(:/icons/setup_btn_hover.svg); } -QPushButton:checked { border-image: url(:/icons/setup_btn_checked.svg); } - -QLabel { -font-size: 14px; - font-weight: bold; - -color: rgba(255, 255, 255, 153); -}
+ diff --git a/ui/trigger_settings.ui b/ui/trigger_settings.ui index 513514bac2..f3ec9ef332 100644 --- a/ui/trigger_settings.ui +++ b/ui/trigger_settings.ui @@ -115,7 +115,7 @@ 0 0 266 - 887 + 929 @@ -482,19 +482,6 @@ color: rgba(255,255,255,51); - - - - color: white; - - - This feature is not supported while the Mixed Signal View is enabled! - - - true - - - @@ -560,6 +547,19 @@ color: rgba(255,255,255,51); + + + + color: white; + + + This feature is not supported while the Mixed Signal View is enabled! + + + true + + + @@ -670,6 +670,38 @@ color: rgba(255,255,255,51); + + + + +QPushButton { + +height: 40px; + + text-align: left; + font-weight: bold; + padding-left: 15px; + padding-right: 15px; + border-radius: 4px; + + background-color: #4a64ff; + color: #ffffff; + +} + +QPushButton:pressed { + background-color: #2a44df; +} + +QPushButton:hover { + background-color: #4a34ff; +} + + + Logic Analyzer trigger settings + + + @@ -937,7 +969,7 @@ color: rgba(255,255,255,51); verticalSpacer_3 trigger_logic_controls - mixedSignalLbl + btnLogicAnalyzerTriggers