Add qmodmaster and move udp app to applications

This commit is contained in:
2023-12-04 16:26:09 +01:00
parent 6906abb18d
commit 915abfcc9a
147 changed files with 15978 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
#include "about.h"
#include "ui_about.h"
#include "modbus-version.h"
const QString VER = "QModMaster 0.5.3-beta";
const QString LIB_VER = LIBMODBUS_VERSION_STRING;
const QString URL = "<a href = ""http://sourceforge.net/projects/qmodmaster"">Sourceforge Project Home Page</a>";
About::About(QWidget *parent) :
QDialog(parent),
ui(new Ui::About)
{
ui->setupUi(this);
ui->lblVersion->setText(VER);
ui->lblLibVersion->setText("libmodbus " + LIB_VER);
ui->lblURL->setText(URL);
}
About::~About()
{
delete ui;
}

View File

@@ -0,0 +1,25 @@
#ifndef ABOUT_H
#define ABOUT_H
#include <QDialog>
namespace Ui {
class About;
}
class About : public QDialog
{
Q_OBJECT
public:
explicit About(QWidget *parent = 0);
~About();
private:
Ui::About *ui;
protected:
};
#endif // ABOUT_H

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>About</class>
<widget class="QDialog" name="About">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>90</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>320</width>
<height>90</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>150</height>
</size>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/icons/info16.png</normaloff>:/icons/info16.png</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblVersion">
<property name="font">
<font>
<pointsize>18</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">QModMaster</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblLibVersion">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>lib version</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblURL">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">http://</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,353 @@
#include <QtDebug>
#include <QFile>
#include <QFileDialog>
#include <QCloseEvent>
#include <QShowEvent>
#include "busmonitor.h"
#include "ui_busmonitor.h"
#include "./src/rawdatadelegate.h"
BusMonitor::BusMonitor(QWidget *parent, RawDataModel *rawDataModel) :
QMainWindow(parent),
ui(new Ui::BusMonitor),
m_rawDataModel(rawDataModel)
{
ui->setupUi(this);
ui->lstRawData->setModel(m_rawDataModel->model);
//TODO : use delegate
//ui->lstRawData->setItemDelegate(new RawDataDelegate());
//Setup Toolbar
ui->toolBar->addAction(ui->actionSave);
ui->toolBar->addAction(ui->actionClear);
ui->toolBar->addAction(ui->actionSxS);
ui->toolBar->addAction(ui->actionExit);
connect(ui->actionSave,SIGNAL(triggered()),this,SLOT(save()));
connect(ui->actionClear,SIGNAL(triggered()),this,SLOT(clear()));
connect(ui->actionSxS,SIGNAL(triggered()),this,SLOT(SxS()));
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(exit()));
connect(ui->lstRawData,SIGNAL(activated(QModelIndex)),this,SLOT(selectedRow(QModelIndex)));
connect(ui->lstRawData,SIGNAL(clicked(QModelIndex)),this,SLOT(selectedRow(QModelIndex)));
ui->lblADU2->setVisible(false);
ui->txtADU2->setVisible(false);
}
BusMonitor::~BusMonitor()
{
delete ui;
}
void BusMonitor::save()
{
//Select file
QString fileName = QFileDialog::getSaveFileName(NULL,"Save File As...",
QDir::homePath(),"Text (*.txt)",0,
QFileDialog::DontConfirmOverwrite);
//Open File
if (fileName.isEmpty())
return;
//continue only if a file name exists
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) return;
//Text Stream
QTextStream ts(&file);
QStringList sl = m_rawDataModel->model->stringList();
//iterate
for (int i = 0; i < sl.size(); ++i)
ts << sl.at(i) << Qt::endl;
//Close File
file.close();
}
void BusMonitor::clear()
{
//qDebug()<< "BusMonitor : clear" ;
m_rawDataModel->clear();
ui->txtADU1->clear();
}
void BusMonitor::SxS()
{
//qDebug()<< "BusMonitor : SxS" ;
if (ui->actionSxS->isChecked()) {
ui->lblADU1->setText("Tx ADU");
ui->lblADU2->setVisible(true);
ui->txtADU2->setVisible(true);
}
else {
ui->lblADU1->setText("ADU");
ui->lblADU2->setVisible(false);
ui->txtADU2->setVisible(false);
}
ui->txtADU1->setPlainText("");
ui->txtADU2->setPlainText("");
}
void BusMonitor::exit()
{
//qDebug()<< "BusMonitor : exit" ;
this->close();
}
void BusMonitor::closeEvent(QCloseEvent *event)
{
m_rawDataModel->enableAddLines(false);
clear();
event->accept();
}
void BusMonitor::showEvent(QShowEvent *event)
{
m_rawDataModel->enableAddLines(true);
event->accept();
}
void BusMonitor::selectedRow(const QModelIndex & selected)
{
int rowCount;
int currRow;
QModelIndex next;
QModelIndex prev;
rowCount = ui->lstRawData->model()->rowCount();
currRow = selected.row();
if (currRow < rowCount - 1){
next = ui->lstRawData->model()->index(currRow +1, 0);
qDebug()<< "Next Row : "<< next.row();
qDebug()<< "Next Data : "<< next.data();
}
if (ui->actionSxS->isChecked()) { //Side by Side Tx - Rx packests
if (selected.data().canConvert(QVariant::String)) {
QString val = selected.data().value<QString>();
qDebug()<< "BusMonitor : selectedRow - " << val;
if (val.indexOf("Sys") > -1)
parseSysMsg(val, ui->txtADU1);
else if (val.indexOf("Tx") > -1){
parseTxMsg(val, ui->txtADU1);
if (currRow < rowCount - 1){
next = ui->lstRawData->model()->index(currRow + 1, 0);
QString valNext = next.data().value<QString>();
if (valNext.indexOf("Rx") > -1)
parseRxMsg(valNext, ui->txtADU2);
}
else {
ui->txtADU2->setPlainText("-");
}
}
else if (val.indexOf("Rx") > -1){
parseRxMsg(val, ui->txtADU2);
if (currRow > 0){
prev = ui->lstRawData->model()->index(currRow - 1, 0);
QString valPrev = prev.data().value<QString>();
if (valPrev.indexOf("Tx") > -1)
parseTxMsg(valPrev, ui->txtADU1);
}
else {
ui->txtADU1->setPlainText("-");
}
}
else
ui->txtADU1->setPlainText("Type : Unknown Message");
}
}
else {
if (selected.data().canConvert(QVariant::String)) {
QString val = selected.data().value<QString>();
qDebug()<< "BusMonitor : selectedRow - " << val;
if (val.indexOf("Sys") > -1)
parseSysMsg(val, ui->txtADU1);
else if (val.indexOf("Tx") > -1)
parseTxMsg(val, ui->txtADU1);
else if (val.indexOf("Rx") > -1)
parseRxMsg(val, ui->txtADU1);
else
ui->txtADU1->setPlainText("Type : Unknown Message");
}
}
}
void BusMonitor::parseTxMsg(QString msg, QPlainTextEdit* txtADU)
{
txtADU->setPlainText("Type : Tx Message");
QStringList row = msg.split(QRegularExpression("\\s+"));
txtADU->appendPlainText("Timestamp : " + row[2]);
if (msg.indexOf("RTU") > -1){//RTU message
QStringList pdu;
if (row.length() < 5){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
for (int i = 4; i < row.length() - 1 ; i++)
pdu.append(row[i]);
parseTxPDU(pdu, "Slave Addr : ", txtADU);
txtADU->appendPlainText("CRC : " + pdu[pdu.length() - 2] + pdu[pdu.length() - 1]);
}
else if (msg.indexOf("TCP") > -1){//TCP message
if (row.length() < 11){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText("Transaction ID : " + row[4] + row[5]);
txtADU->appendPlainText("Protocol ID : " + row[6] + row[7]);
txtADU->appendPlainText("Length : " + row[8] + row[9]);
QStringList pdu;
for (int i = 10; i < row.length() - 1 ; i++)
pdu.append(row[i]);
parseTxPDU(pdu, "Unit ID : ", txtADU);
}
else
txtADU->appendPlainText("Error! Cannot parse Message");
}
void BusMonitor::parseTxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU)
{
if (pdu.length() < 6){//check message length
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code : " + pdu[1]);
//txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code : " + pdu[1]);
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
bool ok;
int fcode = pdu[1].toInt(&ok,16);
if (fcode == 1 || fcode == 2 || fcode == 3 || fcode == 4){//read
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
}
else if (fcode == 5 || fcode == 6){//write
txtADU->appendPlainText("Output Value : " + pdu[4] + pdu[5]);
}
else if (fcode == 15 || fcode == 16){//write multiple
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
if (pdu.length() < 8){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText("Byte Count : " + pdu[6]);
int byteCount = pdu[6].toInt(&ok,16);
QString outputValues = "";
for (int i = 7; i < 7 + byteCount; i++)
outputValues += pdu[i] + " ";
txtADU->appendPlainText("Output Values : " + outputValues);
}
}
void BusMonitor::parseRxMsg(QString msg, QPlainTextEdit* txtADU)
{
txtADU->setPlainText("Type : Rx Message");
QStringList row = msg.split(QRegularExpression("\\s+"));
txtADU->appendPlainText("Timestamp : " + row[2]);
if (msg.indexOf("RTU") > -1){//RTU message
QStringList pdu;
if (row.length() < 5){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
for (int i = 4; i < row.length() - 1 ; i++)
pdu.append(row[i]);
parseRxPDU(pdu, "Slave Addr : ", txtADU);
txtADU->appendPlainText("CRC : " + pdu[pdu.length() - 2] + pdu[pdu.length() - 1]);
}
else if (msg.indexOf("TCP") > -1){//TCP message
if (row.length() < 11){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText("Transaction ID : " + row[4] + row[5]);
txtADU->appendPlainText("Protocol ID : " + row[6] + row[7]);
txtADU->appendPlainText("Length : " + row[8] + row[9]);
QStringList pdu;
for (int i = 10; i < row.length() - 1 ; i++)
pdu.append(row[i]);
parseRxPDU(pdu, "Unit ID : ", txtADU);
}
else
txtADU->appendPlainText("Error! Cannot parse Message");
}
void BusMonitor::parseRxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU)
{
bool ok;
int fcode = pdu[1].toInt(&ok,16);
if (fcode == 1 || fcode == 2 || fcode == 3 || fcode == 4){//read
if (pdu.length() < 4){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code : " + pdu[1]);
txtADU->appendPlainText("Byte Count : " + pdu[2]);
int byteCount = pdu[2].toInt(&ok,16);
QString inputValues = "";
for (int i = 3; i < 3 + byteCount; i++)
inputValues += pdu[i] + " ";
txtADU->appendPlainText("Register Values : " + inputValues);
}
else if (fcode == 5 || fcode == 6){//write
if (pdu.length() < 6){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code : " + pdu[1]);
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
txtADU->appendPlainText("Output Value : " + pdu[4] + pdu[5]);
}
else if (fcode == 15 || fcode == 16){//write multiple
if (pdu.length() < 6){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code : " + pdu[1]);
txtADU->appendPlainText("Starting Address : " + pdu[2] + pdu[3]);
txtADU->appendPlainText("Quantity of Registers : " + pdu[4] + pdu[5]);
}
else if (fcode > 0x80){//exception
if (pdu.length() < 3){//check message length
txtADU->appendPlainText("Error! Cannot parse Message");
return;
}
txtADU->appendPlainText(slave + pdu[0]);
txtADU->appendPlainText("Function Code [80 + Rx Function Code] : " + pdu[1]);
txtADU->appendPlainText("Exception Code : " + pdu[2]);
}
}
void BusMonitor::parseSysMsg(QString msg, QPlainTextEdit* txtADU)
{
txtADU->setPlainText("Type : System Message");
QStringList row = msg.split(QRegularExpression("\\s+"));
txtADU->appendPlainText("Timestamp : " + row[2]);
txtADU->appendPlainText("Message" + msg.mid(msg.indexOf(" : ")));
}

View File

@@ -0,0 +1,43 @@
#ifndef BUSMONITOR_H
#define BUSMONITOR_H
#include <QMainWindow>
#include <QLabel>
#include <QPlainTextEdit>
#include "src/rawdatamodel.h"
namespace Ui {
class BusMonitor;
}
class BusMonitor : public QMainWindow
{
Q_OBJECT
public:
explicit BusMonitor(QWidget *parent, RawDataModel *rawDataModel);
~BusMonitor();
private:
Ui::BusMonitor *ui;
RawDataModel *m_rawDataModel;
void parseTxMsg(QString msg, QPlainTextEdit* txtADU);
void parseTxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU);
void parseRxMsg(QString msg, QPlainTextEdit* txtADU);
void parseRxPDU(QStringList pdu, QString slave, QPlainTextEdit* txtADU);
void parseSysMsg(QString msg, QPlainTextEdit* txtADU);
protected:
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
private slots:
void clear();
void exit();
void save();
void SxS();
void selectedRow(const QModelIndex & selected);
};
#endif // BUSMONITOR_H

View File

@@ -0,0 +1,233 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BusMonitor</class>
<widget class="QMainWindow" name="BusMonitor">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>474</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>540</width>
<height>474</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>720</width>
<height>720</height>
</size>
</property>
<property name="windowTitle">
<string>Bus Monitor</string>
</property>
<property name="windowIcon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/TV-16.png</normaloff>:/icons/TV-16.png</iconset>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>540</width>
<height>460</height>
</size>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>12</x>
<y>2</y>
<width>522</width>
<height>432</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblRawData">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Raw Data</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="lstRawData">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="selectionRectVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblADU1">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">ADU</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblADU2">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">Rx ADU</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPlainTextEdit" name="txtADU1">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="tabChangesFocus">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPlainTextEdit" name="txtADU2">
<property name="enabled">
<bool>true</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string notr="true">toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="actionClear">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
</property>
<property name="text">
<string>Clear</string>
</property>
<property name="toolTip">
<string>Clear</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionExit">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/Close-16.png</normaloff>:/icons/Close-16.png</iconset>
</property>
<property name="text">
<string>Exit</string>
</property>
<property name="toolTip">
<string>Exit</string>
</property>
</action>
<action name="actionSave">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/save-16.png</normaloff>:/icons/save-16.png</iconset>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="toolTip">
<string>Save</string>
</property>
</action>
<action name="actionSxS">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/data-sort-16.png</normaloff>:/icons/data-sort-16.png</iconset>
</property>
<property name="text">
<string>actionSxS</string>
</property>
<property name="toolTip">
<string>Tx-Rx Side by Side</string>
</property>
</action>
</widget>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,779 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>564</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>720</width>
<height>720</height>
</size>
</property>
<property name="windowTitle">
<string>QModMaster</string>
</property>
<property name="windowIcon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/connect-24.png</normaloff>:/icons/connect-24.png</iconset>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="InfoBar" name="infobar">
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_1">
<property name="minimumSize">
<size>
<width>0</width>
<height>38</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lblModbusMode">
<property name="text">
<string>Modbus Mode</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbModbusMode</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbModbusMode">
<item>
<property name="text">
<string notr="true">RTU</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">TCP</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="lblSlave">
<property name="text">
<string>Slave Addr</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>sbSlaveID</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbSlaveID">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>255</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblScan">
<property name="text">
<string>Scan Rate (ms)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spInterval">
<property name="minimum">
<number>1000</number>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="singleStep">
<number>500</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>38</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="topMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lblFunctionCode">
<property name="text">
<string>Function Code</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbFunctionCode</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbFunctionCode">
<property name="frame">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Read Coils (0x01)</string>
</property>
</item>
<item>
<property name="text">
<string>Read Discrete Inputs (0x02)</string>
</property>
</item>
<item>
<property name="text">
<string>Read Holding Registers (0x03)</string>
</property>
</item>
<item>
<property name="text">
<string>Read Input Registers (0x04)</string>
</property>
</item>
<item>
<property name="text">
<string>Write Single Coil (0x05)</string>
</property>
</item>
<item>
<property name="text">
<string>Write Single Register (0x06)</string>
</property>
</item>
<item>
<property name="text">
<string>Write Multiple Coils (0x0f)</string>
</property>
</item>
<item>
<property name="text">
<string>Write Multiple Registers (0x10)</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="lblStartAddress">
<property name="text">
<string>Start Address</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>sbStartAddress</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbStartAddress">
<property name="maximum">
<number>65535</number>
</property>
<property name="displayIntegerBase">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbStartAddrBase">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Dec</string>
</property>
</item>
<item>
<property name="text">
<string>Hex</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<property name="minimumSize">
<size>
<width>0</width>
<height>38</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="topMargin">
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lblNoOfCoils">
<property name="text">
<string>Number of Coils</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>sbNoOfRegs</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbNoOfRegs">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>2000</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblDataFormat">
<property name="text">
<string>Data Format</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>sbStartAddress</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cmbFrmt">
<property name="currentText">
<string>Bin</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Bin</string>
</property>
</item>
<item>
<property name="text">
<string>Dec</string>
</property>
</item>
<item>
<property name="text">
<string>Hex</string>
</property>
</item>
<item>
<property name="text">
<string>Float</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkSigned">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Signed</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblPrecision">
<property name="text">
<string>Precision</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbPrecision">
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>7</number>
</property>
<property name="value">
<number>3</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTableView" name="tblRegisters">
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>true</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionLoad_Session"/>
<addaction name="actionSave_Session"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuOptions">
<property name="title">
<string>Options</string>
</property>
<addaction name="actionSerial_RTU"/>
<addaction name="actionTCP"/>
<addaction name="separator"/>
<addaction name="actionSettings"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionModbus_Manual"/>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionOpenLogFile"/>
<addaction name="actionBus_Monitor"/>
<addaction name="actionTools"/>
<addaction name="separator"/>
<addaction name="actionHeaders"/>
</widget>
<widget class="QMenu" name="menuCommands">
<property name="title">
<string>Commands</string>
</property>
<addaction name="actionConnect"/>
<addaction name="actionRead_Write"/>
<addaction name="actionScan"/>
<addaction name="actionClear"/>
<addaction name="actionReset_Counters"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuOptions"/>
<addaction name="menuCommands"/>
<addaction name="menuView"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="autoFillBackground">
<bool>false</bool>
</property>
</widget>
<action name="actionExit">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/exit-16.png</normaloff>:/icons/exit-16.png</iconset>
</property>
<property name="text">
<string>Exit</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionSerial_RTU">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/serial-pot-16.png</normaloff>:/icons/serial-pot-16.png</iconset>
</property>
<property name="text">
<string notr="true">Modbus RTU...</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionTCP">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/ethernet-port-16.png</normaloff>:/icons/ethernet-port-16.png</iconset>
</property>
<property name="text">
<string notr="true">Modbus TCP...</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionAbout">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/info-sign-16.png</normaloff>:/icons/info-sign-16.png</iconset>
</property>
<property name="text">
<string>About...</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionBus_Monitor">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/TV-16.png</normaloff>:/icons/TV-16.png</iconset>
</property>
<property name="text">
<string>Bus Monitor</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionSettings">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
</property>
<property name="text">
<string>Settings...</string>
</property>
<property name="iconVisibleInMenu">
<bool>true</bool>
</property>
</action>
<action name="actionRead_Write">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/data-sort-16.png</normaloff>:/icons/data-sort-16.png</iconset>
</property>
<property name="text">
<string>Read / Write</string>
</property>
</action>
<action name="actionConnect">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/plug-disconnect-16.png</normaloff>
<normalon>:/icons/plug-connect-16.png</normalon>:/icons/plug-disconnect-16.png</iconset>
</property>
<property name="text">
<string>Connect</string>
</property>
</action>
<action name="actionScan">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/cyclic-process-16.png</normaloff>:/icons/cyclic-process-16.png</iconset>
</property>
<property name="text">
<string>Scan</string>
</property>
</action>
<action name="actionReset_Counters">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/reset-16.png</normaloff>:/icons/reset-16.png</iconset>
</property>
<property name="text">
<string>Reset Counters</string>
</property>
</action>
<action name="actionSimplified_Chinese_zh_CN">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/China-flag-16.png</normaloff>:/icons/China-flag-16.png</iconset>
</property>
<property name="text">
<string notr="true">简体中文 (zh_CN)</string>
</property>
<property name="iconText">
<string notr="true">简体中文 (zh_CN)</string>
</property>
<property name="toolTip">
<string notr="true">简体中文 (zh_CN)</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</action>
<action name="actionTraditional_Chinese_zh_TW">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/Taiwan-flag-16.png</normaloff>:/icons/Taiwan-flag-16.png</iconset>
</property>
<property name="text">
<string notr="true">繁體中文 (zh_TW)</string>
</property>
<property name="iconText">
<string notr="true">繁體中文 (zh_TW)</string>
</property>
<property name="toolTip">
<string notr="true">繁體中文 (zh_TW)</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</action>
<action name="actionEnglish_en_US">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/usa-flag-16.png</normaloff>:/icons/usa-flag-16.png</iconset>
</property>
<property name="text">
<string notr="true">English (en_US)</string>
</property>
<property name="iconText">
<string notr="true">English (en_US)</string>
</property>
<property name="toolTip">
<string notr="true">English (en_US)</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
</action>
<action name="actionOpenLogFile">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/text-x-log-16.png</normaloff>:/icons/text-x-log-16.png</iconset>
</property>
<property name="text">
<string>Log File</string>
</property>
</action>
<action name="actionClear">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
</property>
<property name="text">
<string>Clear Table</string>
</property>
</action>
<action name="actionModbus_Manual">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/help-desk-icon-16.png</normaloff>:/icons/help-desk-icon-16.png</iconset>
</property>
<property name="text">
<string>Modbus Manual</string>
</property>
</action>
<action name="actionLoad_Session">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/document-import-16.png</normaloff>:/icons/document-import-16.png</iconset>
</property>
<property name="text">
<string>Load Session...</string>
</property>
</action>
<action name="actionSave_Session">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/document-export-16.png</normaloff>:/icons/document-export-16.png</iconset>
</property>
<property name="text">
<string>Save Session...</string>
</property>
</action>
<action name="actionHeaders">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/Header16.png</normaloff>:/icons/Header16.png</iconset>
</property>
<property name="text">
<string>Headers</string>
</property>
</action>
<action name="actionTools">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/tools-16.png</normaloff>:/icons/tools-16.png</iconset>
</property>
<property name="text">
<string>Tools</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>InfoBar</class>
<extends>QFrame</extends>
<header>src/infobar.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tblRegisters</tabstop>
</tabstops>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>actionExit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>149</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,49 @@
#include <QtDebug>
#include "settings.h"
#include "ui_settings.h"
Settings::Settings(QWidget *parent ,ModbusCommSettings *settings) :
QDialog(parent),
ui(new Ui::Settings),
m_settings(settings)
{
ui->setupUi(this);
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
}
Settings::~Settings()
{
delete ui;
}
void Settings::showEvent(QShowEvent * event)
{
//Load Settings
ui->sbMaxNoOfRawDataLines->setEnabled(!modbus_connected);
ui->sbResponseTimeout->setEnabled(!modbus_connected);
if (m_settings != NULL) {
ui->sbMaxNoOfRawDataLines->setValue(m_settings->maxNoOfLines().toInt());
ui->sbResponseTimeout->setValue(m_settings->timeOut().toInt());
ui->sbBaseAddr->setValue(m_settings->baseAddr().toInt());
ui->cmbEndian->setCurrentIndex(m_settings->endian());
}
}
void Settings::changesAccepted()
{
//Save Settings
if (m_settings != NULL) {
m_settings->setMaxNoOfLines(ui->sbMaxNoOfRawDataLines->cleanText());
m_settings->setTimeOut(ui->sbResponseTimeout->cleanText());
m_settings->setBaseAddr(ui->sbBaseAddr->cleanText());
if (m_settings->endian() != ui->cmbEndian->currentIndex())
emit changedEndianess(ui->cmbEndian->currentIndex());
m_settings->setEndian(ui->cmbEndian->currentIndex());
}
}

View File

@@ -0,0 +1,38 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QDialog>
#include <QSettings>
#include "src/modbuscommsettings.h"
namespace Ui {
class Settings;
}
class Settings : public QDialog
{
Q_OBJECT
public:
explicit Settings(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
~Settings();
bool modbus_connected;
private:
Ui::Settings *ui;
ModbusCommSettings *m_settings;
signals:
void changedEndianess(int endian);
private slots:
void changesAccepted();
protected:
void showEvent(QShowEvent * event);
};
#endif // SETTINGS_H

View File

@@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings</class>
<widget class="QDialog" name="Settings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>220</width>
<height>150</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>220</width>
<height>150</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>320</width>
<height>150</height>
</size>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<property name="windowIcon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QSpinBox" name="sbResponseTimeout">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblBaseAddr">
<property name="text">
<string>Base Addr</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblMaxNoOfRawDataLines">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>132</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Max No Of Bus Monitor Lines</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblTimeout">
<property name="text">
<string>Response Timeout (sec)</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="sbMaxNoOfRawDataLines">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>600</number>
</property>
<property name="singleStep">
<number>60</number>
</property>
<property name="value">
<number>60</number>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="sbBaseAddr">
<property name="maximum">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblEndian">
<property name="text">
<string>Endian</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="cmbEndian">
<item>
<property name="text">
<string>Little</string>
</property>
</item>
<item>
<property name="text">
<string>Big</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Settings</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Settings</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,81 @@
#include <QtDebug>
#include "settingsmodbusrtu.h"
#include "ui_settingsmodbusrtu.h"
SettingsModbusRTU::SettingsModbusRTU(QWidget *parent,ModbusCommSettings * settings) :
QDialog(parent),
ui(new Ui::SettingsModbusRTU),
m_settings(settings)
{
ui->setupUi(this);
/* device name is needed only in Linux */
#ifdef Q_OS_WIN32
ui->cmbDev->setDisabled(true);
#else
ui->cmbDev->setDisabled(false);
#endif
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
}
SettingsModbusRTU::~SettingsModbusRTU()
{
delete ui;
}
void SettingsModbusRTU::showEvent(QShowEvent * event)
{
//Load Settings
ui->cmbDataBits->setEnabled(!modbus_connected);
ui->cmbBaud->setEnabled(!modbus_connected);
ui->sbPort->setEnabled(!modbus_connected);
ui->cmbParity->setEnabled(!modbus_connected);
ui->cmbRTS->setEnabled(!modbus_connected);
ui->cmbStopBits->setEnabled(!modbus_connected);
if (m_settings != NULL) {
ui->cmbRTS->clear();
//Populate cmbPort-cmbRTS
#ifdef Q_OS_WIN32
ui->cmbRTS->addItem("Disable");
ui->cmbRTS->addItem("Enable");
ui->cmbRTS->addItem("HandShake");
ui->cmbRTS->addItem("Toggle");
#else
ui->cmbRTS->addItem("None");
ui->cmbRTS->addItem("Up");
ui->cmbRTS->addItem("Down");
#endif
ui->cmbDev->setCurrentText(m_settings->serialDev());
ui->sbPort->setValue(m_settings->serialPort().toInt());
ui->cmbBaud->setCurrentIndex(ui->cmbBaud->findText(m_settings->baud()));
ui->cmbDataBits->setCurrentIndex(ui->cmbDataBits->findText(m_settings->dataBits()));
ui->cmbStopBits->setCurrentIndex(ui->cmbStopBits->findText(m_settings->stopBits()));
ui->cmbParity->setCurrentIndex(ui->cmbParity->findText(m_settings->parity()));
ui->cmbRTS->setCurrentIndex(ui->cmbRTS->findText(m_settings->RTS()));
}
}
void SettingsModbusRTU::changesAccepted()
{
//Save Settings
if (m_settings != NULL) {
m_settings->setSerialPort(QString::number(ui->sbPort->value()), ui->cmbDev->currentText());
m_settings->setBaud(ui->cmbBaud->currentText());
m_settings->setDataBits(ui->cmbDataBits->currentText());
m_settings->setStopBits(ui->cmbStopBits->currentText());
m_settings->setParity(ui->cmbParity->currentText());
m_settings->setRTS((QString)ui->cmbRTS->currentText());
}
}

View File

@@ -0,0 +1,34 @@
#ifndef SETTINGSMODBUSRTU_H
#define SETTINGSMODBUSRTU_H
#include <QDialog>
#include <QSettings>
#include "src/modbuscommsettings.h"
namespace Ui {
class SettingsModbusRTU;
}
class SettingsModbusRTU : public QDialog
{
Q_OBJECT
public:
explicit SettingsModbusRTU(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
~SettingsModbusRTU();
bool modbus_connected;
private:
Ui::SettingsModbusRTU *ui;
ModbusCommSettings * m_settings;
private slots:
void changesAccepted();
protected:
void showEvent(QShowEvent * event);
};
#endif // SETTINGSMODBUSRTU_H

View File

@@ -0,0 +1,352 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsModbusRTU</class>
<widget class="QDialog" name="SettingsModbusRTU">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>220</width>
<height>256</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>220</width>
<height>256</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>220</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>Modbus RTU Settings</string>
</property>
<property name="windowIcon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/options-16.png</normaloff>:/icons/options-16.png</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="cmbDev">
<property name="editable">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>/dev/ttyS</string>
</property>
</item>
<item>
<property name="text">
<string>/dev/ttyUSB</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblDev">
<property name="text">
<string>Serial device</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblBaud">
<property name="text">
<string>Baud</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbBaud</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="sbPort">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>128</number>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cmbBaud">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string notr="true">110</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">300</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">600</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">1200</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">2400</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">4800</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">9600</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">14400</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">19200</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">28800</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">38400</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">57600</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">115200</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">128000</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">256000</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">921600</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cmbDataBits">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string notr="true">7</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">8</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblDataBits">
<property name="text">
<string>Data Bits</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbDataBits</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblRTS">
<property name="text">
<string notr="true">RTS</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblStopBits">
<property name="text">
<string>Stop Bits</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbStopBits</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cmbRTS"/>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cmbParity">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Odd</string>
</property>
</item>
<item>
<property name="text">
<string>Even</string>
</property>
</item>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="cmbStopBits">
<property name="currentIndex">
<number>-1</number>
</property>
<item>
<property name="text">
<string notr="true">1</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">1.5</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">2</string>
</property>
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblParity">
<property name="text">
<string>Parity</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>cmbParity</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblPort">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Serial port</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsModbusRTU</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsModbusRTU</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,81 @@
#include <QtDebug>
#include <QMessageBox>
#include "settingsmodbustcp.h"
#include "ui_settingsmodbustcp.h"
SettingsModbusTCP::SettingsModbusTCP(QWidget *parent, ModbusCommSettings * settings) :
QDialog(parent),
ui(new Ui::SettingsModbusTCP),
m_settings(settings)
{
ui->setupUi(this);
connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(changesAccepted()));
}
SettingsModbusTCP::~SettingsModbusTCP()
{
delete ui;
}
void SettingsModbusTCP::showEvent(QShowEvent * event)
{
//Load Settings
ui->leSlaveIP->setEnabled(!modbus_connected);
ui->leTCPPort->setEnabled(!modbus_connected);
if (m_settings != NULL) {
ui->leTCPPort->setText(m_settings->TCPPort());
ui->leSlaveIP->setText(m_settings->slaveIP());
}
}
void SettingsModbusTCP::changesAccepted()
{
int validation;
validation = validateInputs();
switch(validation){
case 0 : // ok
//Save Settings
if (m_settings != NULL) {
m_settings->setTCPPort(ui->leTCPPort->text());
m_settings->setSlaveIP(ui->leSlaveIP->text());
}
break;
case 1 : // wrong ip
QMessageBox::critical(NULL, "Modbus TCP Settings","Wrong IP Address.");
break;
case 2 : // wrong port
QMessageBox::critical(NULL, "Modbus TCP Settings","Wrong Port Number.");
break;
}
}
int SettingsModbusTCP::validateInputs()
{
//Strip zero's from IP
QStringList ipBytes;
bool ok;
int i, ipByte, port;
ipBytes = (ui->leSlaveIP->text()).split(".");
if (ipBytes.size() == 4){
for (i = 0; i < ipBytes.size(); i++){
ipByte = ipBytes[i].toInt(&ok);
if (!ok || ipByte > 255 )
return 1; // wrong ip
}
}
else
return 1; // wrong ip
port = (ui->leTCPPort->text()).toInt(&ok);
if (!ok || port <= 0 || port > 65535)
return 2; // wrong port
return 0; // validate ok
}

View File

@@ -0,0 +1,37 @@
#ifndef SETTINGSMODBUSTCP_H
#define SETTINGSMODBUSTCP_H
#include <QDialog>
#include <QSettings>
#include <QAbstractButton>
#include "src/modbuscommsettings.h"
namespace Ui {
class SettingsModbusTCP;
}
class SettingsModbusTCP : public QDialog
{
Q_OBJECT
public:
explicit SettingsModbusTCP(QWidget *parent = 0 ,ModbusCommSettings * settings = 0);
~SettingsModbusTCP();
bool modbus_connected;
private:
Ui::SettingsModbusTCP *ui;
ModbusCommSettings * m_settings;
int validateInputs();
private slots:
void changesAccepted();
protected:
void showEvent(QShowEvent * event);
};
#endif // SETTINGSMODBUSTCP_H

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsModbusTCP</class>
<widget class="QDialog" name="SettingsModbusTCP">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>240</width>
<height>110</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>240</width>
<height>110</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>240</width>
<height>160</height>
</size>
</property>
<property name="windowTitle">
<string>Modbus TCP Settings</string>
</property>
<property name="windowIcon">
<iconset>
<normaloff>:/img/network-16.png</normaloff>:/img/network-16.png</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QLabel" name="lblSlaveIP">
<property name="text">
<string>Slave IP</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblTCPPort">
<property name="text">
<string>TCP Port</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>leTCPPort</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="leTCPPort">
<property name="inputMask">
<string/>
</property>
<property name="text">
<string/>
</property>
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leSlaveIP">
<property name="inputMask">
<string notr="true">999.999.999.999;_</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsModbusTCP</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsModbusTCP</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,216 @@
#include "tools.h"
#include "ui_tools.h"
#include "QsLog.h"
Tools::Tools(QWidget *parent, ModbusAdapter *adapter, ModbusCommSettings *settings) :
QMainWindow(parent),
m_modbusAdapter(adapter), m_modbusCommSettings(settings),
ui(new Ui::Tools)
{
//setup UI
ui->setupUi(this);
cmbModbusMode = new QComboBox(this);
cmbModbusMode->setMinimumWidth(96);
cmbModbusMode->addItem("RTU/TCP");cmbModbusMode->addItem("TCP");
cmbCmd = new QComboBox(this);
cmbCmd->setMinimumWidth(96);
cmbCmd->addItem("Report Slave ID");
ui->toolBar->addWidget(cmbModbusMode);
ui->toolBar->addWidget(cmbCmd);
ui->toolBar->addSeparator();
ui->toolBar->addAction(ui->actionExec);
ui->toolBar->addAction(ui->actionClear);
ui->toolBar->addAction(ui->actionExit);
//UI - connections
connect(cmbModbusMode,SIGNAL(currentIndexChanged(int)),this,SLOT(changedModbusMode(int)));
connect(ui->actionExec,SIGNAL(triggered(bool)),this,SLOT(execCmd()));
connect(ui->actionClear,SIGNAL(triggered(bool)),this,SLOT(clear()));
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(exit()));
connect(&m_pingProc,SIGNAL(readyReadStandardOutput()),this,SLOT(pingData()));
connect(&m_pingProc,SIGNAL(readyReadStandardError()),this,SLOT(pingData()));
}
Tools::~Tools()
{
delete ui;
}
void Tools::exit()
{
this->close();
}
QString Tools::ipConv(QString ip)
{
/* convert ip - remove leding 0's */
QStringList m_ip;
QStringList m_ip_conv;
QString m_ip_byte;
m_ip = ip.split(".");
for (int i = 0; i < m_ip.size(); i++){
m_ip_byte = m_ip.at(i);
if (m_ip_byte.at(0)=='0')
m_ip_conv << m_ip_byte.remove(0,1);
else
m_ip_conv << m_ip_byte;
}
return (m_ip_conv.at(0) + "." + m_ip_conv.at(1) + "." + m_ip_conv.at(2) + "." + m_ip_conv.at(3));
}
void Tools::changedModbusMode(int currIndex)
{
QLOG_TRACE()<< "Modbus Mode changed. Index = " << currIndex;
cmbCmd->clear();
if (currIndex == 0) { //RTU/TCP
cmbCmd->addItem("Report Slave ID");
}
else { //TCP
cmbCmd->addItem("Report Slave ID");cmbCmd->addItem("Ping");cmbCmd->addItem("Port Status");
}
}
void Tools::execCmd()
{
ui->txtOutput->moveCursor(QTextCursor::End);
QLOG_TRACE()<< "Tools Execute Cmd " << cmbCmd->currentText();
switch (cmbCmd->currentIndex()){
case 0:
ui->txtOutput->appendPlainText(QString("------- Modbus Diagnotics : Report Slave ID %1 -------\n").arg(m_modbusCommSettings->slaveID()));
diagnosticsProc();
break;
case 1:
ui->txtOutput->appendPlainText(QString("------- Modbus TCP : Ping IP %1 -------\n").arg(m_modbusCommSettings->slaveIP()));
pingProc();
break;
case 2:
ui->txtOutput->appendPlainText(QString("------- Modbus TCP : Check Port %1:%2 Status -------\n").arg(m_modbusCommSettings->slaveIP(),m_modbusCommSettings->TCPPort()));
portProc();
break;
default:
ui->txtOutput->appendPlainText("------- No Valid Selection -------\n");
break;
}
}
void Tools::clear()
{
QLOG_TRACE()<< "Tools Clear Ouput";
ui->txtOutput->clear();
}
void Tools::diagnosticsProc()
{
qApp->processEvents();
ui->txtOutput->moveCursor(QTextCursor::End);
if(m_modbusAdapter->m_modbus != NULL){
modbusDiagnostics();
}
else{
ui->txtOutput->insertPlainText("Not Connected.\n");
}
}
void Tools::pingProc()
{
qApp->processEvents();
m_pingProc.start("ping", QStringList() << ipConv(m_modbusCommSettings->slaveIP()));
if (m_pingProc.waitForFinished(5000)){
//just wait -> execute button is pressed
}
}
void Tools::pingData()
{
qApp->processEvents();
ui->txtOutput->moveCursor(QTextCursor::End);
ui->txtOutput->insertPlainText(m_pingProc.readAll());
}
void Tools::portProc()
{
qApp->processEvents();
ui->txtOutput->moveCursor(QTextCursor::End);
m_portProc.connectToHost(ipConv(m_modbusCommSettings->slaveIP()),m_modbusCommSettings->TCPPort().toInt());
if (m_portProc.waitForConnected(5000)){//wait -> execute button is pressed
ui->txtOutput->insertPlainText("Connected.Port is opened\n");
m_portProc.close();
}
else{
ui->txtOutput->insertPlainText("Not connected.Port is closed\n");
}
}
void Tools::modbusDiagnostics()
{
//Modbus diagnostics - RTU/TCP
QLOG_TRACE()<< "Modbus diagnostics.";
//Modbus data
m_modbusAdapter->setFunctionCode(0x11);
uint8_t dest[1024]; //setup memory for data
memset(dest, 0, 1024);
int ret = -1; //return value from read functions
modbus_set_slave(m_modbusAdapter->m_modbus, m_modbusCommSettings->slaveID());
//request data from modbus
ret = modbus_report_slave_id(m_modbusAdapter->m_modbus, MODBUS_MAX_PDU_LENGTH, dest);
QLOG_TRACE() << "Modbus Read Data return value = " << ret << ", errno = " << errno;
//update data model
if(ret > 1)
{
QString line;
line = dest[1]?"ON":"OFF";
ui->txtOutput->insertPlainText("Run Status : " + line + "\n");
QString id = QString::fromUtf8((char*)dest);
ui->txtOutput->insertPlainText("ID : " + id.right(id.size()-2) + "\n");;
}
else
{
QString line = "";
if(ret < 0) {
line = QString("Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Read diagnostics data failed. " << line;
line = QString(tr("Read diagnostics data failed.\nError : ")) + EUtils::libmodbus_strerror(errno);
ui->txtOutput->insertPlainText(line);
}
else {
line = QString("Unknown Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Read diagnostics data failed. " << line;
line = QString(tr("Read diagnostics data failed.\nUnknown Error : ")) + EUtils::libmodbus_strerror(errno);
ui->txtOutput->insertPlainText(line);
}
modbus_flush(m_modbusAdapter->m_modbus); //flush data
}
}

View File

@@ -0,0 +1,47 @@
#ifndef TOOLS_H
#define TOOLS_H
#include <QMainWindow>
#include <QProcess>
#include <QTcpSocket>
#include <qcombobox.h>
#include "src/modbusadapter.h"
#include "src/modbuscommsettings.h"
namespace Ui {
class Tools;
}
class Tools : public QMainWindow
{
Q_OBJECT
public:
explicit Tools(QWidget *parent = 0, ModbusAdapter *adapter = 0, ModbusCommSettings *settings = 0);
~Tools();
private:
Ui::Tools *ui;
QComboBox *cmbModbusMode;
QComboBox *cmbCmd;
ModbusAdapter *m_modbusAdapter;
ModbusCommSettings *m_modbusCommSettings;
QProcess m_pingProc;
QTcpSocket m_portProc;
QString ipConv(QString ip);
void pingProc();
void portProc();
void diagnosticsProc();
void modbusDiagnostics();
private slots:
void exit();
void changedModbusMode(int currIndex);
void execCmd();
void clear();
void pingData();
};
#endif // TOOLS_H

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Tools</class>
<widget class="QMainWindow" name="Tools">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>564</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>720</width>
<height>720</height>
</size>
</property>
<property name="windowTitle">
<string>Tools</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="txtOutput">
<property name="font">
<font>
<family>Tahoma</family>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="actionExit">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/Close-16.png</normaloff>:/icons/Close-16.png</iconset>
</property>
<property name="text">
<string>Exit</string>
</property>
<property name="toolTip">
<string>Exit</string>
</property>
</action>
<action name="actionExec">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/play-16.png</normaloff>:/icons/play-16.png</iconset>
</property>
<property name="text">
<string>Exec</string>
</property>
<property name="toolTip">
<string>Execute Command</string>
</property>
</action>
<action name="actionClear">
<property name="icon">
<iconset resource="../icons/icons.qrc">
<normaloff>:/icons/edit-clear-16.png</normaloff>:/icons/edit-clear-16.png</iconset>
</property>
<property name="text">
<string>Clear</string>
</property>
<property name="toolTip">
<string>Clear Output</string>
</property>
</action>
</widget>
<resources>
<include location="../icons/icons.qrc"/>
</resources>
<connections/>
</ui>