1.头文件
#ifndef CMODBUSTCP_H
#define CMODBUSTCP_H
#include <QObject>
#include <QModbusTcpClient>
class QModbusClient;
class QModbusReply;
class CModbusTcp : public QObject
{
Q_OBJECT
public:
enum DATAFORMAT{
INT_FORMAT = 0,
FLOAT_FORMAT,
STRING_FORMAT,
BOOL_FORMAT,
MAXDATA_FORMAT
};
Q_ENUM(DATAFORMAT)
public:
explicit CModbusTcp(QObject *parent = nullptr);
~CModbusTcp();
QString m_strReceived;
QModbusClient *m_pmodbusDevice = nullptr;
private:
bool bHexFormatEchoDisplay; //flag whether the echo string is hex format, default is false
bool bHexFormatDataSend; //flag whether the data sent is hex format, default is true
DATAFORMAT m_analysisDataFormat;
signals:
void signalStateChanged(bool bConnected);
void signalDataReceived(QString strDataReceived);
//reserved for send original data
void signalOriginalData(QModbusDataUnit responseData);
public slots:
void onReadReady();
void onModbusStateChanged(QModbusDevice::State state);
void coilRead(int nStartAddress,uint16_t numbers,int ServerID);
void coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID);
void discreteInputRead(int nStartAddress,uint16_t numbers,int ServerID);
void inputRegisterRead(int nStartAddress,uint16_t numbers,int ServerID);
void holdingRegsiterRead(int nStartAddress,uint16_t numbers,int ServerID, int nDataFormat);
void holdingRegisterWrite(int nStartAddress,QString strHoldingRegisterToWrite,int ServerID, int nDataFormat);
bool connect2Server(QString strIP = "127.0.0.1", QString strPort = "502");
void disconnectFromServer();
private:
QString getAnalysisReturnString(QModbusDataUnit responseData);
};
#endif // CMODBUSTCP_H
2.实现文件
#include "cmodbustcp.h"
#include <QThread>
#include <QDebug>
#define DELETE_AND_SET_NULL(pointer) if(pointer != nullptr) { delete pointer; pointer = nullptr;};
#define DELETE_AND_SET_NULL_ARRAY(pointer) if(pointer != nullptr) { delete[] pointer; pointer = nullptr;};
CModbusTcp::CModbusTcp(QObject *parent) :
QObject(parent)
,bHexFormatEchoDisplay(false)
,bHexFormatDataSend(true)
{
m_analysisDataFormat = INT_FORMAT;
m_pmodbusDevice = new QModbusTcpClient(this);
connect(m_pmodbusDevice, &QModbusClient::stateChanged,this, &CModbusTcp::onModbusStateChanged);
}
CModbusTcp::~CModbusTcp()
{
DELETE_AND_SET_NULL(m_pmodbusDevice);
}
bool CModbusTcp::connect2Server(QString strIP, QString strPort)
{
bool bRet= false;
m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, strIP);
m_pmodbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, strPort.toInt());
m_pmodbusDevice->setTimeout(1000);
m_pmodbusDevice->setNumberOfRetries(3);
bRet = m_pmodbusDevice->connectDevice();
if(bRet)
{
qDebug()<< "connect to PLC OK";
} else {
qDebug()<< "connect to PLC Fail";
}
return bRet;
}
void CModbusTcp::disconnectFromServer()
{
if(m_pmodbusDevice) m_pmodbusDevice->disconnectDevice();
}
void CModbusTcp::coilRead(int nStartAddress,uint16_t numbers,int ServerID)
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::Coils, nStartAddress, numbers);
auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
if(nullptr == reply)
{
qDebug() << "faile to send request data: " << m_pmodbusDevice->errorString();
} else {
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::coilWrite(int nStartAddress,QString strCoilToWrite,int ServerID)
{
if(m_pmodbusDevice)
{
int nstrLength = strCoilToWrite.length();
if(nstrLength == 0)
{
qDebug() << "Warnning:Coil String to send is Null!";
return;
}
QModbusDataUnit writeData(QModbusDataUnit::Coils, nStartAddress, (nstrLength >> 1) + (nstrLength & 1));
for (uint i = 0; i < writeData.valueCount(); i++)
{
writeData.setValue(i, strCoilToWrite.at(2*i).unicode() - '0');
}
qDebug() << "data sent is: " << writeData.values();
QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, ServerID);
if (reply)
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "data written error: " << reply->errorString();
}
else if (reply->error() != QModbusDevice::NoError)
{
qDebug() << "data written error: " << reply->errorString();
}
else
{
const QModbusDataUnit data = reply->result();
qDebug() << "data written: " << data.values();
m_strReceived = "";
for(auto value: data.values())
{
m_strReceived += tr("%1 ").arg(value);
}
emit signalDataReceived(m_strReceived);
}
reply->deleteLater();
});
}
else
{
reply->deleteLater();
}
}
else
{
qDebug() << "sendWriteRequest Error: " << reply->errorString();
}
}
}
void CModbusTcp::discreteInputRead(int nStartAddress,uint16_t numbers,int ServerID)
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::DiscreteInputs, nStartAddress, numbers);
auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
if (nullptr == reply)
{
qDebug() << "fail to send data: " << m_pmodbusDevice->errorString();
}
else
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::inputRegisterRead(int nStartAddress,uint16_t numbers,int ServerID)
{
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::InputRegisters, nStartAddress, numbers);
QModbusReply* reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
if (nullptr == reply)
{
qDebug() << "failed to send data: " << m_pmodbusDevice->errorString();
}
else
{
qDebug() << "input register Read command have sent";
if (!reply->isFinished())
{
qDebug() << "input register Read command is running";
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
qDebug() << "input register Read command immediately reply";
delete reply;
}
}
}
}
void CModbusTcp::holdingRegsiterRead(int nStartAddress,uint16_t numbers,int ServerID, int nDataFormat)
{
assert((nDataFormat >=0) && (nDataFormat < MAXDATA_FORMAT));
m_analysisDataFormat = DATAFORMAT(nDataFormat);
if(m_pmodbusDevice)
{
QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, nStartAddress, numbers);
auto reply = m_pmodbusDevice->sendReadRequest(data, ServerID);
if (nullptr == reply)
{
qDebug() << "failed to send request data: " << m_pmodbusDevice->errorString();
}
else
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &CModbusTcp::onReadReady);
}
else
{
delete reply;
}
}
}
}
void CModbusTcp::holdingRegisterWrite(int nStartAddress,QString strHoldingRegisterToWrite,int ServerID, int nDataFormat)
{
assert((nDataFormat >=0) && (nDataFormat < MAXDATA_FORMAT));
m_analysisDataFormat = DATAFORMAT(nDataFormat);
if(m_pmodbusDevice)
{
QModbusDataUnit writeData;
if (nDataFormat == INT_FORMAT)
{
writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 1);
writeData.setValue(0,strHoldingRegisterToWrite.toUShort());
} else if (nDataFormat == FLOAT_FORMAT) {
writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 2);
float fData = strHoldingRegisterToWrite.toFloat();
unsigned char* p = (unsigned char*)&fData;
writeData.setValue(0, *p | *(p+1) << 8);
writeData.setValue(1, *(p+2) | *(p+3) << 8);
} else if (nDataFormat == STRING_FORMAT) {
int nDataLength = (strHoldingRegisterToWrite.length() >> 1) + (strHoldingRegisterToWrite.length() & 1);
writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, nDataLength);
for (uint i = 0; i < writeData.valueCount(); i++) {
char tmpChar1 = strHoldingRegisterToWrite.at(2*i).toLatin1();
char tmpChar2 = 0;
if(2*i + 1 <= strHoldingRegisterToWrite.length() - 1 )
{
tmpChar2 = strHoldingRegisterToWrite.at(2*i + 1).toLatin1();
}
writeData.setValue(i, tmpChar2 <<8 | tmpChar1);
}
} else if (nDataFormat == BOOL_FORMAT) {
writeData = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, nStartAddress, 1);
writeData.setValue(0,strHoldingRegisterToWrite.toUInt());
}
QModbusReply* reply = m_pmodbusDevice->sendWriteRequest(writeData, ServerID);
if (reply)
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply](){
if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "data written error: " << reply->errorString();
}
else if (reply->error() != QModbusDevice::NoError)
{
qDebug() << "data written error: " << reply->errorString();
}
else
{
const QModbusDataUnit data = reply->result();
//solution1: send the analysis result string
getAnalysisReturnString(data);
emit signalDataReceived(m_strReceived);
//soltion2: send orignal data
//emit signalOriginalData(data);
}
reply->deleteLater();
});
}
else
{
reply->deleteLater();
}
}
else
{
qDebug() << "sendWriteRequest Error: " << reply->errorString();
}
}
}
void CModbusTcp::onReadReady()
{
auto reply = qobject_cast<QModbusReply*>(sender());
if (nullptr == reply)
{
return;
}
if (reply->error() == QModbusDevice::NoError)
{
const QModbusDataUnit responseData = reply->result();
//方案1:发送解析过的数据
getAnalysisReturnString(responseData);
emit signalDataReceived(m_strReceived);
//方案2:发送原始数据包,由界面GUI解析
//emit signalOriginalData(responseData);
}
else if (reply->error() == QModbusDevice::ProtocolError)
{
qDebug() << "Read response Protocol error: " << reply->errorString();
}
else
{
qDebug() << "Read response Error: " << reply->errorString();
}
reply->deleteLater();
}
void CModbusTcp::onModbusStateChanged(QModbusDevice::State state)
{
bool bConnected=false;
if(state == QModbusDevice::ConnectedState)
{
bConnected=true;
}
else
{
bConnected=false;
}
emit signalStateChanged(bConnected);
}
QString CModbusTcp::getAnalysisReturnString(QModbusDataUnit responseData)
{
quint16 highword;
quint16 lowword;
char tmpCharArrays[4];
float *pFloat;
float ftemp;
m_strReceived = "";
switch (m_analysisDataFormat) {
case INT_FORMAT:
m_strReceived += tr("%1 ").arg(responseData.values()[0]);
break;
case FLOAT_FORMAT:
highword = responseData.values()[0];
lowword = responseData.values()[1];
tmpCharArrays[0] = highword & 0xff;
tmpCharArrays[1] = (highword >>8) & 0xff;
tmpCharArrays[2] = lowword & 0xff;
tmpCharArrays[3] = (lowword >>8) & 0xff;
pFloat = (float*)&tmpCharArrays[0];
ftemp = *pFloat;
m_strReceived += tr("%1 ").arg(ftemp);
break;
case STRING_FORMAT:
char chTmp1;
char chTmp2;
for(auto value: responseData.values())
{
chTmp1 = value & 0xff;
chTmp2 = (value >> 8) & 0xff;
m_strReceived += tr("%1%2").arg(chTmp1).arg(chTmp2);
}
break;
case BOOL_FORMAT:
m_strReceived += tr("%1 ").arg(responseData.values()[0]);
break;
default:
qDebug() << "NOT SUPPORTED DATA FORMAT!!!";
break;
}
return m_strReceived;
}