chore: remove useless files

This commit is contained in:
x-tools-author 2024-03-27 15:28:44 +08:00
parent fa498769cf
commit b33cfa1b39
23 changed files with 0 additions and 5028 deletions

View File

@ -1,15 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsCanBusStudio.h"
xToolsCanBusStudio::xToolsCanBusStudio(QObject* parent)
: QThread(parent)
{}
xToolsCanBusStudio::~xToolsCanBusStudio() {}

View File

@ -1,19 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QThread>
class xToolsCanBusStudio : public QThread
{
Q_OBJECT
public:
xToolsCanBusStudio(QObject *parent = nullptr);
~xToolsCanBusStudio();
};

View File

@ -1,550 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsCanBusStudioUi.h"
#include "ui_xToolsCanBusStudioUi.h"
#include <QCanBus>
#include <QCheckBox>
#include <QDateTime>
#include <QLineEdit>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QVector>
#include "xToolsSettings.h"
const QLoggingCategory gLC("sak.canstudio");
xToolsCanBusStudioUi::xToolsCanBusStudioUi(QWidget* parent)
: QWidget{parent}
, ui(new Ui::xToolsCanBusStudioUi)
, mDevice(Q_NULLPTR)
{
if (!mSettings) {
mSettings = xToolsSettings::instance();
}
ui->setupUi(this);
initUi();
initSetting();
// Device is not connected.
updateUiState(false);
}
xToolsCanBusStudioUi::~xToolsCanBusStudioUi()
{
delete ui;
}
void xToolsCanBusStudioUi::initUi()
{
initUiSelectPlugin();
initUiSpecifyConfiguration();
initUiCanFrame();
initUiSendCanFrame();
}
void xToolsCanBusStudioUi::initUiSelectPlugin()
{
ui->pluginComboBox->clear();
ui->pluginComboBox->addItems(QCanBus::instance()->plugins());
ui->disconnectPushButton->setEnabled(false);
ui->connectPushButton->setEnabled(true);
connect(ui->pluginComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onPluginChanged);
connect(ui->disconnectPushButton,
&QPushButton::clicked,
this,
&xToolsCanBusStudioUi::onDisconnectClicked);
connect(ui->connectPushButton, &QPushButton::clicked, this, &xToolsCanBusStudioUi::onConnectClicked);
}
void xToolsCanBusStudioUi::initUiSpecifyConfiguration()
{
setOptions(ui->loopbackComboBox, true);
setOptions(ui->receivOwnComboBox, true);
setOptions(ui->canFdComboBox, false);
setBitRates(ui->bitrateComboBox, false);
setBitRates(ui->dataBitrateComboBox, true);
ui->interfaceNameComboBox->lineEdit()->setPlaceholderText(tr("can0"));
connect(ui->customConfigurationCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onCustomConfigurationChanged);
connect(ui->loopbackComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onLoopbackIndexChanged);
connect(ui->receivOwnComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onReceiveOwnIndexChanged);
connect(ui->canFdComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onCanFdIndexChanged);
connect(ui->bitrateComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onBitrateChanged);
connect(ui->dataBitrateComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onDataBitrateChanged);
connect(ui->customBitrateCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onCustomBitrateChanged);
connect(ui->customDataBitrateCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onCustomDataBitrateChanged);
}
void xToolsCanBusStudioUi::initUiCanFrame()
{
ui->frameTypeComboBox->clear();
ui->frameTypeComboBox->addItem(tr("DataFrame"), QCanBusFrame::DataFrame);
ui->frameTypeComboBox->addItem(tr("ErrorFrame"), QCanBusFrame::ErrorFrame);
ui->frameTypeComboBox->addItem(tr("RemoteRequestFrame"), QCanBusFrame::RemoteRequestFrame);
connect(ui->frameTypeComboBox,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsCanBusStudioUi::onFrameTypeChanged);
connect(ui->extendedFormatCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onExtendedFormatChanged);
connect(ui->flexibleDataRateCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onFlexibleDataRateChanged);
connect(ui->bitrateSwitchCheckBox,
&QCheckBox::clicked,
this,
&xToolsCanBusStudioUi::onBitrateSwitchChanged);
}
void xToolsCanBusStudioUi::initUiSendCanFrame()
{
const QString inputTips = tr("Hex");
ui->frameIdComboBox->lineEdit()->setPlaceholderText(inputTips);
ui->payloadComboBox->lineEdit()->setPlaceholderText(inputTips);
connect(ui->sendPushButton, &QPushButton::clicked, this, &xToolsCanBusStudioUi::onSendButtonClicked);
}
void xToolsCanBusStudioUi::initSetting()
{
initSettingSelectPlugin();
initSettingSpecifyConfiguration();
initSettingCanFrame();
initSettingSendCanFrame();
}
void xToolsCanBusStudioUi::initSettingSelectPlugin()
{
setCurrentIndex(ui->pluginComboBox, mSettingKeyCtx.pluginIndex);
}
void xToolsCanBusStudioUi::initSettingSpecifyConfiguration()
{
QString name = mSettings->value(mSettingKeyCtx.interfaceName).toString();
ui->interfaceNameComboBox->lineEdit()->setText(name);
setChecked(ui->customConfigurationCheckBox, mSettingKeyCtx.customConfiguration);
setCurrentIndex(ui->loopbackComboBox, mSettingKeyCtx.loopback);
setCurrentIndex(ui->receivOwnComboBox, mSettingKeyCtx.receiveOwn);
setCurrentIndex(ui->bitrateComboBox, mSettingKeyCtx.bitrate);
setCurrentIndex(ui->canFdComboBox, mSettingKeyCtx.canFd);
setCurrentIndex(ui->dataBitrateComboBox, mSettingKeyCtx.dataBitRate);
setChecked(ui->customBitrateCheckBox, mSettingKeyCtx.customBitRate);
setChecked(ui->customDataBitrateCheckBox, mSettingKeyCtx.customDataBitRate);
bool enable = mSettings->value(mSettingKeyCtx.customConfiguration).toBool();
setCustomConfigurationEnable(enable);
}
void xToolsCanBusStudioUi::initSettingCanFrame()
{
setCurrentIndex(ui->frameTypeComboBox, mSettingKeyCtx.frameTypeIndex);
setChecked(ui->extendedFormatCheckBox, mSettingKeyCtx.extendedFormat);
setChecked(ui->flexibleDataRateCheckBox, mSettingKeyCtx.flexibleDataRate);
setChecked(ui->bitrateSwitchCheckBox, mSettingKeyCtx.bitrateSwitch);
onFrameTypeChanged();
}
void xToolsCanBusStudioUi::initSettingSendCanFrame() {}
void xToolsCanBusStudioUi::onPluginChanged()
{
int index = ui->pluginComboBox->currentIndex();
mSettings->setValue(mSettingKeyCtx.pluginIndex, index);
}
void xToolsCanBusStudioUi::onDisconnectClicked()
{
if (mDevice) {
mDevice->disconnectDevice();
mDevice->deleteLater();
mDevice = Q_NULLPTR;
}
updateUiState(false);
}
void xToolsCanBusStudioUi::onConnectClicked()
{
const QString pluginName = ui->pluginComboBox->currentText();
const QString interfaceName = ui->interfaceNameComboBox->currentText();
if (interfaceName.isEmpty()) {
QMessageBox::warning(this,
tr("Interface Name is Empty"),
tr("Interface name is empty, "
"please input the name then try again!"));
return;
}
QString errorString;
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
mDevice = QCanBus::instance()->createDevice(pluginName, interfaceName, &errorString);
if (!mDevice) {
qCWarning(gLC) << errorString;
return;
}
#else
mDevice = QCanBus::instance()->createDevice(pluginName.toLatin1(), interfaceName);
if (!mDevice) {
qCWarning(gLC) << tr("Create device failed!");
return;
}
#endif
connect(mDevice, &QCanBusDevice::errorOccurred, this, &xToolsCanBusStudioUi::onErrorOccure);
connect(mDevice, &QCanBusDevice::framesReceived, this, &xToolsCanBusStudioUi::onFrameReceived);
connect(mDevice, &QCanBusDevice::framesWritten, this, &xToolsCanBusStudioUi::onFrameWritten);
auto items = configurationItems();
for (auto& item : items) {
mDevice->setConfigurationParameter(item.first, item.second);
}
if (!mDevice->connectDevice()) {
qCWarning(gLC) << tr("Connection error: %1").arg(mDevice->errorString());
QMessageBox::warning(this,
tr("Connection Error"),
tr("Connection error: %1").arg(mDevice->errorString()));
mDevice->deleteLater();
mDevice = Q_NULLPTR;
return;
}
mSettings->setValue(mSettingKeyCtx.interfaceName, interfaceName);
updateUiState(true);
}
void xToolsCanBusStudioUi::onLoopbackIndexChanged(int index)
{
mSettings->setValue(mSettingKeyCtx.loopback, index);
}
void xToolsCanBusStudioUi::onCustomConfigurationChanged()
{
bool checked = ui->customConfigurationCheckBox->isChecked();
setCustomConfigurationEnable(checked);
mSettings->setValue(mSettingKeyCtx.customConfiguration, checked);
}
void xToolsCanBusStudioUi::onReceiveOwnIndexChanged(int index)
{
mSettings->setValue(mSettingKeyCtx.receiveOwn, index);
}
void xToolsCanBusStudioUi::onCanFdIndexChanged(int index)
{
mSettings->setValue(mSettingKeyCtx.canFd, index);
}
void xToolsCanBusStudioUi::onBitrateChanged(int index)
{
mSettings->setValue(mSettingKeyCtx.bitrate, index);
}
void xToolsCanBusStudioUi::onDataBitrateChanged(int index)
{
mSettings->setValue(mSettingKeyCtx.dataBitRate, index);
}
void xToolsCanBusStudioUi::onCustomBitrateChanged()
{
bool checked = ui->customBitrateCheckBox->isChecked();
mSettings->setValue(mSettingKeyCtx.customBitRate, checked);
ui->bitrateComboBox->setEditable(checked);
}
void xToolsCanBusStudioUi::onCustomDataBitrateChanged()
{
bool checked = ui->customDataBitrateCheckBox->isChecked();
mSettings->setValue(mSettingKeyCtx.customDataBitRate, checked);
ui->dataBitrateComboBox->setEditable(true);
}
void xToolsCanBusStudioUi::onFrameTypeChanged()
{
int index = ui->frameTypeComboBox->currentIndex();
mSettings->setValue(mSettingKeyCtx.frameTypeIndex, index);
int type = ui->frameTypeComboBox->currentData().toInt();
if (type == QCanBusFrame::DataFrame) {
ui->flexibleDataRateCheckBox->setEnabled(true);
bool checked = ui->flexibleDataRateCheckBox->isChecked();
ui->bitrateSwitchCheckBox->setEnabled(checked);
} else {
ui->flexibleDataRateCheckBox->setEnabled(false);
ui->bitrateSwitchCheckBox->setEnabled(false);
}
}
void xToolsCanBusStudioUi::onExtendedFormatChanged()
{
bool checked = ui->extendedFormatCheckBox->isChecked();
mSettings->setValue(mSettingKeyCtx.extendedFormat, checked);
}
void xToolsCanBusStudioUi::onFlexibleDataRateChanged()
{
bool checked = ui->flexibleDataRateCheckBox->isChecked();
mSettings->setValue(mSettingKeyCtx.flexibleDataRate, checked);
ui->bitrateSwitchCheckBox->setEnabled(checked);
}
void xToolsCanBusStudioUi::onBitrateSwitchChanged()
{
bool checked = ui->bitrateSwitchCheckBox->isChecked();
mSettings->setValue(mSettingKeyCtx.bitrateSwitch, checked);
}
void xToolsCanBusStudioUi::onSendButtonClicked()
{
if (!mDevice) {
QString title = tr("Device is Not Ready");
QString msg = tr("Device is not ready,"
" please connect the device then try angin!");
QMessageBox::warning(this, title, msg);
return;
}
const uint frameId = ui->frameIdComboBox->currentText().toUInt(Q_NULLPTR, 16);
QString data = ui->payloadComboBox->currentText().trimmed();
const QByteArray payload = QByteArray::fromHex(data.remove(QLatin1Char(' ')).toLatin1());
QCanBusFrame frame = QCanBusFrame(frameId, payload);
frame.setExtendedFrameFormat(ui->extendedFormatCheckBox->isChecked());
if (ui->flexibleDataRateCheckBox->isEnabled()) {
frame.setFlexibleDataRateFormat(ui->flexibleDataRateCheckBox->isChecked());
}
if (ui->bitrateSwitchCheckBox->isEnabled()) {
frame.setBitrateSwitch(ui->bitrateSwitchCheckBox);
}
if (mDevice->writeFrame(frame)) {
QString view;
if (frame.frameType() == QCanBusFrame::ErrorFrame) {
view = mDevice->interpretErrorFrame(frame);
} else {
view = frame.toString();
}
QString flag = QString("<font color=green>[Tx] </font>");
outputMessage(flag + view);
} else {
qCWarning(gLC) << mDevice->errorString();
}
}
void xToolsCanBusStudioUi::onErrorOccure(QCanBusDevice::CanBusError error)
{
if (mDevice) {
Q_UNUSED(error);
QMessageBox::warning(this, tr("Error Occure"), mDevice->errorString());
onDisconnectClicked();
}
}
void xToolsCanBusStudioUi::onFrameReceived()
{
if (!mDevice) {
return;
}
while (mDevice->framesAvailable()) {
const QCanBusFrame frame = mDevice->readFrame();
QString view;
if (frame.frameType() == QCanBusFrame::ErrorFrame) {
view = mDevice->interpretErrorFrame(frame);
} else {
view = frame.toString();
}
QString flag = QString("<font color=blue>[Rx] </font>");
outputMessage(flag + view);
}
}
void xToolsCanBusStudioUi::onFrameWritten(qint64 framesCount)
{
qCInfo(gLC) << framesCount;
}
void xToolsCanBusStudioUi::setOptions(QComboBox* cb, bool usingUnspecified)
{
if (cb) {
cb->clear();
if (usingUnspecified) {
cb->addItem(tr("unspecified"), QVariant());
}
cb->addItem(tr("false"), QVariant(false));
cb->addItem(tr("true"), QVariant(true));
}
}
void xToolsCanBusStudioUi::setCurrentIndex(QComboBox* cb, const QString& key)
{
int index = mSettings->value(key).toInt();
if (index >= 0 && index <= cb->count() - 1) {
cb->setCurrentIndex(index);
}
}
void xToolsCanBusStudioUi::setChecked(QCheckBox* cb, const QString& key)
{
if (cb) {
bool checked = mSettings->value(key).toBool();
cb->setChecked(checked);
}
}
void xToolsCanBusStudioUi::setCustomConfigurationEnable(bool enable)
{
ui->errorFilterComboBox->setEnabled(enable);
ui->loopbackComboBox->setEnabled(enable);
ui->receivOwnComboBox->setEnabled(enable);
ui->canFdComboBox->setEnabled(enable);
ui->bitrateComboBox->setEnabled(enable);
ui->dataBitrateComboBox->setEnabled(enable);
ui->customBitrateCheckBox->setEnabled(enable);
ui->customDataBitrateCheckBox->setEnabled(enable);
}
void xToolsCanBusStudioUi::outputMessage(const QString& msg)
{
QString datetimeString =
#if 0
QDateTime::currentDateTime().toString("yyyy/MM/dd hh:mm:ss.zzz");
#else
QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
#endif
QString cookedMsg;
cookedMsg = QString("<font color=silver>%1 </font>").arg(datetimeString);
cookedMsg += msg;
ui->textBrowser->append(cookedMsg);
}
void xToolsCanBusStudioUi::updateUiState(bool connected)
{
ui->connectPushButton->setEnabled(!connected);
ui->disconnectPushButton->setEnabled(connected);
ui->interfaceNameComboBox->setEnabled(!connected);
ui->customConfigurationCheckBox->setEnabled(!connected);
if (connected) {
setCustomConfigurationEnable(false);
} else {
bool checked = ui->customConfigurationCheckBox->isChecked();
setCustomConfigurationEnable(checked);
}
}
QVector<xToolsCanBusStudioUi::ConfigurationItem> xToolsCanBusStudioUi::configurationItems()
{
QVector<xToolsCanBusStudioUi::ConfigurationItem> items;
ConfigurationItem item;
QString errorFilter = ui->errorFilterComboBox->currentText();
if (!errorFilter.isEmpty()) {
bool ok = false;
int dec = errorFilter.toInt(&ok);
if (ok) {
item.first = QCanBusDevice::ErrorFilterKey;
item.second = QVariant::fromValue(QCanBusFrame::FrameErrors(dec));
items.append(item);
}
}
item.first = QCanBusDevice::LoopbackKey;
item.second = ui->loopbackComboBox->currentData();
items.append(item);
item.first = QCanBusDevice::ReceiveOwnKey;
item.second = ui->receivOwnComboBox->currentData();
items.append(item);
item.first = QCanBusDevice::CanFdKey;
item.second = ui->canFdComboBox->currentData();
items.append(item);
item.first = QCanBusDevice::BitRateKey;
item.second = ui->bitrateComboBox->currentData();
items.append(item);
item.first = QCanBusDevice::DataBitRateKey;
item.second = ui->dataBitrateComboBox->currentData();
items.append(item);
return items;
}
void xToolsCanBusStudioUi::setBitRates(QComboBox* cb, bool isFlexibleDataRateEnable)
{
if (!cb) {
return;
}
const QVector<int> rates = {10000, 20000, 50000, 100000, 125000, 250000, 500000, 800000, 1000000};
const QVector<int> dataRates = {2000000, 4000000, 8000000};
cb->clear();
for (int rate : rates) {
cb->addItem(QString::number(rate), rate);
}
if (isFlexibleDataRateEnable) {
for (int rate : dataRates) {
cb->addItem(QString::number(rate), rate);
}
}
}

View File

@ -1,108 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QCanBusDevice>
#include <QCanBusFrame>
#include <QCheckBox>
#include <QComboBox>
#include <QSettings>
#include <QVector>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class xToolsCanBusStudioUi;
}
QT_END_NAMESPACE
class xToolsCanBusStudioUi : public QWidget
{
Q_OBJECT
typedef QPair<QCanBusDevice::ConfigurationKey, QVariant> ConfigurationItem;
public:
Q_INVOKABLE xToolsCanBusStudioUi(QWidget *parent = Q_NULLPTR);
~xToolsCanBusStudioUi();
private:
struct
{
const QString pluginIndex = "CANStudio/pluginIndex";
const QString interfaceName = "CANStudio/interfaceName";
const QString customConfiguration = "CANStudio/customConfiguration";
const QString loopback = "CANStudio/loopback";
const QString receiveOwn = "CANStudio/receiveOwn";
const QString canFd = "CANStudio/canFd";
const QString bitrate = "CANStudio/bitrate";
const QString dataBitRate = "CANStudio/dataBitRate";
const QString customBitRate = "CANStudio/customBitRate";
const QString customDataBitRate = "CANStudio/customDataBitRate";
const QString frameTypeIndex = "CANStudio/frameTypeIndex";
const QString extendedFormat = "CANStudio/extendedFormat";
const QString flexibleDataRate = "CANStudio/fleibleDataRate";
const QString bitrateSwitch = "CANStudio/bitrateSwitch";
} mSettingKeyCtx;
private:
Ui::xToolsCanBusStudioUi *ui;
QSettings *mSettings{nullptr};
QCanBusDevice *mDevice{nullptr};
private:
void initUi();
void initUiSelectPlugin();
void initUiSpecifyConfiguration();
void initUiCanFrame();
void initUiSendCanFrame();
void initSetting();
void initSettingSelectPlugin();
void initSettingSpecifyConfiguration();
void initSettingCanFrame();
void initSettingSendCanFrame();
// These are slots.
void onPluginChanged();
void onDisconnectClicked();
void onConnectClicked();
void onCustomConfigurationChanged();
void onLoopbackIndexChanged(int index);
void onReceiveOwnIndexChanged(int index);
void onCanFdIndexChanged(int index);
void onBitrateChanged(int index);
void onDataBitrateChanged(int index);
void onCustomBitrateChanged();
void onCustomDataBitrateChanged();
void onFrameTypeChanged();
void onExtendedFormatChanged();
void onFlexibleDataRateChanged();
void onBitrateSwitchChanged();
void onSendButtonClicked();
// Slots about CAN bus device
void onErrorOccure(QCanBusDevice::CanBusError error);
void onFrameReceived();
void onFrameWritten(qint64 framesCount);
private:
void setOptions(QComboBox *cb, bool usingUnspecified);
void setCurrentIndex(QComboBox *cb, const QString &key);
void setBitRates(QComboBox *cb, bool isFlexibleDataRateEnable);
void setChecked(QCheckBox *cb, const QString &key);
void setCustomConfigurationEnable(bool enable);
void outputMessage(const QString &msg);
void updateUiState(bool connected);
QVector<ConfigurationItem> configurationItems();
};

View File

@ -1,329 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>xToolsCanBusStudioUi</class>
<widget class="QWidget" name="xToolsCanBusStudioUi">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>691</width>
<height>634</height>
</rect>
</property>
<property name="windowTitle">
<string>CANBus Studio</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="0" rowspan="2">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>CAN frame</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="bitrateSwitchCheckBox">
<property name="text">
<string>Bitrate switch</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Frame type</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="flexibleDataRateCheckBox">
<property name="text">
<string>Flexible data-rate</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="frameTypeComboBox"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="extendedFormatCheckBox">
<property name="text">
<string>Extended format</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="5" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Send CAN frame</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Frame ID</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="frameIdComboBox">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Payload</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="payloadComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="sendPushButton">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" rowspan="5">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Console</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextBrowser" name="textBrowser"/>
</item>
</layout>
</widget>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Select plugin</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QComboBox" name="pluginComboBox"/>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="disconnectPushButton">
<property name="text">
<string>Disconnect</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="connectPushButton">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Specify configuration</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="10" column="0" colspan="2">
<widget class="QCheckBox" name="customDataBitrateCheckBox">
<property name="text">
<string>Custom data bitrate</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="dataBitrateComboBox"/>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="bitrateComboBox"/>
</item>
<item row="9" column="0" colspan="2">
<widget class="QCheckBox" name="customBitrateCheckBox">
<property name="text">
<string>Custom bitrate</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="errorFilterComboBox">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>CAN FD</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Loopback</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bitrate</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="interfaceNameComboBox">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="loopbackComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="canFdComboBox"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_10">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Data bitrate</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="receivOwnComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Receive own</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Error filter</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="customConfigurationCheckBox">
<property name="text">
<string>Custom configurations</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,25 +0,0 @@
file(GLOB_RECURSE SOURCES_H "${CMAKE_SOURCE_DIR}/Source/CANBusStudio/*.h")
file(GLOB_RECURSE SOURCES_UI "${CMAKE_SOURCE_DIR}/Source/CANBusStudio/*.ui")
file(GLOB_RECURSE SOURCES_CPP "${CMAKE_SOURCE_DIR}/Source/CANBusStudio/*.cpp")
list(APPEND ALL_SOURCE ${SOURCES_H})
list(APPEND ALL_SOURCE ${SOURCES_UI})
list(APPEND ALL_SOURCE ${SOURCES_CPP})
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsSettings.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsSettings.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsInterface.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsInterface.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsTranslator.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsTranslator.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsUi.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsMainWindow.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsMainWindow.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/xTools.qrc)
x_tools_add_executable("CANBusStudio" ${ALL_SOURCE})
x_tools_set_target_properties(CANBusStudio)
x_tools_deploy_qt(CANBusStudio)
target_link_libraries(CANBusStudio PRIVATE glog::glog)
target_link_libraries(CANBusStudio PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(CANBusStudio PRIVATE Qt${QT_VERSION_MAJOR}::SerialBus)

View File

@ -1,16 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsCanBusStudioUi.h"
#include "xToolsUi.h"
int main(int argc, char* argv[])
{
const QString appName = QObject::tr("CAN Bus Studio");
return xToolsExec<xToolsCanBusStudioUi>(argc, argv, appName);
}

View File

@ -1,149 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsBleScanner.h"
#include <QBluetoothDeviceInfo>
#include <QDebug>
#include <QtGlobal>
#define BLE_ERR_SIG void (QBluetoothDeviceDiscoveryAgent::*)(QBluetoothDeviceDiscoveryAgent::Error)
xToolsBleScanner::xToolsBleScanner(QObject* parent)
: QThread(parent)
, m_discover(Q_NULLPTR)
{}
xToolsBleScanner::~xToolsBleScanner() {}
void xToolsBleScanner::startDiscover()
{
start();
}
void xToolsBleScanner::stopDiscover()
{
exit();
}
bool xToolsBleScanner::isActive()
{
return isRunning();
}
QVariant xToolsBleScanner::deviceInfo(int index)
{
m_deviceInfoListMutex.lock();
if (index >= 0 && index < m_deviceInfoList.length()) {
QBluetoothDeviceInfo info = m_deviceInfoList.at(index);
return QVariant::fromValue<QBluetoothDeviceInfo>(info);
}
m_deviceInfoListMutex.unlock();
return QVariant();
}
QString xToolsBleScanner::deviceName(const QVariant& deviceInfo)
{
auto cookedInfo = deviceInfo.value<QBluetoothDeviceInfo>();
return cookedInfo.name();
}
void xToolsBleScanner::run()
{
m_discover = new QBluetoothDeviceDiscoveryAgent();
connect(m_discover,
&QBluetoothDeviceDiscoveryAgent::finished,
this,
&xToolsBleScanner::onDiscoveryFinished);
connect(m_discover,
&QBluetoothDeviceDiscoveryAgent::errorOccurred,
this,
&xToolsBleScanner::onDiscoveryErrorOccurred);
connect(m_discover,
&QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this,
&xToolsBleScanner::onDiscoveryDeviceDiscovered);
// 10s-1minute
int interval = m_timeoutInterval < 10 ? 10 : m_timeoutInterval;
interval = interval > 120 ? 120 : interval;
m_discover->setLowEnergyDiscoveryTimeout(interval * 1000);
m_deviceInfoListMutex.lock();
m_deviceInfoList.clear();
m_deviceInfoListMutex.unlock();
m_discover->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
exec();
}
void xToolsBleScanner::onDiscoveryFinished()
{
emit devicesInfoListChanged();
exit();
}
void xToolsBleScanner::onDiscoveryErrorOccurred(QBluetoothDeviceDiscoveryAgent::Error error)
{
Q_UNUSED(error);
qWarning() << "QBluetoothDeviceDiscoveryAgent error:" << m_discover->errorString();
exit();
emit errorOccurred(m_discover->errorString());
}
void xToolsBleScanner::onDiscoveryDeviceDiscovered(const QBluetoothDeviceInfo& info)
{
const QString name = info.name();
qInfo() << "new ble device:" << name;
if (!m_nameFiltter.isEmpty()) {
if (!name.contains(m_nameFiltter)) {
qInfo() << "device is ignored:" << name;
return;
}
}
m_deviceInfoListMutex.lock();
m_deviceInfoList.append(info);
m_deviceInfoListMutex.unlock();
emit deviceDiscovered(info);
}
QVariantList xToolsBleScanner::devicesInfoList()
{
QVariantList list;
m_deviceInfoListMutex.lock();
for (auto& info : m_deviceInfoList) {
list.append(QVariant::fromValue(info));
}
m_deviceInfoListMutex.unlock();
return list;
}
int xToolsBleScanner::timeoutInterval()
{
return m_timeoutInterval;
}
void xToolsBleScanner::setTimeoutInterval(int interval)
{
m_timeoutInterval = interval;
emit timeoutIntervalChanged();
}
QString xToolsBleScanner::namefiltter()
{
return m_nameFiltter;
}
void xToolsBleScanner::setNameFiltter(const QString& flag)
{
m_nameFiltter = flag;
emit filtterNameChanged();
}

View File

@ -1,71 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothDeviceInfo>
#include <QLoggingCategory>
#include <QMutex>
#include <QThread>
#include <QVariant>
class xToolsBleScanner : public QThread
{
Q_OBJECT
// clang-format off
Q_PROPERTY(QVariantList deviceInfoList READ devicesInfoList NOTIFY devicesInfoListChanged)
Q_PROPERTY(int timeoutInterval READ timeoutInterval WRITE setTimeoutInterval NOTIFY timeoutIntervalChanged)
Q_PROPERTY(QString namefiltter READ namefiltter WRITE setNameFiltter NOTIFY filtterNameChanged)
// clang-format on
public:
explicit xToolsBleScanner(QObject *parent = nullptr);
~xToolsBleScanner();
public:
Q_INVOKABLE void startDiscover();
Q_INVOKABLE void stopDiscover();
Q_INVOKABLE bool isActive();
Q_INVOKABLE QVariant deviceInfo(int index);
Q_INVOKABLE QString deviceName(const QVariant &deviceInfo);
signals:
void deviceDiscovered(const QBluetoothDeviceInfo &info);
void errorOccurred(const QString &errStr);
protected:
virtual void run() override;
private:
QBluetoothDeviceDiscoveryAgent *m_discover;
QMutex m_deviceInfoListMutex;
private:
void onDiscoveryFinished();
void onDiscoveryErrorOccurred(QBluetoothDeviceDiscoveryAgent::Error error);
void onDiscoveryDeviceDiscovered(const QBluetoothDeviceInfo &info);
public:
QVariantList devicesInfoList();
int timeoutInterval();
void setTimeoutInterval(int interval);
QString namefiltter();
void setNameFiltter(const QString &flag);
signals:
void devicesInfoListChanged();
void enableRefreshChanged();
void timeoutIntervalChanged();
void filtterNameChanged();
private:
QVector<QBluetoothDeviceInfo> m_deviceInfoList;
int m_timeoutInterval{120};
QString m_nameFiltter{""};
};

View File

@ -1,101 +0,0 @@
/***************************************************************************************************
* Copyright 2023 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsBleDeviceInfoComboBox.h"
#include <QBluetoothDeviceInfo>
#include <QMessageBox>
xToolsBleDeviceInfoComboBox::xToolsBleDeviceInfoComboBox(QWidget* parent)
: xToolsComboBox(parent)
, mScanner(Q_NULLPTR)
{
mScanner = new xToolsBleScanner(this);
connect(mScanner, &xToolsBleScanner::finished, this, &xToolsBleDeviceInfoComboBox::onFinished);
connect(mScanner, &xToolsBleScanner::started, this, &xToolsBleDeviceInfoComboBox::started);
connect(mScanner,
&xToolsBleScanner::deviceDiscovered,
this,
&xToolsBleDeviceInfoComboBox::onDeviceDiscovered);
connect(mScanner,
&xToolsBleScanner::errorOccurred,
this,
&xToolsBleDeviceInfoComboBox::onErrorOccurred);
}
xToolsBleDeviceInfoComboBox::~xToolsBleDeviceInfoComboBox()
{
mScanner->stopDiscover();
}
void xToolsBleDeviceInfoComboBox::startDiscover()
{
clear();
mScanner->startDiscover();
}
void xToolsBleDeviceInfoComboBox::stopDiscover()
{
mScanner->stopDiscover();
}
bool xToolsBleDeviceInfoComboBox::isActive()
{
return mScanner->isActive();
return false;
}
void xToolsBleDeviceInfoComboBox::setTimeoutInterval(int interval)
{
#if 0
mScanner->setTimeoutInterval(interval);
#endif
}
void xToolsBleDeviceInfoComboBox::setNameFiltter(const QString& filtter)
{
mScanner->setNameFiltter(filtter);
}
void xToolsBleDeviceInfoComboBox::changeEvent(QEvent* event)
{
xToolsComboBox::changeEvent(event);
if ((event->type() == QEvent::EnabledChange) && isEnabled()) {
onFinished();
}
}
void xToolsBleDeviceInfoComboBox::onFinished()
{
if (!isEnabled()) {
return;
}
clear();
auto infos = mScanner->devicesInfoList();
for (auto& info : infos) {
QString name = mScanner->deviceName(info);
addItem(name, info);
}
emit finished();
}
void xToolsBleDeviceInfoComboBox::onDeviceDiscovered(const QBluetoothDeviceInfo& info)
{
if (!isEnabled()) {
return;
}
addItem(info.name(), QVariant::fromValue(info));
}
void xToolsBleDeviceInfoComboBox::onErrorOccurred(const QString& errStr)
{
QMessageBox::warning(this, tr("Error Occurred"), errStr);
}

View File

@ -1,42 +0,0 @@
/***************************************************************************************************
* Copyright 2023 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QEvent>
#include "xToolsBleScanner.h"
#include "xToolsComboBox.h"
class xToolsBleDeviceInfoComboBox : public xToolsComboBox
{
Q_OBJECT
public:
xToolsBleDeviceInfoComboBox(QWidget *parent = Q_NULLPTR);
~xToolsBleDeviceInfoComboBox();
void startDiscover();
void stopDiscover();
bool isActive();
void setTimeoutInterval(int interval);
void setNameFiltter(const QString &filtter);
signals:
void finished();
void started();
protected:
virtual void changeEvent(QEvent *event) override;
private:
xToolsBleScanner *mScanner;
private slots:
void onFinished();
void onDeviceDiscovered(const QBluetoothDeviceInfo &info);
void onErrorOccurred(const QString &errStr);
};

View File

@ -1,27 +0,0 @@
file(GLOB_RECURSE SOURCE_H "${CMAKE_SOURCE_DIR}/Source/ModbusStudio/*.h")
file(GLOB_RECURSE SOURCE_UI "${CMAKE_SOURCE_DIR}/Source/ModbusStudio/*.ui")
file(GLOB_RECURSE SOURCE_CPP "${CMAKE_SOURCE_DIR}/Source/ModbusStudio/*.cpp")
list(APPEND ALL_SOURCE ${SOURCE_H})
list(APPEND ALL_SOURCE ${SOURCE_UI})
list(APPEND ALL_SOURCE ${SOURCE_CPP})
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsSettings.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsSettings.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsInterface.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsInterface.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsTranslator.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/Common/xToolsTranslator.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsUi.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsMainWindow.h)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/Source/Common/CommonUI/xToolsMainWindow.cpp)
list(APPEND ALL_SOURCE ${CMAKE_SOURCE_DIR}/xTools.qrc)
x_tools_add_executable("ModbusStudio" ${ALL_SOURCE})
x_tools_set_target_properties(ModbusStudio)
x_tools_deploy_qt(ModbusStudio)
target_link_libraries(ModbusStudio PRIVATE glog::glog)
target_link_libraries(ModbusStudio PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(ModbusStudio PRIVATE Qt${QT_VERSION_MAJOR}::Network)
target_link_libraries(ModbusStudio PRIVATE Qt${QT_VERSION_MAJOR}::SerialBus)
target_link_libraries(ModbusStudio PRIVATE Qt${QT_VERSION_MAJOR}::SerialPort)

View File

@ -1,346 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsModbusStudio.h"
#include <QCoreApplication>
#include <QDebug>
#include <QModbusTcpClient>
#include <QModbusTcpServer>
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
#include <QModbusRtuSerialMaster>
#include <QModbusRtuSerialSlave>
#else
#include <QModbusRtuSerialClient>
#include <QModbusRtuSerialServer>
#endif
xToolsModbusStudio::xToolsModbusStudio(QObject *parent)
: QObject(parent)
{}
xToolsModbusStudio::~xToolsModbusStudio() {}
xToolsModbusStudio *xToolsModbusStudio::Instance()
{
static xToolsModbusStudio *factory = Q_NULLPTR;
if (!factory) {
factory = new xToolsModbusStudio(qApp);
}
return factory;
}
const QString xToolsModbusStudio::TypeName(int type)
{
if (type == kModbusRtuSerialClient) {
return tr("RTU Client");
} else if (type == kModbusRtuSerialServer) {
return tr("RTU Server");
} else if (type == kModbusTcpClient) {
return tr("TCP Client");
} else if (type == kModbusTcpServer) {
return tr("TCP Server");
}
Q_ASSERT_X(false, __FUNCTION__, "Unknown modebus device type");
qWarning() << "Unknown modebus device type";
return "Unknown";
}
QModbusDevice *xToolsModbusStudio::CreateDevice(int type)
{
if (type == kModbusRtuSerialClient) {
qInfo() << "Create rtu serial client.";
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
return new QModbusRtuSerialMaster(this);
#else
return new QModbusRtuSerialClient(this);
#endif
} else if (type == kModbusRtuSerialServer) {
qInfo() << "Create rtu serial server.";
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
return new QModbusRtuSerialSlave(this);
#else
return new QModbusRtuSerialServer(this);
#endif
} else if (type == kModbusTcpClient) {
qInfo() << "Create tcp client.";
return new QModbusTcpClient();
} else if (type == kModbusTcpServer) {
qInfo() << "Create tcp server.";
return new QModbusTcpServer();
}
Q_ASSERT_X(false, __FUNCTION__, "Unknown modebus device type");
qWarning() << "Unknown modebus device type";
return Q_NULLPTR;
}
bool xToolsModbusStudio::IsTcpDevice(QModbusDevice *modbus_device)
{
if (modbus_device) {
if (qobject_cast<QModbusTcpClient *>(modbus_device)) {
return true;
} else if (qobject_cast<QModbusTcpServer *>(modbus_device)) {
return true;
}
}
return false;
}
bool xToolsModbusStudio::IsRtuSerialDevice(QModbusDevice *modbus_device)
{
if (modbus_device) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
if (qobject_cast<QModbusRtuSerialClient *>(modbus_device)) {
#else
if (qobject_cast<QModbusRtuSerialMaster *>(modbus_device)) {
#endif
return true;
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
} else if (qobject_cast<QModbusRtuSerialServer *>(modbus_device)) {
#else
} else if (qobject_cast<QModbusRtuSerialSlave *>(modbus_device)) {
#endif
return true;
}
}
return false;
}
bool xToolsModbusStudio::IsTcpDeviceType(int type)
{
bool is_tcp = (type == kModbusTcpClient);
is_tcp |= (type == kModbusTcpServer);
return is_tcp;
}
bool xToolsModbusStudio::IsRtuSerialDeviceType(int type)
{
bool is_rtu = (type == kModbusRtuSerialClient);
is_rtu |= (type == kModbusRtuSerialServer);
return is_rtu;
}
bool xToolsModbusStudio::IsServerDevice(QModbusDevice *modbus_device)
{
if (modbus_device && qobject_cast<QModbusServer *>(modbus_device)) {
return true;
}
return false;
}
bool xToolsModbusStudio::IsClientDevice(QModbusDevice *modbus_device)
{
if (modbus_device && qobject_cast<QModbusClient *>(modbus_device)) {
return true;
}
return false;
}
bool xToolsModbusStudio::ConnectDeivce(QModbusDevice *modbus_device)
{
if (modbus_device) {
return modbus_device->connectDevice();
}
return false;
}
bool xToolsModbusStudio::IsConnected(QModbusDevice *modbus_device)
{
if (modbus_device) {
if (modbus_device->state() == QModbusDevice::ConnectedState) {
return true;
}
}
return false;
}
bool xToolsModbusStudio::IsValidModbusReply(QModbusReply *reply)
{
if (reply && !reply->isFinished()) {
return true;
}
return false;
}
bool xToolsModbusStudio::SetServerData(QModbusDevice *server,
QModbusDataUnit::RegisterType table,
int address,
int data,
bool enable_log)
{
bool is_ok = false;
if (server && qobject_cast<QModbusServer *>(server)) {
QModbusServer *modbusServer = qobject_cast<QModbusServer *>(server);
is_ok = modbusServer->setData(table, address, data);
if (enable_log) {
qInfo() << "Set register data result:" << is_ok << "table:" << table
<< "address:" << address << "data:" << data;
}
}
return is_ok;
}
QList<quint16> xToolsModbusStudio::GetServerData(QModbusDevice *server,
QModbusDataUnit::RegisterType table,
int address,
int quantity)
{
QList<quint16> values;
if (server && qobject_cast<QModbusServer *>(server)) {
QModbusServer *cooked_server = qobject_cast<QModbusServer *>(server);
for (int i = address; i < quantity; i++) {
quint16 value;
if (cooked_server->data(table, i, &value)) {
values.append(value);
} else {
qWarning() << "Parameters error!";
break;
}
}
} else {
qWarning() << "Can not get values from null object!";
}
return values;
}
void xToolsModbusStudio::DeleteModbusDevuce(QModbusDevice **modbus_device)
{
if (*modbus_device) {
QModbusServer *server = qobject_cast<QModbusServer *>(*modbus_device);
if (server) {
server->disconnect();
}
(*modbus_device)->deleteLater();
(*modbus_device) = Q_NULLPTR;
}
}
QModbusDevice *xToolsModbusStudio::CreateRtuSerialDevice(
int type, const QString &port_name, int parity, int baud_rate, int data_bits, int stop_bits)
{
QModbusDevice *device = CreateDevice(type);
if (IsRtuSerialDevice(device)) {
device->setConnectionParameter(QModbusDevice::SerialPortNameParameter, port_name);
device->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baud_rate);
device->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, data_bits);
device->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stop_bits);
device->setConnectionParameter(QModbusDevice::SerialParityParameter, parity);
qInfo() << "Set rtu serial modbus device parameters:"
<< "port name:" << port_name << "baud rate:" << baud_rate
<< "data bits:" << data_bits << "stop bits" << stop_bits << "parity" << parity;
}
return device;
}
QModbusDevice *xToolsModbusStudio::CreateTcpDevice(int type, QString address, int port)
{
QModbusDevice *device = CreateDevice(type);
if (IsTcpDevice(device)) {
device->setConnectionParameter(QModbusDevice::NetworkAddressParameter, address);
device->setConnectionParameter(QModbusDevice::NetworkPortParameter, port);
qInfo() << "Set tcp modbus device parameters:"
<< "ip address:" << address << "port" << port;
}
return device;
}
void xToolsModbusStudio::SetClientDeviceParameters(QModbusDevice *client,
int timeout,
int number_of_retries)
{
if (client) {
qInfo() << "Set modbus client device parameters:"
<< "timeout:" << timeout << "number_of_retries" << number_of_retries;
QModbusClient *cooked_client = qobject_cast<QModbusClient *>(client);
cooked_client->setTimeout(timeout);
cooked_client->setNumberOfRetries(number_of_retries);
}
}
void xToolsModbusStudio::SetServerDeviceParameters(QModbusDevice *server,
int address,
bool device_busy,
bool listen_only_mode)
{
if (server) {
qInfo() << "Set modbus server device parameters:"
<< "address:" << address << "device busy" << device_busy
<< "listen only mode:" << listen_only_mode;
QModbusServer *cooked_server = qobject_cast<QModbusServer *>(server);
cooked_server->setServerAddress(address);
cooked_server->setValue(QModbusServer::DeviceBusy, device_busy);
cooked_server->setValue(QModbusServer::ListenOnlyMode, listen_only_mode);
}
}
QModbusReply *xToolsModbusStudio::SendWriteRequest(QModbusDevice *modbus_device,
int register_type,
int start_address,
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
QVector<quint16> values,
#else
QList<quint16> values,
#endif
int server_address)
{
if (modbus_device && IsClientDevice(modbus_device)) {
auto cooked_type = QModbusDataUnit::RegisterType(register_type);
QModbusDataUnit dataUnit(cooked_type, start_address, values);
if (dataUnit.isValid()) {
qInfo() << "register-type:" << register_type << " start-address:" << start_address
<< " serverAddress:" << server_address << " values:" << values;
auto *client = qobject_cast<QModbusClient *>(modbus_device);
QModbusReply *reply = client->sendWriteRequest(dataUnit, server_address);
return reply;
} else {
qWarning() << "Unvalid data unit!";
}
}
return Q_NULLPTR;
}
QModbusReply *xToolsModbusStudio::SendRawRequest(QModbusDevice *modbus_device,
int server_address,
int function_code,
const QByteArray &data)
{
auto cooked_function_code = QModbusPdu::FunctionCode(function_code);
QModbusRequest request(cooked_function_code, data);
if (IsClientDevice(modbus_device)) {
QModbusClient *client = qobject_cast<QModbusClient *>(modbus_device);
return client->sendRawRequest(request, server_address);
}
return Q_NULLPTR;
}

View File

@ -1,79 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QModbusDataUnit>
#include <QModbusDevice>
#include <QModbusReply>
#include <QObject>
class xToolsModbusStudio : public QObject
{
Q_OBJECT
public:
enum ModbusDeviceType {
kModbusRtuSerialClient,
kModbusRtuSerialServer,
kModbusTcpClient,
kModbusTcpServer
};
Q_ENUM(ModbusDeviceType)
private:
xToolsModbusStudio(QObject *parent = Q_NULLPTR);
public:
~xToolsModbusStudio();
static xToolsModbusStudio *Instance();
public:
const QString TypeName(int type);
QModbusDevice *CreateDevice(int type);
bool IsTcpDevice(QModbusDevice *modbus_device);
bool IsRtuSerialDevice(QModbusDevice *modbus_device);
bool IsTcpDeviceType(int type);
bool IsRtuSerialDeviceType(int type);
bool IsServerDevice(QModbusDevice *modbus_device);
bool IsClientDevice(QModbusDevice *modbus_device);
bool ConnectDeivce(QModbusDevice *modbus_device);
bool IsConnected(QModbusDevice *modbus_device);
bool IsValidModbusReply(QModbusReply *reply);
bool SetServerData(QModbusDevice *server,
QModbusDataUnit::RegisterType table,
int address,
int data,
bool enable_log = true);
QList<quint16> GetServerData(QModbusDevice *server,
QModbusDataUnit::RegisterType table,
int address,
int quantity);
void DeleteModbusDevuce(QModbusDevice **modbus_device);
QModbusDevice *CreateRtuSerialDevice(
int type, const QString &port_name, int parity, int baud_rate, int data_bits, int stop_bits);
QModbusDevice *CreateTcpDevice(int deviceType, QString address, int port);
void SetClientDeviceParameters(QModbusDevice *client, int timeout, int number_of_retries);
void SetServerDeviceParameters(QModbusDevice *server,
int address,
bool device_busy,
bool listen_only_mode);
QModbusReply *SendWriteRequest(QModbusDevice *modbus_device,
int register_type,
int start_address,
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
QVector<quint16> values,
#else
QList<quint16> values,
#endif
int server_address);
QModbusReply *SendRawRequest(QModbusDevice *modbus_device,
int server_address,
int function_code,
const QByteArray &data);
};

File diff suppressed because it is too large Load Diff

View File

@ -1,134 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QJsonArray>
#include <QLoggingCategory>
#include <QModbusDataUnit>
#include <QModbusDevice>
#include <QModbusReply>
#include <QModbusServer>
#include <QSettings>
#include <QStandardItemModel>
#include <QTableView>
#include <QVector>
#include <QWidget>
namespace Ui {
class xToolsModbusStudioUi;
}
struct xToolsModbusUiSettingKeys;
class xToolsModbusStudioUi : public QWidget
{
Q_OBJECT
public:
explicit xToolsModbusStudioUi(QWidget *parent = Q_NULLPTR);
~xToolsModbusStudioUi();
signals:
void deviceChanged(QModbusDevice *device);
private:
Ui::xToolsModbusStudioUi *ui;
QModbusDevice *m_modbusDevice{Q_NULLPTR};
QSettings *m_settings{Q_NULLPTR};
QStandardItemModel *m_registerModel{Q_NULLPTR};
xToolsModbusUiSettingKeys *m_keyCtx;
private:
void initComponents();
void initComponentDevices();
void initComponentAddress();
void initComponentPortName();
void initComponnetBaudRate();
void initComponnetDataBits();
void initComponnetStopBits();
void initComponnetParity();
void initComponentFunctionCode();
void initComponentRegisterTableView();
void initComponentInput();
void initComponentRegisterTabWidget();
void initSettings();
void initSettingsDevice();
void initSettingsNetwork();
void initSettingsSerialPort();
void initSettingsClient();
void initSettingsServer();
void initSettingsClientOperations();
void initSettingsInput();
void initSignals();
void initSignalsDevice();
void initSignalsNetworking();
void initSignalsSerialPort();
void initSignalsClient();
void initSignalsServer();
void initSignalsClientOperations();
void onErrorOccurred();
void onDeviceTypeChanged();
void onCloseClicked();
void onOpenClicked();
void onAddressChanged();
void onPortChanged();
void onCustomAddressChanged();
void onPortNameChanged();
void onParityChanged();
void onBaudRateChanged();
void onDataBitsChanged();
void onStopBistChanged();
void onInvokeRefresh();
void onClientTimeoutChanged();
void onClientRepeatTimeChanged();
void onServerIsBusyChanged();
void onServerJustListenChanged();
void onServerAddressChanged();
void onFunctionCodeChanged();
void onTargetAddressChanged();
void onStartAddressChanged();
void onAddressNumberChanged();
void onReadClicked();
void onWriteClicked();
void onSendClicked();
void onDateWritten(QModbusDataUnit::RegisterType table, int address, int size);
void onItemChanged(QStandardItem *item);
private:
QModbusDevice *CreateModbusDevice();
QTableView *CreateTableView(int rowCount, QTableView *tableView);
void updateUiState(bool connected);
void updateClientTableView();
void updateClientTableViewData(const QList<quint16> &values);
void updateClientReadWriteButtonState();
void updateClientParameters();
void updateClientTableViewAddress(QTableView *view, int startAddress);
void updateServerParameters();
bool updateServerMap(QModbusDevice *server);
void updateServerRegistersData();
quint8 getClientFunctionCode();
QList<quint16> getClientRegisterValue();
QByteArray getClientPdu();
QTableView *getTableView(QModbusDataUnit::RegisterType table);
QList<quint16> getTableValues(QTableView *tableView, int row, int count);
void outputModbusReply(QModbusReply *reply, int functionCode);
void outputMessage(const QString &msg,
bool isError,
const QString &color = QString(),
const QString &flag = QString());
bool isConnected();
bool writeSettingsArray(
const QString &group, const QString &key, const QString &value, int index, int maxIndex);
};

View File

@ -1,773 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>xToolsModbusStudioUi</class>
<widget class="QWidget" name="xToolsModbusStudioUi">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1022</width>
<height>795</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">Modbus Studio</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widgetDeviceOperations" native="true">
<layout class="QGridLayout" name="gridLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_7">
<property name="font">
<font>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Device operations</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="cloese_button_">
<property name="text">
<string>CloseDevice</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="open_button_">
<property name="text">
<string>OpenDevice</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="device_list_"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Device list</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetNetworkSettings" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="1">
<widget class="QComboBox" name="address_combo_box">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_14">
<property name="font">
<font>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Network settings</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="port_spin_box">
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Address</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetSerialPortSettings" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_15">
<property name="font">
<font>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Serial port settings</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Port name</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Baud rate</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="stop_bits_"/>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="data_bits_"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Data bits</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="port_name_"/>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="parity_"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Parity</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Stop bits</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="baud_rate_">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetServerParameters" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_12">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="4" column="1">
<widget class="QSpinBox" name="server_address">
<property name="maximum">
<number>265</number>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="device_busy_">
<property name="text">
<string>Device busy</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Server address</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_16">
<property name="font">
<font>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Server parameters</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="listen_only_mode_">
<property name="text">
<string>Listen only mode</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetClientParameters" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_13">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="1">
<widget class="QSpinBox" name="repeat_time_">
<property name="minimum">
<number>0</number>
</property>
<property name="value">
<number>3</number>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="device_address_">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Repeat times</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Timeout</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_17">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Function code</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="function_code_">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="quantity_">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="timeout_">
<property name="minimum">
<number>500</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>500</number>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="start_address_">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_18">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Target address</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_19">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Start address</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Address number</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="read_">
<property name="text">
<string>Read</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="write_">
<property name="text">
<string>Write</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_21">
<property name="font">
<font>
<italic>true</italic>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Client parameters</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="console_">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Colsole</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextBrowser" name="text_browser_"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="clientRegistersGroupBox">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Client registers</string>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0" colspan="2">
<widget class="QTableView" name="client_registers_"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="clientCustomCommandGroupBox">
<property name="title">
<string>Custom command</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>Protocol data unit</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="pdu_">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="send_">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="registersGroupBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Server registers</string>
</property>
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0">
<widget class="QTabWidget" name="server_registers_">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,16 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsModbusStudioUi.h"
#include "xToolsUi.h"
int main(int argc, char* argv[])
{
const QString appName = QObject::tr("Modbus Studio");
return xToolsExec<xToolsModbusStudioUi>(argc, argv, appName);
}

View File

@ -1,363 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsBleCentralTool.h"
#include <QBluetoothDeviceInfo>
#include <QMetaObject>
#define BLE_ERR_SIG QLowEnergyController::Error
xToolsBleCentralTool::xToolsBleCentralTool(QObject *parent)
: xToolsCommunicationTool(parent)
{}
xToolsBleCentralTool::~xToolsBleCentralTool() {}
QString xToolsBleCentralTool::serviceName(QVariant service)
{
QObject *obj = service.value<QObject *>();
auto cookedService = qobject_cast<QLowEnergyService *>(obj);
if (cookedService) {
return cookedService->serviceName();
} else {
qWarning() << "invalid valud of service, not a object!";
}
return "Invalid";
}
QVariantList xToolsBleCentralTool::characteristics(QVariant service)
{
QVariantList list;
if (service.canConvert<QLowEnergyService *>()) {
return list;
}
auto cookedService = service.value<QLowEnergyService *>();
if (cookedService) {
auto characteristics = cookedService->characteristics();
for (auto &characteristic : characteristics) {
list.append(QVariant::fromValue(characteristic));
}
}
return list;
}
QString xToolsBleCentralTool::characteristicName(QVariant characteristic)
{
if (characteristic.canConvert<QLowEnergyCharacteristic>()) {
auto c = characteristic.value<QLowEnergyCharacteristic>();
return c.name();
}
return "Invalid";
}
void xToolsBleCentralTool::readCharacteristic()
{
if (!(m_serviceIndex >= 0 && m_serviceIndex < m_services.length())) {
qWarning() << "invalid service index";
return;
}
auto service = m_services.at(m_serviceIndex);
auto chs = service->characteristics();
if (!(m_characteristicIndex >= 0 && m_characteristicIndex < chs.count())) {
qWarning() << "invalid characteristic index";
return;
}
auto c = chs.at(m_characteristicIndex);
service->readCharacteristic(c);
}
void xToolsBleCentralTool::changeNotify()
{
if (!((m_serviceIndex >= 0) && (m_serviceIndex < m_services.length()))) {
return;
}
auto service = m_services.at(m_serviceIndex);
auto characteristics = service->characteristics();
if (!((m_characteristicIndex >= 0) && (m_characteristicIndex < characteristics.length()))) {
return;
}
auto characteristic = characteristics.at(m_characteristicIndex);
auto descriptors = characteristic.descriptors();
typedef QBluetoothUuid::DescriptorType SAKDescriptorType;
auto type = SAKDescriptorType::ClientCharacteristicConfiguration;
for (auto &descriptor : descriptors) {
auto value = descriptor.value();
if (descriptor.type() != type) {
continue;
}
if (value == QByteArray::fromHex("0100")) {
QByteArray value = QByteArray::fromHex("0000");
service->writeDescriptor(descriptor, value);
qWarning() << "disable notify";
} else {
QByteArray value = QByteArray::fromHex("0100");
service->writeDescriptor(descriptor, value);
qWarning() << "enable notify";
}
}
}
bool xToolsBleCentralTool::hasFlag(QVariant characteristic, int flag)
{
auto ch = characteristic.value<QLowEnergyCharacteristic>();
auto properties = ch.properties();
if (properties & flag) {
return true;
}
return false;
}
bool xToolsBleCentralTool::isNotified(QVariant characteristic)
{
auto cookedCh = characteristic.value<QLowEnergyCharacteristic>();
auto desList = cookedCh.descriptors();
bool notified = false;
for (auto &des : desList) {
if (des.value() == QByteArray::fromHex("0100")) {
notified = true;
break;
}
}
return notified;
}
bool xToolsBleCentralTool::initialize(QString &errStr)
{
if (!m_bluetoothDeviceInfo.isValid()) {
errStr = "invalid ble information.";
return false;
}
m_services.clear();
mBleCentral = QLowEnergyController::createCentral(m_bluetoothDeviceInfo);
connect(mBleCentral,
&QLowEnergyController::serviceDiscovered,
mBleCentral,
[=](const QBluetoothUuid &newService) { onServiceDiscovered(newService); });
connect(mBleCentral, &QLowEnergyController::discoveryFinished, mBleCentral, [=]() {
onServiceDiscoveryFinished();
});
connect(mBleCentral,
&QLowEnergyController::errorOccurred,
mBleCentral,
[=](QLowEnergyController::Error err) { onBleCentralErrorOccuured(err); });
connect(mBleCentral, &QLowEnergyController::connected, mBleCentral, [=]() {
onBleCentralConnected();
});
connect(mBleCentral, &QLowEnergyController::disconnected, mBleCentral, [=]() {
onBleCentralDisconnected();
});
mBleCentral->connectToDevice();
emit serviceDiscoveryStarted();
return true;
}
void xToolsBleCentralTool::readBytes()
{
if (!((m_serviceIndex >= 0) && (m_serviceIndex < m_services.length()))) {
return;
}
auto service = m_services.at(m_serviceIndex);
auto characteristics = service->characteristics();
auto characteristic = characteristics.at(m_characteristicIndex);
service->readCharacteristic(characteristic);
}
void xToolsBleCentralTool::writeBytes(const QByteArray &bytes)
{
if (!((m_serviceIndex >= 0) && (m_serviceIndex < m_services.length()))) {
qWarning() << "invalid parameters.";
return;
}
auto service = m_services.at(m_serviceIndex);
auto characteristics = service->characteristics();
auto characteristic = characteristics.at(m_characteristicIndex);
if (m_writeModel == 0) {
if (!hasFlag(QVariant::fromValue(characteristic), QLowEnergyCharacteristic::Write)) {
QString str = "QLowEnergyService::WriteWithResponse";
qWarning() << "unsupported write model: " + str;
return;
}
qInfo() << "try to write bytes:" << QString::fromLatin1(bytes.toHex());
service->writeCharacteristic(characteristic, bytes);
} else {
if (!hasFlag(QVariant::fromValue(characteristic),
QLowEnergyCharacteristic::WriteNoResponse)) {
QString str = "QLowEnergyService::WriteWithoutResponse";
qWarning() << "unsupported write model: " + str;
return;
}
qInfo() << "try to write bytes without response:"
<< QString::fromLatin1(bytes.toHex());
auto opt = QLowEnergyService::WriteWithoutResponse;
service->writeCharacteristic(characteristic, bytes, opt);
}
}
void xToolsBleCentralTool::uninitialize()
{
mBleCentral->disconnectFromDevice();
mBleCentral->deleteLater();
mBleCentral = nullptr;
}
void xToolsBleCentralTool::onServiceDiscovered(const QBluetoothUuid &newService)
{
qInfo() << "new ble service discovered:" + newService.toString();
}
void xToolsBleCentralTool::onServiceDiscoveryFinished()
{
qInfo() << "ble service discovery finished.";
QList<QBluetoothUuid> uuids = mBleCentral->services();
qInfo() << "service count:" + QString::number(uuids.length());
for (auto &uuid : uuids) {
auto service = mBleCentral->createServiceObject(uuid);
if (!service) {
continue;
}
connect(service,
&QLowEnergyService::characteristicChanged,
service,
[=](const QLowEnergyCharacteristic &info, const QByteArray &value) {
emit outputBytes(value);
emit bytesRead(value, info.name());
});
connect(service,
&QLowEnergyService::characteristicRead,
service,
[=](const QLowEnergyCharacteristic &info, const QByteArray &value) {
emit outputBytes(value);
emit bytesRead(value, info.name());
});
connect(service,
&QLowEnergyService::characteristicWritten,
service,
[=](const QLowEnergyCharacteristic &info, const QByteArray &value) {
emit bytesWritten(value, info.name());
});
connect(service,
&QLowEnergyService::stateChanged,
service,
[=](QLowEnergyService::ServiceState newState) {
onServiceObjectStateChanged(service, newState);
});
connect(service,
&QLowEnergyService::descriptorWritten,
this,
&xToolsBleCentralTool::descriptorWritten);
m_services.append(service);
service->discoverDetails();
}
emit serviceDiscoveryFinished();
}
void xToolsBleCentralTool::onBleCentralErrorOccuured(QLowEnergyController::Error err)
{
if (err == QLowEnergyController::UnknownError) {
return;
}
qWarning() << "new ble service error:" + mBleCentral->errorString();
exit();
}
void xToolsBleCentralTool::onBleCentralConnected()
{
qWarning() << "connect to device successfully.";
mBleCentral->discoverServices();
}
void xToolsBleCentralTool::onBleCentralDisconnected()
{
QString msg = "disconnect from device";
qWarning() << msg;
emit errorOccurred(msg);
}
void xToolsBleCentralTool::onServiceObjectStateChanged(QLowEnergyService *service,
QLowEnergyService::ServiceState newState)
{
Q_UNUSED(service);
auto state = QLowEnergyService::RemoteServiceDiscovered;
if (newState == state) {
qInfo() << "Remote service discovered:" << newState;
}
}
QVariant xToolsBleCentralTool::info()
{
return QVariant::fromValue(m_bluetoothDeviceInfo);
}
void xToolsBleCentralTool::setInfo(QVariant info)
{
m_bluetoothDeviceInfo = info.value<QBluetoothDeviceInfo>();
emit infoChanged();
}
QVariantList xToolsBleCentralTool::services()
{
QVariantList varList;
for (auto &var : m_services) {
varList.append(QVariant::fromValue(var));
}
return varList;
}
int xToolsBleCentralTool::serviceIndex()
{
return m_serviceIndex;
}
void xToolsBleCentralTool::setServiceIndex(int index)
{
m_serviceIndex = index;
emit serviceIndexChanged();
}
int xToolsBleCentralTool::characteristicIndex()
{
return m_characteristicIndex;
}
void xToolsBleCentralTool::setCharacteristicIndex(int index)
{
m_characteristicIndex = index;
emit characteristicIndexChanged();
}
int xToolsBleCentralTool::writeModel()
{
return m_writeModel;
}
void xToolsBleCentralTool::setWriteModel(int model)
{
m_writeModel = model;
emit writeModelChanged();
}

View File

@ -1,90 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#pragma once
#include <QBluetoothDeviceInfo>
#include <QBluetoothUuid>
#include <QLowEnergyController>
#include <QLowEnergyService>
#include <QVariantList>
#include "xToolsCommunicationTool.h"
class xToolsBleCentralTool : public xToolsCommunicationTool
{
Q_OBJECT
// clang-format off
Q_PROPERTY(QVariant info READ info WRITE setInfo NOTIFY infoChanged)
Q_PROPERTY(QVariantList services READ services NOTIFY servicesChanged)
Q_PROPERTY(int serviceIndex READ serviceIndex WRITE setServiceIndex NOTIFY serviceIndexChanged)
Q_PROPERTY(int characteristicIndex READ characteristicIndex WRITE setCharacteristicIndex NOTIFY characteristicIndexChanged)
Q_PROPERTY(int writeModel READ writeModel WRITE setWriteModel NOTIFY writeModelChanged)
// clang-format on
public:
xToolsBleCentralTool(QObject *parent = nullptr);
~xToolsBleCentralTool();
public:
Q_INVOKABLE QString serviceName(QVariant service);
Q_INVOKABLE QVariantList characteristics(QVariant service);
Q_INVOKABLE QString characteristicName(QVariant characteristic);
Q_INVOKABLE void readCharacteristic();
Q_INVOKABLE void changeNotify();
Q_INVOKABLE bool hasFlag(QVariant characteristic, int flag);
Q_INVOKABLE bool isNotified(QVariant characteristic);
signals:
void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue);
void serviceDiscoveryStarted();
void serviceDiscoveryFinished();
protected:
bool initialize(QString &errStr) override;
void writeBytes(const QByteArray &bytes) override;
void readBytes();
void uninitialize() override;
private:
QLowEnergyController *mBleCentral{nullptr};
private:
void onServiceDiscovered(const QBluetoothUuid &newService);
void onServiceDiscoveryFinished();
void onBleCentralErrorOccuured(QLowEnergyController::Error err);
void onBleCentralConnected();
void onBleCentralDisconnected();
void onServiceObjectStateChanged(QLowEnergyService *service,
QLowEnergyService::ServiceState newState);
public:
Q_INVOKABLE QVariant info();
Q_INVOKABLE void setInfo(QVariant info);
Q_INVOKABLE QVariantList services();
Q_INVOKABLE int serviceIndex();
Q_INVOKABLE void setServiceIndex(int index);
Q_INVOKABLE int characteristicIndex();
Q_INVOKABLE void setCharacteristicIndex(int index);
Q_INVOKABLE int writeModel();
Q_INVOKABLE void setWriteModel(int model);
signals:
void infoChanged();
void servicesChanged();
void serviceIndexChanged();
void characteristicsChanged();
void characteristicIndexChanged();
void writeModelChanged();
private:
QBluetoothDeviceInfo m_bluetoothDeviceInfo;
QVector<QLowEnergyService *> m_services;
int m_serviceIndex{-1};
int m_characteristicIndex{-1};
int m_writeModel;
};

View File

@ -1,269 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include "xToolsBleCentralToolUi.h"
#include "ui_xToolsBleCentralToolUi.h"
#include <QGridLayout>
#include <QLabel>
#include <QLowEnergyCharacteristic>
#include <QMenu>
#include <QWidget>
#include <QWidgetAction>
#include "xToolsLineEdit.h"
#include "xToolsSpinBox.h"
xToolsBleCentralToolUi::xToolsBleCentralToolUi(QWidget* parent)
: xToolsCommunicationToolUi{parent}
, ui(new Ui::xToolsBleCentralToolUi)
, mBleTool(Q_NULLPTR)
{
ui->setupUi(this);
ui->progressBar->hide();
connect(ui->pushButtonScan,
&QPushButton::clicked,
this,
&xToolsBleCentralToolUi::onPushButtonScanClicked);
connect(ui->comboBoxDevices,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsBleCentralToolUi::onComboBoxDevicesActived);
connect(ui->comboBoxServices,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsBleCentralToolUi::onComboBoxServicesCurrentIndexChanged);
connect(ui->comboBoxCharacteristics,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsBleCentralToolUi::onComboBoxCharacteristicsActived);
connect(ui->comboBoxWriteWay,
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
&xToolsBleCentralToolUi::onComboBoxWriteWayCurrentIndexChanged);
connect(ui->pushButtonNotify,
&QPushButton::clicked,
this,
&xToolsBleCentralToolUi::onPushButtonNotifyClicked);
connect(ui->pushButtonRead,
&QPushButton::clicked,
this,
&xToolsBleCentralToolUi::onPushButtonReadClicked);
connect(ui->comboBoxDevices, &xToolsBleDeviceInfoComboBox::finished, this, [=]() {
ui->pushButtonScan->setText(tr("Scan"));
ui->pushButtonScan->setEnabled(true);
});
connect(ui->comboBoxDevices, &xToolsBleDeviceInfoComboBox::started, this, [=]() {
ui->pushButtonScan->setText(tr("Stop"));
ui->pushButtonScan->setEnabled(true);
});
ui->labelWriteWay->setVisible(false);
ui->comboBoxWriteWay->setVisible(false);
ui->pushButtonNotify->setVisible(false);
ui->pushButtonRead->setVisible(false);
ui->labelUnsupported->setVisible(false);
ui->labelUnsupported->setStyleSheet("QLabel{color:red}");
}
xToolsBleCentralToolUi::~xToolsBleCentralToolUi()
{
delete ui;
}
void xToolsBleCentralToolUi::onBaseToolUiInitialized(xToolsBaseTool* tool,
const QString& settingsGroup)
{
xToolsCommunicationToolUi::onBaseToolUiInitialized(tool, settingsGroup);
mBleTool = qobject_cast<xToolsBleCentralTool*>(mTool);
if (!mBleTool) {
QByteArray msg("invalid SAKBleCentralTool tool");
qWarning() << QString::fromLatin1(msg);
Q_ASSERT_X(false, __FUNCTION__, msg.data());
return;
}
onComboBoxWriteWayCurrentIndexChanged();
connect(mBleTool,
&xToolsBleCentralTool::descriptorWritten,
this,
&xToolsBleCentralToolUi::onDescriptorWritten);
initSettingsMenu(settingsGroup);
}
void xToolsBleCentralToolUi::onIsWorkingChanged(bool isWorking)
{
if (!isWorking) {
ui->progressBar->hide();
}
}
void xToolsBleCentralToolUi::initSettingsMenu(const QString& settingsGroup)
{
QWidget* w = new QWidget(this);
QGridLayout* gl = new QGridLayout();
w->setLayout(gl);
int rowIndex = 0;
gl->addWidget(new QLabel(tr("Timeout interval(S)"), w), rowIndex, 0, 1, 1);
xToolsSpinBox* sp = new xToolsSpinBox(w);
sp->setMinimum(10);
sp->setMaximum(120);
sp->setValue(120);
sp->setGroupKey(settingsGroup, "timeoutInterval");
gl->addWidget(sp, rowIndex, 1, 1, 1);
connect(sp, QOverload<int>::of(&QSpinBox::valueChanged), this, [=](int v) {
ui->comboBoxDevices->setTimeoutInterval(v);
});
rowIndex += 1;
gl->addWidget(new QLabel(tr("Name filtter"), w), rowIndex, 0, 1, 1);
xToolsLineEdit* le = new xToolsLineEdit(w);
le->setGroupKey(settingsGroup, "nameFiltter");
gl->addWidget(le, rowIndex, 1, 1, 1);
connect(le, &xToolsLineEdit::textChanged, this, [=](const QString& text) {
ui->comboBoxDevices->setNameFiltter(text);
});
rowIndex += 1;
QMenu* menu = new QMenu(this);
QPushButton* bt = new QPushButton(tr("OK"));
connect(bt, &QPushButton::clicked, menu, &QMenu::close);
gl->addWidget(bt, rowIndex, 1, 1, 1);
QWidgetAction* a = new QWidgetAction(this);
a->setDefaultWidget(w);
menu->addAction(a);
ui->pushButtonSettings->setMenu(menu);
connect(mBleTool,
&xToolsBleCentralTool::serviceDiscoveryStarted,
this,
&xToolsBleCentralToolUi::onServiceDiscoveryStarted);
connect(mBleTool,
&xToolsBleCentralTool::serviceDiscoveryFinished,
this,
&xToolsBleCentralToolUi::onServiceDiscoveryFinished);
int timeoutInterval = sp->value();
QString nameFiltter = le->text().trimmed();
ui->comboBoxDevices->setTimeoutInterval(timeoutInterval);
ui->comboBoxDevices->setNameFiltter(nameFiltter);
onComboBoxDevicesActived();
}
void xToolsBleCentralToolUi::onServiceDiscoveryStarted()
{
ui->progressBar->show();
}
void xToolsBleCentralToolUi::onServiceDiscoveryFinished()
{
ui->comboBoxServices->clear();
auto services = mBleTool->services();
for (auto& service : services) {
auto cookedSerivce = service.value<QLowEnergyService*>();
ui->comboBoxServices->addItem(cookedSerivce->serviceName(), service);
connect(cookedSerivce,
&QLowEnergyService::stateChanged,
this,
[=](QLowEnergyService::ServiceState state) {
if (state == QLowEnergyService::RemoteServiceDiscovered) {
onComboBoxServicesCurrentIndexChanged();
}
});
}
ui->progressBar->hide();
}
void xToolsBleCentralToolUi::onDescriptorWritten(const QLowEnergyDescriptor& descriptor,
const QByteArray& newValue)
{
Q_UNUSED(descriptor)
Q_UNUSED(newValue)
onComboBoxCharacteristicsActived();
}
void xToolsBleCentralToolUi::onPushButtonScanClicked()
{
ui->pushButtonScan->setEnabled(false);
if (ui->comboBoxDevices->isActive()) {
ui->comboBoxDevices->stopDiscover();
} else {
ui->comboBoxDevices->startDiscover();
}
}
void xToolsBleCentralToolUi::onComboBoxDevicesActived()
{
QVariant data = ui->comboBoxDevices->currentData();
mBleTool->setInfo(data);
}
void xToolsBleCentralToolUi::onComboBoxServicesCurrentIndexChanged()
{
mBleTool->setServiceIndex(ui->comboBoxServices->currentIndex());
auto service = ui->comboBoxServices->currentData();
auto cookedSerivce = service.value<QLowEnergyService*>();
auto chs = cookedSerivce->characteristics();
ui->comboBoxCharacteristics->clear();
for (int i = 0; i < chs.count(); i++) {
auto ch = chs.at(i);
QVariant var = QVariant::fromValue<QLowEnergyCharacteristic>(ch);
QString name = ch.name();
name = name.isEmpty() ? tr("Characteristics%1").arg(i + 1) : name;
ui->comboBoxCharacteristics->addItem(name, var);
}
}
void xToolsBleCentralToolUi::onComboBoxCharacteristicsActived()
{
int index = ui->comboBoxCharacteristics->currentIndex();
mBleTool->setCharacteristicIndex(index);
QVariant ch = ui->comboBoxCharacteristics->currentData();
bool writeFlag = mBleTool->hasFlag(ch, QLowEnergyCharacteristic::Write);
int writeNoResponse = QLowEnergyCharacteristic::WriteNoResponse;
bool writeNoResponseFlag = mBleTool->hasFlag(ch, writeNoResponse);
ui->labelWriteWay->setVisible(writeFlag);
ui->comboBoxWriteWay->setVisible(writeNoResponseFlag);
bool readFlag = mBleTool->hasFlag(ch, QLowEnergyCharacteristic::Read);
bool notifyFlag = mBleTool->hasFlag(ch, QLowEnergyCharacteristic::Notify);
ui->pushButtonNotify->setVisible(notifyFlag);
ui->pushButtonRead->setVisible(readFlag);
bool supported = writeFlag || writeNoResponseFlag || readFlag || notifyFlag;
ui->labelUnsupported->setVisible(!supported);
if (notifyFlag) {
bool isNotified = mBleTool->isNotified(ch);
QString txt = isNotified ? tr("Disnotify") : tr("Notify");
ui->pushButtonNotify->setText(txt);
}
}
void xToolsBleCentralToolUi::onComboBoxWriteWayCurrentIndexChanged()
{
int index = ui->comboBoxWriteWay->currentIndex();
mBleTool->setWriteModel(index);
qInfo() << "set write model to:" << index;
}
void xToolsBleCentralToolUi::onPushButtonNotifyClicked()
{
mBleTool->changeNotify();
}
void xToolsBleCentralToolUi::onPushButtonReadClicked()
{
mBleTool->readCharacteristic();
}

View File

@ -1,50 +0,0 @@
/***************************************************************************************************
* Copyright 2023-2024 x-tools-author(x-tools@outlook.com). All rights reserved.
*
* The file is encoded using "utf8 with bom", it is a part of xTools project.
*
* xTools is licensed according to the terms in the file LICENCE(GPL V3) in the root of the source
* code directory.
**************************************************************************************************/
#include <QLowEnergyDescriptor>
#include "xToolsBleCentralTool.h"
#include "xToolsCommunicationToolUi.h"
namespace Ui {
class xToolsBleCentralToolUi;
}
class xToolsBleCentralToolUi : public xToolsCommunicationToolUi
{
Q_OBJECT
public:
explicit xToolsBleCentralToolUi(QWidget *parent = nullptr);
~xToolsBleCentralToolUi();
protected:
virtual void onBaseToolUiInitialized(xToolsBaseTool *tool,
const QString &settingsGroup) override;
virtual void onIsWorkingChanged(bool isWorking) final;
private:
Ui::xToolsBleCentralToolUi *ui{nullptr};
xToolsBleCentralTool *mBleTool;
const QLoggingCategory mLoggingCategory{"sak.blecentraltoolui"};
private:
void initSettingsMenu(const QString &settingsGroup);
private slots:
void onServiceDiscoveryStarted();
void onServiceDiscoveryFinished();
void onDescriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue);
void onPushButtonScanClicked();
void onComboBoxDevicesActived();
void onComboBoxServicesCurrentIndexChanged();
void onComboBoxCharacteristicsActived();
void onComboBoxWriteWayCurrentIndexChanged();
void onPushButtonNotifyClicked();
void onPushButtonReadClicked();
};

View File

@ -1,185 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>xToolsBleCentralToolUi</class>
<widget class="QWidget" name="xToolsBleCentralToolUi">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>256</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="3" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Service</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Devices</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelWriteWay">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Write way</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="xToolsBleDeviceInfoComboBox" name="comboBoxDevices"/>
</item>
<item row="7" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonNotify">
<property name="text">
<string>Notify</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonRead">
<property name="text">
<string>Read</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="comboBoxCharacteristics"/>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxServices">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="comboBoxWriteWay">
<item>
<property name="text">
<string>WriteWithResponse</string>
</property>
</item>
<item>
<property name="text">
<string>WriteWithoutResponse</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Characteristic</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="pushButtonSettings">
<property name="text">
<string>Settings</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonScan">
<property name="text">
<string>Scan</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="labelUnsupported">
<property name="text">
<string>(Unsupported characteristic)</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>xToolsBleDeviceInfoComboBox</class>
<extends>QComboBox</extends>
<header location="global">xToolsBleDeviceInfoComboBox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>