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


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

    标签: 通讯c#数据分析byteclassstring
     分类:
     

    串口是很简单的,编写基于串口的程序也很容易。新手们除了要面对一堆的生僻概念,以及跨线程访问的细节,还有一个需要跨越的难题,就是协议解析,上一篇已经说明了:

    一个二进制格式的协议一般包含: 协议头 + 数据段长度 + 数据  + 校验

    一个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,协议尾是回车换行,中间是一个整形数字。我只需要设置好头、尾,编写数据分析。

    [c-sharp] view plain copy
     
    1. public class MyData1 : TextAnalyzeResult<int>  
    2. {  
    3.     public MyData1()  
    4.     {  
    5.         this.BeginOfLine = "WYZ";  
    6.         this.EndOfLine = "/r/n";  
    7.     }  
    8.   
    9.     public override void Analyze()  
    10.     {  
    11.         string s = Encoding.GetString(Raw);  
    12.         Match m = Regex.Match(s, "//d+");  
    13.         if (m.Success)  
    14.         {  
    15.             this.Data = int.Parse(m.Value);  
    16.             this.Valid = true;  
    17.         }  
    18.     }  
    19. }  

    然后我定义了一个二进制协议,分析一条数据包含2个子项。

    我首先定义这个数据的具体类型

    [c-sharp] view plain copy
     
    1. public class SampleData  
    2. {  
    3.     public int Version { get; set; }  
    4.     public float Voltage { get; set; }  
    5.     public SampleData()  
    6.     {  
    7.         Version = 0;  
    8.         Voltage = 0;  
    9.     }  
    10.     public override string ToString()  
    11.     {  
    12.         return string.Format("{0},{1}", Version.ToString(), Voltage.ToString());  
    13.     }  
    14. }  

    然后我编写协议分析类

    [c-sharp] view plain copy
     
    1. public class MyData2 : BinaryAnalyzeResult<SampleData>  
    2. {  
    3.     public MyData2()  
    4.     {  
    5.         this._mask = new byte[] { 0xAA, 0xBB, 0xCC };  
    6.         this.TimeOut = 5;//超过5秒,收不到数据,则此数据无效。  
    7.         //自定义校验方法,演示为逐个相加和随便一个数字取模,我选择的是42  
    8.         this.checksum = (buf, offset, count) =>  
    9.             {  
    10.                 byte checksum = 0;  
    11.                 for (int i = offset; i < offset + count; i++)  
    12.                 {  
    13.                     checksum = (byte)((checksum + buf[i]) % 42);  
    14.                 }  
    15.                 return checksum;  
    16.             };  
    17.     }  
    18.   
    19.     public override void Analyze()  
    20.     {  
    21.         int offset = _mask.Length + LenLength;//_mask.Length表示标记后的一个字节,_mask.Length+1表示标记后的第二个字节,有一个字节表示长度。  
    22.         this.Data.Version = BitConverter.ToInt32(Raw, offset + 0);  
    23.         this.Data.Voltage = BitConverter.ToSingle(Raw, offset + 4);  
    24.         this.Valid = true;//注意要设置数据有效状态  
    25.     }  
    26. }  

    完成了。一个基于串口的,同时分析2种数据的,数据具有有效性判断,支持独立数据通知界面,整体原始数据缓存显示的功能。完成了。

    为了演示功能,我写了新的校验方式,当然,你不用管,默认已经支持了异或校验,后续还会把常用校验都添加进去,crc16,crc32,奇偶校验等。

    模拟发送数据为:

    文本格式发送:WYZ123<CR><LF>

    二进制格式发送:AA BB CC 08 0A 00 00 00 FA 3E F7 42 05

    vs2008工程项目源码范例

     
    4
  • 相关阅读:
    poj 3280 Cheapest Palindrome(区间DP)
    POJ 2392 Space Elevator(多重背包)
    HDU 1285 定比赛名次(拓扑排序)
    HDU 2680 Choose the best route(最短路)
    hdu 2899 Strange fuction (三分)
    HDU 4540 威威猫系列故事――打地鼠(DP)
    HDU 3485 Count 101(递推)
    POJ 1315 Don't Get Rooked(dfs)
    脱离eclipse,手动写一个servlet
    解析xml,几种方式
  • 原文地址:https://www.cnblogs.com/laocainiao160622/p/5620305.html
Copyright © 2020-2023  润新知