1. 程式人生 > 實用技巧 >Qt windows串列埠通訊

Qt windows串列埠通訊

Qt 串列埠通訊SerialServer

原始碼

serialserver.h

#ifndef SERIALSERVER_H
#define SERIALSERVER_H

#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>

class SerialServer : public QObject
{
    Q_OBJECT
public:
    enum SerialStatus{
        connect = 0x01,
        disconnect = 0x02
    };
    explicit        SerialServer(QObject *parent = nullptr);
    QStringList     getAvailableSerialPort();
    bool            connectToDevice(QString portName);
    void            close();
    bool            serialGetResp(const QByteArray sendData,QByteArray *respData,int timeout);
private slots:
    void            serialRead();
    void            recvTimerTimeOut(void);
signals:
    void            serialStatusChanged(SerialStatus status);
    void            serialErrorOccur(QString errorMsg);
private:
    QSerialPort     *m_serial;
    QTimer          *m_serialRecvTimer;
    QByteArray      serialDataCache;
    QByteArray      serialFrameData;
    bool            newFrameDataRecv = false;
    QString         errorMsg;
    QString         getPortName(int index, QString keyorvalue);
    QStringList     availableSerialPortName;
};

#endif // SERIALSERVER_H

serialserver.cpp

#include "serialserver.h"
#include <QSettings>
#include <QTime>
#include <QCoreApplication>
#include <qt_windows.h>

SerialServer::SerialServer(QObject *parent) : QObject(parent)
{
    m_serial = new QSerialPort(this);
    m_serialRecvTimer = new QTimer(this);
    QObject::connect(m_serial,SIGNAL(readyRead()),this,SLOT(serialRead()));
    QObject::connect(m_serialRecvTimer,SIGNAL(timeout()),SLOT(recvTimerTimeOut()));
    QObject::connect(m_serial,&QSerialPort::errorOccurred,[=](QSerialPort::SerialPortError error){
        if(error == QSerialPort::SerialPortError::NoError) return ;
        QString errMsg;
        switch(error){
        case QSerialPort::SerialPortError::DeviceNotFoundError :errMsg=tr("裝置不存在");break;//PermissionError
        case QSerialPort::SerialPortError::PermissionError :errMsg=tr("裝置連接出錯:已有其他軟體連線該裝置");break;
        case QSerialPort::SerialPortError::OpenError :errMsg=tr("裝置打開出錯。");break;
        case QSerialPort::SerialPortError::WriteError :errMsg=tr("裝置通訊寫入發生錯誤,串列埠已關閉");break;
        case QSerialPort::SerialPortError::ReadError :errMsg=tr("裝置通訊讀取發生錯誤,串列埠已關閉");break;
        case QSerialPort::SerialPortError::ResourceError :errMsg=tr("裝置已拔出,串列埠已關閉");break;
        default :errMsg = tr("未知錯誤:錯誤碼")+QString::number(error);break;
        }
        this->errorMsg = errMsg;
        m_serial->clearError();
        this->close();
        QMessageBox::information(NULL,"ERROR",errMsg);
    });
}

bool SerialServer::serialGetResp(const QByteArray sendData, QByteArray *respData, int timeout)
{
    if(!m_serial->isOpen()){
        QMessageBox::information(NULL,"info","裝置未連線");
        return false;
    }
    serialDataCache.clear();
    newFrameDataRecv = false;
    this->m_serial->write(sendData);
    QTime dieTime = QTime::currentTime().addMSecs(timeout);
    while(QTime::currentTime()<dieTime){
         QCoreApplication::processEvents(QEventLoop::AllEvents,100);
         if(newFrameDataRecv == true){
             respData->append(serialFrameData);
             return true;
         }
    }
    return false;
}

bool SerialServer::connectToDevice(QString portName)
{
    if(m_serial->isOpen()) return false;
    if(!availableSerialPortName.contains(portName)){
        QMessageBox::information(NULL,"ERROR","串列埠開啟錯誤,當前串列埠已被其他裝置佔用");
        return false;
    }
    m_serial->setPortName(portName);
    m_serial->setBaudRate(QSerialPort::Baud9600);
    m_serial->setDataBits(QSerialPort::Data8);
    m_serial->setParity(QSerialPort::Parity::NoParity);
    m_serial->setStopBits(QSerialPort::StopBits::OneStop);
    m_serial->setFlowControl(QSerialPort::NoFlowControl);
    if(m_serial->open(QIODevice::ReadWrite)==true){
        emit serialStatusChanged(SerialStatus::connect);
        return true;
    }else{
        return false;
    }
}

void SerialServer::close()
{
    if(m_serial->isOpen()){
        m_serial->clear();
        m_serial->close();
        emit serialStatusChanged(SerialStatus::disconnect);
    }
}

void SerialServer::serialRead()
{
    serialDataCache.append(m_serial->readAll());
    m_serialRecvTimer->stop();
    m_serialRecvTimer->start(100);
    m_serialRecvTimer->setSingleShot(true);
}

void SerialServer::recvTimerTimeOut()
{
    serialFrameData = serialDataCache;
    serialDataCache.clear();
    newFrameDataRecv = true;
}

QStringList SerialServer::getAvailableSerialPort()
{
    QStringList availablePortName;
    if(m_serial->isOpen()){
        this->close();
    }
    if(m_serial != NULL){
        QString path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM";
        QSettings *settings = new QSettings(path, QSettings::NativeFormat);
        QStringList key = settings->allKeys();
        for(int i = 0;i<key.size();i++){
            QString key = getPortName(i,"key");
            QString value = getPortName(i,"value");
            availablePortName<<value;
        }
    }
    availableSerialPortName = availablePortName;
    return availablePortName;
}

QString SerialServer::getPortName(int index, QString keyorvalue)
{
    QString commresult;
    HKEY        hKey;
    wchar_t     keyname[256]; //鍵名陣列
    char        keyvalue[256];  //鍵值陣列
    DWORD       keysize,type,valuesize;
    if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_READ, &hKey) != 0) {
        QString error="Cannot open regedit!";   //無法開啟登錄檔時返回error
        return error;
    }
    QString keymessage;//鍵名
    QString message;
    QString valuemessage;//鍵值
    keysize = sizeof(keyname);
    valuesize = sizeof(keyvalue);

    if (RegEnumValue(hKey, index, keyname, &keysize, 0, &type, (BYTE*)keyvalue, &valuesize) == 0) { //列舉鍵名和值
        for (int i=0; i<(int)keysize; i++) {
            message = keyname[i];
            keymessage.append(message);
        }
        for (int j=0; j<(int)valuesize; j++) {
            if (keyvalue[j] != 0x00) {
                valuemessage.append(keyvalue[j]);
            }
        }
        if (keyorvalue == "key") {
            commresult = keymessage;
        }

        if (keyorvalue == "value") {
            commresult=valuemessage;
        }
    } else {
        commresult = "nokey";
    }
    RegCloseKey(hKey);//關閉登錄檔
    return commresult;
}