经过汇川AM403测试的Modbus Tcp 类的C++实现

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;

}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>