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指標詳解