diff --git a/core/include/core/browsemenu.h b/core/include/core/browsemenu.h index 03da7910e2..1c4eba42c3 100644 --- a/core/include/core/browsemenu.h +++ b/core/include/core/browsemenu.h @@ -55,6 +55,7 @@ class SCOPY_CORE_EXPORT BrowseMenu : public QWidget private: void add(QWidget *w, QString name, MenuAlignment position); void toggleCollapsed(); + void hideBtnText(QPushButton *btn, QString name, bool hide); QPushButton *createBtn(QString name, QString iconPath, QWidget *parent = nullptr); QFrame *createHLine(QWidget *parent = nullptr); QWidget *createHeader(QWidget *parent = nullptr); diff --git a/core/include/core/device.h b/core/include/core/device.h index 9dd382241f..3dac1b9bf7 100644 --- a/core/include/core/device.h +++ b/core/include/core/device.h @@ -48,8 +48,10 @@ class SCOPY_CORE_EXPORT Device virtual QString param() = 0; virtual QString displayParam() = 0; virtual QWidget *icon() = 0; + virtual QPixmap iconPixmap() = 0; virtual QWidget *page() = 0; + virtual QWidget *configPage() = 0; virtual QList toolList() = 0; virtual void init() = 0; diff --git a/core/include/core/devicebrowser.h b/core/include/core/devicebrowser.h index beac1ecc46..5a943bd615 100644 --- a/core/include/core/devicebrowser.h +++ b/core/include/core/devicebrowser.h @@ -64,6 +64,8 @@ private Q_SLOTS: void updateSelectedDeviceIdx(QString); void forwardRequestDeviceWithDirection(); + void onScrollRangeChanged(int min, int max); + private: void initBtns(); DeviceIcon *buildDeviceIcon(Device *d, QWidget *parent = nullptr); diff --git a/core/include/core/deviceimpl.h b/core/include/core/deviceimpl.h index 5b6c7b2b8b..dba938ab07 100644 --- a/core/include/core/deviceimpl.h +++ b/core/include/core/deviceimpl.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace scopy { @@ -48,7 +49,9 @@ class SCOPY_CORE_EXPORT DeviceImpl : public QObject, public Device QString category() override; QString param() override; QWidget *icon() override; + QPixmap iconPixmap() override; QWidget *page() override; + QWidget *configPage() override; QList toolList() override; virtual void init() override; virtual void preload() override; @@ -84,6 +87,7 @@ public Q_SLOTS: void loadName(); void loadIcons(); void loadPages(); + void loadConfigPage(); void loadToolList(); void loadBadges(); void setPingPlugin(Plugin *plugin); @@ -102,6 +106,7 @@ public Q_SLOTS: QString m_param; QWidget *m_icon; QWidget *m_page; + QTabWidget *m_configPage; QPushButton *connbtn, *discbtn; Plugin *m_pingPlugin = nullptr; }; diff --git a/core/include/core/scopymainwindow.h b/core/include/core/scopymainwindow.h index 5e4263e017..552a44420d 100644 --- a/core/include/core/scopymainwindow.h +++ b/core/include/core/scopymainwindow.h @@ -108,6 +108,7 @@ public Q_SLOTS: void handleScanner(); void enableScanner(); void deviceAutoconnect(); + void collapseToolMenu(bool collapse); protected: void closeEvent(QCloseEvent *event) override; diff --git a/core/include/core/toolmenuitem.h b/core/include/core/toolmenuitem.h index 2dc1a7f8ca..3930b6c5b0 100644 --- a/core/include/core/toolmenuitem.h +++ b/core/include/core/toolmenuitem.h @@ -49,13 +49,13 @@ class ToolMenuItem : public QPushButton public Q_SLOTS: void setDisabled(bool disabled); void updateItem(); + void onCollapsed(bool collapsed); protected: void enterEvent(QEvent *event); void leaveEvent(QEvent *event); private: - // QPushButton *m_toolBtn; CustomPushButton *m_toolRunBtn; QString m_uuid; diff --git a/core/include/core/toolmenumanager.h b/core/include/core/toolmenumanager.h index 930ec2983f..66cf2d98e5 100644 --- a/core/include/core/toolmenumanager.h +++ b/core/include/core/toolmenumanager.h @@ -34,6 +34,16 @@ #include "scopy-core_export.h" namespace scopy { + +typedef struct +{ + QString id; + QString name; + QString param; + QPixmap icon; + QList tools; +} DeviceInfo; + class SCOPY_CORE_EXPORT ToolMenuManager : public QObject { Q_OBJECT @@ -41,7 +51,7 @@ class SCOPY_CORE_EXPORT ToolMenuManager : public QObject ToolMenuManager(ToolStack *ts, DetachedToolWindowManager *dtm, ToolMenu *toolMenu, QObject *parent = nullptr); ~ToolMenuManager(); - void addMenuItem(QString deviceId, QString devName, QList tools, int itemIndex = -1); + void addMenuItem(DeviceInfo dInfo, int itemIndex = -1); void removeMenuItem(QString deviceId); void changeToolListContents(QString deviceId, QList tools); @@ -52,13 +62,17 @@ public Q_SLOTS: void deviceConnected(QString id); void deviceDisconnected(QString id); void onDisplayNameChanged(QString id, QString devName); + void onIioEvent(QString id, int retCode, IIOCallType type); Q_SIGNALS: void requestToolSelect(QString id); + void connState(QString id, bool isConnected); + void menuCollapsed(bool collapsed); private Q_SLOTS: void updateTool(QWidget *old); void updateToolAttached(bool oldAttach, ToolMenuItem *toolMenuItem); + void setCollapsed(bool collapse); private: void loadToolAttachedState(ToolMenuEntry *tme); @@ -68,15 +82,22 @@ private Q_SLOTS: void showTool(ToolMenuItem *toolMenuItem); void selectTool(ToolMenuItem *toolMenuItem, bool on); void setTmeAttached(ToolMenuEntry *tme); - MenuSectionCollapseWidget *createMenuSectionItem(QString deviceName, QString uri = ""); + MenuSectionCollapseWidget *createMenuSectionItem(const DeviceInfo &dInfo); ToolMenuItem *createToolMenuItem(ToolMenuEntry *tme, QWidget *parent = nullptr); + MenuCollapseHeader *getCollapseSectionHeader(MenuSectionCollapseWidget *section); + void initHeaderWidget(MenuCollapseSection::MenuHeaderWidgetType type, MenuCollapseHeader *header, + const DeviceInfo &dInfo); + void initToolMenuHeaderWidget(MenuCollapseHeader *header, const DeviceInfo &dInfo); + void initCompositeHeaderWidget(MenuCollapseHeader *header, const DeviceInfo &dInfo); + bool m_collapsed; QString m_prevItem; QStringList m_connectedDev; ToolStack *m_ts; DetachedToolWindowManager *m_dtm; ToolMenu *m_toolMenu; QMap m_itemMap; + QMap m_dInfoMap; }; } // namespace scopy diff --git a/core/src/browsemenu.cpp b/core/src/browsemenu.cpp index 576496570b..95f680e2e8 100644 --- a/core/src/browsemenu.cpp +++ b/core/src/browsemenu.cpp @@ -63,6 +63,8 @@ BrowseMenu::BrowseMenu(QWidget *parent) homeBtn->setIconSize(QSize(32, 32)); homeBtn->setStyleSheet("text-align: left"); connect(homeBtn, &QPushButton::clicked, this, [=]() { Q_EMIT requestTool("home"); }); + connect(this, &BrowseMenu::collapsed, homeBtn, + [this, homeBtn](bool collapsed) { hideBtnText(homeBtn, tr("Home"), collapsed); }); QWidget *saveLoadWidget = new QWidget(m_content); saveLoadWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); @@ -93,6 +95,8 @@ BrowseMenu::BrowseMenu(QWidget *parent) QPushButton *aboutBtn = createBtn( "About", ":/gui/icons/" + Style::getAttribute(json::theme::icon_theme_folder) + "/icons/info.svg", m_content); + aboutBtn->setIconSize( + QSize(Style::getDimension(json::global::unit_2), Style::getDimension(json::global::unit_2))); connect(aboutBtn, &QPushButton::clicked, this, [=]() { Q_EMIT requestTool("about"); }); aboutBtn->setCheckable(true); @@ -139,16 +143,26 @@ void BrowseMenu::toggleCollapsed() { m_collapsed = !m_collapsed; m_btnCollapse->setHidden(m_collapsed); - m_content->setHidden(m_collapsed); Q_EMIT collapsed(m_collapsed); } +void BrowseMenu::hideBtnText(QPushButton *btn, QString name, bool hide) +{ + if(hide) { + btn->setText(""); + } else { + btn->setText(name); + } +} + QPushButton *BrowseMenu::createBtn(QString name, QString iconPath, QWidget *parent) { QPushButton *btn = new QPushButton(parent); btn->setIcon(QIcon(iconPath)); btn->setText(tr(name.toStdString().c_str())); - Style::setStyle(btn, style::properties::button::toolButton); + Style::setStyle(btn, style::properties::button::toolButton, true); + connect(this, &BrowseMenu::collapsed, btn, + [this, btn, name](bool collapsed) { hideBtnText(btn, tr(name.toStdString().c_str()), collapsed); }); return btn; } @@ -172,7 +186,7 @@ QWidget *BrowseMenu::createHeader(QWidget *parent) Style::setStyle(btnCollapseMini, style::properties::widget::toolMenu); Style::setStyle(btnCollapseMini, style::properties::button::toolButton); btnCollapseMini->setCheckable(true); - btnCollapseMini->setFixedSize(Style::getDimension(json::global::unit_4), + btnCollapseMini->setFixedSize(Style::getDimension(json::global::unit_4_5), Style::getDimension(json::global::unit_4)); headerLay->addWidget(btnCollapseMini); @@ -190,6 +204,7 @@ QLabel *BrowseMenu::createScopyLogo(QWidget *parent) { QLabel *logo = new QLabel(m_content); Style::setStyle(logo, style::properties::widget::logo); + connect(this, &BrowseMenu::collapsed, logo, &QWidget::setHidden); return logo; } diff --git a/core/src/devicebrowser.cpp b/core/src/devicebrowser.cpp index 5ae442c989..55a8791d17 100644 --- a/core/src/devicebrowser.cpp +++ b/core/src/devicebrowser.cpp @@ -31,6 +31,7 @@ #include #include +#include #include Q_LOGGING_CATEGORY(CAT_DEVBROWSER, "DeviceBrowser") @@ -45,13 +46,19 @@ DeviceBrowser::DeviceBrowser(QWidget *parent) this->setFixedHeight(185); auto dbm = ui->wDeviceBrowserMenu; - layout = new QHBoxLayout(dbm); + layout = dynamic_cast(dbm->layout()); + + auto scrollArea = ui->scrollArea; + scrollArea->horizontalScrollBar()->setVisible(false); initBtns(); connect(ui->btnHome, SIGNAL(clicked()), this, SLOT(forwardRequestDeviceWithDirection())); connect(ui->btnAdd, SIGNAL(clicked()), this, SLOT(forwardRequestDeviceWithDirection())); connect(this, SIGNAL(requestDevice(QString, int)), this, SLOT(updateSelectedDeviceIdx(QString))); + + connect(scrollArea->horizontalScrollBar(), &QScrollBar::rangeChanged, this, + &DeviceBrowser::onScrollRangeChanged); } DeviceBrowser::~DeviceBrowser() @@ -96,13 +103,16 @@ void DeviceBrowser::addDevice(QString id, Device *d, int position) { qInfo(CAT_DEVBROWSER) << "adding device " << id; auto w = dynamic_cast(buildDeviceIcon(d, this)); + int spacerIndex = layout->indexOf(ui->hSpacer); w->setProperty(devBrowserId, id); - layout->insertWidget(position, w); bg->addButton(w); - if(position == -1) + if(position == -1) { + layout->insertWidget(spacerIndex, w); list.append(w); - else + } else { + layout->insertWidget(position, w); list.insert(position, w); + } connect(w, &QAbstractButton::clicked, this, &DeviceBrowser::forwardRequestDeviceWithDirection); } @@ -230,6 +240,20 @@ DeviceIcon *DeviceBrowser::buildDeviceIcon(Device *d, QWidget *parent) return devIcon; } +// Used to display the scrollbar when needed and to maintain its size in the scroll area when not needed. +// We chose this approach because for the Qt::ScrollBarAsNeeded policy the size of the scrollball cannot be retained +// with Util::retainWidgetSizeWhenHidden because the resizing of the scrollbar is done dynamically (withoud using the +// show/hide default functions). +void DeviceBrowser::onScrollRangeChanged(int min, int max) +{ + auto scrollArea = ui->scrollArea; + if(max > min) { + scrollArea->horizontalScrollBar()->setVisible(true); + } else { + scrollArea->horizontalScrollBar()->setVisible(false); + } +} + /* auto &&is = ui->wInfoPageStack; auto &&hc = is->getHomepageControls(); diff --git a/core/src/deviceimpl.cpp b/core/src/deviceimpl.cpp index 67d6c9d01d..91ae688654 100644 --- a/core/src/deviceimpl.cpp +++ b/core/src/deviceimpl.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ Q_LOGGING_CATEGORY(CAT_DEVICEIMPL, "Device") namespace scopy { + DeviceImpl::DeviceImpl(QString param, PluginManager *p, QString category, QObject *parent) : QObject{parent} , m_param(param) @@ -89,6 +91,7 @@ void DeviceImpl::loadPlugins() loadIcons(); loadBadges(); loadPages(); + loadConfigPage(); loadToolList(); if(m_plugins.isEmpty()) { connbtn->hide(); @@ -156,17 +159,22 @@ void DeviceImpl::loadName() void DeviceImpl::loadIcons() { m_icon = new QWidget(); + QHBoxLayout *lay = new QHBoxLayout(m_icon); m_icon->setFixedHeight(100); m_icon->setFixedWidth(100); - new QHBoxLayout(m_icon); for(auto &p : m_plugins) { if(p->loadIcon()) { - m_icon->layout()->addWidget(p->icon()); + lay->addWidget(p->icon()); return; } } - new QLabel("No PLUGIN", m_icon); + QLabel *header = new QLabel("No Plugin"); + Style::setStyle(header, style::properties::label::deviceIcon, true); + + QWidget *noPluginIcon = + DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).color("gray").headerWidget(header).build(); + lay->addWidget(noPluginIcon); } void DeviceImpl::loadPages() @@ -215,6 +223,18 @@ void DeviceImpl::loadPages() } } +void DeviceImpl::loadConfigPage() +{ + m_configPage = new QTabWidget(); + m_configPage->setTabPosition(QTabWidget::South); + + for(auto &&p : plugins()) { + if(p->loadConfigPage()) { + m_configPage->addTab(p->configPage(), p->name()); + } + } +} + void DeviceImpl::loadToolList() { for(auto &&p : m_plugins) { @@ -435,6 +455,22 @@ QString DeviceImpl::param() { return m_param; } QWidget *DeviceImpl::icon() { return m_icon; } +QPixmap DeviceImpl::iconPixmap() +{ + QPixmap pixmap; + QLayoutItem *item = m_icon->layout()->itemAt(0); + if(!item || !item->widget()) { + return pixmap; + } + QLabel *iconLabel = dynamic_cast(item->widget()); + if(iconLabel) { + pixmap = iconLabel->grab(); + } + return pixmap; +} + +QWidget *DeviceImpl::configPage() { return m_configPage; } + QWidget *DeviceImpl::page() { return m_page; } QList DeviceImpl::toolList() diff --git a/core/src/scopymainwindow.cpp b/core/src/scopymainwindow.cpp index f3c6b3f016..891e7263f5 100644 --- a/core/src/scopymainwindow.cpp +++ b/core/src/scopymainwindow.cpp @@ -96,22 +96,13 @@ ScopyMainWindow::ScopyMainWindow(QWidget *parent) auto ts = ui->wsToolStack; - //////// BrowseMenu *browseMenu = new BrowseMenu(ui->wToolBrowser); ui->wToolBrowser->layout()->addWidget(browseMenu); - connect(browseMenu, &BrowseMenu::requestTool, ts, &ToolStack::show, Qt::QueuedConnection); connect(browseMenu, SIGNAL(requestLoad()), this, SLOT(load())); connect(browseMenu, SIGNAL(requestSave()), this, SLOT(save())); - connect(browseMenu, &BrowseMenu::collapsed, this, [this](bool coll) { - if(coll) { - ui->animHolder->setAnimMin(Style::getDimension(json::global::unit_4)); - } else { - ui->animHolder->setAnimMax(230); - } - ui->animHolder->toggleMenu(!coll); - }); - //////// + connect(browseMenu, &BrowseMenu::collapsed, this, &ScopyMainWindow::collapseToolMenu); + Style::setBackgroundColor(ui->centralwidget, json::theme::background_primary); scanTask = new IIOScanTask(this); @@ -174,7 +165,6 @@ ScopyMainWindow::ScopyMainWindow(QWidget *parent) } enableScanner(); - connect(dm, &DeviceManager::deviceChangedToolList, m_toolMenuManager, &ToolMenuManager::changeToolListContents); connect(dm, SIGNAL(deviceConnected(QString, Device *)), m_toolMenuManager, SLOT(deviceConnected(QString))); connect(dm, SIGNAL(deviceDisconnected(QString, Device *)), m_toolMenuManager, @@ -183,6 +173,7 @@ ScopyMainWindow::ScopyMainWindow(QWidget *parent) connect(m_toolMenuManager, &ToolMenuManager::requestToolSelect, ts, &ToolStack::show); connect(m_toolMenuManager, &ToolMenuManager::requestToolSelect, dtm, &DetachedToolWindowManager::show); connect(hp, &ScopyHomePage::displayNameChanged, m_toolMenuManager, &ToolMenuManager::onDisplayNameChanged); + connect(browseMenu, &BrowseMenu::collapsed, m_toolMenuManager, &ToolMenuManager::menuCollapsed); connect(hp, &ScopyHomePage::newDeviceAvailable, dm, &DeviceManager::addDevice); @@ -254,6 +245,16 @@ void ScopyMainWindow::deviceAutoconnect() } } +void ScopyMainWindow::collapseToolMenu(bool collapse) +{ + if(collapse) { + ui->animHolder->setAnimMin(Style::getDimension(json::global::unit_4_5)); + } else { + ui->animHolder->setAnimMax(230); + } + ui->animHolder->toggleMenu(!collapse); +} + void ScopyMainWindow::save() { QString selectedFilter; @@ -603,14 +604,19 @@ void ScopyMainWindow::initApi() void ScopyMainWindow::addDeviceToUi(QString id, Device *d) { - m_toolMenuManager->addMenuItem(id, d->displayName(), d->toolList()); + DeviceInfo dInfo = {id, d->displayName(), d->param(), d->iconPixmap(), d->toolList()}; + m_toolMenuManager->addMenuItem(dInfo); hp->addDevice(id, d); + auto ts = ui->wsToolStack; + ts->add(id, d->configPage()); } void ScopyMainWindow::removeDeviceFromUi(QString id) { m_toolMenuManager->removeMenuItem(id); hp->removeDevice(id); + auto ts = ui->wsToolStack; + ts->remove(id); } void ScopyMainWindow::receiveVersionDocument(QJsonDocument document) diff --git a/core/src/scopypreferencespage.cpp b/core/src/scopypreferencespage.cpp index c8bf42f718..3446825320 100644 --- a/core/src/scopypreferencespage.cpp +++ b/core/src/scopypreferencespage.cpp @@ -281,6 +281,8 @@ QWidget *ScopyPreferencesPage::buildGeneralPreferencesPage() "Connect to multiple devices (EXPERIMENTAL)", generalSection)); generalSection->contentLayout()->addWidget(PreferencesHelper::addPreferenceCheckBox( p, "general_scan_for_devices", "Regularly scan for new devices", generalSection)); + generalSection->contentLayout()->addWidget(PreferencesHelper::addPreferenceCheckBox( + p, "device_menu_item", "Use detailed device header for tool menu", generalSection)); // Auto-connect m_autoConnectWidget = new MenuSectionCollapseWidget("Session devices", MenuCollapseSection::MHCW_NONE, diff --git a/core/src/toolmenuitem.cpp b/core/src/toolmenuitem.cpp index 9c46a243d1..a60222315b 100644 --- a/core/src/toolmenuitem.cpp +++ b/core/src/toolmenuitem.cpp @@ -144,6 +144,16 @@ void ToolMenuItem::updateItem() qDebug(CAT_TOOLMENUITEM) << "updating toolmenuentry for " << tme->name() << " - " << tme->uuid(); } +void ToolMenuItem::onCollapsed(bool collapsed) +{ + m_toolRunBtn->setHidden(collapsed); + if(collapsed) { + setText(""); + } else { + setText(m_name); + } +} + void ToolMenuItem::enterEvent(QEvent *event) { #ifndef __ANDROID__ diff --git a/core/src/toolmenumanager.cpp b/core/src/toolmenumanager.cpp index 3ada849ba9..63ec5ebafc 100644 --- a/core/src/toolmenumanager.cpp +++ b/core/src/toolmenumanager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include Q_LOGGING_CATEGORY(CAT_TOOLMENUMANAGER, "ToolMenuManager") using namespace scopy; @@ -37,29 +38,32 @@ ToolMenuManager::ToolMenuManager(ToolStack *ts, DetachedToolWindowManager *dtm, , m_ts(ts) , m_dtm(dtm) , m_toolMenu(toolMenu) -{} +{ + qRegisterMetaType("scopy::IIOCallType"); +} ToolMenuManager::~ToolMenuManager() {} -void ToolMenuManager::addMenuItem(QString deviceId, QString devName, QList tools, int itemIndex) +void ToolMenuManager::addMenuItem(DeviceInfo dInfo, int itemIndex) { - QString param; - if(!tools.isEmpty()) - param = tools.at(0)->param(); - MenuSectionCollapseWidget *devSection = createMenuSectionItem(devName, param); + QString id = dInfo.id; + MenuSectionCollapseWidget *devSection = createMenuSectionItem(dInfo); QButtonGroup *menuBtnGroup = m_toolMenu->btnGroup(); - for(ToolMenuEntry *tme : tools) { + for(ToolMenuEntry *tme : qAsConst(dInfo.tools)) { ToolMenuItem *toolMenuItem = createToolMenuItem(tme, devSection); devSection->add(toolMenuItem); menuBtnGroup->addButton(toolMenuItem); connect(tme, &ToolMenuEntry::updateTool, this, &ToolMenuManager::updateTool); connect(tme, &ToolMenuEntry::updateToolAttached, this, [this, toolMenuItem](bool oldAttach) { updateToolAttached(oldAttach, toolMenuItem); }); + connect(tme, &ToolMenuEntry::iioEvent, this, + [this, id](int retCode, scopy::IIOCallType type) { onIioEvent(id, retCode, type); }); Q_EMIT tme->updateToolEntry(); } - m_toolMenu->add(itemIndex, deviceId, devSection); - m_itemMap[deviceId] = devSection; - qDebug(CAT_TOOLMENUMANAGER) << "Menu item with id" << deviceId << "has been added"; + m_toolMenu->add(itemIndex, id, devSection); + m_itemMap[id] = devSection; + m_dInfoMap[id] = dInfo; + qDebug(CAT_TOOLMENUMANAGER) << "Menu item with id" << id << "has been added"; } void ToolMenuManager::removeMenuItem(QString deviceId) @@ -85,11 +89,11 @@ void ToolMenuManager::changeToolListContents(QString deviceId, QListdisconnect(this); } + m_dInfoMap[deviceId].tools = tools; MenuSectionCollapseWidget *menuItem = m_itemMap[deviceId]; - QString devName = menuItem->collapseSection()->title(); int itemIndex = m_toolMenu->indexOf(menuItem); removeMenuItem(deviceId); - addMenuItem(deviceId, devName, tools, itemIndex); + addMenuItem(m_dInfoMap[deviceId], itemIndex); showMenuItem(deviceId); } @@ -102,7 +106,6 @@ void ToolMenuManager::showMenuItem(QString id) Q_EMIT requestToolSelect(id); return; } - m_itemMap[id]->show(); m_prevItem = id; } @@ -118,6 +121,7 @@ void ToolMenuManager::deviceConnected(QString id) { m_connectedDev.append(id); showMenuItem(id); + Q_EMIT connState(id, true); } void ToolMenuManager::deviceDisconnected(QString id) @@ -126,16 +130,32 @@ void ToolMenuManager::deviceDisconnected(QString id) if(m_prevItem.compare(id) != 0) { hideMenuItem(id); } + Q_EMIT connState(id, false); } void ToolMenuManager::onDisplayNameChanged(QString id, QString devName) { m_itemMap[id]->collapseSection()->setTitle(devName); + m_dInfoMap[id].name = devName; } -void ToolMenuManager::updateTool(QWidget *old) +void ToolMenuManager::onIioEvent(QString id, int retCode, IIOCallType type) { + if(!m_itemMap.contains(id)) { + return; + } + MenuCollapseHeader *collapseHeader = getCollapseSectionHeader(m_itemMap[id]); + if(!collapseHeader) { + return; + } + ToolMenuHeaderWidget *thw = dynamic_cast(collapseHeader->headerWidget()); + if(thw) { + Q_EMIT thw->blinkLed(retCode, type); + } +} +void ToolMenuManager::updateTool(QWidget *old) +{ ToolMenuEntry *tme = dynamic_cast(QObject::sender()); Q_ASSERT(tme); QString id = tme->uuid(); @@ -203,6 +223,8 @@ void ToolMenuManager::updateToolAttached(bool oldAttach, ToolMenuItem *toolMenuI } } +void ToolMenuManager::setCollapsed(bool collapse) { m_collapsed = collapse; } + void ToolMenuManager::loadToolAttachedState(ToolMenuEntry *tme) { Preferences *p = Preferences::GetInstance(); @@ -268,31 +290,85 @@ void ToolMenuManager::setTmeAttached(ToolMenuEntry *tme) tme->setAttached(!tme->attached()); } -MenuSectionCollapseWidget *ToolMenuManager::createMenuSectionItem(QString deviceName, QString uri) +MenuSectionCollapseWidget *ToolMenuManager::createMenuSectionItem(const DeviceInfo &dInfo) { - MenuSectionCollapseWidget *section = new MenuSectionCollapseWidget( - deviceName, MenuCollapseSection::MHCW_ARROW, MenuCollapseSection::MHW_COMPOSITEWIDGET, m_toolMenu); + MenuCollapseSection::MenuHeaderWidgetType type = Preferences::get("device_menu_item").toBool() + ? MenuCollapseSection::MHW_TOOLMENUWIDGET + : MenuCollapseSection::MHW_COMPOSITEWIDGET; + MenuSectionCollapseWidget *section = + new MenuSectionCollapseWidget(dInfo.name, MenuCollapseSection::MHCW_ARROW, type, m_toolMenu); section->contentLayout()->setSpacing(0); section->menuSection()->layout()->setMargin(0); section->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - MenuCollapseHeader *collapseHeader = dynamic_cast(section->collapseSection()->header()); + MenuCollapseHeader *collapseHeader = getCollapseSectionHeader(section); if(collapseHeader) { - CompositeHeaderWidget *chw = dynamic_cast(collapseHeader->headerWidget()); - if(chw) { - chw->add(new QLabel(uri, chw)); - chw->layout()->setContentsMargins(Style::getDimension(json::global::unit_1), 0, 0, 0); - } + initHeaderWidget(type, collapseHeader, dInfo); Style::setStyle(collapseHeader, style::properties::widget::bottomBorder); + Style::setStyle(collapseHeader, style::properties::widget::deviceHeaderWidget, "idle"); } section->setCollapsed(false); section->hide(); return section; } +void ToolMenuManager::initHeaderWidget(MenuCollapseSection::MenuHeaderWidgetType type, MenuCollapseHeader *header, + const DeviceInfo &dInfo) +{ + switch(type) { + case MenuCollapseSection::MHW_TOOLMENUWIDGET: + initToolMenuHeaderWidget(header, dInfo); + break; + case MenuCollapseSection::MHW_COMPOSITEWIDGET: + initCompositeHeaderWidget(header, dInfo); + break; + default: + break; + } +} + +void ToolMenuManager::initToolMenuHeaderWidget(MenuCollapseHeader *header, const DeviceInfo &dInfo) +{ + bool isConnected = m_connectedDev.contains(dInfo.id); + ToolMenuHeaderWidget *thw = dynamic_cast(header->headerWidget()); + QButtonGroup *menuBtnGroup = m_toolMenu->btnGroup(); + if(!thw) { + return; + } + thw->setDeviceId(dInfo.id); + thw->setUri(dInfo.param); + thw->setDeviceIcon(dInfo.icon); + thw->layout()->setContentsMargins(Style::getDimension(json::global::unit_1), 0, 0, 0); + Style::setStyle(header, style::properties::widget::ledBorder, isConnected); + + menuBtnGroup->addButton(thw->deviceBtn()); + connect(thw->deviceBtn(), &QPushButton::toggled, this, [=](bool en) { + if(en) { + Style::setStyle(header, style::properties::widget::deviceHeaderWidget, "selected"); + Q_EMIT requestToolSelect(dInfo.id); + } else { + Style::setStyle(header, style::properties::widget::deviceHeaderWidget, "idle"); + } + }); + connect(this, &ToolMenuManager::connState, thw, &ToolMenuHeaderWidget::connState); +} + +void ToolMenuManager::initCompositeHeaderWidget(MenuCollapseHeader *header, const DeviceInfo &dInfo) +{ + CompositeHeaderWidget *chw = dynamic_cast(header->headerWidget()); + if(!chw) { + return; + } + chw->add(new QLabel(dInfo.param)); + chw->layout()->setContentsMargins(Style::getDimension(json::global::unit_1), 0, 0, 0); + chw->setHidden(m_collapsed); + connect(this, &ToolMenuManager::menuCollapsed, chw, &QWidget::setHidden); +} + ToolMenuItem *ToolMenuManager::createToolMenuItem(ToolMenuEntry *tme, QWidget *parent) { ToolMenuItem *toolMenuItem = new ToolMenuItem(tme->uuid(), tme->name(), tme->icon(), parent); + toolMenuItem->onCollapsed(m_collapsed); connect(toolMenuItem->getToolRunBtn(), &QPushButton::toggled, tme, &ToolMenuEntry::runToggled); connect(toolMenuItem->getToolRunBtn(), &QPushButton::clicked, tme, &ToolMenuEntry::runClicked); connect(toolMenuItem, &QPushButton::clicked, this, [=]() { Q_EMIT requestToolSelect(toolMenuItem->getId()); }); @@ -300,8 +376,14 @@ ToolMenuItem *ToolMenuManager::createToolMenuItem(ToolMenuEntry *tme, QWidget *p [this, toolMenuItem](bool on) { selectTool(toolMenuItem, on); }); connect(toolMenuItem, &ToolMenuItem::doubleclick, this, [this, tme]() { setTmeAttached(tme); }); connect(tme, &ToolMenuEntry::updateToolEntry, toolMenuItem, &ToolMenuItem::updateItem); + connect(this, &ToolMenuManager::menuCollapsed, toolMenuItem, &ToolMenuItem::onCollapsed); return toolMenuItem; } +MenuCollapseHeader *ToolMenuManager::getCollapseSectionHeader(MenuSectionCollapseWidget *section) +{ + return dynamic_cast(section->collapseSection()->header()); +} + #include "moc_toolmenumanager.cpp" diff --git a/core/ui/devicebrowser.ui b/core/ui/devicebrowser.ui index d4de72d3dc..fa61640efb 100644 --- a/core/ui/devicebrowser.ui +++ b/core/ui/devicebrowser.ui @@ -7,11 +7,11 @@ 0 0 464 - 108 + 140 - + 0 0 @@ -42,218 +42,288 @@ 0 - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 9 + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Orientation::Vertical - - 9 + + + 0 + 0 + - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - - - - :/gui/icons/home.svg - - - - - 40 - 40 - - - - true - - - false - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 9 + + + + + + + 0 + 0 + - - 9 + + + 0 + 0 + - - - - - 0 - 0 - - - - - 40 - 40 - - - - - 40 - 40 - - - - - - - - :/gui/icons/add.svg - - - - - 40 - 40 - - - - true - - - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + + + 9 + + + 9 + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + + + + :/gui/icons/home.svg + + + + + 40 + 40 + + + + true + + + false + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + QFrame::Shape::StyledPanel + + + QFrame::Shadow::Raised + + + + 9 + + + 9 + + + + + + 0 + 0 + + + + + 40 + 40 + + + + + 40 + 40 + + + + + + + + :/gui/icons/add.svg + + + + + 40 + 40 + + + + true + + + + + + + + + + Qt::Orientation::Vertical + + + + 0 + 0 + + + + + + - + - + 0 0 - - - - - - Qt::Orientation::Horizontal + + Qt::ScrollBarPolicy::ScrollBarAlwaysOff + + + Qt::ScrollBarPolicy::ScrollBarAlwaysOn + + + QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents - - - 40 - 20 - + + true - + + + + 0 + 0 + 392 + 124 + + + + + 0 + 0 + + + + + 0 + + + + + Qt::Orientation::Horizontal + + + + 0 + 0 + + + + + + + - - - 0 + + + + 0 + 0 + - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Orientation::Vertical + + + + 0 + 40 + + + + + + diff --git a/gui/include/gui/deviceiconbuilder.h b/gui/include/gui/deviceiconbuilder.h new file mode 100644 index 0000000000..6cca005487 --- /dev/null +++ b/gui/include/gui/deviceiconbuilder.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024 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 DEVICEICONBUILDER_H +#define DEVICEICONBUILDER_H + +#include "hoverwidget.h" +#include "scopy-gui_export.h" +#include +#include +#include + +namespace scopy { +class SCOPY_GUI_EXPORT DeviceIconBuilder : public QObject +{ + Q_OBJECT +public: + typedef enum + { + SQUARE, + ROUNDED_SQUARE + + } IconShape; + + DeviceIconBuilder(QObject *parent = nullptr); + ~DeviceIconBuilder(); + + /** + * @brief Builds the device icon. + * @return QWidget* + */ + QWidget *build(); + + /** + * @brief Sets the IconShape. + * @param s - Related to this shape, the corresponding svg icon will be selected. + */ + DeviceIconBuilder &shape(IconShape s); + + /** + * @brief Sets the icon bgColor. + * @param bgColor - A QString with the desired color code. + */ + DeviceIconBuilder &color(QString bgColor); + + /** + * @brief Sets the header widget and the header hover widget offset. + * @param w - Header widget. + * @param offset - The offset related to the top-center position of the icon. By default is set in the middle of + * the header section. + */ + DeviceIconBuilder &headerWidget(QWidget *w, QPoint offset = {0, 24}); + + /** + * @brief Sets the footer widget and the footer hover widget offset. + * @param w - Footer widget. + * @param offset - The offset related to the bottom-center position of the icon. By default is set in the middle + * of the footer section. + */ + DeviceIconBuilder &footerWidget(QWidget *w, QPoint offset = {0, -10}); + +private: + void createHover(QWidget *icon, QWidget *w, HoverPosition anchor, HoverPosition content, QPoint offset); + void setIconShape(QLabel *icon, QString shapePath, QList specs); + + IconShape m_shape; + QString m_bgColor; + QWidget *m_headerWidget; + QPoint m_headerOffset; + QWidget *m_footerWidget; + QPoint m_footerOffset; + + const int DEVICE_BTN_HEIGHT = 80; +}; +} // namespace scopy + +#endif // DEVICEICONBUILDER_H diff --git a/gui/include/gui/utils.h b/gui/include/gui/utils.h index f5fd5fadd1..967cec37c8 100644 --- a/gui/include/gui/utils.h +++ b/gui/include/gui/utils.h @@ -42,14 +42,23 @@ class SCOPY_GUI_EXPORT Util { public: + typedef struct + { + QString tag; + QString id; + QString attrName; + QString attrVal; + } SVGSpec; + static void retainWidgetSizeWhenHidden(QWidget *w, bool retain = true); static void setWidgetNrOfChars(QWidget *w, int minNrOfChars, int maxNrOfChars = 0); static QString loadStylesheetFromFile(const QString &path); static bool compareNatural(const std::string &a, const std::string &b); static QString doubleToQString(double value); static QWidget *findContainingWindow(QWidget *w); - static void SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, QString strattrval); + static void SetAttrRecur(QDomElement &elem, SVGSpec s); static QPixmap ChangeSVGColor(QString iconPath, QString color, float opacity); + static QPixmap ChangeSVGAttr(QString iconPath, QList list); }; #define PLOT_MENU_BAR_ENABLED diff --git a/gui/include/gui/widgets/ledbutton.h b/gui/include/gui/widgets/ledbutton.h new file mode 100644 index 0000000000..74bd07695d --- /dev/null +++ b/gui/include/gui/widgets/ledbutton.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 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 LEDBUTTON_H +#define LEDBUTTON_H + +#include +#include + +namespace scopy { +class LedButton : public QPushButton +{ + Q_OBJECT +public: + LedButton(QWidget *parent = nullptr); + ~LedButton(); + + void setLedState(bool ledState); + void ledOn(); + void ledOff(); + +private: + QTimer *m_timer; +}; +} // namespace scopy + +#endif // LEDBUTTON_H diff --git a/gui/include/gui/widgets/menucollapsesection.h b/gui/include/gui/widgets/menucollapsesection.h index 031dc8dbb2..283ca90b55 100644 --- a/gui/include/gui/widgets/menucollapsesection.h +++ b/gui/include/gui/widgets/menucollapsesection.h @@ -51,7 +51,8 @@ class SCOPY_GUI_EXPORT MenuCollapseSection : public QWidget typedef enum { MHW_BASEWIDGET, - MHW_COMPOSITEWIDGET + MHW_COMPOSITEWIDGET, + MHW_TOOLMENUWIDGET } MenuHeaderWidgetType; MenuCollapseSection(QString title, MenuCollapseSection::MenuHeaderCollapseStyle style = MHCW_ARROW, @@ -81,7 +82,6 @@ class SCOPY_GUI_EXPORT MenuCollapseHeader : public QAbstractButton MenuCollapseSection::MenuHeaderWidgetType headerType, QWidget *parent); ~MenuCollapseHeader(); QString title(); - QWidget *headerWidget() const; private: diff --git a/gui/include/gui/widgets/toolmenuheaderwidget.h b/gui/include/gui/widgets/toolmenuheaderwidget.h new file mode 100644 index 0000000000..ec5a7b4ad6 --- /dev/null +++ b/gui/include/gui/widgets/toolmenuheaderwidget.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 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 TOOLMENUHEADERWIDGET_H +#define TOOLMENUHEADERWIDGET_H + +#include "iioutil/iioeventemitter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace scopy { +class SCOPY_GUI_EXPORT ToolMenuHeaderWidget : public QWidget, public BaseHeader +{ + Q_OBJECT +public: + typedef enum + { + SINGLE_INTERRUPT, + STREAM_RUNNING, + SINGLE_RUNNING, + IDLE + } LedState; + ToolMenuHeaderWidget(QString title, QWidget *parent); + ~ToolMenuHeaderWidget(); + + void setTitle(QString title) override; + QString title() override; + void setDeviceIcon(QPixmap icon); + void setUri(QString uri); + void setDeviceId(QString deviceId); + QPushButton *deviceBtn() const; + + void setState(QString id, bool state, QWidget *parent); + +Q_SIGNALS: + void connState(QString id, bool isConnected); + void blinkLed(int retCode, IIOCallType type); + +private Q_SLOTS: + void onBlinkLed(int retCode, IIOCallType type); + void refresh(); + void onTimeout(); + +private: + void handleSingle(bool isSuccess); + void handleStream(bool isSuccess); + + QTimer *m_refreshTimer; + QTimer *m_timer; + QString m_id; + LedButton *m_ledBtn; + QPushButton *m_deviceBtn; + QLineEdit *m_title; + QLabel *m_uriLabel; + LedState m_ledState; + + const int LED_ON_MSEC = 100; + const int WAITING_FACTOR = 10; +}; +} // namespace scopy + +#endif // TOOLMENUHEADERWIDGET_H diff --git a/gui/res/icons/circle_led.svg b/gui/res/icons/circle_led.svg new file mode 100644 index 0000000000..ce5766cc7c --- /dev/null +++ b/gui/res/icons/circle_led.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/res/icons/device-shapes/rounded_square.svg b/gui/res/icons/device-shapes/rounded_square.svg new file mode 100644 index 0000000000..d780d65c86 --- /dev/null +++ b/gui/res/icons/device-shapes/rounded_square.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/res/icons/device-shapes/square.svg b/gui/res/icons/device-shapes/square.svg new file mode 100644 index 0000000000..a766c381ff --- /dev/null +++ b/gui/res/icons/device-shapes/square.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gui/res/resources.qrc b/gui/res/resources.qrc index a571a6a331..89a0c7247f 100644 --- a/gui/res/resources.qrc +++ b/gui/res/resources.qrc @@ -169,6 +169,9 @@ icons/scopy-light/icons/search.svg Arial.ttf icons/notification_bell.svg + icons/circle_led.svg + icons/device-shapes/square.svg + icons/device-shapes/rounded_square.svg icons/scopy-default/icons/search.svg diff --git a/gui/src/deviceiconbuilder.cpp b/gui/src/deviceiconbuilder.cpp new file mode 100644 index 0000000000..b6a0332f53 --- /dev/null +++ b/gui/src/deviceiconbuilder.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 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 "deviceiconbuilder.h" + +#include +#include +#include +#include +#include + +using namespace scopy; + +DeviceIconBuilder::DeviceIconBuilder(QObject *parent) + : QObject(parent) + , m_shape(SQUARE) + , m_bgColor("") + , m_headerWidget(nullptr) + , m_footerWidget(nullptr) + , m_headerOffset({0, 0}) + , m_footerOffset({0, 0}) +{} + +DeviceIconBuilder::~DeviceIconBuilder() {} + +QWidget *DeviceIconBuilder::build() +{ + QLabel *icon = new QLabel(); + QList specs; + QString shapePath = ""; + switch(m_shape) { + case SQUARE: + specs.append({"rect", "icon-rect", "fill", m_bgColor}); + shapePath = ":/gui/icons/device-shapes/square.svg"; + break; + case ROUNDED_SQUARE: + specs.append({"use", "icon-path-color", "fill", m_bgColor}); + specs.append({"polygon", "", "fill", m_bgColor}); + shapePath = ":/gui/icons/device-shapes/rounded_square.svg"; + break; + default: + break; + } + createHover(icon, m_headerWidget, HP_TOP, HP_BOTTOM, m_headerOffset); + createHover(icon, m_footerWidget, HP_BOTTOM, HP_TOP, m_footerOffset); + setIconShape(icon, shapePath, specs); + return icon; +} + +DeviceIconBuilder &DeviceIconBuilder::shape(IconShape s) +{ + m_shape = s; + return *this; +} + +DeviceIconBuilder &DeviceIconBuilder::color(QString bgColor) +{ + m_bgColor = bgColor; + return *this; +} + +DeviceIconBuilder &DeviceIconBuilder::headerWidget(QWidget *w, QPoint offset) +{ + m_headerWidget = w; + m_headerOffset = offset; + return *this; +} + +DeviceIconBuilder &DeviceIconBuilder::footerWidget(QWidget *w, QPoint offset) +{ + m_footerWidget = w; + m_footerOffset = offset; + return *this; +} + +void DeviceIconBuilder::createHover(QWidget *icon, QWidget *w, HoverPosition anchor, HoverPosition content, + QPoint offset) +{ + if(!w) { + return; + } + HoverWidget *hover = new HoverWidget(w, icon, icon); + hover->setStyleSheet("background-color: transparent; border: 0px;"); + hover->setAnchorPos(anchor); + hover->setContentPos(content); + hover->setVisible(true); + hover->setAnchorOffset(offset); + hover->raise(); +} + +void DeviceIconBuilder::setIconShape(QLabel *icon, QString shapePath, QList specs) +{ + QPixmap pixmap(shapePath); + if(!m_bgColor.isEmpty()) { + pixmap = Util::ChangeSVGAttr(shapePath, specs); + } + pixmap = pixmap.scaledToHeight(DEVICE_BTN_HEIGHT, Qt::SmoothTransformation); + icon->setPixmap(pixmap); +} + +#include "moc_deviceiconbuilder.cpp" diff --git a/gui/src/utils.cpp b/gui/src/utils.cpp index 1aa3c63f1a..ec45afdf3c 100644 --- a/gui/src/utils.cpp +++ b/gui/src/utils.cpp @@ -168,25 +168,38 @@ void DockerUtils::configureTopBar(QDockWidget *docker) }); } -void Util::SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, QString strattrval) +void Util::SetAttrRecur(QDomElement &elem, SVGSpec s) { // if it has the tagname then overwritte desired attribute - if(elem.tagName().compare(strtagname) == 0) { - elem.setAttribute(strattr, strattrval); + if(elem.tagName().compare(s.tag) == 0) { + if(s.id.isEmpty()) { + elem.setAttribute(s.attrName, s.attrVal); + } else if(elem.attribute("id").compare(s.id) == 0) { + elem.setAttribute(s.attrName, s.attrVal); + } } + // loop all children for(int i = 0; i < elem.childNodes().count(); i++) { if(!elem.childNodes().at(i).isElement()) { continue; } QDomElement docElem = elem.childNodes().at(i).toElement(); //<-- make const "variable" - SetAttrRecur(docElem, strtagname, strattr, strattrval); + SetAttrRecur(docElem, s); } } /*QIcon*/ QPixmap Util::ChangeSVGColor(QString iconPath, QString color, float opacity) { - // open svg resource load contents to qbytearray + SVGSpec pathFill{"path", "", "fill", color}; + SVGSpec pathOpacity{"path", "", "opacity", QString::number(opacity, 'g', 2)}; + SVGSpec polygonFill{"polygon", "", "fill", color}; + QPixmap pix = ChangeSVGAttr(iconPath, {pathFill, pathOpacity, polygonFill}); + return pix; +} + +QPixmap Util::ChangeSVGAttr(QString iconPath, QList list) +{ QFile file(iconPath); if(!file.open(QIODevice::ReadOnly)) return {}; @@ -196,11 +209,9 @@ void Util::SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, doc.setContent(baData); // recurivelly change color QDomElement docElem = doc.documentElement(); //<-- make const "variable" - SetAttrRecur(docElem, "path", "fill", color); - // SetAttrRecur(docElem, "rect", "fill", color); - SetAttrRecur(docElem, "polygon", "fill", color); - SetAttrRecur(docElem, "path", "opacity", QString::number(opacity, 'g', 2)); - // create svg renderer with edited contents + for(const SVGSpec &s : list) { + SetAttrRecur(docElem, s); + } QSvgRenderer svgRenderer(doc.toByteArray()); // create pixmap target (could be a QImage) QPixmap pix(svgRenderer.defaultSize()); @@ -210,6 +221,4 @@ void Util::SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, // use renderer to render over painter which paints on pixmap svgRenderer.render(&pixPainter); return pix; - // QIcon myicon(pix); - // return myicon; } diff --git a/gui/src/widgets/ledbutton.cpp b/gui/src/widgets/ledbutton.cpp new file mode 100644 index 0000000000..e5ebbdde9f --- /dev/null +++ b/gui/src/widgets/ledbutton.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 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 "ledbutton.h" +#include "style.h" + +using namespace scopy; + +LedButton::LedButton(QWidget *parent) + : QPushButton(parent) +{ + setCheckable(true); + setVisible(false); + setAttribute(Qt::WA_TransparentForMouseEvents, true); + QIcon ledIcon; + ledIcon.addPixmap(Style::getPixmap(":/gui/icons/circle_led.svg", Style::getColor(json::global::led_success)), + QIcon::Normal, QIcon::On); + ledIcon.addPixmap(Style::getPixmap(":/gui/icons/circle_led.svg", Style::getColor(json::global::led_error)), + QIcon::Normal, QIcon::Off); + setIcon(ledIcon); + QSize size = QSize(Style::getDimension(json::global::unit_0_5), Style::getDimension(json::global::unit_0_5)); + setIconSize(size); + setFixedSize(size); + + m_timer = new QTimer(this); + connect(m_timer, &QTimer::timeout, m_timer, &QTimer::stop); +} + +LedButton::~LedButton() {} + +void LedButton::setLedState(bool ledState) { setChecked(ledState); } + +void LedButton::ledOn() { setVisible(true); } + +void LedButton::ledOff() { setVisible(false); } + +#include "moc_ledbutton.cpp" diff --git a/gui/src/widgets/menucollapsesection.cpp b/gui/src/widgets/menucollapsesection.cpp index 03630ceaf2..102d1f5829 100644 --- a/gui/src/widgets/menucollapsesection.cpp +++ b/gui/src/widgets/menucollapsesection.cpp @@ -25,6 +25,7 @@ #include #include #include +#include Q_LOGGING_CATEGORY(CAT_MENU_COLLAPSE_SECTION, "MenuCollapseSection") @@ -50,6 +51,9 @@ MenuCollapseHeader::MenuCollapseHeader(QString title, MenuCollapseSection::MenuH case MenuCollapseSection::MHW_COMPOSITEWIDGET: m_headerWidget = new CompositeHeaderWidget(title, this); break; + case scopy::MenuCollapseSection::MHW_TOOLMENUWIDGET: + m_headerWidget = new ToolMenuHeaderWidget(title, this); + break; } switch(style) { diff --git a/gui/src/widgets/toolmenuheaderwidget.cpp b/gui/src/widgets/toolmenuheaderwidget.cpp new file mode 100644 index 0000000000..ea2b27d777 --- /dev/null +++ b/gui/src/widgets/toolmenuheaderwidget.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2024 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 "toolmenuheaderwidget.h" + +#include +#include + +using namespace scopy; + +ToolMenuHeaderWidget::ToolMenuHeaderWidget(QString title, QWidget *parent) + : QWidget(parent) + , m_ledState(IDLE) +{ + QHBoxLayout *hLay = new QHBoxLayout(this); + hLay->setMargin(0); + hLay->setSpacing(10); + + QWidget *titleWidget = new QWidget(this); + QVBoxLayout *titleLay = new QVBoxLayout(titleWidget); + titleLay->setMargin(0); + titleLay->setSpacing(0); + + m_title = new QLineEdit(title, this); + m_title->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + m_title->setEnabled(false); + m_title->setReadOnly(false); + StyleHelper::MenuCollapseHeaderLineEdit(m_title, "menuCollapseLabel"); + + m_uriLabel = new QLabel(titleWidget); + titleLay->addWidget(m_title); + titleLay->addWidget(m_uriLabel); + + m_ledBtn = new LedButton(this); + m_deviceBtn = new QPushButton(this); + m_deviceBtn->setCheckable(true); + + int offset = Style::getDimension(json::global::unit_0_5) / 2; + HoverWidget *ledHover = new HoverWidget(m_ledBtn, m_deviceBtn, this); + ledHover->setStyleSheet("background-color: transparent; border: 0px;"); + ledHover->setAnchorPos(HoverPosition::HP_BOTTOMRIGHT); + ledHover->setContentPos(HoverPosition::HP_TOPLEFT); + ledHover->setVisible(true); + ledHover->setAnchorOffset({offset, offset}); + ledHover->raise(); + + hLay->addWidget(m_deviceBtn); + hLay->addWidget(titleWidget); + hLay->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + + m_refreshTimer = new QTimer(this); + m_refreshTimer->setInterval(LED_ON_MSEC * WAITING_FACTOR); + connect(m_refreshTimer, &QTimer::timeout, this, &ToolMenuHeaderWidget::refresh); + + m_timer = new QTimer(this); + m_timer->setInterval(LED_ON_MSEC); + connect(m_timer, &QTimer::timeout, this, &ToolMenuHeaderWidget::onTimeout); + + connect(this, &ToolMenuHeaderWidget::blinkLed, this, &ToolMenuHeaderWidget::onBlinkLed); + connect(this, &ToolMenuHeaderWidget::connState, this, + [this, parent](QString id, bool isConnected) { setState(id, isConnected, parent); }); +} + +ToolMenuHeaderWidget::~ToolMenuHeaderWidget() {} + +void ToolMenuHeaderWidget::setTitle(QString title) { m_title->setText(title); } + +QString ToolMenuHeaderWidget::title() { return m_title->text(); } + +void ToolMenuHeaderWidget::setDeviceIcon(QPixmap icon) +{ + m_deviceBtn->setIcon(QIcon(icon)); + m_deviceBtn->setIconSize( + QSize(Style::getDimension(json::global::unit_2), Style::getDimension(json::global::unit_2))); + m_deviceBtn->setFixedSize( + QSize(Style::getDimension(json::global::unit_2), Style::getDimension(json::global::unit_2))); +} + +void ToolMenuHeaderWidget::setUri(QString uri) +{ + m_uriLabel->clear(); + m_uriLabel->setText(uri); +} + +void ToolMenuHeaderWidget::setDeviceId(QString deviceId) { m_id = deviceId; } + +void ToolMenuHeaderWidget::onBlinkLed(int retCode, IIOCallType type) +{ + bool isSuccess = (retCode >= 0); + if(m_ledState == IDLE) { + m_refreshTimer->start(); + } + if(!m_refreshTimer->isActive()) { + return; + } + switch(type) { + case IIOCallType::SINGLE: + handleSingle(isSuccess); + break; + case IIOCallType::STREAM: + handleStream(isSuccess); + break; + default: + break; + } +} + +void ToolMenuHeaderWidget::handleSingle(bool isSuccess) +{ + if(m_ledState != IDLE && m_ledState != STREAM_RUNNING) { + return; + } + if(m_ledState == IDLE) { + m_ledBtn->ledOn(); + m_ledState = SINGLE_RUNNING; + } else { + m_ledBtn->ledOff(); + m_ledState = SINGLE_INTERRUPT; + } + m_ledBtn->setLedState(isSuccess); + m_timer->start(); +} + +void ToolMenuHeaderWidget::handleStream(bool isSuccess) +{ + if(m_ledState != STREAM_RUNNING && m_ledState != IDLE) { + return; + } + m_ledState = STREAM_RUNNING; + m_ledBtn->setLedState(isSuccess); + m_ledBtn->ledOn(); + m_timer->start(); +} + +void ToolMenuHeaderWidget::onTimeout() +{ + switch(m_ledState) { + case SINGLE_INTERRUPT: + m_ledBtn->ledOn(); + m_ledState = SINGLE_RUNNING; + break; + case IDLE: + m_ledBtn->ledOff(); + m_timer->stop(); + break; + default: + m_ledState = IDLE; + break; + } +} + +void ToolMenuHeaderWidget::refresh() +{ + m_refreshTimer->stop(); + m_ledBtn->ledOff(); + m_timer->start(); +} + +QPushButton *ToolMenuHeaderWidget::deviceBtn() const { return m_deviceBtn; } + +void ToolMenuHeaderWidget::setState(QString id, bool state, QWidget *parent) +{ + if(m_id == id) { + Style::setStyle(parent, style::properties::widget::ledBorder, state); + } +} + +#include "moc_toolmenuheaderwidget.cpp" diff --git a/gui/style/json/global.json b/gui/style/json/global.json index 2eac1689d2..43df67f038 100644 --- a/gui/style/json/global.json +++ b/gui/style/json/global.json @@ -11,6 +11,7 @@ "unit_2_5": "32", "unit_3": "36", "unit_4": "48", +"unit_4_5": "54", "unit_5": "80", "unit_6": "128", "radius_interactive": "4", @@ -20,6 +21,7 @@ "padding_2": "12", "padding_interactive": "5", "border_width": "1", +"border_width_2": "4", "border_width_interactive": "1", "ch0": "#E76423", "ch1": "#B16EE0", @@ -31,5 +33,7 @@ "ch7": "#c7c10a", "white": "#FFFFFF", "black": "#000000", +"led_success": "#2E9E6F", +"led_error": "#F64C5A", "run_button_color": "&interactive_primary_idle&" } diff --git a/gui/style/qss/properties/label/deviceIcon.qss b/gui/style/qss/properties/label/deviceIcon.qss new file mode 100644 index 0000000000..8bd6b76e2d --- /dev/null +++ b/gui/style/qss/properties/label/deviceIcon.qss @@ -0,0 +1,8 @@ +QLabel[&&property&&=true] { + color: white; + font-weight: bold; + font-size: &font_size_0_5&; +} +QLabel[&&property&&=true]:disabled { + color: grey; +} diff --git a/gui/style/qss/properties/widget/deviceHeaderWidget.qss b/gui/style/qss/properties/widget/deviceHeaderWidget.qss new file mode 100644 index 0000000000..da4ce75064 --- /dev/null +++ b/gui/style/qss/properties/widget/deviceHeaderWidget.qss @@ -0,0 +1,14 @@ +QWidget[&&property&&="idle"] { + background-color: transparent; + color: &content_default&; +} + +QWidget[&&property&&="idle"]:hover { + background-color: &content_silent&; + color: &content_default&; +} + +QWidget[&&property&&="selected"] { + background-color: &interactive_subtle_disabled&; + color: &content_default&; +} diff --git a/gui/style/qss/properties/widget/ledBorder.qss b/gui/style/qss/properties/widget/ledBorder.qss new file mode 100644 index 0000000000..8a4c6ea510 --- /dev/null +++ b/gui/style/qss/properties/widget/ledBorder.qss @@ -0,0 +1,9 @@ +QWidget[&&property&&=false] { + border-left: &border_width_2& solid transparent; + border-radius: 0; +} + +QWidget[&&property&&=true] { + border-left: &border_width_2& solid &led_success&; + border-radius: 0; +} diff --git a/iioutil/include/iioutil/iioeventemitter.h b/iioutil/include/iioutil/iioeventemitter.h new file mode 100644 index 0000000000..2b3f846b45 --- /dev/null +++ b/iioutil/include/iioutil/iioeventemitter.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 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 IIOEVENTEMITTER_H +#define IIOEVENTEMITTER_H + +#include +namespace scopy { +const int IIO_SUCCESS = 0; +const int IIO_ERROR = -1; +typedef enum +{ + SINGLE, + STREAM +} IIOCallType; +class IIOEventEmitter +{ +public: + virtual void iioEvent(int retCode, scopy::IIOCallType type) = 0; +}; +} // namespace scopy +Q_DECLARE_METATYPE(scopy::IIOCallType); +#endif // IIOEVENTEMITTER_H diff --git a/pluginbase/include/pluginbase/plugin.h b/pluginbase/include/pluginbase/plugin.h index a1140cf115..233dbd72c9 100644 --- a/pluginbase/include/pluginbase/plugin.h +++ b/pluginbase/include/pluginbase/plugin.h @@ -190,6 +190,13 @@ class SCOPY_PLUGINBASE_EXPORT Plugin * Default implementation in PluginBase - can be overriden */ virtual bool loadPage() = 0; + /** + * @brief loadConfigPage + * is called postcompatible. initialize m_configPage widget. This widget is added to the device configpage + * @return bool if page is loaded + * Default implementation in PluginBase - can be overriden + */ + virtual bool loadConfigPage() = 0; /** * @brief loadToolList * is called postcompatible. initialize m_toolList. m_toolList is used to populate tool menu @@ -289,6 +296,13 @@ class SCOPY_PLUGINBASE_EXPORT Plugin */ virtual QWidget *page() = 0; + /** + * @brief configPage + * @return plugin m_configPage getter - plugin configpage widget. used to create device configpage + * Default implementation in PluginBase - override not recommended + */ + virtual QWidget *configPage() = 0; + /** * @brief preferencesPage * @return plugin m_preferencesPage getter - preferences widget diff --git a/pluginbase/include/pluginbase/pluginbase.h b/pluginbase/include/pluginbase/pluginbase.h index e7149a4fc1..ee71e07299 100644 --- a/pluginbase/include/pluginbase/pluginbase.h +++ b/pluginbase/include/pluginbase/pluginbase.h @@ -51,6 +51,7 @@ class SCOPY_PLUGINBASE_EXPORT PluginBase : public Plugin virtual bool loadIcon() override; virtual bool loadPage() override; + virtual bool loadConfigPage() override; virtual void loadToolList() override; virtual bool loadPreferencesPage() override; virtual bool loadExtraButtons() override; @@ -67,6 +68,7 @@ class SCOPY_PLUGINBASE_EXPORT PluginBase : public Plugin virtual QString displayParam() override; virtual QWidget *icon() override; virtual QWidget *page() override; + virtual QWidget *configPage() override; virtual QWidget *preferencesPage() override; virtual QList extraButtons() override; virtual QList toolList() override; @@ -97,6 +99,7 @@ public Q_SLOTS: QString m_displayName; QString m_displayParam; QWidget *m_page; + QWidget *m_configPage; QWidget *m_preferencesPage; QWidget *m_icon; QList m_toolList; diff --git a/pluginbase/include/pluginbase/toolmenuentry.h b/pluginbase/include/pluginbase/toolmenuentry.h index e83a97a164..6fd17e34f6 100644 --- a/pluginbase/include/pluginbase/toolmenuentry.h +++ b/pluginbase/include/pluginbase/toolmenuentry.h @@ -22,6 +22,7 @@ #ifndef TOOLMENUENTRY_H #define TOOLMENUENTRY_H +#include "iioutil/iioeventemitter.h" #include "scopy-pluginbase_export.h" #include @@ -186,6 +187,12 @@ public Q_SLOTS: */ void runClicked(bool); + /** + * @brief iioEvent + * The signal must be emitted whenever an iio command is executed + */ + void iioEvent(int retCode, scopy::IIOCallType type); + private: QString m_id; QString m_uuid; diff --git a/pluginbase/src/pluginbase.cpp b/pluginbase/src/pluginbase.cpp index bacdf0c29d..5d49e0dfb1 100644 --- a/pluginbase/src/pluginbase.cpp +++ b/pluginbase/src/pluginbase.cpp @@ -56,6 +56,12 @@ bool PluginBase::loadPage() return false; } +bool PluginBase::loadConfigPage() +{ + m_configPage = nullptr; + return false; +} + void PluginBase::loadToolList() {} bool PluginBase::loadPreferencesPage() @@ -94,8 +100,11 @@ QString PluginBase::displayName() { return m_displayName; } QString PluginBase::displayParam() { return m_displayParam; } QWidget *PluginBase::icon() { return m_icon; } + QWidget *PluginBase::page() { return m_page; } +QWidget *PluginBase::configPage() { return m_configPage; } + QWidget *PluginBase::preferencesPage() { return m_preferencesPage; } QList PluginBase::extraButtons() { return m_extraButtons; } diff --git a/plugins/adc/src/adcfftinstrumentcontroller.cpp b/plugins/adc/src/adcfftinstrumentcontroller.cpp index 7fd56adaae..d10d02eb35 100644 --- a/plugins/adc/src/adcfftinstrumentcontroller.cpp +++ b/plugins/adc/src/adcfftinstrumentcontroller.cpp @@ -122,13 +122,13 @@ void ADCFFTInstrumentController::createIIODevice(AcqTreeNode *node) { GRIIODeviceSourceNode *griiodsn = dynamic_cast(node); GRDeviceComponent *d = new GRDeviceComponent(griiodsn); - addComponent(d); m_ui->addDevice(d->ctrl(), d); m_acqNodeComponentMap[griiodsn] = (d); m_fftPlotSettingsComponent->addSampleRateProvider(d); addComponent(d); + connect(d, &GRDeviceComponent::iioEvent, this, &ADCInstrumentController::iioEvent); connect(m_fftPlotSettingsComponent, &FFTPlotManagerSettings::samplingInfoChanged, this, [=](SamplingInfo p) { d->setBufferSize(p.bufferSize); }); } @@ -141,6 +141,7 @@ void ADCFFTInstrumentController::createIIOFloatChannel(AcqTreeNode *node) GRFFTChannelComponent *c = new GRFFTChannelComponent(griiofcn, dynamic_cast(m_plotComponentManager->plot(0)), grtsc, chIdP->pen(idx), m_ui->rightStack); + connect(c, &GRFFTChannelComponent::iioEvent, this, &ADCInstrumentController::iioEvent); Q_ASSERT(grtsc); m_plotComponentManager->addChannel(c); @@ -164,6 +165,7 @@ void ADCFFTInstrumentController::createIIOFloatChannel(AcqTreeNode *node) m_ui->addChannel(c->ctrl(), c, cw); + connect(dc, &GRDeviceComponent::iioEvent, this, &ADCInstrumentController::iioEvent); connect(c->ctrl(), &QAbstractButton::clicked, this, [=]() { m_plotComponentManager->selectChannel(c); }); grtsc->addChannel(c); // For matching Sink To Channels @@ -228,6 +230,7 @@ void ADCFFTInstrumentController::createIIOComplexChannel(AcqTreeNode *node_I, Ac m_ui->addChannel(c->ctrl(), c, cw); + connect(dc, &GRDeviceComponent::iioEvent, this, &ADCInstrumentController::iioEvent); connect(c->ctrl(), &QAbstractButton::clicked, this, [=]() { m_plotComponentManager->selectChannel(c); }); grtsc->addChannel(c); // For matching Sink To Channels diff --git a/plugins/adc/src/adcinstrumentcontroller.cpp b/plugins/adc/src/adcinstrumentcontroller.cpp index 7399e8cd34..cade0ec89b 100644 --- a/plugins/adc/src/adcinstrumentcontroller.cpp +++ b/plugins/adc/src/adcinstrumentcontroller.cpp @@ -57,10 +57,12 @@ ADCInstrumentController::ADCInstrumentController(ToolMenuEntry *tme, QString uri update(); if(m_refreshTimerRunning) m_plotTimer->start(); + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); }, Qt::QueuedConnection); m_ui = new ADCInstrument(tme, nullptr); + connect(this, &ADCInstrumentController::iioEvent, m_tme, &ToolMenuEntry::iioEvent); } ADCInstrumentController::~ADCInstrumentController() {} @@ -110,6 +112,7 @@ void ADCInstrumentController::start() ResourceManager::open("adc" + m_uri, this); bool ret = m_dataProvider->start(); if(!ret) { + Q_EMIT iioEvent(IIO_ERROR); Q_EMIT requestDisconnect(); } } diff --git a/plugins/adc/src/adcinstrumentcontroller.h b/plugins/adc/src/adcinstrumentcontroller.h index 538d187aa9..7a21e64345 100644 --- a/plugins/adc/src/adcinstrumentcontroller.h +++ b/plugins/adc/src/adcinstrumentcontroller.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "adcacquisitionmanager.h" namespace scopy { @@ -43,7 +44,8 @@ class ADCInstrument; class SCOPY_ADC_EXPORT ADCInstrumentController : public QObject, public AcqNodeChannelAware, public MetaComponent, - public ResourceUser + public ResourceUser, + public IIOEventEmitter { Q_OBJECT public: @@ -71,6 +73,9 @@ public Q_SLOTS: virtual void start(); virtual void stop() override; +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + protected Q_SLOTS: virtual void stopUpdates(); virtual void startUpdates(); diff --git a/plugins/adc/src/adcplugin.cpp b/plugins/adc/src/adcplugin.cpp index c6ae0b4ba7..7c074dc897 100644 --- a/plugins/adc/src/adcplugin.cpp +++ b/plugins/adc/src/adcplugin.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include "adctimeinstrumentcontroller.h" #include "adcfftinstrumentcontroller.h" @@ -145,8 +146,16 @@ bool ADCPlugin::loadPreferencesPage() bool ADCPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/gui/icons/" + Style::getAttribute(json::theme::icon_theme_folder) + - "/icons/tool_oscilloscope.svg"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("ADC"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } diff --git a/plugins/adc/src/adctimeinstrumentcontroller.cpp b/plugins/adc/src/adctimeinstrumentcontroller.cpp index 52d5644635..ecc1529db1 100644 --- a/plugins/adc/src/adctimeinstrumentcontroller.cpp +++ b/plugins/adc/src/adctimeinstrumentcontroller.cpp @@ -167,6 +167,7 @@ void ADCTimeInstrumentController::createIIODevice(AcqTreeNode *node) m_timePlotSettingsComponent->addSampleRateProvider(d); addComponent(d); + connect(d, &GRDeviceComponent::iioEvent, this, &ADCInstrumentController::iioEvent); connect(m_timePlotSettingsComponent, &TimePlotManagerSettings::bufferSizeChanged, d, &GRDeviceComponent::setBufferSize); } @@ -179,6 +180,7 @@ void ADCTimeInstrumentController::createIIOFloatChannel(AcqTreeNode *node) GRTimeChannelComponent *c = new GRTimeChannelComponent(griiofcn, dynamic_cast(m_plotComponentManager->plot(0)), grtsc, chIdP->pen(idx), m_ui->rightStack); + connect(c, &GRTimeChannelComponent::iioEvent, this, &ADCInstrumentController::iioEvent); Q_ASSERT(grtsc); m_plotComponentManager->addChannel(c); @@ -215,6 +217,7 @@ void ADCTimeInstrumentController::createIIOFloatChannel(AcqTreeNode *node) m_defaultCh = c; m_plotComponentManager->selectChannel(c); } + connect(dc, &GRDeviceComponent::iioEvent, this, &ADCInstrumentController::iioEvent); } void ADCTimeInstrumentController::createImportFloatChannel(AcqTreeNode *node) diff --git a/plugins/adc/src/freq/grfftchannelcomponent.cpp b/plugins/adc/src/freq/grfftchannelcomponent.cpp index df2d1cc8b0..dfb51d905e 100644 --- a/plugins/adc/src/freq/grfftchannelcomponent.cpp +++ b/plugins/adc/src/freq/grfftchannelcomponent.cpp @@ -20,6 +20,7 @@ */ #include "grfftchannelcomponent.h" +#include "datastrategy/channelattrdatastrategy.h" #include #include #include @@ -286,6 +287,11 @@ QWidget *GRFFTChannelComponent::createChAttrMenu(iio_channel *ch, QString title, for(auto w : attrWidgets) { layout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } section->contentLayout()->addLayout(layout); diff --git a/plugins/adc/src/freq/grfftchannelcomponent.h b/plugins/adc/src/freq/grfftchannelcomponent.h index 1259c305b3..b147665923 100644 --- a/plugins/adc/src/freq/grfftchannelcomponent.h +++ b/plugins/adc/src/freq/grfftchannelcomponent.h @@ -40,6 +40,7 @@ #include #include #include +#include namespace scopy { namespace adc { @@ -151,7 +152,8 @@ class SCOPY_ADC_EXPORT GRFFTChannelComponent : public ChannelComponent, public GRChannel, public MeasurementProvider, public SampleRateProvider, - public FFTChannel + public FFTChannel, + public IIOEventEmitter { Q_OBJECT public: @@ -198,6 +200,7 @@ public Q_SLOTS: void powerOffsetChanged(double); void windowChanged(int); void windowCorrectionChanged(bool); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: double m_powerOffset; diff --git a/plugins/adc/src/grdevicecomponent.cpp b/plugins/adc/src/grdevicecomponent.cpp index 7ade95098b..f6e85bfb11 100644 --- a/plugins/adc/src/grdevicecomponent.cpp +++ b/plugins/adc/src/grdevicecomponent.cpp @@ -20,6 +20,7 @@ */ #include "grdevicecomponent.h" +#include "datastrategy/deviceattrdatastrategy.h" #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include using namespace scopy; using namespace scopy::adc; @@ -116,6 +118,10 @@ QWidget *GRDeviceComponent::createChCommonAttrMenu(QWidget *parent) for(auto w : attrWidgets) { layout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), &MultiDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } attr->contentLayout()->addLayout(layout); @@ -145,6 +151,11 @@ QWidget *GRDeviceComponent::createAttrMenu(QWidget *parent) for(auto w : attrWidgets) { layout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), + &DeviceAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } attr->contentLayout()->addLayout(layout); diff --git a/plugins/adc/src/grdevicecomponent.h b/plugins/adc/src/grdevicecomponent.h index 5a972970e0..276d92a691 100644 --- a/plugins/adc/src/grdevicecomponent.h +++ b/plugins/adc/src/grdevicecomponent.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -38,7 +39,10 @@ namespace scopy::adc { // class GRTimeChannelAddon; -class SCOPY_ADC_EXPORT GRDeviceComponent : public QWidget, public ToolComponent, public SampleRateProvider +class SCOPY_ADC_EXPORT GRDeviceComponent : public QWidget, + public ToolComponent, + public SampleRateProvider, + public IIOEventEmitter { Q_OBJECT public: @@ -61,6 +65,9 @@ public Q_SLOTS: void removeChannel(ChannelComponent *c); void addChannel(ChannelComponent *c); +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private: QString name; QWidget *widget; diff --git a/plugins/adc/src/time/grtimechannelcomponent.cpp b/plugins/adc/src/time/grtimechannelcomponent.cpp index 81c008a646..c2df3f697f 100644 --- a/plugins/adc/src/time/grtimechannelcomponent.cpp +++ b/plugins/adc/src/time/grtimechannelcomponent.cpp @@ -20,6 +20,7 @@ */ #include "grtimechannelcomponent.h" +#include "datastrategy/channelattrdatastrategy.h" #include #include #include @@ -95,6 +96,11 @@ QWidget *GRTimeChannelComponent::createYAxisMenu(QWidget *parent) .channel(m_src->channel()) .attribute(m_src->scaleAttribute()) .buildSingle(); + connect(dynamic_cast(m_scaleWidget->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } m_yCtrl = new MenuPlotAxisRangeControl(m_timePlotComponentChannel->m_timePlotYAxis, m_yaxisMenu); @@ -210,6 +216,11 @@ QWidget *GRTimeChannelComponent::createAttrMenu(QWidget *parent) for(auto w : attrWidgets) { layout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } section->contentLayout()->addLayout(layout); diff --git a/plugins/adc/src/time/grtimechannelcomponent.h b/plugins/adc/src/time/grtimechannelcomponent.h index 025fe27bbe..adf0d1e7cb 100644 --- a/plugins/adc/src/time/grtimechannelcomponent.h +++ b/plugins/adc/src/time/grtimechannelcomponent.h @@ -35,6 +35,7 @@ #include "adcinterfaces.h" #include #include +#include #include "time/timeplotcomponent.h" namespace scopy { @@ -84,7 +85,8 @@ class SCOPY_ADC_EXPORT GRTimeChannelComponent : public ChannelComponent, public GRChannel, public MeasurementProvider, public SampleRateProvider, - public ScaleProvider + public ScaleProvider, + public IIOEventEmitter { Q_OBJECT @@ -129,6 +131,7 @@ public Q_SLOTS: Q_SIGNALS: void yModeChanged(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: GRIIOFloatChannelNode *m_node; diff --git a/plugins/dac/src/bufferdacaddon.cpp b/plugins/dac/src/bufferdacaddon.cpp index 2aa727de52..2947310fbb 100644 --- a/plugins/dac/src/bufferdacaddon.cpp +++ b/plugins/dac/src/bufferdacaddon.cpp @@ -445,6 +445,11 @@ QWidget *BufferDacAddon::createAttrMenu(TxNode *node, QWidget *parent) for(IIOWidget *w : qAsConst(attrWidgets)) { layout->addWidget(w); detectSamplingFrequency(w); + connect(dynamic_cast(w->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } attr->contentLayout()->addLayout(layout); diff --git a/plugins/dac/src/dacaddon.h b/plugins/dac/src/dacaddon.h index 2360eb544b..53cfd49cd3 100644 --- a/plugins/dac/src/dacaddon.h +++ b/plugins/dac/src/dacaddon.h @@ -22,13 +22,14 @@ #ifndef DACADDON_H_ #define DACADDON_H_ +#include "iioutil/iioeventemitter.h" #include #include #include namespace scopy { namespace dac { -class DacAddon : public QWidget +class DacAddon : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -42,6 +43,7 @@ class DacAddon : public QWidget Q_SIGNALS: void running(bool enabled); void requestChannelMenu(QString uuid); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; protected: QMap m_channelBtns; diff --git a/plugins/dac/src/dacdatamanager.cpp b/plugins/dac/src/dacdatamanager.cpp index 7014352c83..a78d1b7ddc 100644 --- a/plugins/dac/src/dacdatamanager.cpp +++ b/plugins/dac/src/dacdatamanager.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,7 @@ DacDataManager::DacDataManager(struct iio_device *dev, QWidget *parent) // Setup menu widget m_widget = createMenu(); + connect(m_model, &DacDataModel::iioEvent, this, &DacDataManager::iioEvent); } DacDataManager::~DacDataManager() {} @@ -115,6 +117,11 @@ QWidget *DacDataManager::createAttrMenu(QWidget *parent) for(auto w : attrWidgets) { layout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), + &DeviceAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } attr->contentLayout()->addLayout(layout); @@ -186,6 +193,7 @@ void DacDataManager::setupDacMode(QString mode_name, unsigned int mode) } connect(dac, &DacAddon::requestChannelMenu, this, &DacDataManager::handleChannelMenuRequest); connect(dac, &DacAddon::running, this, &DacDataManager::running); + connect(dac, &DacAddon::iioEvent, this, &DacDataManager::iioEvent); dacAddonStack->add(QString::number(mode), dac); m_mode->combo()->addItem(mode_name, mode); } diff --git a/plugins/dac/src/dacdatamanager.h b/plugins/dac/src/dacdatamanager.h index a583f49205..b5b50ed71d 100644 --- a/plugins/dac/src/dacdatamanager.h +++ b/plugins/dac/src/dacdatamanager.h @@ -22,6 +22,7 @@ #ifndef DACDATAMANAGER_H #define DACDATAMANAGER_H +#include "iioutil/iioeventemitter.h" #include #include #include @@ -39,7 +40,7 @@ namespace scopy { namespace dac { class DacDataModel; class DacAddon; -class DacDataManager : public QWidget +class DacDataManager : public QWidget, IIOEventEmitter { Q_OBJECT public: @@ -75,6 +76,7 @@ private Q_SLOTS: Q_SIGNALS: void running(bool toggled); void requestMenu(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: QVBoxLayout *m_layout; diff --git a/plugins/dac/src/dacdatamodel.cpp b/plugins/dac/src/dacdatamodel.cpp index e2519be64d..6a6eaab7a8 100644 --- a/plugins/dac/src/dacdatamodel.cpp +++ b/plugins/dac/src/dacdatamodel.cpp @@ -248,10 +248,12 @@ bool DacDataModel::validateBufferParams() auto enabledChannelsCount = getEnabledChannelsCount(); ssize_t s_size = iio_device_get_sample_size(m_dev); + if(!s_size || enabledChannelsCount == 0) { auto msg = "Unable to create buffer, no channel enabled."; qDebug(CAT_DAC_DATA) << msg; Q_EMIT log(msg); + Q_EMIT iioEvent(IIO_ERROR); return false; } @@ -259,6 +261,7 @@ bool DacDataModel::validateBufferParams() auto msg = "Unable to create buffer due to data size."; qDebug(CAT_DAC_DATA) << msg; Q_EMIT log(msg); + Q_EMIT iioEvent(IIO_ERROR); return false; } @@ -266,6 +269,7 @@ bool DacDataModel::validateBufferParams() auto msg = "Not enough data columns for all enabled channels."; qDebug(CAT_DAC_DATA) << msg; Q_EMIT log(msg); + Q_EMIT iioEvent(IIO_ERROR); return false; } @@ -273,6 +277,7 @@ bool DacDataModel::validateBufferParams() auto msg = "Unable to create buffer due to incompatible channels enabled."; qDebug(CAT_DAC_DATA) << msg; Q_EMIT log(msg); + Q_EMIT iioEvent(IIO_ERROR); return false; } @@ -289,10 +294,11 @@ bool DacDataModel::validateBufferParams() auto msg = "Unable to create buffer due to high decimation."; qDebug(CAT_DAC_DATA) << msg; Q_EMIT log(msg); + Q_EMIT iioEvent(IIO_ERROR); return false; } } - + Q_EMIT iioEvent(IIO_SUCCESS); return true; } @@ -331,6 +337,7 @@ void DacDataModel::push() QString logMsg = QString("Unable to create buffer: %1").arg(strerror(errno)); qDebug(CAT_DAC_DATA) << logMsg; Q_EMIT log(logMsg); + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -383,6 +390,7 @@ void DacDataModel::push() if(m_interrupted) { Q_EMIT log(QString("Aborting thread...")); } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } void DacDataModel::start() { initBuffer(); } @@ -419,6 +427,7 @@ bool DacDataModel::initBufferDac() QString uuid = iio_device_get_name(m_dev); uuid += ":" + id; m_bufferTxs.insert(uuid, new TxNode(uuid, chn, this)); + connect(m_bufferTxs[uuid], &TxNode::iioEvent, this, &DacDataModel::iioEvent); } } return (txCount != 0); @@ -453,6 +462,7 @@ bool DacDataModel::initDdsDac() if(!parentTxNode) { parentTxNode = new TxNode(txNameCurrent, nullptr, this); m_ddsTxs.insert(txNameCurrent, parentTxNode); + connect(parentTxNode, &TxNode::iioEvent, this, &DacDataModel::iioEvent); } if(txNodesNames.size() == 2) { QString toneName = txNodesNames.at(1); @@ -462,6 +472,7 @@ bool DacDataModel::initDdsDac() QString toneName = txNodesNames.at(2); TxNode *complexChnNode = parentTxNode->addChildNode(complexChnName, nullptr); complexChnNode->addChildNode(toneName, chn); + connect(complexChnNode, &TxNode::iioEvent, this, &DacDataModel::iioEvent); } } return (ddsTonesCount != 0); diff --git a/plugins/dac/src/dacdatamodel.h b/plugins/dac/src/dacdatamodel.h index fb64fac8b6..39457d3ae9 100644 --- a/plugins/dac/src/dacdatamodel.h +++ b/plugins/dac/src/dacdatamodel.h @@ -22,6 +22,7 @@ #ifndef DACDATAMODEL_H #define DACDATAMODEL_H +#include "iioutil/iioeventemitter.h" #include #include #include @@ -32,7 +33,7 @@ namespace scopy { namespace dac { class TxNode; -class DacDataModel : public QObject +class DacDataModel : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -67,6 +68,7 @@ class DacDataModel : public QObject void invalidRunParams(); void updateBuffersize(unsigned int bf); void updateKernelBuffers(unsigned int kb); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; public Q_SLOTS: void reset(); diff --git a/plugins/dac/src/dacinstrument.cpp b/plugins/dac/src/dacinstrument.cpp index e1ae5d4fe5..4a4932cff3 100644 --- a/plugins/dac/src/dacinstrument.cpp +++ b/plugins/dac/src/dacinstrument.cpp @@ -241,6 +241,8 @@ void DacInstrument::setupDacDataManagers() for(MenuControlButton *btn : qAsConst(menuBtns)) { devicesGroup->addButton(btn); } + + connect(dm, &DacDataManager::iioEvent, this, &DacInstrument::iioEvent); break; } } diff --git a/plugins/dac/src/dacinstrument.h b/plugins/dac/src/dacinstrument.h index 9ee604382d..3506f39481 100644 --- a/plugins/dac/src/dacinstrument.h +++ b/plugins/dac/src/dacinstrument.h @@ -21,6 +21,7 @@ #ifndef DACINSTRUMENT_H #define DACINSTRUMENT_H +#include "iioutil/iioeventemitter.h" #include "scopy-dac_export.h" #include @@ -38,7 +39,7 @@ namespace scopy { namespace dac { class DacDataManager; -class SCOPY_DAC_EXPORT DacInstrument : public QWidget +class SCOPY_DAC_EXPORT DacInstrument : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -51,6 +52,7 @@ public Q_SLOTS: void dacRunning(bool toggled); Q_SIGNALS: void running(bool toggled); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: void setupDacDataManagers(); diff --git a/plugins/dac/src/dacplugin.cpp b/plugins/dac/src/dacplugin.cpp index cf6e03f403..a178520c46 100644 --- a/plugins/dac/src/dacplugin.cpp +++ b/plugins/dac/src/dacplugin.cpp @@ -25,6 +25,7 @@ #include "dacutils.h" #include +#include #include #include @@ -79,8 +80,16 @@ bool DACPlugin::loadPage() bool DACPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/gui/icons/" + Style::getAttribute(json::theme::icon_theme_folder) + - "/icons/tool_oscilloscope.svg"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("DAC"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } @@ -116,6 +125,7 @@ bool DACPlugin::onConnect() m_toolList[0]->setTool(dac); m_toolList[0]->setEnabled(true); m_toolList[0]->setRunBtnVisible(true); + connect(dynamic_cast(dac), &DacInstrument::iioEvent, m_toolList[0], &ToolMenuEntry::iioEvent); connect(m_toolList.last(), &ToolMenuEntry::runToggled, dynamic_cast(dac), &DacInstrument::runToggled); connect(dynamic_cast(dac), &DacInstrument::running, m_toolList[0], &ToolMenuEntry::setRunning); diff --git a/plugins/dac/src/ddsdacaddon.cpp b/plugins/dac/src/ddsdacaddon.cpp index 57631c39b3..7e67948f80 100644 --- a/plugins/dac/src/ddsdacaddon.cpp +++ b/plugins/dac/src/ddsdacaddon.cpp @@ -146,6 +146,7 @@ QWidget *DdsDacAddon::setupDdsTx(TxNode *txNode) QWidget *DdsDacAddon::setupTxMode(TxNode *txNode, unsigned int mode) { TxMode *txModeWidget = new TxMode(txNode, mode, this); + connect(txModeWidget, &TxMode::iioEvent, this, &DdsDacAddon::iioEvent); return txModeWidget; } @@ -184,6 +185,7 @@ TxMode::TxMode(TxNode *node, unsigned int mode, QWidget *parent) } else { txChn->setVisible(false); } + connect(txChn, &TxChannel::iioEvent, this, &TxMode::iioEvent); } auto emitterChannel = m_txChannels.at(0); diff --git a/plugins/dac/src/ddsdacaddon.h b/plugins/dac/src/ddsdacaddon.h index d244df1c0b..a3f6494259 100644 --- a/plugins/dac/src/ddsdacaddon.h +++ b/plugins/dac/src/ddsdacaddon.h @@ -48,7 +48,7 @@ class DdsDacAddon : public DacAddon QWidget *setupTxMode(TxNode *txNode, unsigned int mode); }; -class TxMode : public QWidget +class TxMode : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -66,6 +66,9 @@ class TxMode : public QWidget void read(); void enable(bool enable); +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private: TxNode *m_node; unsigned int m_mode; diff --git a/plugins/dac/src/txchannel.cpp b/plugins/dac/src/txchannel.cpp index 681e4ddce6..cde5a2fa8c 100644 --- a/plugins/dac/src/txchannel.cpp +++ b/plugins/dac/src/txchannel.cpp @@ -120,6 +120,7 @@ TxTone *TxChannel::setupTxTone(TxNode *nodeTone, unsigned int index) { TxTone *tone = new TxTone(nodeTone, index, this); m_tones.insert(index, tone); + connect(tone, &TxTone::iioEvent, this, &TxChannel::iioEvent); return tone; } diff --git a/plugins/dac/src/txchannel.h b/plugins/dac/src/txchannel.h index 697851a4f0..6420e8a6d7 100644 --- a/plugins/dac/src/txchannel.h +++ b/plugins/dac/src/txchannel.h @@ -22,6 +22,7 @@ #ifndef TXCHANNEL_H #define TXCHANNEL_H +#include "iioutil/iioeventemitter.h" #include #include @@ -29,7 +30,7 @@ namespace scopy { namespace dac { class TxNode; class TxTone; -class TxChannel : public QWidget +class TxChannel : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -46,6 +47,8 @@ class TxChannel : public QWidget QMap getToneMenus() const; Q_SIGNALS: void resetChannelScales(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + public Q_SLOTS: void scaleUpdated(int toneIdx, QString oldScale, QString newScale); diff --git a/plugins/dac/src/txnode.cpp b/plugins/dac/src/txnode.cpp index 6a297438c5..b9a9f95bfb 100644 --- a/plugins/dac/src/txnode.cpp +++ b/plugins/dac/src/txnode.cpp @@ -75,12 +75,14 @@ bool TxNode::enableDds(bool enable) int ret = iio_channel_attr_write_bool(m_channel, "raw", enable); if(ret < 0) { qDebug(CAT_DAC_DATA) << QString("Can't enable DDS channel, error: %1").arg(ret); + Q_EMIT iioEvent(ret); return false; } qDebug(CAT_DAC_DATA) << QString("DDS channel %1 enabled: %2, ret code %3") .arg(m_txUuid) .arg(enable) .arg(ret); + Q_EMIT iioEvent(ret); } else { qDebug(CAT_DAC_DATA) << QString("%1 not a DDS channel").arg(m_txUuid); return false; diff --git a/plugins/dac/src/txnode.h b/plugins/dac/src/txnode.h index de914af139..1a7c9e8aad 100644 --- a/plugins/dac/src/txnode.h +++ b/plugins/dac/src/txnode.h @@ -22,6 +22,7 @@ #ifndef TXNODE_H #define TXNODE_H +#include "iioutil/iioeventemitter.h" #include #include #include @@ -31,7 +32,7 @@ namespace scopy { namespace dac { -class TxNode : public QObject +class TxNode : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -51,6 +52,9 @@ class TxNode : public QObject const QColor &getColor() const; void setColor(const QColor &newColor); +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private: QString m_txUuid; QMap m_childNodes = {}; diff --git a/plugins/dac/src/txtone.cpp b/plugins/dac/src/txtone.cpp index 9a98f41fb4..41dd240db7 100644 --- a/plugins/dac/src/txtone.cpp +++ b/plugins/dac/src/txtone.cpp @@ -62,6 +62,11 @@ TxTone::TxTone(TxNode *node, unsigned int idx, QWidget *parent) .buildSingle(); m_frequency->setUItoDataConversion(std::bind(&TxTone::frequencyUItoDS, this, std::placeholders::_1)); m_frequency->setDataToUIConversion(std::bind(&TxTone::frequencyDStoUI, this, std::placeholders::_1)); + connect(dynamic_cast(m_frequency->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); m_scale = IIOWidgetBuilder(this) .channel(m_node->getChannel()) @@ -71,6 +76,11 @@ TxTone::TxTone(TxNode *node, unsigned int idx, QWidget *parent) .buildSingle(); m_scale->setUItoDataConversion(std::bind(&TxTone::scaleUItoDS, std::placeholders::_1)); m_scale->setDataToUIConversion(std::bind(&TxTone::scaleDStoUI, std::placeholders::_1)); + connect(dynamic_cast(m_scale->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); m_phase = IIOWidgetBuilder(this) .channel(m_node->getChannel()) @@ -78,9 +88,13 @@ TxTone::TxTone(TxNode *node, unsigned int idx, QWidget *parent) .uiStrategy(IIOWidgetBuilder::UIS::EditableUi) .parent(this) .buildSingle(); - m_phase->setUItoDataConversion(std::bind(&TxTone::phaseUItoDS, this, std::placeholders::_1)); m_phase->setDataToUIConversion(std::bind(&TxTone::phaseDStoUI, this, std::placeholders::_1)); + connect(dynamic_cast(m_phase->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); connect(dynamic_cast(m_frequency->getDataStrategy()), &ChannelAttrDataStrategy::emitStatus, this, &TxTone::forwardFreqChange); diff --git a/plugins/dac/src/txtone.h b/plugins/dac/src/txtone.h index cdb1421153..7259a479d2 100644 --- a/plugins/dac/src/txtone.h +++ b/plugins/dac/src/txtone.h @@ -22,13 +22,14 @@ #ifndef TXTONE_H #define TXTONE_H +#include "iioutil/iioeventemitter.h" #include #include namespace scopy { namespace dac { class TxNode; -class TxTone : public QWidget +class TxTone : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -47,6 +48,7 @@ class TxTone : public QWidget void frequencyUpdated(unsigned int toneIdx, QString frequency); void scaleUpdated(unsigned int toneIdx, QString oldScale, QString scale); void phaseUpdated(unsigned int toneIdx, QString phase); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; public Q_SLOTS: void updateFrequency(QString frequency); diff --git a/plugins/datalogger/include/datalogger/dataacquisitionmanager.hpp b/plugins/datalogger/include/datalogger/dataacquisitionmanager.hpp index 1de94880e2..109997a771 100644 --- a/plugins/datalogger/include/datalogger/dataacquisitionmanager.hpp +++ b/plugins/datalogger/include/datalogger/dataacquisitionmanager.hpp @@ -26,13 +26,15 @@ #include #include +#include + #include "datamonitor/datamonitormodel.hpp" #include "scopy-datalogger_export.h" namespace scopy { namespace datamonitor { -class SCOPY_DATALOGGER_EXPORT DataAcquisitionManager : public QObject +class SCOPY_DATALOGGER_EXPORT DataAcquisitionManager : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -56,6 +58,7 @@ class SCOPY_DATALOGGER_EXPORT DataAcquisitionManager : public QObject void monitorAdded(DataMonitorModel *monitor); void monitorRemoved(QString monitorName); void deviceRemoved(QString deviceName); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: QMap *m_activeMonitorsMap; diff --git a/plugins/datalogger/include/datalogger/datamonitor/datamonitormodel.hpp b/plugins/datalogger/include/datalogger/datamonitor/datamonitormodel.hpp index 1a201cb786..fceae44fa0 100644 --- a/plugins/datalogger/include/datalogger/datamonitor/datamonitormodel.hpp +++ b/plugins/datalogger/include/datalogger/datamonitor/datamonitormodel.hpp @@ -29,10 +29,12 @@ #include #include +#include + namespace scopy { namespace datamonitor { -class SCOPY_DATALOGGER_EXPORT DataMonitorModel : public QObject +class SCOPY_DATALOGGER_EXPORT DataMonitorModel : public QObject, public IIOEventEmitter { Q_OBJECT @@ -83,6 +85,7 @@ class SCOPY_DATALOGGER_EXPORT DataMonitorModel : public QObject void minValueUpdated(double value); void maxValueUpdated(double value); void dataCleared(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; protected: void setDataStorageSize(); diff --git a/plugins/datalogger/include/datalogger/datamonitor/readabledatamonitormodel.hpp b/plugins/datalogger/include/datalogger/datamonitor/readabledatamonitormodel.hpp index 125a9f3f1f..a138aa30a0 100644 --- a/plugins/datalogger/include/datalogger/datamonitor/readabledatamonitormodel.hpp +++ b/plugins/datalogger/include/datalogger/datamonitor/readabledatamonitormodel.hpp @@ -42,8 +42,6 @@ class SCOPY_DATALOGGER_EXPORT ReadableDataMonitorModel : public DataMonitorModel void setReadStrategy(IReadStrategy *newReadStrategy); void resetMinMax(); -signals: - private: IReadStrategy *m_readStrategy; }; diff --git a/plugins/datalogger/include/datalogger/datamonitor/readstrategy/ireadstrategy.hpp b/plugins/datalogger/include/datalogger/datamonitor/readstrategy/ireadstrategy.hpp index b258d246f5..bbe5966435 100644 --- a/plugins/datalogger/include/datalogger/datamonitor/readstrategy/ireadstrategy.hpp +++ b/plugins/datalogger/include/datalogger/datamonitor/readstrategy/ireadstrategy.hpp @@ -23,11 +23,12 @@ #define IREGISTERREADSTRATEGY_HPP #include +#include #include "../../scopy-datalogger_export.h" namespace scopy { namespace datamonitor { -class SCOPY_DATALOGGER_EXPORT IReadStrategy : public QObject +class SCOPY_DATALOGGER_EXPORT IReadStrategy : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -36,6 +37,7 @@ class SCOPY_DATALOGGER_EXPORT IReadStrategy : public QObject Q_SIGNALS: void readDone(double time, double value); void readError(const char *err); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; }; } // namespace datamonitor } // namespace scopy diff --git a/plugins/datalogger/include/datalogger/datamonitortool.h b/plugins/datalogger/include/datalogger/datamonitortool.h index 8d4661cc52..a210abab9f 100644 --- a/plugins/datalogger/include/datalogger/datamonitortool.h +++ b/plugins/datalogger/include/datalogger/datamonitortool.h @@ -44,7 +44,7 @@ namespace scopy::datamonitor { class SevenSegmentDisplay; class DataMonitorSettings; -class SCOPY_DATALOGGER_EXPORT DatamonitorTool : public QWidget +class SCOPY_DATALOGGER_EXPORT DatamonitorTool : public QWidget, public IIOEventEmitter { friend class DataLogger_API; friend class DataMonitorStyleHelper; @@ -61,6 +61,7 @@ class SCOPY_DATALOGGER_EXPORT DatamonitorTool : public QWidget void runToggled(bool toggled); void settingsTitleChanged(QString newTitle); void requestDeleteTool(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: MenuControlButton *monitorsButton; diff --git a/plugins/datalogger/include/datalogger/menus/channelattributesmenu.hpp b/plugins/datalogger/include/datalogger/menus/channelattributesmenu.hpp index fb08d9596a..57ce443da1 100644 --- a/plugins/datalogger/include/datalogger/menus/channelattributesmenu.hpp +++ b/plugins/datalogger/include/datalogger/menus/channelattributesmenu.hpp @@ -29,11 +29,14 @@ namespace scopy { namespace datamonitor { -class SCOPY_DATALOGGER_EXPORT ChannelAttributesMenu : public QWidget +class SCOPY_DATALOGGER_EXPORT ChannelAttributesMenu : public QWidget, public IIOEventEmitter { Q_OBJECT public: explicit ChannelAttributesMenu(DataMonitorModel *model, QWidget *parent = nullptr); + +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; }; } // namespace datamonitor } // namespace scopy diff --git a/plugins/datalogger/src/dataloggerplugin.cpp b/plugins/datalogger/src/dataloggerplugin.cpp index e3a062660f..8f8be8ea07 100644 --- a/plugins/datalogger/src/dataloggerplugin.cpp +++ b/plugins/datalogger/src/dataloggerplugin.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -65,8 +66,16 @@ bool DataLoggerPlugin::loadPage() { return false; } bool DataLoggerPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/gui/icons/" + Style::getAttribute(json::theme::icon_theme_folder) + - "/icons/tool_datalogger.svg"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("DLOG"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } @@ -102,6 +111,8 @@ bool DataLoggerPlugin::onConnect() foreach(ReadableDataMonitorModel *monitor, dmmList) { m_dataAcquisitionManager->getDataMonitorMap()->insert(monitor->getName(), monitor); + connect(monitor, &ReadableDataMonitorModel::iioEvent, m_dataAcquisitionManager, + &DataAcquisitionManager::iioEvent); } Preferences *p = Preferences::GetInstance(); @@ -201,6 +212,9 @@ void DataLoggerPlugin::addNewTool() Q_EMIT toolListChanged(); m_toolList.last()->setTool(datamonitorTool); + connect(datamonitorTool, &DatamonitorTool::iioEvent, m_toolList.last(), &ToolMenuEntry::iioEvent); + connect(m_dataAcquisitionManager, &DataAcquisitionManager::iioEvent, m_toolList.last(), + &ToolMenuEntry::iioEvent); if(m_toolList.length() > 1) { requestTool(tool_name); } diff --git a/plugins/datalogger/src/datamonitor/dmmdatamonitormodel.cpp b/plugins/datalogger/src/datamonitor/dmmdatamonitormodel.cpp index b1fede1993..b17affc79f 100644 --- a/plugins/datalogger/src/datamonitor/dmmdatamonitormodel.cpp +++ b/plugins/datalogger/src/datamonitor/dmmdatamonitormodel.cpp @@ -50,6 +50,7 @@ DmmDataMonitorModel::DmmDataMonitorModel(QString name, QColor color, UnitOfMeasu setDataStorageSize(); setReadStrategy(readStrategy); + connect(readStrategy, &DMMReadStrategy::iioEvent, this, &DmmDataMonitorModel::iioEvent); } iio_channel *DmmDataMonitorModel::iioChannel() const { return m_iioChannel; } diff --git a/plugins/datalogger/src/datamonitor/readstrategy/dmmreadstrategy.cpp b/plugins/datalogger/src/datamonitor/readstrategy/dmmreadstrategy.cpp index b269059d15..0c8ac8e007 100644 --- a/plugins/datalogger/src/datamonitor/readstrategy/dmmreadstrategy.cpp +++ b/plugins/datalogger/src/datamonitor/readstrategy/dmmreadstrategy.cpp @@ -47,11 +47,12 @@ void DMMReadStrategy::read() char err[1024]; iio_strerror(-(int)readRaw, err, sizeof(err)); qDebug() << "device read error " << err; - + Q_EMIT iioEvent(readRaw); } else if(readScale < 0) { char err[1024]; iio_strerror(-(int)readScale, err, sizeof(err)); qDebug() << "device read error " << err; + Q_EMIT iioEvent(readScale); } else { double result = (raw + m_offset) * scale * m_umScale; qDebug() << "dmm read success "; @@ -60,6 +61,7 @@ void DMMReadStrategy::read() double currentTime = QwtDate::toDouble(timeTracker->lastReadValue()); Q_EMIT readDone(currentTime, result); + Q_EMIT iioEvent(IIO_SUCCESS); } } diff --git a/plugins/datalogger/src/datamonitortool.cpp b/plugins/datalogger/src/datamonitortool.cpp index 137c9e7982..90eecf94bc 100644 --- a/plugins/datalogger/src/datamonitortool.cpp +++ b/plugins/datalogger/src/datamonitortool.cpp @@ -269,7 +269,9 @@ DatamonitorTool::DatamonitorTool(DataAcquisitionManager *dataAcquisitionManager, ////generate channel settings for compatible monitors foreach(QString monitor, m_dataAcquisitionManager->getDataMonitorMap()->keys()) { auto monitorModel = m_dataAcquisitionManager->getDataMonitorMap()->value(monitor); - tool->rightStack()->add(monitor, new ChannelAttributesMenu(monitorModel, this)); + ChannelAttributesMenu *chnlAttrMenu = new ChannelAttributesMenu(monitorModel, this); + tool->rightStack()->add(monitor, chnlAttrMenu); + connect(chnlAttrMenu, &ChannelAttributesMenu::iioEvent, this, &DatamonitorTool::iioEvent); } /////////////////monitor selection menu /////////////// @@ -282,7 +284,9 @@ DatamonitorTool::DatamonitorTool(DataAcquisitionManager *dataAcquisitionManager, connect(m_dataAcquisitionManager, &DataAcquisitionManager::monitorAdded, this, [=, this](DataMonitorModel *monitor) { m_monitorSelectionMenu->addMonitor(monitor); - tool->rightStack()->add(monitor->getName(), new ChannelAttributesMenu(monitor, this)); + ChannelAttributesMenu *chnlAttrMenu = new ChannelAttributesMenu(monitor, this); + tool->rightStack()->add(monitor->getName(), chnlAttrMenu); + connect(chnlAttrMenu, &ChannelAttributesMenu::iioEvent, this, &DatamonitorTool::iioEvent); }); connect(m_dataAcquisitionManager, &DataAcquisitionManager::monitorRemoved, this, diff --git a/plugins/datalogger/src/menus/channelattributesmenu.cpp b/plugins/datalogger/src/menus/channelattributesmenu.cpp index 1051210e89..606c66979d 100644 --- a/plugins/datalogger/src/menus/channelattributesmenu.cpp +++ b/plugins/datalogger/src/menus/channelattributesmenu.cpp @@ -20,6 +20,7 @@ */ #include "menus/channelattributesmenu.hpp" +#include "datastrategy/channelattrdatastrategy.h" #include #include @@ -66,6 +67,10 @@ ChannelAttributesMenu::ChannelAttributesMenu(DataMonitorModel *model, QWidget *p for(auto w : attrWidgets) { attrLayout->addWidget(w); + connect(dynamic_cast(w->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, + bool isReadOp) { Q_EMIT iioEvent(returnCode); }); } } else { diff --git a/plugins/debugger/include/debugger/iioexplorerinstrument.h b/plugins/debugger/include/debugger/iioexplorerinstrument.h index 7cbc3e3cbb..789d8af161 100644 --- a/plugins/debugger/include/debugger/iioexplorerinstrument.h +++ b/plugins/debugger/include/debugger/iioexplorerinstrument.h @@ -39,7 +39,7 @@ #include namespace scopy::debugger { -class SCOPY_DEBUGGER_EXPORT IIOExplorerInstrument : public QWidget +class SCOPY_DEBUGGER_EXPORT IIOExplorerInstrument : public QWidget, public IIOEventEmitter { Q_OBJECT friend class IIOExplorerInstrument_API; @@ -51,6 +51,9 @@ class SCOPY_DEBUGGER_EXPORT IIOExplorerInstrument : public QWidget void saveSettings(QSettings &); void loadSettings(QSettings &); +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private Q_SLOTS: void applySelection(const QItemSelection &selected, const QItemSelection &deselected); void filterAndExpand(const QString &text); diff --git a/plugins/debugger/include/debugger/iiomodel.h b/plugins/debugger/include/debugger/iiomodel.h index a47bb2c5b1..c7c6725200 100644 --- a/plugins/debugger/include/debugger/iiomodel.h +++ b/plugins/debugger/include/debugger/iiomodel.h @@ -27,10 +27,11 @@ #include #include #include +#include #include "iiostandarditem.h" namespace scopy::debugger { -class IIOModel : public QObject +class IIOModel : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -42,6 +43,7 @@ class IIOModel : public QObject Q_SIGNALS: void emitLog(QDateTime timestamp, bool isRead, QString path, QString oldValue, QString newValue, int returnCode); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private: void iioTreeSetup(); diff --git a/plugins/debugger/src/debuggerplugin.cpp b/plugins/debugger/src/debuggerplugin.cpp index f360a0c555..1e9d09eb7f 100644 --- a/plugins/debugger/src/debuggerplugin.cpp +++ b/plugins/debugger/src/debuggerplugin.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -131,6 +132,7 @@ bool DebuggerPlugin::onConnect() if(m_useDebuggerV2) { m_iioDebugger = new IIOExplorerInstrument(m_conn->context(), nullptr, nullptr); dbgTme->setTool(m_iioDebugger); + connect(m_iioDebugger, &IIOExplorerInstrument::iioEvent, dbgTme, &ToolMenuEntry::iioEvent); } else { dbgTme->setTool(new DebuggerInstrument(m_conn->context(), nullptr, nullptr)); } @@ -173,7 +175,16 @@ bool DebuggerPlugin::loadPage() bool DebuggerPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/gui/icons/adalm.svg"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("DEBUG"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } diff --git a/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp b/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp index bdc4e0162d..144d8d6d2f 100644 --- a/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp +++ b/plugins/debugger/src/iioexplorer/iioexplorerinstrument.cpp @@ -147,6 +147,8 @@ void IIOExplorerInstrument::setupUi() setLayout(new QVBoxLayout(this)); layout()->setContentsMargins(0, 0, 0, 0); layout()->addWidget(m_tabWidget); + + connect(m_iioModel, &IIOModel::iioEvent, this, &IIOExplorerInstrument::iioEvent); } void IIOExplorerInstrument::connectSignalsAndSlots() diff --git a/plugins/debugger/src/iioexplorer/iiomodel.cpp b/plugins/debugger/src/iioexplorer/iiomodel.cpp index 2efa13adde..25220e5472 100644 --- a/plugins/debugger/src/iioexplorer/iiomodel.cpp +++ b/plugins/debugger/src/iioexplorer/iiomodel.cpp @@ -20,6 +20,9 @@ */ #include "iiomodel.h" +#include "datastrategy/channelattrdatastrategy.h" +#include "datastrategy/contextattrdatastrategy.h" +#include "datastrategy/deviceattrdatastrategy.h" #include #define BUFFER_SIZE 256 @@ -88,6 +91,11 @@ void IIOModel::generateCtxAttributes() IIOStandardItem::ContextAttribute); attrItem->setEditable(false); m_rootItem->appendRow(attrItem); + connect(dynamic_cast(ctxWidget->getDataStrategy()), + &ContextAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } } @@ -130,6 +138,11 @@ void IIOModel::generateDeviceAttributes() attrItem->setDevice(m_currentDevice); attrItem->setEditable(false); m_currentDeviceItem->appendRow(attrItem); + connect(dynamic_cast(m_devList[j]->getDataStrategy()), + &DeviceAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } } @@ -169,6 +182,11 @@ void IIOModel::generateChannelAttributes() attr_item->setChannel(m_currentChannel); attr_item->setEditable(false); m_currentChannelItem->appendRow(attr_item); + connect(dynamic_cast(m_chnlList[i]->getDataStrategy()), + &ChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } } diff --git a/plugins/m2k/src/old/digitalio.cpp b/plugins/m2k/src/old/digitalio.cpp index 9063e5ffb6..28316ab97b 100644 --- a/plugins/m2k/src/old/digitalio.cpp +++ b/plugins/m2k/src/old/digitalio.cpp @@ -257,6 +257,7 @@ void DigitalIO::updateUi() if(groups[1]->ui->inout->isChecked()) { groups[1]->ui->horizontalSlider->setValue(gpigrp2); } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } } diff --git a/plugins/m2k/src/old/dmm.cpp b/plugins/m2k/src/old/dmm.cpp index 17adcbbffa..2f0f09b61c 100644 --- a/plugins/m2k/src/old/dmm.cpp +++ b/plugins/m2k/src/old/dmm.cpp @@ -415,12 +415,15 @@ void DMM::checkAndUpdateGainMode(const std::vector &volts) if(currentChannelGain[i] == libm2k::analog::PLUS_MINUS_2_5V) { // only show out of range for +/- 2.5 errorLabels[i]->setText("Out of range"); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); } else { errorLabels[i]->setText(""); + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } } } else { errorLabels[i]->setText(""); + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } } @@ -851,8 +854,10 @@ void DMM::writeAllSettingsToHardware() trigger->setAnalogMode(i, libm2k::ALWAYS); } } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { qDebug(CAT_VOLTMETER) << "Can't write to hardware: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } } diff --git a/plugins/m2k/src/old/logicanalyzer/logic_analyzer.cpp b/plugins/m2k/src/old/logicanalyzer/logic_analyzer.cpp index df05a2638b..d9fed8d052 100644 --- a/plugins/m2k/src/old/logicanalyzer/logic_analyzer.cpp +++ b/plugins/m2k/src/old/logicanalyzer/logic_analyzer.cpp @@ -2114,6 +2114,7 @@ void LogicAnalyzer::startStop(bool start) m_m2kDigital->setKernelBuffersCountIn(1); } catch(libm2k::m2k_exception &e) { qDebug() << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } chunk_size = bufferSizeAdjusted; @@ -2178,6 +2179,7 @@ void LogicAnalyzer::startStop(bool start) m_m2kDigital->setKernelBuffersCountIn(m_currentKernelBuffers); } catch(libm2k::m2k_exception &e) { qDebug() << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } // time for one kernel buffer + 100ms for the transfer @@ -2227,6 +2229,7 @@ void LogicAnalyzer::startStop(bool start) } catch(libm2k::m2k_exception &e) { qDebug() << e.what() << " code: " << e.iioCode(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); break; } @@ -2235,6 +2238,7 @@ void LogicAnalyzer::startStop(bool start) } Q_EMIT dataAvailable(absIndex - captureSize, absIndex, m_buffer); + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); QMetaObject::invokeMethod(&m_plot, // trigger replot on Main Thread "replot", Qt::QueuedConnection); @@ -2299,6 +2303,7 @@ void LogicAnalyzer::startStop(bool start) m_m2kDigital->cancelAcquisition(); // cancelBufferIn } catch(...) { qDebug() << "Error"; + Q_EMIT iioEvent(IIO_ERROR); } m_captureThread->join(); diff --git a/plugins/m2k/src/old/m2ktool.cpp b/plugins/m2k/src/old/m2ktool.cpp index b8a2afdeba..b7ef750f0a 100644 --- a/plugins/m2k/src/old/m2ktool.cpp +++ b/plugins/m2k/src/old/m2ktool.cpp @@ -41,6 +41,7 @@ M2kTool::M2kTool(ToolMenuEntry *tme, ApiObject *api, const QString &name, QWidge tme->setEnabled(true); p = Preferences::GetInstance(); connect(p, &Preferences::preferenceChanged, this, &M2kTool::readPreferences); + connect(this, &M2kTool::iioEvent, tme, &ToolMenuEntry::iioEvent); M2kTool::readPreferences(); Style::GetInstance()->setM2KStylesheet(this); } diff --git a/plugins/m2k/src/old/m2ktool.hpp b/plugins/m2k/src/old/m2ktool.hpp index 7939d2cfff..10eb2d58d7 100644 --- a/plugins/m2k/src/old/m2ktool.hpp +++ b/plugins/m2k/src/old/m2ktool.hpp @@ -34,6 +34,8 @@ #include #include +#include + class QJSEngine; class QPushButton; @@ -47,7 +49,7 @@ class ApiObject; class ToolLauncher; namespace m2k { -class M2kTool : public QWidget, public ResourceUser +class M2kTool : public QWidget, public ResourceUser, public IIOEventEmitter { Q_OBJECT @@ -66,6 +68,7 @@ class M2kTool : public QWidget, public ResourceUser Q_SIGNALS: void detachedState(bool detached); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; public Q_SLOTS: virtual void run(); diff --git a/plugins/m2k/src/old/network_analyzer.cpp b/plugins/m2k/src/old/network_analyzer.cpp index 4d02d68a19..d9ec0e268d 100644 --- a/plugins/m2k/src/old/network_analyzer.cpp +++ b/plugins/m2k/src/old/network_analyzer.cpp @@ -1197,6 +1197,7 @@ void NetworkAnalyzer::goertzel() m_m2k_analogout->push(buffers); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); return; } } @@ -1229,6 +1230,7 @@ void NetworkAnalyzer::goertzel() } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_NETWORK_ANALYZER) << e.what(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); } } @@ -1245,6 +1247,7 @@ void NetworkAnalyzer::goertzel() } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_NETWORK_ANALYZER) << e.what(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); return; } if(m_stop) { @@ -1311,7 +1314,7 @@ void NetworkAnalyzer::goertzel() m_averaged_count = 0; } } - + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); m_m2k_analogout->stop(); // Process was cancelled @@ -1648,6 +1651,7 @@ void NetworkAnalyzer::startStop(bool pressed) } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_NETWORK_ANALYZER) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } m_dBgraph.sweepDone(); m_phaseGraph.sweepDone(); @@ -1658,6 +1662,7 @@ void NetworkAnalyzer::startStop(bool pressed) m_m2k_analogin->setKernelBuffersCount(KERNEL_BUFFERS_DEFAULT); } catch(libm2k::m2k_exception &e) { qDebug() << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } } @@ -1676,6 +1681,7 @@ std::vector NetworkAnalyzer::generateSinWave(unsigned int chn_idx, doubl } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_NETWORK_ANALYZER) << e.what(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); } } diff --git a/plugins/m2k/src/old/oscilloscope.cpp b/plugins/m2k/src/old/oscilloscope.cpp index 46b8a643af..032244fcf0 100644 --- a/plugins/m2k/src/old/oscilloscope.cpp +++ b/plugins/m2k/src/old/oscilloscope.cpp @@ -2287,7 +2287,9 @@ void Oscilloscope::import() } catch(FileManagerException &ex) { import_error = QString(ex.what()); Q_EMIT importFileLoaded(false); + Q_EMIT iioEvent(IIO_ERROR); } + Q_EMIT iioEvent(IIO_SUCCESS); } unsigned int Oscilloscope::find_curve_number() @@ -4767,9 +4769,11 @@ void Oscilloscope::resetStreamingFlag(bool enable) try { m_m2k_analogin->getTrigger()->setAnalogStreamingFlag(false); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } cleanBuffersAllSinks(); @@ -4780,9 +4784,11 @@ void Oscilloscope::resetStreamingFlag(bool enable) if(enable && !d_displayOneBuffer) { m_m2k_analogin->getTrigger()->setAnalogStreamingFlag(true); } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } /* Single capture done */ @@ -4840,6 +4846,7 @@ void Oscilloscope::onPlotNewData() updateBufferPreviewer(); trigger_input = true; // used to read trigger status from Js + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } void Oscilloscope::onTriggerModeChanged(int mode) @@ -4964,10 +4971,11 @@ void Oscilloscope::setGainMode(uint chnIdx, libm2k::analog::M2K_RANGE gain_mode) try { libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(chnIdx); runInHwThreadPool(m_m2k_analogin->setRange(chn, gain_mode)); - + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } @@ -4986,10 +4994,12 @@ void Oscilloscope::setChannelHwOffset(uint chnIdx, double offset) try { libm2k::analog::ANALOG_IN_CHANNEL chn = static_cast(chnIdx); runInHwThreadPool(m_m2k_analogin->setVerticalOffset(chn, offset);); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } } @@ -5036,8 +5046,10 @@ void Oscilloscope::writeAllSettingsToHardware() } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } + Q_EMIT iioEvent(IIO_SUCCESS); setSampleRate(active_sample_rate); } for(size_t i = 0; i < nb_channels; i++) { @@ -5132,9 +5144,11 @@ void Oscilloscope::setSampleRate(double sample_rate) m_m2k_analogin->setSampleRate(sample_rate); m_m2k_analogin->setOversamplingRatio(1); } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e) qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } }); } @@ -5154,10 +5168,12 @@ double Oscilloscope::getSampleRate() } sr = (double)(sr / osr); } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); return sr; } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_OSCILLOSCOPE) << e.what(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); return 0; } } diff --git a/plugins/m2k/src/old/patterngenerator/pattern_generator.cpp b/plugins/m2k/src/old/patterngenerator/pattern_generator.cpp index a02b25181b..5d52030264 100644 --- a/plugins/m2k/src/old/patterngenerator/pattern_generator.cpp +++ b/plugins/m2k/src/old/patterngenerator/pattern_generator.cpp @@ -745,10 +745,11 @@ void PatternGenerator::startStop(bool start) 0.2 + static_cast(m_bufferSize) / static_cast(m_sampleRate); // * 1000.0 (timeout is in seconds, start expects milliseconds) m_singleTimer->start(timeout * 1000.0); - + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug() << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } else { try { @@ -764,9 +765,11 @@ void PatternGenerator::startStop(bool start) m_m2kDigital->enableChannel(i, false); } } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug() << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } diff --git a/plugins/m2k/src/old/power_controller.cpp b/plugins/m2k/src/old/power_controller.cpp index 424c291ab7..fd36234f93 100644 --- a/plugins/m2k/src/old/power_controller.cpp +++ b/plugins/m2k/src/old/power_controller.cpp @@ -153,9 +153,11 @@ void PowerController::dac1_set_value(double value) { try { m_m2k_powersupply->pushChannel(0, value); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_POWERCONTROL) << "Can't write push value: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } averageVoltageCh1.clear(); @@ -171,9 +173,11 @@ void PowerController::dac2_set_value(double value) { try { m_m2k_powersupply->pushChannel(1, value); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_POWERCONTROL) << "Can't write push value: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } averageVoltageCh2.clear(); } @@ -182,9 +186,11 @@ void PowerController::dac1_set_enabled(bool enabled) { try { m_m2k_powersupply->enableChannel(0, enabled); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_POWERCONTROL) << "Can't enable channel: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } averageVoltageCh1.clear(); @@ -199,9 +205,11 @@ void PowerController::dac2_set_enabled(bool enabled) { try { m_m2k_powersupply->enableChannel(1, enabled); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_POWERCONTROL) << "Can't enable channel: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } averageVoltageCh2.clear(); setDynamicProperty(ui->dac2, "running", enabled); @@ -230,9 +238,11 @@ void PowerController::update_lcd() try { value1 = m_m2k_powersupply->readChannel(0); value2 = m_m2k_powersupply->readChannel(1); + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_POWERCONTROL) << "Can't read value: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); } averageVoltageCh1.push_back(value1); diff --git a/plugins/m2k/src/old/signal_generator.cpp b/plugins/m2k/src/old/signal_generator.cpp index bdd306308b..109e7242bb 100644 --- a/plugins/m2k/src/old/signal_generator.cpp +++ b/plugins/m2k/src/old/signal_generator.cpp @@ -1109,8 +1109,9 @@ bool SignalGenerator::loadParametersFromFile(QSharedPointerfile_nr_of_samples.push_back(0); ptr->file_type = FORMAT_NO_FILE; } - if(!ok) + if(!ok) { return false; + } riff_header_t riff; chunk_header_t chunk; @@ -1122,6 +1123,7 @@ bool SignalGenerator::loadParametersFromFile(QSharedPointersetCyclic(true); m_m2k_analogout->push(buffers); + Q_EMIT iioEvent(IIO_SUCCESS); } void SignalGenerator::run() { start(); } @@ -1395,9 +1398,11 @@ void SignalGenerator::stop() ui->run_button->toggle(false); buffers.clear(); m_m2k_analogout->stop(); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_SIGNAL_GENERATOR) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } ResourceManager::close("m2k-dac" + m_uri); } @@ -1558,11 +1563,12 @@ void SignalGenerator::loadFileChannelData(int chIdx) return; } #endif - + Q_EMIT iioEvent(IIO_SUCCESS); } catch(FileManagerException &e) { ptr->file_message = QString::fromLocal8Bit(e.what()); ptr->file_nr_of_samples.push_back(0); ptr->file_type = FORMAT_NO_FILE; + Q_EMIT iioEvent(IIO_ERROR); } } @@ -1686,6 +1692,7 @@ gr::basic_block_sptr SignalGenerator::getSource(QWidget *obj, double samp_rate, } catch(std::runtime_error &e) { ptr->file_message = QString::fromLocal8Bit(e.what()); fs = blocks::null_source::make(sizeof(float)); + Q_EMIT iioEvent(IIO_ERROR); } for(size_t i = 0; i < ptr->file_nr_of_channels; i++) { if(i == ptr->file_channel) { diff --git a/plugins/m2k/src/old/spectrum_analyzer.cpp b/plugins/m2k/src/old/spectrum_analyzer.cpp index 4db1b3dc3a..d1cc7c5ad6 100644 --- a/plugins/m2k/src/old/spectrum_analyzer.cpp +++ b/plugins/m2k/src/old/spectrum_analyzer.cpp @@ -447,9 +447,11 @@ SpectrumAnalyzer::SpectrumAnalyzer(libm2k::context::M2k *m2k, QString uri, Filte if(canConvRawToVolts) { fft_plot->setScaleFactor(crt_channel, m_m2k_analogin->getScalingFactor(chn)); } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_SPECTRUM_ANALYZER) << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } if(started) { @@ -525,6 +527,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(libm2k::context::M2k *m2k, QString uri, Filte iio->stop(fft_ids[i]); } } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); }); connect(waterfall_plot, &WaterfallDisplayPlot::newWaterfallData, this, [=]() { @@ -539,6 +542,7 @@ SpectrumAnalyzer::SpectrumAnalyzer(libm2k::context::M2k *m2k, QString uri, Filte iio->stop(waterfall_ids[i]); } } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::STREAM); }); connect(fft_plot, SIGNAL(currentAverageIndex(unsigned int, unsigned int)), @@ -2572,9 +2576,11 @@ void SpectrumAnalyzer::writeAllSettingsToHardware() } } } + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_SPECTRUM_ANALYZER) << "Can't write settings to hardware: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } @@ -2688,9 +2694,11 @@ void SpectrumAnalyzer::setSampleRate(double sr) if(m_m2k_analogin) { try { m_m2k_analogin->setOversamplingRatio(sample_rate_divider); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(libm2k::m2k_exception &e) { HANDLE_EXCEPTION(e); qDebug(CAT_M2K_SPECTRUM_ANALYZER) << "Can't write oversampling ratio: " << e.what(); + Q_EMIT iioEvent(IIO_ERROR); } } diff --git a/plugins/pqm/include/pqm/acquisitionmanager.h b/plugins/pqm/include/pqm/acquisitionmanager.h index bd1ab1e416..a09521cc97 100644 --- a/plugins/pqm/include/pqm/acquisitionmanager.h +++ b/plugins/pqm/include/pqm/acquisitionmanager.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include @@ -37,7 +37,7 @@ #define BUFFER_SIZE 256 #define DEVICE_PQM "pqm" namespace scopy::pqm { -class AcquisitionManager : public QObject +class AcquisitionManager : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -56,6 +56,7 @@ public Q_SLOTS: void bufferDataAvailable(QMap>); void logData(PqmDataLogger::ActiveInstrument instr, const QString &filePath); void pqEvent(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::STREAM) override; private Q_SLOTS: void futureReadData(); diff --git a/plugins/pqm/src/acquisitionmanager.cpp b/plugins/pqm/src/acquisitionmanager.cpp index 683422b3f1..8afeac3d9f 100644 --- a/plugins/pqm/src/acquisitionmanager.cpp +++ b/plugins/pqm/src/acquisitionmanager.cpp @@ -151,9 +151,11 @@ bool AcquisitionManager::readPqmAttributes() { iio_device *dev = iio_context_find_device(m_ctx, DEVICE_PQM); if(!dev) { + Q_EMIT iioEvent(IIO_ERROR); qDebug(CAT_PQM_ACQ) << "Device is unavailable!"; return false; } + int retCode = IIO_SUCCESS; int attrNo = iio_device_get_attrs_count(dev); int chnlsNo = iio_device_get_channels_count(dev); const char *attrName = nullptr; @@ -161,8 +163,12 @@ bool AcquisitionManager::readPqmAttributes() char dest[MAX_ATTR_SIZE]; for(int i = 0; i < attrNo; i++) { attrName = iio_device_get_attr(dev, i); - iio_device_attr_read(dev, attrName, dest, MAX_ATTR_SIZE); + int ret = iio_device_attr_read(dev, attrName, dest, MAX_ATTR_SIZE); m_pqmAttr[DEVICE_PQM][attrName] = QString(dest); + retCode |= ret; + if(ret < 0) { + qWarning(CAT_PQM_ACQ) << "Cannot read device attribute:" << attrName; + } } for(int i = 0; i < chnlsNo; i++) { iio_channel *chnl = iio_device_get_channel(dev, i); @@ -170,24 +176,36 @@ bool AcquisitionManager::readPqmAttributes() chnlId = iio_channel_get_name(chnl); for(int j = 0; j < attrNo; j++) { attrName = iio_channel_get_attr(chnl, j); - iio_channel_attr_read(chnl, attrName, dest, MAX_ATTR_SIZE); + int ret = iio_channel_attr_read(chnl, attrName, dest, MAX_ATTR_SIZE); m_pqmAttr[chnlId][attrName] = QString(dest); + retCode |= ret; + if(ret < 0) { + qWarning(CAT_PQM_ACQ) << "Cannot read channel" << chnlId << "attribute:" << attrName; + } } } m_pqmLog->acquireAttrData(m_pqmAttr); handlePQEvents(); m_pqmLog->log(); + if(m_tools["settings"]) { + Q_EMIT iioEvent(retCode, IIOCallType::SINGLE); + } else { + Q_EMIT iioEvent(retCode); + } + return true; } bool AcquisitionManager::readBufferedData() { if(!m_buffer) { + Q_EMIT iioEvent(IIO_ERROR); qWarning(CAT_PQM_ACQ) << "The buffer is NULL!"; return false; } ssize_t ret = iio_buffer_refill(m_buffer); if(ret < 0) { + Q_EMIT iioEvent(IIO_ERROR); qWarning(CAT_PQM_ACQ) << "An error occurred while refilling! [" << ret << "]"; return false; } @@ -208,6 +226,7 @@ bool AcquisitionManager::readBufferedData() m_bufferData[chnl].push_back(d_ptr); samplesCounter++; } + Q_EMIT iioEvent(IIO_SUCCESS); m_pqmLog->log(); return true; } @@ -263,8 +282,10 @@ void AcquisitionManager::setData(QMap> attr) { QMutexLocker locker(&m_mutex); iio_device *dev = iio_context_find_device(m_ctx, DEVICE_PQM); - if(!dev) + if(!dev) { + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::SINGLE); return; + } const QStringList keys = attr[DEVICE_PQM].keys(); for(const QString &key : keys) { if(m_pqmAttr[DEVICE_PQM].contains(key) && @@ -274,6 +295,7 @@ void AcquisitionManager::setData(QMap> attr) iio_device_attr_write(dev, key.toStdString().c_str(), newVal.toStdString().c_str()); } } + Q_EMIT iioEvent(IIO_SUCCESS, IIOCallType::SINGLE); } void AcquisitionManager::setProcessData(bool en) diff --git a/plugins/pqm/src/pqmplugin.cpp b/plugins/pqm/src/pqmplugin.cpp index b29b4fa2c7..00b6d74331 100644 --- a/plugins/pqm/src/pqmplugin.cpp +++ b/plugins/pqm/src/pqmplugin.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -96,7 +97,16 @@ bool PQMPlugin::loadPage() bool PQMPlugin::loadIcon() { - SCOPY_PLUGIN_ICON(":/pqm/pqm_icon.svg"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("PQMON"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } @@ -173,6 +183,7 @@ bool PQMPlugin::onConnect() for(auto &tool : m_toolList) { connect(tool->tool(), SIGNAL(enableTool(bool, QString)), m_acqManager, SLOT(toolEnabled(bool, QString))); + connect(m_acqManager, &AcquisitionManager::iioEvent, tool, &ToolMenuEntry::iioEvent); } return true; } diff --git a/plugins/regmap/src/readwrite/iioregisterreadstrategy.cpp b/plugins/regmap/src/readwrite/iioregisterreadstrategy.cpp index e8206ff003..e2d9ca2f5a 100644 --- a/plugins/regmap/src/readwrite/iioregisterreadstrategy.cpp +++ b/plugins/regmap/src/readwrite/iioregisterreadstrategy.cpp @@ -47,6 +47,7 @@ void IIORegisterReadStrategy::read(uint32_t address) << "device read success for register " << address << " with value " << reg_val; Q_EMIT readDone(address, reg_val); } + Q_EMIT iioEvent(read); } uint32_t IIORegisterReadStrategy::getAddressSpace() const { return addressSpace; } diff --git a/plugins/regmap/src/readwrite/iioregisterreadstrategy.hpp b/plugins/regmap/src/readwrite/iioregisterreadstrategy.hpp index a4ad7fc080..3bfb251045 100644 --- a/plugins/regmap/src/readwrite/iioregisterreadstrategy.hpp +++ b/plugins/regmap/src/readwrite/iioregisterreadstrategy.hpp @@ -38,8 +38,6 @@ class IIORegisterReadStrategy : public IRegisterReadStrategy uint32_t getAddressSpace() const; void setAddressSpace(uint32_t newAddressSpace); -Q_SIGNALS: - private: struct iio_device *dev; uint32_t addressSpace = 0; diff --git a/plugins/regmap/src/readwrite/iioregisterwritestrategy.cpp b/plugins/regmap/src/readwrite/iioregisterwritestrategy.cpp index afb44a113f..fc4c7d1474 100644 --- a/plugins/regmap/src/readwrite/iioregisterwritestrategy.cpp +++ b/plugins/regmap/src/readwrite/iioregisterwritestrategy.cpp @@ -43,6 +43,7 @@ void IIORegisterWriteStrategy::write(uint32_t address, uint32_t val) << "device write successfull for register " << address << " with value " << val; Q_EMIT writeSuccess(address); } + Q_EMIT iioEvent(write); } uint32_t IIORegisterWriteStrategy::getAddressSpace() const { return addressSpace; } diff --git a/plugins/regmap/src/readwrite/iregisterreadstrategy.hpp b/plugins/regmap/src/readwrite/iregisterreadstrategy.hpp index 8cfd6b8e21..5a84f098f8 100644 --- a/plugins/regmap/src/readwrite/iregisterreadstrategy.hpp +++ b/plugins/regmap/src/readwrite/iregisterreadstrategy.hpp @@ -24,8 +24,10 @@ #include +#include + namespace scopy::regmap { -class IRegisterReadStrategy : public QObject +class IRegisterReadStrategy : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -34,6 +36,7 @@ class IRegisterReadStrategy : public QObject Q_SIGNALS: void readDone(uint32_t address, uint32_t value); void readError(const char *err); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; }; } // namespace scopy::regmap #endif // IREGISTERREADSTRATEGY_HPP diff --git a/plugins/regmap/src/readwrite/iregisterwritestrategy.hpp b/plugins/regmap/src/readwrite/iregisterwritestrategy.hpp index 5c9ada3f2c..54606480d5 100644 --- a/plugins/regmap/src/readwrite/iregisterwritestrategy.hpp +++ b/plugins/regmap/src/readwrite/iregisterwritestrategy.hpp @@ -24,8 +24,10 @@ #include +#include + namespace scopy::regmap { -class IRegisterWriteStrategy : public QObject +class IRegisterWriteStrategy : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -34,6 +36,7 @@ class IRegisterWriteStrategy : public QObject Q_SIGNALS: void writeError(const char *err); void writeSuccess(uint32_t address); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; }; } // namespace scopy::regmap #endif // IREGISTERWRITESTRATEGY_HPP diff --git a/plugins/regmap/src/regmapplugin.cpp b/plugins/regmap/src/regmapplugin.cpp index 3a5a1d8862..819600aa19 100644 --- a/plugins/regmap/src/regmapplugin.cpp +++ b/plugins/regmap/src/regmapplugin.cpp @@ -52,6 +52,7 @@ #include #include "logging_categories.h" #include +#include #include "iioutil/connectionprovider.h" #include "jsonformatedelement.hpp" @@ -83,9 +84,16 @@ bool RegmapPlugin::loadPage() bool RegmapPlugin::loadIcon() { - m_icon = new QLabel(""); - m_icon->setStyleSheet("border-image: url(:/gui/icons/" + Style::getAttribute(json::theme::icon_theme_folder) + - "/icons/RegMap.svg);"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("REGMAP"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } @@ -222,6 +230,10 @@ bool RegmapPlugin::onConnect() } else { generateDevice(templatePath, dev, devName, iioReadStrategy, iioWriteStrategy); } + connect(iioReadStrategy, &IIORegisterReadStrategy::iioEvent, m_toolList.last(), + &ToolMenuEntry::iioEvent); + connect(iioWriteStrategy, &IIORegisterWriteStrategy::iioEvent, m_toolList.last(), + &ToolMenuEntry::iioEvent); } m_toolList[0]->setEnabled(true); diff --git a/plugins/swiot/include/swiot/ad74413r/buffermenu.h b/plugins/swiot/include/swiot/ad74413r/buffermenu.h index 791d5cf27f..0fa5576734 100644 --- a/plugins/swiot/include/swiot/ad74413r/buffermenu.h +++ b/plugins/swiot/include/swiot/ad74413r/buffermenu.h @@ -25,13 +25,14 @@ #include #include #include +#include #define OUTPUT_CHNL "output" #define INPUT_CHNL "input" namespace scopy::swiot { -class BufferMenu : public QWidget +class BufferMenu : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -60,6 +61,7 @@ public Q_SLOTS: void freqChangeEnd(); void thresholdChangeStart(); void thresholdChangeEnd(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; protected: IIOWidget *m_samplingFreq; diff --git a/plugins/swiot/include/swiot/ad74413r/buffermenuview.h b/plugins/swiot/include/swiot/ad74413r/buffermenuview.h index b57bab7bd9..bf3a486069 100644 --- a/plugins/swiot/include/swiot/ad74413r/buffermenuview.h +++ b/plugins/swiot/include/swiot/ad74413r/buffermenuview.h @@ -30,7 +30,7 @@ #include namespace scopy::swiot { -class BufferMenuView : public QWidget +class BufferMenuView : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -56,6 +56,7 @@ class BufferMenuView : public QWidget void samplingFreqWritten(bool written); void runBtnsPressed(bool en); + void iioEvent(int retCode, scopy::IIOCallType type); private: void createConnections(); diff --git a/plugins/swiot/include/swiot/faults/faultsdevice.h b/plugins/swiot/include/swiot/faults/faultsdevice.h index d4dcfb5ffd..cf6027ccdd 100644 --- a/plugins/swiot/include/swiot/faults/faultsdevice.h +++ b/plugins/swiot/include/swiot/faults/faultsdevice.h @@ -29,11 +29,12 @@ #include #include +#include namespace scopy::swiot { class FaultsGroup; -class FaultsDevice : public QWidget +class FaultsDevice : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -55,6 +56,7 @@ public Q_SLOTS: void specialFaultsUpdated(int index, QString channelFunction); void faultNumericUpdated(); void faultRegisterRead(int iReg, uint32_t value); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private Q_SLOTS: void updateMinimumHeight(); diff --git a/plugins/swiot/include/swiot/faults/faultspage.h b/plugins/swiot/include/swiot/faults/faultspage.h index 2acf6029dc..5b7ad248b8 100644 --- a/plugins/swiot/include/swiot/faults/faultspage.h +++ b/plugins/swiot/include/swiot/faults/faultspage.h @@ -31,7 +31,7 @@ namespace scopy::swiot { class FaultsDevice; -class FaultsPage : public QWidget +class FaultsPage : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -39,6 +39,8 @@ class FaultsPage : public QWidget ~FaultsPage(); void update(); +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type); private: QString m_uri; diff --git a/plugins/swiot/include/swiot/max14906/diodigitalchannelcontroller.h b/plugins/swiot/include/swiot/max14906/diodigitalchannelcontroller.h index 77689c1ab6..cbb1d74cb5 100644 --- a/plugins/swiot/include/swiot/max14906/diodigitalchannelcontroller.h +++ b/plugins/swiot/include/swiot/max14906/diodigitalchannelcontroller.h @@ -25,9 +25,10 @@ #include #include +#include namespace scopy::swiot { -class DioDigitalChannelController : public QWidget +class DioDigitalChannelController : public QWidget, public IIOEventEmitter { Q_OBJECT public: @@ -36,6 +37,10 @@ class DioDigitalChannelController : public QWidget ~DioDigitalChannelController() override; DioDigitalChannel *getDigitalChannel() const; + +Q_SIGNALS: + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private Q_SLOTS: void createWriteCurrentLimitCommand(int index); void createWriteRawCommand(bool value); diff --git a/plugins/swiot/include/swiot/readerthread.h b/plugins/swiot/include/swiot/readerthread.h index b0029307a7..e42e48c9f7 100644 --- a/plugins/swiot/include/swiot/readerthread.h +++ b/plugins/swiot/include/swiot/readerthread.h @@ -31,9 +31,10 @@ #include #include +#include namespace scopy::swiot { -class ReaderThread : public QThread +class ReaderThread : public QThread, public IIOEventEmitter { Q_OBJECT public: @@ -77,6 +78,7 @@ public Q_SLOTS: void readerThreadFinished(); void bufferRefilled(QMap> bufferData, int bufferCounter); void channelDataChanged(int channelId, double value); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private Q_SLOTS: void bufferRefillCommandFinished(scopy::Command *cmd); diff --git a/plugins/swiot/include/swiot/swiotcontroller.h b/plugins/swiot/include/swiot/swiotcontroller.h index 3653da809d..6fbe0354ce 100644 --- a/plugins/swiot/include/swiot/swiotcontroller.h +++ b/plugins/swiot/include/swiot/swiotcontroller.h @@ -31,7 +31,7 @@ #include namespace scopy::swiot { -class SwiotController : public QObject +class SwiotController : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -60,6 +60,8 @@ public Q_SLOTS: void modeAttributeChanged(QString mode); void isRuntimeCtxChanged(bool isRuntimeCtx); void writeModeFailed(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; + private Q_SLOTS: void writeModeCommandFinished(scopy::Command *cmd); void readModeCommandFinished(scopy::Command *cmd); diff --git a/plugins/swiot/include/swiot/swiotreadtemperaturetask.h b/plugins/swiot/include/swiot/swiotreadtemperaturetask.h index 1877e5a2df..5dfbdf886f 100644 --- a/plugins/swiot/include/swiot/swiotreadtemperaturetask.h +++ b/plugins/swiot/include/swiot/swiotreadtemperaturetask.h @@ -27,9 +27,10 @@ #include #include +#include namespace scopy::swiot { -class SwiotReadTemperatureTask : public QThread +class SwiotReadTemperatureTask : public QThread, public IIOEventEmitter { Q_OBJECT public: @@ -39,6 +40,7 @@ class SwiotReadTemperatureTask : public QThread Q_SIGNALS: void newTemperature(double value); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE) override; private Q_SLOTS: void readRawCommandFinished(scopy::Command *cmd); diff --git a/plugins/swiot/src/ad74413r/ad74413r.cpp b/plugins/swiot/src/ad74413r/ad74413r.cpp index ed50e32807..df5097be5c 100644 --- a/plugins/swiot/src/ad74413r/ad74413r.cpp +++ b/plugins/swiot/src/ad74413r/ad74413r.cpp @@ -128,6 +128,7 @@ void Ad74413r::setupConnections() &BufferAcquisitionHandler::onBufferRefilled, Qt::QueuedConnection); connect(m_readerThread, &ReaderThread::readerThreadFinished, this, &Ad74413r::onReaderThreadFinished, Qt::QueuedConnection); + connect(m_readerThread, &ReaderThread::iioEvent, m_tme, &ToolMenuEntry::iioEvent); connect(m_acqHandler, &BufferAcquisitionHandler::bufferDataReady, this, &Ad74413r::onBufferRefilled); connect(m_acqHandler, &BufferAcquisitionHandler::singleCaptureFinished, this, &Ad74413r::onSingleCaptureFinished, Qt::QueuedConnection); @@ -508,6 +509,7 @@ void Ad74413r::setupChannel(int chnlIdx, QString function) connect(menu, &BufferMenuView::diagnosticFunctionUpdated, this, &Ad74413r::onDiagnosticFunctionUpdated); connect(menu, &BufferMenuView::samplingFreqWritten, this, &Ad74413r::samplingFreqWritten); connect(menu, &BufferMenuView::thresholdWritten, this, &Ad74413r::onThresholdWritten); + connect(menu, &BufferMenuView::iioEvent, m_tme, &ToolMenuEntry::iioEvent); connect(this, &Ad74413r::broadcastThreshold, menu, &BufferMenuView::broadcastThreshold); connect(this, &Ad74413r::updateDiagSamplingFreq, menu, &BufferMenuView::updateDiagSamplingFreq); } diff --git a/plugins/swiot/src/ad74413r/buffermenu.cpp b/plugins/swiot/src/ad74413r/buffermenu.cpp index 521064033d..96bfa428a8 100644 --- a/plugins/swiot/src/ad74413r/buffermenu.cpp +++ b/plugins/swiot/src/ad74413r/buffermenu.cpp @@ -53,6 +53,11 @@ BufferMenu::BufferMenu(QWidget *parent, QString chnlFunction, Connection *conn, &BufferMenu::freqChangeStart); connect(dynamic_cast(m_samplingFreq->getDataStrategy()), &CmdQChannelAttrDataStrategy::emitStatus, this, &BufferMenu::freqChangeEnd); + connect(dynamic_cast(m_samplingFreq->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } } @@ -124,6 +129,11 @@ CurrentInLoopMenu::CurrentInLoopMenu(QWidget *parent, QString chnlFunction, Conn &CurrentInLoopMenu::updateCnvtLabel); connect(dynamic_cast(dacCode->getDataStrategy()), &CmdQChannelAttrDataStrategy::sendData, this, &CurrentInLoopMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } CurrentInLoopMenu::~CurrentInLoopMenu() {} @@ -161,6 +171,10 @@ DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Conn connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, &BufferMenu::thresholdChangeStart); connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInLoopMenu::onEmitStatus); + connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // dac code - output channel IIOWidget *dacCode = IIOWidgetBuilder(this) .connection(const_cast(m_connection)) @@ -192,6 +206,11 @@ DigitalInLoopMenu::DigitalInLoopMenu(QWidget *parent, QString chnlFunction, Conn &DigitalInLoopMenu::updateCnvtLabel); connect(dynamic_cast(dacCode->getDataStrategy()), &CmdQChannelAttrDataStrategy::sendData, this, &DigitalInLoopMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } DigitalInLoopMenu::~DigitalInLoopMenu() {} @@ -271,6 +290,11 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection &VoltageOutMenu::updateCnvtLabel); connect(dynamic_cast(dacCode->getDataStrategy()), &CmdQChannelAttrDataStrategy::sendData, this, &VoltageOutMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew - output channel IIOWidget *slewOptions = IIOWidgetBuilder(this) @@ -280,6 +304,11 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection .optionsValues("0 1") .buildSingle(); addMenuWidget(slewOptions); + connect(dynamic_cast(slewOptions->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew step - output channel IIOWidget *slewStep = IIOWidgetBuilder(this) @@ -290,6 +319,11 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection .uiStrategy(IIOWidgetBuilder::UIS::ComboUi) .buildSingle(); addMenuWidget(slewStep); + connect(dynamic_cast(slewStep->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew rate - output channel IIOWidget *slewRate = IIOWidgetBuilder(this) @@ -300,6 +334,11 @@ VoltageOutMenu::VoltageOutMenu(QWidget *parent, QString chnlFunction, Connection .uiStrategy(IIOWidgetBuilder::UIS::ComboUi) .buildSingle(); addMenuWidget(slewRate); + connect(dynamic_cast(slewRate->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } VoltageOutMenu::~VoltageOutMenu() {} @@ -354,6 +393,11 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection &CurrentOutMenu::updateCnvtLabel); connect(dynamic_cast(dacCode->getDataStrategy()), &CmdQChannelAttrDataStrategy::sendData, this, &CurrentOutMenu::updateCnvtLabel); + connect(dynamic_cast(dacCode->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew - output channel IIOWidget *slewOptions = IIOWidgetBuilder(this) @@ -363,6 +407,11 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection .optionsValues("0 1") .buildSingle(); addMenuWidget(slewOptions); + connect(dynamic_cast(slewOptions->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew step - output channel IIOWidget *slewStep = IIOWidgetBuilder(this) @@ -373,6 +422,11 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection .uiStrategy(IIOWidgetBuilder::UIS::ComboUi) .buildSingle(); addMenuWidget(slewStep); + connect(dynamic_cast(slewStep->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); // slew rate - output channel IIOWidget *slewRate = IIOWidgetBuilder(this) @@ -383,6 +437,11 @@ CurrentOutMenu::CurrentOutMenu(QWidget *parent, QString chnlFunction, Connection .uiStrategy(IIOWidgetBuilder::UIS::ComboUi) .buildSingle(); addMenuWidget(slewRate); + connect(dynamic_cast(slewRate->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } CurrentOutMenu::~CurrentOutMenu() {} @@ -420,6 +479,11 @@ DiagnosticMenu::DiagnosticMenu(QWidget *parent, QString chnlFunction, Connection [=, this](QString data, QString dataOptions) { Q_EMIT diagnosticFunctionUpdated(); }); connect(dynamic_cast(m_samplingFreq->getDataStrategy()), &CmdQChannelAttrDataStrategy::emitStatus, this, &DiagnosticMenu::onSamplingFreqWrite); + connect(dynamic_cast(diagOptions->getDataStrategy()), + &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } DiagnosticMenu::~DiagnosticMenu() {} @@ -463,6 +527,10 @@ DigitalInMenu::DigitalInMenu(QWidget *parent, QString chnlFunction, Connection * connect(dynamic_cast(m_threshold->getUiStrategy()), &EditableGuiStrategy::emitData, this, &BufferMenu::thresholdChangeStart); connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, &DigitalInMenu::onEmitStatus); + connect(dataStrategy, &CmdQChannelAttrDataStrategy::emitStatus, this, + [this](QDateTime timestamp, QString oldData, QString newData, int returnCode, bool isReadOp) { + Q_EMIT iioEvent(returnCode); + }); } DigitalInMenu::~DigitalInMenu() {} diff --git a/plugins/swiot/src/ad74413r/buffermenuview.cpp b/plugins/swiot/src/ad74413r/buffermenuview.cpp index 08413cf42d..6f76ce0f55 100644 --- a/plugins/swiot/src/ad74413r/buffermenuview.cpp +++ b/plugins/swiot/src/ad74413r/buffermenuview.cpp @@ -86,6 +86,7 @@ void BufferMenuView::createConnections() 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(m_swiotAdvMenu, &BufferMenu::iioEvent, this, &BufferMenuView::iioEvent); connect(this, &BufferMenuView::runBtnsPressed, m_swiotAdvMenu, &BufferMenu::onRunBtnsPressed); } diff --git a/plugins/swiot/src/config/configmodel.cpp b/plugins/swiot/src/config/configmodel.cpp index 61300e1f30..c77fe5f321 100644 --- a/plugins/swiot/src/config/configmodel.cpp +++ b/plugins/swiot/src/config/configmodel.cpp @@ -51,6 +51,7 @@ void ConfigModel::readEnabled() [=, this](scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -66,6 +67,7 @@ void ConfigModel::readEnabled() qCritical(CAT_SWIOT_CONFIG) << "Error: could not read attribute \"enable\" on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(enabledChnCmd); @@ -80,6 +82,7 @@ void ConfigModel::writeEnabled(const QString &enabled) [=, this](scopy::Command *cmd) { IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { @@ -89,6 +92,7 @@ void ConfigModel::writeEnabled(const QString &enabled) } else { Q_EMIT configChannelEnabled(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(enabledChnCmd); @@ -102,6 +106,7 @@ void ConfigModel::readDevice() [=, this](scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -112,6 +117,7 @@ void ConfigModel::readDevice() qDebug(CAT_SWIOT_CONFIG) << "Can't read value from device on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(deviceChnCmd); @@ -126,6 +132,7 @@ void ConfigModel::writeDevice(const QString &device) [=, this](scopy::Command *cmd) { IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { @@ -135,6 +142,7 @@ void ConfigModel::writeDevice(const QString &device) } else { Q_EMIT configChannelDevice(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(deviceChnCmd); @@ -149,6 +157,7 @@ void ConfigModel::readFunction() [=, this](scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -159,6 +168,7 @@ void ConfigModel::readFunction() qCritical(CAT_SWIOT_CONFIG) << "Error: could not read attribute \"function\" on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(functionChnCmd); @@ -173,6 +183,7 @@ void ConfigModel::writeFunction(const QString &function) [=, this](scopy::Command *cmd) { IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { @@ -182,6 +193,7 @@ void ConfigModel::writeFunction(const QString &function) } else { Q_EMIT configChannelFunction(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(functionChnCmd); @@ -196,6 +208,7 @@ void ConfigModel::readDeviceAvailable() [=, this](scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -208,6 +221,7 @@ void ConfigModel::readDeviceAvailable() << "Error: could not read attribute \"function available\" on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(deviceAvailableChnCmd); @@ -222,6 +236,7 @@ void ConfigModel::readFunctionAvailable() [=, this](scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } @@ -234,6 +249,7 @@ void ConfigModel::readFunctionAvailable() << "Error: could not read attribute \"device available\" on channel" << m_channelId << "error id ->" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_commandQueue->enqueue(functionAvailableChnCmd); diff --git a/plugins/swiot/src/config/configmodel.h b/plugins/swiot/src/config/configmodel.h index dd88a3ef88..098cd36a60 100644 --- a/plugins/swiot/src/config/configmodel.h +++ b/plugins/swiot/src/config/configmodel.h @@ -21,6 +21,7 @@ #ifndef CONFIGMODEL_H #define CONFIGMODEL_H +#include "iioutil/iioeventemitter.h" #include #include @@ -33,7 +34,7 @@ extern "C" } namespace scopy::swiot { -class ConfigModel : public QObject +class ConfigModel : public QObject, public IIOEventEmitter { Q_OBJECT public: @@ -62,6 +63,8 @@ class ConfigModel : public QObject void configChannelDevice(); void configChannelFunction(); + void iioEvent(int retCode, scopy::IIOCallType type = IIOCallType::SINGLE); + private: struct iio_device *m_device; int m_channelId; diff --git a/plugins/swiot/src/config/swiotconfig.cpp b/plugins/swiot/src/config/swiotconfig.cpp index b083f0379c..0ac81c703a 100644 --- a/plugins/swiot/src/config/swiotconfig.cpp +++ b/plugins/swiot/src/config/swiotconfig.cpp @@ -34,9 +34,11 @@ using namespace scopy::swiot; -SwiotConfig::SwiotConfig(QString uri, QWidget *parent) +SwiotConfig::SwiotConfig(QString uri, ToolMenuEntry *tme, QWidget *parent) : QWidget(parent) , m_uri(uri) + , m_tme(tme) + { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QHBoxLayout *layout = new QHBoxLayout(this); @@ -132,6 +134,7 @@ void SwiotConfig::buildGridLayout() QObject::connect(configController, &ConfigController::clearDrawArea, this, [this]() { m_drawArea->deactivateConnections(); }); + QObject::connect(configModel, &ConfigModel::iioEvent, m_tme, &ToolMenuEntry::iioEvent); } // The apply button will always be at the end of the channel widgets m_chnlsGrid->layout()->addWidget(m_applyBtn); diff --git a/plugins/swiot/src/config/swiotconfig.h b/plugins/swiot/src/config/swiotconfig.h index 9fe65b124a..b5a63b6541 100644 --- a/plugins/swiot/src/config/swiotconfig.h +++ b/plugins/swiot/src/config/swiotconfig.h @@ -22,6 +22,7 @@ #define SWIOTCONFIG_H #include "configcontroller.h" +#include "pluginbase/toolmenuentry.h" #include "src/config/drawarea.h" #include @@ -40,7 +41,7 @@ class SwiotConfig : public QWidget { Q_OBJECT public: - SwiotConfig(QString uri, QWidget *parent = nullptr); + SwiotConfig(QString uri, ToolMenuEntry *tme, QWidget *parent = nullptr); ~SwiotConfig(); public Q_SLOTS: @@ -52,6 +53,7 @@ public Q_SLOTS: void configBtnPressed(); private: + ToolMenuEntry *m_tme; QString m_uri; QMap m_iioDevices; iio_context *m_context; diff --git a/plugins/swiot/src/faults/faults.cpp b/plugins/swiot/src/faults/faults.cpp index 8859c1a104..27f11506d9 100644 --- a/plugins/swiot/src/faults/faults.cpp +++ b/plugins/swiot/src/faults/faults.cpp @@ -101,6 +101,7 @@ void Faults::connectSignalsAndSlots() }); QObject::connect(m_tme, &ToolMenuEntry::runToggled, m_runBtn, &QPushButton::setChecked); + QObject::connect(m_faultsPage, &FaultsPage::iioEvent, m_tme, &ToolMenuEntry::iioEvent); } void Faults::onBackBtnPressed() diff --git a/plugins/swiot/src/faults/faultsdevice.cpp b/plugins/swiot/src/faults/faultsdevice.cpp index 78cf615160..cd361322e1 100644 --- a/plugins/swiot/src/faults/faultsdevice.cpp +++ b/plugins/swiot/src/faults/faultsdevice.cpp @@ -188,19 +188,23 @@ void FaultsDevice::readRegister() IioRegisterRead *tcmd = dynamic_cast(cmd); if(!tcmd) { qCritical(CAT_SWIOT_FAULTS) << m_name << "faults register could not be read."; + Q_EMIT iioEvent(IIO_ERROR); return; } uint32_t reg = tcmd->getResult(); if(tcmd->getReturnCode() < 0) { qCritical(CAT_SWIOT_FAULTS) << m_name << "faults register could not be read."; + Q_EMIT iioEvent(IIO_ERROR); } else { qDebug(CAT_SWIOT_FAULTS) << m_name << "faults register read val:" << reg; try { Q_EMIT faultRegisterRead(i, reg); + Q_EMIT iioEvent(IIO_SUCCESS); } catch(std::invalid_argument &exception) { qCritical(CAT_SWIOT_FAULTS) << m_name << "faults register could not be read."; + Q_EMIT iioEvent(IIO_ERROR); } } }, @@ -214,16 +218,19 @@ void FaultsDevice::functionConfigCmdFinished(scopy::Command *cmd) IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { qCritical(CAT_SWIOT_FAULTS) << "Error: cannot read swiot special fault property"; + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { qCritical(CAT_SWIOT_FAULTS) << "Error: cannot read swiot special fault property"; + } else { int cmdIndex = m_functionConfigCmds.indexOf(cmd); char *readFunction = tcmd->getResult(); Q_EMIT specialFaultsUpdated(cmdIndex, QString(readFunction)); disconnect(cmd, &scopy::Command::finished, this, &FaultsDevice::deviceConfigCmdFinished); + Q_EMIT iioEvent(IIO_SUCCESS); } } @@ -232,11 +239,13 @@ void FaultsDevice::deviceConfigCmdFinished(scopy::Command *cmd) IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { qCritical(CAT_SWIOT_FAULTS) << "Error: cannot read swiot special fault config property"; + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { qCritical(CAT_SWIOT_FAULTS) << "Error: cannot read swiot special fault config property"; + Q_EMIT iioEvent(IIO_ERROR); } else { char *readDevice = tcmd->getResult(); int cmdIndex = m_deviceConfigCmds.indexOf(cmd); @@ -249,6 +258,7 @@ void FaultsDevice::deviceConfigCmdFinished(scopy::Command *cmd) &FaultsDevice::functionConfigCmdFinished, Qt::QueuedConnection); disconnect(cmd, &scopy::Command::finished, this, &FaultsDevice::deviceConfigCmdFinished); m_cmdQueue->enqueue(m_functionConfigCmds.at(cmdIndex)); + Q_EMIT iioEvent(IIO_SUCCESS); } } } diff --git a/plugins/swiot/src/faults/faultspage.cpp b/plugins/swiot/src/faults/faultspage.cpp index 28348c28a0..773d4f4749 100644 --- a/plugins/swiot/src/faults/faultspage.cpp +++ b/plugins/swiot/src/faults/faultspage.cpp @@ -21,6 +21,7 @@ #include "faults/faultspage.h" #include "swiot_logging_categories.h" #include +#include #include #include @@ -80,6 +81,7 @@ void FaultsPage::setupDevices() QVector faultRegistersAddr = {0x02e}; m_ad74413rFaultsDevice = new FaultsDevice("ad74413r", ":/swiot/swiot_faults.json", m_uri, faultRegistersAddr, this); + connect(m_ad74413rFaultsDevice, &FaultsDevice::iioEvent, this, &FaultsPage::iioEvent); } else { qCritical(CAT_SWIOT_FAULTS) << "Error: did not find ad74413r device."; } @@ -88,6 +90,7 @@ void FaultsPage::setupDevices() QVector faultRegistersAddr = {0x04, 0x05, 0x06, 0x07}; m_max14906FaultsDevice = new FaultsDevice("max14906", ":/swiot/swiot_faults.json", m_uri, faultRegistersAddr, this); + connect(m_max14906FaultsDevice, &FaultsDevice::iioEvent, this, &FaultsPage::iioEvent); } else { qCritical(CAT_SWIOT_FAULTS) << "Error: did not find max14906 device."; } diff --git a/plugins/swiot/src/max14906/diodigitalchannelcontroller.cpp b/plugins/swiot/src/max14906/diodigitalchannelcontroller.cpp index d2f3c833a4..acff2b369c 100644 --- a/plugins/swiot/src/max14906/diodigitalchannelcontroller.cpp +++ b/plugins/swiot/src/max14906/diodigitalchannelcontroller.cpp @@ -91,6 +91,7 @@ void DioDigitalChannelController::createWriteRawCommand(bool value) [=, this](scopy::Command *cmd) { IioChannelAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { @@ -98,6 +99,7 @@ void DioDigitalChannelController::createWriteRawCommand(bool value) << "Could not write value " << value << " to channel " << m_channelName << " error code" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_cmdQueue->enqueue(writeRawCmd); @@ -221,24 +223,28 @@ void DioDigitalChannelController::writeCurrentLimitCmdFinished(Command *cmd) { IioChannelAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { qCritical(CAT_SWIOT_MAX14906) << "Could not write current limit value to channel " << m_channelName << " error code " << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); } void DioDigitalChannelController::writeTypeCmdFinished(Command *cmd) { IioChannelAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { qCritical(CAT_SWIOT_MAX14906) << "Could not write attr to channel " << m_channelName << " error code " << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); } #include "moc_diodigitalchannelcontroller.cpp" diff --git a/plugins/swiot/src/max14906/max14906.cpp b/plugins/swiot/src/max14906/max14906.cpp index 57ca5bbea5..254140d880 100644 --- a/plugins/swiot/src/max14906/max14906.cpp +++ b/plugins/swiot/src/max14906/max14906.cpp @@ -131,6 +131,7 @@ void Max14906::connectSignalsAndSlots() connect(m_max14906SettingsTab, &DioSettingsTab::timeValueChanged, this, &Max14906::timerChanged); connect(m_qTimer, &QTimer::timeout, this, [&]() { m_readerThread->start(); }); connect(m_readerThread, &ReaderThread::started, this, [&]() { m_qTimer->start(1000); }); + connect(m_readerThread, &ReaderThread::iioEvent, m_tme, &ToolMenuEntry::iioEvent); connect(m_tme, &ToolMenuEntry::runToggled, m_runBtn, &QPushButton::setChecked); } @@ -269,6 +270,7 @@ void Max14906::initChannels() m_channelControls.insert(i, channel_control); m_readerThread->addDioChannel(i, channel); + connect(channel_control, &DioDigitalChannelController::iioEvent, m_tme, &ToolMenuEntry::iioEvent); connect(m_readerThread, &ReaderThread::channelDataChanged, channel_control, [this, i](int index, double value) { if(i == index) { diff --git a/plugins/swiot/src/readerthread.cpp b/plugins/swiot/src/readerthread.cpp index 5c19c223d0..4dd588a433 100644 --- a/plugins/swiot/src/readerthread.cpp +++ b/plugins/swiot/src/readerthread.cpp @@ -66,11 +66,13 @@ void ReaderThread::createDioChannelCommand(int index) [=, this](scopy::Command *cmd) { IioChannelAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } auto channel = tcmd->getChannel(); if(!channel) { + Q_EMIT iioEvent(IIO_ERROR); return; } int channelIndex = m_dioChannels.key(channel); @@ -87,6 +89,7 @@ void ReaderThread::createDioChannelCommand(int index) qCritical(CAT_SWIOT_MAX14906) << "Failed to acquire data on DioReaderThread " << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); }, Qt::QueuedConnection); m_cmdQueue->enqueue(dioChannelReadCommand); @@ -171,9 +174,11 @@ void ReaderThread::bufferRefillCommandFinished(scopy::Command *cmd) std::unique_lock lock(m_mutex); IioBufferRefill *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); return; } if(m_bufferInvalid) { + Q_EMIT iioEvent(IIO_ERROR, IIOCallType::STREAM); return; } if(tcmd->getReturnCode() > 0) { @@ -200,6 +205,7 @@ void ReaderThread::bufferRefillCommandFinished(scopy::Command *cmd) qDebug(CAT_SWIOT_AD74413R) << "Refill error " << QString(strerror(-tcmd->getReturnCode())); } start(); + Q_EMIT iioEvent(tcmd->getReturnCode(), IIOCallType::STREAM); } void ReaderThread::bufferCreateCommandFinished(scopy::Command *cmd) @@ -207,6 +213,7 @@ void ReaderThread::bufferCreateCommandFinished(scopy::Command *cmd) std::unique_lock lock(m_mutex); IioDeviceCreateBuffer *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() < 0) { @@ -216,6 +223,7 @@ void ReaderThread::bufferCreateCommandFinished(scopy::Command *cmd) m_bufferInvalid = false; start(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); } void ReaderThread::bufferCancelCommandFinished(scopy::Command *cmd) diff --git a/plugins/swiot/src/swiotcontroller.cpp b/plugins/swiot/src/swiotcontroller.cpp index a7f3eac5c5..9cc3b0f7e6 100644 --- a/plugins/swiot/src/swiotcontroller.cpp +++ b/plugins/swiot/src/swiotcontroller.cpp @@ -90,6 +90,7 @@ void SwiotController::startTemperatureTask() temperatureTask = new SwiotReadTemperatureTask(uri, this); temperatureTimer = new CyclicalTask(temperatureTask); connect(temperatureTask, &SwiotReadTemperatureTask::newTemperature, this, &SwiotController::readTemperature); + connect(temperatureTask, &SwiotReadTemperatureTask::iioEvent, this, &SwiotController::iioEvent); temperatureTimer->start(2000); m_temperatureReadEn = true; } @@ -102,6 +103,7 @@ void SwiotController::stopTemperatureTask() temperatureTask->requestInterruption(); temperatureTimer->stop(); disconnect(temperatureTask, &SwiotReadTemperatureTask::newTemperature, this, &SwiotController::readTemperature); + disconnect(temperatureTask, &SwiotReadTemperatureTask::iioEvent, this, &SwiotController::iioEvent); temperatureTimer->deleteLater(); temperatureTask->deleteLater(); m_temperatureReadEn = false; @@ -141,6 +143,7 @@ void SwiotController::writeModeCommandFinished(scopy::Command *cmd) { IioDeviceAttributeWrite *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() >= 0) { @@ -174,6 +177,7 @@ void SwiotController::readModeCommandFinished(scopy::Command *cmd) { IioDeviceAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() >= 0) { @@ -184,6 +188,7 @@ void SwiotController::readModeCommandFinished(scopy::Command *cmd) qDebug(CAT_SWIOT) << R"(Critical error: could not read mode attribute, error code:)" << tcmd->getReturnCode(); } + Q_EMIT iioEvent(tcmd->getReturnCode()); } void SwiotController::setIsRuntimeCtx(bool runtimeCtx) diff --git a/plugins/swiot/src/swiotplugin.cpp b/plugins/swiot/src/swiotplugin.cpp index 2ced510b72..ac26ab5ecb 100644 --- a/plugins/swiot/src/swiotplugin.cpp +++ b/plugins/swiot/src/swiotplugin.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "swiot_logging_categories.h" @@ -129,8 +130,16 @@ bool SWIOTPlugin::loadExtraButtons() bool SWIOTPlugin::loadIcon() { - m_icon = new QLabel(""); - m_icon->setStyleSheet("border-image: url(:/swiot/swiot_icon.svg);"); + QLabel *logo = new QLabel(); + QPixmap pixmap(":/gui/icons/scopy-default/icons/logo_analog.svg"); + int pixmapHeight = 14; + pixmap = pixmap.scaledToHeight(pixmapHeight, Qt::SmoothTransformation); + logo->setPixmap(pixmap); + + QLabel *footer = new QLabel("SWIOT1L"); + Style::setStyle(footer, style::properties::label::deviceIcon, true); + + m_icon = DeviceIconBuilder().shape(DeviceIconBuilder::SQUARE).headerWidget(logo).footerWidget(footer).build(); return true; } @@ -200,6 +209,8 @@ bool SWIOTPlugin::onDisconnect() tme->setTool(nullptr); } + disconnect(m_swiotController, &SwiotController::iioEvent, ad74413rTme, &ToolMenuEntry::iioEvent); + disconnect(m_swiotController, &SwiotController::iioEvent, configTme, &ToolMenuEntry::iioEvent); disconnect(dynamic_cast(configTme->tool()), &SwiotConfig::writeModeAttribute, this, &SWIOTPlugin::setCtxMode); disconnect(dynamic_cast(ad74413rTme->tool()), &Ad74413r::configBtnPressed, m_runtime, @@ -344,8 +355,10 @@ void SWIOTPlugin::setupToolList() ad74413rTme->setTool(new swiot::Ad74413r(m_param, ad74413rTme)); max14906Tme->setTool(new swiot::Max14906(m_param, max14906Tme)); faultsTme->setTool(new swiot::Faults(m_param, faultsTme)); + connect(m_swiotController, &SwiotController::iioEvent, ad74413rTme, &ToolMenuEntry::iioEvent); } else { - configTme->setTool(new swiot::SwiotConfig(m_param)); + configTme->setTool(new swiot::SwiotConfig(m_param, configTme)); + connect(m_swiotController, &SwiotController::iioEvent, configTme, &ToolMenuEntry::iioEvent); } connect(dynamic_cast(configTme->tool()), &SwiotConfig::writeModeAttribute, this, diff --git a/plugins/swiot/src/swiotreadtemperaturetask.cpp b/plugins/swiot/src/swiotreadtemperaturetask.cpp index 8cf2cd98e7..fbadd86d46 100644 --- a/plugins/swiot/src/swiotreadtemperaturetask.cpp +++ b/plugins/swiot/src/swiotreadtemperaturetask.cpp @@ -100,6 +100,7 @@ void SwiotReadTemperatureTask::readRawCommandFinished(Command *cmd) } IioChannelAttributeRead *tcmd = dynamic_cast(cmd); if(!tcmd) { + Q_EMIT iioEvent(IIO_ERROR); return; } if(tcmd->getReturnCode() >= 0) { @@ -116,6 +117,7 @@ void SwiotReadTemperatureTask::readRawCommandFinished(Command *cmd) qDebug(CAT_SWIOT) << "Error, could not read \"raw\" attribute from " << DEVICE_NAME << ". Temperature not available."; } + Q_EMIT iioEvent(tcmd->getReturnCode()); } void SwiotReadTemperatureTask::readScaleCommandFinished(Command *cmd)