Qt中的串口编程之三

QtSerialPort

今天我们来介绍一下QtSerialPort模块的源代码,学习一下该可移植的串口编程库是怎么实现的。

首先,我们下载好了源代码之后,使用QtCreator打开整个工程,可以看到如下图的源代码结构:


我们先来看一下serialport-lib.pri这个文件,serialport.pro工程文件就是靠这个文件来控制整个源代码的编译的。,具体内容如下:


上面的内容只是最基本的类,大家知道,跨平台的类一般在底层都包含这与操作系统相关的一些实现,这里也不例外,大家看看下面的图就明白了,

这里只以类unix操作系统为例来做说明:


也许看到这个大家不是很明白:


      这与qmake的一些特性相关:CONFIG、DEFINE、PKGCONFIG都是qmake私有的一些变量,而packagesExist()则是qmake私有的函数,

整个这一块要表达的意思是"如果udev这个库存在,则编译程序的时候就定义HAVE_LIBUDEV这个宏定义(在我们的代码中使用了这个宏定义),

并且链接程序的时候,也链接udev这个库"。至于qmake的一些特性以及使用方法,后续会专门写几篇博文详细介绍。

      至于udev这个库的介绍,请见:libudev

      我们在代码中是如下使用udev库的:


      在serialport源代码中还是用了另外一个开源库,那就是lockdev,该库主要提供的功能就是“Lockdev is a setgid binary,
which provides a reliable way to put an exclusive lock in /var/lock to devices (e.g. ttyS0) using both FSSTND and SVr4 methods,
so regular users don't need write access there.”

      下面,看看我们在代码中是如何使用lockdev的:


      对于lockdev,我们在下一篇博客中将详细介绍它的功能的和实现。

 好了,言归正传,我们来看看serialport库在类unix操作系统上是如何实现的:

头文件:

与平台无关的公共头文件:qserialportglobal.h qserialport.h qserialportinfo.h
与平台无关的私有头文件:qserialport_p.h qserialportinfo_p.h
与平台有关的头文件:       qttylocker_unix_p.h qserialport_unix_p.h

源文件:

与平台无关的源文件:qserialport.cpp qserialportinfo.cpp
与平台有关的源文件:qttylocker_unix.cpp qserialport_unix.cpp qserialportinfo_unix.cpp

源代码解析:

1、QSerialPort类源码解析

(1)QSerialPort类继承自QIODevice,包含对串口的基本操作:

与该类有关系的类主要是如下几个:

QIODevice、QSerialPort、QSerialPortPrivate、QSerialPortPrivateData。

它们的关系如下:

QSerialPort继承自QIODevice,继承了对设备文件基本的操作。

QSerialPortPrivate是QSerialPort对象中表示操作一类的,该部分与操作系统有关。QSerialPortvate继承自QSerialPortPrivateData。

QSerialPortPrivateData是一个串口设备的初始化数据,例如波特率等等。

QSerialPortPrivateData更多表示串口设备的初始数据,QSerialPortPrivate更多表示平台相关的对串口设备的操作。

(2)QSerialPort类定义:

class QSerialPortInfo;
class QSerialPortPrivate;

class Q_SERIALPORT_EXPORT QSerialPort : public QIODevice
{
    Q_OBJECT

    Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate NOTIFY baudRateChanged)
    Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits NOTIFY dataBitsChanged)
    Q_PROPERTY(Parity parity READ parity WRITE setParity NOTIFY parityChanged)
    Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits NOTIFY stopBitsChanged)
    Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl NOTIFY flowControlChanged)
    Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy NOTIFY dataErrorPolicyChanged)
    Q_PROPERTY(bool dataTerminalReady READ isDataTerminalReady WRITE setDataTerminalReady NOTIFY dataTerminalReadyChanged)
    Q_PROPERTY(bool requestToSend READ isRequestToSend WRITE setRequestToSend NOTIFY requestToSendChanged)
    Q_PROPERTY(SerialPortError error READ error RESET clearError NOTIFY error)
    Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged)

    Q_ENUMS( Directions Rate DataBits Parity StopBits FlowControl PinoutSignals DataErrorPolicy SerialPortError )

public:

    enum Direction  {
        Input = 1,
        Output = 2,
        AllDirections = Input | Output
    };
    Q_DECLARE_FLAGS(Directions, Direction)

    enum BaudRate {
        Baud1200 = 1200,
        Baud2400 = 2400,
        Baud4800 = 4800,
        Baud9600 = 9600,
        Baud19200 = 19200,
        Baud38400 = 38400,
        Baud57600 = 57600,
        Baud115200 = 115200,
        UnknownBaud = -1
    };

    enum DataBits {
        Data5 = 5,
        Data6 = 6,
        Data7 = 7,
        Data8 = 8,
        UnknownDataBits = -1
    };

    enum Parity {
        NoParity = 0,
        EvenParity = 2,
        OddParity = 3,
        SpaceParity = 4,
        MarkParity = 5,
        UnknownParity = -1
    };

    enum StopBits {
        OneStop = 1,
        OneAndHalfStop = 3,
        TwoStop = 2,
        UnknownStopBits = -1
    };

    enum FlowControl {
        NoFlowControl,
        HardwareControl,
        SoftwareControl,
        UnknownFlowControl = -1
    };

    enum PinoutSignal {
        NoSignal = 0x00,
        TransmittedDataSignal = 0x01,
        ReceivedDataSignal = 0x02,
        DataTerminalReadySignal = 0x04,
        DataCarrierDetectSignal = 0x08,
        DataSetReadySignal = 0x10,
        RingIndicatorSignal = 0x20,
        RequestToSendSignal = 0x40,
        ClearToSendSignal = 0x80,
        SecondaryTransmittedDataSignal = 0x100,
        SecondaryReceivedDataSignal = 0x200
    };
    Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal)

    enum DataErrorPolicy {
        SkipPolicy,
        PassZeroPolicy,
        IgnorePolicy,
        StopReceivingPolicy,
        UnknownPolicy = -1
    };

    enum SerialPortError {
        NoError,
        DeviceNotFoundError,
        PermissionError,
        OpenError,
        ParityError,
        FramingError,
        BreakConditionError,
        WriteError,
        ReadError,
        ResourceError,
        UnsupportedOperationError,
        UnknownError
    };

    explicit QSerialPort(QObject *parent = 0);
    explicit QSerialPort(const QString &name, QObject *parent = 0);
    explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = 0);
    virtual ~QSerialPort();

    void setPortName(const QString &name);
    QString portName() const;

    void setPort(const QSerialPortInfo &info);

    bool open(OpenMode mode) Q_DECL_OVERRIDE;
    void close() Q_DECL_OVERRIDE;

    void setSettingsRestoredOnClose(bool restore);
    bool settingsRestoredOnClose() const;

    bool setBaudRate(qint32 baudRate, Directions dir = AllDirections);
    qint32 baudRate(Directions dir = AllDirections) const;

    bool setDataBits(DataBits dataBits);
    DataBits dataBits() const;

    bool setParity(Parity parity);
    Parity parity() const;

    bool setStopBits(StopBits stopBits);
    StopBits stopBits() const;

    bool setFlowControl(FlowControl flow);
    FlowControl flowControl() const;

    bool setDataTerminalReady(bool set);
    bool isDataTerminalReady();

    bool setRequestToSend(bool set);
    bool isRequestToSend();

    PinoutSignals pinoutSignals();

    bool flush();
    bool clear(Directions dir = AllDirections);
    bool atEnd() const Q_DECL_OVERRIDE;

    bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy);
    DataErrorPolicy dataErrorPolicy() const;

    SerialPortError error() const;
    void clearError();

    qint64 readBufferSize() const;
    void setReadBufferSize(qint64 size);

    bool isSequential() const Q_DECL_OVERRIDE;

    qint64 bytesAvailable() const Q_DECL_OVERRIDE;
    qint64 bytesToWrite() const Q_DECL_OVERRIDE;
    bool canReadLine() const Q_DECL_OVERRIDE;

    bool waitForReadyRead(int msecs) Q_DECL_OVERRIDE;
    bool waitForBytesWritten(int msecs) Q_DECL_OVERRIDE;

    bool sendBreak(int duration = 0);
    bool setBreakEnabled(bool set = true);

Q_SIGNALS:
    void baudRateChanged(qint32 baudRate, QSerialPort::Directions dir);
    void dataBitsChanged(QSerialPort::DataBits dataBits);
    void parityChanged(QSerialPort::Parity parity);
    void stopBitsChanged(QSerialPort::StopBits stopBits);
    void flowControlChanged(QSerialPort::FlowControl flow);
    void dataErrorPolicyChanged(QSerialPort::DataErrorPolicy policy);
    void dataTerminalReadyChanged(bool set);
    void requestToSendChanged(bool set);
    void error(QSerialPort::SerialPortError serialPortError);
    void settingsRestoredOnCloseChanged(bool restore);

protected:
    qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
    qint64 readLineData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
    qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE;

private:
    void setError(QSerialPort::SerialPortError error, const QString &errorString = QString());

    QSerialPortPrivate * const d_ptr;

    Q_DECLARE_PRIVATE(QSerialPort)
    Q_DISABLE_COPY(QSerialPort)
};

Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals)

2、QserialPortInfo类源码解析

(1)QserialPortInfo主要是枚举系统上可用串口设备的信息:

与该类的类主要是如下几个:

QSerialPort、QSerialPortInfo、QSerialPortInfoPrivate、QSerialPortInfoPrivateDeleter。

QSerialPortInfo的构造函数中使用到了QSerialPort。

QSerialPortInfoPrivate则代表QSerialPortInfo的私有数据。

(2)QserialPortInfo类定义:

class QSerialPort;
class QSerialPortInfoPrivate;
class QSerialPortInfoPrivateDeleter;

class Q_SERIALPORT_EXPORT QSerialPortInfo
{
    Q_DECLARE_PRIVATE(QSerialPortInfo)
public:
    QSerialPortInfo();
    explicit QSerialPortInfo(const QSerialPort &port);
    explicit QSerialPortInfo(const QString &name);
    QSerialPortInfo(const QSerialPortInfo &other);
    ~QSerialPortInfo();

    QSerialPortInfo& operator=(const QSerialPortInfo &other);
    void swap(QSerialPortInfo &other);

    QString portName() const;
    QString systemLocation() const;
    QString description() const;
    QString manufacturer() const;

    quint16 vendorIdentifier() const;
    quint16 productIdentifier() const;

    bool hasVendorIdentifier() const;
    bool hasProductIdentifier() const;

    bool isNull() const;
    bool isBusy() const;
    bool isValid() const;

    static QList<qint32> standardBaudRates();
    static QList<QSerialPortInfo> availablePorts();

private:
    QScopedPointer<QSerialPortInfoPrivate, QSerialPortInfoPrivateDeleter> d_ptr;
};

inline bool QSerialPortInfo::isNull() const
{ return !d_ptr; }


附录:

1、qtserialport源代码中使用了D指针,Q指针,这方面的介绍请见Qt之美(一):d指针/p指针详解

原文地址:https://www.cnblogs.com/jiangu66/p/3192304.html