From 559e058087f666af78af9db49adefcd4e6183f1f Mon Sep 17 00:00:00 2001 From: "andrei.danila" Date: Wed, 27 Mar 2024 08:06:24 +0200 Subject: [PATCH 1/3] plugins/swiotrefactor: Ad74413r tool refactoring. Signed-off-by: andrei.danila --- plugins/swiotrefactor/CMakeLists.txt | 8 + .../include/swiotrefactor/ad74413r/ad74413r.h | 160 ++++ .../ad74413r/bufferacquisitionhandler.h | 66 ++ .../swiotrefactor/ad74413r/bufferlogic.h | 95 +++ .../swiotrefactor/ad74413r/buffermenu.h | 266 +++++++ .../swiotrefactor/ad74413r/buffermenuview.h | 72 ++ .../swiotrefactor/ad74413r/channelplotscale.h | 61 ++ .../ad74413r/channelplotscalescontroller.h | 56 ++ .../include/swiotrefactor/ad74413r/chnlinfo.h | 65 ++ .../swiotrefactor/ad74413r/chnlinfobuilder.h | 36 + .../swiotrefactor/ad74413r/currentchnlinfo.h | 20 + .../swiotrefactor/ad74413r/digitalchnlinfo.h | 20 + .../ad74413r/resistancechnlinfo.h | 21 + .../swiotrefactor/ad74413r/voltagechnlinfo.h | 20 + .../swiotrefactor/externalpsreaderthread.h | 46 ++ .../include/swiotrefactor/readerthread.h | 14 +- .../include/swiotrefactor/swiotcontroller.h | 91 +++ .../include/swiotrefactor/swiotidentifytask.h | 20 + .../include/swiotrefactor/swiotinfopage.h | 48 ++ .../include/swiotrefactor/swiotpingtask.h | 32 + .../swiotrefactor/swiotreadtemperaturetask.h | 57 ++ .../include/swiotrefactor/swiotrefactor.h | 53 +- .../include/swiotrefactor/swiotruntime.h | 61 ++ .../swiotrefactor/src/ad74413r/ad74413r.cpp | 720 ++++++++++++++++++ .../src/ad74413r/bufferacquisitionhandler.cpp | 113 +++ .../src/ad74413r/bufferlogic.cpp | 320 ++++++++ .../swiotrefactor/src/ad74413r/buffermenu.cpp | 499 ++++++++++++ .../src/ad74413r/buffermenuview.cpp | 180 +++++ .../src/ad74413r/channelplotscale.cpp | 90 +++ .../ad74413r/channelplotscalescontroller.cpp | 109 +++ .../swiotrefactor/src/ad74413r/chnlinfo.cpp | 120 +++ .../src/ad74413r/chnlinfobuilder.cpp | 25 + .../src/ad74413r/currentchnlinfo.cpp | 23 + .../src/ad74413r/digitalchnlinfo.cpp | 21 + .../src/ad74413r/resistancechnlinfo.cpp | 22 + .../src/ad74413r/voltagechnlinfo.cpp | 24 + .../src/config/configchannelview.cpp | 186 +++++ .../src/config/configchannelview.h | 90 +++ .../src/config/configcontroller.cpp | 107 +++ .../src/config/configcontroller.h | 54 ++ .../swiotrefactor/src/config/configmodel.cpp | 240 ++++++ .../swiotrefactor/src/config/configmodel.h | 81 ++ plugins/swiotrefactor/src/config/drawarea.cpp | 68 ++ plugins/swiotrefactor/src/config/drawarea.h | 59 ++ .../swiotrefactor/src/config/swiotconfig.cpp | 167 ++++ .../swiotrefactor/src/config/swiotconfig.h | 79 ++ .../src/externalpsreaderthread.cpp | 90 +++ .../swiotrefactor/src/faults/faultspage.cpp | 8 +- .../src/max14906/diodigitalchannel.cpp | 2 + plugins/swiotrefactor/src/readerthread.cpp | 130 ++-- plugins/swiotrefactor/src/swiotcontroller.cpp | 211 +++++ .../swiotrefactor/src/swiotidentifytask.cpp | 62 ++ plugins/swiotrefactor/src/swiotinfopage.cpp | 53 ++ plugins/swiotrefactor/src/swiotpingtask.cpp | 50 ++ .../src/swiotreadtemperaturetask.cpp | 159 ++++ plugins/swiotrefactor/src/swiotrefactor.cpp | 408 ++++++++-- plugins/swiotrefactor/src/swiotruntime.cpp | 90 +++ 57 files changed, 5924 insertions(+), 124 deletions(-) create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/ad74413r.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferacquisitionhandler.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferlogic.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenu.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenuview.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscale.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscalescontroller.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfo.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfobuilder.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/currentchnlinfo.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/digitalchnlinfo.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/resistancechnlinfo.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/ad74413r/voltagechnlinfo.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/externalpsreaderthread.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotcontroller.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotidentifytask.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotinfopage.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotpingtask.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotreadtemperaturetask.h create mode 100644 plugins/swiotrefactor/include/swiotrefactor/swiotruntime.h create mode 100644 plugins/swiotrefactor/src/ad74413r/ad74413r.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/bufferacquisitionhandler.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/bufferlogic.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/buffermenu.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/buffermenuview.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/channelplotscale.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/channelplotscalescontroller.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/chnlinfo.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/chnlinfobuilder.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/currentchnlinfo.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/digitalchnlinfo.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/resistancechnlinfo.cpp create mode 100644 plugins/swiotrefactor/src/ad74413r/voltagechnlinfo.cpp create mode 100644 plugins/swiotrefactor/src/config/configchannelview.cpp create mode 100644 plugins/swiotrefactor/src/config/configchannelview.h create mode 100644 plugins/swiotrefactor/src/config/configcontroller.cpp create mode 100644 plugins/swiotrefactor/src/config/configcontroller.h create mode 100644 plugins/swiotrefactor/src/config/configmodel.cpp create mode 100644 plugins/swiotrefactor/src/config/configmodel.h create mode 100644 plugins/swiotrefactor/src/config/drawarea.cpp create mode 100644 plugins/swiotrefactor/src/config/drawarea.h create mode 100644 plugins/swiotrefactor/src/config/swiotconfig.cpp create mode 100644 plugins/swiotrefactor/src/config/swiotconfig.h create mode 100644 plugins/swiotrefactor/src/externalpsreaderthread.cpp create mode 100644 plugins/swiotrefactor/src/swiotcontroller.cpp create mode 100644 plugins/swiotrefactor/src/swiotidentifytask.cpp create mode 100644 plugins/swiotrefactor/src/swiotinfopage.cpp create mode 100644 plugins/swiotrefactor/src/swiotpingtask.cpp create mode 100644 plugins/swiotrefactor/src/swiotreadtemperaturetask.cpp create mode 100644 plugins/swiotrefactor/src/swiotruntime.cpp diff --git a/plugins/swiotrefactor/CMakeLists.txt b/plugins/swiotrefactor/CMakeLists.txt index f709b18ad2..981af0232b 100644 --- a/plugins/swiotrefactor/CMakeLists.txt +++ b/plugins/swiotrefactor/CMakeLists.txt @@ -35,8 +35,12 @@ file( src/max14906/*.cc src/faults/*.cpp src/faults/*.cc + src/ad74413r/*.cpp + src/ad74413r/*.cc src/*.cpp src/*.cc + src/config/*.cpp + src/config/*.cc model/* ) @@ -49,6 +53,10 @@ file( include/${SCOPY_MODULE}/max14906/*.hpp include/${SCOPY_MODULE}/faults/*.h include/${SCOPY_MODULE}/faults/*.hpp + include/${SCOPY_MODULE}/ad74413r/*.h + include/${SCOPY_MODULE}/ad74413r/*.hpp + include/${SCOPY_MODULE}/config/*.h + include/${SCOPY_MODULE}/config/*.hpp ) file(GLOB UI_LIST ui/*.ui) diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/ad74413r.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/ad74413r.h new file mode 100644 index 0000000000..2fc93f9ca3 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/ad74413r.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef AD74413R_H +#define AD74413R_H + +#include "bufferlogic.h" +#include "bufferacquisitionhandler.h" +#include "pluginbase/toolmenuentry.h" +#include "readerthread.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#define MAX_CURVES_NUMBER 8 +#define AD_NAME "ad74413r" +#define SWIOT_DEVICE_NAME "swiot" +#define MAX_SAMPLE_RATE 4800 + +namespace scopy { + +namespace swiotrefactor { +class Ad74413r : public QWidget +{ + Q_OBJECT +public: + explicit Ad74413r(QString uri = "", ToolMenuEntry *tme = 0, QWidget *parent = nullptr); + + ~Ad74413r(); + +public Q_SLOTS: + void onRunBtnPressed(bool toggled); + void onSingleBtnPressed(bool toggled); + + void onReaderThreadFinished(); + void onSingleCaptureFinished(); + + void onDiagnosticFunctionUpdated(); + + void onActivateRunBtns(bool activate); + + void handleConnectionDestroyed(); + + void onSamplingFrequencyUpdated(int channelId, int sampFreq); + +Q_SIGNALS: + void broadcastThreshold(); + void updateDiagSamplingFreq(QString data); + void activateRunBtns(bool activate); + void configBtnPressed(); + +private Q_SLOTS: + void onConfigBtnPressed(); + void showPlotLabels(bool b); + void setupChannel(int chnlIdx, QString function); + void onSamplingFreqComputed(double freq); + void onBufferRefilled(QMap> chnlData); + void onChannelBtnChecked(int chnWidgetId, bool en); + void samplingFreqWritten(bool written); + void onThresholdWritten(bool written); + +private: + void init(); + bool eventFilter(QObject *watched, QEvent *event) override; + void updateXData(int dataSize); + void plotData(QVector curveData, int chnlIdx); + void createDevicesMap(iio_context *ctx); + void setupConnections(); + void verifyChnlsChanges(); + void initTutorialProperties(); + void initPlotData(); + void initPlot(); + void setupToolTemplate(); + void setupDeviceBtn(); + void setupChannelBtn(MenuControlButton *btn, PlotChannel *ch, QString chnlId, int chnlIdx); + void setupMeasureButtonHelper(MenuControlButton *btn); + void setupChannelsMenuControlBtn(MenuControlButton *btn, QString name); + void updateMeasurements(PlotAxis *axis, int chnlIdx); + void createMeasurementsLabel(int chnlIdx, QPen chPen, QStringList labels); + QPushButton *createConfigBtn(); + QWidget *createSettingsMenu(QWidget *parent); + PlotAxis *createYChnlAxis(QPen pen, QString unitType = "V", int yMin = -1, int yMax = 1); + +private: + ToolMenuEntry *m_tme; + PositionSpinButton *m_timespanSpin; + + QVector m_enabledChannels; + + QString m_uri; + + BufferLogic *m_swiotAdLogic; + ReaderThread *m_readerThread; + BufferAcquisitionHandler *m_acqHandler; + CommandQueue *m_cmdQueue; + MeasurementsPanel *m_measurePanel; + + struct iio_context *m_ctx; + Connection *m_conn; + + ToolTemplate *m_tool; + RunBtn *m_runBtn; + SingleShotBtn *m_singleBtn; + QPushButton *m_configBtn; + GearBtn *m_settingsBtn; + InfoBtn *m_infoBtn; + + PlotWidget *m_plot; + TimePlotInfo *m_info; + PlotSamplingInfo m_currentSamplingInfo; + QMap m_plotChnls; + + QMap m_iioDevicesMap; + CollapsableMenuControlButton *m_devBtn; + MenuControlButton *m_chnlsMenuBtn; + QButtonGroup *m_rightMenuBtnGrp; + QButtonGroup *m_chnlsBtnGroup; + + MapStackedWidget *m_channelStack; + + int m_currentChannelSelected = 0; + QVector m_xTime; + QMap> m_labels; + + QTimer *m_rstAcqTimer; + const QString channelsMenuId = "channels"; + const QString measureMenuId = "measure"; +}; +} // namespace swiotrefactor +} // namespace scopy +#endif // AD74413R_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferacquisitionhandler.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferacquisitionhandler.h new file mode 100644 index 0000000000..5798b1d8fb --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferacquisitionhandler.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BUFFERACQUISITIONHANDLER_H +#define BUFFERACQUISITIONHANDLER_H + +#include +#include +#include + +namespace scopy::swiotrefactor { +#define DIAG_CHNLS_NUMBER 4 +class BufferAcquisitionHandler : public QObject +{ + Q_OBJECT +public: + BufferAcquisitionHandler(QObject *parent); + ~BufferAcquisitionHandler(); + + void setSingleCapture(bool en); + void resetPlotParameters(); + bool singleCapture() const; + int getRequiredBuffersNumber(); +public Q_SLOTS: + void onBufferRefilled(QMap> data, int bufferCounter); + void onTimespanChanged(double value); + void onSamplingFrequencyComputed(double samplingFrequency); +Q_SIGNALS: + void bufferDataReady(QMap> data); + void singleCaptureFinished(); + +private: + void resetDataPoints(); + + double m_plotSamplingFreq = 4800; + double m_timespan = 1; + + int m_buffersNumber = 0; + int m_bufferIndex = 0; + int m_bufferSize = 0; + + bool m_singleCapture = false; + + QMap> m_dataPoints; + QMutex *m_lock; +}; +} // namespace scopy::swiotrefactor + +#endif // BUFFERACQUISITIONHANDLER_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferlogic.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferlogic.h new file mode 100644 index 0000000000..f59ba3c973 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/bufferlogic.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BUFFERLOGIC_H +#define BUFFERLOGIC_H + +#include "chnlinfo.h" + +#include + +#include +#include + +#include +#include +#include + +Q_DECLARE_OPAQUE_POINTER(struct iio_buffer *) + +#define MAX_BUFFER_SIZE 160 +#define MIN_BUFFER_SIZE 5 +#define SAMPLING_FREQ_ATTR_NAME "sampling_frequency" +#define MAX_INPUT_CHNLS_NO 8 + +namespace scopy::swiotrefactor { +class BufferLogic : public QObject +{ + Q_OBJECT +public: + explicit BufferLogic(QMap devicesMap, CommandQueue *commandQueue); + + ~BufferLogic(); + + QMap getIioChnl(int chnlIdx); + + bool verifyChannelsEnabledChanges(QVector enabledChnls); + void applyChannelsEnabledChanges(QVector enabledChnls); + + void applySamplingFrequencyChanges(int channelId, int value); + + int getPlotChnlsNo(); + QString getPlotChnlUnitOfMeasure(int channel); + QVector getPlotChnlsUnitOfMeasure(); + std::pair getPlotChnlRangeValues(int channel); + QVector> getPlotChnlsRangeValues(); + std::pair getChnlOffsetScale(int channel); + QMap getPlotChnlsId(); + void initAd74413rChnlsFunctions(); + void initDiagnosticChannels(); + +Q_SIGNALS: + void chnlsChanged(QMap chnlsInfo); + void samplingFrequencyComputed(double value); + void channelFunctionDetermined(unsigned int i, QString function); + void instantValueChanged(int channel, double value); + +private Q_SLOTS: + void enabledChnCmdFinished(unsigned int i, scopy::Command *cmd); + void configuredDevCmdFinished(unsigned int i, scopy::Command *cmd); + void chnFunctionCmdFinished(unsigned int i, scopy::Command *cmd); + +private: + void createChannels(); + void initChannelFunction(unsigned int i); + void computeSamplingFrequency(); + +private: + int m_plotChnlsNo; + QMap m_iioDevicesMap; + QMap m_samplingFrequencies; + double m_samplingFrequency; + + QMap m_chnlsInfo; + CommandQueue *m_commandQueue; +}; +} // namespace scopy::swiotrefactor + +#endif // BUFFERLOGIC_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenu.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenu.h new file mode 100644 index 0000000000..b386e38013 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenu.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SWIOTADVMENU_H +#define SWIOTADVMENU_H + +#include +#include +#include +#include + +#define OUTPUT_CHNL "output" +#define INPUT_CHNL "input" + +namespace scopy::swiotrefactor { + +class BufferMenu : public QWidget +{ + Q_OBJECT +public: + explicit BufferMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~BufferMenu(); + + virtual QString getInfoMessage(); + + QList getWidgetsList(); + void addMenuWidget(QWidget *widget); + + void setOffsetScalePair(const std::pair &newOffsetScalePair); + double convertFromRaw(double rawValue); + +public Q_SLOTS: + virtual void onBroadcastThreshold(); + virtual void onDiagSamplingChange(QString samplingFreq); + virtual void onSamplingFreqWrite(QString data, QString dataOptions); + virtual void onRunBtnsPressed(bool en); + +Q_SIGNALS: + void diagnosticFunctionUpdated(); + void diagSamplingFreqChange(QString data); + void samplingFrequencyUpdated(int sr); + void freqChangeStart(); + void freqChangeEnd(); + void thresholdChangeStart(); + void thresholdChangeEnd(); + +protected: + IIOWidget *m_samplingFreq; + QString m_chnlFunction; + Connection *m_connection; + QMap m_chnls; + std::pair m_offsetScalePair = {0, 1}; + +private: + QList m_widgetsList; +}; + +class CurrentInLoopMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit CurrentInLoopMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~CurrentInLoopMenu(); + + QString getInfoMessage() override; + +private Q_SLOTS: + void updateCnvtLabel(QString data); + +private: + QLabel *m_cnvtLabel; +}; + +class DigitalInLoopMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit DigitalInLoopMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~DigitalInLoopMenu(); + + QString getInfoMessage() override; +public Q_SLOTS: + void onBroadcastThreshold() override; + void onRunBtnsPressed(bool en) override; + void onEmitStatus(int retCode); + +private Q_SLOTS: + void updateCnvtLabel(QString data); + +private: + IIOWidget *m_threshold; + QLabel *m_cnvtLabel; +}; + +class VoltageOutMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit VoltageOutMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~VoltageOutMenu(); + + QString getInfoMessage() override; + +private Q_SLOTS: + void updateCnvtLabel(QString data); + +private: + QLabel *m_cnvtLabel; +}; + +class CurrentOutMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit CurrentOutMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~CurrentOutMenu(); + + QString getInfoMessage() override; + +private Q_SLOTS: + void updateCnvtLabel(QString data); + +private: + QLabel *m_cnvtLabel; +}; + +class DiagnosticMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit DiagnosticMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~DiagnosticMenu(); + +public Q_SLOTS: + void onDiagSamplingChange(QString samplingFreq) override; + void onSamplingFreqWrite(QString data, QString dataOptions) override; +}; + +class DigitalInMenu : public BufferMenu +{ + Q_OBJECT +public: + explicit DigitalInMenu(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~DigitalInMenu(); + +public Q_SLOTS: + void onBroadcastThreshold() override; + void onRunBtnsPressed(bool en) override; + void onEmitStatus(int retCode); + +private: + IIOWidget *m_threshold; +}; + +class WithoutAdvSettings : public BufferMenu +{ + Q_OBJECT +public: + explicit WithoutAdvSettings(QWidget *parent = nullptr, QString chnlFunction = "", Connection *conn = nullptr, + QMap chnls = {}); + ~WithoutAdvSettings(); +}; + +class BufferMenuBuilder +{ + +public: + enum MenuType + { + CURRENT_IN_LOOP = 0, + DIGITAL_IN = 1, + DIGITAL_IN_LOOP = 2, + VOLTAGE_OUT = 3, + CURRENT_OUT = 4, + VOLTAGE_IN = 5, + CURRENT_IN_EXT = 6, + CURRENT_IN_LOOP_HART = 7, + CURRENT_IN_EXT_HART = 8, + RESISTANCE = 9, + DIAGNOSTIC = 10, + HIGH_Z = 11 + }; + + static int decodeFunctionName(QString function) + { + if(function.compare("voltage_in") == 0) { + return VOLTAGE_IN; + } else if(function.compare("current_in_ext") == 0) { + return CURRENT_IN_EXT; + } else if(function.compare("current_in_loop_hart") == 0) { + return CURRENT_IN_LOOP_HART; + } else if(function.compare("current_in_ext_hart") == 0) { + return CURRENT_IN_EXT_HART; + } else if(function.compare("resistance") == 0) { + return RESISTANCE; + } else if(function.compare("current_in_loop") == 0) { + return CURRENT_IN_LOOP; + } else if(function.compare("digital_input") == 0) { + return DIGITAL_IN; + } else if(function.compare("digital_input_loop") == 0) { + return DIGITAL_IN_LOOP; + } else if(function.compare("voltage_out") == 0) { + return VOLTAGE_OUT; + } else if(function.compare("current_out") == 0) { + return CURRENT_OUT; + } else if(function.compare("diagnostic") == 0) { + return DIAGNOSTIC; + } else if(function.compare("high_z") == 0) { + return HIGH_Z; + } else { + return -1; + } + } + + static BufferMenu *newAdvMenu(QWidget *widget, QString function, Connection *conn, + QMap chnls) + { + int menu_type = decodeFunctionName(function); + switch(menu_type) { + case CURRENT_IN_LOOP: + return new CurrentInLoopMenu(widget, function, conn, chnls); + case CURRENT_IN_LOOP_HART: + return new CurrentInLoopMenu(widget, function, conn, chnls); + case DIGITAL_IN_LOOP: + return new DigitalInLoopMenu(widget, function, conn, chnls); + case VOLTAGE_OUT: + return new VoltageOutMenu(widget, function, conn, chnls); + case CURRENT_OUT: + return new CurrentOutMenu(widget, function, conn, chnls); + case DIGITAL_IN: + return new DigitalInMenu(widget, function, conn, chnls); + case DIAGNOSTIC: + return new DiagnosticMenu(widget, function, conn, chnls); + default: + return new WithoutAdvSettings(widget, function, conn, chnls); + } + } +}; + +} // namespace scopy::swiotrefactor + +#endif // SWIOTADVMENU_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenuview.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenuview.h new file mode 100644 index 0000000000..0852f2e8b6 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/buffermenuview.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SWIOTGENERICMENU_H +#define SWIOTGENERICMENU_H + +#include "buffermenu.h" + +#include +#include +#include + +#include + +namespace scopy::swiotrefactor { +class BufferMenuView : public QWidget +{ + Q_OBJECT +public: + BufferMenuView(QMap chnls, Connection *conn, QWidget *parent = nullptr); + ~BufferMenuView(); + + void init(QString title, QString function, QPen color, QString unit, double yMin, double yMax); + + BufferMenu *getAdvMenu(); + +Q_SIGNALS: + void setYMin(double yMin); + void minChanged(double yMin); + void setYMax(double yMax); + void maxChanged(double yMax); + + void diagnosticFunctionUpdated(); + void samplingFrequencyUpdated(int val); + void diagSamplingFreqChange(QString data); + void updateDiagSamplingFreq(QString data); + void thresholdWritten(bool written); + void broadcastThreshold(); + void samplingFreqWritten(bool written); + + void runBtnsPressed(bool en); + +private: + void createConnections(); + QWidget *createDescriptionSection(QWidget *parent); + QWidget *createAttrSection(QWidget *parent); + QWidget *createVerticalSettingsMenu(QString unit, double yMin, double yMax, QWidget *parent); + + BufferMenu *m_swiotAdvMenu; + Connection *m_connection; + QMap m_chnls; +}; +} // namespace scopy::swiotrefactor + +#endif // SWIOTGENERICMENU_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscale.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscale.h new file mode 100644 index 0000000000..4503fa8d20 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscale.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CHANNELPLOTSCALE_H +#define CHANNELPLOTSCALE_H + +#include +#include + +#include + +namespace scopy::swiotrefactor { +class ChannelPlotScale : public QWidget +{ + Q_OBJECT +public: + explicit ChannelPlotScale(int channel, QString unit, QColor m_color, QWidget *parent = nullptr); + ~ChannelPlotScale(); + + void setInstantValue(double value); + void setUnitPerDivision(double value); + int getChannelId(); + bool getEnabled(); + void setEnabled(bool en); +Q_SIGNALS: + void requestUpdate(); + +private Q_SLOTS: + void update(); + +private: + QString m_unit; + QLabel *m_unitPerDivisionLbl; + QLabel *m_instantValueLbl; + QColor m_channelColor; + int m_channel; + double m_unitPerDivision; + double m_instantValue; + bool m_enabled; + MetricPrefixFormatter *m_formatter; +}; +} // namespace scopy::swiotrefactor + +#endif // CHANNELPLOTSCALE_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscalescontroller.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscalescontroller.h new file mode 100644 index 0000000000..18233f9ee8 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/channelplotscalescontroller.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CHANNELPLOTSCALESCONTROLLER_H +#define CHANNELPLOTSCALESCONTROLLER_H + +#include "channelplotscale.h" + +#include +#include +#include + +#include + +namespace scopy::swiotrefactor { +class ChannelPlotScalesController : public QWidget +{ + Q_OBJECT +public: + explicit ChannelPlotScalesController(QWidget *parent); + ~ChannelPlotScalesController(); + + void addChannel(int index, QColor color, QString unit, bool enabled); + void setChannelEnabled(int channel, bool enabled); + void setUnitPerDivision(int channel, double unitPerDivision); + void setInstantValue(int channel, double value); + +private: + void updateLayout(); + +private: + QString m_unit; + QColor *m_channelColor; + QVector m_channelPlotScales; + QHBoxLayout *m_layout; +}; +} // namespace scopy::swiotrefactor + +#endif // CHANNELPLOTSCALESCONTROLLER_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfo.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfo.h new file mode 100644 index 0000000000..e7c33f435e --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfo.h @@ -0,0 +1,65 @@ +#ifndef CHNLINFO_H +#define CHNLINFO_H + +#include "plot_utils.hpp" + +#include + +#include +#include + +#include +#include + +#define SWAP_UINT32(x) (((x) >> 24) | (((x)&0x00FF0000) >> 8) | (((x)&0x0000FF00) << 8) | ((x) << 24)) +namespace scopy::swiotrefactor { +class ChnlInfo : public QObject +{ + Q_OBJECT +public: + explicit ChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue); + ~ChnlInfo(); + + virtual double convertData(unsigned int data) = 0; + iio_channel *iioChnl() const; + + bool isOutput() const; + + bool isScanElement() const; + + QString chnlId() const; + + std::pair rangeValues() const; + + std::pair offsetScalePair() const; + + bool isEnabled() const; + void setIsEnabled(bool newIsEnabled); + + QString unitOfMeasure() const; + + void addReadScaleCommand(); + void addReadOffsetCommand(); +private Q_SLOTS: + void readScaleCommandFinished(scopy::Command *cmd); + void readOffsetCommandFinished(scopy::Command *cmd); + +protected: + bool m_isOutput; + bool m_isEnabled; + bool m_isScanElement; + QString m_chnlId; + QString m_plotUm; + QString m_hwUm; + std::pair m_rangeValues = {-5, 5}; + std::pair m_offsetScalePair; + QMap m_unitOfMeasureFactor; + CommandQueue *m_commandQueue; + +private: + void initUnitOfMeasureFactor(); + struct iio_channel *m_iioChnl; +}; +} // namespace scopy::swiotrefactor + +#endif // CHNLINFO_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfobuilder.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfobuilder.h new file mode 100644 index 0000000000..39b0eb6413 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/chnlinfobuilder.h @@ -0,0 +1,36 @@ +#ifndef CHNLINFOBUILDER_H +#define CHNLINFOBUILDER_H + +#include "chnlinfo.h" + +namespace scopy::swiotrefactor { +class ChnlInfoBuilder +{ +public: + enum ChnlInfoType + { + VOLTAGE = 0, + CURRENT = 1, + RESISTANCE = 2, + DIGITAL = 3 + }; + + static int decodeId(QString function) + { + if(function.compare("v") == 0) { + return VOLTAGE; + } else if(function.compare("c") == 0) { + return CURRENT; + } else if(function.compare("r") == 0) { + return RESISTANCE; + } else if(function.compare("d") == 0) { + return DIGITAL; + } else { + return -1; + } + } + static ChnlInfo *build(iio_channel *iioChnl, QString id, CommandQueue *cmdQueue); +}; +} // namespace scopy::swiotrefactor + +#endif // CHNLINFOBUILDER_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/currentchnlinfo.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/currentchnlinfo.h new file mode 100644 index 0000000000..a49f05f7d5 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/currentchnlinfo.h @@ -0,0 +1,20 @@ +#ifndef CURRENTCHNLINFO_H +#define CURRENTCHNLINFO_H + +#include "chnlinfo.h" +#define MIN_CURRENT_VALUE -25 +#define MAX_CURRENT_VALUE 25 +namespace scopy::swiotrefactor { +class CurrentChnlInfo : public ChnlInfo +{ + Q_OBJECT +public: + explicit CurrentChnlInfo(QString plotUm = "A", QString hwUm = "mA", iio_channel *iioChnl = nullptr, + CommandQueue *cmdQueue = nullptr); + ~CurrentChnlInfo(); + + double convertData(unsigned int data) override; +}; +} // namespace scopy::swiotrefactor + +#endif // CURRENTCHNLINFO_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/digitalchnlinfo.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/digitalchnlinfo.h new file mode 100644 index 0000000000..0fe9199287 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/digitalchnlinfo.h @@ -0,0 +1,20 @@ +#ifndef DIGITALCHNLINFO_H +#define DIGITALCHNLINFO_H + +#include "chnlinfo.h" +#define MIN_DIGITAL_VALUE -2 +#define MAX_DIGITAL_VALUE 2 +namespace scopy::swiotrefactor { +class DigitalChnlInfo : public ChnlInfo +{ + Q_OBJECT +public: + explicit DigitalChnlInfo(QString plotUm = "", QString hwUm = "", iio_channel *iioChnl = nullptr, + CommandQueue *cmdQueue = nullptr); + ~DigitalChnlInfo(); + + double convertData(unsigned int data) override; +}; +} // namespace scopy::swiotrefactor + +#endif // DIGITALCHNLINFO_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/resistancechnlinfo.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/resistancechnlinfo.h new file mode 100644 index 0000000000..5a874c41f3 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/resistancechnlinfo.h @@ -0,0 +1,21 @@ +#ifndef RESISTANCECHNLINFO_H +#define RESISTANCECHNLINFO_H +#include "chnlinfo.h" + +#define RPULL_UP 2100 +#define ADC_MAX_VALUE 65535 +#define MIN_RESISTANCE_VALUE 0 +#define MAX_RESISTANCE_VALUE 1000000000 +namespace scopy::swiotrefactor { +class ResistanceChnlInfo : public ChnlInfo +{ + Q_OBJECT +public: + explicit ResistanceChnlInfo(QString plotUm = "Ω", QString hwUm = "Ω", iio_channel *iioChnl = nullptr, + CommandQueue *cmdQueue = nullptr); + ~ResistanceChnlInfo(); + + double convertData(unsigned int data) override; +}; +} // namespace scopy::swiotrefactor +#endif // RESISTANCECHNLINFO_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/ad74413r/voltagechnlinfo.h b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/voltagechnlinfo.h new file mode 100644 index 0000000000..31008a1330 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/ad74413r/voltagechnlinfo.h @@ -0,0 +1,20 @@ +#ifndef VOLTAGECHNLINFO_H +#define VOLTAGECHNLINFO_H + +#include "chnlinfo.h" +#define MIN_VOLTAGE_VALUE -10 +#define MAX_VOLTAGE_VALUE 10 +namespace scopy::swiotrefactor { +class VoltageChnlInfo : public ChnlInfo +{ + Q_OBJECT +public: + explicit VoltageChnlInfo(QString plotUm = "V", QString hwUm = "mV", iio_channel *iioChnl = nullptr, + CommandQueue *cmdQueue = nullptr); + ~VoltageChnlInfo(); + + double convertData(unsigned int data) override; +}; +} // namespace scopy::swiotrefactor + +#endif // VOLTAGECHNLINFO_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/externalpsreaderthread.h b/plugins/swiotrefactor/include/swiotrefactor/externalpsreaderthread.h new file mode 100644 index 0000000000..0688ab6fdf --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/externalpsreaderthread.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCOPY_EXTERNALPSREADERTHREAD_H +#define SCOPY_EXTERNALPSREADERTHREAD_H + +#include +#include + +namespace scopy::swiotrefactor { +class ExternalPsReaderThread : public QThread +{ + Q_OBJECT +public: + explicit ExternalPsReaderThread(QString uri, QString attr, QObject *parent = nullptr); + ~ExternalPsReaderThread(); + + void run() override; +Q_SIGNALS: + void hasConnectedPowerSupply(bool ps); + +private: + QString m_uri; + QString m_attribute; + Connection *m_conn; +}; +} // namespace scopy::swiotrefactor + +#endif // SCOPY_EXTERNALPSREADERTHREAD_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/readerthread.h b/plugins/swiotrefactor/include/swiotrefactor/readerthread.h index 3dbf979964..41a007ae6e 100644 --- a/plugins/swiotrefactor/include/swiotrefactor/readerthread.h +++ b/plugins/swiotrefactor/include/swiotrefactor/readerthread.h @@ -21,7 +21,7 @@ #ifndef READERTHREAD_H #define READERTHREAD_H -//#include "src/runtime/ad74413r/chnlinfo.h" +#include "ad74413r/chnlinfo.h" #include @@ -62,7 +62,7 @@ class ReaderThread : public QThread int getEnabledChnls(); - // QVector getEnabledBufferedChnls(); + QVector getEnabledBufferedChnls(); void startCapture(int requiredBuffersNumber = 0); @@ -70,12 +70,12 @@ class ReaderThread : public QThread void forcedStop(); public Q_SLOTS: void handleConnectionDestroyed(); - // void onChnlsChange(QMap chnlsInfo); + void onChnlsChange(QMap chnlsInfo); void onSamplingFrequencyComputed(double samplingFreq); Q_SIGNALS: void readerThreadFinished(); - void bufferRefilled(QVector> bufferData, int bufferCounter); + void bufferRefilled(QMap> bufferData, int bufferCounter); void channelDataChanged(int channelId, double value); private Q_SLOTS: @@ -100,9 +100,9 @@ private Q_SLOTS: struct iio_device *m_iioDev; struct iio_buffer *m_iioBuff; - // QMap m_chnlsInfo; - // QVector m_bufferedChnls; - QVector> m_bufferData; + QMap m_chnlsInfo; + QVector m_bufferedChnls; + QMap> m_bufferData; std::atomic m_running, m_bufferInvalid; std::mutex m_mutex; }; diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotcontroller.h b/plugins/swiotrefactor/include/swiotrefactor/swiotcontroller.h new file mode 100644 index 0000000000..bfec9c4759 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotcontroller.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SWIOTCONTROLLER_H +#define SWIOTCONTROLLER_H + +#include "iioutil/cyclicaltask.h" +#include "externalpsreaderthread.h" +#include "swiotidentifytask.h" +#include "swiotpingtask.h" +#include "swiotreadtemperaturetask.h" + +#include + +#include + +namespace scopy::swiotrefactor { +class SwiotController : public QObject +{ + Q_OBJECT +public: + SwiotController(QString uri, QObject *parent = nullptr); + ~SwiotController(); + + void startPingTask(); + void stopPingTask(); + + void startPowerSupplyTask(QString attribute); + void stopPowerSupplyTask(); + + void startTemperatureTask(); + void stopTemperatureTask(); + + void connectSwiot(); + void disconnectSwiot(); + +public Q_SLOTS: + void identify(); + void writeModeAttribute(QString mode); + void readModeAttribute(); + +Q_SIGNALS: + void pingSuccess(); + void pingFailed(); + void hasConnectedPowerSupply(bool ps); + void readTemperature(double temperature); + void modeAttributeChanged(QString mode); + void isRuntimeCtxChanged(bool isRuntimeCtx); + void writeModeFailed(); +private Q_SLOTS: + void writeModeCommandFinished(scopy::Command *cmd); + void readModeCommandFinished(scopy::Command *cmd); + +private: + void setIsRuntimeCtx(bool runtimeCtx); + + SwiotIdentifyTask *identifyTask; + SwiotPingTask *pingTask; + ExternalPsReaderThread *extPsTask; + SwiotReadTemperatureTask *temperatureTask; + CommandQueue *m_cmdQueue; + iio_context *m_iioCtx; + Connection *m_conn; + QString uri; + bool m_isRuntimeCtx; + bool m_temperatureReadEn; + + CyclicalTask *pingTimer; + CyclicalTask *powerSupplyTimer; + CyclicalTask *temperatureTimer; +}; +} // namespace scopy::swiotrefactor + +#endif // SWIOTCONTROLLER_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotidentifytask.h b/plugins/swiotrefactor/include/swiotrefactor/swiotidentifytask.h new file mode 100644 index 0000000000..89c07bffaa --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotidentifytask.h @@ -0,0 +1,20 @@ +#ifndef SWIOTIDENTIFYTASK_H +#define SWIOTIDENTIFYTASK_H + +#include +#include + +namespace scopy::swiotrefactor { +class SwiotIdentifyTask : public QThread +{ +public: + SwiotIdentifyTask(QString uri, QObject *parent = nullptr); + ~SwiotIdentifyTask(); + void run() override; + +private: + QString m_uri; + Connection *m_conn; +}; +} // namespace scopy::swiotrefactor +#endif // SWIOTIDENTIFYTASK_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotinfopage.h b/plugins/swiotrefactor/include/swiotrefactor/swiotinfopage.h new file mode 100644 index 0000000000..2007cfe6f7 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotinfopage.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCOPY_SWIOTINFOPAGE_H +#define SCOPY_SWIOTINFOPAGE_H + +#include +#include +#include + +#include + +namespace scopy::swiotrefactor { +class SwiotInfoPage : public InfoPage +{ + Q_OBJECT +public: + explicit SwiotInfoPage(QWidget *parent = nullptr); + void enableTemperatureReadBtn(bool enable); + +Q_SIGNALS: + void temperatureReadEnabled(bool toggled); + +private: + void initTempCheckBox(); + + QCheckBox *m_enTempReadCheckBox; +}; +} // namespace scopy::swiotrefactor + +#endif // SCOPY_SWIOTINFOPAGE_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotpingtask.h b/plugins/swiotrefactor/include/swiotrefactor/swiotpingtask.h new file mode 100644 index 0000000000..dce7114bb8 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotpingtask.h @@ -0,0 +1,32 @@ +#ifndef SWIOTPINGTASK_H +#define SWIOTPINGTASK_H + +#include + +#include + +#include +#include + +namespace scopy::swiotrefactor { +class SwiotPingTask : public QThread +{ + Q_OBJECT +public: + SwiotPingTask(Connection *conn, QObject *parent = nullptr); + ~SwiotPingTask(); + virtual void run() override; +Q_SIGNALS: + void pingSuccess(); + void pingFailed(); + +protected: + QString m_uri; + Connection *c; + bool enabled; + +private Q_SLOTS: + void getTriggerCommandFinished(scopy::Command *cmd); +}; +} // namespace scopy::swiotrefactor +#endif // SWIOTPINGTASK_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotreadtemperaturetask.h b/plugins/swiotrefactor/include/swiotrefactor/swiotreadtemperaturetask.h new file mode 100644 index 0000000000..94f9f6e708 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotreadtemperaturetask.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCOPY_SWIOTREADTEMPERATURETASK_H +#define SCOPY_SWIOTREADTEMPERATURETASK_H + +#include + +#include + +#include +#include + +namespace scopy::swiotrefactor { +class SwiotReadTemperatureTask : public QThread +{ + Q_OBJECT +public: + explicit SwiotReadTemperatureTask(QString uri, QObject *parent = nullptr); + ~SwiotReadTemperatureTask(); + void run() override; + +Q_SIGNALS: + void newTemperature(double value); + +private Q_SLOTS: + void readRawCommandFinished(scopy::Command *cmd); + void readScaleCommandFinished(scopy::Command *cmd); + void readOffsetCommandFinished(scopy::Command *cmd); + +private: + QString m_uri; + struct iio_channel *m_channel; + struct iio_device *m_device; + Connection *m_conn; + double m_raw, m_scale, m_offset; +}; +} // namespace scopy::swiotrefactor + +#endif // SCOPY_SWIOTREADTEMPERATURETASK_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotrefactor.h b/plugins/swiotrefactor/include/swiotrefactor/swiotrefactor.h index a20be6c54c..d95517155e 100644 --- a/plugins/swiotrefactor/include/swiotrefactor/swiotrefactor.h +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotrefactor.h @@ -3,8 +3,18 @@ #define SCOPY_PLUGIN_NAME SWIOTREFACTORPlugin +#define AD74413R_TME_ID "swiotad74413r" +#define CONFIG_TME_ID "swiotconfig" +#define FAULTS_TME_ID "swiotfaults" +#define MAX14906_TME_ID "swiotmax14906" + #include "scopy-swiotrefactor_export.h" +#include "swiotcontroller.h" +#include "swiotruntime.h" +#include "swiotinfopage.h" #include +#include +#include #include #include @@ -15,17 +25,58 @@ class SCOPY_SWIOTREFACTOR_EXPORT SWIOTREFACTORPlugin : public QObject, public Pl SCOPY_PLUGIN; public: - bool compatible(QString m_param, QString category) override; + void preload() override; bool loadPage() override; + bool loadExtraButtons() override; bool loadIcon() override; void loadToolList() override; void unload() override; + bool compatible(QString param, QString category) override; void initMetadata() override; QString description() override; public Q_SLOTS: bool onConnect() override; bool onDisconnect() override; + void onIsRuntimeCtxChanged(bool isRuntimeCtx); + + void startTutorial(); + void abortTutorial(); + + void startAd74413rTutorial(); + void startMax14906Tutorial(); + void startFaultsTutorial(); + + void powerSupplyStatus(bool ps); + +private Q_SLOTS: + void setCtxMode(QString mode); + void onModeAttributeChanged(QString mode); + +private: + void switchCtx(); + void setupToolList(); + void createStatusContainer(); + QPushButton *m_btnIdentify; + QPushButton *m_btnTutorial; + QWidget *m_statusContainer; + SwiotInfoPage *m_infoPage; + + QWidget *config; + QWidget *adtool; + QWidget *faults; + QWidget *maxtool; + + SwiotController *m_swiotController; + SwiotRuntime *m_runtime; + + gui::TutorialBuilder *m_ad74413rTutorial; + gui::TutorialBuilder *m_max14906Tutorial; + gui::TutorialBuilder *m_faultsTutorial; + + bool m_isRuntime; + bool m_switchCmd = false; + QString m_ctxMode; }; } // namespace scopy::swiotrefactor #endif // SWIOTREFACTORPLUGIN_H diff --git a/plugins/swiotrefactor/include/swiotrefactor/swiotruntime.h b/plugins/swiotrefactor/include/swiotrefactor/swiotruntime.h new file mode 100644 index 0000000000..66c6bb9622 --- /dev/null +++ b/plugins/swiotrefactor/include/swiotrefactor/swiotruntime.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SWIOTRUNTIME_H +#define SWIOTRUNTIME_H + +#include +#include +#include + +#include + +namespace scopy::swiotrefactor { +#define AD_NAME "ad74413r" +#define AD_TRIGGER_NAME "ad74413r-dev0" + +class SwiotRuntime : public QObject +{ + Q_OBJECT +public: + SwiotRuntime(QString m_uri, QObject *parent = nullptr); + ~SwiotRuntime(); + +public Q_SLOTS: + void onBackBtnPressed(); + void writeTriggerDevice(); + void onIsRuntimeCtxChanged(bool isRuntimeCtx); +private Q_SLOTS: + void setTriggerCommandFinished(scopy::Command *); +Q_SIGNALS: + void writeModeAttribute(QString mode); + +private: + void createDevicesMap(); + +private: + QString m_uri; + iio_context *m_iioCtx; + QMap m_iioDevices; + CommandQueue *m_cmdQueue; +}; +} // namespace scopy::swiotrefactor + +#endif // SWIOTRUNTIME_H diff --git a/plugins/swiotrefactor/src/ad74413r/ad74413r.cpp b/plugins/swiotrefactor/src/ad74413r/ad74413r.cpp new file mode 100644 index 0000000000..d51f5e901e --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/ad74413r.cpp @@ -0,0 +1,720 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/ad74413r.h" + +#include "ad74413r/buffermenuview.h" +#include "swiot_logging_categories.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace scopy::swiotrefactor; +using namespace scopy; + +Ad74413r::Ad74413r(QString uri, ToolMenuEntry *tme, QWidget *parent) + : QWidget(parent) + , m_uri(uri) + , m_tme(tme) + , m_swiotAdLogic(nullptr) + , m_readerThread(nullptr) + , m_currentChannelSelected(0) +{ + initPlotData(); + setupToolTemplate(); + m_conn = ConnectionProvider::open(m_uri); + if(m_conn) { + connect(m_conn, &Connection::aboutToBeDestroyed, this, &Ad74413r::handleConnectionDestroyed); + m_ctx = m_conn->context(); + m_cmdQueue = m_conn->commandQueue(); + createDevicesMap(m_ctx); + init(); + } + initTutorialProperties(); +} + +Ad74413r::~Ad74413r() +{ + if(m_readerThread) { + m_readerThread->forcedStop(); + delete m_readerThread; + } + if(m_conn) { + ConnectionProvider::close(m_uri); + } +} + +void Ad74413r::handleConnectionDestroyed() +{ + qDebug(CAT_SWIOT_AD74413R) << "Ad74413R connection destroyed slot"; + m_ctx = nullptr; + m_cmdQueue = nullptr; + m_conn = nullptr; +} + +void Ad74413r::init() +{ + if(m_iioDevicesMap.contains(AD_NAME) && m_iioDevicesMap.contains(SWIOT_DEVICE_NAME)) { + char mode[64]; + ssize_t result = iio_device_attr_read(m_iioDevicesMap[SWIOT_DEVICE_NAME], "mode", mode, 64); + if((result >= 0) && (strcmp(mode, "runtime") == 0)) { + m_enabledChannels = QVector(MAX_CURVES_NUMBER, false); + + m_swiotAdLogic = new BufferLogic(m_iioDevicesMap, m_cmdQueue); + m_readerThread = new ReaderThread(true, m_cmdQueue, this); + m_readerThread->addBufferedDevice(m_iioDevicesMap[AD_NAME]); + m_acqHandler = new BufferAcquisitionHandler(this); + m_rstAcqTimer = new QTimer(this); + + setupConnections(); + m_swiotAdLogic->initAd74413rChnlsFunctions(); + } + } +} + +void Ad74413r::setupConnections() +{ + connect(m_conn, &Connection::aboutToBeDestroyed, m_readerThread, &ReaderThread::handleConnectionDestroyed); + connect(m_configBtn, &QPushButton::pressed, this, &Ad74413r::onConfigBtnPressed); + connect(m_runBtn, &QPushButton::toggled, this, &Ad74413r::onRunBtnPressed); + connect(m_singleBtn, &QPushButton::toggled, this, &Ad74413r::onSingleBtnPressed); + + connect(m_swiotAdLogic, &BufferLogic::chnlsChanged, m_readerThread, &ReaderThread::onChnlsChange); + connect(m_swiotAdLogic, &BufferLogic::samplingFrequencyComputed, m_readerThread, + &ReaderThread::onSamplingFrequencyComputed); + connect(m_swiotAdLogic, &BufferLogic::samplingFrequencyComputed, m_acqHandler, + &BufferAcquisitionHandler::onSamplingFrequencyComputed); + + connect(m_swiotAdLogic, &BufferLogic::samplingFrequencyComputed, this, &Ad74413r::onSamplingFreqComputed); + connect(this, &Ad74413r::activateRunBtns, this, &Ad74413r::onActivateRunBtns); + + connect(m_swiotAdLogic, &BufferLogic::channelFunctionDetermined, this, &Ad74413r::setupChannel); + connect(m_tme, &ToolMenuEntry::runToggled, m_runBtn, &QPushButton::setChecked); + + connect(m_readerThread, &ReaderThread::bufferRefilled, m_acqHandler, + &BufferAcquisitionHandler::onBufferRefilled, Qt::QueuedConnection); + connect(m_readerThread, &ReaderThread::readerThreadFinished, this, &Ad74413r::onReaderThreadFinished, + Qt::QueuedConnection); + connect(m_acqHandler, &BufferAcquisitionHandler::bufferDataReady, this, &Ad74413r::onBufferRefilled); + connect(m_acqHandler, &BufferAcquisitionHandler::singleCaptureFinished, this, + &Ad74413r::onSingleCaptureFinished, Qt::QueuedConnection); + + connect(m_timespanSpin, &PositionSpinButton::valueChanged, m_acqHandler, + &BufferAcquisitionHandler::onTimespanChanged); + + connect(m_rstAcqTimer, &QTimer::timeout, this, [&]() { + m_rstAcqTimer->stop(); + m_runBtn->setChecked(true); + }); +} + +void Ad74413r::onChannelBtnChecked(int chnlIdx, bool en) +{ + m_enabledChannels[chnlIdx] = en; + verifyChnlsChanges(); + bool activateBtns = + std::find(m_enabledChannels.begin(), m_enabledChannels.end(), true) != m_enabledChannels.end(); + + Q_EMIT activateRunBtns(activateBtns); +} + +void Ad74413r::samplingFreqWritten(bool written) +{ + bool activateBtns = + std::find(m_enabledChannels.begin(), m_enabledChannels.end(), true) != m_enabledChannels.end(); + Q_EMIT activateRunBtns(activateBtns && written); +} + +void Ad74413r::onThresholdWritten(bool written) +{ + bool activateBtns = + std::find(m_enabledChannels.begin(), m_enabledChannels.end(), true) != m_enabledChannels.end(); + if(written) { + Q_EMIT broadcastThreshold(); + } + Q_EMIT activateRunBtns(activateBtns && written); +} + +void Ad74413r::onActivateRunBtns(bool enable) +{ + if(!enable) { + if(m_runBtn->isChecked()) { + m_runBtn->setChecked(false); + } + if(m_singleBtn->isChecked()) { + m_singleBtn->setChecked(false); + } + m_runBtn->setEnabled(false); + m_singleBtn->setEnabled(false); + m_tme->setRunEnabled(false); + } else { + m_runBtn->setEnabled(true); + m_singleBtn->setEnabled(true); + m_tme->setRunEnabled(true); + } +} + +void Ad74413r::onRunBtnPressed(bool toggled) +{ + if(toggled) { + m_singleBtn->setChecked(false); + m_singleBtn->setEnabled(false); + verifyChnlsChanges(); + if(!m_readerThread->isRunning()) { + m_acqHandler->setSingleCapture(false); + m_acqHandler->resetPlotParameters(); + m_readerThread->startCapture(); + } + if(!m_tme->running()) { + m_tme->setRunning(toggled); + } + } else { + m_singleBtn->setEnabled(true); + m_readerThread->requestStop(); + if(m_tme->running()) { + m_tme->setRunning(toggled); + } + } +} + +void Ad74413r::onSingleBtnPressed(bool toggled) +{ + bool runBtnChecked = m_runBtn->isChecked(); + if(toggled) { + verifyChnlsChanges(); + if(runBtnChecked) { + m_runBtn->setChecked(false); + } + m_acqHandler->setSingleCapture(true); + if(!m_readerThread->isRunning()) { + m_acqHandler->resetPlotParameters(); + int bufNumber = m_acqHandler->getRequiredBuffersNumber(); + m_readerThread->startCapture(bufNumber); + } + m_singleBtn->setEnabled(false); + } +} + +void Ad74413r::verifyChnlsChanges() +{ + bool changes = m_swiotAdLogic->verifyChannelsEnabledChanges(m_enabledChannels); + if(changes) { + m_readerThread->requestStop(); + m_swiotAdLogic->applyChannelsEnabledChanges(m_enabledChannels); + } +} + +void Ad74413r::createDevicesMap(iio_context *ctx) +{ + int devicesCount = iio_context_get_devices_count(ctx); + for(int i = 0; i < devicesCount; i++) { + struct iio_device *iioDev = iio_context_get_device(ctx, i); + if(iioDev) { + QString deviceName = QString(iio_device_get_name(iioDev)); + if((deviceName.compare(AD_NAME) && deviceName.compare(SWIOT_DEVICE_NAME)) == 0) { + m_iioDevicesMap[deviceName] = iioDev; + } + } + } +} + +void Ad74413r::onSamplingFrequencyUpdated(int channelId, int value) +{ + m_readerThread->requestStop(); + m_swiotAdLogic->applySamplingFrequencyChanges(channelId, value); +} + +void Ad74413r::onDiagnosticFunctionUpdated() +{ + m_readerThread->requestStop(); + m_swiotAdLogic->applyChannelsEnabledChanges(m_enabledChannels); +} + +void Ad74413r::onConfigBtnPressed() +{ + bool runBtnChecked = m_runBtn->isChecked(); + bool singleBtnChecked = m_singleBtn->isChecked(); + + if(runBtnChecked) { + m_runBtn->setChecked(false); + } + if(singleBtnChecked) { + m_singleBtn->setChecked(false); + } + Q_EMIT configBtnPressed(); +} + +// TBD - The value of 500 is set so that the device reaches a stable state before the new acquisition +// It is possible that this problem can be solved in other way +void Ad74413r::onReaderThreadFinished() +{ + bool singleCaptureOn = m_acqHandler->singleCapture(); + if(singleCaptureOn) { + m_acqHandler->setSingleCapture(false); + } + if(m_runBtn->isChecked()) { + onRunBtnPressed(false); + m_rstAcqTimer->start(500); + } + if(m_singleBtn->isChecked()) { + m_singleBtn->setChecked(false); + } +} + +void Ad74413r::onSingleCaptureFinished() +{ + bool runBtnChecked = m_runBtn->isChecked(); + if(!runBtnChecked) { + if(m_tme->running()) { + m_tme->setRunning(false); + } + m_singleBtn->setEnabled(true); + } + m_readerThread->requestStop(); + m_singleBtn->setChecked(false); +} + +void Ad74413r::updateXData(int dataSize) +{ + double timespanValue = m_timespanSpin->value(); + double plotSamples = m_currentSamplingInfo.sampleRate * timespanValue; + if(m_xTime.size() == plotSamples && dataSize == plotSamples) { + return; + } + m_xTime.clear(); + for(int i = dataSize - 1; i >= 0; i--) { + m_xTime.push_back(-(i / plotSamples) * timespanValue); + } +} + +void Ad74413r::plotData(QVector chnlData, int chnlIdx) +{ + int dataSize = chnlData.size(); + updateXData(dataSize); + m_plotChnls[chnlIdx]->curve()->setSamples(m_xTime.data(), chnlData.data(), dataSize); + m_currentSamplingInfo.plotSize = dataSize; + m_info->update(m_currentSamplingInfo); + m_plot->replot(); +} + +void Ad74413r::onBufferRefilled(QMap> bufferData) +{ + QList chnls = m_plotChnls.keys(); + int dataIdx = 0; + for(int chnlIdx : chnls) { + if(!m_enabledChannels[chnlIdx]) { + continue; + } + plotData(bufferData[dataIdx], chnlIdx); + m_labels[chnlIdx].last()->setValue(bufferData[dataIdx].last()); + dataIdx++; + } +} + +void Ad74413r::onSamplingFreqComputed(double freq) +{ + m_currentSamplingInfo.sampleRate = freq; + m_info->update(m_currentSamplingInfo); +} + +void Ad74413r::initPlotData() +{ + m_currentSamplingInfo.startingPoint = 0; + m_currentSamplingInfo.plotSize = 0; + m_currentSamplingInfo.sampleRate = MAX_SAMPLE_RATE; + m_currentSamplingInfo.freqOffset = 0; + + m_xTime.clear(); + for(int i = m_currentSamplingInfo.sampleRate - 1; i >= 0; i--) { + m_xTime.push_back(-(i / m_currentSamplingInfo.sampleRate)); + } +} + +void Ad74413r::initPlot() +{ + m_plot->xAxis()->setInterval(-1, 0); + m_plot->xAxis()->scaleDraw()->setFormatter(new MetricPrefixFormatter()); + m_plot->xAxis()->scaleDraw()->setFloatPrecision(2); + m_plot->xAxis()->setVisible(false); + m_plot->yAxis()->setVisible(false); + m_plot->replot(); +} + +void Ad74413r::showPlotLabels(bool b) +{ + m_plot->setShowXAxisLabels(b); + m_plot->setShowYAxisLabels(b); + m_plot->showAxisLabels(); +} + +PlotAxis *Ad74413r::createYChnlAxis(QPen pen, QString unitType, int yMin, int yMax) +{ + PlotAxis *chYAxis = new PlotAxis(QwtAxis::YRight, m_plot, pen); + chYAxis->setVisible(false); + chYAxis->setInterval(yMin, yMax); + chYAxis->scaleDraw()->setFormatter(new MetricPrefixFormatter()); + chYAxis->scaleDraw()->setFloatPrecision(2); + chYAxis->scaleDraw()->setUnitType(unitType); + return chYAxis; +} + +void Ad74413r::setupChannelBtn(MenuControlButton *btn, PlotChannel *ch, QString chnlId, int chnlIdx) +{ + btn->setName(chnlId); + btn->setCheckBoxStyle(MenuControlButton::CS_CIRCLE); + btn->setOpenMenuChecksThis(true); + btn->setDoubleClickToOpenMenu(true); + btn->setColor(ch->curve()->pen().color()); + btn->button()->setVisible(false); + btn->setCheckable(true); + btn->checkBox()->setChecked(false); + + connect(btn, &MenuControlButton::toggled, this, [=, this](bool en) { + if(!en) { + return; + } + if(btn->checkBox()->isChecked()) { + m_plot->selectChannel(ch); + m_plot->replot(); + } + m_chnlsMenuBtn->button()->setChecked(en); + m_channelStack->show(chnlId); + }); + + connect( + btn->checkBox(), &QCheckBox::toggled, this, + [=, this](bool en) { + onChannelBtnChecked(chnlIdx, en); + ch->handle()->handle()->setVisible(en); + ch->setEnabled(en); + if(en && btn->isChecked()) { + m_plot->selectChannel(ch); + } + m_plot->replot(); + }, + Qt::DirectConnection); +} + +void Ad74413r::setupChannel(int chnlIdx, QString function) +{ + if(function.compare("no_config") != 0) { + QString chnlId(function + " " + QString::number(chnlIdx + 1)); + QPen chPen = QPen(QColor(StyleHelper::getColor("CH" + QString::number(chnlIdx))), 1); + + QString unit = m_swiotAdLogic->getPlotChnlUnitOfMeasure(chnlIdx); + auto yRange = m_swiotAdLogic->getPlotChnlRangeValues(chnlIdx); + + PlotAxis *chYAxis = createYChnlAxis(chPen, unit, yRange.first, yRange.second); + PlotChannel *plotCh = new PlotChannel(chnlId, chPen, m_plot->xAxis(), chYAxis, this); + m_plot->addPlotChannel(plotCh); + plotCh->setEnabled(false); + + PlotAxisHandle *chHandle = new PlotAxisHandle(m_plot, chYAxis); + chHandle->handle()->setBarVisibility(BarVisibility::ON_HOVER); + chHandle->handle()->setColor(chPen.color()); + chHandle->handle()->setHandlePos(HandlePos::SOUTH_EAST); + connect(chHandle, &PlotAxisHandle::scalePosChanged, this, [=](double pos) { + double min = chYAxis->min() - pos; + double max = chYAxis->max() - pos; + chYAxis->setInterval(min, max); + m_plot->plot()->replot(); + }); + plotCh->setHandle(chHandle); + m_plot->addPlotAxisHandle(chHandle); + m_plotChnls.insert(chnlIdx, plotCh); + + QString unitPerDivLabel = unit + "/div"; + QString valueLabel = "Value(" + unit + ")"; + createMeasurementsLabel(chnlIdx, chPen, {unitPerDivLabel, valueLabel}); + updateMeasurements(chYAxis, chnlIdx); + + QMap chnlsMap = m_swiotAdLogic->getIioChnl(chnlIdx); + BufferMenuView *menu = new BufferMenuView(chnlsMap, m_conn, this); + menu->init(chnlId, function, chPen, unit, yRange.first, yRange.second); + std::pair offsetScale = {0, 1}; + offsetScale = (chnlsMap.size() > 1) ? m_swiotAdLogic->getChnlOffsetScale(chnlIdx + MAX_INPUT_CHNLS_NO) + : m_swiotAdLogic->getChnlOffsetScale(chnlIdx); + menu->getAdvMenu()->setOffsetScalePair(offsetScale); + + m_channelStack->add(chnlId, menu); + + MenuControlButton *btn = new MenuControlButton(m_devBtn); + m_devBtn->add(btn); + m_chnlsBtnGroup->addButton(btn); + setupChannelBtn(btn, plotCh, chnlId, chnlIdx); + + connect(m_runBtn, &QPushButton::toggled, menu, &BufferMenuView::runBtnsPressed); + connect(m_singleBtn, &QPushButton::toggled, menu, &BufferMenuView::runBtnsPressed); + + connect(menu, &BufferMenuView::setYMin, chYAxis, &PlotAxis::setMin); + connect(chYAxis, &PlotAxis::minChanged, this, [=, this]() { + updateMeasurements(chYAxis, chnlIdx); + Q_EMIT menu->minChanged(chYAxis->min()); + }); + connect(menu, &BufferMenuView::setYMax, chYAxis, &PlotAxis::setMax); + connect(chYAxis, &PlotAxis::maxChanged, this, [=, this]() { + updateMeasurements(chYAxis, chnlIdx); + Q_EMIT menu->maxChanged(chYAxis->max()); + }); + + connect(menu, &BufferMenuView::samplingFrequencyUpdated, this, + [=, this](int sr) { onSamplingFrequencyUpdated(chnlIdx, sr); }); + + connect(menu, &BufferMenuView::diagSamplingFreqChange, this, [=, this](QString data) { + onSamplingFrequencyUpdated(chnlIdx, data.toInt()); + Q_EMIT updateDiagSamplingFreq(data); + }); + connect(menu, &BufferMenuView::diagnosticFunctionUpdated, this, &Ad74413r::onDiagnosticFunctionUpdated); + connect(menu, &BufferMenuView::samplingFreqWritten, this, &Ad74413r::samplingFreqWritten); + connect(menu, &BufferMenuView::thresholdWritten, this, &Ad74413r::onThresholdWritten); + connect(this, &Ad74413r::broadcastThreshold, menu, &BufferMenuView::broadcastThreshold); + connect(this, &Ad74413r::updateDiagSamplingFreq, menu, &BufferMenuView::updateDiagSamplingFreq); + } + m_currentChannelSelected++; + if(m_currentChannelSelected == 4) { + m_swiotAdLogic->initDiagnosticChannels(); + } +} + +void Ad74413r::setupChannelsMenuControlBtn(MenuControlButton *btn, QString name) +{ + btn->setName(name); + btn->setOpenMenuChecksThis(true); + btn->setDoubleClickToOpenMenu(true); + btn->checkBox()->setVisible(false); + btn->button()->setChecked(true); + btn->setChecked(true); +} + +void Ad74413r::updateMeasurements(PlotAxis *axis, int chnlIdx) +{ + double numOfDivs = axis->divs(); + double unitsPerDivs = abs(axis->max() - axis->min()) / numOfDivs; + m_labels[chnlIdx].first()->setValue(unitsPerDivs); +} + +void Ad74413r::createMeasurementsLabel(int chnlIdx, QPen chPen, QStringList labels) +{ + for(const QString &label : labels) { + MeasurementLabel *ml = new MeasurementLabel(this); + ml->setColor(chPen.color()); + ml->setName(label); + m_labels[chnlIdx].append(ml); + m_measurePanel->addMeasurement(ml); + } +} + +void Ad74413r::setupDeviceBtn() +{ + VerticalChannelManager *vcm = new VerticalChannelManager(this); + m_tool->leftStack()->add("vcm", vcm); + m_devBtn = new CollapsableMenuControlButton(this); + m_devBtn->getControlBtn()->setName("AD74413R"); + m_devBtn->getControlBtn()->setCheckable(false); + m_devBtn->getControlBtn()->button()->setVisible(false); + vcm->add(m_devBtn); + m_chnlsBtnGroup = new QButtonGroup(this); +} + +void Ad74413r::setupMeasureButtonHelper(MenuControlButton *btn) +{ + btn->setName("Measure"); + btn->checkBox()->setVisible(false); + btn->button()->setVisible(false); + btn->setChecked(true); +} + +void Ad74413r::setupToolTemplate() +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QHBoxLayout *layout = new QHBoxLayout(this); + setLayout(layout); + StyleHelper::GetInstance()->initColorMap(); + + m_tool = new ToolTemplate(this); + m_tool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_tool->topContainer()->setVisible(true); + m_tool->topCentral()->setVisible(true); + m_tool->centralContainer()->setVisible(true); + m_tool->bottomContainer()->setVisible(true); + m_tool->leftContainer()->setVisible(true); + m_tool->rightContainer()->setVisible(true); + + m_tool->setTopContainerHeight(100); + m_tool->setLeftContainerWidth(200); + m_tool->setRightContainerWidth(300); + + layout->addWidget(m_tool); + + m_plot = new PlotWidget(this); + m_info = new TimePlotInfo(m_plot, this); + m_plot->addPlotInfoSlot(m_info); + initPlot(); + setupDeviceBtn(); + m_tool->addWidgetToCentralContainerHelper(m_plot); + + m_infoBtn = new InfoBtn(this); + m_infoBtn->installEventFilter(this); + m_settingsBtn = new GearBtn(this); + m_runBtn = new RunBtn(this); + m_runBtn->setEnabled(false); + m_runBtn->setChecked(false); + m_singleBtn = new SingleShotBtn(this); + m_singleBtn->setEnabled(false); + m_singleBtn->setChecked(false); + m_configBtn = createConfigBtn(); + + MenuControlButton *measure = new MenuControlButton(this); + setupMeasureButtonHelper(measure); + m_measurePanel = new MeasurementsPanel(this); + m_tool->topStack()->add(measureMenuId, m_measurePanel); + connect(measure, &MenuControlButton::toggled, this, [&](bool en) { + if(en) + m_tool->requestMenu(measureMenuId); + m_tool->openTopContainerHelper(en); + }); + + m_chnlsMenuBtn = new MenuControlButton(this); + setupChannelsMenuControlBtn(m_chnlsMenuBtn, "Channels"); + connect(m_chnlsMenuBtn->button(), &QAbstractButton::toggled, this, [=, this](bool b) { + if(b) { + m_settingsBtn->setChecked(!b); + m_tool->requestMenu(channelsMenuId); + } + }); + connect(m_chnlsMenuBtn, &QPushButton::toggled, dynamic_cast(m_tool->leftContainer()), + &MenuHAnim::toggleMenu); + + QPushButton *openLastMenuBtn = + new OpenLastMenuBtn(dynamic_cast(m_tool->rightContainer()), true, this); + m_rightMenuBtnGrp = dynamic_cast(openLastMenuBtn)->getButtonGroup(); + m_rightMenuBtnGrp->addButton(m_chnlsMenuBtn->button()); + + m_channelStack = new MapStackedWidget(this); + m_tool->rightStack()->add(channelsMenuId, m_channelStack); + + QString settingsMenuId = "PlotSettings"; + m_tool->rightStack()->add(settingsMenuId, createSettingsMenu(this)); + connect(m_settingsBtn, &QPushButton::toggled, this, [=, this](bool b) { + if(b) + m_tool->requestMenu(settingsMenuId); + }); + m_rightMenuBtnGrp->addButton(m_settingsBtn); + + m_tool->addWidgetToBottomContainerHelper(m_chnlsMenuBtn, TTA_LEFT); + m_tool->addWidgetToBottomContainerHelper(measure, TTA_RIGHT); + + m_tool->addWidgetToTopContainerMenuControlHelper(openLastMenuBtn, TTA_RIGHT); + m_tool->addWidgetToTopContainerMenuControlHelper(m_settingsBtn, TTA_LEFT); + + m_tool->addWidgetToTopContainerHelper(m_runBtn, TTA_RIGHT); + m_tool->addWidgetToTopContainerHelper(m_singleBtn, TTA_RIGHT); + + m_tool->addWidgetToTopContainerHelper(m_infoBtn, TTA_LEFT); + m_tool->addWidgetToTopContainerHelper(m_configBtn, TTA_LEFT); +} + +QPushButton *Ad74413r::createConfigBtn() +{ + QPushButton *configBtn = new QPushButton(); + StyleHelper::BlueGrayButton(configBtn, "config_btn"); + configBtn->setFixedWidth(128); + configBtn->setCheckable(false); + configBtn->setText("Config"); + return configBtn; +} + +QWidget *Ad74413r::createSettingsMenu(QWidget *parent) +{ + QWidget *widget = new QWidget(parent); + QVBoxLayout *layout = new QVBoxLayout(widget); + layout->setMargin(0); + layout->setSpacing(10); + + MenuHeaderWidget *header = new MenuHeaderWidget("AD74413R", QPen(StyleHelper::getColor("ScopyBlue")), widget); + MenuSectionWidget *plotSettingsContainer = new MenuSectionWidget(widget); + MenuCollapseSection *plotTimespanSection = + new MenuCollapseSection("PLOT", MenuCollapseSection::MHCW_NONE, widget); + plotTimespanSection->setLayout(new QVBoxLayout()); + plotTimespanSection->contentLayout()->setSpacing(10); + plotTimespanSection->contentLayout()->setMargin(0); + + // timespan + m_timespanSpin = new PositionSpinButton({{"ms", 1E-3}, {"s", 1E0}}, "Timespan", 0.1, 10, true, false); + m_timespanSpin->setStep(0.1); + m_timespanSpin->setValue(1); + connect(m_timespanSpin, &PositionSpinButton::valueChanged, this, + [=, this](double value) { m_plot->xAxis()->setMin(-value); }); + + // show labels + MenuOnOffSwitch *showLabels = new MenuOnOffSwitch("PLOT LABELS", plotTimespanSection); + showPlotLabels(true); + showLabels->onOffswitch()->setChecked(true); + connect(showLabels->onOffswitch(), &QAbstractButton::toggled, this, &Ad74413r::showPlotLabels); + + plotTimespanSection->contentLayout()->addWidget(m_timespanSpin); + plotTimespanSection->contentLayout()->addWidget(showLabels); + + plotSettingsContainer->contentLayout()->addWidget(plotTimespanSection); + layout->addWidget(header); + layout->addWidget(plotSettingsContainer); + layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + return widget; +} + +bool Ad74413r::eventFilter(QObject *watched, QEvent *event) +{ + if(watched == (QObject *)m_infoBtn) { + if(event->type() == QEvent::Enter) { + auto enabledPlotsNo = std::count(m_enabledChannels.begin(), m_enabledChannels.end(), true); + m_infoBtn->setToolTip( + "sps = samples per second \n" + "sps = sampling_frequency / enabled_channels \n" + "Enabled channels = " + + QString::number(enabledPlotsNo) + "\n" + + "Samples per channel = " + QString::number(m_currentSamplingInfo.plotSize) + "\n" + + "Sampling frequency = " + QString::number(m_currentSamplingInfo.sampleRate)); + } + return false; + } else { + return QWidget::eventFilter(watched, event); + } +} + +void Ad74413r::initTutorialProperties() +{ + // initialize components that might be used for the AD74413R tutorial + m_plot->setProperty("tutorial_name", "AD74413R_PLOT"); + m_singleBtn->setProperty("tutorial_name", "SINGLE_BUTTON"); + m_runBtn->setProperty("tutorial_name", "RUN_BUTTON"); + m_settingsBtn->setProperty("tutorial_name", "AD74413R_SETTINGS"); + m_configBtn->setProperty("tutorial_name", "CONFIG_BUTTON"); +} diff --git a/plugins/swiotrefactor/src/ad74413r/bufferacquisitionhandler.cpp b/plugins/swiotrefactor/src/ad74413r/bufferacquisitionhandler.cpp new file mode 100644 index 0000000000..d737d09b2e --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/bufferacquisitionhandler.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/bufferacquisitionhandler.h" + +#include "ad74413r/ad74413r.h" +#include "swiot_logging_categories.h" + +using namespace scopy::swiotrefactor; + +BufferAcquisitionHandler::BufferAcquisitionHandler(QObject *parent) + : QObject(parent) +{ + m_lock = new QMutex(); +} +BufferAcquisitionHandler::~BufferAcquisitionHandler() +{ + if(m_dataPoints.size() > 0) { + m_dataPoints.clear(); + } +} + +// bufferCounter is used only for debug +void BufferAcquisitionHandler::onBufferRefilled(QMap> bufferData, int bufferCounter) +{ + int bufferDataSize = bufferData.size(); + bool rolling = false; + m_lock->lock(); + if(!(m_singleCapture && (m_bufferIndex == m_buffersNumber))) { + if(bufferDataSize > 0) { + int samplingFreq = m_plotSamplingFreq * m_timespan; + QList keys = bufferData.keys(); + for(const auto &key : keys) { + m_dataPoints[key].append(bufferData[key]); + if(m_dataPoints[key].size() > samplingFreq) { + int unnecessarySamples = m_dataPoints[key].size() - samplingFreq; + m_dataPoints[key].erase(m_dataPoints[key].begin(), + m_dataPoints[key].begin() + unnecessarySamples); + } + rolling = (m_bufferIndex == m_buffersNumber); + } + } + m_bufferIndex = (rolling) ? m_bufferIndex : m_bufferIndex + 1; + Q_EMIT bufferDataReady(m_dataPoints); + } + if(m_singleCapture && (m_bufferIndex == m_buffersNumber)) { + Q_EMIT singleCaptureFinished(); + } + m_lock->unlock(); +} + +int BufferAcquisitionHandler::getRequiredBuffersNumber() { return m_buffersNumber; } + +void BufferAcquisitionHandler::onTimespanChanged(double value) +{ + m_timespan = value; + resetPlotParameters(); +} + +void BufferAcquisitionHandler::onSamplingFrequencyComputed(double samplingFrequency) +{ + m_plotSamplingFreq = samplingFrequency; + resetPlotParameters(); +} + +void BufferAcquisitionHandler::setSingleCapture(bool en) { m_singleCapture = en; } + +void BufferAcquisitionHandler::resetPlotParameters() +{ + m_lock->lock(); + auto plotSampleNumber = m_plotSamplingFreq * m_timespan; + m_bufferSize = (m_plotSamplingFreq > MAX_BUFFER_SIZE) ? MAX_BUFFER_SIZE : MIN_BUFFER_SIZE; + m_buffersNumber = (((int)plotSampleNumber % m_bufferSize) == 0) ? (plotSampleNumber / m_bufferSize) + : ((plotSampleNumber / m_bufferSize) + 1); + m_bufferIndex = 0; + resetDataPoints(); + + qDebug(CAT_SWIOT_AD74413R) << "Plot samples number: " << QString::number(plotSampleNumber) << " " + << QString::number(m_buffersNumber) + " " + + QString::number(plotSampleNumber / m_bufferSize) + " "; + m_lock->unlock(); +} + +void BufferAcquisitionHandler::resetDataPoints() +{ + const QList &chnls = m_dataPoints.keys(); + for(int chnlIdx : chnls) { + m_dataPoints[chnlIdx].clear(); + } + m_dataPoints.clear(); + for(int chnlIdx = 0; chnlIdx < MAX_CURVES_NUMBER; chnlIdx++) { + m_dataPoints.insert(chnlIdx, QVector()); + } +} + +bool BufferAcquisitionHandler::singleCapture() const { return m_singleCapture; } diff --git a/plugins/swiotrefactor/src/ad74413r/bufferlogic.cpp b/plugins/swiotrefactor/src/ad74413r/bufferlogic.cpp new file mode 100644 index 0000000000..bbedaa854c --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/bufferlogic.cpp @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/bufferlogic.h" + +#include "ad74413r/chnlinfobuilder.h" +#include "ad74413r/ad74413r.h" + +#include +#include +#include + +using namespace scopy::swiotrefactor; + +BufferLogic::BufferLogic(QMap devicesMap, CommandQueue *commandQueue) + : m_plotChnlsNo(0) + , m_iioDevicesMap(devicesMap) + , m_commandQueue(commandQueue) +{ + if(m_iioDevicesMap.contains(AD_NAME) && m_iioDevicesMap.contains(SWIOT_DEVICE_NAME)) { + createChannels(); + } +} + +BufferLogic::~BufferLogic() +{ + if(m_chnlsInfo.size() > 0) { + qDeleteAll(m_chnlsInfo); + m_chnlsInfo.clear(); + } +} + +void BufferLogic::createChannels() +{ + if(m_iioDevicesMap[AD_NAME]) { + int chnlsNumber = iio_device_get_channels_count(m_iioDevicesMap[AD_NAME]); + int plotChnlsNo = 0; + int chnlIdx = -1; + const QRegExp rx("[^0-9]+"); + for(int i = 0; i < chnlsNumber; i++) { + struct iio_channel *iioChnl = iio_device_get_channel(m_iioDevicesMap[AD_NAME], i); + QString chnlId(iio_channel_get_id(iioChnl)); + QString chnlInfoId = chnlId[0].toLower(); + if(iio_channel_find_attr(iioChnl, "threshold")) { + chnlInfoId = "d"; + } + ChnlInfo *channelInfo = ChnlInfoBuilder::build(iioChnl, chnlInfoId, m_commandQueue); + const auto &&parts = chnlId.split(rx); + chnlIdx = -1; + plotChnlsNo = (!channelInfo->isOutput() && channelInfo->isScanElement()) ? (plotChnlsNo + 1) + : plotChnlsNo; + if(parts.size() <= 1) { + continue; + } + if(parts[1].compare("")) { + chnlIdx = parts[1].toInt(); + chnlIdx = (channelInfo->isOutput()) ? (chnlIdx + MAX_INPUT_CHNLS_NO) : chnlIdx; + } + m_chnlsInfo[chnlIdx] = channelInfo; + } + m_plotChnlsNo = plotChnlsNo; + } +} + +bool BufferLogic::verifyChannelsEnabledChanges(QVector enabledChnls) +{ + bool changes = false; + for(int i = 0; i < enabledChnls.size(); i++) { + if(m_chnlsInfo.contains(i)) { + if(enabledChnls[i] != m_chnlsInfo[i]->isEnabled()) { + changes = true; + break; + } + } + } + return changes; +} + +void BufferLogic::applyChannelsEnabledChanges(QVector enabledChnls) +{ + for(int i = 0; i < enabledChnls.size(); i++) { + if(m_chnlsInfo.contains(i)) { + if(enabledChnls[i] != m_chnlsInfo[i]->isEnabled()) { + m_chnlsInfo[i]->setIsEnabled(enabledChnls[i]); + } + } + } + Q_EMIT chnlsChanged(m_chnlsInfo); + computeSamplingFrequency(); +} + +void BufferLogic::applySamplingFrequencyChanges(int channelId, int value) +{ + if(m_samplingFrequencies.contains(channelId)) { + m_samplingFrequencies[channelId] = value; + } else { + m_samplingFrequencies.insert(channelId, value); + } + computeSamplingFrequency(); +} + +void BufferLogic::computeSamplingFrequency() +{ + double newSamplingFrequency = 0.0; + auto keys = m_samplingFrequencies.keys(); + for(int channelId : keys) { + if(m_chnlsInfo[channelId]->isEnabled()) { + newSamplingFrequency += (1.0 / m_samplingFrequencies[channelId]); + } + } + newSamplingFrequency = (newSamplingFrequency != 0.0) ? (1.0 / newSamplingFrequency) : 1.0; + m_samplingFrequency = newSamplingFrequency; + Q_EMIT samplingFrequencyComputed(newSamplingFrequency); +} + +int BufferLogic::getPlotChnlsNo() { return m_plotChnlsNo; } + +QString BufferLogic::getPlotChnlUnitOfMeasure(int channel) +{ + QString unit = ""; + ChnlInfo *chnlInfo = m_chnlsInfo[channel]; + if(chnlInfo) { + if(chnlInfo->isScanElement() && !chnlInfo->isOutput()) { + unit = chnlInfo->unitOfMeasure(); + } + } + return unit; +} + +QVector BufferLogic::getPlotChnlsUnitOfMeasure() +{ + QVector chnlsUnitOfMeasure; + + for(ChnlInfo *chnl : qAsConst(m_chnlsInfo)) { + if(chnl->isScanElement() && !chnl->isOutput()) { + QString unitOfMeasure = chnl->unitOfMeasure(); + chnlsUnitOfMeasure.push_back(unitOfMeasure); + } + } + return chnlsUnitOfMeasure; +} + +std::pair BufferLogic::getPlotChnlRangeValues(int channel) +{ + std::pair range = {0, 0}; + ChnlInfo *chnlInfo = m_chnlsInfo[channel]; + if(chnlInfo) { + if(chnlInfo->isScanElement() && !chnlInfo->isOutput()) { + range = chnlInfo->rangeValues(); + } + } + return range; +} + +QVector> BufferLogic::getPlotChnlsRangeValues() +{ + QVector> chnlsRangeValues; + for(ChnlInfo *chnl : qAsConst(m_chnlsInfo)) { + if(chnl->isScanElement() && !chnl->isOutput()) { + std::pair rangeValues = chnl->rangeValues(); + chnlsRangeValues.push_back(rangeValues); + } + } + return chnlsRangeValues; +} + +std::pair BufferLogic::getChnlOffsetScale(int channel) +{ + std::pair offsetScale = {0, 1}; + ChnlInfo *chnlInfo = m_chnlsInfo.contains(channel) ? m_chnlsInfo[channel] : nullptr; + if(chnlInfo) { + offsetScale = chnlInfo->offsetScalePair(); + } + return offsetScale; +} + +QMap BufferLogic::getPlotChnlsId() +{ + QMap chnlsId; + auto keys = m_chnlsInfo.keys(); + for(int key : keys) { + if(m_chnlsInfo[key]->isScanElement() && !m_chnlsInfo[key]->isOutput()) { + QString chnlId = m_chnlsInfo[key]->chnlId(); + chnlsId[key] = chnlId; + } + } + + return chnlsId; +} + +void BufferLogic::initAd74413rChnlsFunctions() +{ + // on the SWIOT board we have only 4 channels + for(int i = 0; i < 4; ++i) { + initChannelFunction(i); + } +} + +void BufferLogic::initDiagnosticChannels() +{ + // The last 4 channels from context are always the diagnostic channels + // (they are not physically on the board) + for(int i = 4; i < MAX_INPUT_CHNLS_NO; i++) { + Q_EMIT channelFunctionDetermined(i, "diagnostic"); + } +} + +void BufferLogic::initChannelFunction(unsigned int i) +{ + std::string chnlEnableAttribute = "ch" + std::to_string(i) + "_enable"; + Command *enabledChnCmd = + new IioDeviceAttributeRead(m_iioDevicesMap[SWIOT_DEVICE_NAME], chnlEnableAttribute.c_str(), nullptr); + connect( + enabledChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { enabledChnCmdFinished(i, cmd); }, Qt::QueuedConnection); + m_commandQueue->enqueue(enabledChnCmd); +} + +void BufferLogic::enabledChnCmdFinished(unsigned int i, scopy::Command *cmd) +{ + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + bool ok = false; + bool enabled = QString(result).toInt(&ok); + if(!ok) { + return; + } + if(enabled) { + std::string deviceAttributeName = "ch" + std::to_string(i) + "_device"; + Command *configuredDevCmd = new IioDeviceAttributeRead(m_iioDevicesMap[SWIOT_DEVICE_NAME], + deviceAttributeName.c_str(), nullptr); + connect( + configuredDevCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { configuredDevCmdFinished(i, cmd); }, + Qt::QueuedConnection); + m_commandQueue->enqueue(configuredDevCmd); + + } else { + Q_EMIT channelFunctionDetermined(i, "no_config"); + } + } +} + +void BufferLogic::configuredDevCmdFinished(unsigned int i, scopy::Command *cmd) +{ + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + std::string device = std::string(result); + if(device == "ad74413r") { + std::string functionAttributeName = "ch" + std::to_string(i) + "_function"; + Command *chnFunctionCmd = new IioDeviceAttributeRead(m_iioDevicesMap[SWIOT_DEVICE_NAME], + functionAttributeName.c_str(), nullptr); + connect( + chnFunctionCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { chnFunctionCmdFinished(i, cmd); }, + Qt::QueuedConnection); + m_commandQueue->enqueue(chnFunctionCmd); + + } else { + Q_EMIT channelFunctionDetermined(i, "no_config"); + } + } +} + +void BufferLogic::chnFunctionCmdFinished(unsigned int i, scopy::Command *cmd) +{ + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + QString function = QString(result); + Q_EMIT channelFunctionDetermined(i, function); + } +} + +QMap BufferLogic::getIioChnl(int chnlIdx) +{ + QMap chnlsMap; + int outputChblIdx = chnlIdx + MAX_INPUT_CHNLS_NO; + + if(m_chnlsInfo.contains(chnlIdx) && !m_chnlsInfo[chnlIdx]->isOutput()) { + chnlsMap["input"] = m_chnlsInfo[chnlIdx]->iioChnl(); + } + + if(m_chnlsInfo.contains(outputChblIdx) && m_chnlsInfo[outputChblIdx]->isOutput()) { + chnlsMap["output"] = m_chnlsInfo[outputChblIdx]->iioChnl(); + } + + return chnlsMap; +} diff --git a/plugins/swiotrefactor/src/ad74413r/buffermenu.cpp b/plugins/swiotrefactor/src/ad74413r/buffermenu.cpp new file mode 100644 index 0000000000..41c0b13254 --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/buffermenu.cpp @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/buffermenu.h" +#include "swiot_logging_categories.h" + +#include +#include +#include +#include +#include +#include + +using namespace scopy::swiotrefactor; +BufferMenu::BufferMenu(QWidget *parent, QString chnlFunction, Connection *conn, QMap chnls) + : QWidget(parent) + , m_chnlFunction(chnlFunction) + , m_connection(conn) + , m_chnls(chnls) +{ + + if(m_chnls.contains(INPUT_CHNL)) { + m_samplingFreq = + IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[INPUT_CHNL]), + .data = "sampling_frequency", + .iioDataOptions = "sampling_frequency_available"}, + this); + addMenuWidget(m_samplingFreq); + connect(dynamic_cast(m_samplingFreq->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, &BufferMenu::onSamplingFreqWrite); + connect(dynamic_cast(m_samplingFreq->getUiStrategy()), &ComboAttrUi::emitData, this, + &BufferMenu::freqChangeStart); + connect(dynamic_cast(m_samplingFreq->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, &BufferMenu::freqChangeEnd); + + m_samplingFreq->getUiStrategy()->requestData(); + } +} + +BufferMenu::~BufferMenu() {} + +QString BufferMenu::getInfoMessage() +{ + QString defaultMessage = "\"" + m_chnlFunction + + "\" configuration generates a buffer capable channel which is directly related to the plot. The " + "channel attributes can be changed through this menu."; + return defaultMessage; +} + +void BufferMenu::addMenuWidget(QWidget *widget) { m_widgetsList.push_back(widget); } + +void BufferMenu::onBroadcastThreshold() {} + +void BufferMenu::onDiagSamplingChange(QString samplingFreq) {} + +void BufferMenu::onSamplingFreqWrite(QString data, QString dataOptions) +{ + Q_EMIT samplingFrequencyUpdated(data.toInt()); +} + +void BufferMenu::onRunBtnsPressed(bool en) +{ + dynamic_cast(m_samplingFreq->getUiStrategy())->ui()->setEnabled(!en); +} + +void BufferMenu::setOffsetScalePair(const std::pair &newOffsetScalePair) +{ + m_offsetScalePair = newOffsetScalePair; +} + +double BufferMenu::convertFromRaw(double rawValue) +{ + return (rawValue + m_offsetScalePair.first) * m_offsetScalePair.second; +} + +QList BufferMenu::getWidgetsList() { return m_widgetsList; } + +CurrentInLoopMenu::CurrentInLoopMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // dac code - output channel + IIOWidget *dacCode = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::RangeUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "raw", + .constDataOptions = "[0 1 8191]"}, + this); + QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); + PositionSpinButton *dacSpin = nullptr; + if(item) { + dacSpin = dynamic_cast(item->widget()); + } + if(dacSpin) { + dacSpin->nameLabel()->setText("DAC Code"); + dacSpin->comboBox()->clear(); + dacSpin->comboBox()->addItem("raw value"); + dacSpin->comboBox()->setEnabled(false); + } + addMenuWidget(dacCode); + + QWidget *cnvtWidget = new QWidget(this); + QHBoxLayout *cnvtLayout = new QHBoxLayout(cnvtWidget); + cnvtWidget->setLayout(cnvtLayout); + cnvtLayout->setMargin(0); + + m_cnvtLabel = new QLabel(cnvtWidget); + cnvtLayout->addItem(new QSpacerItem(20, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); + cnvtLayout->addWidget(m_cnvtLabel); + addMenuWidget(cnvtWidget); + + connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, + &CurrentInLoopMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, &CurrentInLoopMenu::updateCnvtLabel); +} + +CurrentInLoopMenu::~CurrentInLoopMenu() {} + +QString CurrentInLoopMenu::getInfoMessage() +{ + QString infoMessage = "\"" + m_chnlFunction + + "\" configuration generates 2 context channels. One of them is an input buffer capable channel " + "(current_in) which is related to the plot and the other one is an output channel (current_out) whose " + "attributes can be changed from this menu."; + return infoMessage; +} + +void CurrentInLoopMenu::updateCnvtLabel(QString data) +{ + double convertedData = convertFromRaw(data.toDouble()); + m_cnvtLabel->setText(QString::number(convertedData) + " mA"); +} + +DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // threshold - input channel + m_threshold = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::EditableUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[INPUT_CHNL]), + .data = "threshold", + .constDataOptions = "[0 1 16000]"}, + this); + addMenuWidget(m_threshold); + + CmdQChannelAttrDataStrategy *dataStrategy = + dynamic_cast(m_threshold->getDataStrategy()); + connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, + &BufferMenu::thresholdChangeStart); + connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInLoopMenu::onEmitStatus); + // dac code - output channel + IIOWidget *dacCode = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::RangeUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "raw", + .constDataOptions = "[0 1 8191]"}, + this); + QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); + PositionSpinButton *dacSpin = nullptr; + if(item) { + dacSpin = dynamic_cast(item->widget()); + } + if(dacSpin) { + dacSpin->nameLabel()->setText("DAC Code"); + dacSpin->comboBox()->clear(); + dacSpin->comboBox()->addItem("raw value"); + dacSpin->comboBox()->setEnabled(false); + } + addMenuWidget(dacCode); + + QWidget *cnvtWidget = new QWidget(this); + QHBoxLayout *cnvtLayout = new QHBoxLayout(cnvtWidget); + cnvtWidget->setLayout(cnvtLayout); + cnvtLayout->setMargin(0); + + m_cnvtLabel = new QLabel(cnvtWidget); + cnvtLayout->addItem(new QSpacerItem(20, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); + cnvtLayout->addWidget(m_cnvtLabel); + addMenuWidget(cnvtWidget); + + connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, + &DigitalInLoopMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, &DigitalInLoopMenu::updateCnvtLabel); +} + +DigitalInLoopMenu::~DigitalInLoopMenu() {} + +QString DigitalInLoopMenu::getInfoMessage() +{ + QString infoMessage = "\"" + m_chnlFunction + + "\" configuration generates 2 context channels. One of them is an input buffer capable channel " + "(voltage_in) which is related to the plot and the other one is an output channel (current_out). The " + "threshold is set for the input channel and the DAC Code for the output channel."; + return infoMessage; +} + +void DigitalInLoopMenu::updateCnvtLabel(QString data) +{ + double convertedData = convertFromRaw(data.toDouble()); + m_cnvtLabel->setText(QString::number(convertedData) + " mA"); +} + +void DigitalInLoopMenu::onBroadcastThreshold() +{ + CmdQChannelAttrDataStrategy *dataStrategy = + dynamic_cast(m_threshold->getDataStrategy()); + dataStrategy->requestData(); +} + +void DigitalInLoopMenu::onRunBtnsPressed(bool en) +{ + BufferMenu::onRunBtnsPressed(en); + m_threshold->getUiStrategy()->ui()->setEnabled(!en); +} + +void DigitalInLoopMenu::onEmitStatus(int retCode) +{ + if(retCode != 0) { + qWarning(CAT_SWIOT_AD74413R) << "[" << m_chnlFunction << "] Treshold value cannot be written!"; + return; + } + Q_EMIT thresholdChangeEnd(); +} + +VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // dac code - output channel + IIOWidget *dacCode = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::RangeUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "raw", + .constDataOptions = "[0 1 8191]"}, + this); + QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); + PositionSpinButton *dacSpin = nullptr; + if(item) { + dacSpin = dynamic_cast(item->widget()); + } + if(dacSpin) { + dacSpin->nameLabel()->setText("DAC Code"); + dacSpin->comboBox()->clear(); + dacSpin->comboBox()->addItem("raw value"); + dacSpin->comboBox()->setEnabled(false); + } + addMenuWidget(dacCode); + + QWidget *cnvtWidget = new QWidget(this); + QHBoxLayout *cnvtLayout = new QHBoxLayout(cnvtWidget); + cnvtWidget->setLayout(cnvtLayout); + cnvtLayout->setMargin(0); + + m_cnvtLabel = new QLabel(cnvtWidget); + cnvtLayout->addItem(new QSpacerItem(20, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); + cnvtLayout->addWidget(m_cnvtLabel); + addMenuWidget(cnvtWidget); + + connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, + &VoltageOutMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, &VoltageOutMenu::updateCnvtLabel); + + // slew - output channel + IIOWidget *slewOptions = + IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_en", + .constDataOptions = "0 1"}, + this); + + addMenuWidget(slewOptions); + // slew step - output channel + IIOWidget *slewStep = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_step", + .iioDataOptions = "slew_step_available"}, + this); + addMenuWidget(slewStep); + // slew rate - output channel + IIOWidget *slewRate = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_rate", + .iioDataOptions = "slew_rate_available"}, + this); + addMenuWidget(slewRate); +} + +VoltageOutMenu::~VoltageOutMenu() {} + +QString VoltageOutMenu::getInfoMessage() +{ + QString infoMessage = "\"" + m_chnlFunction + + "\" configuration generates 2 context channels. One of them is an input buffer capable channel " + "(current_in) which is related to the plot and the other one is an output channel whose attributes can " + "be changed from this menu."; + return infoMessage; +} + +void VoltageOutMenu::updateCnvtLabel(QString data) +{ + double convertedData = convertFromRaw(data.toDouble()) * 0.001; + m_cnvtLabel->setText(QString::number(convertedData) + " V"); +} + +CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // dac code - output channel + IIOWidget *dacCode = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::RangeUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "raw", + .constDataOptions = "[0 1 8191]"}, + this); + QLayoutItem *item = dacCode->getUiStrategy()->ui()->layout()->itemAt(0); + PositionSpinButton *dacSpin = nullptr; + if(item) { + dacSpin = dynamic_cast(item->widget()); + } + if(dacSpin) { + dacSpin->nameLabel()->setText("DAC Code"); + dacSpin->comboBox()->clear(); + dacSpin->comboBox()->addItem("raw value"); + dacSpin->comboBox()->setEnabled(false); + } + addMenuWidget(dacCode); + + QWidget *cnvtWidget = new QWidget(this); + QHBoxLayout *cnvtLayout = new QHBoxLayout(cnvtWidget); + cnvtWidget->setLayout(cnvtLayout); + cnvtLayout->setMargin(0); + + m_cnvtLabel = new QLabel(cnvtWidget); + cnvtLayout->addItem(new QSpacerItem(20, 0, QSizePolicy::Expanding, QSizePolicy::Fixed)); + cnvtLayout->addWidget(m_cnvtLabel); + addMenuWidget(cnvtWidget); + + connect(dynamic_cast(dacCode->getUiStrategy()), &RangeAttrUi::emitData, this, + &CurrentOutMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, &CurrentOutMenu::updateCnvtLabel); + + // slew - output channel + IIOWidget *slewOptions = + IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_en", + .constDataOptions = "0 1"}, + this); + + addMenuWidget(slewOptions); + // slew step - output channel + IIOWidget *slewStep = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_step", + .iioDataOptions = "slew_step_available"}, + this); + addMenuWidget(slewStep); + // slew rate - output channel + IIOWidget *slewRate = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[OUTPUT_CHNL]), + .data = "slew_rate", + .iioDataOptions = "slew_rate_available"}, + this); + addMenuWidget(slewRate); +} + +CurrentOutMenu::~CurrentOutMenu() {} + +QString CurrentOutMenu::getInfoMessage() +{ + QString infoMessage = "\"" + m_chnlFunction + + "\" configuration generates 2 context channels. One of them is an input buffer capable channel " + "(voltage_in) which is related to the plot and the other one is an output channel whose attributes can " + "be changed from this menu."; + return infoMessage; +} + +void CurrentOutMenu::updateCnvtLabel(QString data) +{ + double convertedData = convertFromRaw(data.toDouble()); + m_cnvtLabel->setText(QString::number(convertedData) + " mA"); +} + +DiagnosticMenu::DiagnosticMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // diag options - input channel + IIOWidget *diagOptions = + IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::ComboUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[INPUT_CHNL]), + .data = "diag_function", + .iioDataOptions = "diag_function_available"}, + this); + addMenuWidget(diagOptions); + + connect(dynamic_cast(diagOptions->getDataStrategy()), + &CmdQChannelAttrDataStrategy::sendData, this, + [=, this](QString data, QString dataOptions) { Q_EMIT diagnosticFunctionUpdated(); }); +} + +DiagnosticMenu::~DiagnosticMenu() {} + +// TBD - it is possible that there is a better option +void DiagnosticMenu::onDiagSamplingChange(QString samplingFreq) +{ + QWidget *w = m_samplingFreq->getUiStrategy()->ui()->layout()->itemAt(0)->widget(); + if(w) { + dynamic_cast(w)->combo()->setCurrentText(samplingFreq); + } +} + +void DiagnosticMenu::onSamplingFreqWrite(QString data, QString dataOptions) { Q_EMIT diagSamplingFreqChange(data); } + +WithoutAdvSettings::WithoutAdvSettings(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + QLabel *msgLabel = new QLabel("No advanced settings available", this); + StyleHelper::MenuSmallLabel(msgLabel); + addMenuWidget(msgLabel); +} + +WithoutAdvSettings::~WithoutAdvSettings() {} + +DigitalInMenu::DigitalInMenu(QWidget *parent, QString chnlFunction, Connection *conn, + QMap chnls) + : BufferMenu(parent, chnlFunction, conn, chnls) +{ + // threshold - input channel + m_threshold = IIOWidgetFactory::buildSingle(IIOWidgetFactory::CMDQAttrData | IIOWidgetFactory::EditableUi, + {.connection = const_cast(m_connection), + .channel = const_cast(m_chnls[INPUT_CHNL]), + .data = "threshold", + .constDataOptions = "[0 1 16000]"}, + this); + addMenuWidget(m_threshold); + CmdQChannelAttrDataStrategy *dataStrategy = + dynamic_cast(m_threshold->getDataStrategy()); + connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, + &BufferMenu::thresholdChangeStart); + connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInMenu::onEmitStatus); +} + +DigitalInMenu::~DigitalInMenu() {} + +void DigitalInMenu::onBroadcastThreshold() +{ + CmdQChannelAttrDataStrategy *dataStrategy = + dynamic_cast(m_threshold->getDataStrategy()); + dataStrategy->requestData(); +} + +void DigitalInMenu::onRunBtnsPressed(bool en) +{ + BufferMenu::onRunBtnsPressed(en); + m_threshold->getUiStrategy()->ui()->setEnabled(!en); +} + +void DigitalInMenu::onEmitStatus(int retCode) +{ + if(retCode != 0) { + qWarning(CAT_SWIOT_AD74413R) << "[" << m_chnlFunction << "] Treshold value cannot be written!"; + return; + } + Q_EMIT thresholdChangeEnd(); +} diff --git a/plugins/swiotrefactor/src/ad74413r/buffermenuview.cpp b/plugins/swiotrefactor/src/ad74413r/buffermenuview.cpp new file mode 100644 index 0000000000..bf652296a8 --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/buffermenuview.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/buffermenuview.h" + +#include + +#include +#include +#include +#include + +using namespace scopy::swiotrefactor; + +BufferMenuView::BufferMenuView(QMap chnls, Connection *conn, QWidget *parent) + : QWidget(parent) + , m_swiotAdvMenu(nullptr) + , m_chnls(chnls) + , m_connection(conn) +{ + setLayout(new QVBoxLayout()); + layout()->setMargin(0); +} + +BufferMenuView::~BufferMenuView() {} + +void BufferMenuView::init(QString title, QString function, QPen color, QString unit, double yMin, double yMax) +{ + m_swiotAdvMenu = BufferMenuBuilder::newAdvMenu(this, function, m_connection, m_chnls); + + QScrollArea *scrollArea = new QScrollArea(this); + QWidget *scrollWidget = new QWidget(scrollArea); + QVBoxLayout *layScroll = new QVBoxLayout(scrollWidget); + layScroll->setSpacing(10); + layScroll->setMargin(0); + scrollWidget->setLayout(layScroll); + + scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scrollArea->setWidgetResizable(true); + scrollArea->setWidget(scrollWidget); + + MenuHeaderWidget *header = new MenuHeaderWidget(title, color, scrollWidget); + QWidget *descriptionSection = createDescriptionSection(scrollWidget); + QWidget *yAxisMenu = createVerticalSettingsMenu(unit, yMin, yMax, scrollWidget); + QWidget *attrSection = createAttrSection(scrollWidget); + + layScroll->addWidget(header); + layScroll->addWidget(descriptionSection); + layScroll->addWidget(yAxisMenu); + layScroll->addWidget(attrSection); + layScroll->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + layout()->addWidget(scrollArea); + + createConnections(); +} + +void BufferMenuView::createConnections() +{ + connect(m_swiotAdvMenu, &BufferMenu::diagnosticFunctionUpdated, this, + &BufferMenuView::diagnosticFunctionUpdated); + connect(m_swiotAdvMenu, &BufferMenu::samplingFrequencyUpdated, this, &BufferMenuView::samplingFrequencyUpdated); + connect(m_swiotAdvMenu, &BufferMenu::thresholdChangeStart, this, [&]() { Q_EMIT thresholdWritten(false); }); + connect(m_swiotAdvMenu, &BufferMenu::thresholdChangeEnd, this, [&]() { Q_EMIT thresholdWritten(true); }); + connect(this, &BufferMenuView::broadcastThreshold, m_swiotAdvMenu, &BufferMenu::onBroadcastThreshold); + connect(m_swiotAdvMenu, &BufferMenu::diagSamplingFreqChange, this, &BufferMenuView::diagSamplingFreqChange); + connect(this, &BufferMenuView::updateDiagSamplingFreq, m_swiotAdvMenu, &BufferMenu::onDiagSamplingChange); + connect(m_swiotAdvMenu, &BufferMenu::freqChangeStart, this, [&]() { Q_EMIT samplingFreqWritten(false); }); + connect(m_swiotAdvMenu, &BufferMenu::freqChangeEnd, this, [&]() { Q_EMIT samplingFreqWritten(true); }); + + connect(this, &BufferMenuView::runBtnsPressed, m_swiotAdvMenu, &BufferMenu::onRunBtnsPressed); +} + +QWidget *BufferMenuView::createDescriptionSection(QWidget *parent) +{ + MenuSectionWidget *descriptionContainer = new MenuSectionWidget(parent); + MenuCollapseSection *descriptionSection = + new MenuCollapseSection("FUNCTION DESCRIPTION", MenuCollapseSection::MHCW_NONE, descriptionContainer); + + QLabel *description = new QLabel(descriptionContainer); + description->setText(m_swiotAdvMenu->getInfoMessage()); + description->setTextFormat(Qt::TextFormat::RichText); + description->setWordWrap(true); + + descriptionSection->contentLayout()->addWidget(description); + descriptionContainer->contentLayout()->addWidget(descriptionSection); + + return descriptionContainer; +} + +QWidget *BufferMenuView::createAttrSection(QWidget *parent) +{ + MenuSectionWidget *attrContainer = new MenuSectionWidget(parent); + auto layout = new QVBoxLayout(attrContainer); + layout->setSpacing(10); + layout->setMargin(0); + + MenuCollapseSection *attrSection = + new MenuCollapseSection("ATTRIBUTES", MenuCollapseSection::MHCW_NONE, attrContainer); + + QList widgets = m_swiotAdvMenu->getWidgetsList(); + for(QWidget *w : qAsConst(widgets)) { + layout->addWidget(w); + } + + attrSection->contentLayout()->addLayout(layout); + attrContainer->contentLayout()->addWidget(attrSection); + + return attrContainer; +} + +QWidget *BufferMenuView::createVerticalSettingsMenu(QString unit, double yMin, double yMax, QWidget *parent) +{ + MenuSectionWidget *verticalContainer = new MenuSectionWidget(this); + auto layout = new QHBoxLayout(verticalContainer); + layout->setSpacing(10); + layout->setMargin(0); + + MenuCollapseSection *verticalSettings = + new MenuCollapseSection("Y-AXIS", MenuCollapseSection::MHCW_NONE, verticalContainer); + + auto m_yMin = new PositionSpinButton( + { + {"" + unit, 1e0}, + {"k" + unit, 1e3}, + {"M" + unit, 1e6}, + {"G" + unit, 1e9}, + }, + "YMin", -DBL_MAX, DBL_MAX, false, false, verticalContainer); + m_yMin->setValue(yMin); + + auto m_yMax = new PositionSpinButton( + { + {"" + unit, 1e0}, + {"k" + unit, 1e3}, + {"M" + unit, 1e6}, + {"G" + unit, 1e9}, + }, + "YMax", -DBL_MAX, DBL_MAX, false, false, verticalContainer); + m_yMax->setValue(yMax); + + layout->addWidget(m_yMin); + layout->addWidget(m_yMax); + + verticalSettings->contentLayout()->addLayout(layout); + verticalContainer->contentLayout()->addWidget(verticalSettings); + + // Connects + connect(m_yMin, &PositionSpinButton::valueChanged, this, &BufferMenuView::setYMin); + connect(this, &BufferMenuView::minChanged, this, [=](double min) { + QSignalBlocker b(m_yMin); + m_yMin->setValue(min); + }); + + connect(m_yMax, &PositionSpinButton::valueChanged, this, &BufferMenuView::setYMax); + connect(this, &BufferMenuView::maxChanged, this, [=](double max) { + QSignalBlocker b(m_yMax); + m_yMax->setValue(max); + }); + return verticalContainer; +} + +BufferMenu *BufferMenuView::getAdvMenu() { return m_swiotAdvMenu; } diff --git a/plugins/swiotrefactor/src/ad74413r/channelplotscale.cpp b/plugins/swiotrefactor/src/ad74413r/channelplotscale.cpp new file mode 100644 index 0000000000..49e8409cdb --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/channelplotscale.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/channelplotscale.h" + +#include + +using namespace scopy::swiotrefactor; + +ChannelPlotScale::ChannelPlotScale(int channel, QString unit, QColor color, QWidget *parent) + : QWidget(parent) + , m_channel(channel) + , m_unit(unit) + , m_enabled(true) + , m_channelColor(color) +{ + m_formatter = new MetricPrefixFormatter(); + auto layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(5); + this->setLayout(layout); + + m_unitPerDivisionLbl = new QLabel(this); + m_instantValueLbl = new QLabel(this); + m_unitPerDivisionLbl->setVisible(true); + m_instantValueLbl->setVisible(true); + layout->addWidget(m_unitPerDivisionLbl); + layout->addWidget(m_instantValueLbl); + + connect(this, &ChannelPlotScale::requestUpdate, this, &ChannelPlotScale::update); + m_unitPerDivisionLbl->setStyleSheet(QString("QLabel {" + "color: %1;" + "font-weight: bold;" + "}") + .arg(m_channelColor.name())); + m_instantValueLbl->setStyleSheet(QString("QLabel {" + "color: %1;" + "font-weight: bold;" + "}") + .arg(m_channelColor.name())); + setInstantValue(0); + setUnitPerDivision(0); +} + +ChannelPlotScale::~ChannelPlotScale() { delete m_formatter; } + +void ChannelPlotScale::setInstantValue(double value) +{ + if(qFuzzyCompare(m_instantValue, value)) + return; + m_instantValue = value; + Q_EMIT requestUpdate(); +} + +void ChannelPlotScale::setUnitPerDivision(double value) +{ + if(qFuzzyCompare(m_unitPerDivision, value)) + return; + m_unitPerDivision = value; + Q_EMIT requestUpdate(); +} + +void ChannelPlotScale::update() +{ + m_unitPerDivisionLbl->setText(m_formatter->format(m_unitPerDivision, m_unit + "/div", 2)); + m_instantValueLbl->setText(m_formatter->format(m_instantValue, m_unit, 2)); +} + +int ChannelPlotScale::getChannelId() { return m_channel; } + +bool ChannelPlotScale::getEnabled() { return m_enabled; } + +void ChannelPlotScale::setEnabled(bool en) { m_enabled = en; } diff --git a/plugins/swiotrefactor/src/ad74413r/channelplotscalescontroller.cpp b/plugins/swiotrefactor/src/ad74413r/channelplotscalescontroller.cpp new file mode 100644 index 0000000000..557d8d6919 --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/channelplotscalescontroller.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ad74413r/channelplotscalescontroller.h" + +#include +#include +using namespace scopy::swiotrefactor; + +ChannelPlotScalesController::ChannelPlotScalesController(QWidget *parent) + : QWidget(parent) + , m_layout(nullptr) +{ + auto layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(10); + layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); + this->setLayout(m_layout); +} + +ChannelPlotScalesController::~ChannelPlotScalesController() +{ + if(m_layout) { + QLayoutItem *child; + while((child = m_layout->takeAt(0)) != nullptr) { + delete child->widget(); + delete child; + } + auto oldLayout = m_layout; + oldLayout->deleteLater(); + } +} + +void ChannelPlotScalesController::addChannel(int index, QColor color, QString unit, bool enabled) +{ + ChannelPlotScale *chnPlotScale = new ChannelPlotScale(index, unit, color, this); + chnPlotScale->setEnabled(enabled); + m_channelPlotScales.push_back(chnPlotScale); + updateLayout(); +} + +void ChannelPlotScalesController::updateLayout() +{ + QHBoxLayout *mainLayout = (QHBoxLayout *)this->layout(); + if(m_layout) { + QLayoutItem *child; + while((child = m_layout->takeAt(0)) != nullptr) { + delete child; + } + mainLayout->removeItem(m_layout); + delete m_layout; + } + m_layout = new QHBoxLayout(this); + m_layout->setMargin(0); + m_layout->setSpacing(20); + for(auto chnPlotScale : qAsConst(m_channelPlotScales)) { + m_layout->addWidget(chnPlotScale); + } + mainLayout->insertLayout(0, m_layout); +} + +void ChannelPlotScalesController::setChannelEnabled(int channel, bool enable) +{ + for(auto chn : qAsConst(m_channelPlotScales)) { + if(chn->getChannelId() == channel) { + chn->setEnabled(enable); + chn->setVisible(enable); + break; + } + } + updateLayout(); +} + +void ChannelPlotScalesController::setUnitPerDivision(int channel, double unitPerDivision) +{ + for(auto chn : qAsConst(m_channelPlotScales)) { + if(chn->getChannelId() == channel) { + chn->setUnitPerDivision(unitPerDivision); + break; + } + } +} + +void ChannelPlotScalesController::setInstantValue(int channel, double value) +{ + for(auto chn : qAsConst(m_channelPlotScales)) { + if(chn->getChannelId() == channel) { + chn->setInstantValue(value); + break; + } + } +} diff --git a/plugins/swiotrefactor/src/ad74413r/chnlinfo.cpp b/plugins/swiotrefactor/src/ad74413r/chnlinfo.cpp new file mode 100644 index 0000000000..2ae113d651 --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/chnlinfo.cpp @@ -0,0 +1,120 @@ +#include "ad74413r/chnlinfo.h" + +#include +#include + +using namespace scopy::swiotrefactor; + +ChnlInfo::ChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue) + : m_iioChnl(iioChnl) + , m_plotUm(plotUm) + , m_hwUm(hwUm) + , m_commandQueue(cmdQueue) +{ + m_offsetScalePair = {0, 1}; + if(m_iioChnl) { + iio_channel_disable(iioChnl); + m_chnlId = QString(iio_channel_get_id(m_iioChnl)); + double offset = 0.0; + double scale = 0.0; + int erno = 0; + m_isOutput = iio_channel_is_output(iioChnl); + + addReadScaleCommand(); + addReadOffsetCommand(); + + m_isScanElement = iio_channel_is_scan_element(iioChnl); + m_isEnabled = false; + + initUnitOfMeasureFactor(); + } +} + +ChnlInfo::~ChnlInfo() +{ + if(m_commandQueue) { + m_commandQueue = nullptr; + } +} + +void ChnlInfo::addReadScaleCommand() +{ + Command *attrReadScale = new IioChannelAttributeRead(m_iioChnl, "scale", nullptr); + connect(attrReadScale, &scopy::Command::finished, this, &ChnlInfo::readScaleCommandFinished, + Qt::QueuedConnection); + m_commandQueue->enqueue(attrReadScale); +} + +void ChnlInfo::addReadOffsetCommand() +{ + Command *attrReadOffset = new IioChannelAttributeRead(m_iioChnl, "offset", nullptr); + connect(attrReadOffset, &scopy::Command::finished, this, &ChnlInfo::readOffsetCommandFinished, + Qt::QueuedConnection); + m_commandQueue->enqueue(attrReadOffset); +} + +void ChnlInfo::readScaleCommandFinished(Command *cmd) +{ + IioChannelAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *res = tcmd->getResult(); + bool ok = false; + double scale = QString(res).toDouble(&ok); + if(ok) { + m_offsetScalePair.second = scale; + } + } else { + // qDebug(CAT_SWIOT) << "Error, could not read \"scale\" attribute for channel."; + } +} + +void ChnlInfo::readOffsetCommandFinished(Command *cmd) +{ + IioChannelAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *res = tcmd->getResult(); + bool ok = false; + double offset = QString(res).toDouble(&ok); + if(ok) { + m_offsetScalePair.first = offset; + } + } else { + // qDebug(CAT_SWIOT) << "Error, could not read \"offset\" attribute from channel"; + } +} + +iio_channel *ChnlInfo::iioChnl() const { return m_iioChnl; } + +bool ChnlInfo::isOutput() const { return m_isOutput; } + +bool ChnlInfo::isScanElement() const { return m_isScanElement; } + +QString ChnlInfo::chnlId() const { return m_chnlId; } + +std::pair ChnlInfo::rangeValues() const { return m_rangeValues; } + +std::pair ChnlInfo::offsetScalePair() const { return m_offsetScalePair; } + +bool ChnlInfo::isEnabled() const { return m_isEnabled; } + +void ChnlInfo::setIsEnabled(bool newIsEnabled) { m_isEnabled = newIsEnabled; } + +QString ChnlInfo::unitOfMeasure() const { return m_plotUm; } + +void ChnlInfo::initUnitOfMeasureFactor() +{ + m_unitOfMeasureFactor["G"] = pow(10, 9); + m_unitOfMeasureFactor["M"] = pow(10, 6); + m_unitOfMeasureFactor["K"] = pow(10, 3); + m_unitOfMeasureFactor["m"] = pow(10, -3); + m_unitOfMeasureFactor["u"] = pow(10, -6); + m_unitOfMeasureFactor["µ"] = pow(10, -6); + m_unitOfMeasureFactor["n"] = pow(10, -9); + m_unitOfMeasureFactor["p"] = pow(10, -12); +} diff --git a/plugins/swiotrefactor/src/ad74413r/chnlinfobuilder.cpp b/plugins/swiotrefactor/src/ad74413r/chnlinfobuilder.cpp new file mode 100644 index 0000000000..ec73f85bae --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/chnlinfobuilder.cpp @@ -0,0 +1,25 @@ +#include "ad74413r/chnlinfobuilder.h" + +#include "ad74413r/resistancechnlinfo.h" +#include "ad74413r/currentchnlinfo.h" +#include "ad74413r/voltagechnlinfo.h" +#include "ad74413r/digitalchnlinfo.h" + +using namespace scopy::swiotrefactor; + +ChnlInfo *ChnlInfoBuilder::build(iio_channel *iioChnl, QString id, CommandQueue *cmdQueue) +{ + int chnl_type = decodeId(id); + switch(chnl_type) { + case VOLTAGE: + return new VoltageChnlInfo("V", "mV", iioChnl, cmdQueue); + case CURRENT: + return new CurrentChnlInfo("A", "mA", iioChnl, cmdQueue); + case RESISTANCE: + return new ResistanceChnlInfo("Ω", "Ω", iioChnl, cmdQueue); + case DIGITAL: + return new DigitalChnlInfo("unit", "unit", iioChnl, cmdQueue); + default: + return nullptr; + } +} diff --git a/plugins/swiotrefactor/src/ad74413r/currentchnlinfo.cpp b/plugins/swiotrefactor/src/ad74413r/currentchnlinfo.cpp new file mode 100644 index 0000000000..3fdc996f1a --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/currentchnlinfo.cpp @@ -0,0 +1,23 @@ +#include "ad74413r/currentchnlinfo.h" + +using namespace scopy::swiotrefactor; +CurrentChnlInfo::CurrentChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue) + : ChnlInfo(plotUm, hwUm, iioChnl, cmdQueue) +{ + m_rangeValues = {MIN_CURRENT_VALUE, MAX_CURRENT_VALUE}; +} + +CurrentChnlInfo::~CurrentChnlInfo() {} + +double CurrentChnlInfo::convertData(unsigned int data) +{ + double convertedData = 0.0; + double defaultFactor = m_unitOfMeasureFactor.contains(m_hwUm.at(0)) ? m_unitOfMeasureFactor[m_hwUm.at(0)] : 1; + double newFactor = m_unitOfMeasureFactor.contains(m_plotUm.at(0)) ? m_unitOfMeasureFactor[m_plotUm.at(0)] : 1; + double factor = defaultFactor / newFactor; + data <<= 8; + data = SWAP_UINT32(data); + data &= 0x0000FFFF; + convertedData = (data + m_offsetScalePair.first) * m_offsetScalePair.second * factor; + return convertedData; +} diff --git a/plugins/swiotrefactor/src/ad74413r/digitalchnlinfo.cpp b/plugins/swiotrefactor/src/ad74413r/digitalchnlinfo.cpp new file mode 100644 index 0000000000..b45b9f738b --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/digitalchnlinfo.cpp @@ -0,0 +1,21 @@ +#include "ad74413r/digitalchnlinfo.h" + +using namespace scopy::swiotrefactor; + +DigitalChnlInfo::DigitalChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue) + : ChnlInfo(plotUm, hwUm, iioChnl, cmdQueue) +{ + m_rangeValues = {MIN_DIGITAL_VALUE, MAX_DIGITAL_VALUE}; +} + +DigitalChnlInfo::~DigitalChnlInfo() {} + +double DigitalChnlInfo::convertData(unsigned int data) +{ + double convertedData = 0.0; + data <<= 8; + data = SWAP_UINT32(data); + data &= 0x0000FFFF; + convertedData = (data + m_offsetScalePair.first) * m_offsetScalePair.second; + return convertedData; +} diff --git a/plugins/swiotrefactor/src/ad74413r/resistancechnlinfo.cpp b/plugins/swiotrefactor/src/ad74413r/resistancechnlinfo.cpp new file mode 100644 index 0000000000..5c6f56699a --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/resistancechnlinfo.cpp @@ -0,0 +1,22 @@ +#include "ad74413r/resistancechnlinfo.h" + +using namespace scopy::swiotrefactor; + +ResistanceChnlInfo::ResistanceChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue) + : ChnlInfo(plotUm, hwUm, iioChnl, cmdQueue) +{ + m_rangeValues = {MIN_RESISTANCE_VALUE, MAX_RESISTANCE_VALUE}; +} + +ResistanceChnlInfo::~ResistanceChnlInfo() {} + +double ResistanceChnlInfo::convertData(unsigned int data) +{ + double convertedData = 0.0; + data <<= 8; + data = SWAP_UINT32(data); + data &= 0x0000FFFF; + convertedData = + ((ADC_MAX_VALUE - data) != 0) ? ((data * RPULL_UP) / (ADC_MAX_VALUE - data)) : MAX_RESISTANCE_VALUE; + return convertedData; +} diff --git a/plugins/swiotrefactor/src/ad74413r/voltagechnlinfo.cpp b/plugins/swiotrefactor/src/ad74413r/voltagechnlinfo.cpp new file mode 100644 index 0000000000..3bca0afbc7 --- /dev/null +++ b/plugins/swiotrefactor/src/ad74413r/voltagechnlinfo.cpp @@ -0,0 +1,24 @@ +#include "ad74413r/voltagechnlinfo.h" + +using namespace scopy::swiotrefactor; + +VoltageChnlInfo::VoltageChnlInfo(QString plotUm, QString hwUm, iio_channel *iioChnl, CommandQueue *cmdQueue) + : ChnlInfo(plotUm, hwUm, iioChnl, cmdQueue) +{ + m_rangeValues = {MIN_VOLTAGE_VALUE, MAX_VOLTAGE_VALUE}; +} + +VoltageChnlInfo::~VoltageChnlInfo() {} + +double VoltageChnlInfo::convertData(unsigned int data) +{ + double defaultFactor = m_unitOfMeasureFactor.contains(m_hwUm.at(0)) ? m_unitOfMeasureFactor[m_hwUm.at(0)] : 1; + double newFactor = m_unitOfMeasureFactor.contains(m_plotUm.at(0)) ? m_unitOfMeasureFactor[m_plotUm.at(0)] : 1; + double factor = defaultFactor / newFactor; + double convertedData = 0.0; + data <<= 8; + data = SWAP_UINT32(data); + data &= 0x0000FFFF; + convertedData = (data + m_offsetScalePair.first) * m_offsetScalePair.second * factor; + return convertedData; +} diff --git a/plugins/swiotrefactor/src/config/configchannelview.cpp b/plugins/swiotrefactor/src/config/configchannelview.cpp new file mode 100644 index 0000000000..6a19f62a7b --- /dev/null +++ b/plugins/swiotrefactor/src/config/configchannelview.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "configchannelview.h" +#include + +using namespace scopy::swiotrefactor; + +ConfigChannelView::ConfigChannelView(int channelIndex, QWidget *parent) + : QWidget(parent) + , m_channelEnabled(false) + , m_channelIndex(channelIndex) +{ + installEventFilter(this); + setHighlightPalette(); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_chnlLabel = new QLabel(this); + m_chnlLabel->setText(QString::fromStdString("Channel ") + QString::number(m_channelIndex + 1)); + StyleHelper::MenuSmallLabel(m_chnlLabel); + + m_chnlCheck = new QCheckBox(this); + StyleHelper::BlueSquareCheckbox(m_chnlCheck); + Q_EMIT m_chnlCheck->toggled(true); + + m_deviceOptions = new QComboBox(this); + m_deviceOptions->setFixedWidth(DEVICE_COMBO_WIDTH); + StyleHelper::MenuComboBox(m_deviceOptions); + + m_functionOptions = new QComboBox(this); + m_functionOptions->setFixedWidth(FUNCTION_COMBO_WIDTH); + StyleHelper::MenuComboBox(m_functionOptions); + + layout->addWidget(m_chnlLabel); + layout->addWidget(m_chnlCheck); + layout->addWidget(m_deviceOptions); + layout->addWidget(m_functionOptions); + + setAttribute(Qt::WA_Hover, true); + connectSignalsAndSlots(); + initTutorialProperties(); +} + +ConfigChannelView::~ConfigChannelView() {} + +void ConfigChannelView::connectSignalsAndSlots() +{ + QObject::connect(m_chnlCheck, &QCheckBox::stateChanged, this, [=, this](int state) { + this->setChannelEnabled(state); + if(m_channelEnabled) { + Q_EMIT showPath(m_channelIndex, m_selectedDevice); + } else { + Q_EMIT hidePaths(); + } + Q_EMIT enabledChanged(m_channelIndex, state); + }); + + QObject::connect(m_deviceOptions, &QComboBox::textActivated, this, [this](const QString &text) { + m_selectedDevice = text; + Q_EMIT deviceChanged(m_channelIndex, m_deviceOptions->currentText()); + }); + + QObject::connect(m_functionOptions, &QComboBox::textActivated, this, [=, this](const QString &text) { + m_selectedFunction = text; + Q_EMIT functionChanged(m_channelIndex, m_functionOptions->currentText()); + }); +} + +void ConfigChannelView::setHighlightPalette() +{ + QString highlightColor = StyleHelper::getColor("UIElementHighlight"); + QPalette newPalette = QPalette(palette()); + newPalette.setColor(QPalette::Highlight, QColor(highlightColor)); + setPalette(newPalette); +} + +bool ConfigChannelView::isChannelEnabled() const { return m_channelEnabled; } + +void ConfigChannelView::setChannelEnabled(bool mChannelEnabled) +{ + m_channelEnabled = mChannelEnabled; + + if(m_channelEnabled) { + m_chnlCheck->setChecked(true); + m_deviceOptions->setEnabled(true); + m_functionOptions->setEnabled(true); + } else { + m_chnlCheck->setChecked(false); + m_deviceOptions->setEnabled(false); + m_functionOptions->setEnabled(false); + } +} + +const QString &ConfigChannelView::getSelectedDevice() const { return m_selectedDevice; } + +void ConfigChannelView::setSelectedDevice(const QString &mSelectedDevice) +{ + m_selectedDevice = mSelectedDevice; + int index = m_deviceOptions->findText(m_selectedDevice); + m_deviceOptions->setCurrentIndex(index); +} + +const QStringList &ConfigChannelView::getDeviceAvailable() const { return m_deviceAvailable; } + +void ConfigChannelView::setDeviceAvailable(const QStringList &mDeviceAvailable) +{ + m_deviceAvailable = mDeviceAvailable; + m_deviceOptions->clear(); + for(const QString &device : qAsConst(m_deviceAvailable)) { + m_deviceOptions->addItem(device); + } +} + +const QString &ConfigChannelView::getSelectedFunction() const { return m_selectedFunction; } + +void ConfigChannelView::setSelectedFunction(const QString &mSelectedFunction) +{ + m_selectedFunction = mSelectedFunction; + if(mSelectedFunction.isEmpty()) { + m_functionOptions->setCurrentIndex(0); + } else { + int index = m_functionOptions->findText(m_selectedFunction); + if(index >= 0) { + m_functionOptions->setCurrentIndex(index); + } + } +} + +const QStringList &ConfigChannelView::getFunctionAvailable() const { return m_functionAvailable; } + +void ConfigChannelView::setFunctionAvailable(const QStringList &mFunctionAvailable) +{ + m_functionAvailable = mFunctionAvailable; + m_functionOptions->clear(); + for(const QString &device : qAsConst(m_functionAvailable)) { + m_functionOptions->addItem(device); + } +} + +bool ConfigChannelView::eventFilter(QObject *object, QEvent *event) +{ + if(event->type() == QEvent::Enter) { + setBackgroundRole(QPalette::Highlight); + setAutoFillBackground(true); + if(m_channelEnabled) { + Q_EMIT showPath(m_channelIndex, m_selectedDevice); + } + } + + if(event->type() == QEvent::Leave) { + setBackgroundRole(QPalette::Window); + setAutoFillBackground(false); + Q_EMIT hidePaths(); + } + + return QWidget::event(event); +} + +void ConfigChannelView::initTutorialProperties() +{ + if(m_channelIndex == 0) { + setProperty("tutorial_name", "CHANNEL_WIDGET_1"); + m_chnlCheck->setProperty("tutorial_name", "CHANNEL_ENABLE_1"); + m_deviceOptions->setProperty("tutorial_name", "CHANNEL_DEVICE_1"); + m_functionOptions->setProperty("tutorial_name", "CHANNEL_FUNCTION_1"); + } +} diff --git a/plugins/swiotrefactor/src/config/configchannelview.h b/plugins/swiotrefactor/src/config/configchannelview.h new file mode 100644 index 0000000000..7e77ddc3a1 --- /dev/null +++ b/plugins/swiotrefactor/src/config/configchannelview.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONFIGCHANNELVIEW_H +#define CONFIGCHANNELVIEW_H + +#include +#include +#include +#include +#include +#include + +#define DEVICE_COMBO_WIDTH 105 +#define FUNCTION_COMBO_WIDTH 175 + +namespace scopy::swiotrefactor { +class ConfigChannelView : public QWidget +{ + Q_OBJECT +public: + explicit ConfigChannelView(int channelIndex, QWidget *parent = nullptr); + ~ConfigChannelView(); + + bool isChannelEnabled() const; + void setChannelEnabled(bool channelEnabled); + + const QString &getSelectedDevice() const; + void setSelectedDevice(const QString &selectedDevice); + +protected: + bool eventFilter(QObject *object, QEvent *event) override; + +public: + const QStringList &getDeviceAvailable() const; + void setDeviceAvailable(const QStringList &deviceAvailable); + + const QString &getSelectedFunction() const; + void setSelectedFunction(const QString &selectedFunction); + + const QStringList &getFunctionAvailable() const; + void setFunctionAvailable(const QStringList &functionAvailable); + + void connectSignalsAndSlots(); + +Q_SIGNALS: + void enabledChanged(int channelIndex, bool enabled); + void deviceChanged(int channelIndex, const QString &device); + void functionChanged(int channelIndex, const QString &function); + + void showPath(int channelIndex, const QString &device); + void hidePaths(); + +private: + int m_channelIndex; + bool m_channelEnabled; + QString m_selectedDevice; + QStringList m_deviceAvailable; + + QString m_selectedFunction; + QStringList m_functionAvailable; + + QLabel *m_chnlLabel; + QCheckBox *m_chnlCheck; + QComboBox *m_deviceOptions; + QComboBox *m_functionOptions; + + void setHighlightPalette(); + void initTutorialProperties(); +}; +} // namespace scopy::swiotrefactor + +#endif // CONFIGCHANNELVIEW_H diff --git a/plugins/swiotrefactor/src/config/configcontroller.cpp b/plugins/swiotrefactor/src/config/configcontroller.cpp new file mode 100644 index 0000000000..4fddc4732d --- /dev/null +++ b/plugins/swiotrefactor/src/config/configcontroller.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "configcontroller.h" + +using namespace scopy::swiotrefactor; + +ConfigController::ConfigController(ConfigChannelView *channelView, ConfigModel *model, int channelId) + : m_channelsView(channelView) + , m_model(model) + , m_channelId(channelId) +{ + this->connectSignalsAndSlots(); + this->initChannelView(); +} + +ConfigController::~ConfigController() +{ + if(m_channelsView) { + delete m_channelsView; + m_channelsView = nullptr; + } + + if(m_model) { + delete m_model; + m_model = nullptr; + } +} + +void ConfigController::connectSignalsAndSlots() +{ + connect(m_model, &ConfigModel::readConfigChannelEnabled, this, + [=, this](bool enabled) { m_channelsView->setChannelEnabled(enabled); }); + connect(m_model, &ConfigModel::readConfigChannelDevice, this, [=, this](QString device) { + m_channelsView->setSelectedDevice(device); + Q_EMIT deviceReadingComplete(); + }); + connect(m_model, &ConfigModel::readConfigChannelFunction, this, + [=, this](QString function) { m_channelsView->setSelectedFunction(function); }); + connect(m_model, &ConfigModel::readConfigChannelDeviceAvailable, this, + [=, this](QStringList devicesAvailable) { m_channelsView->setDeviceAvailable(devicesAvailable); }); + connect(m_model, &ConfigModel::readConfigChannelFunctionAvailable, this, + [=, this](QStringList functionsAvailable) { + m_channelsView->setFunctionAvailable(functionsAvailable); + Q_EMIT functionAvailableReadingComplete(); + }); + connect(m_model, &ConfigModel::configChannelDevice, this, [=, this]() { + Q_EMIT deviceReadingComplete(); + // stop and wait for readConfigChannelDevice to finish in order to continue + }); + connect(this, &ConfigController::deviceReadingComplete, this, [this]() { + m_model->readFunctionAvailable(); + // stop and wait for readConfigChannelFunctionAvailable to finish in order to continue + }); + connect(this, &ConfigController::functionAvailableReadingComplete, this, [this]() { m_model->readFunction(); }); + + QObject::connect(m_channelsView, &ConfigChannelView::enabledChanged, this, [this](int index, bool value) { + if(m_channelId == index) { + if(value) { + m_model->writeEnabled("1"); + } else { + m_model->writeEnabled("0"); + } + } + }); + + QObject::connect(m_channelsView, &ConfigChannelView::deviceChanged, this, + [this](int index, const QString &device) { + if(m_channelId == index) { + m_model->writeDevice(device); + Q_EMIT clearDrawArea(); + } + }); + + QObject::connect(m_channelsView, &ConfigChannelView::functionChanged, this, + [this](int index, const QString &function) { + if(m_channelId == index) { + m_model->writeFunction(function); + } + }); +} + +void ConfigController::initChannelView() +{ + m_model->readEnabled(); + m_model->readDeviceAvailable(); + m_model->readDevice(); + // the read device function activates a sequence that also reads the "function_available" and "function" + // attributes +} diff --git a/plugins/swiotrefactor/src/config/configcontroller.h b/plugins/swiotrefactor/src/config/configcontroller.h new file mode 100644 index 0000000000..9a281107ed --- /dev/null +++ b/plugins/swiotrefactor/src/config/configcontroller.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONFIGCONTROLLER_H +#define CONFIGCONTROLLER_H + +#include +#include "configmodel.h" +#include "src/config/configchannelview.h" + +namespace scopy::swiotrefactor { + +class ConfigController : public QObject +{ + Q_OBJECT +public: + explicit ConfigController(ConfigChannelView *channelView, ConfigModel *model, int channelId); + + ~ConfigController(); + + void connectSignalsAndSlots(); + void initChannelView(); + +Q_SIGNALS: + void clearDrawArea(); + void deviceReadingComplete(); + void functionAvailableReadingComplete(); + +private: + ConfigChannelView *m_channelsView; + ConfigModel *m_model; + int m_channelId; +}; + +} // namespace scopy::swiotrefactor + +#endif // CONFIGCONTROLLER_H diff --git a/plugins/swiotrefactor/src/config/configmodel.cpp b/plugins/swiotrefactor/src/config/configmodel.cpp new file mode 100644 index 0000000000..34e3de4f9b --- /dev/null +++ b/plugins/swiotrefactor/src/config/configmodel.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "configmodel.h" +#include "swiot_logging_categories.h" + +#include +#include +#include + +using namespace scopy::swiotrefactor; + +ConfigModel::ConfigModel(struct iio_device *device, int channelId, CommandQueue *commandQueue) + : m_device(device) + , m_channelId(channelId) + , m_commandQueue(commandQueue) +{ + QString attributePrefix = "ch" + QString::number(m_channelId); + + m_enableAttribute = attributePrefix + "_enable"; + m_functionAttribute = attributePrefix + "_function"; + m_functionAvailableAttribute = attributePrefix + "_function_available"; + m_deviceAttribute = attributePrefix + "_device"; + m_deviceAvailableAttribute = attributePrefix + "_device_available"; +} + +ConfigModel::~ConfigModel() {} + +void ConfigModel::readEnabled() +{ + Command *enabledChnCmd = new IioDeviceAttributeRead(m_device, m_enableAttribute.toStdString().c_str(), nullptr); + connect( + enabledChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + bool ok = false; + bool enabled = QString(result).toInt(&ok); + if(!ok) { + return; + } + Q_EMIT readConfigChannelEnabled(enabled); + } else { + qCritical(CAT_SWIOT_CONFIG) << "Error: could not read attribute \"enable\" on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(enabledChnCmd); +} + +void ConfigModel::writeEnabled(const QString &enabled) +{ + Command *enabledChnCmd = new IioDeviceAttributeWrite(m_device, m_enableAttribute.toStdString().c_str(), + enabled.toStdString().c_str(), nullptr); + connect( + enabledChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() < 0) { + qCritical(CAT_SWIOT_CONFIG) + << "Error: could not write attribute \"enable\", (" << enabled << ") on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } else { + Q_EMIT configChannelEnabled(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(enabledChnCmd); +} + +void ConfigModel::readDevice() +{ + Command *deviceChnCmd = new IioDeviceAttributeRead(m_device, m_deviceAttribute.toStdString().c_str(), nullptr); + connect( + deviceChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + Q_EMIT readConfigChannelDevice(result); + } else { + qDebug(CAT_SWIOT_CONFIG) << "Can't read value from device on channel" << m_channelId + << "error id ->" << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(deviceChnCmd); +} + +void ConfigModel::writeDevice(const QString &device) +{ + Command *deviceChnCmd = new IioDeviceAttributeWrite(m_device, m_deviceAttribute.toStdString().c_str(), + device.toStdString().c_str(), nullptr); + connect( + deviceChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() < 0) { + qCritical(CAT_SWIOT_CONFIG) + << "Error: could not write attribute \"device\", (" << device << ") on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } else { + Q_EMIT configChannelDevice(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(deviceChnCmd); +} + +void ConfigModel::readFunction() +{ + Command *functionChnCmd = + new IioDeviceAttributeRead(m_device, m_functionAttribute.toStdString().c_str(), nullptr); + connect( + functionChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + Q_EMIT readConfigChannelFunction(result); + } else { + qCritical(CAT_SWIOT_CONFIG) << "Error: could not read attribute \"function\" on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(functionChnCmd); +} + +void ConfigModel::writeFunction(const QString &function) +{ + Command *functionChnCmd = new IioDeviceAttributeWrite(m_device, m_functionAttribute.toStdString().c_str(), + function.toStdString().c_str(), nullptr); + connect( + functionChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() < 0) { + qCritical(CAT_SWIOT_CONFIG) + << "Error: could not write attribute \"function\", (" << function + << ") on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); + } else { + Q_EMIT configChannelFunction(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(functionChnCmd); +} + +void ConfigModel::readDeviceAvailable() +{ + Command *deviceAvailableChnCmd = + new IioDeviceAttributeRead(m_device, m_deviceAvailableAttribute.toStdString().c_str(), nullptr); + connect( + deviceAvailableChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + QStringList resultList = QStringList(QString(result).split(" ")); + Q_EMIT readConfigChannelDeviceAvailable(resultList); + } else { + qCritical(CAT_SWIOT_CONFIG) + << "Error: could not read attribute \"function available\" on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(deviceAvailableChnCmd); +} + +void ConfigModel::readFunctionAvailable() +{ + Command *functionAvailableChnCmd = + new IioDeviceAttributeRead(m_device, m_functionAvailableAttribute.toStdString().c_str(), nullptr); + connect( + functionAvailableChnCmd, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + + if(tcmd->getReturnCode() >= 0) { + char *result = tcmd->getResult(); + QStringList resultList = QStringList(QString(result).split(" ")); + Q_EMIT readConfigChannelFunctionAvailable(resultList); + } else { + qCritical(CAT_SWIOT_CONFIG) + << "Error: could not read attribute \"device available\" on channel" + << m_channelId << "error id ->" << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + m_commandQueue->enqueue(functionAvailableChnCmd); +} diff --git a/plugins/swiotrefactor/src/config/configmodel.h b/plugins/swiotrefactor/src/config/configmodel.h new file mode 100644 index 0000000000..15de0ab1dd --- /dev/null +++ b/plugins/swiotrefactor/src/config/configmodel.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONFIGMODEL_H +#define CONFIGMODEL_H + +#include + +#include +#include + +extern "C" +{ + struct iio_channel; + struct iio_device; +} + +namespace scopy::swiotrefactor { +class ConfigModel : public QObject +{ + Q_OBJECT +public: + explicit ConfigModel(struct iio_device *device, int channelId, CommandQueue *m_commandQueue); + ~ConfigModel(); + + void readEnabled(); + void writeEnabled(const QString &enabled); + + void readDevice(); + void writeDevice(const QString &device); + + void readFunction(); + void writeFunction(const QString &function); + + void readDeviceAvailable(); + void readFunctionAvailable(); +Q_SIGNALS: + void readConfigChannelEnabled(bool); + void readConfigChannelDevice(QString); + void readConfigChannelFunction(QString); + void readConfigChannelDeviceAvailable(QStringList); + void readConfigChannelFunctionAvailable(QStringList); + + void configChannelEnabled(); + void configChannelDevice(); + void configChannelFunction(); + +private: + struct iio_device *m_device; + int m_channelId; + + QString m_enableAttribute; + QString m_functionAttribute; + QString m_functionAvailableAttribute; + QString m_deviceAttribute; + QString m_deviceAvailableAttribute; + + QString m_enabled; + QStringList m_availableDevices; + QStringList m_availableFunctions; + CommandQueue *m_commandQueue; +}; +} // namespace scopy::swiotrefactor +#endif // CONFIGMODEL_H diff --git a/plugins/swiotrefactor/src/config/drawarea.cpp b/plugins/swiotrefactor/src/config/drawarea.cpp new file mode 100644 index 0000000000..5befa6e754 --- /dev/null +++ b/plugins/swiotrefactor/src/config/drawarea.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "drawarea.h" + +#include +#include +#include +#include +#include + +using namespace scopy::swiotrefactor; + +DrawArea::DrawArea(QWidget *parent) + : QWidget(parent) + , m_filePath(":/swiotrefactor/swiot_board.svg") + , m_drawLabel(new QLabel(this)) + , m_baseImage(new QImage(m_filePath)) + , m_connectionsMap(new QMap, QPixmap *>()) +{ + this->setLayout(new QVBoxLayout(this)); + this->setStyleSheet("background-color: black;"); + + // insert, for each channel, the 2 PixMaps, one for ad74413r and one for max14906 + for(int i = 1; i <= 4; ++i) { + m_connectionsMap->insert({i, AD74413R}, + new QPixmap(":/swiotrefactor/ad74413r_channel" + QString::number(i) + ".png")); + m_connectionsMap->insert({i, MAX14906}, + new QPixmap(":/swiotrefactor/max14906_channel" + QString::number(i) + ".png")); + } + + m_boardImage = new QImage(m_filePath); + m_drawLabel->setPixmap(QPixmap::fromImage(*m_boardImage)); + m_drawLabel->setStyleSheet("border: 20px solid #272730;"); + this->layout()->addWidget(m_drawLabel); +} + +DrawArea::~DrawArea() { delete m_connectionsMap; } + +void DrawArea::activateConnection(int channelIndex, DrawArea::ChannelName channelName) +{ + QPainter painter(m_boardImage); + painter.drawPixmap(0, 0, *m_connectionsMap->value(qMakePair(channelIndex, channelName))); + m_drawLabel->setPixmap(QPixmap::fromImage(*m_boardImage)); +} + +void DrawArea::deactivateConnections() +{ + m_boardImage = new QImage(*m_baseImage); + m_drawLabel->setPixmap(QPixmap::fromImage(*m_baseImage)); +} diff --git a/plugins/swiotrefactor/src/config/drawarea.h b/plugins/swiotrefactor/src/config/drawarea.h new file mode 100644 index 0000000000..d9136be05c --- /dev/null +++ b/plugins/swiotrefactor/src/config/drawarea.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TOOL_LAUNCHER_DRAWAREA_H +#define TOOL_LAUNCHER_DRAWAREA_H + +#include +#include +#include + +namespace scopy::swiotrefactor { +class DrawArea : public QWidget +{ + Q_OBJECT + +public: + explicit DrawArea(QWidget *parent = nullptr); + + ~DrawArea() override; + + enum ChannelName : int + { + AD74413R = 0, + MAX14906 = 1 + }; + + void activateConnection(int channelIndex, ChannelName channelName); + void deactivateConnections(); + +private: + QString m_filePath; + QImage *m_boardImage; + const QImage *m_baseImage; + + QLabel *m_drawLabel; + + // channel-device pairs + QMap, QPixmap *> *m_connectionsMap; +}; +} // namespace scopy::swiotrefactor + +#endif // TOOL_LAUNCHER_DRAWAREA_H diff --git a/plugins/swiotrefactor/src/config/swiotconfig.cpp b/plugins/swiotrefactor/src/config/swiotconfig.cpp new file mode 100644 index 0000000000..cf90efa284 --- /dev/null +++ b/plugins/swiotrefactor/src/config/swiotconfig.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "swiotconfig.h" +#include "swiot_logging_categories.h" + +#include "configcontroller.h" +#include "configmodel.h" + +#include +#include + +#include + +using namespace scopy::swiotrefactor; + +SwiotConfig::SwiotConfig(QString uri, QWidget *parent) + : QWidget(parent) + , m_uri(uri) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QHBoxLayout *layout = new QHBoxLayout(this); + setLayout(layout); + + // tool template configuration + m_tool = new ToolTemplate(this); + m_tool->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_tool->centralContainer()->setVisible(true); + m_tool->topContainerMenuControl()->setVisible(false); + layout->addWidget(m_tool); + + provideDeviceConnection(); + + setupUiElements(); + buildGridLayout(); + createPageLayout(); + initTutorialProperties(); + QObject::connect(m_applyBtn, &QPushButton::pressed, this, &SwiotConfig::onConfigBtnPressed); +} + +SwiotConfig::~SwiotConfig() { ConnectionProvider::close(m_uri); } + +void SwiotConfig::provideDeviceConnection() +{ + Connection *conn = ConnectionProvider::open(m_uri); + m_context = conn->context(); + m_commandQueue = conn->commandQueue(); + m_swiotDevice = iio_context_find_device(m_context, "swiot"); + if(m_swiotDevice == nullptr) { + qCritical(CAT_SWIOT_CONFIG) << "Critical error: the \"swiot\" device was not found."; + } +} + +void SwiotConfig::setupUiElements() +{ + m_applyBtn = createApplyBtn(); + m_drawArea = new DrawArea(this); + m_scrollArea = new QScrollArea(this); + m_chnlsGrid = new QWidget(this); + m_chnlsGrid->setLayout(new QVBoxLayout()); + m_chnlsGrid->layout()->setContentsMargins(0, 0, 0, 0); +} + +QWidget *SwiotConfig::createGridHeader(QWidget *parent) +{ + QWidget *labels = new QWidget(parent); + labels->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QHBoxLayout *layout = new QHBoxLayout(labels); + layout->setContentsMargins(0, 0, 0, 0); + + QLabel *deviceLabel = new QLabel(labels); + deviceLabel->setText("Device"); + StyleHelper::MenuSmallLabel(deviceLabel); + deviceLabel->setFixedWidth(DEVICE_COMBO_WIDTH); + + QLabel *functionLabel = new QLabel(labels); + functionLabel->setText("Function"); + StyleHelper::MenuSmallLabel(functionLabel); + functionLabel->setFixedWidth(FUNCTION_COMBO_WIDTH); + + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + layout->addWidget(deviceLabel); + layout->addWidget(functionLabel); + + return labels; +} + +void SwiotConfig::buildGridLayout() +{ + QWidget *header = createGridHeader(m_chnlsGrid); + m_chnlsGrid->layout()->addWidget(header); + + for(int i = 0; i < NUMBER_OF_CHANNELS; i++) { // there can only be 4 channels + auto *channelView = new ConfigChannelView(i); + auto *configModel = new ConfigModel(m_swiotDevice, i, m_commandQueue); + auto *configController = new ConfigController(channelView, configModel, i); + m_controllers.push_back(configController); + m_chnlsGrid->layout()->addWidget(channelView); + QObject::connect(channelView, &ConfigChannelView::showPath, this, + [this, i](int channelIndex, const QString &deviceName) { + if(channelIndex == i) { + m_drawArea->activateConnection(channelIndex + 1, + (deviceName == "ad74413r") + ? DrawArea::AD74413R + : DrawArea::MAX14906); + } + }); + + QObject::connect(channelView, &ConfigChannelView::hidePaths, this, + [this]() { m_drawArea->deactivateConnections(); }); + + QObject::connect(configController, &ConfigController::clearDrawArea, this, + [this]() { m_drawArea->deactivateConnections(); }); + } + // The apply button will always be at the end of the channel widgets + m_chnlsGrid->layout()->addWidget(m_applyBtn); + m_chnlsGrid->layout()->addItem(new QSpacerItem(20, 40, QSizePolicy::Fixed, QSizePolicy::Expanding)); +} + +void SwiotConfig::createPageLayout() +{ + auto scrollWidget = new QWidget(this); + scrollWidget->setLayout(new QHBoxLayout(this)); + scrollWidget->layout()->addWidget(m_chnlsGrid); + scrollWidget->layout()->addWidget(m_drawArea); + scrollWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + scrollWidget->layout()->setSpacing(40); + m_scrollArea->setWidget(scrollWidget); + + m_tool->addWidgetToCentralContainerHelper(m_scrollArea); +} + +void SwiotConfig::initTutorialProperties() +{ + m_applyBtn->setProperty("tutorial_name", "APPLY_BUTTON"); + m_drawArea->setProperty("tutorial_name", "DRAW_AREA"); +} + +QPushButton *SwiotConfig::createApplyBtn() +{ + auto *applyBtn = new QPushButton(this); + StyleHelper::BlueGrayButton(applyBtn, "applyBtn"); + applyBtn->setCheckable(false); + applyBtn->setText("Apply"); + return applyBtn; +} + +void SwiotConfig::onConfigBtnPressed() { Q_EMIT writeModeAttribute("runtime"); } + +#include "moc_swiotconfig.cpp" diff --git a/plugins/swiotrefactor/src/config/swiotconfig.h b/plugins/swiotrefactor/src/config/swiotconfig.h new file mode 100644 index 0000000000..b40282d3e0 --- /dev/null +++ b/plugins/swiotrefactor/src/config/swiotconfig.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SWIOTCONFIG_H +#define SWIOTCONFIG_H + +#include "configcontroller.h" +#include "src/config/drawarea.h" + +#include +#include +#include +#include + +#include +#include + +#define NUMBER_OF_CHANNELS 4 + +namespace scopy::swiotrefactor { + +class SwiotConfig : public QWidget +{ + Q_OBJECT +public: + SwiotConfig(QString uri, QWidget *parent = nullptr); + ~SwiotConfig(); + +public Q_SLOTS: + void onConfigBtnPressed(); + +Q_SIGNALS: + void writeModeAttribute(QString mode); + void configBtnPressed(); + +private: + QString m_uri; + QMap m_iioDevices; + iio_context *m_context; + iio_device *m_swiotDevice; + + QVector m_controllers; + QVector m_funcAvailable; + QPushButton *m_applyBtn; + CommandQueue *m_commandQueue; + + ToolTemplate *m_tool; + DrawArea *m_drawArea; + QScrollArea *m_scrollArea; + QWidget *m_chnlsGrid; + + void provideDeviceConnection(); + void setupUiElements(); + void buildGridLayout(); + void createPageLayout(); + void initTutorialProperties(); + QWidget *createGridHeader(QWidget *parent); + QPushButton *createApplyBtn(); +}; +} // namespace scopy::swiotrefactor + +#endif // SWIOTCONFIG_H diff --git a/plugins/swiotrefactor/src/externalpsreaderthread.cpp b/plugins/swiotrefactor/src/externalpsreaderthread.cpp new file mode 100644 index 0000000000..65f6839649 --- /dev/null +++ b/plugins/swiotrefactor/src/externalpsreaderthread.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "externalpsreaderthread.h" + +#include "swiot_logging_categories.h" +#include +#include +#include + +using namespace scopy::swiotrefactor; + +ExternalPsReaderThread::ExternalPsReaderThread(QString uri, QString attr, QObject *parent) + : QThread(parent) + , m_uri(uri) + , m_attribute(attr) +{ + m_conn = ConnectionProvider::open(m_uri); + if(!m_conn) { + qDebug(CAT_SWIOT) << "Error, no context available for the external ps task."; + } + connect(m_conn, &Connection::aboutToBeDestroyed, this, [=, this]() { m_conn = nullptr; }); +} + +ExternalPsReaderThread::~ExternalPsReaderThread() +{ + if(m_conn) { + m_conn = nullptr; + ConnectionProvider::close(m_uri); + } +} + +void ExternalPsReaderThread::run() +{ + if(!m_conn) { + return; + } + if(isInterruptionRequested()) { + return; + } + + iio_device *swiotDevice = iio_context_find_device(m_conn->context(), "swiot"); + if(swiotDevice) { + IioDeviceAttributeRead *iioAttrRead = + new IioDeviceAttributeRead(swiotDevice, m_attribute.toStdString().c_str(), nullptr, true); + + connect( + iioAttrRead, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *extPsu = tcmd->getResult(); + bool ok = false; + bool extPsuValue = QString(extPsu).toInt(&ok); + if(ok) { + Q_EMIT hasConnectedPowerSupply(extPsuValue); + } + } else { + qCritical(CAT_SWIOT) << "Error, could not read ext_psu attribute from swiot " + "device, error code" + << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + + m_conn->commandQueue()->enqueue(iioAttrRead); + } +} + +#include "moc_externalpsreaderthread.cpp" diff --git a/plugins/swiotrefactor/src/faults/faultspage.cpp b/plugins/swiotrefactor/src/faults/faultspage.cpp index 2a4b7f695c..d22d76554d 100644 --- a/plugins/swiotrefactor/src/faults/faultspage.cpp +++ b/plugins/swiotrefactor/src/faults/faultspage.cpp @@ -78,16 +78,16 @@ void FaultsPage::setupDevices() if(swiot) { if(ad74413r) { QVector faultRegistersAddr = {0x02e}; - m_ad74413rFaultsDevice = new FaultsDevice("ad74413r", ":/swiot/swiot_faults.json", m_uri, - faultRegistersAddr, this); + m_ad74413rFaultsDevice = new FaultsDevice("ad74413r", ":/swiotrefactor/swiot_faults.json", + m_uri, faultRegistersAddr, this); } else { qCritical(CAT_SWIOT_FAULTS) << "Error: did not find ad74413r device."; } if(max14906) { QVector faultRegistersAddr = {0x04, 0x05, 0x06, 0x07}; - m_max14906FaultsDevice = new FaultsDevice("max14906", ":/swiot/swiot_faults.json", m_uri, - faultRegistersAddr, this); + m_max14906FaultsDevice = new FaultsDevice("max14906", ":/swiotrefactor/swiot_faults.json", + m_uri, faultRegistersAddr, this); } else { qCritical(CAT_SWIOT_FAULTS) << "Error: did not find max14906 device."; } diff --git a/plugins/swiotrefactor/src/max14906/diodigitalchannel.cpp b/plugins/swiotrefactor/src/max14906/diodigitalchannel.cpp index 731e3593fd..4a5f1a8857 100644 --- a/plugins/swiotrefactor/src/max14906/diodigitalchannel.cpp +++ b/plugins/swiotrefactor/src/max14906/diodigitalchannel.cpp @@ -19,6 +19,7 @@ */ #include "max14906/diodigitalchannel.h" +#include "plotnavigator.hpp" #include "swiot_logging_categories.h" #include #include @@ -76,6 +77,7 @@ void DioDigitalChannel::initData() void DioDigitalChannel::initPlot() { m_plot = new PlotWidget(this); + m_plot->navigator()->setEnabled(false); m_plot->xAxis()->scaleDraw()->setFloatPrecision(0); m_plot->xAxis()->setInterval(0, m_timeSpan); m_plot->yAxis()->scaleEngine()->setAttribute(QwtScaleEngine::Floating, true); diff --git a/plugins/swiotrefactor/src/readerthread.cpp b/plugins/swiotrefactor/src/readerthread.cpp index 1284f522a6..24cb50d178 100644 --- a/plugins/swiotrefactor/src/readerthread.cpp +++ b/plugins/swiotrefactor/src/readerthread.cpp @@ -20,7 +20,7 @@ #include "readerthread.h" -//#include "src/runtime/ad74413r/bufferlogic.h" +#include "ad74413r/bufferlogic.h" #include "swiot_logging_categories.h" #include @@ -111,60 +111,60 @@ void ReaderThread::addBufferedDevice(iio_device *device) { m_iioDev = device; } void ReaderThread::initIioChannels() { - // auto vals = m_chnlsInfo.values(); - // for(const auto &val : vals) { - // val->addReadScaleCommand(); - // val->addReadOffsetCommand(); - // } + auto vals = m_chnlsInfo.values(); + for(const auto &val : vals) { + val->addReadScaleCommand(); + val->addReadOffsetCommand(); + } } void ReaderThread::enableIioChnls() { - // if(m_iioDev) { - // auto keys = m_chnlsInfo.keys(); - // for(const auto &key : keys) { - // struct iio_channel *iioChnl = m_chnlsInfo[key]->iioChnl(); - // bool isEnabled = iio_channel_is_enabled(iioChnl); - // if(m_chnlsInfo[key]->isEnabled()) { - // if(!isEnabled) { - // iio_channel_enable(iioChnl); - // } - // qDebug(CAT_SWIOT_AD74413R) << "Chanel en " << key; - // } else { - // if(isEnabled) { - // iio_channel_disable(iioChnl); - // } - // qDebug(CAT_SWIOT_AD74413R) << "Chanel dis " << key; - // } - // } - // } + if(m_iioDev) { + auto keys = m_chnlsInfo.keys(); + for(const auto &key : keys) { + struct iio_channel *iioChnl = m_chnlsInfo[key]->iioChnl(); + bool isEnabled = iio_channel_is_enabled(iioChnl); + if(m_chnlsInfo[key]->isEnabled()) { + if(!isEnabled) { + iio_channel_enable(iioChnl); + } + qDebug(CAT_SWIOT_AD74413R) << "Chanel en " << key; + } else { + if(isEnabled) { + iio_channel_disable(iioChnl); + } + qDebug(CAT_SWIOT_AD74413R) << "Chanel dis " << key; + } + } + } } int ReaderThread::getEnabledChnls() { int enChnls = 0; - // auto keys = m_chnlsInfo.keys(); - // for(const auto &key : keys) { - // if(iio_channel_is_enabled(m_chnlsInfo[key]->iioChnl())) { - // enChnls++; - // } - // } + auto keys = m_chnlsInfo.keys(); + for(const auto &key : keys) { + if(iio_channel_is_enabled(m_chnlsInfo[key]->iioChnl())) { + enChnls++; + } + } return enChnls; } -// QVector ReaderThread::getEnabledBufferedChnls() -//{ -// QVector enabledBufferedChnls = {}; +QVector ReaderThread::getEnabledBufferedChnls() +{ + QVector enabledBufferedChnls = {}; -// auto keys = m_chnlsInfo.keys(); -// for(const auto &key : keys) { -// if(m_chnlsInfo[key]->isScanElement() && m_chnlsInfo[key]->isEnabled() && -// !m_chnlsInfo[key]->isOutput()) { -// enabledBufferedChnls.push_back(m_chnlsInfo[key]); -// } -// } -// return enabledBufferedChnls; -//} + auto keys = m_chnlsInfo.keys(); + for(const auto &key : keys) { + if(m_chnlsInfo[key]->isScanElement() && m_chnlsInfo[key]->isEnabled() && + !m_chnlsInfo[key]->isOutput()) { + enabledBufferedChnls.push_back(m_chnlsInfo[key]); + } + } + return enabledBufferedChnls; +} void ReaderThread::bufferRefillCommandFinished(scopy::Command *cmd) { @@ -185,13 +185,13 @@ void ReaderThread::bufferRefillCommandFinished(scopy::Command *cmd) uint32_t *endAdr = (uint32_t *)iio_buffer_end(m_iioBuff); m_bufferData.clear(); for(int i = 0; i < m_enabledChnlsNo; i++) { - m_bufferData.push_back({}); + m_bufferData.insert(i, {}); } for(uint32_t *ptr = startAdr; ptr != endAdr; ptr++) { idx = i % m_enabledChnlsNo; uint32_t d_ptr = (uint32_t)*ptr; - // data = m_bufferedChnls[idx]->convertData(d_ptr); + data = m_bufferedChnls[idx]->convertData(d_ptr); m_bufferData[idx].push_back(data); i++; } @@ -253,28 +253,28 @@ void ReaderThread::bufferDestroyCommandFinished(scopy::Command *cmd) qDebug(CAT_SWIOT_AD74413R) << "Buffer wasn't destroyed: " + QString(strerror(-tcmd->getReturnCode())); } else { m_iioBuff = nullptr; - // m_bufferedChnls.clear(); + m_bufferedChnls.clear(); } Q_EMIT readerThreadFinished(); } void ReaderThread::createIioBuffer() { - // std::unique_lock lock(m_mutex); - // m_enabledChnlsNo = getEnabledChnls(); - // m_bufferedChnls = getEnabledBufferedChnls(); - // qInfo(CAT_SWIOT_AD74413R) << "Enabled channels number: " + QString::number(m_enabledChnlsNo); - // if(m_iioDev) { - // Command *createBufferCommand; - // if(m_samplingFreq >= MAX_BUFFER_SIZE) { - // createBufferCommand = new IioDeviceCreateBuffer(m_iioDev, MAX_BUFFER_SIZE, false, - // nullptr); } else { createBufferCommand = new - // IioDeviceCreateBuffer(m_iioDev, MIN_BUFFER_SIZE, false, nullptr); - // } - // connect(createBufferCommand, &scopy::Command::finished, this, - // &ReaderThread::bufferCreateCommandFinished, Qt::QueuedConnection); - // m_cmdQueue->enqueue(createBufferCommand); - // } + std::unique_lock lock(m_mutex); + m_enabledChnlsNo = getEnabledChnls(); + m_bufferedChnls = getEnabledBufferedChnls(); + qInfo(CAT_SWIOT_AD74413R) << "Enabled channels number: " + QString::number(m_enabledChnlsNo); + if(m_iioDev) { + Command *createBufferCommand; + if(m_samplingFreq >= MAX_BUFFER_SIZE) { + createBufferCommand = new IioDeviceCreateBuffer(m_iioDev, MAX_BUFFER_SIZE, false, nullptr); + } else { + createBufferCommand = new IioDeviceCreateBuffer(m_iioDev, MIN_BUFFER_SIZE, false, nullptr); + } + connect(createBufferCommand, &scopy::Command::finished, this, + &ReaderThread::bufferCreateCommandFinished, Qt::QueuedConnection); + m_cmdQueue->enqueue(createBufferCommand); + } } void ReaderThread::cancelIioBuffer() @@ -300,7 +300,7 @@ void ReaderThread::destroyIioBuffer() } } -// void ReaderThread::onChnlsChange(QMap chnlsInfo) { m_chnlsInfo = chnlsInfo; } +void ReaderThread::onChnlsChange(QMap chnlsInfo) { m_chnlsInfo = chnlsInfo; } void ReaderThread::onSamplingFrequencyComputed(double samplingFrequency) { m_samplingFreq = samplingFrequency; } @@ -328,7 +328,6 @@ void ReaderThread::runBuffered(int requiredBuffersNumber) void ReaderThread::requestStop() { - requestInterruption(); if(isBuffered && m_running) { m_running = false; destroyIioBuffer(); @@ -363,7 +362,6 @@ void ReaderThread::singleDio() { this->runDio(); } void ReaderThread::forcedStop() { - requestInterruption(); if(isBuffered && m_running) { m_running = false; cancelIioBuffer(); @@ -371,8 +369,4 @@ void ReaderThread::forcedStop() wait(); } -void ReaderThread::handleConnectionDestroyed() -{ - m_deinit = false; - requestInterruption(); -} +void ReaderThread::handleConnectionDestroyed() { m_deinit = false; } diff --git a/plugins/swiotrefactor/src/swiotcontroller.cpp b/plugins/swiotrefactor/src/swiotcontroller.cpp new file mode 100644 index 0000000000..2bcc48e1a1 --- /dev/null +++ b/plugins/swiotrefactor/src/swiotcontroller.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "swiotcontroller.h" + +#include "swiot_logging_categories.h" + +#include +#include +#include + +using namespace scopy; +using namespace scopy::swiotrefactor; + +SwiotController::SwiotController(QString uri, QObject *parent) + : QObject(parent) + , uri(uri) + , m_isRuntimeCtx(false) + , m_temperatureReadEn(false) +{ + pingTask = nullptr; + pingTimer = nullptr; + temperatureTask = nullptr; + temperatureTimer = nullptr; + extPsTask = nullptr; + powerSupplyTimer = nullptr; + identifyTask = nullptr; + m_cmdQueue = nullptr; +} + +SwiotController::~SwiotController() {} + +void SwiotController::startPingTask() +{ + pingTask = new SwiotPingTask(m_conn); + pingTimer = new CyclicalTask(pingTask); + connect(pingTask, SIGNAL(pingSuccess()), this, SIGNAL(pingSuccess())); + connect(pingTask, SIGNAL(pingFailed()), this, SIGNAL(pingFailed())); + pingTimer->start(2000); +} + +void SwiotController::stopPingTask() +{ + pingTask->requestInterruption(); + pingTimer->deleteLater(); + pingTask->deleteLater(); +} + +void SwiotController::connectSwiot() +{ + m_conn = ConnectionProvider::open(uri); + m_iioCtx = m_conn->context(); + m_cmdQueue = m_conn->commandQueue(); +} + +void SwiotController::disconnectSwiot() +{ + if(!m_conn || !m_iioCtx || !m_cmdQueue) { + return; + } + ConnectionProvider::close(uri); + m_conn = nullptr; + m_iioCtx = nullptr; + m_cmdQueue = nullptr; +} + +void SwiotController::startPowerSupplyTask(QString attribute) +{ + extPsTask = new ExternalPsReaderThread(uri, attribute, this); + powerSupplyTimer = new CyclicalTask(extPsTask); + connect(extPsTask, &ExternalPsReaderThread::hasConnectedPowerSupply, this, + &SwiotController::hasConnectedPowerSupply); + powerSupplyTimer->start(5000); +} + +void SwiotController::stopPowerSupplyTask() +{ + powerSupplyTimer->stop(); + extPsTask->requestInterruption(); + disconnect(extPsTask, &ExternalPsReaderThread::hasConnectedPowerSupply, this, + &SwiotController::hasConnectedPowerSupply); + powerSupplyTimer->deleteLater(); + extPsTask->deleteLater(); +} + +void SwiotController::startTemperatureTask() +{ + if(!m_isRuntimeCtx || m_temperatureReadEn) { + return; + } + temperatureTask = new SwiotReadTemperatureTask(uri, this); + temperatureTimer = new CyclicalTask(temperatureTask); + connect(temperatureTask, &SwiotReadTemperatureTask::newTemperature, this, &SwiotController::readTemperature); + temperatureTimer->start(2000); + m_temperatureReadEn = true; +} + +void SwiotController::stopTemperatureTask() +{ + if(!m_isRuntimeCtx || !m_temperatureReadEn) { + return; + } + temperatureTask->requestInterruption(); + temperatureTimer->stop(); + disconnect(temperatureTask, &SwiotReadTemperatureTask::newTemperature, this, &SwiotController::readTemperature); + temperatureTimer->deleteLater(); + temperatureTask->deleteLater(); + m_temperatureReadEn = false; +} + +void SwiotController::identify() +{ + if(!identifyTask) { + identifyTask = new SwiotIdentifyTask(uri); + identifyTask->start(); + connect(identifyTask, &QThread::finished, this, [=, this]() { + delete identifyTask; + identifyTask = nullptr; + }); + } +} + +void SwiotController::writeModeAttribute(QString mode) +{ + if(!m_iioCtx || !m_cmdQueue) { + return; + } + struct iio_device *swiot = iio_context_find_device(m_iioCtx, "swiot"); + if(swiot) { + Command *writeModeCommand = + new IioDeviceAttributeWrite(swiot, "mode", mode.toStdString().c_str(), nullptr); + connect(writeModeCommand, &scopy::Command::finished, this, &SwiotController::writeModeCommandFinished, + Qt::QueuedConnection); + m_cmdQueue->enqueue(writeModeCommand); + } else { + qDebug(CAT_SWIOT) << "Can't find swiot iio_device"; + Q_EMIT writeModeFailed(); + } +} + +void SwiotController::writeModeCommandFinished(scopy::Command *cmd) +{ + IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + ConnectionProvider::closeAll(m_conn->uri()); + QString attrVal = QString::fromStdString(tcmd->getAttributeValue()); + Q_EMIT modeAttributeChanged(attrVal); + qInfo(CAT_SWIOT) << R"(Successfully written swiot mode)"; + } else { + qDebug(CAT_SWIOT) << R"(Error, could not change swiot mode)" << tcmd->getReturnCode(); + Q_EMIT writeModeFailed(); + } +} + +void SwiotController::readModeAttribute() +{ + if(!m_iioCtx || !m_cmdQueue) { + return; + } + struct iio_device *swiot = iio_context_find_device(m_iioCtx, "swiot"); + if(swiot) { + Command *readModeCommand = new IioDeviceAttributeRead(swiot, "mode", nullptr); + connect(readModeCommand, &scopy::Command::finished, this, &SwiotController::readModeCommandFinished, + Qt::QueuedConnection); + m_cmdQueue->enqueue(readModeCommand); + } else { + qDebug(CAT_SWIOT) << "Can't find swiot iio_device"; + } +} + +void SwiotController::readModeCommandFinished(scopy::Command *cmd) +{ + IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *mode = tcmd->getResult(); + bool runtime = (strcmp(mode, "runtime") == 0); + setIsRuntimeCtx(runtime); + } else { + qDebug(CAT_SWIOT) << R"(Critical error: could not read mode attribute, error code:)" + << tcmd->getReturnCode(); + } +} + +void SwiotController::setIsRuntimeCtx(bool runtimeCtx) +{ + m_isRuntimeCtx = runtimeCtx; + Q_EMIT isRuntimeCtxChanged(m_isRuntimeCtx); +} diff --git a/plugins/swiotrefactor/src/swiotidentifytask.cpp b/plugins/swiotrefactor/src/swiotidentifytask.cpp new file mode 100644 index 0000000000..a4b9a24ae2 --- /dev/null +++ b/plugins/swiotrefactor/src/swiotidentifytask.cpp @@ -0,0 +1,62 @@ +#include "swiotidentifytask.h" + +#include "swiot_logging_categories.h" + +#include + +#include +#include + +using namespace scopy::swiotrefactor; +SwiotIdentifyTask::SwiotIdentifyTask(QString uri, QObject *parent) + : QThread(parent) + , m_uri(uri) + , m_conn(nullptr) +{ + m_conn = ConnectionProvider::open(m_uri); + if(!m_conn) { + qDebug(CAT_SWIOT) << "Error, no context available for the identify task."; + } + connect(m_conn, &Connection::aboutToBeDestroyed, this, [=, this]() { m_conn = nullptr; }); +} + +SwiotIdentifyTask::~SwiotIdentifyTask() +{ + if(m_conn) { + m_conn = nullptr; + ConnectionProvider::close(m_uri); + } +} + +void SwiotIdentifyTask::run() +{ + if(!m_conn) { + return; + } + + if(isInterruptionRequested()) { + return; + } + iio_device *swiotDevice = iio_context_find_device(m_conn->context(), "swiot"); + + if(swiotDevice) { + IioDeviceAttributeWrite *iioAttrWrite = + new IioDeviceAttributeWrite(swiotDevice, "identify", "1", nullptr, true); + + connect( + iioAttrWrite, &scopy::Command::finished, this, + [=, this](scopy::Command *cmd) { + IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() < 0) { + qCritical(CAT_SWIOT) << "Error, could not identify swiot, error code" + << tcmd->getReturnCode(); + } + }, + Qt::QueuedConnection); + + m_conn->commandQueue()->enqueue(iioAttrWrite); + } +} diff --git a/plugins/swiotrefactor/src/swiotinfopage.cpp b/plugins/swiotrefactor/src/swiotinfopage.cpp new file mode 100644 index 0000000000..d6d58baffb --- /dev/null +++ b/plugins/swiotrefactor/src/swiotinfopage.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "swiotinfopage.h" + +#include + +using namespace scopy::swiotrefactor; + +SwiotInfoPage::SwiotInfoPage(QWidget *parent) + : InfoPage(parent) +{ + // not enough attributes for correct display with normal size policies, there is too much spacing without this + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + this->initTempCheckBox(); + this->layout()->addWidget(m_enTempReadCheckBox); + this->setAdvancedMode(true); +} + +void SwiotInfoPage::enableTemperatureReadBtn(bool enable) +{ + m_enTempReadCheckBox->setEnabled(enable); + m_enTempReadCheckBox->setVisible(enable); +} + +void SwiotInfoPage::initTempCheckBox() +{ + m_enTempReadCheckBox = new QCheckBox("Enable temperature read"); + m_enTempReadCheckBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + connect(m_enTempReadCheckBox, &QCheckBox::toggled, this, &SwiotInfoPage::temperatureReadEnabled); + m_enTempReadCheckBox->setEnabled(false); + m_enTempReadCheckBox->setVisible(true); + m_enTempReadCheckBox->setChecked(true); +} + +#include "moc_swiotinfopage.cpp" diff --git a/plugins/swiotrefactor/src/swiotpingtask.cpp b/plugins/swiotrefactor/src/swiotpingtask.cpp new file mode 100644 index 0000000000..8704ae2b88 --- /dev/null +++ b/plugins/swiotrefactor/src/swiotpingtask.cpp @@ -0,0 +1,50 @@ +#include "swiotpingtask.h" + +#include + +#include +#include + +using namespace scopy; +using namespace scopy::swiotrefactor; +SwiotPingTask::SwiotPingTask(Connection *conn, QObject *parent) + : QThread(parent) +{ + c = conn; +} + +SwiotPingTask::~SwiotPingTask() {} + +void SwiotPingTask::run() +{ + enabled = true; + if(!c) { + Q_EMIT pingFailed(); + return; + } + + auto dev = iio_context_find_device(c->context(), "sw_trig"); + + if(dev) { + Command *getTriggerCommand = new IioDeviceGetTrigger(dev, nullptr); + connect(getTriggerCommand, &scopy::Command::finished, this, &SwiotPingTask::getTriggerCommandFinished, + Qt::QueuedConnection); + c->commandQueue()->enqueue(getTriggerCommand); + } +} + +void SwiotPingTask::getTriggerCommandFinished(scopy::Command *cmd) +{ + IioDeviceGetTrigger *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + int ret = tcmd->getReturnCode(); + if(ret >= 0 || ret == -ENOENT) { + Q_EMIT pingSuccess(); + } else { + Q_EMIT pingFailed(); + } +} + +#include "moc_swiotpingtask.cpp" diff --git a/plugins/swiotrefactor/src/swiotreadtemperaturetask.cpp b/plugins/swiotrefactor/src/swiotreadtemperaturetask.cpp new file mode 100644 index 0000000000..b24892b8cf --- /dev/null +++ b/plugins/swiotrefactor/src/swiotreadtemperaturetask.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "swiotreadtemperaturetask.h" + +#include "swiot_logging_categories.h" + +#include +#include +#include + +#define DEVICE_NAME "adt75" +#define CHANNEL_NAME "temp" + +using namespace scopy::swiotrefactor; + +SwiotReadTemperatureTask::SwiotReadTemperatureTask(QString uri, QObject *parent) + : QThread(parent) + , m_uri(std::move(uri)) + , m_channel(nullptr) + , m_device(nullptr) + , m_conn(nullptr) + , m_raw(0.0) + , m_scale(0.0) + , m_offset(0.0) +{ + m_conn = ConnectionProvider::open(m_uri); + if(!m_conn) { + qDebug(CAT_SWIOT) << "Error, no context available for the temperature task."; + return; + } + connect(m_conn, &Connection::aboutToBeDestroyed, this, [=, this]() { m_conn = nullptr; }); + + m_device = iio_context_find_device(m_conn->context(), DEVICE_NAME); + if(!m_device) { + qDebug(CAT_SWIOT) << "Error, could not find" << DEVICE_NAME + << "from the given context. Temperature not available."; + return; + } + + m_channel = iio_device_find_channel(m_device, CHANNEL_NAME, false); + if(!m_channel) { + qDebug(CAT_SWIOT) << "Error, could not find channel " << CHANNEL_NAME << "from device" << DEVICE_NAME + << ". Temperature not available."; + return; + } + Command *attrReadScale = new IioChannelAttributeRead(m_channel, "scale", nullptr, true); + Command *attrReadOffset = new IioChannelAttributeRead(m_channel, "offset", nullptr, true); + + connect(attrReadScale, &scopy::Command::finished, this, &SwiotReadTemperatureTask::readScaleCommandFinished, + Qt::QueuedConnection); + connect(attrReadOffset, &scopy::Command::finished, this, &SwiotReadTemperatureTask::readOffsetCommandFinished, + Qt::QueuedConnection); + m_conn->commandQueue()->enqueue(attrReadScale); + m_conn->commandQueue()->enqueue(attrReadOffset); +} + +SwiotReadTemperatureTask::~SwiotReadTemperatureTask() +{ + if(m_conn) { + m_conn = nullptr; + ConnectionProvider::close(m_uri); + } +} + +void SwiotReadTemperatureTask::run() +{ + if(isInterruptionRequested()) { + return; + } + + Command *attrReadRaw = new IioChannelAttributeRead(m_channel, "raw", nullptr); + connect(attrReadRaw, &scopy::Command::finished, this, &SwiotReadTemperatureTask::readRawCommandFinished, + Qt::QueuedConnection); + + m_conn->commandQueue()->enqueue(attrReadRaw); +} + +void SwiotReadTemperatureTask::readRawCommandFinished(Command *cmd) +{ + if(isInterruptionRequested()) { + return; + } + IioChannelAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *res = tcmd->getResult(); + bool ok = false; + double raw = QString(res).toDouble(&ok); + if(ok) { + m_raw = raw; + double temperature = (m_raw + m_offset) * m_scale / 1000; + qDebug(CAT_SWIOT) << "Read temperature value of" << temperature; + Q_EMIT newTemperature(temperature); + } + } else { + qDebug(CAT_SWIOT) << "Error, could not read \"raw\" attribute from " << DEVICE_NAME + << ". Temperature not available."; + } +} + +void SwiotReadTemperatureTask::readScaleCommandFinished(Command *cmd) +{ + IioChannelAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *res = tcmd->getResult(); + bool ok = false; + double scale = QString(res).toDouble(&ok); + if(ok) { + m_scale = scale; + } + } else { + qDebug(CAT_SWIOT) << "Error, could not read \"scale\" attribute from " << DEVICE_NAME + << ". Temperature not available."; + } +} + +void SwiotReadTemperatureTask::readOffsetCommandFinished(Command *cmd) +{ + IioChannelAttributeRead *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + char *res = tcmd->getResult(); + bool ok = false; + double offset = QString(res).toDouble(&ok); + if(ok) { + m_offset = offset; + } + } else { + qDebug(CAT_SWIOT) << "Error, could not read \"offset\" attribute from " << DEVICE_NAME + << ". Temperature not available."; + } +} + +#include "moc_swiotreadtemperaturetask.cpp" diff --git a/plugins/swiotrefactor/src/swiotrefactor.cpp b/plugins/swiotrefactor/src/swiotrefactor.cpp index edb76dd790..7720c7d457 100644 --- a/plugins/swiotrefactor/src/swiotrefactor.cpp +++ b/plugins/swiotrefactor/src/swiotrefactor.cpp @@ -3,106 +3,425 @@ #include #include +#include "swiot_logging_categories.h" #include "max14906/max14906.h" #include "faults/faults.h" +#include "ad74413r/ad74413r.h" + +#include + +#include + +#include Q_LOGGING_CATEGORY(CAT_SWIOTREFACTOR, "SWIOTREFACTORPlugin") using namespace scopy::swiotrefactor; bool SWIOTREFACTORPlugin::compatible(QString m_param, QString category) { - // This function defines the characteristics according to which the - // plugin is compatible with a specific device - bool ret = true; + m_name = "SWIOT1L"; + bool ret = false; + Connection *conn = ConnectionProvider::open(m_param); + + if(!conn) { + qWarning(CAT_SWIOT) << "No context available for swiot"; + return false; + } + + iio_device *swiotDevice = iio_context_find_device(conn->context(), "swiot"); + if(swiotDevice) { + ret = true; + } + + ConnectionProvider::close(m_param); + return ret; } +void SWIOTREFACTORPlugin::preload() +{ + m_displayName = "SWIOT1L"; + m_swiotController = new SwiotController(m_param, this); + m_statusContainer = nullptr; + connect(m_swiotController, &SwiotController::isRuntimeCtxChanged, this, + &SWIOTREFACTORPlugin::onIsRuntimeCtxChanged); + connect(m_swiotController, &SwiotController::modeAttributeChanged, this, + &SWIOTREFACTORPlugin::onModeAttributeChanged); + connect(m_swiotController, &SwiotController::writeModeFailed, m_swiotController, + &SwiotController::disconnectSwiot); +} + bool SWIOTREFACTORPlugin::loadPage() { - // Here you must write the code for the plugin info page - // Below is an example for an iio device - /*m_page = new QWidget(); + m_page = new QWidget(); m_page->setLayout(new QVBoxLayout(m_page)); m_page->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_infoPage = new InfoPage(m_page); - m_infoPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + m_infoPage = new swiotrefactor::SwiotInfoPage(m_page); m_page->layout()->addWidget(m_infoPage); m_page->layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Preferred, QSizePolicy::Expanding)); - auto cp = ContextProvider::GetInstance(); - struct iio_context *context = cp->open(m_param); - ssize_t attributeCount = iio_context_get_attrs_count(context); + connect(m_swiotController, &SwiotController::readTemperature, this, [=, this](double temperature) { + if(m_isRuntime) { + m_infoPage->update("Temperature", QString::number(temperature)); + } + }); + connect(m_infoPage, &SwiotInfoPage::temperatureReadEnabled, this, [=, this](bool toggled) { + if(toggled) { + m_swiotController->startTemperatureTask(); + } else { + m_swiotController->stopTemperatureTask(); + } + }); + connect(m_btnTutorial, &QPushButton::clicked, this, &SWIOTREFACTORPlugin::startTutorial); + + Connection *conn = ConnectionProvider::open(m_param); + + ssize_t attributeCount = iio_context_get_attrs_count(conn->context()); for(int i = 0; i < attributeCount; ++i) { const char *name; const char *value; - int ret = iio_context_get_attr(context, i, &name, &value); + int ret = iio_context_get_attr(conn->context(), i, &name, &value); if(ret < 0) { - qWarning(CAT_SWIOTREFACTOR) << "Could not read attribute with index:" << i; + qWarning(CAT_SWIOT) << "Could not read attribute with index:" << i; continue; } m_infoPage->update(name, value); } - cp->close(m_param); - m_page->ensurePolished();*/ + + ConnectionProvider::close(m_param); + m_page->ensurePolished(); + + return true; +} + +bool SWIOTREFACTORPlugin::loadExtraButtons() +{ + m_btnIdentify = new QPushButton("Identify"); + m_extraButtons.append(m_btnIdentify); + connect(m_btnIdentify, SIGNAL(clicked()), m_swiotController, SLOT(identify())); + + // The tutorial button will only be clickable when the user connects to the device + m_btnTutorial = new QPushButton(tr("Tutorial")); + m_extraButtons.append(m_btnTutorial); + m_btnTutorial->setEnabled(false); + m_btnTutorial->setToolTip("The tutorial will be available once the device is connected."); + return true; } bool SWIOTREFACTORPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/gui/icons/adalm.svg"); + m_icon = new QLabel(""); + m_icon->setStyleSheet("border-image: url(:/swiotrefactor/swiot_icon.svg);"); return true; } void SWIOTREFACTORPlugin::loadToolList() { m_toolList.append( - SCOPY_NEW_TOOLMENUENTRY("max14906", "Max14906", ":/gui/icons/scopy-default/icons/gear_wheel.svg")); + SCOPY_NEW_TOOLMENUENTRY(CONFIG_TME_ID, "Config", ":/gui/icons/scopy-default/icons/tool_debugger.svg")); + m_toolList.append(SCOPY_NEW_TOOLMENUENTRY(AD74413R_TME_ID, "AD74413R", + ":/gui/icons/scopy-default/icons/tool_oscilloscope.svg")); m_toolList.append( - SCOPY_NEW_TOOLMENUENTRY("faults", "Faults", ":/gui/icons/scopy-default/icons/gear_wheel.svg")); + SCOPY_NEW_TOOLMENUENTRY(MAX14906_TME_ID, "MAX14906", ":/gui/icons/scopy-default/icons/tool_io.svg")); + m_toolList.append(SCOPY_NEW_TOOLMENUENTRY(FAULTS_TME_ID, "Faults", ":/swiotrefactor/tool_faults.svg")); } void SWIOTREFACTORPlugin::unload() -{ /*delete m_infoPage;*/ +{ + disconnect(m_swiotController, &SwiotController::isRuntimeCtxChanged, this, + &SWIOTREFACTORPlugin::onIsRuntimeCtxChanged); + disconnect(m_swiotController, &SwiotController::modeAttributeChanged, this, + &SWIOTREFACTORPlugin::onModeAttributeChanged); + disconnect(m_swiotController, &SwiotController::writeModeFailed, m_swiotController, + &SwiotController::disconnectSwiot); + delete m_infoPage; + delete m_swiotController; } -QString SWIOTREFACTORPlugin::description() { return "Write the plugin description here"; } - bool SWIOTREFACTORPlugin::onConnect() { - // This method is called when you try to connect to a device and the plugin is - // compatible to that device - // In case of success the function must return true and false otherwise - Max14906 *max14906 = new Max14906(m_param, m_toolList[0]); - m_toolList[0]->setTool(max14906); - m_toolList[0]->setEnabled(true); - m_toolList[0]->setRunBtnVisible(true); + Connection *conn = ConnectionProvider::open(m_param); + if(!conn) { + return false; + } + + m_runtime = new SwiotRuntime(m_param, this); + connect(m_runtime, &SwiotRuntime::writeModeAttribute, this, &SWIOTREFACTORPlugin::setCtxMode); + connect(m_swiotController, &SwiotController::isRuntimeCtxChanged, m_runtime, + &SwiotRuntime::onIsRuntimeCtxChanged); + connect(m_swiotController, &SwiotController::hasConnectedPowerSupply, this, + &SWIOTREFACTORPlugin::powerSupplyStatus); + + m_swiotController->connectSwiot(); + m_swiotController->readModeAttribute(); + m_swiotController->startPingTask(); + m_swiotController->startPowerSupplyTask("ext_psu"); + m_btnTutorial->setEnabled(true); + m_btnTutorial->setToolTip(""); - Faults *faults = new Faults(m_param, m_toolList[1]); - m_toolList[1]->setTool(faults); - m_toolList[1]->setEnabled(true); - m_toolList[1]->setRunBtnVisible(true); return true; } bool SWIOTREFACTORPlugin::onDisconnect() { - // This method is called when the disconnect button is pressed - // It must remove all connections that were established on the connection - for(auto &tool : m_toolList) { - tool->setEnabled(false); - tool->setRunning(false); - tool->setRunBtnVisible(false); - QWidget *w = tool->tool(); - if(w) { - tool->setTool(nullptr); - delete(w); - } + auto configTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, CONFIG_TME_ID); + auto ad74413rTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, AD74413R_TME_ID); + auto max14906Tme = ToolMenuEntry::findToolMenuEntryById(m_toolList, MAX14906_TME_ID); + auto faultsTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, FAULTS_TME_ID); + + for(ToolMenuEntry *tme : qAsConst(m_toolList)) { + tme->setRunning(false); + tme->setEnabled(false); + tme->setRunBtnVisible(false); + tme->tool()->deleteLater(); + tme->setTool(nullptr); + } + + disconnect(dynamic_cast(configTme->tool()), &SwiotConfig::writeModeAttribute, this, + &SWIOTREFACTORPlugin::setCtxMode); + disconnect(dynamic_cast(ad74413rTme->tool()), &Ad74413r::configBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + disconnect(dynamic_cast(max14906Tme->tool()), &Max14906::configBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + disconnect(dynamic_cast(faultsTme->tool()), &Faults::backBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + + disconnect(m_swiotController, &SwiotController::hasConnectedPowerSupply, this, + &SWIOTREFACTORPlugin::powerSupplyStatus); + + disconnect(m_swiotController, &SwiotController::pingFailed, this, &SWIOTREFACTORPlugin::disconnectDevice); + + disconnect(m_swiotController, &SwiotController::isRuntimeCtxChanged, m_runtime, + &SwiotRuntime::onIsRuntimeCtxChanged); + + m_swiotController->stopPingTask(); + m_swiotController->stopPowerSupplyTask(); + m_swiotController->stopTemperatureTask(); + m_swiotController->disconnectSwiot(); + + m_btnTutorial->setEnabled(false); + + if(m_runtime) { + disconnect(m_runtime, &SwiotRuntime::writeModeAttribute, this, &SWIOTREFACTORPlugin::setCtxMode); + delete m_runtime; + m_runtime = nullptr; + } + + if(m_statusContainer) { + delete m_statusContainer; + m_statusContainer = nullptr; } + + ConnectionProvider::close(m_param); + + if(m_switchCmd) { + m_switchCmd = false; + switchCtx(); + } + return true; } +void SWIOTREFACTORPlugin::onIsRuntimeCtxChanged(bool isRuntimeCtx) +{ + m_isRuntime = isRuntimeCtx; + setupToolList(); +} + +void SWIOTREFACTORPlugin::startTutorial() +{ + if(m_isRuntime) { + qInfo(CAT_SWIOT) << "Starting SWIOT runtime tutorial."; + + // The tutorial builder is responsible for deleting itself after the tutorial is finished, so creating + // a new one each time the tutorial is started will not create memory leaks. + ToolMenuEntry *ad74413rTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, AD74413R_TME_ID); + ToolMenuEntry *max14906Tme = ToolMenuEntry::findToolMenuEntryById(m_toolList, MAX14906_TME_ID); + ToolMenuEntry *faultsTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, FAULTS_TME_ID); + + QWidget *ad74413rTool = ad74413rTme->tool(); + QWidget *max14906Tool = max14906Tme->tool(); + QWidget *faultsTool = faultsTme->tool(); + QWidget *parent = Util::findContainingWindow(ad74413rTool); + + m_ad74413rTutorial = new gui::TutorialBuilder(ad74413rTool, ":/swiotrefactor/tutorial_chapters.json", + "ad74413r", parent); + m_max14906Tutorial = new gui::TutorialBuilder(max14906Tool, ":/swiotrefactor/tutorial_chapters.json", + "max14906", parent); + m_faultsTutorial = new gui::TutorialBuilder(faultsTool, ":/swiotrefactor/tutorial_chapters.json", + "faults", parent); + + connect(m_ad74413rTutorial, &gui::TutorialBuilder::finished, this, + &SWIOTREFACTORPlugin::startMax14906Tutorial); + connect(m_max14906Tutorial, &gui::TutorialBuilder::finished, this, + &SWIOTREFACTORPlugin::startFaultsTutorial); + connect(m_ad74413rTutorial, &gui::TutorialBuilder::aborted, this, &SWIOTREFACTORPlugin::abortTutorial); + + this->startAd74413rTutorial(); + } else { + qInfo(CAT_SWIOT) << "Starting SWIOT config tutorial."; + auto configTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, CONFIG_TME_ID); + + auto configTool = configTme->tool(); + auto parent = Util::findContainingWindow(configTool); + auto tut = new gui::TutorialBuilder(configTool, ":/swiotrefactor/tutorial_chapters.json", "config", + parent); + + tut->setTitle("CONFIG"); + requestTool(configTme->id()); + tut->start(); + } +} + +void SWIOTREFACTORPlugin::startAd74413rTutorial() +{ + qInfo(CAT_SWIOT) << "Starting ad74413r tutorial."; + ToolMenuEntry *ad74413rTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, AD74413R_TME_ID); + this->requestTool(ad74413rTme->id()); + m_ad74413rTutorial->setTitle("AD74413R"); + m_ad74413rTutorial->start(); +} + +void SWIOTREFACTORPlugin::startMax14906Tutorial() +{ + qInfo(CAT_SWIOT) << "Starting max14906 tutorial."; + ToolMenuEntry *max14906Tme = ToolMenuEntry::findToolMenuEntryById(m_toolList, MAX14906_TME_ID); + this->requestTool(max14906Tme->id()); + m_max14906Tutorial->setTitle("MAX14906"); + m_max14906Tutorial->start(); +} + +void SWIOTREFACTORPlugin::startFaultsTutorial() +{ + qInfo(CAT_SWIOT) << "Starting faults tutorial."; + ToolMenuEntry *faultsTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, FAULTS_TME_ID); + this->requestTool(faultsTme->id()); + m_faultsTutorial->setTitle("FAULTS"); + m_faultsTutorial->start(); +} + +void SWIOTREFACTORPlugin::powerSupplyStatus(bool ps) +{ + if(!ps) { + if(!m_statusContainer) { + createStatusContainer(); + StatusBarManager::pushWidget(m_statusContainer, "ExtPsuStatus"); + } + } else { + if(m_statusContainer) { + delete m_statusContainer; + m_statusContainer = nullptr; + } + } +} + +void SWIOTREFACTORPlugin::setCtxMode(QString mode) +{ + m_ctxMode = mode; + m_switchCmd = true; + Q_EMIT disconnectDevice(); +} + +void SWIOTREFACTORPlugin::onModeAttributeChanged(QString mode) +{ + if(m_ctxMode.contains(mode)) { + m_swiotController->disconnectSwiot(); + Q_EMIT connectDevice(); + } +} + +void SWIOTREFACTORPlugin::switchCtx() +{ + m_swiotController->connectSwiot(); + m_swiotController->writeModeAttribute(m_ctxMode); +} + +void SWIOTREFACTORPlugin::createStatusContainer() +{ + m_statusContainer = new QWidget(); + m_statusContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_statusContainer->setLayout(new QHBoxLayout(m_statusContainer)); + m_statusContainer->layout()->setSpacing(0); + m_statusContainer->layout()->setContentsMargins(0, 0, 0, 0); + + auto exclamationIcon = new QPushButton(m_statusContainer); + StyleHelper::NoBackgroundIconButton(exclamationIcon, QIcon::fromTheme(":/swiotrefactor/warning.svg")); + + auto statusLabel = new QLabel("AD-SWIOT1L-SL: The system is powered at limited capacity."); + statusLabel->setWordWrap(true); + StyleHelper::WarningLabel(statusLabel, "extPsuStatusLabel"); + + m_statusContainer->layout()->addWidget(exclamationIcon); + m_statusContainer->layout()->addWidget(statusLabel); +} + +void SWIOTREFACTORPlugin::setupToolList() +{ + m_infoPage->enableTemperatureReadBtn(m_isRuntime); + m_swiotController->startTemperatureTask(); + + auto configTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, CONFIG_TME_ID); + auto ad74413rTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, AD74413R_TME_ID); + auto max14906Tme = ToolMenuEntry::findToolMenuEntryById(m_toolList, MAX14906_TME_ID); + auto faultsTme = ToolMenuEntry::findToolMenuEntryById(m_toolList, FAULTS_TME_ID); + + for(ToolMenuEntry *tme : qAsConst(m_toolList)) { + tme->setEnabled(true); + tme->setVisible(true); + if(!m_isRuntime) { + if(tme->id().compare(CONFIG_TME_ID)) { + tme->setVisible(false); + } + } else { + if(tme->id().compare(CONFIG_TME_ID)) { + tme->setRunBtnVisible(true); + tme->setRunning(false); + } else { + tme->setVisible(false); + } + } + } + + if(m_isRuntime) { + ad74413rTme->setTool(new swiotrefactor::Ad74413r(m_param, ad74413rTme)); + max14906Tme->setTool(new swiotrefactor::Max14906(m_param, max14906Tme)); + faultsTme->setTool(new swiotrefactor::Faults(m_param, faultsTme)); + } else { + configTme->setTool(new swiotrefactor::SwiotConfig(m_param)); + } + + connect(dynamic_cast(configTme->tool()), &SwiotConfig::writeModeAttribute, this, + &SWIOTREFACTORPlugin::setCtxMode); + + connect(dynamic_cast(ad74413rTme->tool()), &Ad74413r::configBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + connect(dynamic_cast(max14906Tme->tool()), &Max14906::configBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + connect(dynamic_cast(faultsTme->tool()), &Faults::backBtnPressed, m_runtime, + &SwiotRuntime::onBackBtnPressed); + + connect(m_swiotController, &SwiotController::pingFailed, this, &SWIOTREFACTORPlugin::disconnectDevice); + + if(!m_isRuntime) { + requestTool(configTme->id()); + } else { + requestTool(ad74413rTme->id()); + } +} + +void SWIOTREFACTORPlugin::abortTutorial() +{ + disconnect(m_ad74413rTutorial, &gui::TutorialBuilder::finished, this, + &SWIOTREFACTORPlugin::startMax14906Tutorial); + disconnect(m_max14906Tutorial, &gui::TutorialBuilder::finished, this, + &SWIOTREFACTORPlugin::startFaultsTutorial); +} + +QString SWIOTREFACTORPlugin::description() { return "Adds functionality specific to SWIOT1L board"; } + void SWIOTREFACTORPlugin::initMetadata() { loadMetadata( @@ -112,7 +431,8 @@ void SWIOTREFACTORPlugin::initMetadata() "category":[ "iio" ], - "exclude":[""] + "exclude":["*", "!debuggerplugin"], + "include-forced":["regmapplugin"] } )plugin"); } diff --git a/plugins/swiotrefactor/src/swiotruntime.cpp b/plugins/swiotrefactor/src/swiotruntime.cpp new file mode 100644 index 0000000000..52b6abaf8d --- /dev/null +++ b/plugins/swiotrefactor/src/swiotruntime.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Analog Devices Inc. + * + * This file is part of Scopy + * (see https://www.github.com/analogdevicesinc/scopy). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "swiotruntime.h" + +#include "swiot_logging_categories.h" +#include +#include +#include + +using namespace scopy::swiotrefactor; + +SwiotRuntime::SwiotRuntime(QString uri, QObject *parent) + : QObject(parent) + , m_uri(uri) +{ + Connection *conn = ConnectionProvider::open(m_uri); + m_iioCtx = conn->context(); + m_cmdQueue = conn->commandQueue(); + createDevicesMap(); +} + +SwiotRuntime::~SwiotRuntime() { ConnectionProvider::close(m_uri); } + +void SwiotRuntime::onIsRuntimeCtxChanged(bool isRuntimeCtx) +{ + if(isRuntimeCtx) { + writeTriggerDevice(); + } +} + +void SwiotRuntime::writeTriggerDevice() +{ + if(m_iioDevices.contains(AD_TRIGGER_NAME)) { + Command *setTriggerCommand = + new IioDeviceSetTrigger(m_iioDevices[AD_NAME], m_iioDevices[AD_TRIGGER_NAME], nullptr); + connect(setTriggerCommand, &scopy::Command::finished, this, &SwiotRuntime::setTriggerCommandFinished, + Qt::QueuedConnection); + m_cmdQueue->enqueue(setTriggerCommand); + } else { + qDebug(CAT_SWIOT) << "Isn't runtime context"; + } +} + +void SwiotRuntime::setTriggerCommandFinished(scopy::Command *cmd) +{ + IioDeviceSetTrigger *tcmd = dynamic_cast(cmd); + if(!tcmd) { + return; + } + if(tcmd->getReturnCode() >= 0) { + qDebug(CAT_SWIOT) << "Trigger has been set: " + QString::number(tcmd->getReturnCode()); + } else { + qDebug(CAT_SWIOT) << "Can't set trigger, not in runtime context"; + } +} + +void SwiotRuntime::createDevicesMap() +{ + if(m_iioCtx) { + int devicesNumber = iio_context_get_devices_count(m_iioCtx); + m_iioDevices.clear(); + for(int i = 0; i < devicesNumber; i++) { + struct iio_device *iioDev = iio_context_get_device(m_iioCtx, i); + if(iioDev) { + QString deviceName = QString(iio_device_get_name(iioDev)); + m_iioDevices[deviceName] = iioDev; + } + } + } +} + +void SwiotRuntime::onBackBtnPressed() { Q_EMIT writeModeAttribute("config"); } From 86b4ec37573116e441b0ac9c30f04eddf25fc2f0 Mon Sep 17 00:00:00 2001 From: "andrei.danila" Date: Mon, 29 Apr 2024 12:48:37 +0300 Subject: [PATCH 2/3] plugins/swiotrefactor/tutorial: Removed Max general_settings chapter. Signed-off-by: andrei.danila --- plugins/swiotrefactor/res/tutorial_chapters.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/plugins/swiotrefactor/res/tutorial_chapters.json b/plugins/swiotrefactor/res/tutorial_chapters.json index 26072a12dc..aa0b8136fa 100644 --- a/plugins/swiotrefactor/res/tutorial_chapters.json +++ b/plugins/swiotrefactor/res/tutorial_chapters.json @@ -60,14 +60,6 @@ }, { "index": 2, - "names": ["GENERAL_SETTINGS"], - "description": "The general settings tab displays settings that influence all channels. (e.g. The Timespan)", - "anchor": "HP_LEFT", - "content": "HP_LEFT", - "x_offset": -10 - }, - { - "index": 3, "names": ["RUN_BUTTON"], "description": "When pressed, the run button starts polling from all channels every second. The values will be plotted in the plot section of each channel.", "anchor": "HP_BOTTOM", @@ -75,7 +67,7 @@ "y_offset": 10 }, { - "index": 4, + "index": 3, "names": ["CONFIG_BUTTON"], "description": "The config button switches the board to config mode, this will allow setting a different configuration.", "anchor": "HP_BOTTOM", From 98dff7772c203193aa2698284cfb248251efde6a Mon Sep 17 00:00:00 2001 From: "andrei.danila" Date: Mon, 29 Apr 2024 16:20:43 +0300 Subject: [PATCH 3/3] swiotrefactor/faults: Fixed index out of range bug. Signed-off-by: andrei.danila --- .../swiotrefactor/include/swiotrefactor/faults/faultsdevice.h | 2 +- plugins/swiotrefactor/src/faults/faultsdevice.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/swiotrefactor/include/swiotrefactor/faults/faultsdevice.h b/plugins/swiotrefactor/include/swiotrefactor/faults/faultsdevice.h index 6e43858418..9ec0ee0b03 100644 --- a/plugins/swiotrefactor/include/swiotrefactor/faults/faultsdevice.h +++ b/plugins/swiotrefactor/include/swiotrefactor/faults/faultsdevice.h @@ -89,7 +89,7 @@ private Q_SLOTS: uint32_t m_faultNumeric = 0; QVector m_registers; - QVector m_registerValues; + QMap m_registerValues; QVector m_deviceConfigCmds; QVector m_functionConfigCmds; }; diff --git a/plugins/swiotrefactor/src/faults/faultsdevice.cpp b/plugins/swiotrefactor/src/faults/faultsdevice.cpp index 3f2de1a753..d8fed1cebc 100644 --- a/plugins/swiotrefactor/src/faults/faultsdevice.cpp +++ b/plugins/swiotrefactor/src/faults/faultsdevice.cpp @@ -167,7 +167,7 @@ void FaultsDevice::onFaultRegisterRead(int iReg, uint32_t value) if(m_registerValues.size() == m_registers.size()) { uint32_t faultRegisterValue = 0; for(int i = 0; i < m_registerValues.size(); i++) { - faultRegisterValue |= (m_registerValues.at(i) << (i * 8)); + faultRegisterValue |= (m_registerValues[i] << (i * 8)); } m_faultNumeric = faultRegisterValue; Q_EMIT faultNumericUpdated();