自定义Qt组件-通讯模块(P2)
1. 抽象协议AbstractProtocol
抽象协议AbstractProtocol定义CommManager与协议之间的接口。AbstractProtocol中的一些属性(如enabled)用于设置是否能够处理数据。
processData是AbstractProtocol中定义的回调函数,当设备中有数据返回时,数据将会被交给该方法进行处理。
若该方法返回true,则表明当前处理数据的协议已经找到相应的数据并且不需要将数据再交给其它协议处理,CommManager便会停止向其它协议发送这些数据;
若该方法返回为false,表明当前处理数据的协议并未找到相应的数据,并且希望交由其它协议进行处理,此时Com会继续转发这些数据。
lastQueryFailed 是在查询失败时由协议实现类进行处理的回调函数。
AbstractProtocol(生产者)实例将会维护各自的命令队列,CommManager(消费者)在完成一次查询后拉取AbstractProtocol(生产者)生成的指令。因此CommManager会根据指令消耗的速度决定是否应该进行下一次查询。有关生产者和消费者的更多信息,可以查看 https://www.cnblogs.com/charlesblc/p/6045238.html。
2. 通讯器构造工厂
CommFactory是通讯器的构造工厂类,要实例化某个AbstractComm的通讯器实现类,需要通过addComm方法将通讯器注册到CommFactory中,工厂会保存各个通讯器的实现类对象,在构造之后进行切换会尝试找出已经构造过的对象,避免重复构造通讯器对象。
CommManager中可用的串口实现类对象由CommFactory进行例化,通过createComm方法将参数传递给工厂类的实例化方法,获取可用的实现类对象指针。
Comm层作为库,暴露给其它代码使用的部分主要是CommManager,因此要在程序运行时改变串口工作模式或切换成网络接口,调用 CommManager::resetMode 方法即可。
若该模块内部已经有实现好的通讯器,则可以调用 CommManager::resetMode(const QString &type, const bool halfDuplex),根据类型和全/半双工模式选择特定的通讯器,若要使用扩展的自定义通讯器,可以使用 CommManager::resetMode(const QString &className) 传入具体的类名选择通讯器。
如果需要添加新的通讯器,创建一个继承于AbstractComm的子类(构造函数需要用Q_INVOKABLE修饰),通过addComm方法将元对象和描述信息添加到工厂类中,之后可以传递类名来构造其它的通讯器。
构造工厂的使用使得CommManager只用传递类名或通讯器类型即可获得通讯器对象,从而使CommManager的功能只需要对通讯器对象进行管理和收发数据,简化CommManager 的实现。
3. 虚拟串口示例(待完善)
虚拟串口VirtualCom是为了方便上位机单独进行调试而编写的AbstractCom的子类。以虚拟串口为例,介绍如何继承实现AbstractCom的子类,以设计新模式的串口。
虚拟串口VirtualCom的接口:
如图所示,VirtualCom的init(), close(), openComm, writeCmd, setCommProperty, query, onRead等方法都是继承自AbstractCom的接口(在方法声明后增加了 Q_DECL_OVERRIDE宏,即override 关键字)。
init()方法中进行成员变量的初始化(多线程中的QIODevice只能在创建其实例的线程中进行操作,否则在运行时会警告/报错),需要在该方法中可以实例化QTimer,QSerialPort或QTcpSocket等对象(这些对象不能在构造函数中实例化)。
虚拟串口中没有使用到串口对象,因此不需要实例化串口/QIODevice对象,这里的init方法中实例化timer对象并连接相应的信号和槽。
openComm方法用于打开设备(串口/Socket),由于虚拟串口中没有串口对象,这里只修改设备状态即可。打开虚拟串口后,timer开始计时。
打开串口后即可调用write写入命令:一般该方法只需要传递参数给query函数执行即可,但半双工模式下,需要保存指令,待线路空闲时发送。
若接受到命令后可以立即查询,那么需要通过QMetaObject::invokeMethod静态方法在子线程中运行(以致访问串口/Socket对象时不会出现错误)。虚拟串口中的该方法就是将cmd参数传递给query方法通过子线程执行。
要使用虚拟串口发送一些特定的数据,需要修改VirtualCom的实现,在实际使用过程中比较麻烦。目前可用的解决方法有两个:
- 把虚拟串口编译成动态链接库,在不同的程序中使用不同的动态库文件即可,但是这样做实际上在开发过程中变得非常麻烦。
- 自定义xml文件格式,从指定的xml文件中读取信息,根据信息来决定发送的数据内容,这样的话就能够使VirtualCom作为库文件与实际的信息回复实现分离。如果要这样实现,首先要定义xml文件的格式,然后编写相应的解析器,并将解析器解析的结果传递给VirtualCom对象,当接收到来自上层的指令后根据解析器的结果进行响应。这样做实际上是在模拟下位机收发数据的行为,看上去工作量较大,但比较实际的下位机应用应该是简单不少了。
自定义Qt组件-通讯模块(P2)的更多相关文章
- 自定义Qt组件-通讯模块(P1)
通讯模块Communicator 通讯模块是整个项目设计中位于最底层的模块,用于处理与串口或网络等设备的通讯,所有设备的通讯通过CommManager类完成,上层软件设计时需要根据comm模块(主要是 ...
- 自定义Qt组件-通讯模块(P3)
1. 半双工模式实时检测串口 ComHalfDuplex类是为了解决上位机发送控制指令和下位机发送数据会在半双工RS485总线中产生冲突引起乱码而引入的(v0.010版本引入). 解决冲突的原理主 ...
- C/C++ Qt TableDelegate 自定义代理组件
TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重 ...
- SSIS自定义数据流组件开发(血路)
由于特殊的原因(怎么特殊不解释),需要开发自定义数据流组件处理. 查了很多资料,用了不同的版本,发现各种各样的问题没有找到最终的解决方案. 遇到的问题如下: 用VS2015编译出来的插件,在SSDTB ...
- Android Studio开发基础之自定义View组件
一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...
- [UE4]自定义MovementComponent组件
自定义Movement组件 目的:实现自定义轨迹如抛物线,线性,定点等运动方式,作为组件控制绑定对象的运动. 基类:UMovementComponent 过程: 1.创建UCustomMovement ...
- Qt组件中的双缓冲无闪烁绘图
双缓冲绘图在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图.使用双缓冲,可以减轻绘制的闪烁感.在有些情况下,用户要关闭双缓冲,自己管理绘图.下面的语句设置了窗口部件的Qt::WA_PaintOn ...
- 【转】Android学习基础自定义Checkbox组件
原文网址:http://forum.maiziedu.com/thread-515-1-1.html heckbox组件是一种可同时选中多项的基础控件,即复选框,在android学习中,Checkbo ...
- 自定义Qt按钮
转自:http://blog.csdn.net/starcloud_zxt/article/details/5185556 Qt自带的PushButton样式比较单一,在开发的时候往往按钮的形状各异, ...
随机推荐
- SQLServer存储引擎——05.索引的结构和分类
5. SQLServer存储引擎——索引的结构和分类 关系型数据库中以二维表来表达关系模型,表中的数据以页的形式存储在磁盘上,在SQL SERVER中,数据页是磁盘上8k的连续空间,那么,一个表的所有 ...
- c# winform使用IrisSkin2换肤弹不出窗口解决方案
winform使用IrisSkin2换肤弹不出窗口解决方案 这张图能解决超级多博友的问题,知识是共享的,绝不私吞.共同学习,共同进步! 不需要说太多,只需1张图! ...
- 【转】使用母版页时内容页如何使用css和javascript
源地址:https://www.cnblogs.com/accumulater/p/6767138.html
- Apache 性能调优-参考篇
1 内存 适当选用适合大小的内存,保证谷峰负载时,有足够的内存使用 2 使用ab测试apache性能 ab -n 1000 -c 10 http://www.test.com 使用ab的缺点: ...
- Redis及虚拟机windows两种环境安装配置
---恢复内容开始--- Redis /rae dis/是一个开源的Key-Value数据库.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链 ...
- 树状数组 P3605 [USACO17JAN]Promotion Counting晋升者计数
P3605 [USACO17JAN]Promotion Counting晋升者计数 题目描述 奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训--牛是可怕的管理者! 为了方便,把奶牛从 ...
- 去除掉svn目录
使用svn提交时,造成有些文件锁住不能使用,百度得到下面相似问题以及解决方法: /*********************************************************** ...
- freemarker ! 用法
${(user.name)!""} 请注意,是打了()的 也就是它会先判断user是不是为null 在判断user.name 是不是为null
- 奇妙的 clip-path 几何图形
CSS 新属性 clip-path,意味裁剪路径的意思,让我们可以很便捷的生成各种几何图形. clip-path 通过定义特殊的路径,实现我们想要的图形.而这个路径,正是 SVG 中的 path . ...
- C语言关于++i,--i,i++,i--
++i 和--i 指的是先进行运算,再进行调用(运算符在前) i++和i--指的是先进行调用,再进行运算(运算符在后) 举例: int k,i=5;k=i++;//k得到5i=5;k=++i;//k得 ...