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,107 @@
#include <QDebug>
#include "eutils.h"
EUtils::EUtils()
{
}
QString EUtils::formatValue(int value,int frmt, bool is16Bit, bool isSigned=false)
{
QString convertedValue;
switch(frmt){
case EUtils::Bin://Binary
if (is16Bit)
if (isSigned)
convertedValue = QString("%1").arg((signed short)value,16,2,QLatin1Char('0'));
else
convertedValue = QString("%1").arg((unsigned short)value,16,2,QLatin1Char('0'));
else
convertedValue = QString("%1").arg(value,0,2);
break;
case EUtils::Dec://Decimal - Unsigned Integer
if (isSigned)
convertedValue = QString("%1").arg((signed short)value,0,10);
else
convertedValue = QString("%1").arg((unsigned short)value,0,10);
break;
case EUtils::Hex://Hex
if (is16Bit)
convertedValue = QString("%1").arg(value,4,16,QLatin1Char('0'));
else
convertedValue = QString("%1").arg(value,0,16);
break;
default://Default
convertedValue = QString("%1").arg(value,0,10);
}
return convertedValue.toUpper();
}
QString EUtils::formatValue32(int valueHi, int valueLo, int endian = EUtils::Little, int precision = -1)
{
union{
struct{qint16 low, high;} reg;
float value;
} data;
QString convertedValue;
if (endian == EUtils::Little){
data.reg.high = valueLo;
data.reg.low = valueHi;
}
else if (endian == EUtils::Big){
data.reg.high = valueHi;
data.reg.low = valueLo;
}
convertedValue = QString("%1").arg(data.value, 0, 'G', precision);
return convertedValue.toUpper();
}
QString EUtils::formatValue32(float value, int precision = -1)
{
QString convertedValue;
convertedValue = QString("%1").arg(value, 0, 'G', precision);
return convertedValue.toUpper();
}
QString EUtils::libmodbus_strerror(int errnum)
{
switch (errnum) {
case EINVAL:
return "Protocol context is NULL";
case ETIMEDOUT:
return "Timeout";
case ECONNRESET:
return "Connection reset";
case ECONNREFUSED:
return "Connection refused";
case EPIPE:
return "Socket error";
default://Default
return modbus_strerror(errno);
}
}

View File

@@ -0,0 +1,173 @@
#ifndef EUTILS_H
#define EUTILS_H
#include <QString>
#include <QMap>
#include <QTime>
#include "modbus.h"
static const QString ModbusFunctionNames[]={"Read Coils (0x01)","Read Discrete Inputs (0x02)","Read Holding Registers (0x03)",
"Read Input Registers (0x04)","Write Single Coil (0x05)","Write Single Register (0x06)",
"Write Multiple Coils (0x0f)","Write Multiple Registers (0x10)","Report Server ID (0x11)"};
static const int ModbusFunctionCodes[]={0x1,0x2,0x3,0x4,0x5,0x6,0xf,0x10,0x11};
static const QString ModbusModeStamp[]={"[RTU]>","[TCP]>",""};
class EUtils
{
private:
EUtils();
public:
static QString ModbusDataTypeName(int fCode)
{
switch(fCode)
{
case MODBUS_FC_READ_COILS:
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
return "Coil (binary)";
case MODBUS_FC_READ_DISCRETE_INPUTS:
return "Discrete Input (binary)";
case MODBUS_FC_READ_HOLDING_REGISTERS:
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
return "Holding Register (16 bit)";
case MODBUS_FC_READ_INPUT_REGISTERS:
return "Input Register (16 bit)";
default:
break;
}
return "Unknown";
}
static bool ModbusIsWriteFunction(int fCode)
{
switch(fCode)
{
case MODBUS_FC_READ_COILS:
case MODBUS_FC_READ_DISCRETE_INPUTS:
case MODBUS_FC_READ_HOLDING_REGISTERS:
case MODBUS_FC_READ_INPUT_REGISTERS:
return false;
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
return true;
default:
break;
}
return false;
}
static bool ModbusIsWriteCoilsFunction(int fCode)
{
switch(fCode)
{
case MODBUS_FC_READ_COILS:
case MODBUS_FC_READ_DISCRETE_INPUTS:
case MODBUS_FC_READ_HOLDING_REGISTERS:
case MODBUS_FC_READ_INPUT_REGISTERS:
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
return false;
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
return true;
default:
break;
}
return false;
}
static bool ModbusIsWriteRegistersFunction(int fCode)
{
switch(fCode)
{
case MODBUS_FC_READ_COILS:
case MODBUS_FC_READ_DISCRETE_INPUTS:
case MODBUS_FC_READ_HOLDING_REGISTERS:
case MODBUS_FC_READ_INPUT_REGISTERS:
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
return false;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
return true;
default:
break;
}
return false;
}
static QString ModbusFunctionName(int index)
{
return ModbusFunctionNames[index];
}
static int ModbusFunctionCode(int index)
{
return ModbusFunctionCodes[index];
}
static QString TxTimeStamp(int md)
{
return (ModbusModeStamp[md] + "Tx > " + QTime::currentTime().toString("HH:mm:ss:zzz"));
}
static QString RxTimeStamp(int md)
{
return (ModbusModeStamp[md] + "Rx > " + QTime::currentTime().toString("HH:mm:ss:zzz"));
}
static QString SysTimeStamp()
{
return ("Sys > " + QTime::currentTime().toString("HH:mm:ss:zzz"));
}
static QChar parity(QString p)
{
//the first char is what we need
return p.at(0);
}
static QString endianness(int endian)
{
switch (endian)
{
case 0:
return "Little";
case 1:
return "Big";
default:
return "N/A";
}
}
static enum {RTU = 0, TCP = 1, None = 0} ModbusMode;
static enum {Bin = 2, Dec = 10, Float = 11, Hex = 16} NumberFormat;
static enum {Little =0, Big = 1} Endianness;
static enum {ReadCoils = 0x1, ReadDisInputs = 0x2,
ReadHoldRegs = 0x3, ReadInputRegs = 0x4,
WriteSingleCoil = 0x5, WriteSingleReg = 0x6,
WriteMultiCoils = 0xf, WriteMultiRegs = 0x10} FunctionCodes;
static QString formatValue(int value,int frmt, bool is16Bit, bool isSigned);
static QString formatValue32(int valueHi, int valueLo, int endian, int precision);
static QString formatValue32(float value, int precision);
static QString libmodbus_strerror(int errnum);
};
#endif // EUTILS_H

View File

@@ -0,0 +1,76 @@
#include <QFrame>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include "infobar.h"
InfoBar::InfoBar(QWidget *parent) : QFrame(parent)
{
label = new QLabel;
QPushButton *button = new QPushButton;
button->setStyleSheet("QPushButton{image: url(:/icons/close8-black.png);\
background-color: lightgrey;\
border: none;\
height: 12px;\
width: 12px}\
QPushButton:hover{image: url(:/icons/close8-red.png);\
background-color: lightgrey;\
border: none;\
height: 12px;\
width: 12px}\
QPushButton:pressed{image: url(:/icons/close8-red.png);\
background-color: lightgrey;\
border: 1px solid darkgrey;\
border-radius: 2px;\
height: 12px;\
width: 12px}");
button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
button->setFocusPolicy(Qt::NoFocus);
connect(button, SIGNAL(clicked()), this, SLOT(hide()));
QHBoxLayout *hboxlayout = new QHBoxLayout;
hboxlayout->addWidget(label);
hboxlayout->addWidget(button);
setLayout(hboxlayout);
setFrameStyle(QFrame::Box);
hide();
}
InfoBar::InfoBar(QString message, InfoType type, QWidget *parent) : InfoBar(parent)
{
setMessage(message);
setInfoType(type);
}
void InfoBar::setInfoType(InfoType type)
{
switch (type) {
case Question:
setStyleSheet("color: black;\
background-color: skyblue");
break;
case Error:
setStyleSheet("color: white;\
background-color: red");
break;
default:
case Warning:
setStyleSheet("color: black;\
background-color: yellow");
break;
}
}
void InfoBar::setMessage(QString message)
{
label->setText(message);
}
void InfoBar::show(QString message, InfoType type)
{
setMessage(message);
setInfoType(type);
QFrame::show();
}

View File

@@ -0,0 +1,26 @@
#ifndef _MyInfoBar_H_
#define _MyInfoBar_H_
#include <QLabel>
#include <QFrame>
class InfoBar : public QFrame
{
Q_OBJECT
private:
QLabel *label;
public:
enum InfoType {
Question,
Warning,
Error
};
InfoBar(QWidget *parent = 0);
InfoBar(QString message, InfoType type, QWidget *parent = 0);
void setInfoType(InfoType type);
void setMessage(QString message);
void show(QString message, InfoType type);
};
#endif

View File

@@ -0,0 +1,63 @@
#include <QApplication>
#include <stdio.h>
#include <stdlib.h>
#include <QDir>
#include <QTranslator>
#include "QsLog.h"
#include "QsLogDest.h"
#include "mainwindow.h"
#include "modbusadapter.h"
#include "modbuscommsettings.h"
QTranslator *Translator;
//Logging Levels
//TraceLevel : 0
//DebugLevel : 1
//InfoLevel : 2
//WarnLevel : 3
//ErrorLevel : 4
//FatalLevel : 5
//OffLevel : 6
int main(int argc, char *argv[])
{
//qt dpi warnings
qputenv("QT_DEVICE_PIXEL_RATIO", "0");
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
qputenv("QT_SCREEN_SCALE_FACTORS", "1");
qputenv("QT_SCALE_FACTOR", "1");
//application startup
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
Translator = new QTranslator;
Translator->load(":/translations/" + QCoreApplication::applicationName() + "_" + QLocale::system().name());
app.installTranslator(Translator);
//init the logging mechanism
QsLogging::Logger& logger = QsLogging::Logger::instance();
logger.setLoggingLevel(QsLogging::OffLevel); // start with no logging
const QString sLogPath(QDir(app.applicationDirPath()).filePath("QModMaster.log"));
QsLogging::DestinationPtr fileDestination(QsLogging::DestinationFactory::MakeFileDestination(sLogPath,true,65535,7));
QsLogging::DestinationPtr debugDestination(QsLogging::DestinationFactory::MakeDebugOutputDestination());
logger.addDestination(debugDestination);
logger.addDestination(fileDestination);
//Modbus Adapter
ModbusAdapter modbus_adapt(NULL);
//Program settings
ModbusCommSettings settings("qModMaster.ini");
//show main window
mainWin = new MainWindow(NULL, &modbus_adapt, &settings);
//connect signals - slots
QObject::connect(&modbus_adapt, SIGNAL(refreshView()), mainWin, SLOT(refreshView()));
QObject::connect(mainWin, SIGNAL(resetCounters()), &modbus_adapt, SLOT(resetCounters()));
mainWin->show();
return app.exec();
}

View File

@@ -0,0 +1,860 @@
#include <QtDebug>
#include <QCoreApplication>
#include <QDesktopServices>
#include <QUrl>
#include <QTranslator>
#include <QMessageBox>
#include <QFileDialog>
#include "QsLog.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "eutils.h"
MainWindow *mainWin;
MainWindow::MainWindow(QWidget *parent, ModbusAdapter *adapter, ModbusCommSettings *settings) :
QMainWindow(parent), m_modbus(adapter), m_modbusCommSettings(settings),
ui(new Ui::MainWindow)
{
//setup UI
ui->setupUi(this);
ui->sbNoOfRegs->setEnabled(true);
ui->actionRead_Write->setEnabled(false);
ui->actionScan->setEnabled(false);
ui->sbStartAddress->setMinimum(m_modbusCommSettings->baseAddr().toInt());
ui->cmbFrmt->setCurrentIndex(m_modbusCommSettings->frmt());
ui->cmbFunctionCode->setCurrentIndex(m_modbusCommSettings->functionCode());
ui->cmbModbusMode->setCurrentIndex(m_modbusCommSettings->modbusMode());
ui->sbSlaveID->setValue(m_modbusCommSettings->slaveID());
ui->spInterval->setValue(m_modbusCommSettings->scanRate());
ui->sbStartAddress->setValue(m_modbusCommSettings->startAddr());
ui->sbNoOfRegs->setValue(m_modbusCommSettings->noOfRegs());
ui->chkSigned->setVisible(false);
ui->tblRegisters->setStyleSheet("QHeaderView::section { background-color:lightGray }");
//UI - dialogs
m_dlgAbout = new About();
connect(ui->actionAbout,SIGNAL(triggered()),m_dlgAbout,SLOT(show()));
m_dlgModbusRTU = new SettingsModbusRTU(this,m_modbusCommSettings);
connect(ui->actionSerial_RTU,SIGNAL(triggered()),this,SLOT(showSettingsModbusRTU()));
m_dlgModbusTCP = new SettingsModbusTCP(this,m_modbusCommSettings);
connect(ui->actionTCP,SIGNAL(triggered()),this,SLOT(showSettingsModbusTCP()));
m_dlgSettings = new Settings(this,m_modbusCommSettings);
connect(ui->actionSettings,SIGNAL(triggered()),this,SLOT(showSettings()));
m_busMonitor = new BusMonitor(this, m_modbus->rawModel);
connect(ui->actionBus_Monitor,SIGNAL(triggered()),this,SLOT(showBusMonitor()));
m_tools = new Tools(this, m_modbus, m_modbusCommSettings);
connect(ui->actionTools,SIGNAL(triggered()),this,SLOT(showTools()));
//UI - connections
connect(ui->cmbModbusMode,SIGNAL(currentIndexChanged(int)),this,SLOT(changedModbusMode(int)));
connect(ui->cmbFunctionCode,SIGNAL(currentIndexChanged(int)),this,SLOT(changedFunctionCode(int)));
connect(ui->cmbFrmt,SIGNAL(currentIndexChanged(int)),this,SLOT(changedFrmt(int)));
connect(ui->chkSigned,SIGNAL(toggled(bool)),this,SLOT(changedDecSign(bool)));
connect(ui->cmbStartAddrBase,SIGNAL(currentIndexChanged(int)),this,SLOT(changedStartAddrBase(int)));
connect(ui->sbSlaveID,SIGNAL(valueChanged(int)),this,SLOT(changedSlaveID(int)));
connect(ui->sbNoOfRegs,SIGNAL(valueChanged(int)),this,SLOT(changedNoOfRegs(int)));
connect(ui->sbStartAddress,SIGNAL(valueChanged(int)),this,SLOT(changedStartAddress(int)));
connect(ui->spInterval,SIGNAL(valueChanged(int)),this,SLOT(changedScanRate(int)));
connect(ui->sbPrecision,SIGNAL(valueChanged(int)),this,SLOT(changedFloatPrecision(int)));
connect(ui->actionClear,SIGNAL(triggered()),this,SLOT(clearItems()));
connect(ui->actionRead_Write,SIGNAL(triggered()),this,SLOT(modbusRequest()));
connect(ui->actionScan,SIGNAL(toggled(bool)),this,SLOT(modbusScanCycle(bool)));
connect(ui->actionConnect,SIGNAL(toggled(bool)),this,SLOT(changedConnect(bool)));
connect(ui->actionReset_Counters,SIGNAL(triggered()),this,SIGNAL(resetCounters()));
connect(ui->actionOpenLogFile,SIGNAL(triggered()),this,SLOT(openLogFile()));
connect(ui->actionHeaders,SIGNAL(triggered(bool)),this,SLOT(showHeaders(bool)));
connect(ui->actionModbus_Manual,SIGNAL(triggered()),this,SLOT(openModbusManual()));
//connect(ui->actionEnglish_en_US,SIGNAL(triggered()),this,SLOT(changeLanguage()));
//connect(ui->actionSimplified_Chinese_zh_CN,SIGNAL(triggered()),this,SLOT(changeLanguage()));
//connect(ui->actionTraditional_Chinese_zh_TW,SIGNAL(triggered()),this,SLOT(changeLanguage()));
connect(ui->actionLoad_Session,SIGNAL(triggered(bool)),this,SLOT(loadSession()));
connect(ui->actionSave_Session,SIGNAL(triggered(bool)),this,SLOT(saveSession()));
connect(m_dlgSettings, SIGNAL(changedEndianess(int)),this,SLOT(changedEndianess(int)));
//UI - status
m_statusInd = new QLabel;
m_statusInd->setFixedSize( 16, 16 );
m_statusText = new QLabel;
m_baseAddr = new QLabel(tr("Base Addr : ") + "0");
m_statusPackets = new QLabel(tr("Packets : ") + "0");
m_statusPackets->setStyleSheet("QLabel {color:blue;}");
m_statusErrors = new QLabel(tr("Errors : ") + "0");
m_statusErrors->setStyleSheet("QLabel {color:red;}");
m_endian = new QLabel(tr("Endian : ") + EUtils::endianness(m_modbusCommSettings->endian()));
m_endian->setStyleSheet("QLabel {color:black;}");
ui->statusBar->addWidget(m_statusInd);
ui->statusBar->addWidget(m_statusText, 10);
ui->statusBar->addWidget(m_baseAddr, 10);
ui->statusBar->addWidget(m_statusPackets, 10);
ui->statusBar->addWidget(m_endian, 10);
ui->statusBar->addWidget(m_statusErrors, 10);
m_statusInd->setPixmap(QPixmap(":/img/ballorange-16.png"));
//Setup Toolbar
ui->mainToolBar->addAction(ui->actionLoad_Session);
ui->mainToolBar->addAction(ui->actionSave_Session);
ui->mainToolBar->addAction(ui->actionConnect);
ui->mainToolBar->addAction(ui->actionRead_Write);
ui->mainToolBar->addAction(ui->actionScan);
ui->mainToolBar->addAction(ui->actionClear);
ui->mainToolBar->addAction(ui->actionReset_Counters);
ui->mainToolBar->addSeparator();
ui->mainToolBar->addAction(ui->actionOpenLogFile);
ui->mainToolBar->addAction(ui->actionBus_Monitor);
ui->mainToolBar->addAction(ui->actionTools);
ui->mainToolBar->addAction(ui->actionHeaders);
ui->mainToolBar->addSeparator();
ui->mainToolBar->addAction(ui->actionSerial_RTU);
ui->mainToolBar->addAction(ui->actionTCP);
ui->mainToolBar->addAction(ui->actionSettings);
ui->mainToolBar->addSeparator();
ui->mainToolBar->addAction(ui->actionModbus_Manual);
ui->mainToolBar->addAction(ui->actionAbout);
ui->mainToolBar->addAction(ui->actionExit);
//Init models
ui->tblRegisters->setItemDelegate(m_modbus->regModel->itemDelegate());
ui->tblRegisters->setModel(m_modbus->regModel->model);
ui->tblRegisters->horizontalHeader()->hide();
ui->tblRegisters->verticalHeader()->hide();
changedFrmt(m_modbusCommSettings->frmt());
m_modbus->regModel->setStartAddrBase(10);
m_modbus->regModel->setEndian(m_modbusCommSettings->endian());
m_modbus->setBaseAddr(m_modbusCommSettings->baseAddr().toInt());
m_modbus->regModel->setFloatPrecision(m_modbusCommSettings->floatPrecision());
m_modbus->setReadOutputsBeforeWrite(m_modbusCommSettings->readOutputsBeforeWrite());
clearItems();//init model ui
//Update UI
changedFunctionCode(m_modbusCommSettings->functionCode());
changedModbusMode(m_modbusCommSettings->modbusMode());
updateStatusBar();
refreshView();
//Logging level
QsLogging::Logger::instance().setLoggingLevel((QsLogging::Level)m_modbusCommSettings->loggingLevel());
QLOG_INFO()<< "Start Program" ;
}
MainWindow::~MainWindow()
{
if (m_modbus)
m_modbus->modbusDisConnect();
delete ui;
QLOG_INFO()<< "Stop Program" ;
}
void MainWindow::showSettingsModbusRTU()
{
//Show RTU Settings Dialog
m_dlgModbusRTU->modbus_connected = m_modbus->isConnected();
if (m_dlgModbusRTU->exec()==QDialog::Accepted) {
QLOG_TRACE()<< "RTU settings changes accepted ";
updateStatusBar();
m_modbusCommSettings->saveSettings();
}
else
QLOG_WARN()<< "RTU settings changes rejected ";
}
void MainWindow::showSettingsModbusTCP()
{
//Show TCP Settings Dialog
m_dlgModbusTCP->modbus_connected = m_modbus->isConnected();
if (m_dlgModbusTCP->exec()==QDialog::Accepted) {
QLOG_TRACE()<< "TCP settings changes accepted ";
updateStatusBar();
m_modbusCommSettings->saveSettings();
}
else
QLOG_WARN()<< "TCP settings changes rejected ";
}
void MainWindow::showSettings()
{
//Show General Settings Dialog
m_dlgSettings->modbus_connected = m_modbus->isConnected();
if (m_dlgSettings->exec()==QDialog::Accepted) {
QLOG_TRACE()<< "Settings changes accepted ";
m_modbus->rawModel->setMaxNoOfLines(m_modbusCommSettings->maxNoOfLines().toInt());
m_modbus->setTimeOut(m_modbusCommSettings->timeOut().toInt());
ui->sbStartAddress->setMinimum(m_modbusCommSettings->baseAddr().toInt());
m_modbus->setBaseAddr(m_modbusCommSettings->baseAddr().toInt());
m_modbus->regModel->setEndian(m_modbusCommSettings->endian());
m_modbusCommSettings->saveSettings();
}
else
QLOG_WARN()<< "Settings changes rejected ";
updateStatusBar();
}
void MainWindow::showBusMonitor()
{
//Show Bus Monitor
m_modbus->rawModel->setMaxNoOfLines(m_modbusCommSettings->maxNoOfLines().toInt());
m_busMonitor->move(this->x() + this->width() + 20, this->y());
m_busMonitor->show();
}
void MainWindow::showTools()
{
//Show Tools
m_tools->move(this->x() + this->width() + 40, this->y() + 20);
m_tools->show();
}
void MainWindow::changedModbusMode(int currIndex)
{
//Change lblSlave text : Slave Addr, Unit ID
QLOG_TRACE()<< "Modbus Mode changed. Index = " << currIndex;
m_modbusCommSettings->setModbusMode(currIndex);
m_modbusCommSettings->saveSettings();
if (currIndex == 0) { //RTU
ui->lblSlave->setText("Slave Addr");
}
else { //TCP
ui->lblSlave->setText("Unit ID");
}
updateStatusBar();
}
void MainWindow::changedFunctionCode(int currIndex)
{
//Enable-Disable number of coils or registers
QLOG_TRACE()<< "Function Code changed. Index = " << currIndex;
m_modbusCommSettings->setFunctionCode(currIndex);
m_modbusCommSettings->saveSettings();
const int functionCode = EUtils::ModbusFunctionCode(currIndex);
QString String_number_of_coils(tr("Number of Coils"));
QString String_number_of_inputs(tr("Number of Inputs"));
QString String_number_of_registers(tr("Number of Registers"));
switch(functionCode)//Label = Read Request, Write Request
{
case MODBUS_FC_READ_COILS:
m_modbus->regModel->setIs16Bit(false);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(2000);
ui->lblNoOfCoils->setText(String_number_of_coils);
ui->cmbFrmt->setCurrentIndex(0);
ui->cmbFrmt->setEnabled(false);
break;
case MODBUS_FC_READ_DISCRETE_INPUTS:
m_modbus->regModel->setIs16Bit(false);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(2000);
ui->lblNoOfCoils->setText(String_number_of_inputs);
ui->cmbFrmt->setCurrentIndex(0);
ui->cmbFrmt->setEnabled(false);
break;
case MODBUS_FC_READ_HOLDING_REGISTERS:
m_modbus->regModel->setIs16Bit(true);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(125);
ui->lblNoOfCoils->setText(String_number_of_registers);
ui->cmbFrmt->setEnabled(true);
break;
case MODBUS_FC_READ_INPUT_REGISTERS:
m_modbus->regModel->setIs16Bit(true);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(125);
ui->lblNoOfCoils->setText(String_number_of_registers);
ui->cmbFrmt->setEnabled(true);
break;
case MODBUS_FC_WRITE_SINGLE_COIL:
m_modbus->regModel->setIs16Bit(false);
ui->sbNoOfRegs->setValue(1);
ui->sbNoOfRegs->setEnabled(false);
ui->lblNoOfCoils->setText(String_number_of_coils);
ui->cmbFrmt->setCurrentIndex(0);
ui->cmbFrmt->setEnabled(false);
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS:
m_modbus->regModel->setIs16Bit(false);
if (ui->sbNoOfRegs->value() < 2)
ui->sbNoOfRegs->setValue(2);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(2000);
ui->lblNoOfCoils->setText(String_number_of_coils);
ui->cmbFrmt->setCurrentIndex(0);
ui->cmbFrmt->setEnabled(false);
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
m_modbus->regModel->setIs16Bit(true);
ui->sbNoOfRegs->setValue(1);
ui->sbNoOfRegs->setEnabled(false);
ui->lblNoOfCoils->setText(String_number_of_registers);
ui->cmbFrmt->setEnabled(true);
break;
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
m_modbus->regModel->setIs16Bit(true);
if (ui->sbNoOfRegs->value() < 2)
ui->sbNoOfRegs->setValue(2);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(125);
ui->lblNoOfCoils->setText(String_number_of_registers);
ui->cmbFrmt->setEnabled(true);
break;
default:
m_modbus->regModel->setIs16Bit(false);
ui->sbNoOfRegs->setValue(1);
ui->sbNoOfRegs->setEnabled(true);
ui->sbNoOfRegs->setMaximum(2000);
ui->lblNoOfCoils->setText(String_number_of_coils);
ui->cmbFrmt->setEnabled(true);
break;
}
m_modbus->setNumOfRegs(ui->sbNoOfRegs->value());
addItems();
}
void MainWindow::changedFrmt(int currIndex)
{
//Change Format
QLOG_TRACE()<< "Format changed. Index = " << currIndex;
m_modbusCommSettings->setFrmt(currIndex);
m_modbusCommSettings->saveSettings();
switch(currIndex)
{
case 0:
ui->chkSigned->setVisible(false);
ui->chkSigned->setChecked(false);
m_modbus->regModel->setFrmt(EUtils::Bin);
ui->lblPrecision->setVisible(false);
ui->sbPrecision->setVisible(false);
ui->sbNoOfRegs->setMinimum(1);
break;
case 1:
ui->chkSigned->setVisible(true);
m_modbus->regModel->setFrmt(EUtils::Dec);
ui->lblPrecision->setVisible(false);
ui->sbPrecision->setVisible(false);
ui->sbNoOfRegs->setMinimum(1);
break;
case 2:
ui->chkSigned->setVisible(false);
ui->chkSigned->setChecked(false);
m_modbus->regModel->setFrmt(EUtils::Hex);
ui->lblPrecision->setVisible(false);
ui->sbPrecision->setVisible(false);
ui->sbNoOfRegs->setMinimum(1);
break;
case 3:
ui->chkSigned->setVisible(false);
ui->chkSigned->setChecked(false);
m_modbus->regModel->setFrmt(EUtils::Float);
ui->lblPrecision->setVisible(true);
ui->sbPrecision->setVisible(true);
ui->sbNoOfRegs->setMinimum(1);
break;
default:
m_modbus->regModel->setFrmt(EUtils::Dec);
ui->chkSigned->setVisible(true);
ui->lblPrecision->setVisible(false);
ui->sbPrecision->setVisible(false);
ui->sbNoOfRegs->setMinimum(1);
break;
}
//clear table on format change
addItems();
}
void MainWindow::changedDecSign(bool value)
{
//Change Dec Signed - Unsigned
QLOG_TRACE()<< "Dec Signed-Unsigned changed. Signed = " << value;
m_modbus->regModel->setIsSigned(value);
}
void MainWindow::changedScanRate(int value)
{
//Enable-Disable Time Interval
QLOG_TRACE()<< "ScanRate changed. Value = " << value;
m_modbusCommSettings->setScanRate(value);
m_modbusCommSettings->saveSettings();
m_modbus->setScanRate(value);
}
void MainWindow::changedConnect(bool value)
{
//Connect - Disconnect
if (value) { //Connected
modbusConnect(true);
QLOG_INFO()<< "Connected ";
}
else { //Disconnected
modbusConnect(false);
QLOG_INFO()<< "Disconnected ";
}
m_modbus->resetCounters();
refreshView();
}
void MainWindow::changedSlaveID(int value)
{
//Slave ID
QLOG_TRACE()<< "Slave ID Changed. Value = " << value;
m_modbusCommSettings->setSlaveID(value);
m_modbusCommSettings->saveSettings();
}
void MainWindow::changedEndianess(int endian)
{
//Endianess
QLOG_TRACE()<< "Endianess Changed. Value = " << endian;
//clear table on endianess change
addItems();
}
void MainWindow::openLogFile()
{
//Open log file
QString arg;
QLOG_TRACE()<< "Open log file";
arg = "file:///" + QCoreApplication::applicationDirPath() + "/QModMaster.log";
QDesktopServices::openUrl(QUrl(arg));
}
void MainWindow::openModbusManual()
{
//Open Modbus Manual
QString arg;
QLOG_TRACE()<< "Open Modbus Manual";
arg = "file:///" + QCoreApplication::applicationDirPath() + "/ManModbus/index.html";
QDesktopServices::openUrl(QUrl(arg));
}
void MainWindow::changedStartAddrBase(int currIndex)
{
//Change Base
QLOG_TRACE()<< "Start Addr Base changed. Index = " << currIndex;
switch(currIndex)
{
case 0:
ui->sbStartAddress->setDisplayIntegerBase(10);
m_modbus->regModel->setStartAddrBase(10);
break;
case 1:
ui->sbStartAddress->setDisplayIntegerBase(16);
m_modbus->regModel->setStartAddrBase(16);
break;
default:
ui->sbStartAddress->setDisplayIntegerBase(10);
m_modbus->regModel->setStartAddrBase(10);
break;
}
}
void MainWindow::changedStartAddress(int value)
{
//Start Address changed
QLOG_TRACE()<< "Start Address changed. Value = " << value;
m_modbusCommSettings->setStartAddr(value);
m_modbusCommSettings->saveSettings();
m_modbus->setStartAddr(value);
addItems();
}
void MainWindow::changedNoOfRegs(int value)
{
//No of regs changed
QLOG_TRACE()<< "No Of Regs changed. Value = " << value;
m_modbusCommSettings->setNoOfRegs(value);
m_modbusCommSettings->saveSettings();
m_modbus->setNumOfRegs(value);
addItems();
}
void MainWindow::changedFloatPrecision(int precision)
{
//Float precision changed
m_modbusCommSettings->setfloatPrecision(precision);
m_modbusCommSettings->saveSettings();
m_modbus->regModel->setFloatPrecision(precision);
}
void MainWindow::updateStatusBar()
{
//Update status bar
QString msg;
if(ui->cmbModbusMode->currentIndex() == 0) { //RTU
msg = "RTU : ";
msg += m_modbusCommSettings->serialPortName() + " | ";
msg += m_modbusCommSettings->baud() + ",";
msg += m_modbusCommSettings->dataBits() + ",";
msg += m_modbusCommSettings->stopBits() + ",";
msg += m_modbusCommSettings->parity();
}
else {
msg = "TCP : ";
msg += m_modbusCommSettings->slaveIP() + ":";
msg += m_modbusCommSettings->TCPPort();
}
m_statusText->clear();
m_statusText->setText(msg);
//Connection is valid
if (m_modbus->isConnected()) {
m_statusInd->setPixmap(QPixmap(":/icons/bullet-green-16.png"));
}
else {
m_statusInd->setPixmap(QPixmap(":/icons/bullet-red-16.png"));
}
//base Address
m_baseAddr->setText("Base Addr : " + m_modbusCommSettings->baseAddr());
//endianness
m_endian->setText(("Endian : ") + EUtils::endianness(m_modbusCommSettings->endian()));
}
void MainWindow::addItems()
{
int baseAddr;
//add items
m_modbus->setSlave(ui->sbSlaveID->value());
m_modbus->setFunctionCode(EUtils::ModbusFunctionCode(ui->cmbFunctionCode->currentIndex()));
m_modbus->setNumOfRegs(ui->sbNoOfRegs->value());
//get base address
baseAddr = m_modbusCommSettings->baseAddr().toInt();
m_modbus->setStartAddr(ui->sbStartAddress->value() - baseAddr);
QLOG_INFO()<< "Add Items. Function Code = " << QString::number(EUtils::ModbusFunctionCode(ui->cmbFunctionCode->currentIndex()),16);
m_modbus->addItems();
}
void MainWindow::clearItems()
{
//Clear items from registers model
QLOG_TRACE()<< "clearItems" ;
m_modbus->regModel->clear();
addItems();
}
void MainWindow::modbusRequest()
{
//Request items from modbus adapter and add raw data to raw data model
int rowCount = m_modbus->regModel->model->rowCount();
int baseAddr;
QLOG_TRACE()<< "Request transaction. No or registers = " << rowCount;
if (rowCount == 0) {
mainWin->showUpInfoBar(tr("Request failed\nAdd items to Registers Table."), InfoBar::Error);
QLOG_WARN()<< "Request failed. No items in registers table ";
return;
}
else if (m_modbus->regModel->getFrmt() == EUtils::Float &&
ui->sbNoOfRegs->value() % 2 != 0) {
mainWin->showUpInfoBar(tr("The number of registers must be even."), InfoBar::Error);
QLOG_WARN()<< "Request failed. The number of registers must be even ";
return;
}
else {
mainWin->hideInfoBar();
}
//get base address
baseAddr = m_modbusCommSettings->baseAddr().toInt();
m_modbus->setSlave(ui->sbSlaveID->value());
m_modbus->setFunctionCode(EUtils::ModbusFunctionCode(ui->cmbFunctionCode->currentIndex()));
m_modbus->setStartAddr(ui->sbStartAddress->value() - baseAddr);
m_modbus->setNumOfRegs(ui->sbNoOfRegs->value());
//Modbus data
m_modbus->modbusTransaction();
}
void MainWindow::modbusScanCycle(bool value)
{
//Request items from modbus adapter and add raw data to raw data model
int rowCount = m_modbus->regModel->model->rowCount();
int baseAddr;
if (value && rowCount == 0) {
//mainWin->showUpInfoBar(tr("Request failed\nAdd items to Registers Table."), InfoBar::Error);
QLOG_WARN()<< "Request failed. No items in registers table ";
QMessageBox::critical(this, "QModMaster", tr("Request failed\nAdd items to Registers Table."));
ui->actionScan->setChecked(false);
return;
}
else if (value && m_modbus->regModel->getFrmt() == EUtils::Float &&
ui->sbNoOfRegs->value() % 2 != 0) {
//mainWin->showUpInfoBar(tr("The number of registers must be even."), InfoBar::Error);
QLOG_WARN()<< "Request failed. The number of registers must be even ";
QMessageBox::critical(this, "QModMaster", tr("The number of registers must be even."));
ui->actionScan->setChecked(false);
return;
}
else {
mainWin->hideInfoBar();
}
//get base address
baseAddr = m_modbusCommSettings->baseAddr().toInt();
m_modbus->setSlave(ui->sbSlaveID->value());
m_modbus->setFunctionCode(EUtils::ModbusFunctionCode(ui->cmbFunctionCode->currentIndex()));
m_modbus->setStartAddr(ui->sbStartAddress->value() - baseAddr);
m_modbus->setNumOfRegs(ui->sbNoOfRegs->value());
//Start-Stop poll timer
QLOG_TRACE()<< "Scan time = " << value;
if (value){
if (ui->spInterval->value() < m_modbusCommSettings->timeOut().toInt() * 1000 * 2){
mainWin->showUpInfoBar(tr("Scan rate should be at least 2 * Timeout."), InfoBar::Error);
QLOG_ERROR()<< "Scan rate error. should be at least 2 * Timeout ";
}
else {
m_modbus->setScanRate(ui->spInterval->value());
m_modbus->startPollTimer();
}
}
else
m_modbus->stopPollTimer();
//Update UI
ui->cmbFunctionCode->setEnabled(!value);
ui->sbSlaveID->setEnabled(!value);
ui->sbStartAddress->setEnabled(!value);
ui->spInterval->setEnabled(!value);
ui->cmbStartAddrBase->setEnabled(!value);
if (!value)
changedFunctionCode(ui->cmbFunctionCode->currentIndex());
else
ui->sbNoOfRegs->setEnabled(false);
}
void MainWindow::modbusConnect(bool connect)
{
//Modbus connect - RTU/TCP
QLOG_TRACE()<< "Modbus Connect. Value = " << connect;
if (connect) { //RTU
if (ui->cmbModbusMode->currentIndex() == EUtils::RTU) {
m_modbus->setSlave(ui->sbSlaveID->value());
m_modbus->modbusConnectRTU(m_modbusCommSettings->serialPortName(),
m_modbusCommSettings->baud().toInt(),
EUtils::parity(m_modbusCommSettings->parity()),
m_modbusCommSettings->dataBits().toInt(),
m_modbusCommSettings->stopBits().toInt(),
m_modbusCommSettings->RTS().toInt(),
m_modbusCommSettings->timeOut().toInt()
);
}
else { //TCP
m_modbus->modbusConnectTCP(m_modbusCommSettings->slaveIP(),
m_modbusCommSettings->TCPPort().toInt(),
m_modbusCommSettings->timeOut().toInt());
}
}
else { //Disconnect
m_modbus->modbusDisConnect();
ui->actionScan->setChecked(false);
}
updateStatusBar();
//Update UI
ui->actionLoad_Session->setEnabled(!m_modbus->isConnected());
ui->actionSave_Session->setEnabled(!m_modbus->isConnected());
ui->actionConnect->setChecked(m_modbus->isConnected());
ui->actionRead_Write->setEnabled(m_modbus->isConnected());
ui->actionScan->setEnabled(m_modbus->isConnected());
ui->cmbModbusMode->setEnabled(!m_modbus->isConnected());
}
void MainWindow::showHeaders(bool value)
{
QLOG_TRACE()<< "Show Headers = " << value;
if (value){
ui->tblRegisters->horizontalHeader()->show();
ui->tblRegisters->verticalHeader()->show();
}
else {
ui->tblRegisters->horizontalHeader()->hide();
ui->tblRegisters->verticalHeader()->hide();
}
}
void MainWindow::refreshView()
{
QLOG_TRACE()<< "Packets sent / received = " << m_modbus->packets() << ", errors = " << m_modbus->errors();
ui->tblRegisters->resizeColumnsToContents();
m_statusPackets->setText(tr("Packets : ") + QString("%1").arg(m_modbus->packets()));
m_statusErrors->setText(tr("Errors : ") + QString("%1").arg(m_modbus->errors()));
}
void MainWindow::loadSession()
{
QString fName;
QLOG_TRACE()<< "load session";
fName = QFileDialog::getOpenFileName(this,
"Load Session file",
"",
"Session Files (*.ses);;All Files (*.*)");
//check
if (fName != ""){
m_modbusCommSettings->loadSession(fName);
//Update UI
ui->sbStartAddress->setMinimum(m_modbusCommSettings->baseAddr().toInt());
ui->cmbFrmt->setCurrentIndex(m_modbusCommSettings->frmt());
ui->sbPrecision->setValue(m_modbusCommSettings->floatPrecision());
ui->cmbFunctionCode->setCurrentIndex(m_modbusCommSettings->functionCode());
ui->cmbModbusMode->setCurrentIndex(m_modbusCommSettings->modbusMode());
ui->sbSlaveID->setValue(m_modbusCommSettings->slaveID());
ui->spInterval->setValue(m_modbusCommSettings->scanRate());
ui->sbStartAddress->setValue(m_modbusCommSettings->startAddr());
ui->sbNoOfRegs->setValue(m_modbusCommSettings->noOfRegs());
updateStatusBar();
refreshView();
QMessageBox::information(this, "QModMaster", "Load session file : " + fName);
}
else
QMessageBox::information(this, "QModMaster", "Cancel operation Or no file selected");
}
void MainWindow::saveSession()
{
QString fName;
QLOG_TRACE()<< "save session";
fName = QFileDialog::getSaveFileName(this,
"Save Session file",
"",
"Session Files (*.ses)");
//check
if (fName != ""){
m_modbusCommSettings->saveSession(fName);
QMessageBox::information(this, "QModMaster", "Save session file : " + fName);
}
else
QMessageBox::information(this, "QModMaster", "Cancel operation Or no file selected");
}
void MainWindow::showUpInfoBar(QString message, InfoBar::InfoType type)
{
ui->infobar->show(message, type);
}
void MainWindow::hideInfoBar()
{
ui->infobar->hide();
}
void MainWindow::changeEvent(QEvent* event)
{
if(event->type() == QEvent::LanguageChange)
{
ui->retranslateUi(this);
}
QMainWindow::changeEvent(event);
}
void MainWindow::changeLanguage()
{
// Not Used
extern QTranslator *Translator;
QCoreApplication::removeTranslator(Translator);
Translator->load(":/translations/" + QCoreApplication::applicationName() + sender()->objectName().right(6));
QCoreApplication::installTranslator(Translator);
}

View File

@@ -0,0 +1,94 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSettings>
#include <QLabel>
#include <QString>
#include <QProcess>
#include "forms/about.h"
#include "forms/settingsmodbusrtu.h"
#include "forms/settingsmodbustcp.h"
#include "forms/settings.h"
#include "forms/busmonitor.h"
#include "forms/tools.h"
#include "modbuscommsettings.h"
#include "modbusadapter.h"
#include "infobar.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0, ModbusAdapter *adapter = 0, ModbusCommSettings *settings = 0);
~MainWindow();
void showUpInfoBar(QString message, InfoBar::InfoType type);
void hideInfoBar();
private:
Ui::MainWindow *ui;
//UI - Dialogs
About *m_dlgAbout;
SettingsModbusRTU *m_dlgModbusRTU;
SettingsModbusTCP *m_dlgModbusTCP;
Settings *m_dlgSettings;
BusMonitor *m_busMonitor;
Tools *m_tools;
ModbusCommSettings *m_modbusCommSettings;
void updateStatusBar();
QLabel *m_statusText;
QLabel *m_statusInd;
QLabel *m_baseAddr;
QLabel *m_statusPackets;
QLabel *m_statusErrors;
QLabel *m_endian;
ModbusAdapter *m_modbus;
void modbusConnect(bool connect);
void changeEvent(QEvent* event);
private slots:
void showSettingsModbusRTU();
void showSettingsModbusTCP();
void showSettings();
void showBusMonitor();
void showTools();
void changedModbusMode(int currIndex);
void changedFunctionCode(int currIndex);
void changedFrmt(int currIndex);
void changedDecSign(bool value);
void changedStartAddrBase(int currIndex);
void changedScanRate(int value);
void changedConnect(bool value);
void changedStartAddress(int value);
void changedNoOfRegs(int value);
void changedSlaveID(int value);
void changedFloatPrecision(int precision);
void changedEndianess(int endian);
void addItems();
void clearItems();
void openLogFile();
void modbusScanCycle(bool value);
void modbusRequest();
void refreshView();
void changeLanguage();
void openModbusManual();
void loadSession();
void saveSession();
void showHeaders(bool value);
signals:
void resetCounters();
};
extern MainWindow *mainWin;
#endif // MAINWINDOW_H

View File

@@ -0,0 +1,580 @@
#include <QApplication>
#include <QtDebug>
#include "modbusadapter.h"
#include "mainwindow.h"
#include "QsLog.h"
#include <errno.h>
ModbusAdapter *m_instance;
ModbusAdapter::ModbusAdapter(QObject *parent) :
QObject(parent),
m_modbus(NULL)
{
m_instance = this;
regModel=new RegistersModel(this);
rawModel=new RawDataModel(this);
m_connected = false;
m_ModBusMode = EUtils::None;
m_pollTimer = new QTimer(this);
m_timeOut = 0;
m_transactionIsPending = false;
m_packets = 0;
m_errors = 0;
m_readOutputsBeforeWrite = true;
connect(m_pollTimer,SIGNAL(timeout()),this,SLOT(modbusTransaction()));
connect(regModel,SIGNAL(refreshView()),this,SIGNAL(refreshView()));
//setup memory for data
dest = (uint8_t *) malloc(2000 * sizeof(uint8_t));
memset(dest, 0, 2000 * sizeof(uint8_t));
dest16 = (uint16_t *) malloc(125 * sizeof(uint16_t));
memset(dest16, 0, 125 * sizeof(uint16_t));
}
ModbusAdapter::~ModbusAdapter()
{
free(dest);
free(dest16);
}
void ModbusAdapter::modbusConnectRTU(QString port, int baud, QChar parity, int dataBits, int stopBits, int RTS, int timeOut)
{
//Modbus RTU connect
QString line;
modbusDisConnect();
QLOG_INFO()<< "Modbus Connect RTU";
m_modbus = modbus_new_rtu(port.toLatin1().constData(),baud,parity.toLatin1(),dataBits,stopBits,RTS);
line = "Connecting to Serial Port [" + port + "]...";
QLOG_TRACE() << line;
//Debug messages from libmodbus
#ifdef LIB_MODBUS_DEBUG_OUTPUT
modbus_set_debug(m_modbus, 1);
#endif
m_timeOut = timeOut;
if(m_modbus == NULL){
mainWin->showUpInfoBar(tr("Unable to create the libmodbus context."), InfoBar::Error);
QLOG_ERROR()<< "Connection failed. Unable to create the libmodbus context";
return;
}
else if(m_modbus && modbus_set_slave(m_modbus, m_slave) == -1){
modbus_free(m_modbus);
mainWin->showUpInfoBar(tr("Invalid slave ID."), InfoBar::Error);
QLOG_ERROR()<< "Connection failed. Invalid slave ID";
return;
}
else if(m_modbus && modbus_connect(m_modbus) == -1) {
modbus_free(m_modbus);
mainWin->showUpInfoBar(tr("Connection failed\nCould not connect to serial port."), InfoBar::Error);
QLOG_ERROR()<< "Connection failed. Could not connect to serial port";
m_connected = false;
line += "Failed";
}
else {
//error recovery mode
modbus_set_error_recovery(m_modbus, MODBUS_ERROR_RECOVERY_PROTOCOL);
//response_timeout;
modbus_set_response_timeout(m_modbus, timeOut, 0);
m_connected = true;
line += "OK";
mainWin->hideInfoBar();
QLOG_TRACE() << line;
}
m_ModBusMode = EUtils::RTU;
//Add line to raw data model
line = EUtils::SysTimeStamp() + " - " + line;
rawModel->addLine(line);
}
void ModbusAdapter::modbusConnectTCP(QString ip, int port, int timeOut)
{
//Modbus TCP connect
QString strippedIP = "";
QString line;
modbusDisConnect();
QLOG_INFO()<< "Modbus Connect TCP";
line = "Connecting to IP : " + ip + ":" + QString::number(port);
QLOG_TRACE() << line;
strippedIP = stripIP(ip);
if (strippedIP == ""){
mainWin->showUpInfoBar(tr("Connection failed\nBlank IP Address."), InfoBar::Error);
QLOG_ERROR()<< "Connection failed. Blank IP Address";
return;
}
else {
m_modbus = modbus_new_tcp(strippedIP.toLatin1().constData(), port);
mainWin->hideInfoBar();
QLOG_TRACE() << "Connecting to IP : " << ip << ":" << port;
}
//Debug messages from libmodbus
#ifdef LIB_MODBUS_DEBUG_OUTPUT
modbus_set_debug(m_modbus, 1);
#endif
m_timeOut = timeOut;
if(m_modbus == NULL){
mainWin->showUpInfoBar(tr("Unable to create the libmodbus context."), InfoBar::Error);
QLOG_ERROR()<< "Connection failed. Unable to create the libmodbus context";
return;
}
else if(m_modbus && modbus_connect(m_modbus) == -1) {
modbus_free(m_modbus);
mainWin->showUpInfoBar(tr("Connection failed\nCould not connect to TCP port."), InfoBar::Error);
QLOG_ERROR()<< "Connection to IP : " << ip << ":" << port << "...failed. Could not connect to TCP port";
m_connected = false;
line += " Failed";
}
else {
//error recovery mode
modbus_set_error_recovery(m_modbus, MODBUS_ERROR_RECOVERY_PROTOCOL);
//response_timeout;
modbus_set_response_timeout(m_modbus, timeOut, 0);
m_connected = true;
line += " OK";
mainWin->hideInfoBar();
QLOG_TRACE() << line;
}
m_ModBusMode = EUtils::TCP;
//Add line to raw data model
line = EUtils::SysTimeStamp() + " - " + line;
rawModel->addLine(line);
}
void ModbusAdapter::modbusDisConnect()
{
//Modbus disconnect
QLOG_INFO()<< "Modbus disconnected";
if(m_modbus) {
if (m_connected){
modbus_close(m_modbus);
modbus_free(m_modbus);
}
m_modbus = NULL;
}
m_connected = false;
m_ModBusMode = EUtils::None;
}
bool ModbusAdapter::isConnected()
{
//Modbus is connected
return m_connected;
}
void ModbusAdapter::modbusTransaction()
{
//Modbus request data
QLOG_INFO() << "Modbus Transaction. Function Code = " << m_functionCode;
m_packets += 1;
QApplication::setOverrideCursor(Qt::WaitCursor);
switch(m_functionCode)
{
case MODBUS_FC_READ_COILS:
case MODBUS_FC_READ_DISCRETE_INPUTS:
case MODBUS_FC_READ_HOLDING_REGISTERS:
case MODBUS_FC_READ_INPUT_REGISTERS:
modbusReadData(m_slave,m_functionCode,m_startAddr,m_numOfRegs);
break;
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
modbusWriteData(m_slave,m_functionCode,m_startAddr,m_numOfRegs);
break;
default:
break;
}
QApplication::setOverrideCursor(Qt::ArrowCursor);
emit(refreshView());
}
void ModbusAdapter::modbusReadData(int slave, int functionCode, int startAddress, int noOfItems)
{
QLOG_INFO() << "Modbus Read Data ";
if(m_modbus == NULL) return;
int ret = -1; //return value from read functions
bool is16Bit = false;
modbus_set_slave(m_modbus, slave);
//request data from modbus
switch(functionCode)
{
case MODBUS_FC_READ_COILS:
ret = modbus_read_bits(m_modbus, startAddress, noOfItems, dest);
break;
case MODBUS_FC_READ_DISCRETE_INPUTS:
ret = modbus_read_input_bits(m_modbus, startAddress, noOfItems, dest);
break;
case MODBUS_FC_READ_HOLDING_REGISTERS:
ret = modbus_read_registers(m_modbus, startAddress, noOfItems, dest16);
is16Bit = true;
break;
case MODBUS_FC_READ_INPUT_REGISTERS:
ret = modbus_read_input_registers(m_modbus, startAddress, noOfItems, dest16);
is16Bit = true;
break;
default:
break;
}
QLOG_TRACE() << "Modbus Read Data return value = " << ret << ", errno = " << errno;
//update data model
if(ret == noOfItems)
{
if (regModel->getFrmt() != EUtils::Float)
{
for(int i = 0; i < noOfItems; ++i)
{
int data = is16Bit ? dest16[i] : dest[i];
regModel->setValue(i,data);
}
}
else//read float values
{
for(int i = 0; i < noOfItems - 1; i+=2)
{
int dataHi = is16Bit ? dest16[i] : dest[i];
int dataLo = is16Bit ? dest16[i+1] : dest[i+1];
regModel->setValue32(i/2,dataHi,dataLo);
}
}
mainWin->hideInfoBar();
}
else
{
regModel->setNoValidValues();
m_errors += 1;
QString line = "";
if(ret < 0) {
line = QString("Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Read Data failed. " << line;
rawModel->addLine(EUtils::SysTimeStamp() + " - " + line);
line = QString(tr("Read data failed.\nError : ")) + EUtils::libmodbus_strerror(errno);
}
else {
line = QString("Number of registers returned does not match number of registers requested!. Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Read Data failed. " << line;
rawModel->addLine(EUtils::SysTimeStamp() + " - " + line);
line = QString(tr("Read data failed.\nNumber of registers returned does not match number of registers requested!. Error : ")) + EUtils::libmodbus_strerror(errno);
}
mainWin->showUpInfoBar(line, InfoBar::Error);
modbus_flush(m_modbus); //flush data
}
}
void ModbusAdapter::modbusWriteData(int slave, int functionCode, int startAddress, int noOfItems)
{
QLOG_INFO() << "Modbus Write Data ";
if(m_modbus == NULL) return;
int ret = -1; //return value from functions
union{
struct{qint16 low, high;} reg;
float value;
} modelData;
modbus_set_slave(m_modbus, slave);
//request data from modbus
switch(functionCode)
{
case MODBUS_FC_WRITE_SINGLE_COIL:
ret = modbus_write_bit(m_modbus, startAddress,regModel->value(0));
noOfItems = 1;
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
ret = modbus_write_register( m_modbus, startAddress,regModel->value(0));
noOfItems = 1;
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS:
{
uint8_t * data = new uint8_t[noOfItems];
for(int i = 0; i < noOfItems; ++i)
{
data[i] = regModel->value(i);
}
ret = modbus_write_bits(m_modbus, startAddress, noOfItems, data);
delete[] data;
break;
}
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
{
if (regModel->getFrmt() != EUtils::Float) {
uint16_t * data = new uint16_t[noOfItems];
for(int i = 0; i < noOfItems; ++i)
{
data[i] = regModel->value(i);
}
ret = modbus_write_registers(m_modbus, startAddress, noOfItems, data);
delete[] data;
break;
}
else { //write float values
uint16_t * data = new uint16_t[noOfItems];
for(int i = 0; i < noOfItems - 1; i+=2)
{
modelData.value = regModel->floatValue(i/2);
if (regModel->getEndian() == EUtils::Little){
data[i] = modelData.reg.low;
data[i+1] = modelData.reg.high;
}
else if (regModel->getEndian() == EUtils::Big){
data[i] = modelData.reg.high;
data[i+1] = modelData.reg.low;
}
}
ret = modbus_write_registers(m_modbus, startAddress, noOfItems, data);
delete[] data;
break;
}
}
default:
break;
}
QLOG_TRACE() << "Modbus Write Data return value = " << ret << ", errno = " << errno;;
//update data model
if(ret == noOfItems)
{
//values written correctly
rawModel->addLine(EUtils::SysTimeStamp() + " - values written correctly.");
mainWin->hideInfoBar();
}
else
{
regModel->setNoValidValues();
m_errors += 1;
QString line;
if(ret < 0) {
line = QString("Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Write Data failed. " << line;
rawModel->addLine(EUtils::SysTimeStamp() + " - " + line);
line = QString(tr("Write data failed.\nError : ")) + EUtils::libmodbus_strerror(errno);
}
else {
line = QString("Number of registers returned does not match number of registers requested!. Error : ") + EUtils::libmodbus_strerror(errno);
QLOG_ERROR() << "Write Data failed. " << line;
rawModel->addLine(EUtils::SysTimeStamp() + " - " + line);
line = QString(tr("Write data failed.\nNumber of registers returned does not match number of registers requested!. Error : ")) + EUtils::libmodbus_strerror(errno);
}
mainWin->showUpInfoBar(line, InfoBar::Error);
modbus_flush(m_modbus); //flush data
}
}
void ModbusAdapter::busMonitorRequestData(uint8_t * data, int dataLen)
{
//Request Raw data from port - Update raw data model
QString line;
for(int i = 0; i < dataLen; ++i ) {
line += QString().asprintf( "%.2x ", data[i] );
}
QLOG_INFO() << "Tx Data : " << line;
line = EUtils::TxTimeStamp(m_ModBusMode) + " - " + line.toUpper();
rawModel->addLine(line);
m_transactionIsPending = true;
}
void ModbusAdapter::busMonitorResponseData(uint8_t * data, int dataLen)
{
//Response Raw data from port - Update raw data model
QString line;
for(int i = 0; i < dataLen; ++i ) {
line += QString().asprintf( "%.2x ", data[i] );
}
QLOG_INFO() << "Rx Data : " << line;
line = EUtils::RxTimeStamp(m_ModBusMode) + " - " + line.toUpper();
rawModel->addLine(line);
m_transactionIsPending = false;
}
void ModbusAdapter::setSlave(int slave)
{
m_slave = slave;
}
void ModbusAdapter::setFunctionCode(int functionCode)
{
m_functionCode = functionCode;
}
void ModbusAdapter::setStartAddr(int addr)
{
m_startAddr = addr;
}
void ModbusAdapter::setBaseAddr(int baseAddr)
{
m_baseAddr = baseAddr;
}
void ModbusAdapter::setNumOfRegs(int num)
{
m_numOfRegs = num;
}
void ModbusAdapter::addItems()
{
//TODO - fix base addr
regModel->addItems(m_startAddr + m_baseAddr, m_numOfRegs, EUtils::ModbusIsWriteFunction(m_functionCode));
//If it is a write function -> read registers
if (!m_connected || !m_readOutputsBeforeWrite)
return;
else if (EUtils::ModbusIsWriteCoilsFunction(m_functionCode)){
modbusReadData(m_slave,EUtils::ReadCoils,m_startAddr,m_numOfRegs);
emit(refreshView());
}
else if (EUtils::ModbusIsWriteRegistersFunction(m_functionCode)){
modbusReadData(m_slave,EUtils::ReadHoldRegs,m_startAddr,m_numOfRegs);
emit(refreshView());
}
}
void ModbusAdapter::setScanRate(int scanRate)
{
m_scanRate = scanRate;
}
void ModbusAdapter::resetCounters()
{
m_packets = 0;
m_errors = 0;
emit(refreshView());
}
int ModbusAdapter::packets()
{
return m_packets;
}
int ModbusAdapter::errors()
{
return m_errors;
}
void ModbusAdapter::startPollTimer()
{
m_pollTimer->start(m_scanRate);
}
void ModbusAdapter::stopPollTimer()
{
m_pollTimer->stop();
}
void ModbusAdapter::setTimeOut(int timeOut)
{
m_timeOut = timeOut;
}
QString ModbusAdapter::stripIP(QString ip)
{
//Strip zero's from IP
QStringList ipBytes;
QString res = "";
int i;
ipBytes = ip.split(".");
if (ipBytes.size() == 4){
res = QString("").setNum(ipBytes[0].toInt());
i = 1;
while (i < ipBytes.size()){
res = res + "." + QString("").setNum(ipBytes[i].toInt());
i++;
}
return res;
}
else
return "";
}
void ModbusAdapter::setReadOutputsBeforeWrite(bool readOutputsBeforeWrite){
m_readOutputsBeforeWrite = readOutputsBeforeWrite;
}
extern "C" {
void busMonitorRawResponseData(uint8_t * data, int dataLen)
{
m_instance->busMonitorResponseData(data, dataLen);
}
void busMonitorRawRequestData(uint8_t * data, int dataLen)
{
m_instance->busMonitorRequestData(data, dataLen);
}
}

View File

@@ -0,0 +1,74 @@
#ifndef MODBUSADAPTER_H
#define MODBUSADAPTER_H
#include <QObject>
#include "modbus.h"
#include "registersmodel.h"
#include "rawdatamodel.h"
#include <QTimer>
#include "eutils.h"
class ModbusAdapter : public QObject
{
Q_OBJECT
public:
explicit ModbusAdapter(QObject *parent = 0);
~ModbusAdapter();
void busMonitorRequestData(uint8_t * data,int dataLen);
void busMonitorResponseData(uint8_t * data,int dataLen);
void modbusConnectRTU(QString port, int baud, QChar parity, int dataBits, int stopBits, int RTS, int timeOut=1);
void modbusConnectTCP(QString ip, int port, int timeOut=1);
void modbusDisConnect();
RegistersModel *regModel;
RawDataModel *rawModel;
bool isConnected();
void setSlave(int slave);
void setFunctionCode(int functionCode);
void setStartAddr(int addr);
void setNumOfRegs(int num);
void setBaseAddr(int baseAddr);
void addItems();
void setReadOutputsBeforeWrite(bool readOutputsBeforeWrite);
void setScanRate(int scanRate);
void setTimeOut(int timeOut);
void startPollTimer();
void stopPollTimer();
int packets();
int errors();
modbus_t * m_modbus;
private:
void modbusReadData(int slave, int functionCode, int startAddress, int noOfItems);
void modbusWriteData(int slave, int functionCode, int startAddress, int noOfItems);
QString stripIP(QString ip);
bool m_connected;
int m_ModBusMode;
int m_slave;
int m_functionCode;
int m_startAddr;
int m_baseAddr;
int m_numOfRegs;
int m_scanRate;
QTimer *m_pollTimer;
int m_packets;
int m_errors;
int m_timeOut;
bool m_transactionIsPending;
bool m_readOutputsBeforeWrite;
uint8_t *dest;
uint16_t *dest16;
signals:
void refreshView();
public slots:
void modbusTransaction();
void resetCounters();
};
#endif // MODBUSADAPTER_H

View File

@@ -0,0 +1,445 @@
#include "modbuscommsettings.h"
#include "QsLog.h"
ModbusCommSettings::ModbusCommSettings(const QString &fileName, Format format , QObject *parent)
: QSettings(fileName, format, parent)
{
this->loadSettings();
}
void ModbusCommSettings::loadSettings()
{
load(this);
}
void ModbusCommSettings::saveSettings()
{
save(this);
}
QString ModbusCommSettings::TCPPort()
{
return m_TCPPort;
}
void ModbusCommSettings::setTCPPort(QString tcpPort)
{
m_TCPPort = tcpPort;
}
void ModbusCommSettings::setSlaveIP(QString IP)
{
m_slaveIP = IP;
}
QString ModbusCommSettings::slaveIP()
{
return m_slaveIP;
}
QString ModbusCommSettings::serialDev()
{
return m_serialDev;
}
QString ModbusCommSettings::serialPort()
{
return m_serialPort;
}
QString ModbusCommSettings::serialPortName()
{
return m_serialPortName;
}
void ModbusCommSettings::setSerialPort(QString serialPort, QString serialDev)
{
int serialPortNo;
m_serialDev = serialDev;
m_serialPort = serialPort;
serialPortNo = serialPort.toInt();
#ifdef Q_OS_WIN32
if (serialPortNo > 9)
m_serialPortName = "\\\\.\\COM" + serialPort;
else
m_serialPortName = "COM" + serialPort;
#else
m_serialPortName = serialDev;
m_serialPortName += QStringLiteral("%1").arg(serialPort.toInt() - 1);
#endif
}
QString ModbusCommSettings::baud()
{
return m_baud;
}
void ModbusCommSettings::setBaud(QString baud)
{
m_baud = baud;
}
QString ModbusCommSettings::dataBits()
{
return m_dataBits;
}
void ModbusCommSettings::setDataBits(QString dataBits)
{
m_dataBits = dataBits;
}
QString ModbusCommSettings::stopBits()
{
return m_stopBits;
}
void ModbusCommSettings::setStopBits(QString stopBits)
{
m_stopBits = stopBits;
}
QString ModbusCommSettings::parity()
{
return m_parity;
}
void ModbusCommSettings::setParity(QString parity)
{
m_parity = parity;
}
QString ModbusCommSettings::RTS()
{
return m_RTS;
}
void ModbusCommSettings::setRTS(QString RTS)
{
m_RTS = RTS;
}
QString ModbusCommSettings::maxNoOfLines()
{
return m_maxNoOfLines;
}
void ModbusCommSettings::setMaxNoOfLines(QString maxNoOfLines)
{
m_maxNoOfLines = maxNoOfLines;
}
QString ModbusCommSettings::baseAddr()
{
return m_baseAddr;
}
void ModbusCommSettings::setBaseAddr(QString baseAddr)
{
m_baseAddr = baseAddr;
}
QString ModbusCommSettings::timeOut()
{
return m_timeOut;
}
void ModbusCommSettings::setTimeOut(QString timeOut)
{
m_timeOut = timeOut;
}
int ModbusCommSettings::endian()
{
return m_endian;
}
void ModbusCommSettings::setEndian(int endian)
{
m_endian = endian;
}
int ModbusCommSettings::loggingLevel()
{
return m_loggingLevel;
}
bool ModbusCommSettings::readOutputsBeforeWrite()
{
return m_readOutputsBeforeWrite;
}
int ModbusCommSettings::modbusMode()
{
return m_modbusMode;
}
void ModbusCommSettings::setModbusMode(int modbusMode)
{
m_modbusMode = modbusMode;
}
int ModbusCommSettings::slaveID()
{
return m_slaveID;
}
void ModbusCommSettings::setSlaveID(int slaveID)
{
m_slaveID = slaveID;
}
int ModbusCommSettings::scanRate()
{
return m_scanRate;
}
void ModbusCommSettings::setScanRate(int scanRate)
{
m_scanRate = scanRate;
}
int ModbusCommSettings::functionCode()
{
return m_functionCode;
}
void ModbusCommSettings::setFunctionCode(int functionCode)
{
m_functionCode = functionCode;
}
int ModbusCommSettings::startAddr()
{
return m_startAddr;
}
void ModbusCommSettings::setStartAddr(int startAddr)
{
m_startAddr = startAddr;
}
int ModbusCommSettings::noOfRegs()
{
return m_noOfRegs;
}
void ModbusCommSettings::setNoOfRegs(int noOfRegs)
{
m_noOfRegs = noOfRegs;
}
int ModbusCommSettings::frmt()
{
return m_frmt;
}
void ModbusCommSettings::setFrmt(int frmt)
{
m_frmt = frmt;
}
int ModbusCommSettings::floatPrecision()
{
return m_floatPrecision;
}
void ModbusCommSettings::setfloatPrecision(int precision)
{
m_floatPrecision = precision;
}
void ModbusCommSettings::loadSession(QString fName)
{
QLOG_INFO()<< "Load session config from file " << fName;
QSettings m_save_session(fName, QSettings::IniFormat, this);
load(&m_save_session);
}
void ModbusCommSettings::saveSession(QString fName)
{
QLOG_INFO()<< "Save session config to file " << fName;
QSettings m_save_session(fName, QSettings::IniFormat, this);
save(&m_save_session);
}
void ModbusCommSettings::load(QSettings *s)
{
if (s->value("TCP/TCPPort").isNull())
m_TCPPort = "502";
else
m_TCPPort = s->value("TCP/TCPPort").toString();
if (s->value("TCP/SlaveIP").isNull())
m_slaveIP = "127.000.000.001";
else
m_slaveIP = s->value("TCP/SlaveIP").toString();
if (s->value("RTU/SerialDev").isNull())
#ifdef Q_OS_WIN32
m_serialDev = "COM";
#else
m_serialDev = "/dev/ttyS";
#endif
else
#ifdef Q_OS_WIN32
m_serialDev = "COM";
#else
m_serialDev = s->value("RTU/SerialDev").toString();
#endif
if (s->value("RTU/SerialPort").isNull())
{
m_serialPort = "1";
#ifdef Q_OS_WIN32
m_serialPortName = "COM" + m_serialPort;
#else
m_serialPortName = m_serialDev;
m_serialPortName += QStringLiteral("%1").arg(m_serialPort.toInt() - 1);
#endif
}
else {
m_serialPort = s->value("RTU/SerialPort").toString();
m_serialPortName = s->value("RTU/SerialPortName").toString();
}
if (s->value("RTU/Baud").isNull())
m_baud = "9600";
else
m_baud = s->value("RTU/Baud").toString();
if (s->value("RTU/DataBits").isNull())
m_dataBits = "8";
else
m_dataBits = s->value("RTU/DataBits").toString();
if (s->value("RTU/StopBits").isNull())
m_stopBits = "1";
else
m_stopBits = s->value("RTU/StopBits").toString();
if (s->value("RTU/Parity").isNull())
m_parity = "None";
else
m_parity = s->value("RTU/Parity").toString();
if (s->value("RTU/RTS").isNull())
#ifdef Q_OS_WIN32
m_RTS = "Disable";
#else
m_RTS = "None";
#endif
else
m_RTS = s->value("RTU/RTS").toString();
if (s->value("Var/MaxNoOfLines").toInt() == 0 ||
s->value("Var/MaxNoOfLines").isNull())
m_maxNoOfLines = "60";
else
m_maxNoOfLines = s->value("Var/MaxNoOfLines").toString();
if (s->value("Var/BaseAddr").isNull())
m_baseAddr = "1";
else
m_baseAddr = s->value("Var/BaseAddr").toString();
if (s->value("Var/TimeOut").isNull())
m_timeOut = "0";
else
m_timeOut = s->value("Var/TimeOut").toString();
if (s->value("Var/LoggingLevel").isNull())
m_loggingLevel = 3; //warning level
else
m_loggingLevel = s->value("Var/LoggingLevel").toInt();
if (s->value("Var/ReadOutputsBeforeWrite").isNull())
m_readOutputsBeforeWrite = true;
else
m_readOutputsBeforeWrite = s->value("Var/ReadOutputsBeforeWrite").toBool();
if (s->value("Var/Endian").isNull())
m_endian = 0;
else
m_endian = s->value("Var/Endian").toInt();
if (s->value("Session/ModBusMode").isNull())
m_modbusMode = 0; //RTU
else
m_modbusMode = s->value("Session/ModBusMode").toInt();
if (s->value("Session/SlaveID").isNull())
m_slaveID = 1;
else
m_slaveID = s->value("Session/SlaveID").toInt();
if (s->value("Session/ScanRate").isNull())
m_scanRate = 1000;
else
m_scanRate = s->value("Session/ScanRate").toInt();
if (s->value("Session/FunctionCode").isNull())
m_functionCode = 0; //FC1 : Read Coils
else
m_functionCode = s->value("Session/FunctionCode").toInt();
if (s->value("Session/StartAddr").isNull())
m_startAddr = 0;
else
m_startAddr = s->value("Session/StartAddr").toInt();
if (s->value("Session/NoOfRegs").isNull())
m_noOfRegs = 0;
else
m_noOfRegs = s->value("Session/NoOfRegs").toInt();
if (s->value("Session/Format").isNull())
m_frmt = 1; //Dec
else
m_frmt = s->value("Session/Format").toInt();
if (s->value("Session/FloatPrecision").isNull())
m_floatPrecision = 3;
else
m_floatPrecision = s->value("Session/FloatPrecision").toInt();
}
void ModbusCommSettings::save(QSettings *s)
{
s->setValue("TCP/TCPPort",m_TCPPort);
s->setValue("TCP/SlaveIP",m_slaveIP);
s->setValue("RTU/SerialDev",m_serialDev);
s->setValue("RTU/SerialPort",m_serialPort);
s->setValue("RTU/SerialPortName",m_serialPortName);
s->setValue("RTU/Baud",m_baud);
s->setValue("RTU/DataBits",m_dataBits);
s->setValue("RTU/StopBits",m_stopBits);
s->setValue("RTU/Parity",m_parity);
s->setValue("RTU/RTS",m_RTS);
s->setValue("Var/MaxNoOfLines",m_maxNoOfLines);
s->setValue("Var/BaseAddr",m_baseAddr);
s->setValue("Var/TimeOut",m_timeOut);
s->setValue("Var/LoggingLevel",m_loggingLevel);
s->setValue("Var/ReadOutputsBeforeWrite",m_readOutputsBeforeWrite);
s->setValue("Var/Endian",m_endian);
s->setValue("Session/ModBusMode",m_modbusMode);
s->setValue("Session/SlaveID",m_slaveID);
s->setValue("Session/ScanRate",m_scanRate);
s->setValue("Session/FunctionCode",m_functionCode);
s->setValue("Session/StartAddr",m_startAddr);
s->setValue("Session/NoOfRegs",m_noOfRegs);
s->setValue("Session/Format",m_frmt);
s->setValue("Session/FloatPrecision",m_floatPrecision);
}

View File

@@ -0,0 +1,107 @@
#ifndef MODBUSCOMMSETTINGS_H
#define MODBUSCOMMSETTINGS_H
#include <QSettings>
class ModbusCommSettings : public QSettings
{
Q_OBJECT
public:
explicit ModbusCommSettings(QObject *parent = 0) : QSettings(parent) { }
ModbusCommSettings(const QString &fileName, Format format = QSettings::IniFormat, QObject *parent = 0);
//TCP
QString TCPPort();
void setTCPPort(QString tcpPort);
void setSlaveIP(QString IP);
QString slaveIP();
//Serial
QString serialDev();
QString serialPort();
QString serialPortName();
void setSerialPort(QString serialPort, QString serialDev = "");
QString baud();
void setBaud(QString baud);
QString dataBits();
void setDataBits(QString dataBits);
QString stopBits();
void setStopBits(QString stopBits);
QString parity();
void setParity(QString parity);
QString RTS();
void setRTS(QString RTS);
//Var
QString maxNoOfLines();
void setMaxNoOfLines(QString maxNoOfLines);
QString baseAddr();
void setBaseAddr(QString baseAddr);
QString timeOut();
void setTimeOut(QString timeOut);
int endian();
void setEndian(int endian);
void loadSettings();
void saveSettings();
//logging
int loggingLevel();
//
bool readOutputsBeforeWrite();
//session
int modbusMode();
void setModbusMode(int modbusMode);
int slaveID();
void setSlaveID(int slaveID);
int scanRate();
void setScanRate(int scanRate);
int functionCode();
void setFunctionCode(int functionCode);
int startAddr();
void setStartAddr(int startAddr);
int noOfRegs();
void setNoOfRegs(int noOfRegs);
int frmt();
void setFrmt(int frmt);
int floatPrecision();
void setfloatPrecision(int precision);
void loadSession(QString fName);
void saveSession(QString fName);
private:
//TCP
QString m_TCPPort;
QString m_slaveIP;
//Serial
QString m_serialDev;
QString m_serialPort;
QString m_serialPortName;
QString m_baud;
QString m_dataBits;
QString m_stopBits;
QString m_parity;
QString m_RTS;
//Var
QString m_maxNoOfLines;
QString m_baseAddr;
QString m_timeOut;
int m_endian;
void load(QSettings *s);
void save(QSettings *s);
//Log
int m_loggingLevel;
//read outputs before write
bool m_readOutputsBeforeWrite;
//Session vars
int m_modbusMode;
int m_slaveID;
int m_scanRate;
int m_functionCode;
int m_startAddr;
int m_noOfRegs;
int m_frmt;
int m_floatPrecision;
signals:
public slots:
};
#endif // MODBUSCOMMSETTINGS_H

View File

@@ -0,0 +1,12 @@
#include "rawdatadelegate.h"
#include <QtDebug>
#include <QPainter>
//TODO : use delegate
void RawDataDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
}

View File

@@ -0,0 +1,17 @@
#ifndef RAWDATADELEGATE_H
#define RAWDATADELEGATE_H
#include <QStyledItemDelegate>
class RawDataDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
RawDataDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
#endif // RAWDATADELEGATE_H

View File

@@ -0,0 +1,44 @@
#include "rawdatamodel.h"
#include "QsLog.h"
#include <QtDebug>
RawDataModel::RawDataModel(QObject *parent) :
QObject(parent)
{
model = new QStringListModel(this);
m_addLinesEnabled = false;
}
void RawDataModel::addLine(QString line)
{
if (!m_addLinesEnabled) return;
QLOG_TRACE() << "Raw Data Model Line = " << line << " , No of lines = " << m_rawData.length();
if (m_rawData.length() == m_maxNoOfLines)
m_rawData.removeFirst();
m_rawData.append(line);
model->setStringList(m_rawData);
}
void RawDataModel::clear()
{
QLOG_TRACE() << "Raw Data Model cleared" ;
m_rawData.clear();
model->setStringList(m_rawData);
}
void RawDataModel::setMaxNoOfLines(int noOfLines)
{
m_maxNoOfLines = noOfLines;
}
void RawDataModel::enableAddLines(bool en)
{
m_addLinesEnabled = en;
}

View File

@@ -0,0 +1,31 @@
#ifndef RAWDATAMODEL_H
#define RAWDATAMODEL_H
#include <QObject>
#include <QStringListModel>
class RawDataModel : public QObject
{
Q_OBJECT
public:
explicit RawDataModel(QObject *parent = 0);
QStringListModel *model;
void addLine(QString line);
void enableAddLines(bool en);
void clear();
void setMaxNoOfLines(int noOfLines);
int maxNoOfLines() { return m_maxNoOfLines; }
signals:
public slots:
private:
QStringList m_rawData;
int m_maxNoOfLines;
bool m_addLinesEnabled;
};
#endif // RAWDATAMODEL_H

View File

@@ -0,0 +1,158 @@
#include "registersdatadelegate.h"
#include "mainwindow.h"
#include "QsLog.h"
#include <QtDebug>
#include <QPainter>
#include <QSpinBox>
#include <QLineEdit>
#include "eutils.h"
void RegistersDataDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
}
QWidget *RegistersDataDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
if (m_frmt == EUtils::Bin) {//Bin
if (m_is16Bit) {
QLineEdit *editor = new QLineEdit(parent);
editor->setInputMask("bbbbbbbbbbbbbbbb");
return editor;
}
else {
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(0);
editor->setMaximum(1);
return editor;
}
}
else if (m_frmt == EUtils::Dec) {//Dec
QLineEdit *editor = new QLineEdit(parent);
QRegularExpression rx("-{0,1}[0-9]{1,5}");
QValidator *validator = new QRegularExpressionValidator(rx);
editor->setValidator(validator);
return editor;
}
else if (m_frmt == EUtils::Float) {//Float
QLineEdit *editor = new QLineEdit(parent);
QRegularExpression rx("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$");
QValidator *validator = new QRegularExpressionValidator(rx);
editor->setValidator(validator);
return editor;
}
else if (m_frmt == EUtils::Hex) {//Hex
QLineEdit *editor = new QLineEdit(parent);
editor->setInputMask("hhhh");
return editor;
}
else {//Default = Dec
QLineEdit *editor = new QLineEdit(parent);
QRegularExpression rx("-{0,1}[0-9]{1,5}");
QValidator *validator = new QRegularExpressionValidator(rx);
editor->setValidator(validator);
return editor;
}
}
void RegistersDataDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QString value = index.model()->data(index, Qt::EditRole).toString();
if (m_frmt == EUtils::Bin && !m_is16Bit) {//Bin
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value.toInt());
}
else { //Bin 16 Bit, Dec, Hex, Float?
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText(value);
}
}
void RegistersDataDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QString value;
int intVal;
float floatVal;
bool ok;
if (m_frmt == EUtils::Bin && !m_is16Bit) {//Bin
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
intVal = (spinBox->text()).toInt(&ok,m_frmt);
value = EUtils::formatValue(intVal, m_frmt, m_is16Bit, m_isSigned);
}
else if (m_frmt == EUtils::Float){ //Float
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
floatVal = (lineEdit->text()).toFloat(&ok);
value = EUtils::formatValue32(floatVal, m_floatPrecision);
}
else { //Bin 16 Bit, Dec, Hex
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
intVal = (lineEdit->text()).toInt(&ok,m_frmt);
if (intVal > 65535){
mainWin->showUpInfoBar(tr("Set value failed\nValue is greater than 65535."), InfoBar::Error);
QLOG_WARN() << "Set value failed. Value is greater than 65535";
return;
}
else if (intVal < -32768){
mainWin->showUpInfoBar(tr("Set value failed\nValue is smaller than -32768."), InfoBar::Error);
QLOG_WARN() << "Set value failed. Value is smaller than -32768";
return;
}
else
{
mainWin->hideInfoBar();
}
value = EUtils::formatValue(intVal, m_frmt, m_is16Bit, m_isSigned);
}
QLOG_TRACE() << "Set model data value = " << value;
model->setData(index, value, Qt::EditRole);
}
void RegistersDataDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
void RegistersDataDelegate::setFrmt(int frmt)
{
m_frmt = frmt;
}
void RegistersDataDelegate::setIs16Bit(bool is16Bit)
{
m_is16Bit = is16Bit;
}
void RegistersDataDelegate::setIsSigned(bool isSigned)
{
m_isSigned = isSigned;
}
void RegistersDataDelegate::setFloatPrecision(int precision)
{
m_floatPrecision = precision;
}

View File

@@ -0,0 +1,39 @@
#ifndef REGISTERSDELEGATE_H
#define REGISTERSDELEGATE_H
#include <QStyledItemDelegate>
class RegistersDataDelegate : public QStyledItemDelegate
{
Q_OBJECT
private:
int m_frmt;
bool m_is16Bit;
bool m_isSigned;
int m_floatPrecision;
public:
RegistersDataDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { }
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setFrmt(int frmt);
void setIs16Bit(bool is16Bit);
void setIsSigned(bool isSigned);
void setFloatPrecision(int precision);
};
#endif // REGISTERSDELEGATE_H

View File

@@ -0,0 +1,383 @@
#include "registersmodel.h"
#include "QsLog.h"
#include <QStandardItem>
#include <QtDebug>
#include "eutils.h"
RegistersModel::RegistersModel(QObject *parent) :
QObject(parent)
{
model = new QStandardItemModel(0,0,this);
m_regDataDelegate = new RegistersDataDelegate(0);
m_noOfItems = 0;
m_is16Bit = false;
m_isSigned = false;
m_startAddrBase = 10;
clear();
}
void RegistersModel::addItems(int startAddress, int noOfItems, bool valueIsEditable)
{
int row;
int col;
m_startAddress = startAddress;
m_noOfItems = noOfItems;
QLOG_TRACE() << "Registers Model Address = " << startAddress << " , noOfItems = " << noOfItems
<< " , first row = " << m_firstRow << " , last row = " << m_lastRow;
//Format Vertical - Horizontal Headers
clear();
if (noOfItems > 1) {
if (m_frmt == EUtils::Float){
m_firstRow = 0;
m_lastRow = (noOfItems - 1) / 20;
model->setHorizontalHeaderLabels(QStringList()<<RegModelFloatHeaderLabels[0]<<RegModelFloatHeaderLabels[1]
<<RegModelFloatHeaderLabels[2]<<RegModelFloatHeaderLabels[3]
<<RegModelFloatHeaderLabels[4]<<RegModelFloatHeaderLabels[5]
<<RegModelFloatHeaderLabels[6]<<RegModelFloatHeaderLabels[7]
<<RegModelFloatHeaderLabels[8]<<RegModelFloatHeaderLabels[9]);
QStringList vertHeader;
for (int i = m_firstRow; i <= m_lastRow; i++) {
vertHeader<<QString("%1").arg(startAddress + i * 20, 2, 10, QLatin1Char('0'));
}
model->setVerticalHeaderLabels(vertHeader);
}
else {
m_firstRow = 0;
m_lastRow = (noOfItems - 1) / 10;
model->setHorizontalHeaderLabels(QStringList()<<RegModelHeaderLabels[0]<<RegModelHeaderLabels[1]
<<RegModelHeaderLabels[2]<<RegModelHeaderLabels[3]
<<RegModelHeaderLabels[4]<<RegModelHeaderLabels[5]
<<RegModelHeaderLabels[6]<<RegModelHeaderLabels[7]
<<RegModelHeaderLabels[8]<<RegModelHeaderLabels[9]);
QStringList vertHeader;
for (int i = m_firstRow; i <= m_lastRow; i++) {
vertHeader<<QString("%1").arg(startAddress + i * 10, 2, 10, QLatin1Char('0'));
}
model->setVerticalHeaderLabels(vertHeader);
}
}
else {
model->setHorizontalHeaderLabels(QStringList()<<RegModelHeaderLabels[0]);
model->setVerticalHeaderLabels(QStringList()<<QString("%1").arg(startAddress, 2, 10, QLatin1Char('0')));
}
//Add data to model
if (noOfItems == 1){
QStandardItem *valueItem = new QStandardItem("-");model->setItem(0, 0, valueItem);
valueItem->setEditable(valueIsEditable);
}
else {
if (m_frmt == EUtils::Float){
m_firstRow = 0;
m_lastRow = (noOfItems - 1) / 20;
for (int i = m_firstRow; i <= m_lastRow; i++) {
row = i;
for (int j = 0; j < 10; j++) {
col = j;
if ((row * 10 + col) >= (noOfItems / 2)){//not used cells
QStandardItem *valueItem = new QStandardItem("x");model->setItem(row, col, valueItem);
valueItem->setEditable(false);
valueItem->setForeground(QBrush(Qt::red));
valueItem->setBackground(QBrush(Qt::lightGray));
}
else {
QStandardItem *valueItem = new QStandardItem("-");model->setItem(row, col, valueItem);
valueItem->setEditable(valueIsEditable);
}
}
}
}
else {
m_firstRow = 0;
m_lastRow = (noOfItems - 1) / 10;
for (int i = m_firstRow; i <= m_lastRow; i++) {
row = i;
for (int j = 0; j < 10; j++) {
col = j;
if ((row * 10 + col) >= (noOfItems)){//not used cells
QStandardItem *valueItem = new QStandardItem("x");model->setItem(row, col, valueItem);
valueItem->setEditable(false);
valueItem->setForeground(QBrush(Qt::red));
valueItem->setBackground(QBrush(Qt::lightGray));
}
else {
QStandardItem *valueItem = new QStandardItem("-");model->setItem(row, col, valueItem);
valueItem->setEditable(valueIsEditable);
}
}
}
}
}
emit(refreshView());
}
void RegistersModel::setNoValidValues()
{
int row;
int col;
//if we have no valid values we set as value = '-/-'
if (m_frmt == EUtils::Float){
for (int i = 0; i < (m_noOfItems / 2); i++){
row = i / 10;
col = i % 10;
QModelIndex index = model->index(row, col, QModelIndex());
model->setData(index,QBrush(Qt::red),Qt::ForegroundRole);
model->setData(index,"-/-",Qt::DisplayRole);
}
}
else {
for (int i = 0; i < m_noOfItems; i++){
row = i / 10;
col = i % 10;
QModelIndex index = model->index(row, col, QModelIndex());
model->setData(index,QBrush(Qt::red),Qt::ForegroundRole);
model->setData(index,"-/-",Qt::DisplayRole);
}
}
}
void RegistersModel::setValue(int idx, int value)
{
int row;
int col;
QString convertedValue;
convertedValue = EUtils::formatValue(value, m_frmt, m_is16Bit, m_isSigned);
//set model data
if (m_noOfItems == 1){
row = 0;
col = 0;
}
else {
row = (idx) / 10;
col = (idx) % 10;
}
QModelIndex index = model->index(row, col, QModelIndex());
model->setData(index,QBrush(Qt::black),Qt::ForegroundRole);
model->setData(index,convertedValue,Qt::DisplayRole);
model->setData(index,QString("Address : %1").arg(m_startAddress + idx, 1, m_startAddrBase).toUpper(),Qt::ToolTipRole);
}
void RegistersModel::setValue32(int idx, int valueHi, int valueLo)
{//update model with float values
int row;
int col;
QString convertedValue;
convertedValue = EUtils::formatValue32(valueHi, valueLo, m_endian, m_floatPrecision);
//set model data
if (m_noOfItems == 1){
row = 0;
col = 0;
}
else {
row = (idx) / 10;
col = (idx) % 10;
}
QModelIndex index = model->index(row, col, QModelIndex());
model->setData(index,QBrush(Qt::black),Qt::ForegroundRole);
model->setData(index,convertedValue,Qt::DisplayRole);
model->setData(index,QString("Address : %1").arg(m_startAddress + 2*idx, 1, m_startAddrBase).toUpper(),Qt::ToolTipRole);
}
int RegistersModel::value(int idx)
{
QString stringVal;
int intVal;
bool ok;
//Get Value
stringVal = strValue(idx);
intVal = stringVal.toInt(&ok,m_frmt);
if (ok)
return intVal;
else
return -1;
}
float RegistersModel::floatValue(int idx)
{
QString stringVal;
float floatVal;
bool ok;
//Get Value
stringVal = strValue(idx);
floatVal = stringVal.toFloat(&ok);
if (ok)
return floatVal;
else
return -1;
}
QString RegistersModel::strValue(int idx)
{
int row;
int col;
//get model data
if (m_noOfItems == 1){
row = 0;
col = 0;
}
else {
row = (idx) / 10;
col = (idx) % 10;
}
QModelIndex index = model->index(row, col, QModelIndex());
QVariant value = model->data(index,Qt::DisplayRole);
if (value.canConvert<QString>())
return value.toString();
else
return "-/-";
}
void RegistersModel::changeFrmt(int frmt)
{
QString stringVal;
int intVal;
int row;
int col;
bool ok;
QString convertedVal;
QLOG_TRACE()<< "Registers Model changed format from " << m_frmt << " to " << frmt ;
//change base
for (int idx = 0; idx < m_noOfItems ; idx++) {
//Get Value
stringVal = strValue(idx);
intVal = stringVal.toInt(&ok,m_frmt);
//Format Value
if (ok)
convertedVal = EUtils::formatValue(intVal, frmt, m_is16Bit, m_isSigned);
else
convertedVal = "-/-";
//Update
if (m_noOfItems == 1){
row = 0;
col = 0;
}
else {
row = (idx) / 10;
col = (idx) % 10;
}
QModelIndex index = model->index(row, col, QModelIndex());
model->setData(index,convertedVal,Qt::DisplayRole);
model->setData(index,QString("Address : %1").arg(m_startAddress + idx, m_startAddrBase).toUpper(),Qt::ToolTipRole);
}
emit(refreshView());
}
void RegistersModel::clear()
{
QLOG_TRACE()<< "Registers Model Cleared" ;
//Clear model
model->clear();
}
void RegistersModel::setStartAddrBase(int base)
{
QLOG_TRACE()<< "Registers Model start addr set base = " << base ;
m_startAddrBase = base;
changeFrmt(m_frmt);
}
void RegistersModel::setFrmt(int frmt)
{
QLOG_TRACE()<< "Registers Model set base = " << frmt ;
m_regDataDelegate->setFrmt(frmt);
changeFrmt(frmt);
m_frmt = frmt;
}
int RegistersModel::getFrmt()
{
QLOG_TRACE()<< "Registers Model get format = " << m_frmt ;
return m_frmt;
}
void RegistersModel::setIs16Bit(bool is16Bit)
{
QLOG_TRACE()<< "Registers Model Is16Bit = " << is16Bit ;
m_is16Bit = is16Bit;
m_regDataDelegate->setIs16Bit(is16Bit);
}
void RegistersModel::setIsSigned(bool isSigned)
{
QLOG_TRACE()<< "Registers Model IsSigned = " << isSigned ;
m_isSigned = isSigned;
m_regDataDelegate->setIsSigned(isSigned);
changeFrmt(m_frmt);
}
void RegistersModel::setEndian(int endian)
{
QLOG_TRACE()<< "Registers Model endianness = " << endian ;
m_endian = endian;
}
int RegistersModel::getEndian()
{
QLOG_TRACE()<< "Registers Model endianness = " << m_endian ;
return m_endian;
}
void RegistersModel::setFloatPrecision(int precision)
{
QLOG_TRACE()<< "Registers Model float precision = " << precision ;
m_floatPrecision = precision;
m_regDataDelegate->setFloatPrecision(precision);
}
RegistersDataDelegate* RegistersModel::itemDelegate()
{
return m_regDataDelegate;
}

View File

@@ -0,0 +1,59 @@
#ifndef REGISTERSMODEL_H
#define REGISTERSMODEL_H
#include <QObject>
#include <QStandardItemModel>
#include "registersdatadelegate.h"
static const QString RegModelHeaderLabels[]={"+00", "+01", "+02", "+03", "+04", "+05", "+06", "+07", "+08", "+09"};
static const QString RegModelFloatHeaderLabels[]={"+00", "+02", "+04", "+06", "+08", "+10", "+12", "+14", "+16", "+18"};
static const int AddressColumn=0;
static const int ValueColumn=1;
class RegistersModel : public QObject
{
Q_OBJECT
public:
explicit RegistersModel(QObject *parent = 0);
void addItems(int startAddress, int noOfItems, bool valueIsEditable);
void setValue(int idx, int value);
void setValue32(int idx, int valueHi, int valueLo);
void setFrmt(int frmt);
int getFrmt();
void setStartAddrBase(int base);
void setIs16Bit(bool is16Bit);
void setIsSigned(bool isSigned);
void setEndian(int endian);
int getEndian();
void setFloatPrecision(int precision);
QString strValue(int idx);
int value(int idx);
float floatValue(int idx);
QStandardItemModel *model;
void clear();
void setNoValidValues();
RegistersDataDelegate* itemDelegate();
private:
void changeFrmt(int frmt);
int m_startAddress;
int m_noOfItems;
int m_firstRow;
int m_lastRow;
bool m_is16Bit;
bool m_isSigned;
int m_startAddrBase;
int m_frmt;
int m_endian;
int m_floatPrecision;
RegistersDataDelegate *m_regDataDelegate;
signals:
void refreshView();
public slots:
};
#endif // REGISTERSMODEL_H