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指针详解
Qt中的串口编程之三的更多相关文章
- Qt中的串口编程之一
QtSerialPort 简介 功能介绍 SerialPort SerialPortInfo 源代码 编译和安装 配置编译环境 Perl只是在Qt5的时候才需要Qt4的情况下可以不配置 使用如下推荐步 ...
- QT中的SOCKET编程(QT-2.3.2)
转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...
- QT中的SOCKET编程
转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...
- Qt中的多线程编程
http://www.ibm.com/developerworks/cn/linux/l-qt-mthrd/ Qt 作为一种基于 C++ 的跨平台 GUI 系统,能够提供给用户构造图形用户界面的强大功 ...
- <QT障碍之路>qt中使用串口类接收数据不完整
问题:当用QT中的serial->readAll()的时候,不会把全部的数据一次性都读取出来,而是阶段性的.原因是因为当串口有信号时候,readyRead()信号就会被抛出,那么一帧完整的数据帧 ...
- 5.关于QT中的网络编程,QTcpSocket,QUdpSocket
1 新建一个项目:TCPServer.pro A 修改TCPServer.pro,注意:如果是想使用网络库,需要加上network SOURCES += \ TcpServer.cpp \ T ...
- qt中的udp编程
UDP QUdpSocket ---> upd socket 1.创建 QUdpSocket *p = new QUdpSocket(); 2.最先接收数据一方 调用bind-> ip/p ...
- qt中的tcp编程
server .server.h #define DIALOG_H #include <QDialog> #include <QTcpServer> #include < ...
- Qt 多线程和网络编程学习
一,Qt多线程类学习 QThread类,开始一个新的线程就是开始执行重新实现QThread::run(),run()是默认现实调用exec(),QThread::start()开始线程的执行,run( ...
随机推荐
- 在C#编程中玩转枚举,分享我的EnumHelper。
在C#编程中玩转枚举,分享我的EnumHelper. 在软件开发过程中,我们经常会为特定的场景下的特定数据定义逻辑意义.比如在用户表中,我们可能会有一个用户状态字段,该字段为整形.如果该字段的值为1则 ...
- EasyUI的后台界面
EasyUI的后台界面搭建及极致重构 〇.前言 要了解一个东西长什么样,至少得让我们能看到,才能提出针对性的见解.所以,为了言之有物,而不是凭空漫谈,我们先从UI说起,后台管理页面的UI我们将使用应用 ...
- Installshield获取安装包版本的系统变量是IFX_PRODUCT_VERSION
原文:Installshield获取安装包版本的系统变量是IFX_PRODUCT_VERSION Installshield获取安装包版本的系统变量为IFX_PRODUCT_VERSION 当笔记记下 ...
- 那些必须要知道的Javascript
原文:那些必须要知道的Javascript JavaScript是前端必备,而这其中的精髓也太多太多,最近在温习的时候发现有些东西比较容易忽略,这里记录一下,一方面是希望自己在平时应用的时候能够得心应 ...
- Andorid类似Fragment更换布置方法
public void replaceRightView(View v) { int f = LinearLayout.LayoutParams.MATCH_PARENT; LinearLayout. ...
- 如何优雅的研究 RGSS3 (七) 加入LOGO屏幕
对于游戏 LOGO 屏幕. 首先设计 LOGO Scene类.我们知道,现场类 Scene_Base 子类. 让我们回顾一下现场的作品. 首先运行开始处理.其次是开始治疗.然后停止更新屏幕,最后,治疗 ...
- QT5.4 vs2013静态加载插件的sqlite静态编译
1. 非常多同学在静态编译QT5完毕后, sqlite的驱动老是载入不进去, 原因可能是由于你没有例如以下操作: #include <QtPlugin> Q_IMPORT_PLUGIN(Q ...
- Winform无边框窗体(FormBorderStyle属性设为None)自定义移动
为了界面的好看,有时候需要将窗体FormBorderStyle属性设为None,这样就可以根据自己的喜欢来设计界面.但这样窗体无法进行移动的.而且默认的窗体(FormBorderStyle=Sizab ...
- EF的四种开发模式
EF提供了四种开发模式,具体如下:(转载)Code First(New DataBase) :在代码中定义类和映射关系并通过model生成数据库,使用迁移技术更新数据库.Code First(Exis ...
- DotNetOpenAuth搭建OAuth2.0
使用DotNetOpenAuth搭建OAuth2.0授权框架 标题还是一如既往的难取. 我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物 ...