C# 串口操作系列(5)--通讯库雏形

版权声明:本文为博主原创文章,未经博主允许不得转载。
串口是很简单的,编写基于串口的程序也很容易。新手们除了要面对一堆的生僻概念,以及跨线程访问的细节,还有一个需要跨越的难题,就是协议解析,上一篇已经说明了:
一个二进制格式的协议一般包含: 协议头 + 数据段长度 + 数据 + 校验
一个Ascii格式的文本协议,一般包含: 数据头 + 正文 + 数据结束标识
类似的命令可能很多,类似的代码也会重复写很多次。对于我,并不觉得这个有任何难度,但是,很多时候,需要写点类似东西的时候呢,我往往不想写,不是别的,要搭建一个这样的框架,这绝对是个体力活,而且还需要耐心和细心。
从我上一次带项目,我就开始考虑编写通用的一个通讯库,支持很多功能,不过和公司内容结合紧密,不适合开源,更不适合推广。我重新组织、抽象了各个概念。希望能让新人朋友减少学习难度,更快的投入到其他方面。
请注意,此文章我也不知道如何归纳,不算科普,不能算类库的介绍,我是在介绍如何设计一个这样的通讯库。
通讯库,并非串口库,所以,我希望有一个基类,可以描述各种通讯方法的基类或接口,微软已经这么做了,他把这个叫做Stream。我认为不好的理由是,提供了Length属性、peek方法、seek方法却无法使用,很多方法和属性是不支持的,如果使用这个类操作硬件,就像一颗地雷,不小心就会写一个不支持的操作,而且会在运行时报错。所以,我希望能针对流设备的硬件,重新设计,我抽象出了一个接口:ICommunication。提供基本的打开、关闭、读写、字符集和有效数据长度等流设备的特性和操作。
为了能有一个通用的配置类,我定义了一个接口:ICommunicationSetting。
当你实现一个设备的时候,你需要实现ICommunication,还需要编写一个设置的类,去实现ICommunicationSetting接口。别觉得麻烦,这是为了能抽象的好,编写一个一劳永逸不用经常重写的通用代码。有了2个接口,我甚至可以开始编写依赖此接口的功能或软件了。当然,我还有需要写有关协议的分析。
既然协议是分2种,那自然要编写BinaryXXX和TextXXX,没错,有这样2个类。
考虑的更详细一点,任何数据,都不是无限期有效的,比如你获取下位机发来的电压,过了几秒了,应该就无效了,所以要考虑定时失效,于是我实现了有效性检查。数据要在字节数组中查找,分析,通知。所以这些公共的部分,我抽出来了,我写了一个接口,叫做:IAnalyzer,并编写了默认的实现,于是有了AnalyzeResult类,同时,区分2种协议方式,创建了子类:BinaryAnalyzeResult和TextAnalyzeResult。
那么,谁来使用ICommunication,IAnalyzer呢?放心,联系有点紧密,我不会撒手扔给外面的,这样做反而更复杂了,不是么。所以我写了一个带有分析功能的类:WyzComm。
使用通讯库的
这个类实现了数据的采集、缓存、分析器的调用,以及事件调用的通知。数据死锁的控制,所有你认为的麻烦事情,都在这里做了。那么,我编写这个类的时候,我肯定不知道未来有多少种协议是不是?那怎么办呢?我无法写死分析器,所以,我编写了接口:IAnalyzerCollection,因为文章从串口说起,我首先提供了串口的实现:
SerialPort(此类和微软的那个名字一样而已,但不是同一个),实现了ICommunication接口,我定义了一个SerialPortSetting类,实现了ICommunicationSetting。
至此。通讯库的框架就完成了。而这也就是使用通讯库所需要关注的所有内容。下面,为了能进行实际的演示,我编写了简单的实现。来演示一种功能,假设我有个程序,需要同时分析二进制数据格式和ASCII的文本数据格式,数据各不相同,使用了通讯库之后,我不需要重写数据的缓存、关闭的死锁处理、数据对界面的通知。我只需要编写2个协议类,和1个协议集合类。我的数据分析工作就完成了。
首先是一个文本协议,协议头是WYZ,协议尾是回车换行,中间是一个整形数字。我只需要设置好头、尾,编写数据分析。
- public class MyData1 : TextAnalyzeResult<int>
- {
- public MyData1()
- {
- this.BeginOfLine = "WYZ";
- this.EndOfLine = "/r/n";
- }
- public override void Analyze()
- {
- string s = Encoding.GetString(Raw);
- Match m = Regex.Match(s, "//d+");
- if (m.Success)
- {
- this.Data = int.Parse(m.Value);
- this.Valid = true;
- }
- }
- }
然后我定义了一个二进制协议,分析一条数据包含2个子项。
我首先定义这个数据的具体类型
- public class SampleData
- {
- public int Version { get; set; }
- public float Voltage { get; set; }
- public SampleData()
- {
- Version = 0;
- Voltage = 0;
- }
- public override string ToString()
- {
- return string.Format("{0},{1}", Version.ToString(), Voltage.ToString());
- }
- }
然后我编写协议分析类
- public class MyData2 : BinaryAnalyzeResult<SampleData>
- {
- public MyData2()
- {
- this._mask = new byte[] { 0xAA, 0xBB, 0xCC };
- this.TimeOut = 5;//超过5秒,收不到数据,则此数据无效。
- //自定义校验方法,演示为逐个相加和随便一个数字取模,我选择的是42
- this.checksum = (buf, offset, count) =>
- {
- byte checksum = 0;
- for (int i = offset; i < offset + count; i++)
- {
- checksum = (byte)((checksum + buf[i]) % 42);
- }
- return checksum;
- };
- }
- public override void Analyze()
- {
- int offset = _mask.Length + LenLength;//_mask.Length表示标记后的一个字节,_mask.Length+1表示标记后的第二个字节,有一个字节表示长度。
- this.Data.Version = BitConverter.ToInt32(Raw, offset + 0);
- this.Data.Voltage = BitConverter.ToSingle(Raw, offset + 4);
- this.Valid = true;//注意要设置数据有效状态
- }
- }
完成了。一个基于串口的,同时分析2种数据的,数据具有有效性判断,支持独立数据通知界面,整体原始数据缓存显示的功能。完成了。
为了演示功能,我写了新的校验方式,当然,你不用管,默认已经支持了异或校验,后续还会把常用校验都添加进去,crc16,crc32,奇偶校验等。

模拟发送数据为:
文本格式发送:WYZ123<CR><LF>
二进制格式发送:AA BB CC 08 0A 00 00 00 FA 3E F7 42 05

- 顶
- 4
C# 串口操作系列(5)--通讯库雏形的更多相关文章
- C# 串口操作 ---- 系列文章
C# 串口操作系列(5)--通讯库雏形 通讯库雏形的建立. 串口通讯介绍的高级篇,介绍更高级的抽象,为扩展为通用的客户端通讯库做铺垫,扩展性的考虑,能支持任意类型的流设备. ... 2010-08-0 ...
- C# 串口操作系列(4) -- 协议篇,文本协议数据解析
C# 串口操作系列(4) -- 协议篇,文本协议数据解析 标签: c#uiobjectstringbyte 2010-06-09 01:50 19739人阅读 评论(26) 收藏 举报 分类: 通讯 ...
- 【转】C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。
C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子. 标签: c#objectnewlineexceptionbytestring 2010-05-17 01:10 117109人阅读 ...
- C# 串口操作系列(3) -- 协议篇,二进制协议数据解析
原文地址:http://blog.csdn.net/wuyazhe/article/details/5627253 我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要 ...
- C# 串口操作系列(2) -- 入门篇,为什么我的串口程序在关闭串口时候会死锁 ?
第一篇文章我相信很多人不看都能做的出来,但是,用过微软SerialPort类的人,都遇到过这个尴尬,关闭串口的时候会让软件死锁.天哪,我可不是武断,算了.不要太绝对了.99.9%的人吧,都遇到过这个问 ...
- pcommlite串口通讯库使用
MFC下串口编程使用最多的两种方法是读取注册表和使用mscomm组件,都有着或多或少的缺陷,调用系统SDK比较麻烦,而MSCOMm组件最多支持16个串口,串口号大于16的时候无法打开,遇到这种情况,可 ...
- 【STM32H7教程】第29章 STM32H7的USART串口基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第29章 STM32H7的USART串口基础知识和 ...
- c#实现串口操作 SerialPort
命名空间:using System.IO.Ports;该类提供了同步 I/O 和事件驱动的 I/O.对管脚和中断状态的访问以及对串行驱动程序属性的访问. 操作类声明: SerialPort sp = ...
- WeinView 与 MITSUBISHI FX 系列 PLC 通讯范例
1. 范例操作概述 此范例将介绍如何快捷简易地建立WEINVIEW HMI与MITSUBISHI FX系列 PLC通讯. 注意事项:通讯参数设置,通讯线接法. 2. 规划说明 (1) 新建简单 PLC ...
随机推荐
- 一次使用innobackupex重新搭建主从复制报错解决方法及注意事项
[环境介绍] 系统环境:CentOS release 6.4 (Final) + Server version: 5.7.18-log MySQL Community Server (GPL) + i ...
- vue父子组件生命周期执行顺序
之前写了vue的生命周期,本以为明白了vue实例在创建到显示在页面上以及销毁等一系列过程,以及各个生命周期的特点.然而今天被问到父子组件生命周期执行顺序的时候一头雾水,根本不知道怎么回事.然后写了一段 ...
- python—异常
异常是在程序中不可避免的,当程序遇到一个异常时程序就会停止,可以使用try—except进行处理异常,即便在出现异常程序也可以继续运行. 语法: try: 代码 except 异常名: 处理异常的代码 ...
- MySQL sum聚合函数
select sum(if(money > 0, money, 0)) as money from total_money 意思是如果money > 0, 将money的值累加到tot ...
- UE4命令行使用,解释
命令行在外部 从命令行运行编辑项目 1 导航到您的[LauncherInstall][VersionNumber]\Engine\Binaries\Win64 目录中. 2 右键单击上 UE4Edit ...
- 按Ctrl+Enter发送的实现
按Ctrl+Enter发送 1, 监听textarea的onkeydown事件 <textarea tabindex="1" class="ie6ta" ...
- PyCharm的使用教程
1.1 安装 首先去下载最新的pycharm ,进行安装.可以直接在官网下载. 1.2 首次使用 1,点击Create New Project. 2, 输入项目名.路径.选择python解释器.如果没 ...
- dba_segements 没有所有的表的信息
这是oracle11g新增的功能,假设一个一般的用户user新建了一张表user_table,这时切换到sys用户查看dba_segments 查看user_table的信息,发现dba_segmen ...
- SpringMVC使用CommonsMultipartResolver上传文件
DispatcherServlet并没有实现任何解析multipart请求数据的功能,它将该任务委托给了Spring中MultipartResolver策略接口的实现,通过该接口的实现类来解析mult ...
- 2018-2019-2 20165231王杨鸿永《网络对抗》Exp1 PC平台逆向破解
实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. 该程序同时包含另一个代码片段,getShe ...