Windows上C++串口通讯回调模型

WindowsC++串口通讯回调模型

1           简介

本文采用C++的面向对象以及模板技术,在Windows平台上设计了使用OVERLAPPED机制的串口通讯C++Serialflexer。通过使用该C++类,可以方便的创建运行在Windows上的具备串口通讯及状态监控功能的程序。

 

注:类Serialflexer的绝大部分技术思路来源于参考资料[1][3],唯一的创造就是使用接口类IDteCallBack作为串口通讯的事件接受器。通过该接收器接口,可以方便的实现多个串口通讯的统一管理。

 

关键词:

OVERLAPPED Serial C+ + Multithreaded Windows

 

2           C++Serialflexer

Serialflexer名称是Serial communication Multiplexer的缩写,原意是为了能够同时进行多个串口的通讯,不过现在一个类Serialflexer对象只支持一个串口的通讯。

Serialflexer中包含了一个Reader线程对象和Status Monitor线程对象,同时继承了IDteCallBack接口类。通过线程函数的参数将类Serialflexer本身this指针传递给线程对象,两个线程能够调用IDteCallBack中包含的接口函数,从而在类Serialflexer中进行串口数据接收和状态监控。通过让具体的实现类继承自类Serialflexer,实现IDteCallBack中包含的接口函数,就可以在外部控制串口数据和状态。

Serialflexer暂时不包含Writer线程。

 

3           串口通讯的几个问题

开始设计串口通讯程序,需要考虑的问题不外乎:

1.         采用OVERLAPPED或是nonoverlapped模型?

2.         多线程的滥用?

3.         同步亦或异步?

 

3.1          OVERLAPPED I/O

 

如果考虑兼容性问题,OVERLAPPED并不是最好的选择,因为大部分的操作系统都不支持。但是OVERLAPPED的优势在于灵活性和效率更高,因此Serialflexer也采用了OVERLAPPED机制。

 

3.2          多线程问题

过多的线程并不能带给串口通讯更多的效率,但是想在一个线程里同时进行ReadWrite也不是好主意。Serial Port I/O一文中讲“Such code is difficult to create, debug, or even reason about successfully and should be avoided.  Using separate threads for input and output results in cleaner code, with a nice separation of concerns.”所以在[1][3]的例子中都采取了将ReadWrite分开成两个线程的设计。

Serialflexer尚未实现Writer线程,因为Writer线程涉及到UI层面,我原先的设计思路是采用Message Queue来实现一个相对UI窗口独立的Writer线程,但暂时还没有时间完成这个工作。

为了实现串口的状态监控,Serialflexer设定了串口事件接收机制。Serialflexer采用了将ReadStatus分开成两个线程的做法。而将两者放在同一个线程中也未尝不可,C Win32 Serial Communication中介绍的例子MTTTY就采用了后面的做法。

3.3          同步、异步

第三个问题,同步或是异步,这是一个与项目直接相关的问题。同步,即是DTERequest,然后需要从DCE获得ResponseSerialflexer没有考虑同步问题,只是实现了异步的数据接收和状态监控功能。

 

4           使用C++模板技术

使用模板技术主要是在设计Read buffer Size的时候想到的。考虑到不同的DCE设备使用不同长度的数据,除了模板机制,我想不到更好的使用C++实现缓冲不同数据长度的解决方法(std::string无法替代固定长度的缓冲区),所以为了让类Serialflexer能够适应不同的场合,我将缓冲区长度放到了模板参数之中。

由于采用了模板机制,所有的代码都在头文件中实现。而为了考虑代码可读性,使用了inl文件,作为头文件的扩充。

有些参数可以用模板来实现,有些参数则应该作为变参实现,这样可以提供更多的用户选项。这些参数主要视不同产品需求而定,类Serialflexer并没有更多考虑该问题。

 

5           接口IDteCallBack的设计

原先为了实现在Reader线程和Status线程中将数据接收和状态事件反映到串口管理类之中,我首先想到的是全局函数思路。后来才想到了使用ISerialCallback接口类这样面向对象的思路。也就是在ISerialCallback类中定义一系列的纯虚函数,包括DataRece数据接收函数以及Status状态反馈函数,而后,在具体的子类中构造这些回调函数的具体实现。。

使用ISerialCallback的第一步是定义其中的接口函数,第二步是如何将该接口传递到线程之中。我的思路是,类Serialflexer继承ISerialCallback,但是并不实现纯虚函数,而是将实现留给Serialflexer的子类,也就是具体实现类。然后,在其中定义两个嵌套子类ReaderThreadStatusThread,线程函数的参数即是Serialflexerthis指针。这样线程函数不仅可以在权限范围内的操作,还可以通过指针调用ISerialCallback的接口函数。

 

6           Message Queue机制

POSIX Message Queue是通过读、写各一个信号量保护一个列表实现的多线程安全消息队列机制。Windows并没有直接提供这种机制。不过MSDN Issue 2008-7中有一个比较好的类似Message Queue的功能的实现,不过暂时没有纳入Serialflexer之中。

 

7           多串口管理机制

原先类Serialflexer的设计思路是可以同时管理多个串口,这主要通过ISerialCallback的每个函数第一个参数都使用HANDLE参数,代表当前调用的Serial Port。不过在现有实现中,并没有实现该机制。

 

8           串口状态监控

进行串口状态监控的Status线程通过WaitCommEvent监测串口状态。主要的三个状态对象是COMSTATEventsComm Error Flags

9           代码获取

Googlecode中的Serialflexer项目中通过SVN获取代码。

 

 

10       参考资料

[1] C Win32 Serial Communication, MTTTY sample

[2] Introduction to RS232 Serial Communications,

[3] Serial Port I/O, http://www.flounder.com/serial.htm

[4] Serial Port Programming in Windows and Linux, Maxwell Walter, November 7, 2003

 

11       Acronyms

 

DTE

Data Terminal Equip ment

DCT

Data Communication Equipment 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值