summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2015-11-13 10:16:37 +0100
committerKarsten Heimrich <karsten.heimrich@theqtcompany.com>2015-11-13 11:45:51 +0000
commit8e7bdd0954d9ec2a845dd51b76b5da0bc2386614 (patch)
tree97c7abd28595bcb3ccb727b08885abae33c335c6
parent0f9552d8f0eabb6d74a938935283bda469fbd273 (diff)
Permit block writes in Modbus Master example
Change-Id: Id6c27a0055bf38ba072d5ff00af7fcff5e15a74a Reviewed-by: Karsten Heimrich <karsten.heimrich@theqtcompany.com>
-rw-r--r--examples/serialbus/modbus/master/mainwindow.cpp42
-rw-r--r--examples/serialbus/modbus/master/mainwindow.h4
-rw-r--r--examples/serialbus/modbus/master/mainwindow.ui106
-rw-r--r--examples/serialbus/modbus/master/master.pro6
-rw-r--r--examples/serialbus/modbus/master/writeregistermodel.cpp133
-rw-r--r--examples/serialbus/modbus/master/writeregistermodel.h66
6 files changed, 298 insertions, 59 deletions
diff --git a/examples/serialbus/modbus/master/mainwindow.cpp b/examples/serialbus/modbus/master/mainwindow.cpp
index bc0fa32..2f4753b 100644
--- a/examples/serialbus/modbus/master/mainwindow.cpp
+++ b/examples/serialbus/modbus/master/mainwindow.cpp
@@ -41,6 +41,7 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
+#include "writeregistermodel.h"
#include <QtSerialBus/qmodbustcpclient.h>
#include <QtSerialBus/qmodbusrtuserialmaster.h>
@@ -64,11 +65,16 @@ MainWindow::MainWindow(QWidget *parent)
initActions();
+ writeModel = new WriteRegisterModel(this);
+ ui->writeValueTable->setModel(writeModel);
+ ui->writeValueTable->resizeColumnToContents(0);
+ ui->writeValueTable->horizontalHeader()->setStretchLastSection(true);
+ ui->writeValueTable->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
ui->readTable->addItem(tr("Coils"), QModbusDataUnit::Coils);
ui->readTable->addItem(tr("Discrete Inputs"), QModbusDataUnit::DiscreteInputs);
ui->readTable->addItem(tr("Input Registers"), QModbusDataUnit::InputRegisters);
ui->readTable->addItem(tr("Holding Registers"), QModbusDataUnit::HoldingRegisters);
- on_writeTable_currentIndexChanged(ui->writeTable->currentText());
ui->connectType->setCurrentIndex(0);
on_connectType_currentIndexChanged(0);
@@ -224,14 +230,25 @@ void MainWindow::on_writeButton_clicked()
if (ui->writeTable->currentText() == tr("Coils"))
table = QModbusDataUnit::Coils;
- QModbusDataUnit unit(table, ui->writeAddress->text().toInt(), 1u);
- unit.setValue(0, ui->writeValue->text().toInt(0, 16));
+ int numberOfEntries = ui->writeSize->currentText().toInt();
+ int startAddress = ui->writeAddress->text().toInt();
+ // do not go beyond 10 entries
+ numberOfEntries = qMin(numberOfEntries, 10 - startAddress);
+
+ Q_ASSERT(startAddress >= 0 && startAddress < 10);
+ QModbusDataUnit writeUnit(table, startAddress, numberOfEntries);
+ for (int i = startAddress; i < (startAddress + numberOfEntries); i++)
+ {
+ if (table == QModbusDataUnit::Coils)
+ writeUnit.setValue(i - startAddress, writeModel->m_coils[i]);
+ else
+ writeUnit.setValue(i - startAddress, writeModel->m_holdingRegisters[i]);
+ }
statusBar()->clearMessage();
- // TODO extend to test write of single coil and holding register
- // Write Multiple coils and registers as well as R/W MultipleRegisters is missing
- QModbusReply *reply = modbusDevice->sendWriteRequest(unit, ui->writeSlave->text().toInt());
+ // TODO test for R/W MultipleRegisters is missing
+ QModbusReply *reply = modbusDevice->sendWriteRequest(writeUnit, ui->writeSlave->text().toInt());
// broadcast replies return immediately
if (reply && reply->isFinished()) {
@@ -263,16 +280,3 @@ void MainWindow::writeReady()
reply->deleteLater();
}
-
-void MainWindow::on_writeTable_currentIndexChanged(const QString &text)
-{
- ui->writeValue->clear();
- if (text == tr("Coils")) {
- ui->writeValue->setValidator(new QIntValidator(0, 1, this));
- ui->writeValue->setPlaceholderText(tr("Binary 0-1."));
- } else if (text == tr("Holding Registers")) {
- ui->writeValue->setValidator(new QRegExpValidator(QRegExp(QStringLiteral("[0-9a-f]{0,4}"),
- Qt::CaseInsensitive), this));
- ui->writeValue->setPlaceholderText(tr("Hexadecimal A-F, a-f, 0-9."));
- }
-}
diff --git a/examples/serialbus/modbus/master/mainwindow.h b/examples/serialbus/modbus/master/mainwindow.h
index 9bec23c..2f6c481 100644
--- a/examples/serialbus/modbus/master/mainwindow.h
+++ b/examples/serialbus/modbus/master/mainwindow.h
@@ -56,6 +56,7 @@ class SettingsDialog;
QT_END_NAMESPACE
class SettingsDialog;
+class WriteRegisterModel;
class MainWindow : public QMainWindow
{
@@ -78,8 +79,6 @@ private slots:
void on_writeButton_clicked();
void writeReady();
- void on_writeTable_currentIndexChanged(const QString &arg1);
-
void on_connectType_currentIndexChanged(int);
private:
@@ -87,6 +86,7 @@ private:
QModbusReply* lastRequest;
QModbusClient* modbusDevice;
SettingsDialog *m_settingsDialog;
+ WriteRegisterModel *writeModel;
};
#endif // MAINWINDOW_H
diff --git a/examples/serialbus/modbus/master/mainwindow.ui b/examples/serialbus/modbus/master/mainwindow.ui
index e19daa5..a734b90 100644
--- a/examples/serialbus/modbus/master/mainwindow.ui
+++ b/examples/serialbus/modbus/master/mainwindow.ui
@@ -7,9 +7,15 @@
<x>0</x>
<y>0</y>
<width>517</width>
- <height>356</height>
+ <height>550</height>
</rect>
</property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>1000</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Modbus Master Example</string>
</property>
@@ -163,23 +169,10 @@
</property>
</widget>
</item>
- <item row="4" column="1">
- <spacer name="verticalSpacer_3">
- <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="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
- <string>Value:</string>
+ <string>Number of values:</string>
</property>
</widget>
</item>
@@ -190,9 +183,6 @@
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="writeValue"/>
- </item>
<item row="1" column="1">
<widget class="QSpinBox" name="writeAddress">
<property name="maximum">
@@ -228,6 +218,63 @@
</property>
</widget>
</item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QTableView" name="writeValueTable"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="writeSize">
+ <item>
+ <property name="text">
+ <string>1</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>2</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>3</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>4</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>5</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>6</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>7</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>9</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>10</string>
+ </property>
+ </item>
+ </widget>
+ </item>
</layout>
</item>
</layout>
@@ -424,19 +471,6 @@
</item>
</layout>
</item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>417</width>
- <height>1</height>
- </size>
- </property>
- </spacer>
- </item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
@@ -469,7 +503,7 @@
</widget>
<action name="actionConnect">
<property name="icon">
- <iconset resource="../../can/can.qrc">
+ <iconset resource="master.qrc">
<normaloff>:/images/connect.png</normaloff>:/images/connect.png</iconset>
</property>
<property name="text">
@@ -478,7 +512,7 @@
</action>
<action name="actionDisconnect">
<property name="icon">
- <iconset resource="../../can/can.qrc">
+ <iconset resource="master.qrc">
<normaloff>:/images/disconnect.png</normaloff>:/images/disconnect.png</iconset>
</property>
<property name="text">
@@ -487,7 +521,7 @@
</action>
<action name="actionExit">
<property name="icon">
- <iconset resource="../../can/can.qrc">
+ <iconset resource="master.qrc">
<normaloff>:/images/application-exit.png</normaloff>:/images/application-exit.png</iconset>
</property>
<property name="text">
@@ -496,7 +530,7 @@
</action>
<action name="actionOptions">
<property name="icon">
- <iconset resource="../../can/can.qrc">
+ <iconset resource="master.qrc">
<normaloff>:/images/settings.png</normaloff>:/images/settings.png</iconset>
</property>
<property name="text">
@@ -506,7 +540,7 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>
- <include location="../../can/can.qrc"/>
+ <include location="master.qrc"/>
</resources>
<connections/>
</ui>
diff --git a/examples/serialbus/modbus/master/master.pro b/examples/serialbus/modbus/master/master.pro
index dc73984..c7d035e 100644
--- a/examples/serialbus/modbus/master/master.pro
+++ b/examples/serialbus/modbus/master/master.pro
@@ -6,10 +6,12 @@ CONFIG += c++11
SOURCES += main.cpp\
mainwindow.cpp \
- settingsdialog.cpp
+ settingsdialog.cpp \
+ writeregistermodel.cpp
HEADERS += mainwindow.h \
- settingsdialog.h
+ settingsdialog.h \
+ writeregistermodel.h
FORMS += mainwindow.ui \
settingsdialog.ui
diff --git a/examples/serialbus/modbus/master/writeregistermodel.cpp b/examples/serialbus/modbus/master/writeregistermodel.cpp
new file mode 100644
index 0000000..d3656fe
--- /dev/null
+++ b/examples/serialbus/modbus/master/writeregistermodel.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtSerialBus module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "writeregistermodel.h"
+
+#define ROW_COUNT 10
+#define COLUMN_COUNT 2
+
+WriteRegisterModel::WriteRegisterModel(QObject *parent)
+ : QAbstractTableModel(parent),
+ m_coils(10, false), m_holdingRegisters(10, 0u)
+{
+}
+
+int WriteRegisterModel::rowCount(const QModelIndex &/*parent*/) const
+{
+ return ROW_COUNT;
+}
+
+int WriteRegisterModel::columnCount(const QModelIndex &/*parent*/) const
+{
+ return COLUMN_COUNT;
+}
+
+QVariant WriteRegisterModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= ROW_COUNT || index.column() >= COLUMN_COUNT)
+ return QVariant();
+
+ Q_ASSERT(m_coils.count() == ROW_COUNT);
+ Q_ASSERT(m_holdingRegisters.count() == ROW_COUNT);
+
+ if (index.column() == 0 && role == Qt::CheckStateRole) // coils
+ return m_coils.at(index.row()) ? Qt::Checked : Qt::Unchecked;
+ else if (index.column() == 1 && role != Qt::CheckStateRole) //holding registers
+ return QString("0x%1").arg(QString::number(m_holdingRegisters.at(index.row()), 16));
+
+ return QVariant();
+
+}
+
+QVariant WriteRegisterModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal) {
+ if (section == 0)
+ return QStringLiteral("Coils ");
+ else
+ return QStringLiteral("Holding Registers");
+ } else {
+ return QString::number(section);
+ }
+}
+
+bool WriteRegisterModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || index.row() >= ROW_COUNT || index.column() >= COLUMN_COUNT)
+ return false;
+
+ Q_ASSERT(m_coils.count() == ROW_COUNT);
+ Q_ASSERT(m_holdingRegisters.count() == ROW_COUNT);
+
+ if (index.column() == 0 && role == Qt::CheckStateRole) { // coils
+ Qt::CheckState s = static_cast<Qt::CheckState>(value.toUInt());
+ s == Qt::Checked ? m_coils.setBit(index.row()) : m_coils.clearBit(index.row());
+ emit dataChanged(index, index);
+ return true;
+ } else if (index.column() == 1 && Qt::EditRole) { // holding registers
+ bool result = false;
+ quint16 newValue = value.toString().toUShort(&result, 16);
+ if (result)
+ m_holdingRegisters[index.row()] = newValue;
+
+ emit dataChanged(index, index);
+ return result;
+ }
+
+ return false;
+}
+
+Qt::ItemFlags WriteRegisterModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid() || index.row() >= ROW_COUNT || index.column() >= COLUMN_COUNT)
+ return QAbstractTableModel::flags(index);
+
+ if (index.column() == 0) //coils
+ return QAbstractTableModel::flags(index) | Qt::ItemIsUserCheckable;
+
+ if (index.column() == 1) //holding registers
+ return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
+
+ return QAbstractTableModel::flags(index);
+}
+
diff --git a/examples/serialbus/modbus/master/writeregistermodel.h b/examples/serialbus/modbus/master/writeregistermodel.h
new file mode 100644
index 0000000..101d6d9
--- /dev/null
+++ b/examples/serialbus/modbus/master/writeregistermodel.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the QtSerialBus module.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WRITEREGISTERMODEL_H
+#define WRITEREGISTERMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qbitarray.h>
+
+class WriteRegisterModel : public QAbstractTableModel
+{
+public:
+ WriteRegisterModel(QObject* parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
+
+public:
+ QBitArray m_coils;
+ QVector<quint16> m_holdingRegisters;
+};
+
+#endif // WRITEREGISTERMODEL_H