diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2015-11-13 10:16:37 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@theqtcompany.com> | 2015-11-13 11:45:51 +0000 |
commit | 8e7bdd0954d9ec2a845dd51b76b5da0bc2386614 (patch) | |
tree | 97c7abd28595bcb3ccb727b08885abae33c335c6 | |
parent | 0f9552d8f0eabb6d74a938935283bda469fbd273 (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.cpp | 42 | ||||
-rw-r--r-- | examples/serialbus/modbus/master/mainwindow.h | 4 | ||||
-rw-r--r-- | examples/serialbus/modbus/master/mainwindow.ui | 106 | ||||
-rw-r--r-- | examples/serialbus/modbus/master/master.pro | 6 | ||||
-rw-r--r-- | examples/serialbus/modbus/master/writeregistermodel.cpp | 133 | ||||
-rw-r--r-- | examples/serialbus/modbus/master/writeregistermodel.h | 66 |
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 |