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指针详解